# 2026-06-13 工作记录

## H5端邀请功能后续开发

### 后端改动
1. **h5.py** — 新增3个H5专用参与者端点（带员工认证）：
   - `POST /h5/conversations/{id}/join` — 被邀请人加入会话（`_get_current_employee` 认证）
   - `POST /h5/conversations/{id}/leave-participant` — 参与者退出会话（`_get_current_employee` 认证）
   - `GET /h5/conversations/{id}/participants` — 获取参与者列表（`_get_current_employee` 认证）
   - 安全校验：employee_id 从 Token 自动获取，无需前端传递，防止冒充

### H5前端改动
2. **api/conversation.ts** — API路径统一为 `/h5/` 前缀：
   - `joinConversation(conversationId)` — 移除 employeeId 参数，路径改为 `/h5/conversations/{id}/join`
   - `leaveAsParticipant(conversationId)` — 移除 employeeId 参数，路径改为 `/h5/conversations/{id}/leave-participant`
   - `getParticipants(conversationId)` — 路径改为 `/h5/conversations/{id}/participants`（独立端点）
   - `ConversationInfo` 类型新增 `employee_name` 字段

3. **stores/conversation.ts** — `leaveAsParticipant()` 不再传递 employeeId

4. **views/ChatView.vue** — `joinConversationApi(inviteId)` 不再传递 eid

5. **components/chat/ParticipantList.vue** — 修复发起人姓名显示：
   - 当发起人不是当前用户时，显示 `conv.employee_name`（真实姓名）而非固定的"员工"

### 编译验证
- 后端 py_compile ✅（h5.py）
- H5前端 vue-tsc --noEmit ✅
- H5前端 vite build ✅

## 管理后台 — 角色管理界面开发

### 说明
后端 RBAC 角色系统（模型/API/服务/Schema/迁移）已全部完成，但前端管理后台零实现。
本次补齐前端角色管理 UI 层。

### 改动文件

1. **frontend-admin/src/types/index.ts** — 新增角色管理类型定义：
   - `Role`（角色信息，含 permissions JSON 数组、user_count）
   - `UserRole`（用户角色关联，含 source/assigned_by/expires_at）
   - `UserRoleSource`（来源类型：auto/tag/ehr/manual）
   - `RoleMappingRule`（映射规则，含 source_type/source_value/priority）
   - `MappingSourceSource`（映射来源：wecom_tag/ehr_position）
   - `RoleAssignRequest` / `RoleRevokeRequest` / `RoleMappingRuleRequest`
   - `ROLE_SOURCE_LABELS` / `MAPPING_SOURCE_LABELS` 常量

2. **frontend-admin/src/api/admin.ts** — 新增 6 个 API 调用函数：
   - `getRoles()` — 获取所有角色列表
   - `assignRole()` — 手动分配角色
   - `revokeRole()` — 撤销角色
   - `getRoleMappingRules()` — 获取映射规则
   - `createRoleMappingRule()` — 创建映射规则
   - `deleteRoleMappingRule()` — 删除映射规则

3. **frontend-admin/src/views/Roles.vue** — 新建角色管理页面：
   - 角色卡片网格（3 个预置角色：用户/坐席/管理员，含用户数+权限数+权限标签）
   - 用户角色分配表格（employee_id/角色/来源/分配者/时间/操作）
   - 自动映射规则表格（目标角色/来源类型/匹配值/优先级/状态/操作）
   - 4 个对话框：分配角色、撤销确认、新建映射规则
   - Demo fallback 数据（API 不可用时的降级展示）

4. **frontend-admin/src/router/index.ts** — 新增路由：
   - `/roles` → `Roles.vue`，meta.title = "角色管理"

5. **frontend-admin/src/components/Sidebar.vue** — 新增菜单项：
   - "运营管理" 分组下添加"角色管理"（Key 图标），位于"坐席管理"之后

### 编译验证
- 前端 vite build ✅（Roles-4zcp3cuz.js 13.33 kB，gzip: 4.48 kB）
- 仅 @vueuse/core Rollup 注解警告和 chunk 大小警告（非本次引入）

