Commit Graph

101 Commits

Author SHA1 Message Date
wangjia 8d3f902f3b feat(client): Phase 2 库存屏照原型重建(去tab/KPI货值/库存·成本价·单价列)
照原型 inventory.html 把库存屏从「3 tab」重排为单视图:
- 去 3 tab(库存查询/预警/流水)→ 单视图;预警并入 KPI 缺货卡点击筛选;流水移商品详情
- 头部:库存管理 + 共 N 个 SKU·数据实时 + 列设置/导出(盘点/新增入库去掉,走专门菜单)
- KPI 4 卡走全店汇总接口:SKU总数/库存货值(Σqty×进价)/在库数量/缺货预警(可点筛选)
- 表格 12 列:加 库存(低库存染色)/成本价(进价)/单价(售价);操作列只「查看详情」;状态圆点
- 仓库/备注默认隐藏;工具栏 搜索+状态筛选+重置
- 后端 GET /inventory/summary 全店汇总(守 shop_id);前端 model/repository/provider 配套
- golden_harness:monospace 指向 Noto(消等宽数字黑块,全 golden 受益);库存屏存量 grey 清零

后端编译/库存测试通过;前端 analyze 0 error,flutter test 242 通过;代码端颜色闸 0 违规。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TSKEiHsvauyxYUW2itzUXX
2026-07-01 20:46:53 +08:00
wangjia ff45100eed feat(backend): 库存接口带出售价 sale_price(库存屏成本价/单价两列地基)
照原型库存表「成本价(进价)+单价(售价)」两列:
- 库存查询 SELECT 加 p.sale_price AS sale_price;成本价 unit_price 补 p.purchase_price 兜底
- inventoryRow 加 SalePrice;前端 Inventory model 加 salePrice
- 多租户隔离不变(baseWhere 仍 inv.shop_id);库存测试通过

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TSKEiHsvauyxYUW2itzUXX
2026-07-01 20:46:53 +08:00
wangjia 16a56c611d feat(backend): 商品价格历史接口(从入库单价派生)
GET /products/:id/price-history:从已审核入库单明细 unit_price 按 order_date
倒序派生进价变更点,去相邻重复价,守多租户 shop_id(零额外表)。
新增测试 PriceHistory(含草稿排除 + 倒序断言)。go build/vet/test 全过。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TSKEiHsvauyxYUW2itzUXX
2026-07-01 20:46:52 +08:00
wangjia a51a44056d feat(backend): 库存按商品过滤 + 香型(分类)字典 CRUD
商品域富数据/重组所需后端:
- GET /inventory 加 product_id 过滤 → 解锁商品详情「当前库存/货值/各仓库分布」
  (配合已支持 product_id 的 /inventory/logs,详情可拼出大半富数据)
- 新增 /product-options/categories 香型字典 CRUD(ProductCategory 模型已存在,
  补管理接口)→ 商品列表 5-tab 重组的最后一块字典
均守多租户 shop_id;新增 3 个测试(FilterByProduct/CategoryCRUD/CategoryIsolation)。
go build/vet/test 全过。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TSKEiHsvauyxYUW2itzUXX
2026-07-01 20:46:52 +08:00
wangjia 5ff41cc505 chore: release server-v1.0.81
Deploy Server / release-deploy-server (push) Successful in 1m54s
修复入库单/出库单按商品名搜不到历史导入单:搜索酒名条件由 COALESCE(被占位名劫持) 改为 p.name OR it.product_name 任一命中,并加回归测试。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-24 11:56:21 +08:00
wangjia 84f99ef459 test: 补酒名搜索拼音/多租户与前端搜索限流用例
- backend: 入库酒名全拼(feitian)+首字母(ftmt)命中、不相关拼音不命中
- backend: 入库酒名反查的多租户隔离(店A搜茅台不串到店B)
- client: setKeyword 防抖(350ms内连发取最后一次)+去重(同词不重查)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 00:19:34 +08:00
wangjia e8f416ddea feat(backend): 入库/出库列表 keyword 支持酒名模糊反查
- keyword 在单号/往来单位基础上,新增按酒名反查含该酒明细的单据
- 酒名匹配复用拼音基建:name(优先 product 回退快照) + name_pinyin + name_initials
- 子查询带 shop_id,多租户隔离不破
- 补 stock_in/stock_out List 按酒名+拼音命中的测试用例

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 00:19:34 +08:00
wangjia 3625240839 feat(backend): 入库「确认进价」前向补偿(暂估价→真实价)
调货 0 价入库并已审核/出库后,价格确定时补填真实进价:一事务内
回填入库明细/库存批次/已出库成本快照,重算入库单总额,按差额补
应付流水,同步参考进价。按 product_id 精确命中(序列号 1:1),
不动售价/应收。仅 approved 单、管理员/超管,差额幂等可重复确认。

