facc04aa65
本提交为 .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-*/
451 lines
16 KiB
Markdown
451 lines
16 KiB
Markdown
# 技术方案 — 管理后台 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`):
|
||
```diff
|
||
{
|
||
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`):
|
||
```css
|
||
.locked-menu-item {
|
||
pointer-events: none;
|
||
cursor: not-allowed;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. P1 单一真源重构
|
||
|
||
### 4.1 menu.config.ts 数据结构(232 行)
|
||
|
||
```ts
|
||
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 行)
|
||
|
||
```vue
|
||
<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 单文件实现
|
||
|
||
```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 设计
|
||
|
||
```ts
|
||
// 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`)
|
||
|
||
```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)
|
||
|
||
```ts
|
||
{
|
||
// 快速回复模板(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 路由改造
|
||
|
||
```diff
|
||
- {
|
||
- path: 'assignment-mode',
|
||
- name: 'AssignmentMode',
|
||
- component: () => import('@/views/AssignmentMode.vue'),
|
||
- meta: { title: '消息分配模式', priority: 'P1' },
|
||
- },
|
||
```
|
||
|
||
### 8.2 Agents.vue 双 Tab 改造
|
||
|
||
```vue
|
||
<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 代码层
|
||
|
||
- [x] 工程师 IS_PASS: YES(单文件最小变更)
|
||
- [x] 主理人 Grep 核对:行号 / 函数名 / 引用一致
|
||
- [x] QA 工程师六维回归 PASS(路由 entry / 组件独立 / name 唯一 / menu 对齐 / 无回归 / build 成功)
|
||
|
||
### 11.2 Build 层
|
||
|
||
- [x] `npm run build` 成功(9.57s, 2409 modules transformed, 51 chunks)
|
||
- [x] dist 总大小 3.32 MB / 89 文件
|
||
- [x] 主 chunk index-Dnr-1RNY.js (1173 KB)
|
||
|
||
### 11.3 部署层
|
||
|
||
- [x] 主机 dist md5 ↔ 服务器挂载目录 md5 一致
|
||
- [x] `curl http://localhost/itadmin/` HTTP 200
|
||
- [x] 关键路由抽查:dashboard / monitor / quick-rules / quick-rules-audit / quick-rules/template / permissions-matrix 全部 200
|
||
- [x] 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 重构全过程记录) |