 chengmaandClaude Opus 5
|
6a7cde2ca6
|
feat: 顺运宝页与采集采购页搜索框收窄 (#34)
跟上 #23 给 PDD 页做的:搜索框收到 30%,「搜索」按钮紧挨输入框。
蝦皮数据页和客户端列表页按用户要求暂不动。
复用 #23 已有的 .search-narrow 类,没有为这两页新写 CSS 规则——
多写一条就多一处将来要同步的地方。全局规则
.toolbar input[type="text"] 一字未动,它被五个页面共用。
搜索按钮靠左没有加对齐样式,是收窄的自然结果:输入框不再伸展之后,
多余空间留在按钮之后。额外加 margin-right:auto 之类会和 grow 叠加出
难预料的结果。两个表单的 grow 都保留,它负责把删除按钮顶到最右侧。
/tasks 的 placeholder 从「任务编号 / 订单号 / PDD 商品 ID」缩成
「任务编号 / 订单号 / 商品 ID」——收到 30% 之后原文案装不下,
会被截断成看不出意思的半截。缩文案而不是调回宽度。
文档把这条规则从 §5.1 提到 §3.1 表格通用规则里,三个页面都指向它。
原来写在 PDD 页那一节,另外两页要用时看不到。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-07 17:13:42 +08:00 |
|
chengma
|
93beef8b36
|
feat: 保存并展示 PDD 店铺与价格采样信息 (#31)
|
2026-08-07 17:13:25 +08:00 |
|
 chengmaandClaude Opus 5
|
f0d7da37cf
|
feat: 采集采购页,采集与采购统一展示 (#19)
原来的采购任务页是骨架:var rows []gin.H 从不查库,页面永远为空;
TODO 写的还是只查 task_type = 'purchase'。所以 #18 建出来的采集任务
在界面上哪儿都看不到——用户点完「创建采集任务」只能盯着
collect_status 猜。
模块名定为「采集采购」(用户指定),直接点出这页装的是哪两类任务,
比泛称「任务」更能让人一眼知道点进去看什么。路由 /tasks 不变,
改路由会让已有书签和文档链接全失效,没有收益。
列不按类型并列——两种任务字段完全不同,并列会让采集任务行一半是空列。
改成固定列 + 一列「目标」把业务信息概括成一句话:
采集 PDD 737116531267
采购 SO-001 · M/黑色 · 2件 · ≤¥42.00
拼接逻辑在 service 层,模板只负责显示。
统计和列表共用同一个筛选条件拼装函数。分开写的话总有一天会忘了
给统计也加条件,数字和表格对不上,操作员会以为页面坏了。
无主任务的客户端列显示「—」。#17 之后采集任务默认无主,这列会大量为空。
详情弹窗只读,采购专有字段(数量、价格上限、目标规格)在采集任务里
整段不出现,不显示空行。复用 #18 的弹窗机制,app.js 无需改动。
顺带清掉 PDD 页加进来之后一直没跟上的模块计数:多处「四个模块/四个页面」
改成五个。其中 06-quality-security.md 那两处是验证清单,
照着做的人只会测四个页面,PDD 页永远不在回归范围里。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-07 15:16:05 +08:00 |
|
 chengmaandClaude Opus 5
|
96267f4a18
|
feat: PDD 商品页工具条文案与宽度调整 (#23)
三处:
- 「创建」改成「添加 PDD 商品」。同一条工具条上还有「创建采集任务」,
两个都以「创建」开头,第一次用的人分不清哪个是加商品、哪个是发起采集。
- 搜索框收到 30%。
- 「搜索」按钮紧挨输入框——这是收窄的自然结果:表单里没有会伸展的
元素之后,多余空间留在按钮之后,按钮就不会被顶到很右边。
用 .search-narrow 类而不是改 .toolbar input[type="text"]:
后者被五个页面共用(蝦皮/顺运宝/任务/客户端/PDD 各一个搜索框),
改了会把另外四页一起改掉。
用 flex 而不是 width:工具条是 flex 布局,width 会被 flex-grow 盖掉。
min-width: 160px 仍从通用规则继承,窄屏时不会缩到没法输入。
表单上的 grow 类保留,它负责把「删除」按钮顶到最右侧。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-07 14:15:35 +08:00 |
|
 chengmaandClaude Opus 5
|
eb8d357f5a
|
feat: PDD 商品页面 (#18)
打通 Client↔Admin 闭环的一环:录入 PDD 链接 → 创建采集任务 →
客户端领走去采 → 规格和价格显示在页面上。#16 写的 MarkCollecting 和
SoftDeletePddProduct 至此才有生产调用方。
链接解析严格、不做容错兜底:goods_id 上有 UNIQUE 约束,防重全靠它。
猜一个的话同一商品会存成好几行、采好几遍,规格映射还说不清指向哪一行。
短链一律拒绝,卡域名是为了拦"粘了淘宝链接"这种失误。
创建采集任务先占状态再建任务:MarkCollecting 只在 pending/failed 时成功,
同时充当"有没有人已经在采"的判断,与建任务在同一事务里,
所以并发点多次只会建出一个任务(实测 4 并发 → 1 条)。
submit.go 的 collectedData 增加 Dimensions —— 没有它就只能按 Go 的 map
遍历,而 map 无序,同一商品每次刷新"颜色/尺码"的先后都可能变。
顺带修 #16 一处缺陷:EnsurePddProduct 复活分支清空了 skus_json 却漏了
title,导致复活后状态显示"未采集"但标题还留着旧值。
审查打回一次:清理"PDD 链接唯一的录入口"这一过期说法(全库 5 处),
以及 shopee.go 里"空 → no_link"的过期 TODO —— no_link 已在 #16
从 CHECK 约束删除,照写会直接撞约束。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-07 11:27:06 +08:00 |
|
 chengmaandClaude Opus 5
|
6ae768463f
|
feat: 实现客户端注册与任务领取接口
Admin 的第一个业务功能。选它打头是因为它是穿透所有层的最薄一条竖切
(HTTP → handler/api → service → repository → SQLite → handler/web → 页面),
一个工单把分层模式立起来,后面四个模块照抄;同时它是与 Client 联调的接口,
能解锁另一条并行的工作线。
实现
- POST /tasks/claim:注册 + 领取。注册就在这里做,没有单独的注册接口,
也没有心跳(理由见 docs/admin/04-client-api.md §3)
- 领取用条件更新 + 检查影响行数防并发,SQLite 没有 SELECT FOR UPDATE
- 客户端列表页:查询、按名称搜索、批量删除
- 在线状态是**算出来的**(last_seen_at 在 10 分钟内),数据库里没有该字段
- CSRF 中间件:双提交 Cookie,手写 82 行不引依赖。
**只挂页面路由**,/api/v1/client/* 不能加——Client 不是浏览器、没有 Cookie
- 14 个单元测试
修复一个真 bug:PRAGMA 必须写进 DSN
并发领取测试报 database is locked (SQLITE_BUSY)。根因是
PRAGMA busy_timeout 每连接生效,而 database/sql 是连接池——
db.Exec("PRAGMA ...") 只作用于当时那条连接,池子新开的连接没执行过。
单线程正常、一并发就炸。改成 DSN 传参后并发测试跑 20 次全过。
这个坑已写进 docs/admin/03-data-model.md §2.1。
与工单的两处差异
- 去掉 name_is_custom 列后,"人工改的名字不被覆盖"改用更简单的做法:
ON CONFLICT DO UPDATE SET 里不含 name,即只在首次注册时写入。
效果相同,零额外字段、零迁移。已同步 04 §3
- 验收项"不向 dry_run 客户端分配真实下单任务"**未实现**:
tasks 表没有字段标记任务是否需要真实下单。当前真实下单开关默认关闭、
MVP 全是演练模式,暂不出问题,但开真实下单前必须补该字段,需另开工单
已验证(Go 1.23.0)
- go vet / gofmt / go test 全过,并发测试重复 20 次稳定通过
- 端到端:无任务 claim 204;插入任务后 claim 200 且 payload 含
goods_url/goods_id/options/quantity/max_price_cent、无租约无 Admin 状态;
重复 claim 204;缺 X-Client-Id 400;POST 无 CSRF token 403;
列表页两台客户端在线状态与统计正确
说明:Gitea 尚未配置,本次无对应工单号。
submit_result / submit_failure 及其幂等处理留给下一个工单。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-06 16:56:18 +08:00 |
|
 chengmaandClaude Opus 5
|
799ee33045
|
feat: 搭建 Admin 项目骨架(Go + Gin + html/template)
可运行的骨架:四个页面能打开、数据库自动建表、给 Client 的三个接口
按契约响应。业务逻辑留 35 处 TODO(骨架),每处标明要点和文档章节。
结构(对应 docs/admin/02-architecture.md §2/§3)
- handler/web + handler/api 分开:页面要 CSRF、出错渲染错误页;
接口要认证、出错返回 JSON。混在一起迟早写错
- service 不认识 *gin.Context,方便不起服务器直接单测
- 只有 repository 能写 SQL
- 模板用 {{define "目录/名字"}},一次全部 ParseFS 进来不冲突
- 模板和静态资源用 //go:embed 打进二进制
已实测(Go 1.23.0,本机验证)
- go build / go vet / gofmt 全部通过
- 单文件产物 34MB,无需 cgo
- 四个页面 + 静态资源均 200,/ 正确 302 到 /shopee
- 建表 7 张 + 索引 10 个,user_version=1,二次启动不重复建表
- claim 带 X-Client-Id 返回 204(无任务可领),
缺 X-Client-Id 返回 400 + 契约格式的 JSON 错误体
依赖版本被 Go 1.23.0 卡死,已钉住并写进文档
- gin v1.11.0 (v1.12.0 起要求 Go >= 1.25.0)
- modernc.org/sqlite v1.38.0(v1.40.0 起要求 >= 1.24.0,v1.48.0 起 >= 1.25.0)
- excelize v2.9.1 (尚未入 go.mod,写导入功能时再加)
直接 go get 不带版本会拉到最新版并报 requires go >= 1.25.0,
所以文档里的命令一律带版本号。要升依赖就得先升 Go。
一处主动调整:迁移语句从「一个字符串装多条 SQL」改成 [][]string 逐条执行。
database/sql 的 Exec 对一次多条语句的支持因驱动而异,拆开最稳妥,
报错还能精确到第几条。
说明:Gitea 尚未配置,本次无对应工单号。
admin/testdata/ 只有 README,脱敏小样本需人工制作。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-06 16:33:45 +08:00 |
|