## 正式服务器部署

### 迁移修复
- **007_role_system.py** — 修复 PostgreSQL 兼容性：`datetime('now')` → `NOW()`
- SQLite 的 `datetime('now')` 在 PostgreSQL 中不存在，导致后端启动失败

### 部署记录
- 部署包已生成：`deploy-server/it-smart-desk-server-deploy.zip` (1.48 MB)
- 包含：3个前端 dist + 后端代码 + docker-compose.yml + .env + nginx.conf
- ⚠️ **服务器文件上传限制**：10.90.5.110 无法使用 scp，只能通过堡垒机手动上传
- 部署流程：下载部署包 → 通过堡垒机上传到 /tmp/ → 解压 → docker compose build --no-cache backend → up -d

---

## 未完成任务收尾（下午）

### 任务进度确认
- 代码审查确认 #148/#155（H5端邀请功能）**已完整实现**，包括：
  - ParticipantList.vue 完整组件（展示+退出+确认弹窗）
  - conversation.ts store（inviteParticipant/leaveAsParticipant/joinConversation）
  - API层（joinConversation/leaveAsParticipant/getParticipants）
  - ChatView.vue 邀请链接加入流程
  - WebSocket 实时推送（participant_invited/joined/removed/left 事件）
- 标记 #148、#155 为 completed

### #151 H5登录Bug修复（4项）
1. **isAuthenticated 增加 JWT 过期检查**：新增 `isTokenExpired()` 函数，解析 JWT payload 的 exp 字段，60秒安全余量
2. **消除循环依赖**：新建 `utils/authCallback.ts` 独立回调注册中心，打破 api/index.ts ↔ stores/employee.ts 循环依赖
3. **并发401去重**：`_authExpiredPromise` 去重锁，首个401获取锁执行处理，后续复用同一Promise
4. **Portal Token URL安全加固**：使用 URLSearchParams 精确删除 token/code/state 参数，history.replaceState 立即清除

### #156 术语替换 + UI风格更新
**术语替换**：
- "举手"→"招手"（agent 6文件+h5 4文件，约25处）
- "铃铛"→"传菜铃"（H5端2文件6处）
- "申请"→无需替换（均为业务数据内容）

**CSS变量体系更新为企微风格**：
- `--accent`: #3b82f6 → #07C160（企微绿）
- `--bg-primary`: #f5f7fa → #f7f7f7
- `--bg-tertiary`: #f0f2f5 → #ededed
- `--text-primary`: #1e293b → #191919
- `--text-secondary`: #64748b → #666666
- `--text-tertiary`: #94a3b8 → #999999
- `--border`: #e2e8f0 → #e5e5e5
- `--radius`: 6px → 8px, `--radius-lg`: 10px → 12px
- H5 `--color-shake-start/end`: 橙色渐变 → 绿色渐变
- 深色主题变量保持不变

### #149 端到端验证
- 阻塞已解除（#148/#151已完成）
- 待用户在实际环境中执行全链路验证

### 部署方案讨论
- 确认 NAS 测试环境在企微 OAuth2 认证下价值大幅降低
- 确定双企微应用方案（正式应用+测试应用），因公司子域名申请困难
- 正式上线前：正式=10.90.5.10, 测试=NAS
- 正式上线后：正式=高可用架构, 测试=10.90.5.10

---

## 部署包打包 + 调试验证指南（11:00）

### 部署包清单

| 文件 | 大小 | 内容 |
|------|------|------|
| deploy-h5.tar | 0.6 MB | frontend-h5/dist/（含JWT过期检查+企微绿风格） |
| deploy-agent.tar | 2.0 MB | frontend-agent/dist/（含术语替换+企微绿风格） |
| deploy-admin.tar | 1.7 MB | frontend-admin/dist/ |
| deploy-portal.tar | 1.53 MB | frontend-portal/dist/ |
| deploy-backend.tar | 11.02 MB | backend/ |

### 调试验证指南
- 创建 `docs/调试验证指南_2026-06-13.md`
- 包含端到端验证清单（11个验证项）
- 包含测试企微应用创建步骤（6个步骤）
- 包含环境切换方案和常见问题排查

