364e688382
主要改动: backend 业务: - feat(error-codes): 统一错误码表 E1011/E1012 拆码 - E1011 AUTH_PASSWORD_WRONG: 本地密码错误 - E1012 AUTH_FIRST_LOGIN_PASSWORD_REQUIRED: 首次登录请先设置密码 - E1015 AUTH_OLD_PASSWORD_REQUIRED: 改密需要旧密码 - E1016 AUTH_OLD_PASSWORD_WRONG: 旧密码错误 - fix(agents): P0 降级放行时,如坐席已注册但未设密码,正确 raise 1012 (修复前会撞 1011 本地密码错误,与场景不符) - feat(approval): 审批模块 (T审批/A审批) - feat(config): approval_template_resource / approval_template_device 配置 - feat(main): /ready, /metrics, /version 端点(K8s 友好) backend 测试: - test(agents): 新增 test_agents.py — 3 个 Fix-4 降级登录测试 - 错误密码拒绝 - 缺密码拒绝 - 正确密码通过 pytest tests/test_agents.py → 3/3 通过 - test(conftest): 模块级 mock + slowapi 限流重置 + UTF-8 patch 解决 Windows pytest GBK 读 .env 失败 + 降级路径无法测试 仓库治理: - chore(gitignore): 排除 .workbuddy/memory/(workbuddy 本地记忆) - chore(docs): 重命名两份 IT 文档(前缀加智能区分版本) 部署与文档: - docs: RELEASE_NOTES_v0.5.0-beta.md / dashboard.html / 需求-发版预览页面 - docs: 部署、架构、PRD、安全、评审报告等同步 v0.5.0-beta - deploy-server: 打包脚本、nginx、docker-compose 版本号 bump 前端 (frontend-h5 / frontend-agent / frontend-admin / frontend-portal): - index.html / package.json 版本号与构建号 bump 自动验收(RELEASE_NOTES L100-104): - [x] pytest tests/test_agents.py -v → 3 passed - [x] grep Bs7ucT backend frontend-h5 frontend-agent → 无输出 - [x] grep AppException(101[123]) backend → 仅 1 处(登录场景 1012) - [ ] npm run build (frontend-h5 / frontend-agent) → 合并后跑 后续: 合并 feature/t-1-t4-merge → main,tag v0.5.0-beta
8.7 KiB
8.7 KiB
需求: 应急降级页(H5 + Agent Preview)via 企微"服务窗口"
需求提出: 2026-06-15(经多次澄清,核心场景为 BC/DR) 需求方: Simon 核心场景: 🔴 业务连续性(BC/DR) — 系统故障时切换至企微原生服务,坐席保留关键功能 入口: 🏢 企微"员工服务"应用 → "服务窗口"(只配 1 个 URL) 关联规则: locked-decisions § 应急降级 / preview-pages-sync-rule
🎯 业务目标(真实场景)
当本系统出现特殊情况(故障 / 不可用 / 合规要求 / 流量过载)时:
- 员工侧: 切换至企微原生员工服务(群聊/单聊兜底)
- 坐席侧: 通过企微"员工服务 → 服务窗口" 链接,使用本系统应急页
- 目标: 即使主系统挂掉,核心 IT 服务不中断
🏢 入口架构(1 URL + 企微 JS-SDK)
┌────────────────────────────────────────┐
│ 企微"员工服务"应用(企业已建) │
│ └─ "服务窗口" tab(只能配 1 个 URL) │
│ └─ https://itsupport.servyou.com.cn/emergency
└────────────────────────────────────────┘
↓
┌────────────────────────────────────────┐
│ /emergency 页面(身份检测) │
│ 1. 加载企微 JS-SDK(不依赖本后端) │
│ 2. agentConfig 拿当前 userid │
│ 3. 调企微通讯录 API 查 user 详情 │
│ 4. 判断身份:是"IT支持-咨询坐席"标签成员 │
│ ├─ 是 → router.push('/agent/preview')│
│ └─ 否 → router.push('/h5/preview') │
└────────────────────────────────────────┘
关键:
- 身份检测不依赖本系统后端(主系统挂时仍可用)
- 应急页 2 套(h5 + agent),通过 router.push 切换
- 企微通讯录 API 走企微 access_token,跟主系统无关
📋 保留功能(4 件套 + 动态联系人)
| # | 功能 | 描述 | 数据源 |
|---|---|---|---|
| 1 | 🔍 快速回复模板 | 100+ 条按关键词搜索 | mock JSON → localStorage |
| 2 | 🔍 排障流程模板 | vpn/邮箱/系统/账号 4 大类 | mock JSON → localStorage |
| 3 | 📋 资源/审批链接 | 12 个常用入口 | mock JSON → localStorage |
| 4 | 👥 应急联系人 | 企微标签"IT支持-咨询坐席"成员 | 企微 API → 单独 localStorage |
| 合计 | ~750KB + 联系人列表 |
应急联系人(动态,非固定)
数据源: 企微通讯录标签"IT支持-咨询坐席"
预同步:
- 主系统正常时,每 30 分钟调企微通讯录 API 查该标签成员
- 存到独立 localStorage key
emergency_contacts:{ "synced_at": "2026-06-15T10:00:00", "tag_id": "TAG_xxx", "members": [ {"userid": "zhangsan", "name": "张三", "avatar": "...", "online": true}, ... ] }
应急展示:
- 列出标签下所有成员
- 在线/离线状态(企微 status 接口)
- 点击 → 打开企微单聊
- 数据 > 1 小时未更新时标红,提示"联系人可能不准,建议手动搜索标签组"
🆘 "特殊情况" 触发与降级
| 类型 | 触发条件 | 降级动作 |
|---|---|---|
| 🔴 主系统完全不可用 | API 5xx / 网络断开 | 切企微原生 + 服务窗口 |
| 🟡 部分功能故障 | 消息发送失败 / 排队堵死 | 切企微原生 + 工具走应急页 |
| 🟠 合规要求 | 必须用企微审计 | 切企微原生 + 应急页工单 |
| 🟢 流量过载 | 服务降级中 | 部分功能走应急页 |
📋 范围
| 项 | H5 应急页 | Agent 应急页 |
|---|---|---|
| URL | /h5/preview |
/agent/preview |
| 统一入口 | /emergency |
/emergency |
| 显示组件 | RightPanel.vue(3 段式) |
AiAssistantPanel.vue(4 件套) |
| 去除功能 | ChatPanel(聊天走企微原生) |
ConversationList + ChatArea + TopBar |
| 数据源 | 预同步到 localStorage | 预同步到 localStorage |
| 后端调用 | 无(主系统可能挂) | 无 |
| 用户登录 | 跳过(应急场景免登) | 跳过(应急场景免登) |
🔄 数据预同步机制(2 个独立 localStorage)
localStorage #1: emergency_data(静态工具数据)
正常态:
主后端 /api/emergency-data
→ 前端每 30 分钟拉取
→ 存到 localStorage("emergency_data")
应急态:
localStorage("emergency_data") → 应急页直接渲染
内容: 快速回复 / 排障 / 资源(~750KB)
localStorage #2: emergency_contacts(动态联系人)
正常态:
企微通讯录 API 查"IT支持-咨询坐席"标签
→ 前端每 30 分钟拉取
→ 存到 localStorage("emergency_contacts")
应急态:
localStorage("emergency_contacts") → 应急页渲染联系人列表
内容: 标签成员列表(动态,可能多人)
🎨 页面要求(应急场景)
/emergency(身份检测入口,~50 行)
- 加载企微 JS-SDK(wx.config + wx.agentConfig)
- 拿当前 userid
- 调企微通讯录 API 查 user 详情 + 标签
- 判断是否含"IT支持-咨询坐席"标签
- 是坐席 → push /agent/preview,否则 → push /h5/preview
- 检测失败 → 显示"请选择身份"2 个大按钮兜底
H5 应急页(/h5/preview)
- 顶部: 项目名 + "🆘 应急模式" 红色徽章 + 数据更新时间
- 主体:
RightPanel全宽,3 段式(AI 推送 / 资源 / 趣味问答) - 底部: 固定"主系统异常?此页面帮您继续获得服务"
- 移动端: 强制显示(覆盖
isMobile判断)
Agent 应急页(/agent/preview)
- 顶栏: 简化版 TopBar + 🆘 徽章
- 主体:
AiAssistantPanel全宽,4 件套 - 联系人: 标签组成员 + 在线状态
- 底部: 固定"主系统异常"提示
📁 文件改动清单(调整)
H5 端 (frontend-h5/)
| 操作 | 路径 | 说明 |
|---|---|---|
| 新建 | src/views/EmergencyEntry.vue |
身份检测入口(~50 行) |
| 新建 | src/views/H5PreviewView.vue |
应急主页 |
| 新建 | src/mock/emergency-data.json |
应急静态数据 |
| 新建 | src/utils/emergency-sync.ts |
同步工具(2 个 localStorage) |
| 改 | src/router/index.ts |
加 /emergency + /h5/preview |
| 复用 | src/components/assistant/RightPanel.vue |
import 共享 |
Agent 端 (frontend-agent/)
| 操作 | 路径 | 说明 |
|---|---|---|
| 新建 | src/views/AgentPreviewView.vue |
应急主页 |
| 改 | src/router/index.ts |
加 /agent/preview |
| 复用 | src/components/assistant/AiAssistantPanel.vue |
import 共享 |
注: 联系人 API 调用放 emergency-sync.ts 共用模块,h5 + agent 都用
🧪 验收标准
功能验收
- 断网测试: 拔网线/关后端 → 应急页仍能打开
- 身份自动路由: 员工点开 → /h5/preview,坐席点开 → /agent/preview
- 联系人动态: 标签组加新人,预同步后能显示
- 数据新鲜度: 顶部"数据 X 分钟前更新",> 1h 标红
- 2 个 localStorage 独立工作: 删 emergency_data 不影响 emergency_contacts
灾备演练(非工作时间,本月必做)
- 选择非工作时间(晚上 / 周末)
- 模拟主系统挂掉 → 切企微原生服务 → 坐席用应急页
- 演练时长 / 解决率 / 痛点记录
- 详见
docs/SOPs/SOP-005-应急降级演练.md
📅 排期
| 时间 | 任务 |
|---|---|
| 2026-06-16 (周一) | WB 接单,1 入口 + 2 页面 + 1 mock + 1 同步工具 + 2 路由 |
| 2026-06-16 (周一) | 本地 npm run build 验证 |
| 2026-06-17 (周二) | 部署 + 断网演练(非工作时间,如周二晚 20:00) |
| 2026-06-18 (周三) | 收集问题,迭代 |
| 2026-06-19 (周四) | 二次演练确认 |
| 2026-06-20 (周五) | 正式版上线 + 应急页同步上线 |
⚠️ 应急场景的额外考虑
- 入口要醒目: 企微"员工服务 → 服务窗口"配置清晰描述
- 不依赖登录: 应急时坐席可能密码都改不了,免登
- 非工作时间演练: 降低对业务影响
- 联系人降级: 实在没预同步数据,提示"请手动搜索 IT支持-咨询坐席 标签"
- 保留升级路径: 主系统恢复后,应急页要有提示"主系统已恢复,建议返回"
🔗 关联
- 双端同步规则: preview-pages-sync-rule
- 锁定决策: locked-decisions § 应急降级
- 演练 SOP:
docs/SOPs/SOP-005-应急降级演练.md - 需求演进: v1 灰度(误)→ v2 BC/DR(理解)→ v3 服务窗口(1 URL)→ v4 标签联系人(动态)
🤖 Generated with Claude Code