新增 POST /stock-in/orders/:id/confirm-cost 及 4 个测试用例。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 20:07:49 +08:00
wangjia 6570dfc240 chore: release server-v1.0.77
Deploy Server / release-deploy-server (push) Successful in 1m32s
出库列表按商品编码精确反查 + stock_out_items(shop_id,product_code) 索引

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-22 22:24:43 +08:00
wangjia 08f9e20010 chore: release server-v1.0.76
Deploy Server / release-deploy-server (push) Successful in 1m30s
修复编辑入库单草稿后合计金额被清零(Update 漏累加 total)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-22 20:15:38 +08:00
wangjia 3641f1cf16 chore: release server-v1.0.75
Deploy Server / release-deploy-server (push) Successful in 1m7s
出库售价(应收按售价) + 库存选择器分页上限修复 + seed 改为序列号模型

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-22 13:01:25 +08:00
wangjia 20f9e3a410 chore: release server-v1.0.74
Deploy Server / release-deploy-server (push) Successful in 2m4s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-21 22:17:24 +08:00
wangjia 6faadf8670 fix(backend): 库存导入按商品编号匹配不再按名称合并 + 新增 fix-inventory-products 修复工具
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-21 21:24:53 +08:00
wangjia 13a6777a85 chore: release server-v1.0.73
Deploy Server / release-deploy-server (push) Successful in 56s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-21 19:46:30 +08:00
wangjia 7a78448a25 chore: release server-v1.0.72
Deploy Server / release-deploy-server (push) Successful in 56s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-21 19:09:30 +08:00
wangjia 203cc7ce21 chore: release server-v1.0.71
Deploy Server / release-deploy-server (push) Successful in 56s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-21 18:14:27 +08:00
wangjia 7b67466a3e chore: release server-v1.0.70
Deploy Server / release-deploy-server (push) Successful in 56s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-21 17:32:55 +08:00
wangjia c1febfffec feat(backend): 入库每行新建独立产品发独立序列号(product 加生产日期/批次列)
Deploy Server / release-deploy-server (push) Successful in 59s
入库 Create/Update 改为对每条明细新建独立 product(createIndependentProduct,
nextProductCode 自增 + uk_shop_code 唯一约束兜底),回填 product_id;不再按名称复用。
product 表加 production_date/batch_no。向后兼容:保留明细/库存快照列。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-21 16:30:11 +08:00
wangjia 1a1d9aa15e fix(backend): 商品编码改用最大序号生成不复用软删号 + 加 (shop_id,code) 唯一约束,根治重复编码
Deploy Server / release-deploy-server (push) Successful in 53s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-21 10:51:34 +08:00
wangjia fb1e637ce4 fix(backend): 入库审核库存沿用明细真实快照名 + 库存列表过滤软删商品,修复历史导入占位顶替;入库/出库列表支持 keyword 搜索
Deploy Server / release-deploy-server (push) Successful in 53s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-20 16:02:02 +08:00
wangjia 7f3261a4a9 chore: release server-v1.0.66
Deploy Server / release-deploy-server (push) Successful in 51s
fix(backend): 入库/出库列表按 order_date 倒序,历史导入单按业务日期归位

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 12:50:26 +08:00
wangjia 50b5c9fccb chore: release server-v1.0.65
Deploy Server / release-deploy-server (push) Successful in 1m5s
fix(backend): 入库/出库列表 status 支持多状态 IN 查询

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 12:19:46 +08:00
wangjia 15ef71734d chore: release server-v1.0.64
Deploy Server / release-deploy-server (push) Successful in 55s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 10:13:49 +08:00
wangjia 90d2c8668b feat(backend): 历史进销存导入器 cmd/import-history + 单据明细快照列
一次性 CLI 导入旧系统 data/ 入库·出库 总表/详情表到当前库,历史只读(绝不
回放 inventories/inventory_logs)。明细忠实直存不做 SKU 归一:order/item 表
新增 creator_id(制单人)与 product_code/product_name/series/spec 快照列
(出库另补 batch_no/production_date),导入行 product_id 指向共享占位商品。
order_no 天然主键 (shop_id,order_no) 幂等去重,可重复跑。

