13 KiB
13 KiB
IT智能服务台 - 项目记忆
测试铁律
- e2e 测试 poll 不能依赖
after_id(UUID 排序 ≠ 时间排序):messages/poll 的after_id参数使用数据库主键 UUID 排序,与created_at时间戳排序不一致。跨会话复用用户时可能 poll 到修复前的旧消息。应使用created_at时间戳过滤 + 唯一测试用户。 - 宣布修复前必须端到端验证:容器内测试通过 ≠ 外部用户可用。需经过 Mock 登录 → 发消息 → 查回复 全链路验证。
设计决策(锁定)
- AI交互:小段多回合;术语:员工端"人工坐席"按钮 = 用户呼叫坐席(统一命名);"摇人"=坐席呼叫坐席
- 原型:坐席v5.3 + H5 v1.1;UI:企微浅色扁平,accent=#07C160
- 统一入口
/itportal/→ user/agent/admin;admin需OTP - H5 布局铁律:人工坐席按钮在"发送键和语音按钮上方";截图说明 PC 显示/移动端隐藏
技术架构
- 前端:坐席(Vue3+Element Plus) / H5(Vue3+Vant4) / 管理后台(Vue3+Element+Tailwind)
- 后端:FastAPI + SQLAlchemy + PostgreSQL + Redis(代码在
app/) - 字段映射:后端
id/sender_type→ 前端message_id/message_type(conversation.ts的mapMessage()) - WS双连接池:
active_connections(agent) +employee_connections(H5) - H5 参与者系统已完整存在:
ParticipantStrip/ParticipantList/InviteParticipantSheet+useParticipantDisplaycomposable;ROLE_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 backend;env变更→docker compose up -d backend(restart不重载env) - docker-compose.yml environment 铁律(2026-07-13 第二次踩坑导致 P0
[object Object]):.env变量不会自动传入容器,必须在docker-compose.yml的environment:显式声明每个变量(如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)
- H5:
- 服务器 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 前端拦截器 Bug(2026-07-13 修复)
- 根因:
api/index.ts拦截器return res.data剥离了 axios 外壳,但 10 个文件仍用response.data.data旧模式 - 影响:管理后台所有 API 调用 TypeError 被 catch 吞掉 → 集成页面"测试连接"报"请求失败,请检查网络连接"
- 修复:10 文件 25 处
xxx.data.data→xxx;3 种变量名模式:response/res/leakResp - 铁律:新增 API 调用时直接用返回值(
const data = await getXxx()),不要response.data.data - Vite 构建铁律:
dist/assets超 50 文件时 safe-delete 会阻止构建,需先重命名旧 dist 为 dist_bak 再构建 - Vite
@别名铁律(2026-07-13):Windows 上resolve.alias: { '@': '/src' }会解析为 FS 根路径(D:\src\),必须用fileURLToPath(new URL('./src', import.meta.url)) .d.tsvs.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.36MBtar.gzMD5 完全匹配 ✅,推荐优先使用。如必须用 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-timeout15s。脚本 print 用 ASCII(禁用 emoji,否则 GBK 崩溃)。上传后比对远程 md5sum 与本地。 - pscp/plink -T不可用;elFinder上传后需手动mv;httpx.Timeout须含default
- JumpServer v2.28 变更:登录新增图片验证码(CAPTCHA);connection-token 端点改为
/api/v1/authentication/connection-token/
外部集成
- 企微通讯录:通讯录同步Secret
BM6iosc3gKnPqkEXmsQN3ErJUpfO-whfMUN646eezB8已废弃(2022年8月后新增IP不能调department/list和user/list,errcode=48009,非IP白名单问题)。改用自建应用Secret + 可见范围设为全公司,.env中WECOM_CONTACT_SECRET=留空触发降级。验证:651部门/7098员工 - Dify:
http://yw-dify.dc.servyou-it.com/v1/chat-messages- 审批意图Key
app-7jkRkAzvX4QM9v9SM3P8mMEO(✅200,结构化JSON) - 分诊Key
app-z3S9AEUUAVPbtR2rioxpiIvp(✅200,结构化JSON) app-UaTWYdBSwN6VktKQlbh5YN5H(✅200 纯文本,已禁用)app-J3s8sHarZQ2SCaNF3xCppliL(❌400 "Model credentials not initialized")- Dify App ID(Console):
8f0f3d62-f63d-4cf3-815e-b10529c66f1d(智能IT支持-员工咨询,advanced-chat,85节点)
- 审批意图Key
- ⚠️ Dify 发布铁律:
advanced-chat应用改工作流后必须浏览器手动点「发布」,否则API返回400"Workflow not published";此版本 publish 端点不支持 Console API 调用。 - Dify 原生 API 直连(v2.1):后端
_call_dify_native()直连/v1/chat-messages(Bearer+blocking),优先于代理;config.py配dify_native_base_url/dify_native_api_key,docker-compose.yml 须显式声明(.env定义不会自动传入容器)。- ⚠️ 两次踩坑:第一次是配置读取时未意识到容器内为空;第二次是
[object Object]根因正是此变量未声明导致原生 API 不可用、回退到 buggy 代理路径。 - ⚠️ 第三次踩坑(2026-07-13 坐席扫码):
WECOM_SSO_CALLBACK_BASE未声明导致qrcode_service.py抛异常ValueError: 请在环境变量中配置 WECOM_SSO_CALLBACK_BASE。 - 必须确保
environment:部分有(新增变量需同时加入.env和docker-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/draftGET/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 - 前端composable:
frontend-h5/src/composables/useWecomApproval.ts(懒加载+全降级+超时保护) - 既有bug:
EmergencyDispatcher.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() - v5:RightPanel 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/list的parentid构建真正层级树(非扁平分组) - 部门节点 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.py47 个单元测试
运维工具
- SOP:
docs/10-项目管理/IT智能服务台-标准作业流程SOP.md - 故障排查:
docs/09-部署运维/00-标准故障排查手册.md - 全栈改造实施计划:
docs/02-产品需求/AI对话链路全栈改造实施计划-v1.0.md