# 需求: 应急降级页(H5 + Agent Preview)via 企微"服务窗口"

**需求提出**: 2026-06-15(经多次澄清,核心场景为 BC/DR)
**需求方**: Simon
**核心场景**: 🔴 **业务连续性(BC/DR)** — 系统故障时切换至企微原生服务,坐席保留关键功能
**入口**: 🏢 **企微"员工服务"应用 → "服务窗口"**(只配 1 个 URL)
**关联规则**: [[locked-decisions]] § 应急降级 / [[preview-pages-sync-rule]]

---

## 🎯 业务目标(真实场景)

当本系统出现**特殊情况**(故障 / 不可用 / 合规要求 / 流量过载)时:

1. **员工侧**: 切换至企微**原生员工服务**(群聊/单聊兜底)
2. **坐席侧**: 通过企微"员工服务 → 服务窗口" 链接,使用本系统应急页
3. **目标**: 即使主系统挂掉,**核心 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`:
  ```json
  {
    "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 (周五) | 正式版上线 + 应急页同步上线 |

## ⚠️ 应急场景的额外考虑

1. **入口要醒目**: 企微"员工服务 → 服务窗口"配置清晰描述
2. **不依赖登录**: 应急时坐席可能密码都改不了,免登
3. **非工作时间演练**: 降低对业务影响
4. **联系人降级**: 实在没预同步数据,提示"请手动搜索 IT支持-咨询坐席 标签"
5. **保留升级路径**: 主系统恢复后,应急页要有提示"主系统已恢复,建议返回"

## 🔗 关联

- **双端同步规则**: [[preview-pages-sync-rule]]
- **锁定决策**: [[locked-decisions]] § 应急降级
- **演练 SOP**: `docs/SOPs/SOP-005-应急降级演练.md`
- **需求演进**: v1 灰度(误)→ v2 BC/DR(理解)→ v3 服务窗口(1 URL)→ v4 标签联系人(动态)

---

🤖 Generated with [Claude Code](https://claude.com/claude-code)