testutil sqlite DDL 同步补列以保持 service 测试通过。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 07:05:08 +08:00
wangjia 7bbc944ae2 chore: release server-v1.0.62
Deploy Server / release-deploy-server (push) Successful in 51s
服务端安全加固:多维限流(按 IP/按门店)+ 敏感接口独立速率上限抵御 DDoS/刷接口;
登录暴力破解新增按来源 IP 锁定;反代后正确识别真实客户端 IP;
门店 custom_fields 轻量配置(录入默认值)透传保存。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2Wdwo7SmgBJU37cBrkhPK
2026-06-19 20:20:44 +08:00
wangjia 9b6dba4c2b test(backend): 补 redeem_code 单测 + gitignore todo/ 与 gencode 产物
覆盖 NormalizeCode 边界/幂等、GenerateRedeemCode 格式/无歧义字母表
(剔除 0/O/1/I/L)/无碰撞。.gitignore 忽略全局 todo skill 本地数据
与 backend/gencode 构建产物。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2Wdwo7SmgBJU37cBrkhPK
2026-06-19 14:04:22 +08:00
wangjia 23dff69c62 feat(backend): 授权改为时长兑换券体系 + 退役 ed25519/HMAC + 平台生码工具
- 新增 license_codes 码池表 + model.LicenseCode;licenses 加 tier 档位列
- LicenseService.Redeem:单事务 FOR UPDATE 校验码未用 → 时长叠加(可叠加,0=永久)
  → 写 type/tier/max_devices → 绑设备(超限整笔回滚) → 标记已用 → 即时失效 phase 缓存
  路由仍 POST /license/activate,客户端零破坏
- util.GenerateRedeemCode/NormalizeCode:JIUKU-XXXX-XXXX 短码(crypto/rand)
- cmd/gencode:平台批量生成兑换码并落库;删除 cmd/issue、cmd/genkey
- 退役 ed25519 + HMAC:删 util/license_key、GenerateKey、License 全部 config 字段
  及生产启动私钥校验;trial 改直接建行(无需私钥、去 Fatal)
- tier 档位钩子默认 standard,分档消费模式后续设计
- 测试:Redeem 全场景(叠加/过期重置/永久/一码一次/无效/设备上限回滚)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 12:14:27 +08:00
wangjia e41085a878 feat(backend): 会话安全加固 + 授权实时 phase + 首次使用自动试用
会话安全(jti 轮换 / 重用检测 / 改密吊销 / 禁用即时下线 / 清理 / 失败登录落库):
- refresh token 轮换 jti + token-family 重用检测,旧 token 重放即吊销整条会话
- 改密码、停用用户即时吊销其全部活跃会话(revoked_by 审计)
- 中间件 session JOIN user 校验,禁用/删除用户带 token 请求返回 401 USER_DISABLED
- 新增 login_attempts 失败登录落库 + 会话保留期清理 goroutine

授权实时 phase + 心跳回带:
- LicenseGuard 改为按当前 DB 实时计算 phase(30s 每店缓存),续费/过期/被改 ~30s 内对写操作生效,无需重登
- /auth/ping 回带授权概况(ShopInfoView,与 /license/info 同构),客户端一次心跳即刷新横幅/门禁

