deliver Hongfa Laundry M1 desktop release
This commit is contained in:
@@ -16,6 +16,7 @@ authors: claude (brainstorm), manpengan (decision)
|
||||
- 数据:本地 SQLite(WAL + 每日自动备份)
|
||||
|
||||
**典型场景:**
|
||||
|
||||
- 收件:查回头客 → 录物品明细 → 计价收款 → 生成 4 位取件码 → 打印登记单
|
||||
- 取件:客户报取件码 / 电话 / 单号 → 查询 → 收尾款 → 标记已取 → 打印取件条
|
||||
- 管理:店主查看日/月营业额、逾期未取、回头率
|
||||
@@ -28,25 +29,25 @@ authors: claude (brainstorm), manpengan (decision)
|
||||
|
||||
## 3. 技术栈
|
||||
|
||||
| 层 | 选型 |
|
||||
|---|---|
|
||||
| 应用框架 | Electron 32+ |
|
||||
| 前端 | React 19 + TypeScript 5 (strict) |
|
||||
| UI | Tailwind CSS 4 + shadcn/ui |
|
||||
| 动效 | Framer Motion 11 |
|
||||
| 字体 | SF Pro Display/Text + PingFang SC |
|
||||
| 状态 | Zustand |
|
||||
| 路由 | React Router 7 |
|
||||
| 数据库 | better-sqlite3 + Drizzle ORM |
|
||||
| 密码哈希 | @node-rs/argon2 |
|
||||
| 构建 | Vite + electron-vite |
|
||||
| 打包 | electron-builder(NSIS) |
|
||||
| 图表 | Recharts |
|
||||
| 打印 | electron-pos-printer(58mm ESC/POS) |
|
||||
| 短信 | @tencentcloud/tencentcloud-sdk-nodejs-sms |
|
||||
| Excel | exceljs |
|
||||
| 测试 | Vitest(单测)+ Playwright(E2E) |
|
||||
| CI | GitHub Actions(`windows-latest` 构建 + artifact) |
|
||||
| 层 | 选型 |
|
||||
| -------- | -------------------------------------------------- |
|
||||
| 应用框架 | Electron 32+ |
|
||||
| 前端 | React 19 + TypeScript 5 (strict) |
|
||||
| UI | Tailwind CSS 4 + shadcn/ui |
|
||||
| 动效 | Framer Motion 11 |
|
||||
| 字体 | SF Pro Display/Text + PingFang SC |
|
||||
| 状态 | Zustand |
|
||||
| 路由 | React Router 7 |
|
||||
| 数据库 | better-sqlite3 + Drizzle ORM |
|
||||
| 密码哈希 | @node-rs/argon2 |
|
||||
| 构建 | Vite + electron-vite |
|
||||
| 打包 | electron-builder(NSIS) |
|
||||
| 图表 | Recharts |
|
||||
| 打印 | electron-pos-printer(58mm ESC/POS) |
|
||||
| 短信 | @tencentcloud/tencentcloud-sdk-nodejs-sms |
|
||||
| Excel | exceljs |
|
||||
| 测试 | Vitest(单测)+ Playwright(E2E) |
|
||||
| CI | GitHub Actions(`windows-latest` 构建 + artifact) |
|
||||
|
||||
**UI 视觉规范(Apple HIG):** SF Pro + PingFang SC、圆角 12–16px、半透明/毛玻璃卡片、macOS System Colors(`systemBlue #007AFF` 等)、Framer Motion 过渡、深色模式跟随系统、窗口 `titleBarStyle: 'hiddenInset'`(Mac 开发态)/ Windows 下降级为圆角无边框。
|
||||
|
||||
@@ -54,16 +55,16 @@ authors: claude (brainstorm), manpengan (decision)
|
||||
|
||||
金额一律用**整数分**存储(杜绝浮点)。
|
||||
|
||||
| 表 | 关键字段 |
|
||||
|---|---|
|
||||
| `customers` | id, name, phone (unique), vip_level, total_orders, total_spent, created_at, updated_at |
|
||||
| `orders` | id, order_no (unique, `YYYYMMDD-NNNN`), pickup_code (char(4)), customer_id (fk), status (pending/ready/picked_up/cancelled), total_amount, paid_amount, payment_method (cash/wechat/alipay/card/unpaid), receive_date, expected_pickup_date, actual_pickup_at, staff_id (fk), picked_up_by (fk nullable), notes, created_at, updated_at |
|
||||
| `order_items` | id, order_id (fk cascade), item_type, service_type (wash/dry_clean/iron), quantity, unit_price, subtotal, item_notes |
|
||||
| `order_photos` | id, order_id (fk cascade), file_path (相对 userData), taken_at |
|
||||
| `staffs` | id, username (unique), password_hash (Argon2), display_name, role (admin/staff), is_active, created_at, last_login_at |
|
||||
| `sms_log` | id, order_id (fk), phone, content, status (pending/sent/failed), provider_response (json), sent_at |
|
||||
| `settings` | key (pk), value (json), updated_at |
|
||||
| `audit_log` | id, staff_id (fk nullable), action (create/update/delete/pickup/cancel/login/export), entity, entity_id, diff (json), created_at |
|
||||
| 表 | 关键字段 |
|
||||
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `customers` | id, name, phone (unique), vip_level, total_orders, total_spent, created_at, updated_at |
|
||||
| `orders` | id, order_no (unique, `YYYYMMDD-NNNN`), pickup_code (char(4)), customer_id (fk), status (pending/ready/picked_up/cancelled), total_amount, paid_amount, payment_method (cash/wechat/alipay/card/unpaid), receive_date, expected_pickup_date, actual_pickup_at, staff_id (fk), picked_up_by (fk nullable), notes, created_at, updated_at |
|
||||
| `order_items` | id, order_id (fk cascade), item_type, service_type (wash/dry_clean/iron), quantity, unit_price, subtotal, item_notes |
|
||||
| `order_photos` | id, order_id (fk cascade), file_path (相对 userData), taken_at |
|
||||
| `staffs` | id, username (unique), password_hash (Argon2), display_name, role (admin/staff), is_active, created_at, last_login_at |
|
||||
| `sms_log` | id, order_id (fk), phone, content, status (pending/sent/failed), provider_response (json), sent_at |
|
||||
| `settings` | key (pk), value (json), updated_at |
|
||||
| `audit_log` | id, staff_id (fk nullable), action (create/update/delete/pickup/cancel/login/export), entity, entity_id, diff (json), created_at |
|
||||
|
||||
**索引:** `orders(pickup_code)`、`orders(customer_id, status, receive_date)`、`audit_log(created_at)`、`customers(phone) unique`、`orders(order_no) unique`。
|
||||
|
||||
@@ -97,6 +98,7 @@ src/
|
||||
```
|
||||
|
||||
**硬约束:**
|
||||
|
||||
- `contextIsolation: true` / `nodeIntegration: false` / `sandbox: true` / CSP 严格
|
||||
- Renderer 零 Node/DB 访问,全走 IPC
|
||||
- IPC 命名 `<domain>:<action>`(如 `orders:create`);入参一律过 Zod;返回 `{ ok: true, data } | { ok: false, error: { code, message } }`
|
||||
@@ -106,25 +108,29 @@ src/
|
||||
## 6. 核心工作流
|
||||
|
||||
### 6.1 收件
|
||||
|
||||
电话查回头客 → 明细多行 → 付款方式 + 实收 → 事务生成 `pickup_code` + `order_no` → 写 `orders` + `order_items`(+ 可选 `order_photos`)→ 更新 `customers.total_orders/total_spent` → `audit_log` → (M3)打印登记单。
|
||||
|
||||
### 6.2 取件
|
||||
|
||||
取件码(优先)/ 电话 / 单号 / 姓名查询 → 多条时列表选 → 有欠款先收 → `status = picked_up`、`actual_pickup_at`、`picked_up_by` → `audit_log` → (M3)打印取件条。
|
||||
|
||||
### 6.3 自动备份
|
||||
|
||||
`app.ready` 启动 `node-cron` 03:00 → `PRAGMA wal_checkpoint(TRUNCATE)` → 复制 `.db` → zip → 滚动保留 30 份。
|
||||
|
||||
### 6.4 短信通知(M4)
|
||||
|
||||
手动/批量触发 → Service 调腾讯云 SMS SDK → 写 `sms_log`(pending → sent/failed)→ 状态回填订单详情。
|
||||
|
||||
## 7. 分期路线图
|
||||
|
||||
| 期 | Tag | 交付 |
|
||||
|---|---|---|
|
||||
| **M1** | `v0.1.0` | 项目骨架 + Apple HIG 设计系统 + 收件/取件/列表/详情 + 客户自动去重 + 自动备份 + Windows NSIS 打包 |
|
||||
| **M2** | `v0.2.0` | 价格模板 + 按件计费 + 折扣 + 付款/欠款 + 日/月报表(Recharts)+ 逾期未取 + Excel 导入导出 |
|
||||
| **M3** | `v0.3.0` | 收件拍照(1–3 张,存 `userData/photos/YYYY-MM/`)+ 58mm 热敏打印登记单 / 取件条 |
|
||||
| **M4** | `v0.4.0` → `v1.0.0` | 登录(Argon2)+ 权限(admin/staff)+ 审计日志全面绑定 + 腾讯云 SMS 可取件通知(可关闭) |
|
||||
| 期 | Tag | 交付 |
|
||||
| ------ | ------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| **M1** | `v0.1.0` | 项目骨架 + Apple HIG 设计系统 + 收件/取件/列表/详情 + 客户自动去重 + 自动备份 + Windows NSIS 打包 |
|
||||
| **M2** | `v0.2.0` | 价格模板 + 按件计费 + 折扣 + 付款/欠款 + 日/月报表(Recharts)+ 逾期未取 + Excel 导入导出 |
|
||||
| **M3** | `v0.3.0` | 收件拍照(1–3 张,存 `userData/photos/YYYY-MM/`)+ 58mm 热敏打印登记单 / 取件条 |
|
||||
| **M4** | `v0.4.0` → `v1.0.0` | 登录(Argon2)+ 权限(admin/staff)+ 审计日志全面绑定 + 腾讯云 SMS 可取件通知(可关闭) |
|
||||
|
||||
## 8. 验收门禁(每期必过)
|
||||
|
||||
@@ -135,25 +141,25 @@ src/
|
||||
|
||||
## 9. 分工
|
||||
|
||||
| 角色 | 职责 | 工具 |
|
||||
|---|---|---|
|
||||
| 角色 | 职责 | 工具 |
|
||||
| --------------------- | ------------------------------------------ | ----------- |
|
||||
| **Claude (Opus 4.7)** | brainstorm / spec / 门禁验收 / code review | Claude Code |
|
||||
| **Codex** | 关键节点二次审查(架构 / 安全 / 并发) | Codex CLI |
|
||||
| **Gemini** | M1~M4 主力实现、测试编写、修 build | Gemini CLI |
|
||||
| **manpengan** | 决策 / UI 走查 / 发版 | — |
|
||||
| **Codex** | 关键节点二次审查(架构 / 安全 / 并发) | Codex CLI |
|
||||
| **Gemini** | M1~M4 主力实现、测试编写、修 build | Gemini CLI |
|
||||
| **manpengan** | 决策 / UI 走查 / 发版 | — |
|
||||
|
||||
**节奏:** 每期开始 Claude 在 milestone issue 补实施细节 → Gemini 提 PR → Claude 审 → Codex 关键点复审 → Claude 过门禁清单 → manpengan tag release。
|
||||
|
||||
## 10. 风险与缓解
|
||||
|
||||
| 风险 | 缓解 |
|
||||
|---|---|
|
||||
| 风险 | 缓解 |
|
||||
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |
|
||||
| Mac 交叉打 Windows exe,better-sqlite3 native 模块失败 | GH Actions `windows-latest` 为准;本地 `pnpm rebuild`;electron-builder `buildDependenciesFromSource: false` |
|
||||
| 打印机型号差异 | M3 抽象 `PrinterDriver` 接口,先支持 58mm 通用 ESC/POS,型号配置化 |
|
||||
| 腾讯云 SMS 模板审核周期 | Provider 可替换;模板 id 从 settings 读;无短信时仍可发版 |
|
||||
| SQLite 单文件损坏 | WAL + 每日 zip + 备份校验任务 |
|
||||
| Electron XSS → 任意代码 | contextIsolation + sandbox + CSP + 所有 IPC 过 Zod |
|
||||
| 密钥泄漏(短信 SecretKey) | M4 用 OS keychain(`keytar`)加密存储,非明文入库 |
|
||||
| 打印机型号差异 | M3 抽象 `PrinterDriver` 接口,先支持 58mm 通用 ESC/POS,型号配置化 |
|
||||
| 腾讯云 SMS 模板审核周期 | Provider 可替换;模板 id 从 settings 读;无短信时仍可发版 |
|
||||
| SQLite 单文件损坏 | WAL + 每日 zip + 备份校验任务 |
|
||||
| Electron XSS → 任意代码 | contextIsolation + sandbox + CSP + 所有 IPC 过 Zod |
|
||||
| 密钥泄漏(短信 SecretKey) | M4 用 OS keychain(`keytar`)加密存储,非明文入库 |
|
||||
|
||||
## 11. 假设
|
||||
|
||||
|
||||
Reference in New Issue
Block a user