Commit Graph

84 Commits

Author SHA1 Message Date
wangjia 86baaf3a1c fix(model): users 唯一索引改为 (shop_id, username) 复合索引
Deploy / deploy (push) Successful in 1m13s
原来 uniqueIndex:uk_shop_username 只在 Username 字段上,导致用户名全局唯一。
S002/S003 的 admin 用户与 S001 冲突,INSERT 被静默跳过,无法登录。

将 User 的 TenantBase 改为直接定义 ShopID,使其参与复合唯一索引。
需要 Reset DB 使新索引生效。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v20260524.1451
2026-05-24 14:50:34 +08:00
wangjia fcf92675b1 fix(seeds): 修复 clear_shop.sql collation 冲突
Deploy / deploy (push) Successful in 1m13s
用 BINARY 比较绕过 utf8mb4_unicode_ci 与 utf8mb4_0900_ai_ci 的冲突。
shop code 均为纯 ASCII,BINARY 比较结果完全一致。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v20260524.1435
2026-05-24 14:34:14 +08:00
wangjia d81b2d1fac fix(seed.yml): 两步走避免 S001 因 id 冲突被跳过
Deploy / deploy (push) Successful in 1m17s
清空和写入分两个独立循环:先清空所有门店,再依次写入。
避免 S001(硬编码 id=1) 在 S002 尚未清除时被 INSERT IGNORE 跳过。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v20260524.1431
2026-05-24 14:30:46 +08:00
wangjia acf2b22201 fix(seeds): 修复多门店种子数据互不干扰
Deploy / deploy (push) Successful in 1m14s
- S001.sql: 修复 INSERT IGNORE INTO 缺少空格的语法错误
- S002.sql: 重写为动态 @shop_id 模式,移除 TRUNCATE,改用 INSERT IGNORE INTO
- clear_shop.sql: 新增按 @shop_code 清空单店数据的参数化脚本
- scripts/dev.sh: seed 命令支持 --clear 参数(先清空再写入)
- seed.yml: 新增 clear 输入参数,支持按需清空后写入

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v20260524.1354
2026-05-24 13:52:47 +08:00
wangjia 8adb94a9a4 fix(deploy): 修复多 shop seed 互相 TRUNCATE 问题 + 补 utf8mb4 charset
Deploy / deploy (push) Successful in 1m12s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v20260524.1342
2026-05-24 13:41:34 +08:00
wangjia a6e0edbc00 chore(deploy): 新增 debug-db workflow,查询线上数据库内容
Deploy / deploy (push) Successful in 1m14s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v20260524.1320
2026-05-24 13:19:38 +08:00
wangjia 2b180be926 chore(deploy): 新增 reset-db workflow,清库重建表结构并写入 seed 数据
Deploy / deploy (push) Successful in 1m16s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v20260524.1259
2026-05-24 12:58:34 +08:00
wangjia 1bf1f7563f chore(deploy): 新增 seed workflow,支持手动触发写入门店测试数据
Deploy / deploy (push) Successful in 1m13s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v20260524.1252
2026-05-24 12:51:08 +08:00
wangjia 988a941b41 chore(deploy): 简化 nginx 路由 + 自动部署 nginx config + 删除 .github workflows
Deploy / deploy (push) Successful in 1m16s
- nginx: /app/ → Flutter,/ 兜底 → 营销站,移除零散 location 块
- deploy.yml: 每次部署自动 scp nginx-jiu.conf 到服务器并 nginx -t reload
- deploy.yml: Release 附件新增 configs.tar.gz(nginx/systemd/compose 配置)
- 删除 .github/workflows/(已全部迁移到 .gitea/)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v20260524.1245
2026-05-24 12:44:50 +08:00
wangjia 32ea281dfa fix(ci): 修复 deploy.yml YAML 解析错误
Deploy / deploy (push) Has been cancelled
多行 bash 字符串的续行未缩进到 run: | 块内,YAML 解析器
将 '- **版本**' 误判为列表项。改用 printf 单行拼接 BODY。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v20260524.1114
2026-05-24 10:54:35 +08:00
wangjia 9f94cc97b7 fix(test): 修复测试数据库 schema 和 Flutter 测试与屏幕重构的兼容性
- backend/testutil/setup.go: SQLite shops 表补充 business_hours 列
- stock_in_screen_test: 入库管理双 Tab 重构后,draft/pending 测试改为先切换到「入库审核」Tab
- stock_out_insufficient_stock_flow_test: Inventory 构造参数 productUnit→unit,补充必填 id
- inventory_repository_test: mock 数据改为平铺字段格式,补充必填 id
- docs: 新增 NAS + Gitea 部署文档(Runner 设置、Shadowrocket 中继说明)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 10:48:21 +08:00
wangjia b90a89790f feat(web): 五个营销页面完整还原设计稿
统一 nav(5 个链接含支持、auth-aware 用户下拉菜单)、
docs 页补充面包屑/搜索/版本栏三栏布局、
footer 完整 5 列、所有内链替换为生产绝对路径。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 00:57:32 +08:00
wangjia 30a8e791a3 feat: 扫码商品详情页重设计 + 宣传主页 + nginx 路由完善
- public_product_screen: 1:1 复刻设计稿,新增商品介绍、批次防伪(自定义圆形印章)、完整商品参数表、门店营业时间、页脚链接
- app_theme: 完整品牌色系(brand/gray/accent/semantic)
- shop model: 新增 business_hours 字段,public 接口同步返回
- nginx: 新增 /product/ → Flutter app 扫码入口,修复 /docs /download html 后缀兼容
- web/: 新增宣传主页、功能页、文档页、扫码 HTML 及设计资源
- app_shell: 界面优化

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 18:58:04 +08:00
wangjia 1b4ca0c675 fix(test): 修复测试文件类型错误和测试数据库 schema 过期问题
- 修正 stock_in/out 测试中 WarehouseID/ProductID 指针误用(StockOrder 用 uint64,Inventory 用 *uint64)
- 更新 testutil/setup.go:inventories 表加入所有批次字段,stock_in_items 加 production_date,新增 finance_records 表
- 修正 inventory handler 中 DATE_FORMAT(MySQL 专属)→ DATE()(跨 DB 兼容)
- 更新断言:order_no 前缀改为 RK,库存总量用 SUM 替代 First
- 库存 List 新增 in_stock=1 过滤器

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 14:16:10 +08:00
wangjia c1ed81dfab feat: 财务结清、酒行信息、库存备注编辑、标签溯源、入库必填校验
后端
- 新增 shop handler:GET/PUT /shop/info(管理员权限)
- 新增 finance CloseByRef:按单据 ref_type+ref_id 结清账款
- 新增 inventory UpdateRemark:PUT /inventory/:id/remark
- 入库/出库审批自动生成财务应付/应收记录(去除金额>0限制)
- 种子数据 S001-S003 补充真实门店信息

