feat: 按允许店铺筛选顺运宝同步 (#196)
This commit is contained in:
@@ -113,6 +113,9 @@ SQLite 同一时刻只允许一个写事务,连接放太开会互相抢锁、
|
||||
v13(#172)新增 `task_sequences`,把存量 `tasks.task_id` 按类型和创建时间确定性改为
|
||||
`cjN` / `cgN`,同步更新领取历史和顺运宝来源外键。历史 SQLite migrations
|
||||
保持冻结,不追加 v12/v13 生产表结构。
|
||||
v14(#196)新增 `syb_allowed_shops` 全局店铺准入表;`syb_sync_runs` 增加
|
||||
`accepted_stock_count`、`shop_skipped_count` 和 `shop_filter_hash`。旧同步记录回填为
|
||||
“接受数=原始货运单数、店铺跳过=0”;历史顺运宝货运单不删除。
|
||||
|
||||
**v3 为什么丢弃旧 `sku_mappings` 数据(见 #20):** 新主键需要 `pdd_option_key`,
|
||||
这是 Go 的 `service.OptionKey()` 用 `json.Marshal` 算出来的规范化键,SQL 语句
|
||||
@@ -517,6 +520,21 @@ CREATE TABLE syb_sync_state (
|
||||
`[必须]` 本表不保存顺运宝 Cookie、token、密码、验证码、收件信息或原始响应。
|
||||
失败原因最多保留 500 个字符,并在页面输出时由模板转义。
|
||||
|
||||
v14 起,`stock_count` 继续表示通过完整性校验的**原始货运单数**,避免改变旧字段
|
||||
语义;`accepted_stock_count` 是店铺准入后最终接受的货运单数,
|
||||
`shop_skipped_count` 是店铺为空、未启用或明细店铺变化而跳过的货运单数。
|
||||
`shop_filter_hash` 保存同步开始时启用店铺排序后计算的 SHA-256,只用于判断两次同步
|
||||
是否使用同一份快照,不保存 Cookie、密码或原始响应。
|
||||
|
||||
### 5.3 `syb_allowed_shops` 同步店铺准入(MySQL v14)
|
||||
|
||||
每个店铺只保留一条全局记录。`normalized_name` 是去除首尾空白后的名称并使用
|
||||
`utf8mb4_bin` 唯一约束;匹配不做模糊、正则或大小写折叠。停用代替硬删除,方便
|
||||
恢复和审计。同步开始时一次读取所有 `enabled=1` 的名称作为不可变快照。
|
||||
|
||||
`[必须]` 没有任何启用店铺时同步关闭失败,不请求顺运宝、不推进游标。该表只控制
|
||||
后续同步是否入库,不自动删除历史 `syb_orders`。
|
||||
|
||||
## 6. `spec_mappings` 顺运宝规格映射
|
||||
|
||||
"这个蝦皮商品的这条顺运宝规格 = 当前拼多多商品的那个规格",**匹配一次,以后复用**。
|
||||
|
||||
@@ -466,12 +466,15 @@ Go 的 map 是无序的,不靠它定顺序的话,同一个商品每次刷新
|
||||
### 6.1 工具条
|
||||
|
||||
```text
|
||||
开始日期 [2026-08-08] 结束日期 [2026-08-09] [同步] [同步记录]
|
||||
开始日期 [2026-08-08] 结束日期 [2026-08-09] [同步] [同步记录] [同步店铺(N)·管理员]
|
||||
[创建 PDD 采集任务] [创建采购任务] 处理阶段 [全部] 店铺 [___] 订单号 [___] [搜索] [删除]
|
||||
```
|
||||
|
||||
日期始终显示在主工具条,按 UTC+8 解释且两端都包含。首次打开页面固定默认昨天
|
||||
到今天,不因覆盖游标位置自动扩大范围;需要补历史缺口时由采购员明确选择日期。
|
||||
所有账号都能看到当前启用同步店铺数量;只有管理员显示“同步店铺”管理入口。
|
||||
管理页使用可见的“店铺名称”标签,支持新增、停用和重新启用,不提供硬删除。
|
||||
空状态必须明确提示先新增并启用至少一个店铺,否则同步会安全停止。
|
||||
|
||||
`[必须]` 「同步」是唯一同步入口:
|
||||
|
||||
@@ -490,8 +493,8 @@ Go 的 map 是无序的,不靠它定顺序的话,同一个商品每次刷新
|
||||
“最近一次同步报告”和持久化同步记录,下次刷新页面时状态条会显示:
|
||||
|
||||
```text
|
||||
同步完成:日期范围 2026-08-09 ~ 2026-08-09,货运单 12 张,商品明细 27 条
|
||||
(新增 20,更新 7,跳过 0)
|
||||
同步完成:日期范围 2026-08-09 ~ 2026-08-09,原始货运单 12 张,接受 9 张,
|
||||
店铺跳过 3 张;商品明细 27 条(新增 20,更新 7,数量跳过 0)
|
||||
```
|
||||
|
||||
有跳过/失败会在后面列出具体原因,不是只给个数字。同步中再次点「同步」会提示
|
||||
@@ -508,6 +511,8 @@ Go 的 map 是无序的,不靠它定顺序的话,同一个商品每次刷新
|
||||
`[必须]` 「同步记录」打开宽弹窗,按开始时间从新到旧分页显示状态、日期范围、
|
||||
操作账号、开始/完成时间、同步统计、覆盖游标结果和失败原因。状态至少区分同步中、
|
||||
成功、失败、已中断;不能只靠颜色表达。刷新或重启 Admin 后记录仍可查看。
|
||||
同步统计必须区分原始货运单、接受货运单、店铺跳过和数量异常跳过,不能混成一个
|
||||
“跳过”数字。
|
||||
|
||||
弹窗底部右侧依次放“刷新同步记录”、当前页、翻页组件和“关闭”。点击刷新后按钮
|
||||
显示“刷新中…”并暂时禁用;刷新和弹窗内翻页只请求受网页登录保护的同步记录
|
||||
|
||||
@@ -416,6 +416,16 @@ Go 侧不用跟着调。
|
||||
|
||||
这几条不是抓包结论,是本项目的决定,写在这里避免每次重新讨论:
|
||||
|
||||
`[必须]` **同步先校验原始全量,再做店铺准入。** 顺序固定为:按日期查询原始总数
|
||||
并执行单次容量熔断 → 拉完当天原始列表并核对分页前后总数、页长和唯一 ID → 按
|
||||
`shopName` 去除首尾空白后与启用店铺精确匹配 → 只为接受的货运单请求明细和入库。
|
||||
不能先过滤再做完整性校验,否则非目标店铺的分页漂移会被掩盖。
|
||||
|
||||
`[必须]` 同步开始时只读取一次启用店铺,整次运行使用同一个快照。列表允许但明细
|
||||
响应中的 `shopName` 变为空或非允许店铺时再次拦截。没有启用店铺时在会话/OCR/
|
||||
验证码等任何顺运宝请求之前停止,并且不推进覆盖游标。该过滤只影响后续入库,
|
||||
不清理历史货运单。
|
||||
|
||||
`[必须]` **会话缓存存 Admin 的 MySQL,不引入 Redis。** 示例脚本用 Redis 是因为
|
||||
它是反复启动的一次性脚本,进程间要传会话;Admin 是常驻进程,没有这个需求,
|
||||
持久化只为重启后免登录,继续复用现有数据库即可。
|
||||
|
||||
Reference in New Issue
Block a user