Files
wecom_it_smart_desk/.workbuddy/memory/MEMORY.md
T

13 KiB
Raw Blame History

IT智能服务台 - 项目记忆

测试铁律

  • e2e 测试 poll 不能依赖 after_idUUID 排序 ≠ 时间排序)messages/poll 的 after_id 参数使用数据库主键 UUID 排序,与 created_at 时间戳排序不一致。跨会话复用用户时可能 poll 到修复前的旧消息。应使用 created_at 时间戳过滤 + 唯一测试用户。
  • 宣布修复前必须端到端验证:容器内测试通过 ≠ 外部用户可用。需经过 Mock 登录 → 发消息 → 查回复 全链路验证。

设计决策(锁定)

  • AI交互:小段多回合;术语:员工端"人工坐席"按钮 = 用户呼叫坐席(统一命名);"摇人"=坐席呼叫坐席
  • 原型:坐席v5.3 + H5 v1.1UI:企微浅色扁平,accent=#07C160
  • 统一入口 /itportal/ → user/agent/adminadmin需OTP
  • H5 布局铁律:人工坐席按钮在"发送键和语音按钮上方";截图说明 PC 显示/移动端隐藏

技术架构

  • 前端:坐席(Vue3+Element Plus) / H5(Vue3+Vant4) / 管理后台(Vue3+Element+Tailwind)
  • 后端:FastAPI + SQLAlchemy + PostgreSQL + Redis(代码在 app/
  • 字段映射:后端id/sender_type → 前端message_id/message_typeconversation.tsmapMessage()
  • WS双连接池:active_connections(agent) + employee_connections(H5)
  • H5 参与者系统已完整存在:ParticipantStrip/ParticipantList/InviteParticipantSheet + useParticipantDisplay composableROLE_BORDER_COLORS/ROLE_LABELS 常量;canInvite=发起人 OR 已在会话中的参与者

部署铁律(必读)

  • 正式服务器:itsupport.servyou.com.cn (10.90.5.110),出口IP 218.75.34.87
  • 堡垒机:sxn@10.212.189.210:2222 (OTP),脚本 C:\Users\simon\.workbuddy\skills\jumpserver-ops\scripts\jms_ops.py
  • 服务器项目根路径/opt/wecom-it-desk/
  • 后端卷挂载:./app:/app/app.py变更→docker compose restart backendenv变更→docker compose up -d backendrestart不重载env
  • docker-compose.yml environment 铁律2026-07-13 第二次踩坑导致 P0 [object Object]):.env变量不会自动传入容器,必须在docker-compose.ymlenvironment:显式声明每个变量(如 DIFY_NATIVE_BASE_URL=${DIFY_NATIVE_BASE_URL:-})。后端重启时若发现 env 为空但 .env 文件有值,首先检查 docker-compose.yml 是否声明。
  • 前端部署铁律:所有前端 dist 均为 ro bind mount只能在宿主机源路径操作,不可在容器内修改
    • H5/opt/wecom-it-desk/frontend-h5/dist/usr/share/nginx/html/h5 (ro) [新增于 2026-07-13,此前仅 mount 到 itdesk 用于重定向]
    • H5重定向:/opt/wecom-it-desk/frontend-h5/dist/usr/share/nginx/html/itdesk (ro) [用于 /itdesk//h5/ 301重定向]
    • Agent/opt/wecom-it-desk/frontend-agent/dist/usr/share/nginx/html/itagent (ro)
    • Admin/opt/wecom-it-desk/frontend-admin/dist/usr/share/nginx/html/itadmin (ro)
    • Portal/opt/wecom-it-desk/frontend-portal/dist/usr/share/nginx/html/itportal (ro)
    • Terminal/opt/wecom-it-desk/frontend-terminal/dist/usr/share/nginx/html/itterminal (ro)
    • nginx.conf/opt/wecom-it-desk/nginx/nginx.conf/etc/nginx/nginx.conf (ro)
    • 部署命令模板:H5_DIR=/opt/wecom-it-desk/frontend-h5/dist && cp -r $H5_DIR ${H5_DIR}_bak && rm -rf $H5_DIR/* && tar -xzf /tmp/h5-dist-vX.tar.gz -C $H5_DIR/ && docker compose up -d nginx注意:容器重建,不是 nginx -s reload
  • 服务器 nginx /h5/:静态 root /usr/share/nginx/html; try_files $uri /h5/index.html; + /h5/api/ 反代后端
  • Docker bind mount铁律:rm后重建必须重启容器(或 nginx -s reload 热重载)
  • dist 分块上传技巧(2026-07-13 验证):大文件上传时先排除 video 等不变目录(8.35MB→210KB),写 Python 脚本导入 jms_ops 模块复用 PlinkSession 做单会话 base64 分块上传(3800 chars/line × 15 lines/batch here-doc),单会话完成上传+部署+验证,避免 session cache 过期后 Chrome/Playwright 启动失败。脚本模板在 .workbuddy/tmp/upload_and_deploy_h5.py

Admin 前端拦截器 Bug2026-07-13 修复)

  • 根因api/index.ts 拦截器 return res.data 剥离了 axios 外壳,但 10 个文件仍用 response.data.data 旧模式
  • 影响:管理后台所有 API 调用 TypeError 被 catch 吞掉 → 集成页面"测试连接"报"请求失败,请检查网络连接"
  • 修复10 文件 25 处 xxx.data.dataxxx3 种变量名模式:response/res/leakResp
  • 铁律:新增 API 调用时直接用返回值(const data = await getXxx()),不要 response.data.data
  • Vite 构建铁律dist/assets 超 50 文件时 safe-delete 会阻止构建,需先重命名旧 dist 为 dist_bak 再构建
  • Vite @ 别名铁律(2026-07-13Windows 上 resolve.alias: { '@': '/src' } 会解析为 FS 根路径(D:\src\),必须用 fileURLToPath(new URL('./src', import.meta.url))
  • .d.ts vs .ts 铁律(2026-07-13:含运行时值(如 const TONE_LABELS = {...})的文件不能用 .d.ts 扩展名,Vite 构建时会报 does not provide an export named。应使用 .ts

文件上传(关键经验教训)

  • ⚠️ elFinder 上传二进制:旧版手动上传 tar.gz 后 MD5 不匹配(差字节)。2026-07-13 验证jms_ops.py upload 命令对 >=100KB 文件走 elFinder Web UI 通道,上传 7.36MB tar.gz MD5 完全匹配 ,推荐优先使用。如必须用 base64 通道,则参考下一条铁律。
  • ⚠️ JumpServer PTY 4096 字节行缓冲铁律(2026-07-13 严重事故)base64 单行字符数若超 4096 会被 PTY 静默丢弃,导致 gzip 流损坏、线上瘫痪。脚本 .workbuddy/tmp/chunked_upload_v2.py 必须按 base64 字符数分块 B64_CHUNK=3800(非字节数)。subprocess timeout 设 1800s、--cmd-timeout 15s。脚本 print 用 ASCII(禁用 emoji,否则 GBK 崩溃)。上传后比对远程 md5sum 与本地。
  • pscp/plink -T不可用;elFinder上传后需手动mvhttpx.Timeout须含default
  • JumpServer v2.28 变更:登录新增图片验证码(CAPTCHA)connection-token 端点改为 /api/v1/authentication/connection-token/

外部集成

  • 企微通讯录:通讯录同步Secret BM6iosc3gKnPqkEXmsQN3ErJUpfO-whfMUN646eezB8 已废弃(2022年8月后新增IP不能调department/list和user/listerrcode=48009,非IP白名单问题)。改用自建应用Secret + 可见范围设为全公司.envWECOM_CONTACT_SECRET= 留空触发降级。验证:651部门/7098员工
  • Difyhttp://yw-dify.dc.servyou-it.com/v1/chat-messages
    • 审批意图Key app-7jkRkAzvX4QM9v9SM3P8mMEO200,结构化JSON
    • 分诊Key app-z3S9AEUUAVPbtR2rioxpiIvp200,结构化JSON
    • app-UaTWYdBSwN6VktKQlbh5YN5H200 纯文本,已禁用)
    • app-J3s8sHarZQ2SCaNF3xCppliL400 "Model credentials not initialized"
    • Dify App IDConsole):8f0f3d62-f63d-4cf3-815e-b10529c66f1d(智能IT支持-员工咨询,advanced-chat85节点)
  • ⚠️ Dify 发布铁律advanced-chat应用改工作流后必须浏览器手动点「发布」,否则API返回400 "Workflow not published";此版本 publish 端点不支持 Console API 调用。
  • Dify 原生 API 直连v2.1):后端 _call_dify_native() 直连 /v1/chat-messagesBearer+blocking),优先于代理;config.pydify_native_base_url/dify_native_api_keydocker-compose.yml 须显式声明.env 定义不会自动传入容器)。
    • ⚠️ 两次踩坑:第一次是配置读取时未意识到容器内为空;第二次是 [object Object] 根因正是此变量未声明导致原生 API 不可用、回退到 buggy 代理路径。
    • ⚠️ 第三次踩坑(2026-07-13 坐席扫码)WECOM_SSO_CALLBACK_BASE 未声明导致 qrcode_service.py 抛异常 ValueError: 请在环境变量中配置 WECOM_SSO_CALLBACK_BASE
    • 必须确保 environment: 部分有(新增变量需同时加入 .envdocker-compose.yml):
      - DIFY_NATIVE_BASE_URL=${DIFY_NATIVE_BASE_URL:-}
      - DIFY_NATIVE_API_KEY=${DIFY_NATIVE_API_KEY:-}
      - BAIDU_ASR_APP_ID=${BAIDU_ASR_APP_ID:-}
      - BAIDU_ASR_API_KEY=${BAIDU_ASR_API_KEY:-}
      - BAIDU_ASR_SECRET_KEY=${BAIDU_ASR_SECRET_KEY:-}
      - WECOM_SSO_CALLBACK_BASE=${WECOM_SSO_CALLBACK_BASE:-https://itsupport.servyou.com.cn}
      
  • Dify Prompt 自动更新v2.2):Console API Token(localStorage.console_token) → /console/api/apps/{app_id}/workflows/draft GET/POST 批量改 LLM 节点 System Prompt;发布仍需手动。
  • RAGFlow:生产 http://10.80.0.85:8080/ / API :9380
  • 映射策略:联软(主) > aTrust(VPN) > eHR(静态)

企微JS-SDK技术

  • 双鉴权:wx.config()(jsapi_ticket) + wx.agentConfig()(agent_config_ticket),签名算法相同但不能混用
  • wx.invoke('thirdPartyOpenPage', {oaType:'10001', templateId, thirdNo, extData}) 原生打开审批表单
  • 后端端点:GET /wecom/jsapi-config?url=...&with_agent_config=true
  • 前端composablefrontend-h5/src/composables/useWecomApproval.ts(懒加载+全降级+超时保护)
  • 既有bugEmergencyDispatcher.vue 第99-119行 复用jsapi签名给agentConfig(靠3秒超时兜底)

已上线功能模块

  • 群聊(摇人/邀请/四角色) / 审批(12类型18流程/三级意图) / 代办(getapprovalinfo+Semaphore/缓存45s)
  • IT资产推送(模板Bs7ucT...) / 语音转文字(手机JS-SDK/PC百度ASR) / 截图拍照 / 复杂场景P0~P3
  • 会议室预定(终端/itterminal/,企微会议室Secret待申请)
  • 上下文感知智能诊断→修复闭环(三层诊断+三段排队+答题插队+五场景关闭);H5 QueueWaiting/RightPanel双Tab/InputBar三态人工按钮/ResolveConfirmCard;坐席pending_close结单
  • 单通道统一消息架构:Dify输出JSON {text,action,options} → 后端发双WS(ai_reply+dynamic_recommend) → 文字到气泡/卡片到侧边栏;坐席端 ai_thinking 指示器 + ai_structured/byod_card 渲染

H5 版本部署记录

  • v4:人工按钮三态"人工坐席",直接调 store.shakeAgent()
  • v5RightPanel v2.1 删软件安装/资源权限标签,智能推荐直接展示
  • v7(已部署 2026-07-13:① InputBar 删除📷截图图标+说明(工具栏仅表情/文件)② ParticipantStrip 加 hover tooltip(姓名+角色+部门,仅PC) + +邀请按钮(canInvite) + InviteParticipantSheet 引用 ③ 头像条位于会话框正上方 v-if="store.participants.length>0" 保持;④ 修复 CSP 头(添加 'unsafe-inline'https://at.alicdn.com)⑤ 修复 docker-compose mount(新增 h5 目录 bind mount);构建 index-BFvX9hTe.js / index-DLWx4YQ2.css
  • v11(已部署 2026-07-13:修复"IT资产升级"审批报错"审批模板ID不正确"——原企微审批模板 Bs7ucTGsPuFhxfk8pn8EydxrWxkVetB4JR8Pb6PHS 已失效,改用 ITSM 工单系统 https://devops.dc.servyou-it.com/ITSM/workflow/service/createTicket?name=IT%E8%AE%BE%E5%A4%87%E5%8D%87%E7%BA%A7%E4%B8%8E%E7%A1%AC%E4%BB%B6%E7%BB%B4%E4%BF%AE
  • 2026-07-17)零信任VPN卡片免登录修复:将ITSM跳转URL从 devops.dc.servyou-it.com 改为 itsm.servyou.com.cn(企微应用主页域名,从企微工作台打开时免登录)

免登录跳转域名选择(2026-07-17)

  • ITSM系统:使用 itsm.servyou.com.cn(企微应用主页域名)可实现免登录
  • 旧域名 devops.dc.servyou-it.com 需要扫码登录
  • 原因itsm.servyou.com.cn 已配置为企微OAuth2.0应用主页,从企微工作台打开时自带身份信息

组织架构树(2026-07-13 重构)

  • 层级树build_org_tree() 用企微 department/listparentid 构建真正层级树(非扁平分组)
  • 部门节点 ID 加 dept_ 前缀避免与员工 UserID 冲突;员工出现在其所属的所有部门下
  • 三层缓存:wecom:org_directory(1800s) + wecom:dept_list(1800s) + wecom:org_tree:{endpoint}(1800s)
  • get_org_directory()asyncio.gather 并行调用企微 API
  • 降级模式:部门列表不可用时 _build_flat_tree_by_name() 按名称分组
  • H5 前端:多层级扁平化渲染(非 van-collapse),深度缩进 + 展开折叠
  • Agent 前端:el-tree 原生支持多层级,无需改代码
  • 测试:backend/tests/test_org_tree.py 47 个单元测试

运维工具

  • SOPdocs/10-项目管理/IT智能服务台-标准作业流程SOP.md
  • 故障排查:docs/09-部署运维/00-标准故障排查手册.md
  • 全栈改造实施计划:docs/02-产品需求/AI对话链路全栈改造实施计划-v1.0.md