首次使用自动试用 + code-review 修复:
- 门店首次登录/续期无有效授权时自动签发 30 天 trial(快路径无锁 Count,仅首用走 FOR UPDATE 事务)
- ShopInfo 区分「确无授权」与瞬时 DB 错误,避免误降级
- trial 签发后改为在事务提交后再失效 phase 缓存(修复早于提交的竞态)
- 存量无 sid token 续期纳入显式上限,legacy 会话不再游离于并发配额之外

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 07:34:04 +08:00
wangjia 2d84bda99a chore: release server-v1.0.58
Deploy Server / release-deploy-server (push) Successful in 48s
RefreshTokens 续登路径补发首次试用,修复自动续登老用户授权停留「未激活」。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2Wdwo7SmgBJU37cBrkhPK
2026-06-18 19:14:25 +08:00
wangjia 64a64e7c0a feat(backend): 首次登录无有效授权时自动发放 30 天试用
未激活门店(seed/手动建店/老数据,无任何 license 行)此前被当作永久授权,
既不拦截也无提示。现在登录时若门店无有效授权,自动签发 30 天 trial,
之后照常走 grace/readonly/locked 降级链。须在 issueTokens 之前发放,
使 JWT 的 lic_exp 带上新到期日。幂等(已有有效授权不重发),签发失败
仅记日志不阻断登录。复用注册路径的发放逻辑(抽出 issueTrialLicense)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2Wdwo7SmgBJU37cBrkhPK
2026-06-18 07:59:44 +08:00
wangjia 53fa259284 chore: release server-v1.0.56
Deploy Server / release-deploy-server (push) Successful in 40s
会话/设备管理后端:user_sessions 会话表、JWT 加 sid 校验、按平台类限并发登录、
登录失败锁定、修复禁用账号仍可凭 refresh 续期漏洞、/auth/ping、/auth/logout、
GET /sessions、DELETE /sessions/:id(管理员强制下线)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 23:12:13 +08:00
wangjia aa7099ba94 feat(devops): 发版拆分为 client/site/server 三条独立流水线
将单一 CI/CD 流水线拆成三条互不影响的发布流水线,各有 tag 前缀、独立版本
序列与独立 CHANGELOG:

- client(client-v*):Flutter 全平台 + version.yaml 自更新清单
- site(site-v*):web/ Eleventy 营销站,不含 web 版 app
- server(server-v*):backend Go 服务 + 共享基建 nginx/systemd

新增 3 个 workflow(deploy-client/site/server.yml)替换 deploy.yml;CI 脚本
按 part 拆分为 compile-/release-/deploy-{client,site,server}.sh,抽出公共函数
lib-forgejo.sh;compile-{macos,android,ios,windows}.sh 改去 client-v 前缀;
manual.yml 按前缀路由回滚。

跨流水线解耦:version.yaml 归 client,后端每请求实时读取(不重启、不触发
server 流水线);官网下载页的版本徽章/下载链接/更新日志时间线运行时经
/api/v1/public/release 动态拉取(API 不可达回退构建时静态内容)。为此一次性
扩展后端 changelog 字段(version.go/public.go)与 download.njk 动态渲染。

CHANGELOG.md 重命名为 CHANGELOG-client.md,新增 CHANGELOG-site/server.md;
重写 /release 命令为 /release <part> [version];同步更新 CLAUDE.md 与部署文档。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 08:21:28 +08:00
wangjia eca62ba2c3 fix(backend): 库存导入改用 shakinm/xlsReader,按唯一编号去重,入库日期取自 Excel
extrame/xls 误读真实 .xls(3264 行只读出 455 行、编号丢失、数字被当
日期序列),换用 shakinm/xlsReader 正确读取全部行。去重改为「有商品编号
时仅按编号匹配」,避免不同批次被 NSS 回退合并;Inventory.ProductCode
存行自身唯一编号。入库时间取 Excel 入库日期列写入 created_at。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 08:04:04 +08:00
wangjia 5cfd1795ec fix(backend): 库存导入用 Excel「入库日期」+ 同 key 增量更新/全同跳过
- 读取 Excel「入库日期」列(默认第12列,兼容入库日期/入库时间/入库日),
  显式写入库存 CreatedAt,不再被 GORM 落成导入当天;新增
  parseTimeWithFallback 兼容 yyyy-MM-dd / 含时分秒 / Excel 序列号
