本提交为 .git 对象库损坏后的重建提交,内容等价于原先三个本地提交 (5e2fd4c2 / 57a53c98 / 5d7e1873)的累积结果,未做任何额外改动。 一、docs 结构整改(整改 #14) 根因:重构时新结构为 untracked 文件,执行 git stash(未带 -u)未纳入, 随后 git reset 拉回 HEAD 旧 tracked 树,导致旧树复活、新旧两棵目录 树并存于 docs/,共 791 文件、双分类体系冲突。 修复动作: - b2 同名异主题文件改名迁移保全 9 个 - C 类 39 个孤立文件按主题正确归类 - A/B1 类 222 个重复文件删除(新结构已有内容副本) - 9 个旧独有空目录删除 - 270 处内部引用按 verified 映射改写 - 整改记录 #14 登记于 04-运维文档/部署运维 结果:docs 791 → 569 文件,顶层仅规范 8 类 + 治理文件,单树恢复。 残留:约 20 处指向从未存在文件的陈旧死链,归入独立文档卫生任务。 二、compose 双目录对齐(消除踩坑 A) - docker-compose.yml:nginx 前端挂载全部由根目录 frontend-*/dist 改为 src/frontend-*/dist(h5 / agent / admin / terminal) - docker-compose.dev.yml:dev 服务 build context 与卷同步改 src/ - 效果:本地 docker compose up 不再把根目录 stale dist 挂回, 与线上一致,分叉隐患消除(已 docker compose config 校验通过) 防复发铁律: - 重构须提交;仓库修复须 git stash -u 或先 commit - 新结构须 git add 并提交,避免再次 untracked 复活 - H5 改动只动 src/frontend-h5/,禁改根目录遗留 frontend-*/
16 KiB
技术方案 — 管理后台 v1.2 IA 重构整体
版本: v1.2 | 日期: 2026-07-28 作者: 宋献 · 主理人齐活林(Qi) · 高见远(Gao) 关联 PRD:
docs/01-产品文档/08-集成生态/PRD-REQ-集成-002-管理后台-v1.2.md关联原型:docs/01-产品文档/08-集成生态/原型-REQ-集成-000-管理后台-v1.0.html任务说明书:docs/07-项目管理/任务说明书/任务说明书-REQ-集成-002-IA重构整体.md状态: ✅ 已实施(生产环境上线 2026-07-28)
1. 目标
把管理后台从 v1.0 的「4 组按优先级」导航重构为 v1.1 的「5 组按用户场景」结构,覆盖完整 27 项功能域(v1.0 漏列 12 项),并通过单一真源 menu.config.ts 消除「Sidebar 与 router 双重维护脱节」的历史包袱。
本次重构由 6 个阶段组成:
| 阶段 | 内容 | 优先级 | 状态 |
|---|---|---|---|
| P0 | 三 bug 修复(router 重复 / sidebar 漏权限矩阵 / locked-menu-item 可点) | P0 | ✅ 已上线 |
| P1 | 单一真源 menu.config.ts 重构(5 组 27 项 + 子标签 + 角色过滤) | P1 | ✅ 已上线 |
| P1-b | Dashboard 嵌入会话监控 widget(双视图:Dashboard 概览 + /monitor 详情) | P1 | ✅ 已上线 |
| P2-a | /quick-rules-audit 顶级路由补全 |
P2 | ✅ 已上线 |
| P2-c | /quick-rules/template 路由 child 补全(复用 QuickReplies.vue) |
P2 | ✅ 已上线 |
| v1.2 | 分配模式 Tab 收编到坐席管理 | P2 | 🟡 待实施 |
2. 整体架构
2.1 5 组导航结构(v1.1 替代 v1.0 4 组)
🟦 运营中心(7 项 · 实时作战 + 实时监控)
运营总览 / 会话监控 / 坐席管理 / 角色管理 / 权限矩阵 / OTP 管理 / 功能开关
🟪 数据与监控(4 项 · 离线分析 + AI 指标)
会话审计 / 坐席绩效 / 满意度评价 / 自动化指标
🟥 安全审计(5 项 · 合规追溯 + 系统安全)
配置变更历史 / 运行期日志 / 安全审计日志 / 终端安全 / 快速回复审计日志
🟩 系统与集成(4 项 · 底层能力配置)
系统集成 / 欢迎与引导 / 自动化场景 / 规则版本
🟪 知识与 AI(7 项 · 配置规则 + 知识沉淀 + 智能建议)
快速回复规则 / 排查流程图 / 代答排除 / 知识迭代 / RAGFlow / 拓扑预览 / 知识库建议
2.2 单一真源架构
menu.config.ts(单一真源)
├─ groups[] // 5 个分组(顺序、图标、颜色)
├─ items[] // 27 项业务菜单
├─ quickRulesSubTabs[] // 快速回复规则页 5 子 tab
├─ lockedItems[] // 3 个 P2 折叠区占位
└─ rolesFilter // 按角色过滤的字段
↓ 派生
Sidebar.vue // v-for 渲染,零硬编码
router/index.ts // 从 menuConfig 派生路由(meta.menuKey 反查)
收益:新增菜单仅改 menu.ts,自动出现在 Sidebar + router + 角色过滤三处。
3. P0 三 bug 修复
3.1 router 重复注册
症状:router/index.ts L87 + L201 重复注册 path: 'knowledge',后注册 Placeholder 覆盖 Knowledge.vue,导致真页面成死代码。
修复(router/index.ts):
{
path: 'knowledge',
name: 'Knowledge',
component: () => import('@/views/Knowledge.vue'),
},
+ {
+ path: 'knowledge-mgmt', // 占位路由改名避免冲突
+ name: 'KnowledgeMgmt',
+ component: () => import('@/views/Placeholder.vue'),
+ meta: { title: '知识库管理', priority: 'P2', locked: true },
+ }
3.2 Sidebar 漏权限矩阵
症状:/permissions-matrix 路由已注册但 Sidebar 完全没显示(菜单与路由双重维护脱节典型案例)。
修复(P1 阶段由 menu.config.ts 自动修复,菜单项已在 menu.ts 声明)。
3.3 locked-menu-item 可点击
症状:.locked-menu-item { pointer-events: auto !important } 让"开发中"灰化菜单仍可点击,误导用户。
修复(Sidebar.vue 或 global.css):
.locked-menu-item {
pointer-events: none;
cursor: not-allowed;
}
4. P1 单一真源重构
4.1 menu.config.ts 数据结构(232 行)
export const menuConfig = {
groups: [
{ key: 'operation', label: '运营中心', icon: 'Operation', color: '#3b82f6', order: 1 },
{ key: 'monitor', label: '数据与监控', icon: 'Monitor', color: '#8b5cf6', order: 2 },
{ key: 'security', label: '安全审计', icon: 'Security', color: '#ef4444', order: 3 },
{ key: 'system', label: '系统与集成', icon: 'System', color: '#10b981', order: 4 },
{ key: 'ai', label: '知识与 AI', icon: 'AI', color: '#ec4899', order: 5 },
],
items: [
// 27 项业务菜单,每项包含 path/title/icon/groupKey/roles/badge
],
quickRulesSubTabs: [
{ key: 'greeting', label: '打招呼' },
{ key: 'contacts', label: '联系人' },
{ key: 'routing', label: '路由关键词' },
{ key: 'targets', label: '路由目标' },
{ key: 'template', label: '模板', badge: 'v5 收编' },
],
lockedItems: [
{ key: 'themes', label: '主题模板', stage: '阶段二' },
{ key: 'dashboard-board', label: '数据看板', stage: '阶段四' },
{ key: 'knowledge-mgmt', label: '知识库管理', stage: '阶段四' },
],
rolesFilter: ['admin', 'super_admin'],
}
4.2 Sidebar.vue 重构(282 → 222 行)
<template>
<el-menu :default-active="activeRoute">
<template v-for="group in menuConfig.groups" :key="group.key">
<el-sub-menu :index="group.key">
<template #title>
<el-icon><component :is="group.icon" /></el-icon>
<span>{{ group.label }}</span>
</template>
<template v-for="item in itemsOfGroup(group.key)" :key="item.path">
<el-menu-item :index="item.path" :disabled="isLocked(item)">
<el-icon><component :is="item.icon" /></el-icon>
<span>{{ item.title }}</span>
<el-badge v-if="item.badge" :value="item.badge" class="menu-badge" />
</el-menu-item>
</template>
</el-sub-menu>
</template>
<!-- 折叠区占位 -->
<el-sub-menu v-for="locked in lockedItems" :key="locked.key" class="locked-menu-item">
...
</el-sub-menu>
</el-menu>
</template>
4.3 图标替换诚实记录
| 原计划 | 实际使用 | 原因 |
|---|---|---|
Shield(终端安全) |
Warning |
与原 sidebar 一致 |
Bulb(知识库建议) |
Sunny |
element-plus/icons-vue@2.3.0 不存在 Bulb |
5. P1-b Dashboard 嵌入会话监控 widget
5.1 双视图设计(Datadog/Grafana 同款)
Dashboard 概览(/admin/dashboard)
├─ 第一行 4 张核心 KPI(在线坐席/今日会话/平均响应/AI 命中率)
├─ 第二行 3 张副卡(进行中/等待中/异常告警)
├─ 🆕 实时会话 Top 5 widget
├─ 待处理事项
└─ 系统健康
会话监控详情(/admin/monitor)
└─ 完整会话表格 + 详情
5.2 Dashboard.vue 单文件实现
<template>
<!-- 原有 KPI + 待处理 + 系统健康 -->
<!-- 🆕 实时会话监控 widget -->
<div class="monitor-widget">
<div class="widget-header">
<h3>实时会话监控</h3>
<el-button text @click="$router.push('/admin/monitor')">
查看全部 →
</el-button>
</div>
<div class="monitor-stats">
<StatCard label="进行中" :value="monitorStats.in_progress" color="green" />
<StatCard label="等待中" :value="monitorStats.queued" color="yellow" />
<StatCard label="今日已结" :value="monitorStats.resolved_today" color="blue" />
<StatCard label="异常告警" :value="monitorStats.alerts" color="red" />
</div>
<el-table :data="monitorSessions.slice(0, 6)" stripe>
<el-table-column prop="session_id" label="会话 ID" />
<el-table-column prop="employee_name" label="员工" />
<el-table-column prop="agent_name" label="坐席" />
<el-table-column label="持续时长">
<template #default="{ row }">{{ formatDuration(row.started_at) }}</template>
</el-table-column>
<el-table-column label="状态">
<template #default="{ row }">
<el-tag :type="getSessionStatusTag(row.status)">
{{ getSessionStatusText(row.status) }}
</el-tag>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup lang="ts">
import { getMonitorSessions } from '@/api/admin'
import type { MonitorSession, MonitorStats } from '@/types'
const monitorStats = reactive<MonitorStats>({
in_progress: 0, queued: 0, resolved_today: 0, alerts: 0,
})
const monitorSessions = ref<MonitorSession[]>([])
onMounted(async () => {
try {
const res = await getMonitorSessions()
Object.assign(monitorStats, res.stats)
monitorSessions.value = res.items
} catch (err) {
// Demo 兜底(与 Monitor.vue 一致)
monitorStats.in_progress = 5
monitorStats.queued = 0
monitorStats.resolved_today = 42
monitorStats.alerts = 1
monitorSessions.value = [...]
}
})
// 复用 formatDuration / getSessionStatusTag / getSessionStatusText
</script>
5.3 API 设计
// api/admin.ts
export async function getMonitorSessions(params?: { limit?: number }) {
return request<MonitorSessionsData>({
url: '/admin/monitor/sessions',
method: 'get',
params,
})
}
export interface MonitorStats {
in_progress: number
queued: number
resolved_today: number
alerts: number
}
export interface MonitorSession {
session_id: string
employee_name: string
agent_name: string
status: 'pending' | 'active' | 'resolved' | 'abandoned'
started_at: string
}
export interface MonitorSessionsData {
stats: MonitorStats
items: MonitorSession[]
}
6. P2-a /quick-rules-audit 顶级路由补全
6.1 修复内容(router/index.ts)
{
// 快速回复审计日志(v1.1 从快速回复规则组移至安全审计组)
path: 'quick-rules-audit',
name: 'QuickRulesAuditLog',
component: () => import('@/views/quick-rules/audit.vue'),
meta: { title: '快速回复审计日志', requiresAuth: true },
},
复用现有 views/quick-rules/audit.vue,name 与嵌套 QuickRulesAudit 区分避免冲突。
7. P2-c /quick-rules/template 路由 child 补全
7.1 修复内容(router/index.ts L219-225)
{
// 快速回复模板(v5 收编:菜单已配于 menu.ts L197;复用旧 QuickReplies.vue 组件)
path: 'quick-rules/template',
name: 'QuickRulesTemplate',
component: () => import('@/views/QuickReplies.vue'),
meta: { title: '快速回复模板', requiresAuth: true },
},
复用现有 views/QuickReplies.vue(独立页面组件,用全局 quickReplyStore Pinia 单例,无父级 route props 依赖,安全作 route component)。
8. v1.2 分配模式 Tab 收编(待实施)
8.1 路由改造
- {
- path: 'assignment-mode',
- name: 'AssignmentMode',
- component: () => import('@/views/AssignmentMode.vue'),
- meta: { title: '消息分配模式', priority: 'P1' },
- },
8.2 Agents.vue 双 Tab 改造
<el-tabs v-model="activeTab" class="agents-tabs">
<el-tab-pane label="坐席列表" name="agents-list">
<!-- 原 toolbar + AgentTable + 三个 dialog -->
</el-tab-pane>
<el-tab-pane label="分配策略" name="agents-assignment">
<div class="page-desc">
当前坐席 {{ agentStore.agents.length }} 人...
</div>
<div class="mode-card" v-for="mode in modes" :key="mode.id">
<!-- 复用 AssignmentMode.vue 的 mode-card -->
</div>
</el-tab-pane>
</el-tabs>
8.3 旧页面保留
views/AssignmentMode.vue 保留但停用(不删除),方便阶段二/三分配策略膨胀时回滚为独立页。
8.4 后端零改动
仍走 system_configs.assignment_mode + GET/PUT /api/admin/assignment-mode。
9. 关键技术决策
| # | 决策 | 理由 |
|---|---|---|
| 1 | 单一真源 menu.config.ts | 消除「Sidebar 与 router 双重维护脱节」;新增菜单仅改 1 文件 |
| 2 | 5 组按用户场景分组(v1.1) | v1.0 按优先级分组不符合实际运营场景;安全审计类功能分散 |
| 3 | 快速回复审计移出知识与 AI 组 | 审计类功能属安全合规范畴,不应混杂在业务规则配置组 |
| 4 | 终端安全移入安全审计组 | 终端安全是合规管控(联软/火绒),与底层引擎集成性质不同 |
| 5 | 快速回复模板作为 tab 收编 | 与快速回复规则同属「快速回复」业务的不同维度 |
| 6 | Dashboard widget + /monitor 双视图 | 用户进 Dashboard 即见实时状态,无需跳转(Datadog/Grafana 同款) |
| 7 | P2 路由补全复用既有组件 | audit.vue 与 QuickReplies.vue 已有完整实现,避免重复 |
| 8 | v1.2 分配模式 Tab 收编可逆 | 旧 AssignmentMode.vue 保留文件 + 回滚步骤文档化 |
10. 风险与回滚
| 风险 | 概率 | 影响 | 缓解 |
|---|---|---|---|
| menu.config.ts 数据错误导致菜单错位 | 低 | 用户困惑 | 双重核对(sidebar 渲染 + 路由可达) |
| 子标签 / 角色过滤边界 | 低 | 普通管理员看到超管菜单 | menuConfig.rolesFilter 字段校验 |
| Tab 切换时数据二次请求 | 低 | 网络浪费 | watch(activeTab) 懒加载或一次性加载 |
| 旧页面成僵尸代码 | 低 | 维护混淆 | 注释中写明"vX.Y 起停用,仅供回滚" |
| 阶段二/三分配模式复杂化需拆回 | 中 | 需重构 | 已记录回滚步骤,30 分钟内可逆 |
回滚预案:
- 服务器
/tmp/dist-template-deploy.zip+/tmp/dist-widget.zip(最近 2 个 dist 包,保留 7 天) - 各版本 dist md5 在 memory 记录中可查(af00cf1c→a0c93a6c→6e8933dd→6f261495)
11. 验证清单(端到端三层验证)
11.1 代码层
- 工程师 IS_PASS: YES(单文件最小变更)
- 主理人 Grep 核对:行号 / 函数名 / 引用一致
- QA 工程师六维回归 PASS(路由 entry / 组件独立 / name 唯一 / menu 对齐 / 无回归 / build 成功)
11.2 Build 层
npm run build成功(9.57s, 2409 modules transformed, 51 chunks)- dist 总大小 3.32 MB / 89 文件
- 主 chunk index-Dnr-1RNY.js (1173 KB)
11.3 部署层
- 主机 dist md5 ↔ 服务器挂载目录 md5 一致
curl http://localhost/itadmin/HTTP 200- 关键路由抽查:dashboard / monitor / quick-rules / quick-rules-audit / quick-rules/template / permissions-matrix 全部 200
- nginx bind mount 源路径:
/opt/wecom-it-desk/frontend-admin/dist/(带 dist 后缀)
11.4 浏览器层
- 用户登录后 1-click 视觉确认(agent-browser 自动化 / 人工)
- 关键页面:Dashboard 会话监控 widget / 5 组导航 / 快速回复模板 tab
12. 变更日志
| 版本 | 日期 | 变更 | 变更人 | 影响范围 |
|---|---|---|---|---|
| v1.0 | 2026-07-28 12:00 | 初版(仅覆盖分配模式 Tab 收编) | 宋献 | §8 |
| v1.1 | 2026-07-28 13:00 | 扩展为 IA 重构整体(P0+P1+P2) | 宋献 | §1-§7, §9-§11 |
| v1.2 | 2026-07-28 16:30 | 三件套对齐,标记「分配模式 Tab 收编」为待实施 | 宋献 | §8 标记 🟡 待实施 |
13. 关联文档
- PRD v1.2:
docs/01-产品文档/08-集成生态/PRD-REQ-集成-002-管理后台-v1.2.md - 任务说明书 v1.2:
docs/07-项目管理/任务说明书/任务说明书-REQ-集成-002-IA重构整体.md - 原型 HTML:
docs/01-产品文档/08-集成生态/原型-REQ-集成-000-管理后台-v1.0.html(v1.1 已同步更新) - 整改记录:
docs/04-运维文档/部署运维/00-文档规范化整改记录.md(新增整改 #6 - IA 重构三件套补齐) - memory 日志:
D:\资料\03-项目开发\wecom_it_smart_desk\.workbuddy\memory\2026-07-28.md(IA 重构全过程记录)