---

## 管理后台 P2 功能开发（晚间）

### 任务1：仪表盘真实数据
- **admin_service.py** — `get_dashboard_overview()` 新增两项真实计算：
  - `avg_response_time`：从 messages 表计算首条员工消息到首条坐席/AI回复的时间差，最多统计50个会话
  - `ai_hit_rate`：今日有 AI 实质性回复的会话占比（ai_substantive_reply_count > 0）
  - 异常处理：计算失败时降级为 "—" 显示

### 任务2：P2 页面（会话审计/坐席绩效/系统日志）
**后端新增 3 组 API：**
- `GET /admin/audit/conversations` — 会话审计列表（分页+状态/坐席/关键词/日期范围筛选）
- `GET /admin/audit/conversations/{id}` — 会话审计详情（含消息列表，最多200条）
- `GET /admin/agent-performance` — 坐席绩效统计（总会话数/已结单/结单率/今日会话）
- `GET /admin/system-logs` — 系统日志（配置变更历史，含操作人姓名）

**前端新增 3 个页面：**
- `SessionAudit.vue` — 会话审计页（表格+筛选+详情抽屉，消息按类型着色）
- `AgentPerformance.vue` — 坐席绩效页（表格+汇总统计，支持日期范围筛选）
- `SystemLogs.vue` — 系统日志页（表格+分页，变更前后值着色对比）

**路由+侧边栏更新：**
- 路由新增 `/session-audit`、`/agent-performance`、`/system-logs`
- 侧边栏"监控与数据"分组新增 3 个菜单项

### 任务3：功能开关增强
- `CONFIG_GROUP_MAP` 新增 5 个分组前缀：
  - `queue_` → 排队策略
  - `satisfaction_` → 满意度评价
  - `invite_` → 邀请功能
  - `notification_` → 通知推送
  - `security_` → 安全策略

### 编译验证
- 后端 py_compile ✅
- 前端 vite build ✅（SessionAudit-D3UWZck-.js 6.40 kB）

---

## 统一部署包打包（10:58）

### 构建结果
- 4 个前端全部重建成功（H5/Agent/Admin/Portal），耗时 18 秒
- Admin 前端包含新增的 Roles.vue 角色管理页面

### 部署包清单

| 文件 | 大小 | 内容 |
|------|------|------|
| deploy-h5.tar | 0.6 MB | frontend-h5/dist/ |
| deploy-agent.tar | 2.0 MB | frontend-agent/dist/ |
| deploy-admin.tar | 1.7 MB | frontend-admin/dist/（含角色管理页） |
| deploy-portal.tar | 1.5 MB | frontend-portal/dist/ |
| deploy-backend.tar | 11.0 MB | backend/（含角色系统全部代码+迁移） |

### 服务器部署步骤
```bash
# 1. 清理失败的数据库状态
docker compose exec postgres psql -U postgres -d it_smart_desk -c "
DROP TABLE IF EXISTS role_mapping_rules CASCADE;
DROP TABLE IF EXISTS user_roles CASCADE;
DROP TABLE IF EXISTS roles CASCADE;
"

# 2. 通过堡垒机上传 5 个 tar 到 /tmp/

# 3. 在服务器执行
cd /opt/wecom-it-desk
cp /tmp/deploy-*.tar ./
docker compose down
# 解压前端
tar -xf deploy-h5.tar -C frontend-h5/
tar -xf deploy-agent.tar -C frontend-agent/
tar -xf deploy-admin.tar -C frontend-admin/
tar -xf deploy-portal.tar -C frontend-portal/
# 解压后端（保留 .env）
cp backend/.env /tmp/backend-env-backup
tar -xf deploy-backend.tar
cp /tmp/backend-env-backup backend/.env
# 重建并启动
docker compose build --no-cache backend
docker compose up -d
```

---

## Dify/RAGFlow/千问集成调研（12:39）

### 现有服务连通性确认（从 10.90.5.110 测试）