- 同 key(商品编码|仓库,回退 名+系列+规格|仓库):全字段一致则跳过,
  仅差异字段增量更新;库存流水仅在 quantity 实际变化时追加
- 响应新增 skipped 计数;多租户 shop_id 隔离不变

go build / vet / test 全过。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 00:56:31 +08:00
wangjia c1ba6c6d97 feat(backend): 二维码链接统一改为 /app/product/ 路径,消除 URL 跳变
Deploy / build-linux-web (push) Successful in 46s
Deploy / build-windows (push) Successful in 1m41s
Deploy / build-macos (push) Successful in 1m27s
Deploy / build-android (push) Successful in 58s
Deploy / build-ios (push) Successful in 6s
Deploy / release-deploy (push) Successful in 1m53s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 17:55:24 +08:00
wangjia 2b327cd365 fix(backend): 修复 /app/product/ 分享无 OG 标签,描述分两行显示
Deploy / build-linux-web (push) Successful in 49s
Deploy / build-windows (push) Successful in 1m45s
Deploy / build-macos (push) Successful in 1m24s
Deploy / build-android (push) Successful in 58s
Deploy / build-ios (push) Failing after 10m6s
Deploy / release-deploy (push) Has been skipped
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 17:52:41 +08:00
wangjia 07f8973477 fix(backend): 分享卡片描述补充系列(度数)信息
Deploy / build-linux-web (push) Successful in 47s
Deploy / build-windows (push) Successful in 1m44s
Deploy / build-macos (push) Successful in 1m26s
Deploy / build-android (push) Successful in 58s
Deploy / build-ios (push) Successful in 7s
Deploy / release-deploy (push) Successful in 1m50s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 17:36:04 +08:00
wangjia bde2d35756 fix(backend): 修复分享卡片 <title> 因缩进导致替换失效的问题
Deploy / build-linux-web (push) Successful in 47s
Deploy / build-windows (push) Successful in 1m45s
Deploy / build-macos (push) Successful in 1m27s
Deploy / build-android (push) Successful in 1m0s
Deploy / build-ios (push) Successful in 7s
Deploy / release-deploy (push) Successful in 1m48s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 16:37:20 +08:00
wangjia 4ac5adac3e chore: release v1.0.44
Deploy / build-linux-web (push) Successful in 47s
Deploy / build-windows (push) Successful in 1m44s
Deploy / build-macos (push) Successful in 1m24s
Deploy / build-android (push) Successful in 1m0s
Deploy / build-ios (push) Successful in 6s
Deploy / release-deploy (push) Successful in 1m56s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 16:31:47 +08:00
wangjia 8c2dcf49a8 chore: release v1.0.43
Deploy / build-linux-web (push) Successful in 49s
Deploy / build-windows (push) Successful in 1m44s
Deploy / build-macos (push) Successful in 1m25s
Deploy / build-android (push) Successful in 1m9s
Deploy / build-ios (push) Successful in 6s
Deploy / release-deploy (push) Successful in 1m56s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 16:11:38 +08:00
wangjia f400459497 fix(backend): 修复扫码页 index.html not found
Deploy / build-linux-web (push) Successful in 50s
Deploy / build-windows (push) Successful in 1m42s
Deploy / build-macos (push) Successful in 1m28s
Deploy / build-android (push) Successful in 1m0s
Deploy / build-ios (push) Successful in 7s
Deploy / release-deploy (push) Successful in 1m50s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 15:11:30 +08:00
wangjia a5bdb79f81 chore: release v1.0.40
Deploy / build-linux-web (push) Successful in 48s
Deploy / build-windows (push) Successful in 1m41s
Deploy / build-macos (push) Successful in 1m22s
Deploy / build-android (push) Successful in 1m9s
Deploy / build-ios (push) Successful in 6s
Deploy / release-deploy (push) Successful in 1m49s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 14:23:03 +08:00
wangjia 36564571fa chore: 补提测试修复、新增测试工具和设计文档
- fix(test): 同步 listInventory 签名(补 series/spec 参数)
- test(backend): 新增 import_parse_test.go
- chore(backend): 新增 cmd/test_xls 调试工具
- docs: UI 筛选组件设计规范、Gemini 项目配置

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 11:17:35 +08:00
wangjia eac3e8825c feat(client): 库存查询新增规格/系列/入库时间;筛选组件支持搜索+滚动+标签
- 库存查询加规格、系列服务端筛选(后端 IN 条件,前端从 product-options API 加载全量选项)
- 库存查询新增「入库时间」列,导出 Excel 同步带上
- 入库单商品明细:隐藏商品编码列,生产日期从选填折叠区移至主行常显
- 筛选弹窗重构:顶部搜索框实时过滤 + 滚动列表(ConstrainedBox maxHeight)根治溢出
- 已选项以 Chip 标签置顶展示,每个标签带 × 可单独取消
- FilterableColumnHeader 筛选图标改为常驻,不再需要 hover 才显示

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 11:15:43 +08:00
wangjia 316e9b6fc9 fix(backend): ImportProducts 改用 parseUploadedExcel 修复导入截断 100 条问题
旧代码直接调用 excelize.GetRows() 有内部 100 行限制;
其他 7 个导入函数在 50b139c 已修复,唯独 ImportProducts 漏网。
统一改用 parseUploadedExcel() 辅助函数,支持 .xls/.xlsx 且无行数截断。
2026-06-14 08:26:46 +08:00
wangjia 2ed0010c67 fix(backend): 补全多处 Scan/Count 错误未检查,私钥缺失改为 Fatal
- stock.go: ApproveStockIn 入库前库存 Scan 加错误检查
- license.go: Activate 阶段 Count 设备数加错误检查;createTrialLicense
  私钥未配置由静默跳过改为 log.Fatalf,防止生产环境新注册门店无 license