前端
- 设置页新增「酒行信息」Tab,管理员可编辑门店名称/地址/电话/负责人
- 入库单列表新增结清按钮(含确认弹窗),出库单同步
- 入库表单:规格、系列、生产日期、供应商、商品名称改为提交必填
- 入库/出库列表新增入库时间、出库时间、创建时间列
- 商品标签标题改为读取 shop 表门店名,扫码文案改为「扫码溯源 · TRACE」
- 标签页脚显示门店地址和电话(从 API 读取,不再依赖编译时 dart-define)
- 库存备注支持点击编辑,超4字截断显示+Hover展示全文
- ApiClient 新增 patch() 方法(已改用 PUT 规避 CORS)

文档
- 新增 docs/user-manual.md 完整用户操作手册(12章)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 14:05:41 +08:00
wangjia c77e1c1490 fix(scripts): run --help 不再误启动服务,新增完整帮助文档
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 09:01:56 +08:00
wangjia 91343a2349 fix: 修复库存导入 500 错误 + 开启全局文字选中
- findOrCreateProductFn 补充 PublicID(UUID),避免 unique 约束冲突导致事务 500
- main.dart 加 SelectionArea builder,全局开启 Web 文字复制选中能力

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 08:59:21 +08:00
wangjia 86738c903e feat: 新增 superadmin 角色和数据清空功能
后端:
- User.Role enum 增加 superadmin,启动时 ALTER TABLE 兼容已有 DB
- 新增 SuperAdminOnly() 中间件
- 新增 POST /api/v1/admin/clear-data 接口(按表名白名单删除,多租户隔离)

