自动化驱动运营,让电商卖家从重复劳动中解放出来。
项目背景
Temu 平台 POD 商品的日常运营高度依赖手工操作:按品类规则填写商品 Excel、维护模板 SKU 与颜色尺寸、逐一上传产品图到云存储、从订单导出文件解析 SKU 并匹配消费者定制图片、手动去除产品图水印、批量生成商品效果图,再把订单交给本地生产设备处理……这些流程繁琐、易出错,且没有任何可复用的工程化积累。
这个项目是我以工程师视角接手这些业务后,独立完成并持续扩展的全链路自动化系统。核心目标不只是“少点几下”,而是把商品、素材、订单、生产和状态回传收束到同一套可配置、可追踪、可扩展的工具链里。
Vue 3 Composition API
TypeScript · Vite
Naive UI · Pinia
Vue Router · ofetch
useSSETaskuseOrderTaskusePlanEditorPython 3.12 · Uvicorn
Pydantic · SQLModel
Alembic · boto3
google-genai · Playwright
PostgreSQL — 图库元数据
SQLite — 订单历史
JSON — SKU 映射 · 索引
Cloudflare R2 — 图片 CDN
按访问模式选型,职责分离
业务闭环
模板管理、SKU/颜色/尺寸维护、标题库、印花库、标签导入、PSD 与静态图状态检查。
根据 upload_plan 编排多店铺任务,批量生成 Temu / 妙手 Excel,上传图片到 R2,并处理活动与价格相关操作。
解析订单导出文件,校验消费者定制图片,生成生产资源,并将任务同步到本地生产节点执行打印和 PLC 出料。
这次扩展后,平台不再只是“生成 Excel + 上传图片”的工具,而是覆盖 POD 商品运营全流程的工作台:前端已经包含订单处理、订单管理、ERP 接入、活动管理、模板管理、Excel 生成、图片上传、AI 去水印、印花库、印花标签、批量渲染、渲染任务、日志统计、MCP 接入和子系统节点管理等页面。所有高耗时任务通过统一任务接口和 SSE 日志流反馈状态,减少运营人员在表格、终端、浏览器和本地设备之间来回切换。
技术深度
所有长任务都面临同一问题:耗时数秒到数分钟,用户需要实时进度反馈。我选择 SSE 而非 WebSocket——纯 HTTP 单向推流,无需升级协议,与 FastAPI StreamingResponse 天然契合。后端为每个任务分配 UUID,前端 useSSETask composable 统一管理连接生命周期,各模块零重复接入。
@router.get("/sse/{task_id}")
async def sse_stream(task_id: str):
async def event_generator():
queue = task_queues.get(task_id)
while True:
msg = await queue.get()
if msg is None: break # 任务结束信号
yield f"data: {msg}\n\n"
return StreamingResponse(event_generator(), media_type="text/event-stream")图片上传是 I/O 密集型任务——网络传输时间远大于 CPU 计算时间。用 ThreadPoolExecutor(max_workers=48) 实现并发,将串行耗时压缩到约 1/48。48 是通过实验调参得出的 R2 API 限速与本地带宽的最优平衡点。上传完成后自动重建 data.json 资源索引,作为与订单模块之间唯一的数据契约。
with ThreadPoolExecutor(max_workers=48) as executor:
futures = {executor.submit(upload_single, p, bucket): p for p in paths}
for future in as_completed(futures):
try:
future.result()
task_queue.put(f"✓ {futures[future].name}") # SSE 推流
except Exception as e:
failed.append((futures[future], str(e)))
rebuild_index(bucket) # 重建资源索引核心原则:视图层只做渲染,业务逻辑封装在 Composable。四个 Composable 各司其职,且可相互组合——useOrderTask 内部组合了 useSSETask,复用日志流逻辑。TypeScript 在 10 个 API 模块中统一了请求/响应类型,多次重构中精准捕获字段改名引发的编译错误。
useSSETask通用SSE 连接生命周期管理,暴露 logs / isRunning,所有模块复用
useOrderTask订单订单选择、预处理、批量提交,维护 failedImages,组合 useSSETask
usePlanEditor配置YAML Plan 的 CRUD:GET 加载 → 本地编辑 → POST 持久化
useUploadEditor上传上传任务配置管理,模式同 usePlanEditor,增加字段校验
- ›仅暴露 HTTP 端点
- ›Pydantic 入参校验
- ›调用 Service,不含业务逻辑
- ›按业务域拆分为 10+ 路由
- ›核心业务逻辑
- ›可独立单元测试
- ›跨 Router 逻辑复用
- ›封装外部 API / 设备调用
- ›PostgreSQL — 结构化元数据
- ›SQLite — 轻量本地历史
- ›JSON/YAML — 配置与索引
- ›R2 — 图片对象存储
SQLModel(SQLAlchemy + Pydantic 的融合)让同一个 Model 类同时充当 ORM 映射与 API Schema,消除了重复定义。Alembic 管理 PostgreSQL 迁移历史,每次字段变更都有版本记录。三类数据源按访问模式选型,不是过度设计,是针对各自场景的最优解。
传统水印去除依赖固定位置遮罩,但产品图的水印位置、字体、透明度各不相同。引入 Gemini 2.5 Flash 多模态模型,将图片与自然语言指令共同输入,让模型理解语义后执行图像编辑。
工程重点在提示工程:形成”描述任务 + 约束格式 + 给出示例”模板,针对纯色背景与复杂背景分别设计策略。批处理失败的图片进入重试队列,全程 SSE 推送进度。
订单进入生产阶段后,主系统只负责分发和记录状态,本地生产节点部署在实际连接打印机和流水线的电脑上。节点从主系统同步已发布订单,领取任务后按订单 SKU 顺序执行生产动作,调用本机打印机打印面单,并在 claimed、running、printed、done、failed 等关键节点回传状态。
PLC 控制层通过 python-snap7 连接西门子 S7-200 SMART,支持测试连接、测试输出点和按订单明细发送脉冲信号。为了适配真实产线,控制层将设备通讯与订单业务分离,后续可以替换为串口、Modbus 或 HTTP 设备接口,而不会影响主系统的订单模型。
早期脚本的主要问题是参数散落在代码里:换店铺、换模板、换输出目录都要改脚本。现在系统将任务描述从执行逻辑中抽离出来,使用 settings.yaml 描述默认路径和全局变量,用 catalog.yaml 合并商品目录,用 upload_plan.json 编排按日期执行的批量任务。后端同一套 Pipeline 同时暴露 CLI 与 HTTP API,开发调试可以走命令行,运营执行可以走前端按钮。
POD 商品图不是简单的图片上传,而是由模板底图、印花、颜色、定制类型和输出格式共同决定。平台将模板配置、印花标签、PSD 导入、区域配置和渲染任务拆成独立模块:模板页负责维护商品基础信息,印花库负责管理素材和标签,批量渲染模块根据印花区域把素材合成到底图上,渲染任务页负责查看异步任务状态。