Admin:蝦皮数据页分页与状态筛选 #43

Closed
opened 2026-08-08 11:23:41 +08:00 by ila · 1 comment
Owner

基本信息

  • 类型:需求(界面)
  • 父级大工单:#14
  • 所属 MVP / 版本:#15 / MVP
  • 关联:#38(导入)、#41(商品级列表)
  • [注意] 全项目第一个做分页的页面,本工单定下的模式后面四个页面要照抄

要解决什么

① 一次吐 3.4MB

实测导入真实样本后打开 /shopee:

HTML 大小    3.4 MB
表格行数     5195

② 但只加分页会制造一个新问题

商品总数        5195
未填 PDD 链接   5195  (100%)
有待补规格      6

要找出那 6 个待补的商品,得翻 260 页。

现在页面上只有「商品 ID 搜索」——得先知道 ID 才能搜。但「哪些商品需要我处理」
这个问题,恰恰是不知道 ID 的时候才要问的。

只做分页,情况会从「5195 行糊在一起」变成「260 页里藏着 6 个」,两种都找不到。

PDD 商品页(05 §5.1)已经踩过这个坑,那里写着:

[必须] 这个筛选是刚需,不是锦上添花:这个页面的主要用途是维护
(找出失败的重采、找出还没采的),只按 ID 搜的话要翻页去找。

蝦皮页是同样的性质。

做什么 / 不做什么

做:

  1. 分页,每页 20 条
  2. 状态筛选:全部 / 待补规格 / 未填 PDD 链接 / 已填链接
  3. 底部状态条显示全量统计和页码
  4. 更新 docs/admin/05 §3 的每页条数(现在写的是 50)

不做(各自独立工单):

  • 不给另外四个页面加分页(本工单只定模式)
  • 不做排序切换
  • 不实现 ShopeeSave / ShopeeDelete / ShopeeCollect(保持 501)
  • 不改导入逻辑、不改表结构

怎么做

每页 20 条,规范要一起改

[必须] 每页 20 条。docs/admin/05 §3 现在写的是 [建议] 一页 50 条,
要改成 20 并写清理由:20 行在 1366×768 上正好一屏不用滚动。

不改规范的话,下一个人做顺运宝页会照着 50 做,五个页面又不一致。

分页必须在数据库做,不在内存里切

[必须] LIMIT ? OFFSET ?,不得把 5195 行查出来再在 Go 里切片。
这正是现在 3.4MB 的成因。

[必须] 总数用单独的 COUNT(*) 查询,和列表查询共用同一套筛选条件
(抽成共用函数)。分开写两份 WHERE,迟早有一天会忘了给 COUNT 也加条件,
页码算错而且没人发现。这条 #19 已经踩过一次。

状态条必须显示全量,不是本页

[必须]

✗  共 20 个商品                        ← 只数了本页,操作员以为总共就 20 个
✓  共 5195 个商品 · 第 1/260 页

[必须] 筛选后显示筛选结果的总数:

待补规格:6 个商品 · 第 1/1 页

不是本页的 6。这与 #19 的「统计跟随筛选」是同一条规则。

状态筛选的四个取值

取值 含义 SQL 条件
全部 不筛 —
待补规格 有 parse_ok = 0 的 SKU EXISTS (SELECT 1 FROM shopee_skus s WHERE s.goods_id = p.goods_id AND s.parse_ok = 0)
未填 PDD 链接 还没关联拼多多商品 pdd_goods_url IS NULL OR pdd_goods_url = ''
已填链接 已关联 pdd_goods_url IS NOT NULL AND pdd_goods_url <> ''

[必须] 「待补规格」用 EXISTS,不要用 JOIN + DISTINCT——
一个商品有多个失败 SKU 时 JOIN 会出重复行,DISTINCT 又会让
LIMIT/OFFSET 的行为变得难推理。

[必须] 筛选参数认不出来的一律当「全部」,不要报错。
用户手改 URL 或者旧书签不该把页面搞崩。