前端:
- AppUser/AuthUser 支持 role 字段持久化与传递
- 数据导入 Tab 末尾增加「危险操作 — 数据清空」区块(仅 superadmin 可见)
- 支持多选:入库单/出库单/库存管理/商品详情/往来单位
- 红色警告框 + 二次确认弹窗(需手动输入"确认清空")

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 01:07:56 +08:00
wangjia 56e0d9d5b2 fix(client): 开启 macOS 打印沙盒权限
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 00:59:35 +08:00
wangjia 142e92f151 feat(client): 新增入库单/出库单打印,增强商品标签打印布局
- 商品标签改为 4×2 英寸横向,二维码右置,左侧展示系列/规格/批次/生产日期
- 新增 printStockInOrder:A4 入库单,含单号/供应商/仓库/明细表/签字栏
- 新增 printStockOutOrder:A4 出库通知单(温馨提示),含客户/明细表/签字栏
- 入库单/出库单编辑页加载完成后显示「打印」按钮

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 00:50:54 +08:00
wangjia 7ac06a409d feat: 库存 XLS 导入功能(后端接口 + 前端导入按钮) 2026-05-19 00:22:17 +08:00
wangjia b243ad885f chore(deploy): 更新 NAS 部署配置和本地部署脚本
- docker-compose: 切换为 gitea/gitea 镜像,修正备份挂载路径
- scripts/deploy.sh: 新增本地一键部署脚本(测试→编译→发版→部署)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 02:30:03 +08:00
wangjia bf38217e2b feat(ci): Release 添加 commit、构建时间、最近提交记录 2026-05-08 02:29:10 +08:00
wangjia 35d73a93a1 chore: 重新触发(修复 EC2_SSH_KEY 格式)
Deploy / deploy (push) Successful in 1m11s
v20260508.0225
2026-05-08 02:24:19 +08:00
wangjia b3a0c132b7 chore: 重新触发部署(修复 FORGEJO_TOKEN)
Deploy / deploy (push) Failing after 56s
v20260508.0223
2026-05-08 02:22:50 +08:00
wangjia 41c8bd4732 chore: 触发部署测试
Deploy / deploy (push) Failing after 43s
2026-05-08 02:18:30 +08:00
wangjia 7c90661d1a fix(ci): 修复备份路径和 SSH key 换行问题
Deploy / deploy (push) Failing after 1m5s
2026-05-08 02:03:27 +08:00
wangjia cb68b5bdc5 chore: 触发 mac runner 测试
Deploy / deploy (push) Has been cancelled
2026-05-08 02:00:31 +08:00
wangjia 315a328570 chore(ci): 改用 Mac 本机 runner,直接使用已安装的 Go/Flutter
Deploy / deploy (push) Has been cancelled
2026-05-08 01:57:47 +08:00
wangjia a70fdc90b0 chore(ci): 打印 Release API 响应便于排错
Deploy / deploy (push) Failing after 31m28s
2026-05-08 01:00:55 +08:00
wangjia ecd72e8b0a chore(ci): 预装 Go/Flutter 到 NAS,CI 直接挂载使用
Deploy / deploy (push) Failing after 7m29s
2026-05-08 00:49:06 +08:00
wangjia 6a875db001 chore(ci): 添加 Go/Flutter/依赖缓存,避免每次重复下载
Deploy / deploy (push) Has been cancelled
2026-05-08 00:11:41 +08:00
wangjia 4e20203ed1 chore(ci): 用国内镜像替换 GitHub 下载(Go/Flutter)
Deploy / deploy (push) Has been cancelled
2026-05-08 00:09:00 +08:00
wangjia f26565b871 chore: trigger CI/CD test
Deploy / deploy (push) Has been cancelled
2026-05-07 23:41:12 +08:00
wangjia 89d3433a9d ci: 修复 actions 镜像地址
Deploy / deploy (push) Failing after 10m48s
2026-05-07 23:22:49 +08:00
wangjia c738543e86 ci: 修复 runner instance URL
Deploy / deploy (push) Failing after 7m9s
2026-05-07 08:38:01 +08:00
wangjia 6fb1b076ce ci: 触发首次 NAS CI/CD 验证
Deploy / deploy (push) Failing after 56s
2026-05-07 01:19:22 +08:00
wangjia 21088fc908 feat(deploy): 新增 Forgejo NAS 自托管 Git + CI/CD 配置
Deploy / deploy (push) Has been cancelled
- deploy/runner/docker-compose.forgejo.yml:Forgejo + act_runner,ROOT_URL 参数化
- .gitea/workflows/ci.yml:非 main 分支测试
- .gitea/workflows/deploy.yml:main 推送自动构建、创建 Forgejo Release、部署到 EC2
- .gitea/workflows/backup.yml:每日 02:00 备份 MySQL 到 NAS /volume1/backups

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 22:09:00 +08:00
wangjia 50b139c97a fix: 修复打印中文乱码、XLS导入100条截断、Nginx图片路由
- 打印改为 Web 平台用 HTML+CSS 方案,避免 pdf 包中文字体 bug
- 新增 print_util.dart 条件导入层(web/stub),彻底隔离 platform channel
- XLS 导入不再依赖 DIMENSIONS 记录的 MaxRow,改为读到连续5空行停止
- Nginx /images/ 加 ^~ 前缀,防止 .jpg 正则 location 拦截

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 22:07:17 +08:00
wangjia 6fc6b52631 feat(client): 搜索选项支持拼音和首字母
使用 lpinyin 预计算每个选项的全拼和首字母,
输入 wl 可匹配「五粮液」,输入 maotai 可匹配「茅台」。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 20:16:48 +08:00
wangjia cdf273da76 feat(client): 名称/系列/规格可搜索下拉 + 修复打印状态提示
- 新增 SearchableOptionField 组件:点击弹出带搜索框的对话框,支持实时过滤
- 入库/出库表单名称、系列、规格列全部替换为可搜索选择器
- 打印按钮加步骤状态提示(正在准备字体→生成PDF→打开打印)+ catch 错误展示

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 20:13:07 +08:00
wangjia 66dbc4829c fix(client): 修复 web 端选择文件后无反应问题
- 添加 result.files.isEmpty 检查(web file_picker 偶发空列表)
- web 平台不传 initialDirectory(避免潜在兼容性问题)
- 添加 mounted 检查和 try-catch,异常通过 SnackBar 显示

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 19:58:22 +08:00
wangjia 97ca4c7f72 fix(client): 修复导入静默失败问题
捕获所有异常(非仅 DioException),兼容 ImportProducts 响应格式(无 total/skipped),
确保任何错误都在 UI 上显示而不是静默消失。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 19:39:39 +08:00
wangjia 6923a0585c fix(client): 修复打印按钮加载后不激活问题
setState 触发重建,确保二维码加载完成后按钮变为可点击。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 19:30:11 +08:00
wangjia 1747c58246 feat(client): 二维码打印功能
在商品详情二维码弹窗中新增「打印」按钮,使用 printing + pdf
生成含商品名称、编号、规格和二维码图片的 PDF,触发浏览器打印对话框。
嵌入 NotoSansSC-Regular 字体保证中文正常显示。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 19:21:50 +08:00
wangjia cf646226a8 fix(client): 修复图片上传 content-type 被覆盖问题
BaseOptions 不应写死 Content-Type: application/json,
Dio 会根据 data 类型自动选择(FormData → multipart,Map → json)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 00:56:46 +08:00
wangjia f5c41e04f3 fix: 修复测试 schema 缺失字段,标记过时测试为 skip
- testutil/setup.go 补充 products.public_id、description,partners.status
- 过时 products/stock 流程测试标记 skip(provider 已不挂载)
- deploy.sh 补充 PUBLIC_URL dart-define

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 00:46:25 +08:00
wangjia 655c1d366e feat: 公开商品页重设计 + web 上传修复 + 二维码配置
- 公开商品页(/product/:uuid)全面重设计:全宽正方形图片轮播、
  左右滑动切图、点击放大全屏查看、商品参数含描述、页脚贴底
