Files
wecom_it_smart_desk/docs/02-技术文档/技术方案-REQ-集成-002-管理后台v1.2-IA重构整体.md
Simon facc04aa65 chore: docs 结构整改 + compose 双目录对齐(合并重建提交)
本提交为 .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-*/
2026-08-07 22:31:32 +08:00

451 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 技术方案 — 管理后台 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 重构全过程记录)