| 服务 | 地址 | 端口 | 状态 |
|------|------|------|------|
| RAGFlow 前端 | 10.80.0.85 | 8080 | ✅ 200 OK |
| RAGFlow API | 10.80.0.85 | 9380 | ✅ 200 OK（Werkzeug） |
| 千问模型 | 10.80.0.49 | 5000 | ✅ 已连接 |
| Dify | yw-dify.dc.servyou-it.com (10.80.0.240) | 80 | ✅ 307 正常 |

**结论：所有服务均已连通，无需开通新路由。**

### 集成现状

| 组件 | 后端代码 | 需要做什么 |
|------|----------|-----------|
| Dify | ✅ AIService + WingmanService | 无需改动 |
| RAGFlow | ❌ 无客户端代码 | 需开发 RagflowClient |
| 千问 | ℹ️ 通过Dify间接调用 | 无需直连 |

### 交接文档关键信息
- 消息链路：企微 → B端智能体 → dify2openai → Dify Workflow → 千问
- RAGFlow 知识运营：宋献IT组主导
- 模型：Qwen3-30B-A3B-Instruct + bge-m3(向量)
- 对接联系人：dify2openai→JG/CF；Dify应急→CF/WT

---

## RAGFlow 客户端开发（12:49）

### 新增文件
- `backend/app/integrations/ragflow/__init__.py` — 模块导出
- `backend/app/integrations/ragflow/client.py` — RagflowClient 客户端
  - `test_connection()` — 测试连接
  - `retrieval()` — 知识检索（核心接口，POST /api/v1/retrieval）
  - `list_datasets()` — 列出知识库
  - `create_dataset()` — 创建知识库
  - `delete_dataset()` — 删除知识库
  - `list_documents()` — 列出文档
  - `upload_document()` — 上传文档
  - `delete_documents()` — 删除文档
- `backend/app/integrations/ragflow/models.py` — 数据模型
  - RetrievalChunk / DocAggregate / RetrievalResult / DatasetInfo / DocumentInfo
- `backend/app/integrations/ragflow/exceptions.py` — 异常定义
  - RagflowError / RagflowConfigError / RagflowAuthError / RagflowApiError / RagflowConnectionError
- `backend/app/integrations/ragflow/config.py` — 配置加载器
  - 从 system_configs 表读取 integration_ragflow_api_url + integration_ragflow_api_key
  - 默认 API 地址：http://10.80.0.85:9380

### admin.py 新增端点
- `POST /admin/integrations/ragflow/test` — 测试连接
- `GET /admin/integrations/ragflow/datasets` — 列出知识库
- `POST /admin/integrations/ragflow/retrieval` — 知识检索测试

### 编译验证
- 后端 py_compile ✅（所有 ragflow 模块 + admin.py）

### 前端更新
- `frontend-admin/src/api/admin.ts` — 新增 3 个 RAGFlow API 函数：
  - `testRagflowConnection()` — 测试连接
  - `getRagflowDatasets()` — 列出知识库
  - `ragflowRetrieval()` — 知识检索测试
- `frontend-admin/src/views/Integrations.vue` — 更新 handleTest 函数：
  - 支持 RAGFlow 测试连接（调用 testRagflowConnection）
  - 测试成功后更新本地状态为 connected
- 前端 vite build ✅（Integrations-CFvIx0q8.js 14.51 kB）

---

## 修复：消息发送失败 + 截图不可用（15:00）

### 根因
后端 `POST /h5/conversations/current/messages` 抛出异常：
```
TypeError: AIHandler.__init__() missing 1 required positional argument: 'ai_service'
```

**深层原因**：uvicorn `--reload` 模式下 WatchFiles reloader 缓存了旧的 `dependencies.py` 字节码（之前 `dep_ai_handler()` 没有 `ai_service=AIService()` 参数的版本）。即使清空 `__pycache__` 重启，reloader 仍加载旧缓存。

**修复**：去掉 `--reload` 标志启动后端即可。`start_backend.py` 已改为 `reload=False`。

