店铺列表缓存到 SQLite 并在启动时后台刷新 #10

Open
opened 2026-09-02 17:46:34 +08:00 by ila · 0 comments
Owner

基本信息

  • 类型:需求 | 所属 Epic:#2 | 所属 MVP:#3 | 阶段:待实施

依赖与并行

  • 前置工单:#8(已实施完成并推送)
  • 允许并行:否;原因:本工单直接改 #8 的 ListShops 调用链。

原始需求

  • 来源:用户对话,2026-09-02
  • 关键原话:「店铺列表可以保存到sqlite吗,每次启动去更新,如果更新失败弹窗提示,
    使用sqlite里的店铺列表」

要解决什么

现在每次打开「商品列表」都要现调 erp/shop/all。这条链路要先完成货憨憨登录
(取 CID/CST → 验证码 → OCR → 登录 → 验证 token),任何一环失败下拉框就是空的,
连店铺名都看不到,使用者无法判断是网络问题还是账号问题。

改为:店铺列表缓存进 SQLite,启动时后台刷新,刷新失败时弹窗说明并回退到缓存。

做什么 / 不做什么

  • 做:新增 shops 表;缓存读写;启动后台刷新;失败弹窗;下拉框旁显示缓存时间;
    保留手动刷新。
  • 不做:不改登录逻辑;不缓存商品数据(商品已经在 products 表里);
    不做定时自动刷新。

已确认方案(四点必须按此实现,都是实际会遇到的坑)

1. 刷新是全量替换,不是合并

店铺在货憨憨被删除或停用后,缓存必须跟着消失。若只做 upsert,
已删除的店铺会永远留在下拉框里,选中后拉不到任何数据。
实现:在同一个事务里先 DELETE FROM shops 再批量插入。

2. 启动刷新走后台协程,且未配置账号时不刷新

  • 同步刷新会让窗口卡在登录上几秒才显示。
  • 同事第一次安装、尚未填账号就启动时,同步刷新必然失败,
    一开机就弹「登录失败」,体验很差。

实现:startup 里判断 cfg.Huohanhan.Account 和 Password 都非空才
起协程刷新;结果通过 Wails 事件推给前端。

3. 下拉框旁常驻显示「更新于 X」

弹窗关掉就没了,但「我现在用的是不是旧数据」应当一直可见。

4. 弹窗必须同时说明失败原因和缓存时间

只说「更新失败」使用者无法判断该不该继续用。
文案示例:「店铺列表更新失败:<原因>。当前使用 2026-09-02 17:30 缓存的
19 个店铺,可能已过期。」

预计修改文件

  • internal/store/store.go(在 migrations 末尾追加建表语句,不得修改已有条目)
  • internal/store/shop.go、shop_test.go(新建:缓存读写)
  • internal/huohanhan/shop.go(不改 ListShops 本身,只在需要时补导出)
  • app.go(新增 RefreshShops、GetCachedShops;startup 后台刷新;
    ListShops 改为先读缓存)
  • frontend/src/views/ProductListView.vue(缓存时间显示、刷新按钮、失败弹窗)