- inventory.go: List 接口两处 Raw Scan 加错误检查并返回 500
- finance.go: ArBalance 汇总 Raw Scan 加错误检查并返回 500
2026-06-14 08:12:57 +08:00
wangjia c553237f15 fix(db): 缩短 license_key 列至 VARCHAR(768) 避免 InnoDB 索引超限 [tsk_Qmk4wT_dkqRR]
原 size:2048 在 utf8mb4 下产生 8192 字节索引,超过 InnoDB 3072 字节上限,
全新环境 AutoMigrate 必失败。改为 VARCHAR(768)(768×4=3072 字节,恰好
在上限内),schema.sql 同步更新列类型并将 uk_license_key 改为全列索引(无
需前缀)。新增测试 TestLicenseTokenFitsColumnLimit 验证最坏情况 token 长度
确实在 768 字符以内。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 12:01:30 +08:00
wangjia e0bee00ff4 fix: 批量改进 (#2/#23/#38/#39/#40/#47)
- Web: 隐藏 ICP 备案号(条件渲染),联系入口改为微信咨询(条件渲染,配置 wechat 字段后生效)
- backend: 拼音回填抽取为独立 cmd/backfill-pinyin 工具,不再在启动时运行
- backend: DB 连接池参数(max_idle_conns/max_open_conns)改为配置可控,默认 10/100
- backend: Inventory 反范式字段添加注释说明快照语义
- backend: 全量 handler 采用 util.RespondSuccess/RespondCreated 统一响应格式(51 处)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 09:33:43 +08:00
wangjia d28aba863e fix(backend): license service 小修 (#45-46-48)
- #45 Activate 幂等路径 Update 加错误检查,失败时返回 error 而非静默成功
- #46 Verify 加载 license 加 shop_id 过滤(防御纵深)
- #48 删除 ErrDeviceMismatch 死代码(多设备迁移后已无单设备约束)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 09:06:15 +08:00
wangjia f928d5c6a3 fix(backend): 架构质量改进批次三 (#41-44)
- #41 CheckInventoryAvailability Scan 加错误检查,DB 故障不再误报库存不足
- #42 finance ListRecords 和 inventory Logs 补加 pageSize 上限(500)
- #43 ReconcileInventory 两条 Scan 加错误检查,DB 故障返回 500 而非误导性空结果
- #44 license Info 改用 CountDevices(licenseID) 统计当前 license 绑定数,修复跨 license 计数偏差

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 08:21:42 +08:00