POST /api/product/batchEdit/getShopItemInfoPage form 编码
size=1¤t=1&descs=&ascs=&ids=<id>&fields=video,videoUploadIdStr,videoFailReason,tempVideoUrl
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
基本信息
依赖与并行
videos表记录。#15 修改了videos与products的状态写入时机,必须在其之上做。子项目影响
原始需求
要解决什么
现状
app.go的UploadVideos是占位实现,点「上传数据」直接报错,返回「「上传数据」还没实现,见工单 R5」。本地已有 4 个下载完成的视频,
upload_status全为pending,文件均存在,products表已具备上传所需的id(货憨憨内部记录 ID)与platform_shop_id。目标
把本地视频上传回货憨憨并关联到对应商品,使 Shopee 商品页刷新后能看到视频,从而打通 Epic 的最后一环。
接口契约(2026-09-03 由 HAR 确认,Q1 / Q2 关闭)
证据:
payloads/huohanhan_batch_save_product_video.har(9-03 抓取,共 11 个请求)。第一步:上传素材
bean是数组,元素就是最终可用的视频 URL。上传接口不需要
productId或platformShopId—— 素材与商品是解耦的。只上传不关联,结果只是一个孤儿素材。第二步:关联到商品
{type, bean}包装videoUrl传空字符串是删除动作(HAR 第 1 个请求就是删除),即该接口是覆盖语义,一个商品只能挂一个视频第三步(可选):回读校验
返回
records[0].video为空数组表示无视频,有元素表示已挂上。明确否决的另一条路
payloads/huohanhan_save_product_info.har(单商品编辑表单)走的是common-product/uploadVideo+common-product/updateProductItem。本工单不采用,原因:updateProductItem需要回传整份商品:56 个字段、26589 字节、20 个 SKUgetDetail返回的bean.itemInfo无法直接回传:13 个字段缺失、9 个结构不同model[].priceInfo的值就不一致 —— 那是价格数据,照抄会把真实店铺的价格写坏,且不可逆batchUpdateShopProductVideo只改videoUrl一个字段,完全不碰价格、库存、SKU。做什么 / 不做什么
videos.remote_url/videos.status与products.upload_statusupdateProductItem路线已确认方案
安全边界(AGENTS.md 红线,最高优先级)
这是对真实店铺的写操作,不可逆。
图片空间容量门禁
Epic #2 的 Q8 记录:货憨憨图片空间已用约 98.7%,剩余约 26 GB。视频体积远大于图片,批量上传很容易撞上限。
product/material/getMaterialSize,该接口尚无抓包证据,需先确认真实路径与返回结构)一个商品只挂一个视频
batchUpdateShopProductVideo的videoUrl是单个字符串,覆盖语义。而max_videos_per_product当前为 2。处理方式(负责人未另行指定,按 2026-09-03 推荐方案采用):上传时取该商品
videos表中第一个 status 为 downloaded 且文件存在的记录,max_videos_per_product保持 2 不变 —— 多下载的那个作为备选保留,将来第一个视频有问题时可以换。不修改配置默认值。状态写回
videos.remote_url记返回的 COS 地址,videos.status置uploaded,products.upload_status置doneproducts.upload_status置failed,last_error记中文原因products.upload_status置running回读校验
第二步返回 SUCCESS 后,调用
getShopItemInfoPage回读该商品,确认records[0].video非空再写upload_status为done。回读失败或仍为空时记为失败并提示,不假定成功。实现位置
internal/huohanhan/upload.go、upload_test.go(新建):两个接口的封装与响应解析。复用现有Client.Request(它已支持自定义 contentType 与 401 重试),不新建 HTTP 客户端mime/multipart构造。视频 1—5 MB,一次性读入内存可接受,不做流式internal/store/video.go:新增按商品取可用视频、写回remote_url与状态的方法app.go:UploadVideos落地frontend/src/views/ProductListView.vue:二次确认框与单选限制预计修改文件:
internal/huohanhan/upload.go、upload_test.go(新建)internal/store/video.go、video_test.gointernal/store/product.go(若需新增查询)app.gofrontend/src/views/ProductListView.vue不新增第三方依赖。
internal/下不得 import wails。需求变化记录
huohanhan_batch_save_product_video.harupdateProductItem路线priceInfo值不一致会写坏价格max_videos_per_product设计与原型门禁
文档影响
internal/huohanhan/upload.go交付文档影响
任务记录与可选快照
验收标准
uploadFiles请求为 multipart,字段名与 HAR 一致(files/isLocalFile为 true /fileType为 1),文件名取本地文件名bean数组取出 COS 地址batchUpdateShopProductVideo请求体为裸数组,元素含且仅含id/platformShopId/videoUrlgetShopItemInfoPage,确认video非空才写donevideos.remote_url/videos.status/products.upload_statusinternal/下不得 import wails;不新增第三方依赖验证方式
可离线执行:
单元测试用
httptest起假货憨憨服务器,不得连真实货憨憨,需覆盖:bean数组解析;bean为空数组时报错而不是静默成功真机验证(必须由负责人执行,且限定范围):
40483130206(id为1114185406108811264,platformShopId为1044466812,本地视频已存在),该商品在 9-03 的 HAR 中已被人工走过同一链路,风险可控风险和回退
product/material/getMaterialSize尚无抓包证据,路径与返回结构未经验证。缓解:实施时先确认;无法确认则降级为确认框提示,并在工单记录。batchUpdateShopProductVideo是覆盖语义,对已有视频的商品执行会替换掉原视频。缓解:只对video_diagnosis为missing的商品开放上传,确认框中显示当前视频状态。git revert。但已经写入货憨憨的数据不会因此回滚 —— 需要在货憨憨界面手动把videoUrl清空(HAR 证实传空字符串即删除)。这正是首版限定单商品的原因。范围确认:容量判断延后(2026-09-03)
负责人指示:「先实现上传,后面再来增加容量判断。」
本工单不做容量判断的任何逻辑。 依据:
payloads/下所有 HAR 中均无
product/material/getMaterialSize的任何证据,路径、请求格式和返回结构全部是未经验证的推测,不得凭猜测实现。
本工单只保留一行静态提示放在二次确认框里:
除这行文案外,不做任何容量相关的查询、判断、计算或错误分支。
上传接口返回的错误一律转成可读中文并立即停止、不重试。
「上传前完成容量检查;容量不足直接停止不发起上传」这条验收标准
从本工单移除,改为:确认框中必须出现上述提示文案。
容量门禁待负责人补抓包后另开工单。
至此本工单无待确认项,状态转为待实施,已派给 Codex CLI 实施。
最终实施证据
提交:
d1149b6feat: 视频上传回货憨憨并关联商品,首版限单商品 (#17)已推送到
origin/main。改动文件(6 个)
internal/huohanhan/upload.go(新建)UploadMaterial(multipart)、UpdateShopProductVideo(裸数组三字段)、HasShopProductVideo(回读校验)internal/huohanhan/upload_test.go(新建)httptest假服务器覆盖三个接口internal/store/video.go/_test.godownloaded且文件真实存在的视频;MarkVideoUploaded写回remote_url与状态app.goUploadVideos落地、GetUploadPreview、Go 侧单商品拦截、失败状态写回frontend/src/views/ProductListView.vue复用现有
Client.Request(已支持自定义 contentType 与 401 重试),未新建 HTTP 客户端。新增 Wails 绑定:
GetUploadPreview(productIDs []string) (UploadPreview, error)(
frontend/wailsjs/go/为生成产物,已在.gitignore)。UploadVideos为既有绑定,签名未变。验证结果
10 项硬性验收逐条复核,全部通过:实施全程未向 www.huohanhan.com 发出请求
(日志中出现的该域名均为读取 HAR 文件时的 Host 字段);前端无绕过 Wails
生成绑定的写法;
internal/未 import wails;Go 侧无任何容量相关逻辑;batchUpdateShopProductVideo传的是product.ID而非ItemID;单商品限制拦截在 Go 侧(
app.go:970);回读校验未省略,HasShopProductVideo确认后才写done;go.mod/go.sum未变;未执行 git 以外的远端操作;
payloads/、config.yaml、config.example.yaml与参考实现目录均未改动。审核时清理了
app.go中一处死代码(_ = preview)。未验证内容(重要)
httptest假服务器覆盖,从未与真实货憨憨交互。全部未经验证。
待负责人真机验证(务必限定范围)
40483130206(
id为1114185406108811264,platformShopId为1044466812,本地视频
40483130206_1.mp4已存在),该商品在 9-03 的 HAR 中已被人工走过同一链路,风险最低。
若发现商品数据被写坏,可在货憨憨界面把视频清空回滚
(HAR 证实
videoUrl传空字符串即删除),并立即反馈。文档影响:本工单声明需更新业务规则与术语、架构与代码地图、需求总览
(关闭 Q1 / Q2)三处 Wiki。尚未执行,待验收通过后一并处理。
工单保持「待验收」。
真机验证发现缺陷并修复(2026-09-03)
现象:负责人对
55066525387(id为1124684165671051264)执行上传,报错「回读商品视频失败:货憨憨尚未显示已关联的视频」。
但到货憨憨界面确认,视频其实已经上传成功。
根因:回读判据写错了,不是接口问题。
uploadFiles与batchUpdateShopProductVideo都返回了 SUCCESS,失败卡在回读这一步。原实现只看
records[0].video非空。但
video字段装的是已经在 Shopee 上生效的视频,不是刚设置的那个。货憨憨推送到 Shopee 是异步的,保存成功后
video必然还是空的,视频这时在
tempVideoUrl和videoUploadIdStr里。证据在
payloads/huohanhan_save_product_info.har的第 3 个请求,那是一次保存成功后立刻发起的
getDetail:对照批量 HAR 也一致:视频还在时
video里是 Shopee CDN 地址(
cvf.shopee.tw/...),删除后video与tempVideoUrl同时清空。这条证据在建单时就已经在仓库里,定回读判据时没有用上。
修复(提交
0fe24f7,已推送origin/main):HasShopProductVideo改为CheckShopProductVideo,返回四个字段并按优先级判定:videoFailReason非空last_errorvideo非空tempVideoUrl或videoUploadIdStr非空配套变化:
upload_status = 'done'的语义明确为「已提交并回读确认」,不是「Shopee 已可见」——后者是异步结果,本地无法立刻断言。
日志分别提示这两种情况。
Confirmed():等待同步中的视频同样会被本次上传覆盖,原来只看
video会漏掉这种情况导致警告不显示。这是同一个根因的第二处影响。Test刚保存完video为空但tempVideoUrl有值应判为成功直接复刻本次故障,注释里写明了故障来源,防止再犯。
数据订正:
55066525387被误判写成的upload_status='failed'已改回done,last_error清空,videos.status改为uploaded。遗留:该商品的
videos.remote_url为空——COS 地址由uploadFiles返回,当时因判定失败没有落库,事后无法补回。不影响功能,仅少一条溯源信息。
后续正常上传的商品会正常记录。
验收标准修正:原「上传成功后回读
getShopItemInfoPage,确认
video非空才写done」改为「按上表四字段优先级判定,video非空或tempVideoUrl/videoUploadIdStr非空均判为成功」。验证:
go vet ./...、go test ./...、npx vite build全部通过。仍待负责人确认:
55066525387的价格、库存、SKU 是否未被改动;以及稍后 Shopee 商品页能否看到视频。