- webapp/api:getProxyStats/getProxyLedger/listProxyStudents/createStudent/ topup/issueKey/revokeKey 封装 - ProxyView.vue 三卡片:① 命中率-毛利看板(h_g/h_p/综合/收入/成本/毛利/分桶) ② 学生与 key 管理(建学生/签发(明文仅显一次警示)/充值/选中签发) ③ 用量流水表(时间/模型/状态徽标/收入/成本/毛利) - App.vue NAV + router 注册 /proxy;npm run build 产物更新 - 全量 423 passed
161 lines
3.8 KiB
Vue
161 lines
3.8 KiB
Vue
<template>
|
||
<div class="app">
|
||
<!-- 侧边导航(dsh 风格:近白 + 透明描边) -->
|
||
<aside class="side">
|
||
<div class="brand">
|
||
<div class="brand-logo">🤖</div>
|
||
<div class="brand-text">
|
||
<b>端云协同</b>
|
||
<span>编程智能体系统</span>
|
||
</div>
|
||
</div>
|
||
|
||
<nav class="nav">
|
||
<router-link v-for="item in NAV" :key="item.to" :to="item.to" class="nav-item">
|
||
<span class="nav-icon">{{ item.icon }}</span>
|
||
<span class="nav-label">{{ item.label }}</span>
|
||
</router-link>
|
||
</nav>
|
||
|
||
<div class="side-foot">
|
||
<div class="foot-dot" />
|
||
<span>本地网关 · :8000</span>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- 内容区 -->
|
||
<div class="main-col">
|
||
<router-view class="content" />
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
// App.vue — 侧边栏壳(deepseek-harness 配色:sidebar-fill 近白 + 品牌蓝点缀)
|
||
const NAV = [
|
||
{ to: '/chat', icon: '💬', label: '对话' },
|
||
{ to: '/collaboration', icon: '🔄', label: '协作过程' },
|
||
{ to: '/agent', icon: '🤖', label: '智能体' },
|
||
{ to: '/review', icon: '🔍', label: '人工检验' },
|
||
{ to: '/metrics', icon: '📊', label: '指标' },
|
||
{ to: '/proxy', icon: '🏷️', label: '代理' },
|
||
{ to: '/settings', icon: '⚙️', label: '设置' },
|
||
]
|
||
</script>
|
||
|
||
<style>
|
||
.app {
|
||
display: flex;
|
||
height: 100%;
|
||
}
|
||
|
||
/* ---------- 侧边栏(dsh:specific-sidebar-fill 近白) ---------- */
|
||
.side {
|
||
width: 208px;
|
||
flex-shrink: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: var(--c-side-bg);
|
||
border-right: 1px solid var(--c-side-border);
|
||
color: var(--c-side-text);
|
||
padding: 18px 12px 14px;
|
||
user-select: none;
|
||
}
|
||
|
||
.brand {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 4px 8px 16px;
|
||
margin-bottom: 12px;
|
||
}
|
||
.brand-logo {
|
||
width: 38px;
|
||
height: 38px;
|
||
display: grid;
|
||
place-items: center;
|
||
font-size: 20px;
|
||
background: linear-gradient(135deg, var(--ds-blue-400), var(--ds-blue-500));
|
||
border-radius: 11px;
|
||
box-shadow: 0 3px 10px rgba(65, 118, 230, 0.35);
|
||
}
|
||
.brand-text { display: flex; flex-direction: column; line-height: 1.3; }
|
||
.brand-text b { color: var(--c-text); font-size: 15px; letter-spacing: 0.5px; }
|
||
.brand-text span { font-size: 11px; color: var(--c-caption); }
|
||
|
||
.nav { display: flex; flex-direction: column; gap: 2px; flex: 1; }
|
||
|
||
.nav-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 11px;
|
||
padding: 8px 10px;
|
||
border-radius: 9px;
|
||
text-decoration: none;
|
||
color: var(--c-side-text);
|
||
font-size: 13.5px;
|
||
font-weight: 500;
|
||
position: relative;
|
||
transition: background 0.15s var(--ds-ease), color 0.15s var(--ds-ease);
|
||
}
|
||
.nav-item:hover { background: var(--c-side-hover); color: var(--c-text); }
|
||
.nav-item.router-link-active {
|
||
background: var(--c-side-active);
|
||
color: var(--c-side-text-active);
|
||
font-weight: 600;
|
||
}
|
||
.nav-item.router-link-active::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: -12px;
|
||
top: 7px;
|
||
bottom: 7px;
|
||
width: 3px;
|
||
border-radius: 0 3px 3px 0;
|
||
background: var(--c-accent);
|
||
}
|
||
.nav-icon {
|
||
width: 26px;
|
||
height: 26px;
|
||
display: grid;
|
||
place-items: center;
|
||
font-size: 15px;
|
||
background: var(--c-hover);
|
||
border-radius: 7px;
|
||
}
|
||
.nav-item.router-link-active .nav-icon { background: var(--c-primary-soft); }
|
||
|
||
.side-foot {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 7px;
|
||
padding: 12px 8px 2px;
|
||
font-size: 11px;
|
||
color: var(--c-caption);
|
||
}
|
||
.foot-dot {
|
||
width: 7px;
|
||
height: 7px;
|
||
border-radius: 50%;
|
||
background: var(--c-ok);
|
||
box-shadow: 0 0 6px rgba(34, 197, 94, 0.6);
|
||
}
|
||
|
||
/* ---------- 内容区 ---------- */
|
||
.main-col {
|
||
flex: 1;
|
||
min-width: 0;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: var(--c-surface);
|
||
}
|
||
.content {
|
||
flex: 1;
|
||
overflow: hidden;
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-height: 0;
|
||
}
|
||
</style>
|