页码参数

[必须] ?page=N,从 1 开始(不是 0)。给操作员看的东西不要 0-based。

[必须] 越界要兜住:

  • page < 1 或非数字 → 当作 1
  • page > 总页数 → 显示最后一页,不要显示空表格
  • 总数为 0 → 页码显示 第 1/1 页,不要出现 第 1/0 页

[必须] 翻页时保留当前筛选和关键词。丢了的话操作员翻到第二页
筛选就没了,还以为数据变了。

分页控件

共 5195 个商品 · 第 3/260 页    [首页] [上一页] [下一页] [末页]

[必须] 用 <a href> 链接,不要用 JS。这是纯 GET 导航,
浏览器的前进后退和书签都该正常工作。

[必须] 第一页时「首页 / 上一页」禁用,最后一页时「下一页 / 末页」禁用。
禁用要用视觉 + 语义(不可点的元素不要还是 <a>),不能只靠颜色。

[建议] 不要做 1 2 3 ... 260 这种页码列表。260 页列出来没有意义,
操作员靠筛选定位而不是靠翻页。

预计修改文件

文件 改什么
admin/repository/shopee.go 筛选条件拼装抽共用函数;ListShopeeProducts 加 LIMIT/OFFSET;CountShopeeProductsFiltered
admin/service/shopee_list.go 分页计算、状态筛选解析、状态条文案
admin/handler/web/shopee.go 读 page / status 参数
admin/templates/shopee/list.html 状态筛选下拉、分页控件
admin/static/css/app.css 分页控件样式(少量)
docs/admin/05-ui-specification.md §3 每页条数改 20;§4.1 工具条加筛选;新增分页通用规则一节
docs/admin/01-requirements.md §4 蝦皮模块的筛选说明

[必须] 分页规则写成 §3 下的通用小节(像 §3.1 搜索框宽度那样),
不要写在蝦皮页那一节里——后面四个页面都要照抄,写在某一页下面别人看不到。
这个错误 #34 刚犯过一次。

验收标准

分页

  • 每页 20 条,第 1 页正好 20 行
  • LIMIT/OFFSET 在 SQL 里,不是查全量再切片
  • HTML 大小从 3.4MB 降到合理水平(预期 < 100KB)
  • page=0 / page=abc / 负数 → 当作第 1 页,不报错
  • page=9999 → 显示最后一页,不是空表格
  • 翻页保留筛选和关键词
  • 分页控件是 <a href>,浏览器后退可用
  • 首页/末页时对应按钮禁用,不只靠颜色区分

筛选

  • 「待补规格」筛出 6 个商品(导入样本后)
  • 「未填 PDD 链接」筛出 5195 个(导入样本后,因为还没填过)
  • 「已填链接」筛出 0 个;手工填一个后变 1 个
  • 筛选参数认不出来时当「全部」,不报错
  • 筛选与关键词可叠加

状态条

  • 显示全量总数,不是本页数
  • 筛选后显示筛选结果总数(「待补规格:6 个商品」)
  • 总数为 0 时显示 第 1/1 页,不出现 第 1/0 页

其他

  • 列表查询和 COUNT 共用同一套筛选条件拼装
  • ShopeeSave / ShopeeDelete / ShopeeCollect 仍是 501
  • shopee_import.go 未改动
  • 分页规则写在 05 §3 的通用小节,不是蝦皮页那一节
  • 05 §3 的每页条数已从 50 改为 20 并写清理由
  • 五个页面均 200
  • GOTOOLCHAIN=go1.23.0 下 go vet / gofmt -l . / go test ./... 全过

怎么验证

cd D:\chengma\cmautobuy\admin
$env:GOTOOLCHAIN="go1.23.0"
go vet ./...; gofmt -l .; go test ./... -count=1
Remove-Item Env:GOTOOLCHAIN
go run .

