# 2026-06-03 工作日志 ## Docker Compose 部署编排完善 - 重写 `docker-compose.yml`:PostgreSQL 16-alpine + Redis 7-alpine + 后端 + Nginx 四服务 - 增强 nginx.conf:新增 WebSocket 路径代理、HTTPS 模板(含 SSL 安全配置和安全头) - 创建 `.env.production`:生产环境变量模板(企微凭证、数据库、域名、SSL 路径) - 创建 `scripts/build.sh`:一键构建两个前端(agent + h5) - 创建 `scripts/deploy.sh`:一键部署(检查环境 → 构建前端 → 启动服务 → 健康检查) - 后端容器端口不暴露(仅 Nginx 入口),数据库/Redis 端口默认不暴露(安全策略) - 所有服务配置日志轮转(10-20MB/文件,3-5个文件) ## US-7 模型层准备(上下游互联) - 创建 `Employee` 模型(`employees` 表):corp_id + employee_id 复合唯一键,支持跨企业员工 - `Conversation` 模型新增 `corp_id` 字段 + 索引(默认空字符串,不破坏现有数据) - 创建 Alembic 迁移 `001_add_employees_table.py`:创建 employees 表 + 为 conversations 添加 corp_id - 更新 `models/__init__.py` 和 `alembic/env.py` 注册 Employee 模型 - 所有模型导入和应用创建验证通过 ## 文档清理 - `现有系统复用评估报告.md` 已在之前的合并操作中删除(内容合并至团队沟通文档第7章) ## 摇人功能可行性评估 - 分析两种场景: - 情况1(创建企微群+拉员工入群):技术上可行(appchat API),但聊天记录转发体验差、跨企业受限、群生命周期管理复杂。**用户暂缓确认。** - 情况2(坐席B进入同一会话协作):纯内部扩展,成本低体验好。**用户确认优先开发。** - 输出详细技术方案到 `docs/摇人-多坐席协作-技术方案.md`,覆盖模型/API/WS/前端全链路 - 核心设计:Conversation 新增 `collaborating_agent_ids` (JSON),协作坐席可查看+回复但不能结单/转接,不占负载 - 预留情况1接口待用户确认 ## 正式环境独立部署架构方案 - 用户要求以"影响最小、责任清晰、避免系统混搭"为原则,给出正式环境部署建议 - **核心决策:物理隔离 > 逻辑隔离**,修正了原复用评估中的共享建议 - 方案要点: - **独立服务器**:不共用 10.80.0.86,申请新 VM(4C8G/100GB 以上) - **独立数据库**:独立 PostgreSQL 16 容器(不复用旧 PG13 实例) - **独立 Redis**:独立 Redis 7 容器(不复用旧实例,避免 db 号隔离不彻底) - **独立 Nginx + 子域名**:`itdesk.dc.servyou-it.com`,变更不影响旧系统 - **仅共享外部服务**:企微应用凭证(只读)、AI 服务(HTTP 调用)、SSL 证书(只读文件) - 输出完整方案文档 `docs/正式环境独立部署架构方案.md`:含资源申请清单、网络拓扑、容器拓扑、部署步骤、回滚方案、运维责任矩阵、风险矩阵、退化方案 ## 摇人(情况2)多坐席协作 全链路实现 - **13个文件改动**,完整前后端实现: - **模型**:`conversation.py` 新增 `collaborating_agent_ids` (JSON, default list) - **Schema**:新增 `ConversationInvite`、`ConversationResponse` 扩展 `collaborating_agent_ids/names`、`is_collaborator` - **SessionService**:新增 `invite_collaborator()`(6步校验 + WS广播+定向推送)和 `leave_collaboration()`(4步校验 + WS广播) - **API**:新增 `POST /conversations/{id}/invite`(错误码3020-3024)、`POST /conversations/{id}/leave`(错误码3025-3026);列表接口扩展协作字段 - **前端 API**:`inviteCollaborator()`、`leaveCollaboration()`;Conversation 类型扩展 - **Store**:新增 `collaboratingConversations` 计算属性、`inviteToConversation()`、`leaveConvCollaboration()`、`handleCollaboratorInvited()`、`handleCollaboratorChanged()` WS处理器 - **WebSocket**:处理 `collaborator_invited`(弹窗通知被邀请坐席)、`collaborator_joined`、`collaborator_left` 事件 - **新组件 InviteDialog.vue**:搜索在线坐席→选中→确认邀请,排除主责/协作坐席/自己 - **ConversationList**:新增「协作会话」分区(排在「我的会话」之后),支持退出按钮 - **ConversationItem**:新增 `showLeave` prop + 退出按钮样式 - **ChatArea**:新增「🤝 摇人」按钮(仅 serving 且 is_mine/is_collaborator 时显示)、协作信息行(主责+协作坐席展示)、InviteDialog 集成 - **权限矩阵已落地**:主责坐席可做一切;协作坐席可查看+回复+再摇人,不能结单/转接/标记;不占协作坐席负载 ## 应急预案(应急模式)— 方案B:纯应急 + 手动启停 - 决策:先选方案B(员工服务常态隐藏,需要时手动开启),后续条件成熟再升级方案C(自动降级) - **后端**: - `main.py` 默认配置新增 `emergency_mode`(默认 false) - 新建 `app/api/system.py`:GET/PUT `/api/system/emergency-mode` 查询/切换应急模式 - 在 `router.py` 注册系统管理路由 - **前端坐席端**: - 新建 `api/system.ts`:封装 `getEmergencyMode()` / `toggleEmergencyMode()` - `Workspace.vue` 顶部栏新增「启用应急模式」按钮(常态隐藏);开启后显示红色应急横幅 + 「关闭应急模式」按钮 - 开启/关闭均需二次确认,防止误操作 - Phase 2(待条件成熟):服务挂掉时 H5 页面自动显示引导提示走员工服务 ## H5员工端「摇人」→「双手敲桌子」改造 - 用户反馈:前端未发现「举手」和「摇人」功能变更 → 经核查,坐席端「摇人」已完整实现,H5员工端「举手」缺少专用按钮 - 用户决策:将 H5 员工端现有「摇人」按钮改为「双手敲桌子」 - **ShakeButton.vue 完全重写**: - 图标从 🔔 改为 👊👊 双拳 - CSS 动画:交替敲击(左右拳各3轮,0.8s)+ 按钮水平震动(模拟桌子晃动)+ 静止时呼吸浮动 - 按钮底色从 #FF6B35→#FF8F5E 改为 #FF5722→#FF7043(更深的紧急感) - 防抖逻辑保持不变 - **InputBar.vue**:引导条文案「急需 IT 支持?👊👊 敲桌子呼叫坐席」 - **ChatPanel.vue**:空状态提示「输入问题咨询,或 👊👊 敲桌子呼叫坐席」 - **后端 h5.py**:注释/日志从「摇人」改为「举手/敲桌子」 - **前端注释批量更新**:H5 api/conversation.ts、stores/conversation.ts、frontend-agent conversation.ts ## H5员工端「呼叫坐席」完整改造(三步流程 + 七种动画) ### 核心设计变更 - 用户决策:呼叫坐席必须有前置条件——用户先描述问题,AI 复述确认后再呼叫,避免无效转人工 - 动画触发方式:随机选择(方案C),每次点击随机出现7种动画之一,增加趣味性 - 话术与场景一一对应,不同紧急程度有不同表达 ### 三步流程(CallAgentModal.vue) 1. **描述问题**:TextArea 输入(上限500字),引导员工说清楚问题 2. **AI 复述确认**:调后端 API 让 AI 用自己的话复述,用户确认无误后进入下一步 3. **播放动画 + 发请求**:随机选场景播放动画,同时发 shake 请求 ### 七种呼叫场景(权重随机) | # | 场景 | 话术 | 权重 | 核心动画 | |---|------|------|------|----------| | 1 | 🙋 举手 | "看这里!…我有个问题!" | 3.0 | 右手臂上下挥动 + 气泡 | | 2 | 🪑 拍桌子 | "快快快!我等不及了!" | 3.0 | 双拳交替敲击 + 桌面震动 | | 3 | 💀 劈稻草人 | "不解决我要爆炸了💥" | 1.5 | 挥刀 + 稻草人抖动 + 爆炸光效 | | 4 | 🍉 砍西瓜 | "IT救我!卡住了🍉" | 1.5 | 刀砍 + 汁水飞溅 | | 5 | 🔔 摇铃铛 | "叮叮叮!有人吗!" | 1.0 | 双铃铛摆动 + 声波扩散 | | 6 | 💣 大炮发射 | "开炮!必须解决了!" | 1.5 | 引信燃烧 + 炮弹飞行 + 爆炸+靶子抖动 | | 7 | 🚀 导弹发射 | "发射!呼叫IT特种部队!" | 1.5 | 导弹上升 + 尾焰闪烁 + 烟雾扩散 + 按钮闪烁 | ### 技术实现 - **CallAgentModal.vue**:全新组件,Teleport 到 body,三步骤状态机 - **ShakeButton.vue** 重构:从直接发请求 → 只触发弹窗(emit 'trigger') - **ChatPanel.vue**:承载弹窗,监听 call-agent 事件 - **InputBar.vue**:向上传递 trigger 事件 - 所有 SVG 场景内联绘制,CSS @keyframes 驱动动画,无外部图片依赖 - 构建验证通过(CSS 从 26.52 kB → 30.16 kB,ChatView JS 从 48.38 kB → 53.49 kB) ## 呼叫坐席流程重设计:按钮条件显隐 + 弹窗简化(2026-06-03 下午) ### 需求 1. 初始隐藏「呼叫坐席」按钮,AI 实质性回复 >= 3 次后才出现 2. 打招呼(你好/hi等)和直接呼叫人工(人工/转人工等)不计数,AI 回复引导话术 3. CallAgentModal 简化为单步动画,去掉"描述问题"和"AI复述确认"步骤 ### 后端改动 - **conversation.py**:新增 `ai_substantive_reply_count` 字段(Integer, default=0) - **h5.py**: - `_get_current_employee()`:新增 `X-Employee-Id` 头 fallback(开发降级) - 新增 `_is_greeting()` / `_is_call_human()` 检测函数(关键字匹配) - `h5_send_message()` 完全重写:检测消息类型→生成AI回复→计数→返回 `{user_message, ai_reply, is_guidance, ai_reply_count, can_call_agent}` - `GET /h5/conversations/current`:返回 `can_call_agent` 和 `ai_substantive_reply_count` - `POST /h5/conversations/current/shake`:新增前置校验 `ai_substantive_reply_count >= 3`(含无会话场景兜底),不满足返回错误码 1003 - **.env**:`DATABASE_URL` 改为绝对路径 `sqlite+aiosqlite:///C:/Users/simon/wecom_it_smart_desk/backend/it_smart_desk.db` ### 前端改动 - **api/conversation.ts**:新增 `SendMessageResponse` 类型,`sendMessage()` 返回双消息结构 - **stores/conversation.ts**:新增 `canCallAgent` ref;`sendNewMessage()` 处理双消息响应;`fetchCurrentConversation()` 同步 canCallAgent - **InputBar.vue**:`ShakeButton` `v-if="store.canCallAgent"` 条件渲染;底部文案动态切换(默认提示→橙色脉冲「呼叫坐席通道已开启」) - **CallAgentModal.vue**:完全重写为单步动画模式,`watch(visible)` 自动触发 shake,4秒后自动关闭 ### 修复的 Bug 1. `_get_current_employee` 只支持 Bearer Token → 添加 `X-Employee-Id` 开发降级 fallback 2. `.env` 相对路径 `./it_smart_desk.db` → 改为绝对路径 3. shake 端点无会话时直接创建新会话绕过阈值 → 统一拒绝 code=1003 4. 编辑 cut-paste 残留垃圾代码 → 清理修复 ### 验证结果 - 后端 API 全链路测试通过(打招呼引导 + 计数递增 + can_call_agent 阈值 + shake 拒绝/接受) - 前端 `npm run build` 通过(ChatView JS: 53.49 kB → 48.82 kB) - 本地环境:后端 `:8000` + 前端 `:5173` 运行中 - 测试指南:`TESTING_CALL_AGENT.md` ## 部署就绪性完善(2026-06-03 晚) ### 修复的问题 1. **nginx.conf 端口 80 重复监听**:两个 server 块都 `listen 80; server_name _;` → 重写为单一 HTTP server 块 + 注释模板 HTTPS server 块 2. **frontend-agent ConversationList.vue 重复 import**:`import type { Conversation }` 出现两次 → 删除重复行 3. **alembic.ini 日志格式错误**:`[%(name)]` 缺 `s` → 修正为 `[%(name)s]`;中文注释导致 Windows GBK 解码失败 → 改为英文注释 4. **alembic 迁移目录缺失**:env.py 不存在,`docker compose up` 会因 `alembic upgrade head` 失败 → 创建完整 alembic 环境 ### 新建文件 - **alembic/env.py**:从环境变量读取 DATABASE_URL,自动转换异步驱动→同步驱动(aiosqlite→sqlite, asyncpg→psycopg2) - **alembic/script.py.mako**:标准迁移脚本模板 - **alembic/versions/6d5520491644_initial_all_tables.py**:初始迁移(9张表 + 所有索引) - **scripts/deploy.sh**:一键部署脚本(--build/--up/--down/--status 四种模式) - **docs/DEPLOY_NAS.md**:群晖 NAS 部署指南(SSH + Container Manager 两种方式) ### 构建验证 - frontend-h5: `vite build` 通过(10 个文件) - frontend-agent: `vite build` 通过(8 个文件,1.2MB JS 含 Element Plus) - alembic migration: `upgrade head` 执行成功,9 张表全部创建 ### 部署架构决策 - 基于日均 37 次会话的负载分析,现有 4 容器方案(PG + Redis + Backend + Nginx)完全够用 - 暂无需拆分为更复杂的微服务架构 ## 共享域名部署适配(2026-06-03 晚) ### 需求 - 与 IT 数据查询平台共享域名 `http://it-dataquery.dc.servyou-it.com/` - 路径路由:`/itdesk/`(H5员工端) + `/itagent/`(坐席端) + `/api/`(后端) + `/`(数据平台) ### 前端改动 - **frontend-h5/vite.config.ts**:添加 `base: '/itdesk/'` - **frontend-h5/src/router/index.ts**:`createWebHistory('/h5/')` → `createWebHistory('/itdesk/')` - **frontend-h5/src/stores/employee.ts**:OAuth2 回调 URI `/h5/` → `/itdesk/` - **frontend-agent/vite.config.ts**:添加 `base: '/itagent/'` - **frontend-agent/src/router/index.ts**:`createWebHistory()` → `createWebHistory('/itagent/')` - **frontend-agent/index.html**:favicon 路径 `/vite.svg` → `/itagent/vite.svg` - 两个前端 dist 重新构建验证通过 ### Nginx 改动 - **nginx.conf** 完全重写: - `location /itdesk/` → H5 SPA(alias + try_files fallback) - `location /itagent/` → Agent SPA(alias + try_files fallback) - `location /api/` → backend:8000 反代 - `location /ws/` → WebSocket 反代 - `location /` → dataquery:80 反代(兜底到数据平台) ### Docker Compose 改动 - **docker-compose.yml** 重写: - nginx 挂载 `frontend-h5/dist → /usr/share/nginx/html/itdesk` - nginx 挂载 `frontend-agent/dist → /usr/share/nginx/html/itagent` - 添加 `it-desk-internal` 内部网络(PG + Redis + Backend + Nginx) - 添加 `it-platform-net` 外部网络(与数据平台互联) - nginx 暴露 `18080:80`(临时端口,供数据平台反代或直接测试) ### 部署文件 - **scripts/deploy.sh**:更新输出信息 + 添加 `--pack` 打包模式 - **docs/DEPLOY_NAS.md**:重写为远程服务器部署指南(含两种网络接入方式) - **.env.production**:域名改为 `it-dataquery.dc.servyou-it.com` ## T02 后端核心服务 — AI 回复集成(Dify 接入) ### 修改文件清单(11 个文件) **配置层:** - `backend/app/config.py` — 新增 3 个 Dify 配置项:`dify_api_url`、`dify_api_key`、`dify_timeout` - `backend/.env` — 新增 DIFY_API_URL/KEY/TIMEOUT 环境变量 - `backend/.env.example` — 新建环境变量模板 - `.env.production` — 新增 DIFY 配置段 - `docker-compose.yml` — backend 容器新增 DIFY_* 环境变量传递 **模型层:** - `backend/app/models/conversation.py` — 新增 `dify_conversation_id` 字段(String 128,nullable),用于 Dify 多轮对话上下文 **服务层(核心):** - `backend/app/services/message_router.py` — 完整重写,接入 Dify AI: - `__init__` 新增 `ai_service` 参数(可选,None 时跳过 AI) - `route_message` 流程重排:举手优先判断(跳过AI)→ AI 回复(仅 ai_handling 状态)→ 标记检测 → 评分 - 新增 `_try_ai_reply` 方法:调 Dify → 命中则通过企微发回复 + 创建 AI 消息记录 + ai_substantive_reply_count++,未命中则转 queued + 发引导文案 - `_find_or_create_conversation`:新会话默认 `ai_handling`(非 queued),活跃会话查找包含 ai_handling - `backend/app/services/ai_service.py` — 修复配置读取:`getattr(settings, ...)` → `settings.dify_api_url`(直接用 pydantic 属性) - `backend/app/services/session_service.py` — 会话排序新增 `ai_handling` (权重 25),介于 queued(30) 和 serving(20) 之间 **API 层:** - `backend/app/api/wecom_callback.py` — 注入 AIService 到 MessageRouter,回调结束时关闭 ai_service - `backend/app/api/h5.py` — H5 消息发送重写: - 会话查找包含 ai_handling 状态(4处) - `h5_send_message`:实质问题调用 Dify API 替代硬编码模板;打招呼/呼叫人工保持引导话术;Dify 异常降级到模板回复 - 响应新增 `conversation_status` 字段 - `backend/app/api/conversations.py` — status 过滤描述新增 ai_handling ### 前端适配评估 - 坐席工作台:已完整支持 ai_handling 状态——ConversationList 有「AI处理区」分区,ChatArea 有状态标签和颜色,Store 有状态排序权重 - H5 员工端:无需额外改动——通过 can_call_agent 和 ai_reply_count 驱动 UI,状态变化对 H5 透明 ### AI 回复流程(全链路) ``` 员工发消息(企微/H5) → 新会话 → ai_handling → 举手? → 跳过AI,直接 queued → 调 Dify API → 命中 → 企微发回复 + 消息入库 + ai_count++ + 保持 ai_handling → 未命中 → 发引导文案 + 转 queued → 异常 → 降级处理 + 转 queued → ai_count >= 3 → H5 显示「呼叫坐席」按钮 ``` ## 产物文档合并与部署架构修正(2026-06-03 晚) ### 产物文档合并 - 新建 **README.md**:按阅读对象组织(新人/开发/运维/测试),含项目背景、实现进度、快速启动、API概览、已知问题 - 文档体系分层:README(入口)→ ARCHITECTURE.md(架构细节)→ docs/(专题文档) ### 部署架构偏差修正 用户指出预生产实际部署与文档描述存在偏差,已调整: **关键偏差**:文档假设智能咨询系统与数据平台在同一 Docker 主机(通过 `it-platform-net` 共享网络互联),但预生产实际是**不同主机、仅共用域名**。正式环境会迁移到 K8s。 **修正内容**(7个文件): - **README.md**:部署章节明确「预生产独立主机,正式环境 K8s」,部署前必须先改 DATAQUERY_HOST - **docker-compose.yml**:移除 `it-platform-net` 外部网络(Docker 网络无法跨主机),backend 和 nginx 仅连 `it-desk-internal` - **nginx/nginx.conf**:header 注释重写为「预生产·独立主机版」,`upstream dataquery` 改为 `DATAQUERY_HOST` 占位符(需替换为数据平台实际 IP),注释说明远程反代替代 Docker 网络 - **docs/01-项目总览与部署手册.md**:2.1 节新增「预生产 vs 正式环境」对比表,架构图标注跨主机代理;6.2 节「创建共享网络」→「配置数据平台反代地址」;常见问题更新 - **docs/DEPLOY_NAS.md**:网络互联部分重写,移除 it-platform-net 步骤 - **docs/团队沟通文档-架构消息知识库.md**:部署架构描述补充「预生产独立主机,正式 K8s」 - **ARCHITECTURE.md**:部署模式说明更新 ### Simon→宋献 署名统一(6个文件) - README.md、docs/01-项目总览与部署手册.md、docs/正式环境独立部署架构方案.md、docs/团队沟通文档-架构消息知识库.md、PRD.md 中所有署名「Simon」→「宋献」 - node_modules/ 中第三方库的 Simon 引用不修改(与项目署名无关) ### 新建 ai_service.py - `backend/app/services/ai_service.py`:封装 Dify API 调用(非流式+流式),含知识库命中检测、错误降级回复 ## 企微原生群聊方案可行性分析 ### 背景 用户提出:能否用企微原生应用创建群聊/推送消息替代现有 H5 嵌入式员工端 ### 初步结论(已修正) - **完全可行**,企微提供两套原生 API: - 群聊会话 API(`/cgi-bin/appchat/*`):创建/修改/获取群聊 + 群内推送消息 - 应用消息 API(`/cgi-bin/message/send`):1对1 推送(项目已在用),消息出现在与该应用的1对1聊天窗口中 - 关键 API 限制:appchat ≤1000群/天、appchat/send ≤2万人次/分、message/send ≤账号上限×200人次/天 - 群聊 API 要求:仅自建应用、可见范围必须根部门、只能操作本应用创建的群 - 之前"摇人功能评估"(情况1:创建企微群)已分析过 appchat 方案,用户当时暂缓确认 ### 用户修正(关键纠错) 1. **员工可以看到自己发的消息** — 企微1对1应用聊天窗口中,员工自己发的和应用回复的都在同一窗口(我之前错误判断为看不到) 2. **方案B交互路径修正** — 不是"每次咨询都创建群聊",而是: - 主流程:员工↔自建应用1对1交互,AI+坐席都走 `/message/send` → 同一窗口 - 群聊(appchat)仅在坐席需要外援时创建 → 新窗口,非常态 3. **方案A的跨平台移植便利性** — H5可嵌入企微/钉钉/飞书/浏览器,一次开发多处部署 4. **方案A可跨主体企微支持** — 非静默登录时切换其他认证方式(手机号+验证码/SSO),原生方案无法跨主体 ### 修正后结论 - 方案B可行性**大幅提升**:主流程无需群聊,不需要会话存档权限,员工体验最佳 - 方案A的独特价值**被低估**:跨平台移植和跨主体支持是原生方案无法替代的 - 方案C是方案B的子集,不存在独立选型意义 - **推荐 A+B 渐进式**:先上方案B做MVP(改动极小,已在用回调+message/send),H5保留为扩展层 ## 方案B文档纳入(4个文件更新) ### PRD.md §3 方案可行性判断 - 新增"方式五:企微原生1对1 + 外援群聊"到方案对比表 - 新增 §3.2 方式五详解:架构原理、交互路径、API清单、与方式四对比、关键结论 - 更新 §3.3 最终方案:从"方式四"改为"方式四+五混合演进",含选型决策逻辑 ### 01-项目总览与部署手册.md §7 运维管理 - 新增 §7.5 应急预案可选技术项 - §7.5.1 备用方案概述:5种应急场景→备用方案动作映射 - §7.5.2 备用方案技术架构:交互流程图 + 已有能力 + 仅需新增 - §7.5.3 切换流程:H5→原生(5步,前3步零代码)/ 原生→H5(3步) - §7.5.4 企微API限制与容量评估:4项API限额 vs 当前业务量 - §7.5.5 备用方案局限性与适用边界:5项局限 + 决策建议 ### ARCHITECTURE.md §1.2 核心技术挑战 - 表格新增第9项"员工端架构选型":主方案H5,备选原生1对1 - 新增 §1.2.1 员工端架构双方案设计:方案A/B对比、API清单、决策建议 ### 团队沟通文档-架构消息知识库.md §3.6 - 新增员工端架构双方案对比表、方案B交互路径、选型决策、运维应急引用 ## 共享基础设施代码修复(2026-06-03 下午-2) ### 背景 用户决定暂不选择A/B方案,先做两方案共享的基础设施工作。审计4个领域(回调服务器/后端服务/坐席前端/AI集成),发现11个需修复问题。 ### 已完成的修复(主理人直接执行) 1. **Task 9: 启动时校验关键配置非占位符** — `main.py` 新增 `_validate_config()`,启动时检查 wecom_corp_id/wecom_secret/wecom_token/wecom_encoding_aes_key 是否仍为占位符值,醒目警告 2. **Task 7: 坐席登录安全加固** — `agents.py` 的 `agent_login` 新增企微通讯录验证:调用 WecomService.get_user_info() 校验 user_id 是否存在,验证通过后用企微返回的真实姓名覆盖前端输入(防冒用);企微API不可达时降级放行+警告日志;Login.vue 提示文案更新 3. **Message 模型扩展**(Task 4前置) — `message.py` 新增5个字段:media_id(企微媒体ID)、media_url(本地存储URL)、file_name、file_size、extra_data(JSON扩展元数据);新建 Alembic 迁移 `002_add_media_fields.py` ### 企微消息XML结构调研 - 回调支持6种消息类型:text/image/voice/video/location/link - 文件消息(file)不在回调文档中(企微可能不支持接收file类型回调) - MediaId 仅3天有效,需收到后立即下载保存 - 所有消息都有MsgId字段(可用于去重) ### 工程师(寇豆码)进行中的任务 - Task 1: 修复H5端AI降级回复误计数 - Task 2: 统一AI调用逻辑为共享服务 - Task 3: 修复资源泄漏(callback/h5改用DI) ### 待处理任务 - Task 4: 补全回调非文本消息处理 - Task 5: 添加消息去重(MsgId检查) - Task 6: 修复ScoringService硬编码关键词+需介入检测逻辑 - Task 8: 补全会话状态机校验+消除绕过 - Task 10: 补全回调事件处理业务逻辑 - Task 11: QA验证