Files
zyt/server/docs/qywx-im-deploy.md
2026-05-11 17:49:38 +08:00

5.6 KiB
Executable File
Raw Permalink Blame History

企业微信 员工↔客户 IM 功能部署说明

本文档对应「管理后台 IM」功能(admin/src/views/chat),负责在后端/后台视角下的收/发一对一消息。

  • 发送:企业群发 add_msg_template(员工本人身份 + 手机端确认)
  • 接收:会话内容存档(官方 C SDK + RSA 解密 + 计划任务拉取)
  • 老回调接口 QywxExternalContactCallbackController 仍用于 添加/编辑/删除外部联系人 事件,不承载消息内容。

1. 数据表

执行一次:

mysql -u<user> -p<pass> <db> < server/database/migrations/2026_04_20_create_qywx_msg_tables.sql

新增 5 张:qywx_msg_sessionqywx_msg_archiveqywx_msg_archive_mediaqywx_msg_send_taskqywx_msg_archive_cursor

2. 配置(server/config/pay.php → wechat_work

'customer_contact_secret' => '客户联系 Secret',  // 已有:发消息 / 客户列表

// 会话内容存档
'msgaudit_enabled'         => true,               // 开关
'msgaudit_secret'          => '会话存档 Secret',  // 独立应用 Secret
'msgaudit_public_key_ver'  => 1,                  // 管理后台上传公钥返回的版本号
'msgaudit_private_key_path'=> '/data/qywx/priv.pem', // RSA 私钥文件路径(建议)
'msgaudit_sdk_lib_path'    => '/data/qywx/libWeWorkFinanceSdk_C.so', // SDK 动态库
'msgaudit_timeout'         => 60,
'msgaudit_limit'           => 500,

msgaudit_enabled = falsemsgaudit_sdk_lib_path 留空时,后端不会崩溃——拉取命令会以 noop 方式返回,方便「先上线、再接 SDK」。

3. C SDK & 私钥准备

  1. 从企微管理后台 → 安全与合规 → 会话内容存档 → SDK 下载区,下载官方 C SDK。
  2. Linux 部署 libWeWorkFinanceSdk_C.so/data/qywx/,并确保 PHP-FPM 账户有可执行权限。
  3. 安装 PHP FFIphp.ini 开启 ffi.enable=truepreload 场景用 preloadCLI + FPM 用 true)。
  4. 生成 RSA 密钥对:openssl genrsa -out priv.pem 2048 && openssl rsa -in priv.pem -pubout -out pub.pem
  5. 企微后台上传 pub.pem → 记录返回的 public_key_ver → 回填到配置。
  6. 私钥 priv.pem 放到 msgaudit_private_key_path 指向的位置,权限 600。

轮换公钥时,保留历史 public_key_ver → private_key 映射(SDK 会用旧消息的版本号去找旧私钥)。如需多版本,代码已预留:在 WeComFinanceSdkClient::loadPrivateKeys() 同一配置下,可额外传入 msgaudit_private_keys 数组形式支持多版本(自行扩展)。

4. 计划任务

推荐 30 秒一次(企微限制:每分钟不超过 600 次)。

Linux crontab(每 30s 跑一次的 2 行写法):

* * * * * cd /path/to/server && /usr/bin/php think qywx:sync-msg-archive --download >/dev/null 2>&1
* * * * * cd /path/to/server && sleep 30 && /usr/bin/php think qywx:sync-msg-archive --download >/dev/null 2>&1

可选:把媒体下载拆开、并发运行:

* * * * * cd /path/to/server && /usr/bin/php think qywx:sync-msg-archive >/dev/null 2>&1
*/2 * * * * cd /path/to/server && /usr/bin/php think qywx:sync-msg-archive --only-media --max-media=500 >/dev/null 2>&1

命令已做 flock 互斥(runtime/qywx_msg_archive.lock),并发多跑也不会重复写。

5. 权限与菜单

后台菜单需新增一条,路径 /chat(或自定义),component 指向 views/chat/index.vue

建议开启菜单权限控制:仅运营/客服组可见。API 路由前缀为 qywx.message/*,请在 adminapi 权限中心相应配置。

6. 使用流程

  1. 打开「IM」页面,系统自动拉取会话列表。
  2. 左侧可按员工筛选;选中会话后中间展示消息流,8 秒轮询新消息。
  3. 在底部输入框输入文本/添加附件(图片/视频/文件/链接/小程序)→ 点击「发送」。
  4. 后端创建企微 add_msg_template 任务,员工手机会收到确认弹窗,确认后客户即可收到。
  5. 已发送任务可在右侧「发送任务」Tab 查看送达详情。

7. 故障排查

症状 排查
前端顶部提示「会话存档 SDK 不可用」 config/pay.php msgaudit_* 配置 + libWeWorkFinanceSdk_C.so 路径 + ffi.enable + 日志 runtime/log/。调 GET /adminapi/qywx.message/archive_status 看诊断。
消息拉取无数据 php think qywx:sync-msg-archive -vvv;看 qywx_msg_archive_cursor 表 seq 是否推进;确认企微已开通会话存档 License 并勾选目标员工。
媒体文件一直下载中 qywx_msg_archive_media.status / retry_count / last_error;路径 runtime/qywx_msg_media/ 写权限;SDK GetMediaData 超时调大 msgaudit_timeout
发送「消息内容不能为空」 文本 + 附件都为空;或附件上传失败导致没有 media_id,面板会红色报错。
发送成功但客户未收到 员工手机端漏点确认;或该员工未启用企业群发能力;查 qywx_msg_send_task.fail_list & 右侧「送达详情」。
需要撤回消息 企微规则:群发任务已提交后无法撤回单条;会话存档里会记录 recall 动作并在前端打「已撤回」标记。

8. 未来扩展点

  • 多版本 RSA 私钥轮换:WeComFinanceSdkClient::loadPrivateKeys() 改造为读取 msgaudit_private_keys 数组,key 为 public_key_ver
  • WebSocket 推送新消息:在 QywxMsgArchiveService::persistBatch() 写入后发布到 Workerman / Swoole,前端改成订阅(当前是 8s 轮询)。
  • 群聊发送:企微「客户群 SOP」接口,当前 UI 仅展示群会话消息不允许发送(canSendMessage 为 false)。