导入真实样本后:

  1. /shopee → 20 行,状态条 共 5195 个商品 · 第 1/260 页
  2. /shopee?page=9999 → 最后一页,有数据
  3. /shopee?page=abc → 第 1 页
  4. /shopee?status=pending_spec → 6 个商品,状态条显示 6 不是 20
  5. /shopee?status=no_link → 5195 个
  6. 手工 UPDATE shopee_products SET pdd_goods_url='https://x/1' WHERE goods_id='<任选>'
    → status=has_link 筛出 1 个
  7. 带筛选翻到第 2 页,确认筛选还在

[必须] 第 1、2、4 步的实际输出要贴出来,以及 HTML 大小的前后对比。

风险和回退

风险 应对
COUNT 和列表的 WHERE 写成两份,页码算错 强制共用拼装函数,已列为验收项(#19 踩过)
状态条显示本页数而非全量 已列为验收项并给了正误对照
page 越界显示空表格,操作员以为数据没了 越界兜到最后一页,已列为验收项
分页规则写在蝦皮页那一节,另外四页看不到 强制写进 §3 通用小节(#34 踩过)

回退:git revert。纯展示层改动,不影响已导入的数据。

## 基本信息 - 类型:需求(界面) - 父级大工单:#14 - 所属 MVP / 版本:#15 / MVP - 关联:#38(导入)、#41(商品级列表) - `[注意]` **全项目第一个做分页的页面**,本工单定下的模式后面四个页面要照抄 ## 要解决什么 ### ① 一次吐 3.4MB 实测导入真实样本后打开 `/shopee`: ``` HTML 大小 3.4 MB 表格行数 5195 ``` ### ② 但只加分页会制造一个新问题 ``` 商品总数 5195 未填 PDD 链接 5195 (100%) 有待补规格 6 ``` **要找出那 6 个待补的商品,得翻 260 页。** 现在页面上只有「商品 ID 搜索」——得先知道 ID 才能搜。但「哪些商品需要我处理」 这个问题,恰恰是**不知道 ID 的时候才要问的**。 只做分页,情况会从「5195 行糊在一起」变成「260 页里藏着 6 个」,两种都找不到。 PDD 商品页(`05` §5.1)已经踩过这个坑,那里写着: > `[必须]` 这个筛选是**刚需**,不是锦上添花:这个页面的主要用途是维护 > (找出失败的重采、找出还没采的),只按 ID 搜的话要翻页去找。 蝦皮页是同样的性质。 ## 做什么 / 不做什么 做: 1. 分页,**每页 20 条** 2. 状态筛选:全部 / 待补规格 / 未填 PDD 链接 / 已填链接 3. 底部状态条显示**全量**统计和页码 4. 更新 `docs/admin/05` §3 的每页条数(现在写的是 50) 不做(各自独立工单): - **不给另外四个页面加分页**(本工单只定模式) - 不做排序切换 - 不实现 `ShopeeSave` / `ShopeeDelete` / `ShopeeCollect`(保持 501) - 不改导入逻辑、不改表结构 ## 怎么做 ### 每页 20 条,规范要一起改 `[必须]` 每页 **20** 条。`docs/admin/05` §3 现在写的是 `[建议]` 一页 50 条, **要改成 20 并写清理由**:20 行在 1366×768 上正好一屏不用滚动。 不改规范的话,下一个人做顺运宝页会照着 50 做,五个页面又不一致。 ### 分页必须在数据库做,不在内存里切 `[必须]` `LIMIT ? OFFSET ?`,**不得**把 5195 行查出来再在 Go 里切片。 这正是现在 3.4MB 的成因。 `[必须]` 总数用**单独的 `COUNT(*)` 查询**,和列表查询**共用同一套筛选条件** (抽成共用函数)。分开写两份 WHERE,迟早有一天会忘了给 COUNT 也加条件, 页码算错而且没人发现。这条 #19 已经踩过一次。 ### 状态条必须显示全量,不是本页 `[必须]` ```text ✗ 共 20 个商品 ← 只数了本页,操作员以为总共就 20 个 ✓ 共 5195 个商品 · 第 1/260 页 ``` `[必须]` 筛选后显示**筛选结果的总数**: ```text 待补规格:6 个商品 · 第 1/1 页 ``` 不是本页的 6。这与 #19 的「统计跟随筛选」是同一条规则。 ### 状态筛选的四个取值 | 取值 | 含义 | SQL 条件 | |---|---|---| | 全部 | 不筛 | — | | **待补规格** | 有 `parse_ok = 0` 的 SKU | `EXISTS (SELECT 1 FROM shopee_skus s WHERE s.goods_id = p.goods_id AND s.parse_ok = 0)` | | **未填 PDD 链接** | 还没关联拼多多商品 | `pdd_goods_url IS NULL OR pdd_goods_url = ''` | | 已填链接 | 已关联 | `pdd_goods_url IS NOT NULL AND pdd_goods_url <> ''` | `[必须]` 「待补规格」用 `EXISTS`,**不要用 `JOIN` + `DISTINCT`**—— 一个商品有多个失败 SKU 时 JOIN 会出重复行,`DISTINCT` 又会让 `LIMIT/OFFSET` 的行为变得难推理。 `[必须]` 筛选参数认不出来的一律当「全部」,**不要报错**。 用户手改 URL 或者旧书签不该把页面搞崩。 ### 页码参数 `[必须]` `?page=N`,从 **1** 开始(不是 0)。给操作员看的东西不要 0-based。 `[必须]` 越界要兜住: - `page < 1` 或非数字 → 当作 1 - `page > 总页数` → 显示最后一页,**不要显示空表格** - 总数为 0 → 页码显示 `第 1/1 页`,不要出现 `第 1/0 页` `[必须]` 翻页时**保留当前筛选和关键词**。丢了的话操作员翻到第二页 筛选就没了,还以为数据变了。 ### 分页控件 ```text 共 5195 个商品 · 第 3/260 页 [首页] [上一页] [下一页] [末页] ``` `[必须]` 用 `<a href>` 链接,**不要用 JS**。这是纯 GET 导航, 浏览器的前进后退和书签都该正常工作。 `[必须]` 第一页时「首页 / 上一页」禁用,最后一页时「下一页 / 末页」禁用。 禁用要用**视觉 + 语义**(不可点的元素不要还是 `<a>`),不能只靠颜色。 `[建议]` 不要做 `1 2 3 ... 260` 这种页码列表。260 页列出来没有意义, 操作员靠筛选定位而不是靠翻页。 ## 预计修改文件 | 文件 | 改什么 | |---|---| | `admin/repository/shopee.go` | 筛选条件拼装抽共用函数;`ListShopeeProducts` 加 `LIMIT/OFFSET`;`CountShopeeProductsFiltered` | | `admin/service/shopee_list.go` | 分页计算、状态筛选解析、状态条文案 | | `admin/handler/web/shopee.go` | 读 `page` / `status` 参数 | | `admin/templates/shopee/list.html` | 状态筛选下拉、分页控件 | | `admin/static/css/app.css` | 分页控件样式(少量) | | `docs/admin/05-ui-specification.md` | §3 每页条数改 20;§4.1 工具条加筛选;新增分页通用规则一节 | | `docs/admin/01-requirements.md` | §4 蝦皮模块的筛选说明 | `[必须]` 分页规则写成 **§3 下的通用小节**(像 §3.1 搜索框宽度那样), 不要写在蝦皮页那一节里——后面四个页面都要照抄,写在某一页下面别人看不到。 这个错误 #34 刚犯过一次。 ## 验收标准 **分页** - [ ] 每页 20 条,第 1 页正好 20 行 - [ ] `LIMIT/OFFSET` 在 SQL 里,**不是**查全量再切片 - [ ] HTML 大小从 3.4MB 降到合理水平(预期 < 100KB) - [ ] `page=0` / `page=abc` / 负数 → 当作第 1 页,不报错 - [ ] `page=9999` → 显示最后一页,**不是空表格** - [ ] 翻页保留筛选和关键词 - [ ] 分页控件是 `<a href>`,浏览器后退可用 - [ ] 首页/末页时对应按钮禁用,不只靠颜色区分 **筛选** - [ ] 「待补规格」筛出 **6 个商品**(导入样本后) - [ ] 「未填 PDD 链接」筛出 **5195 个**(导入样本后,因为还没填过) - [ ] 「已填链接」筛出 0 个;手工填一个后变 1 个 - [ ] 筛选参数认不出来时当「全部」,不报错 - [ ] 筛选与关键词可叠加 **状态条** - [ ] 显示**全量**总数,不是本页数 - [ ] 筛选后显示筛选结果总数(「待补规格:6 个商品」) - [ ] 总数为 0 时显示 `第 1/1 页`,不出现 `第 1/0 页` **其他** - [ ] 列表查询和 COUNT **共用同一套筛选条件拼装** - [ ] `ShopeeSave` / `ShopeeDelete` / `ShopeeCollect` 仍是 501 - [ ] `shopee_import.go` 未改动 - [ ] 分页规则写在 `05` §3 的通用小节,不是蝦皮页那一节 - [ ] `05` §3 的每页条数已从 50 改为 20 并写清理由 - [ ] 五个页面均 200 - [ ] `GOTOOLCHAIN=go1.23.0` 下 `go vet` / `gofmt -l .` / `go test ./...` 全过 ## 怎么验证 ```powershell cd D:\chengma\cmautobuy\admin $env:GOTOOLCHAIN="go1.23.0" go vet ./...; gofmt -l .; go test ./... -count=1 Remove-Item Env:GOTOOLCHAIN go run . ``` 导入真实样本后: 1. `/shopee` → 20 行,状态条 `共 5195 个商品 · 第 1/260 页` 2. `/shopee?page=9999` → 最后一页,**有数据** 3. `/shopee?page=abc` → 第 1 页 4. `/shopee?status=pending_spec` → **6 个商品**,状态条显示 6 不是 20 5. `/shopee?status=no_link` → 5195 个 6. 手工 `UPDATE shopee_products SET pdd_goods_url='https://x/1' WHERE goods_id='<任选>'` → `status=has_link` 筛出 1 个 7. 带筛选翻到第 2 页,确认筛选还在 `[必须]` 第 1、2、4 步的实际输出要贴出来,以及 HTML 大小的前后对比。 ## 风险和回退 | 风险 | 应对 | |---|---| | COUNT 和列表的 WHERE 写成两份,页码算错 | 强制共用拼装函数,已列为验收项(#19 踩过) | | 状态条显示本页数而非全量 | 已列为验收项并给了正误对照 | | `page` 越界显示空表格,操作员以为数据没了 | 越界兜到最后一页,已列为验收项 | | 分页规则写在蝦皮页那一节,另外四页看不到 | 强制写进 §3 通用小节(#34 踩过) | 回退:`git revert`。纯展示层改动,不影响已导入的数据。
Author
Owner

验收通过,关闭

用户实机确认通过。归档状态已更新(6d40c1e)。

  • 实现提交: edfe39c
  • 归档: docs/task/43-admin-蝦皮数据页分页与状态筛选.md

遗留

另外四个页面(PDD / 顺运宝 / 采集采购 / 客户端)尚未接入分页。通用逻辑已放 service/pagination.go,规则已写进 05 §3.2,后续各自开工单接入即可。

## 验收通过,关闭 用户实机确认通过。归档状态已更新(`6d40c1e`)。 - **实现提交:** `edfe39c` - **归档:** `docs/task/43-admin-蝦皮数据页分页与状态筛选.md` ### 遗留 另外四个页面(PDD / 顺运宝 / 采集采购 / 客户端)**尚未接入分页**。通用逻辑已放 `service/pagination.go`,规则已写进 `05` §3.2,后续各自开工单接入即可。
ila closed this issue 2026-08-09 10:06:49 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chengma/cmautobuy#43