门店企微码 → 共享文档自动登记
固定文件夹里躺着一堆门店企微码,文件名就是门店名。新码一丢进来,自动走完
「读文件名 → 去重 → 加工成统一模板 → 第一列写门店名、第二列写图片链接」 四步,人不用插手。
核心链路
源文件夹(门店名.png) ──扫描──> 按名去重 ──加工──> 模板图 ──写入──> 腾讯文档表格
第一列: 门店名称(文本)
第二列: 企微码图片链接(可点击)
- 第一列:文本字段,值 = 图片文件名(已清洗,去掉「企微码/二维码」等冗余词)
- 第二列:成品图的永久图片链接(腾讯文档 CDN,可点击访问);成品图同时留存到源文件夹下的独立目录(默认「已制作/」)
> 为什么是链接不是图片:腾讯文档在线表格没有图片插入接口,只适合存图片外链;
> upload_image 上传的图经智能表格图库转存后得到 docimg*.docs.qq.com 永久 CDN 链接,写进表格即可长期访问。
环境要求
| 项 | 说明 |
|---|---|
| Python | 3.10+,装有 Pillow(pip install Pillow) |
| wecom-cli | 企业微信 CLI(可选,企微后端需要) |
| 配置文件 | 技能目录下的 config.json(从 config.example.json 复制) |
| 主流程 | scripts/registry.py(企微后端)/ scripts/tdocs_push.py(腾讯文档后端) |
| 加工引擎 | scripts/render.py |
| 腾讯文档直连 | scripts/tdocs_mcp.py(大 base64 参数不走对话上下文) |
| 模板图输出 | output/(默认,可在 config 改) |
> 脚本里的 Python 解释器路径请在本地按实际环境替换(Windows 示例:C:/Users/<你的用户名>/.workbuddy/binaries/python/envs/default/Scripts/python.exe,或用 python / py 命令)。
选哪个后端
| 后端 | 脚本 | 前提 | 图片写入方式 |
|---|---|---|---|
| 腾讯文档智能表格(当前在用) | tdocs_push.py |
腾讯文档连接器已连接 | 本地图 → 压缩 → upload_image 换 image_id → 写入,图片永久存腾讯文档 CDN |
| 企业微信智能表格 | registry.py |
机器人有「文档」权限(常过期) | 直接把本地路径传给 IMAGE 字段,后台转存 |
企微机器人文档权限过期时会报 errcode 850003,此时改用腾讯文档后端,不要反复重试。
从零接入(三步上手,市场用户看这里)
- 准备源文件夹:建一个文件夹,把各门店的企微码图片放进去,图片文件名就是门店名(如
HZ安庆市集贤花苑店.png)。文件名里的「企微码/二维码/副本」等冗余词会被自动清洗掉。 - 建腾讯文档智能表格:打开 docs.qq.com → 新建 → 智能表格,把默认第一列改名为「门店名称」,再加一列「企微码」(图片类型)。复制表格链接。
- 改配置:把
config.example.json复制为config.json,只改四处:
-source_dir→ 你的企微码文件夹路径
-tdocs.url→ 上一步复制的表格链接(file_id/sheet_id 可留空自动解析)
-template.base_image→ 你的模板图路径(想用脚本自动绘制则把template.mode改为build_canvas)
-template.qr.box/template.store_name→ 模板图上二维码和店名的像素坐标(详见references/template-tuning.md)
然后跑 python scripts/tdocs_push.py --dry-run 预览,确认无误后正式执行。就这么简单,不用动任何代码。
首次配置(只需做一次)
编辑 config.json,填这三个值:
"source_dir": "D:/门店企微码",
"tdocs": {
"backend": "smartsheet",
"url": "https://docs.qq.com/smartsheet/你的表格链接",
"col_store_name": "门店名称",
"col_qr_image": "企微码"
}
url 填表格链接即可,file_id/sheet_id 脚本会自动解析;解析失败时用腾讯文档 MCP 的 smartsheet_get_sheet 查询后手动填入。若改用企业微信智能表格后端,则填 target.docid / target.url:
wecom-cli doc smartsheet_get_sheet '{"url": "表格链接"}'
然后初始化表结构(自动创建缺失的两列;仅企微后端需要):
python "技能目录/scripts/registry.py" --init
日常使用
默认:腾讯文档后端(推荐)
PY="python" # 换成你的 Python 解释器
TD="技能目录/scripts/tdocs_push.py"
"$PY" "$TD" --dry-run # 只渲染不上传(推荐先跑这个预览)
"$PY" "$TD" # 正式:渲染 → 压缩 → upload_image → 写入表格
"$PY" "$TD" --force # 忽略已有记录全部重推
"$PY" "$TD" --only 安庆 # 只处理名字含关键字的门店
备选:企业微信智能表格后端
PY="python" # 换成你的 Python 解释器(如 python / py / 完整路径)
REG="技能目录/scripts/registry.py"
"$PY" "$REG" --dry-run # 预览:会新增哪些、更新哪些(推荐先跑这个)
"$PY" "$REG" # 正式执行
"$PY" "$REG" --force # 忽略去重,全部重做并覆盖
"$PY" "$REG" --only "北京,上海" # 只处理含指定关键词的门店
"$PY" "$REG" --config D:/other.json # 换一套配置(多品牌场景)
脚本输出 JSON 报告到 stdout,包含 scanned / new / updated / rendered / failed / warnings。
关键实现点:
upload_image只接受 base64,不能传路径。图片先按tdocs.upload.max_width缩放并转 JPEG(默认 600px / q80,约 67KB),否则 base64 会撑爆上下文。- base64 全程在 Python 内部流转,脚本通过
tdocs_mcp.py直连宿主本地 MCP 代理(票据从CODEBUDDY_MCP_CONFIG自动取),不经过命令行、不进对话。 - 新建的智能表格自带 5 行空记录,首次跑完要用
smartsheet.delete_records清掉。 upload_image返回的 image_id 有效期一天,指的是必须在这天内写入文档;一旦写进表格,图片会落到docimg*.docs.qq.com永久可访问。
执行后必须向用户汇报:新增了哪些门店、更新了哪些、有没有失败项。
加工模板
模板参数全部集中在 config.json 的 template 段,改 JSON 即可,不要改代码。
支持两种模式(template.mode 切换):
模式 A:fill_template(当前默认)—— 用户自带模板图
用户给一张设计好的海报/卡片图,脚本只把门店码贴到指定空白区,店名写在门店码下方。原模板上若有占位灰字,先用白矩形擦除再写新字。
| 段 | 作用 |
|---|---|
template.mode |
设为 fill_template |
template.base_image |
模板图绝对路径(兼容 CMYK) |
template.qr.box |
门店码在模板图上的位置 {x, y, w, h},单位 px(用原图坐标系) |
template.qr.padding |
门店码内边距 |
template.store_name |
门店码下方的店名:cx 横坐标 / y 顶 y / font_size / font_color / max_width 自动缩字号 / eraser_box 擦除原占位灰字 |
template.font |
字体路径,默认微软雅黑,带 fallback |
template.output |
输出格式与文件名规则 |
模式 B:build_canvas —— 脚本从零绘制
如果用户没给模板图,脚本自己画一张 800×1200 的卡片:背景色 / 顶色带 / 标题 / 副标题 / 二维码(圆角、阴影)/ 引导语 / 页脚。
| 段 | 作用 |
|---|---|
template.mode |
设为 build_canvas |
template.canvas |
画布尺寸,默认 800×1200 |
template.background |
底色 / 背景图 / 顶部色带 |
template.title |
门店名大标题,{store} 是门店名占位符 |
template.subtitle |
副标题 |
template.qr |
二维码区:尺寸、圆角、内边距、边框、阴影、auto_trim_whitespace 自动裁白边 |
template.caption |
二维码下方引导语(如「长按识别二维码」) |
template.footer |
底部小字 |
文字内容支持 {store} 占位符和 \n 换行。
详见图层坐标与调参说明:references/template-tuning.md。
用户提供参考图时
- 让用户把参考图路径告诉你
- 按参考图的 比例 / 配色 / 文字位置 修改
config.json的template段 - 用一张真实二维码跑一次,把生成的模板图
present_files给用户看 - 按反馈微调数值,直到对齐
配置项速查(config.json)
| 字段 | 说明 |
|---|---|
source_dir |
固定文件夹绝对路径,脚本递归扫描所有图片 |
output_dir |
模板图输出目录,auto 用 skill/output/,可换成别的盘 |
tdocs.url |
腾讯文档表格链接(默认后端,file_id/sheet_id 自动解析) |
tdocs.backend |
smartsheet(智能表格,默认)/ sheet(在线表格写链接) |
target.docid / target.url |
企微智能表格定位,二选一(仅企微后端) |
target.sheet_id |
子表 ID;首次配置留空,跑 --init 自动建列 |
target.col_store_name |
第一列字段名(默认 门店名称) |
target.col_qr_image |
第二列字段名(默认 企微码,类型 FIELD_TYPE_IMAGE) |
dedupe.mode |
by_store_name(默认)/ by_mtime / none |
dedupe.update_existing_image |
已存在门店是否重新加工并覆盖第二列图片 |
name_clean.strip_patterns |
文件名清洗的子串列表(去掉「企微码」「_qr」之类) |
name_clean.trim_chars |
清洗后去掉的前后字符 |
name_clean.ignore_filename_patterns |
文件名正则黑名单,避免把输出图/临时文件当源图 |
template.* |
见 references/template-tuning.md,改 JSON 即可 |
> 不知道写什么字段值?参考 config.example.json,改四处:source_dir、tdocs.url、template.base_image、template.qr.box。
行为约定
- 去重:默认按门店名比对第一列已有值,只登记新增门店(可在
dedupe.mode改) - 更新:已存在门店默认会重新加工并覆盖第二列图片(
dedupe.update_existing_image) - 防循环:自动跳过输出目录内的文件和
*_企微码模板.png,避免把生成的图当源图重复吃进去 - 批量:写入按 20 条一批,单批失败不影响其他批次,错误汇总在
push_errors - 重试:wecom-cli 调用失败自动重试 1 次,间隔 2 秒
常见故障
| 现象 | 排查 |
|---|---|
source_dir 无效 |
配置路径用了 \ 分隔符或含中文被转义,改用正斜杠 / |
errcode 非 0 |
权限不足或 docid/sheet_id 错;跑 smartsheet_get_sheet 确认能读到表 |
| 第二列空白 | 图片字段类型必须是 FIELD_TYPE_IMAGE,用 --init 自动建列 |
| 表格多出一个空列 | 新表自带默认文本列,用 smartsheet_update_fields 把它改名成第一列 |
| 文字是方块/极小 | 字体路径失效,检查 template.font,Windows 默认 C:/Windows/Fonts/msyh.ttc |
| 二维码糊 | 报告里 low_res_warning: true,说明原图分辨率低于模板尺寸一半,需要门店补发高清码 |
| 中文乱码 | 已设 PYTHONUTF8=1;若仍乱码,检查终端编码是否为 UTF-8 |