- 修复 Flutter web 文件上传无反应(path→bytes)
- 修复 web 路由空白页(usePathUrlStrategy + 单层 MaterialApp.router)
- 二维码 URL 改为从 STORAGE_PUBLIC_URL 环境变量读取
- 新增 PUBLIC_URL dart-define → AppConfig.publicBaseUrl
- 新增 CI/CD workflows + NAS runner compose 配置
- seed S001 补充商品描述字段

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 00:31:11 +08:00
wangjia 393e227de5 feat: 商品详情页、XLS导入修复、分页选择器、导出功能
后端:
- 新增 product_images 表,支持每商品最多5张图(服务端压缩至1200px/JPEG85%)
- products 表新增 public_id(UUID)、description 字段
- 新增商品详情接口、二维码接口、公开商品接口(无鉴权)
- 修复 XLS 导入:OLE2 magic bytes 检测 + 临时文件解析,兼容 extrame/xls
- 修复商品/名称/系列/规格三张表导入数据为0(LastCol()=0 bug)
- 所有导入接口返回 total/imported/skipped 统计
- config 新增 StorageConfig,支持 STORAGE_* 环境变量覆盖
- 种子数据修复:products 补 public_id、新增 product_images TRUNCATE、schema.sql 表名修正

前端:
- 商品详情页:图片上传/删除、描述内联编辑、二维码弹窗、公开链接复制
- 公开商品页:无鉴权路由 /product/:public_id,Flutter Web SPA
- 商品详情列表(批次追踪)商品名超链接跳转详情页
- 导航「商品管理」改名「商品详情」
- 所有列表表格新增每页条数选择(10/20/50/100)
- 表格列头内嵌筛选(FilterableColumnHeader)
- 导出 Excel 功能(入库/出库/库存/财务/批次/往来单位)
- 网络恢复自动刷新 + 离线缓存展示

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 00:29:51 +08:00
wangjia 5dd7c07138 feat(client): 网络恢复自动刷新 + 离线嗅探 + 连通性感知登录
网络嗅探与自动恢复:
- ConnectivityNotifier:在线时 30s 检测,离线时切换为 1min 嗅探
- 新增 networkRecoveryCountProvider:网络恢复时自增,各数据 provider
  通过 ref.watch 实现自动重新加载
- inventory/product/stock_in/stock_out/partner provider 均已接入

FutureBuilder 类屏幕:
- finance_screen + batch_tracking_screen 通过 ref.listen 监听恢复事件

修复问题 1:API 超时 10s/30s → 5s/15s,减少无网络时等待
修复问题 2:offline banner 文字由"写操作已禁用"改为实际行为描述

连通性感知:
- app 启动时(_AppBootstrap)立即 forceCheck,路由跳转前状态已就绪
- 登录页:watch connectivityProvider,离线时显示警告 banner
- 登录按钮:离线状态下直接提示,不等待超时

测试:
- login_screen_test + login_flow_test 通过 ConnectivityNotifier(skipInit: true)
  覆盖 provider,避免测试环境中 pending HTTP timer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 19:52:17 +08:00