### 影响
- 消息发送：后端 500 错误 → 前端超时/失败
- 截图功能：截图本身正常（html2canvas + ScreenshotEditor），但上传后发送消息同样失败
- Mock 登录：正常（不经过 AIHandler）

### 验证
- Mock login → `code: 0` ✅
- Send message → `code: 0`, 返回 user_message + ai_reply ✅
- 后端 108 个路由正常注册 ✅

### 教训
- uvicorn `--reload` 的 WatchFiles reloader 可能缓存旧字节码，清 `__pycache__` 不一定有效
- 本地开发如果不需要热重载，用 `reload=False` 更可靠

---

## AIHandler 初始化问题修复 + 打包部署脚本（23:07）

### 问题描述
后端 `POST /h5/conversations/current/messages` 报错：
```
TypeError: AIHandler.__init__() missing 1 required positional argument: 'ai_service'
```

### 根因
`dependencies.py` 中 `AIHandler()` 调用缺少必需的 `ai_service` 参数。代码重构后 `AIHandler.__init__` 需要传入 `AIService` 实例。

### 修复内容
- `backend/app/dependencies.py` 两处修复：
  - `get_shared_ai_handler()`: `return AIHandler(ai_service=AIService())`
  - `dep_ai_handler()`: `return AIHandler(ai_service=AIService())`

### 数据库修复（已在服务器执行）
```sql
ALTER TABLE conversations ADD COLUMN IF NOT EXISTS impact_scope VARCHAR(50);
ALTER TABLE conversations ADD COLUMN IF NOT EXISTS is_blocking BOOLEAN DEFAULT false;
ALTER TABLE conversations ADD COLUMN IF NOT EXISTS emotion_state VARCHAR(50);
ALTER TABLE conversations ADD COLUMN IF NOT EXISTS dify_conversation_id VARCHAR(255);
```

### 打包部署脚本
新增两个自动化脚本：
1. `deploy-server/build-and-deploy.ps1` — PowerShell 脚本，功能：
   - 打包前端构建产物（frontend-h5/agent/admin/portal dist）
   - 复制 nginx 配置 + docker-compose.yml + .env
   - 构建后端 Docker 镜像（包含修复后的代码）
   - 导出为 `deploy-backend.tar`
   - 支持 `-Mode deploy` 参数自动上传并部署到服务器

2. `deploy-server/打包部署.bat` — 一键执行批处理
   - 不带参数：仅本地打包
   - 带 `deploy` 参数：打包 + 部署到服务器

### 下一步
需要重新构建后端镜像并部署到服务器：
1. 执行 `打包部署.bat deploy` 或手动运行 `build-and-deploy.ps1 -Mode deploy`
2. 脚本会自动：构建镜像 → 导出tar → 上传服务器 → 部署

---

## 剩余安全风险修复（23:03）

### 任务说明
处理 4 个可在代码层面快速修复的风险项。

### 修复内容

#### 1. H-6：角色映射标签验证（高风险）
- `role_mapping_service.py` 新增 `_validate_tag_name()` 方法
- 验证规则：长度限制 50 字符，过滤禁止的特殊字符 (`<>'"&;\\|%$#@``)
- 获取企微标签时过滤不安全的标签名称

#### 2. M-9：异常信息泄露（中等风险）
- `main.py` 两处异常处理器修改
- 响应改为通用消息："服务器内部错误，请稍后重试或联系管理员"
- 详细异常信息仅记录到日志

#### 3. M-10：日志脱敏（中等风险）
- 新增 `_mask_sensitive_data()` 脱敏函数（保留前3位）
- 已处理：`role_mapping_service.py`（3处）、`admin_roles.py`（4处）

#### 4. L-7：坐席列表 API 认证（低风险）
- `agents.py` 导入 `require_role` 依赖
- `/agents` 端点添加 `@require_role("agent", "admin")` 装饰器

### 风险处理进度
| 级别 | 处理率 |
|------|--------|
| 严重 | 100% (4/4) |
| 高风险 | 83% (5/6) |
| 中风险 | 57% (4/7) |
| 低风险 | 60% (3/5) |
| **总计** | **73% (16/22)** |