验收标准

  • shops 表通过在 migrations 末尾追加建立,已有迁移条目未被改动
  • 刷新成功后缓存与线上一致;线上删掉某店铺后再刷新,该店铺从缓存消失
  • 断网或登录失败时,下拉框仍显示缓存店铺,并弹窗说明原因与缓存时间
  • 未配置账号时启动不触发刷新、不弹任何错误
  • 窗口打开不被刷新阻塞
  • 下拉框旁显示缓存更新时间
  • 缓存中不含 accessToken、refreshToken、createUser(沿用 #8 的 Shop 结构体)

验证方式

go vet ./...
go test ./...
cd frontend; npx vite build

真实断网与真实店铺变更由负责人在界面验证。

交给 Codex 实施的约定

本工单由本机 Codex CLI(模型 gpt-5.6-sol)实施,由 Claude 审核。

Codex 必须遵守:

  • 先读仓库根目录 AGENTS.md,第 10 节「项目专用规则」是不可违反的红线。
  • 只改本工单「预计修改文件」列出的范围;发现别的问题记录下来,不要顺手改。
  • Wails 专有 API 只能出现在 main.go 和 app.go;internal/ 不许 import wails。
  • 不把账号、密码、token、Cookie 写入代码、日志、注释或测试固定值。
  • 面向初级维护者写代码:直白实现,注释解释「为什么」和边界,不逐行翻译代码。
  • 新增逻辑要有 go test 覆盖;不能联网的部分用假数据测,不要写需要真实账号才能跑的测试。
  • 完成后必须真实执行并贴出输出:go vet ./...、go build ./...、go test ./...。
  • 不要自行提交 Git,也不要改 docs/ 下的任何文件(那是 Wiki 镜像)。
## 基本信息 - 类型:需求 | 所属 Epic:#2 | 所属 MVP:#3 | 阶段:待实施 ## 依赖与并行 - 前置工单:#8(已实施完成并推送) - 允许并行:否;原因:本工单直接改 #8 的 ListShops 调用链。 ## 原始需求 - 来源:用户对话,2026-09-02 - 关键原话:「店铺列表可以保存到sqlite吗,每次启动去更新,如果更新失败弹窗提示, 使用sqlite里的店铺列表」 ## 要解决什么 现在每次打开「商品列表」都要现调 `erp/shop/all`。这条链路要先完成货憨憨登录 (取 CID/CST → 验证码 → OCR → 登录 → 验证 token),任何一环失败下拉框就是空的, 连店铺名都看不到,使用者无法判断是网络问题还是账号问题。 改为:店铺列表缓存进 SQLite,启动时后台刷新,刷新失败时弹窗说明并回退到缓存。 ## 做什么 / 不做什么 - 做:新增 `shops` 表;缓存读写;启动后台刷新;失败弹窗;下拉框旁显示缓存时间; 保留手动刷新。 - 不做:不改登录逻辑;不缓存商品数据(商品已经在 products 表里); 不做定时自动刷新。 ## 已确认方案(四点必须按此实现,都是实际会遇到的坑) ### 1. 刷新是全量替换,不是合并 店铺在货憨憨被删除或停用后,缓存必须跟着消失。若只做 upsert, 已删除的店铺会永远留在下拉框里,选中后拉不到任何数据。 实现:在同一个事务里先 `DELETE FROM shops` 再批量插入。 ### 2. 启动刷新走后台协程,且未配置账号时不刷新 - 同步刷新会让窗口卡在登录上几秒才显示。 - 同事第一次安装、尚未填账号就启动时,同步刷新必然失败, 一开机就弹「登录失败」,体验很差。 实现:`startup` 里判断 `cfg.Huohanhan.Account` 和 `Password` 都非空才 起协程刷新;结果通过 Wails 事件推给前端。 ### 3. 下拉框旁常驻显示「更新于 X」 弹窗关掉就没了,但「我现在用的是不是旧数据」应当一直可见。 ### 4. 弹窗必须同时说明失败原因和缓存时间 只说「更新失败」使用者无法判断该不该继续用。 文案示例:「店铺列表更新失败:<原因>。当前使用 2026-09-02 17:30 缓存的 19 个店铺,可能已过期。」 ## 预计修改文件 - `internal/store/store.go`(在 migrations 末尾追加建表语句,**不得修改已有条目**) - `internal/store/shop.go`、`shop_test.go`(新建:缓存读写) - `internal/huohanhan/shop.go`(不改 ListShops 本身,只在需要时补导出) - `app.go`(新增 `RefreshShops`、`GetCachedShops`;startup 后台刷新; `ListShops` 改为先读缓存) - `frontend/src/views/ProductListView.vue`(缓存时间显示、刷新按钮、失败弹窗) ## 验收标准 - [ ] `shops` 表通过在 migrations 末尾追加建立,已有迁移条目未被改动 - [ ] 刷新成功后缓存与线上一致;线上删掉某店铺后再刷新,该店铺从缓存消失 - [ ] 断网或登录失败时,下拉框仍显示缓存店铺,并弹窗说明原因与缓存时间 - [ ] 未配置账号时启动不触发刷新、不弹任何错误 - [ ] 窗口打开不被刷新阻塞 - [ ] 下拉框旁显示缓存更新时间 - [ ] 缓存中不含 accessToken、refreshToken、createUser(沿用 #8 的 Shop 结构体) ## 验证方式 ```powershell go vet ./... go test ./... cd frontend; npx vite build ``` 真实断网与真实店铺变更由负责人在界面验证。 ## 交给 Codex 实施的约定 本工单由本机 Codex CLI(模型 `gpt-5.6-sol`)实施,由 Claude 审核。 Codex 必须遵守: - 先读仓库根目录 `AGENTS.md`,第 10 节「项目专用规则」是不可违反的红线。 - 只改本工单「预计修改文件」列出的范围;发现别的问题记录下来,不要顺手改。 - Wails 专有 API 只能出现在 `main.go` 和 `app.go`;`internal/` 不许 import wails。 - 不把账号、密码、token、Cookie 写入代码、日志、注释或测试固定值。 - 面向初级维护者写代码:直白实现,注释解释「为什么」和边界,不逐行翻译代码。 - 新增逻辑要有 `go test` 覆盖;不能联网的部分用假数据测,不要写需要真实账号才能跑的测试。 - 完成后必须真实执行并贴出输出:`go vet ./...`、`go build ./...`、`go test ./...`。 - 不要自行提交 Git,也不要改 `docs/` 下的任何文件(那是 Wiki 镜像)。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chengma/cmsp#10