v3.5.5版本上传
CI / verify (pull_request) Waiting to run

This commit is contained in:
2026-08-23 12:26:57 +08:00
parent f9161368e1
commit 22cd00da42
18 changed files with 2036 additions and 294 deletions
+119 -75
View File
@@ -1,101 +1,145 @@
# 杜康好客 · v3.5.4 商品规格(SPU + SKU
# 杜康好客 · v3.5.4 开发文档
> **2026-08-21** · mini-user / admin-web / h5-partner / API / Prisma
> 目标:商品详情页内可选销售规格;价格、权益、69 码、履约、上下架按 SKU;箱装按瓶当量起购与物流。
> **生产 commit**`5fdddae`(规格主图与门店使用规则合并入 `main`)及后续客户端版本号 `3.5.4`
> **主题**:商品规格(SPU + SKU)上线 + 同批次发票 / 文案 / 门店详情体验
## 范围
---
| # | 项 | 交付 |
## 1. 版本目标
1. 商品由单规格升级为 **SPU + 多 SKU**:价格、权益、69 码、履约、上下架、主图按规格。
2. 箱装按 **瓶当量** 起购与物流,不改城市起购阈值口径。
3. **旧客户端兼容**:不传 `skuId` 仍可下单;无 SKU 回落 SPU,禁止「商品暂无可售规格」误伤。
4. 同批次补齐:发票品类、权益文案、收银台 logo、门店详情「使用规则」、C 端版本号。
**不做**:SKU 库存、把现有酒祖 10/15/20 合并为一个 SPU。
---
## 2. 功能清单(完整)
### 2.1 商品规格(核心)
| # | 模块 | 交付说明 |
|---|------|----------|
| 1 | 数据模型 | `common_product_item` 作 SPU;新增 `spec_attr` / `spec_value` / `sku` / `sku_spec`;订单快照 `sku_id` / `sale_unit` / `bottles_per_unit` |
| 2 | 存量迁移 | 每商品默认 1 个瓶装 SKU;SQL `migrate-product-sku-v354.sql`;脚本 `backfill-product-skus.ts` |
| 3 | Catalog | 列表 `specEnabled`/`saleUnit`;详情 `specAttrs`/`skus`/`defaultSkuId`;旧字段拍平保留 |
| 4 | Trade | preview/create 可选 `skuId`;有可售 SKU → 默认/唯一;**0 可售 → 回落 SPU**;订单 `sku_id` 可空 |
| 5 | Domain | 起购/大单/物流按 `quantity × bottlesPerUnit` 瓶当量 |
| 6 | Admin | `PUT .../specs``PUT .../skus`;抽屉加宽;「填写」弹窗;规格轴 + SKU 矩阵 |
| 7 | mini-user | 详情规格 chips;确认页带 `skuId`;箱装数量文案;选规格切主图 |
| 8 | 代下单 | HQ / 合伙人可选规格 SKU |
### 2.2 SKU 码与 69 码
| # | 项 | 说明 |
|---|----|------|
| 1 | 数据模型 | `common_product_item` 升级为 SPU;新增 `spec_attr` / `spec_value` / `sku` / `sku_spec`;订单快照 `sku_id` / `sale_unit` / `bottles_per_unit` |
| 2 | 存量迁移 | 每商品 1 个默认瓶装 SKU;SQL:`prisma/migrate-product-sku-v354.sql`;脚本:`prisma/backfill-product-skus.ts` |
| 3 | Catalog | 列表附加 `specEnabled`/`saleUnit`;详情附加 `specAttrs`/`skus`/`defaultSkuId`;旧字段拍平保留 |
| 4 | Trade | preview/create 可选 `skuId`;无 SKU 回落 SPU;有可售 SKU 用默认/唯一 |
| 5 | Admin | `PUT /admin/products/:id/specs``PUT .../skus`;商品抽屉加宽;规格弹窗填写;每规格主图 |
| 6 | mini-user | 详情规格 chips;选规格切主图;确认页带 `skuId`;箱装数量文案 |
| 7 | 代下单 | HQ / 合伙人可选规格 SKU |
| 8 | 权益文案 | 「好客权益券」→「好客权益」;首页角标「享{amount}好客权益」(去掉门店 icon) |
| 9 | SKU 码 | 系统生成 `DK` + 6 位数字,后台不可填;每规格独立 69 码 |
| 10 | 规格主图 | `common_product_sku.image_url` 可选;空则 C 端回落商品封面 |
| 9 | SKU 码 | 系统生成 `DK` + 6 位数字,后台不可手填;脚本 `rewrite-sku-codes-dk.ts` 改存量 |
| 10 | 69 码 | **每规格独立**;同商品内 + 跨商品唯一;不可与其它 SKU 冲突 |
**不做**:库存、把现有酒祖 10/15/20 合并为一个 SPU。
### 2.3 规格主图
## 兼容规则(线上)
| # | 项 | 说明 |
|---|----|------|
| 11 | DB | `common_product_sku.image_url``migrate-sku-image.sql` |
| 12 | Admin | 弹窗可为每 SKU 上传主图 |
| 13 | C 端 | 选规格优先 SKU 主图,空则回落商品封面 |
- 不改 `/api/v1` 前缀;**只增字段,不删旧字段语义**。
### 2.4 发票(同批次)
| # | 项 | 说明 |
|---|----|------|
| 14 | 品类 | `user_invoice.invoice_category``LIQUOR` 酒水类 / `CATERING` 餐饮类 |
| 15 | C 端申请 | 票种写死「增值税普通发票」;类型选酒水/餐饮;备注写入申请 |
| 16 | 抬头 | 必填项打 `*`;强调邮箱必填 |
| 17 | Admin | 发票列表展示品类;专票仍可走后台 |
### 2.5 文案与 UI(同批次)
| # | 位置 | 变更 |
|---|------|------|
| 18 | 全局权益文案 | 「好客权益券」→「好客权益」 |
| 19 | 首页角标 | 「享{amount}好客权益」,去掉门店 icon |
| 20 | 商品详情 | 规格区与「好客权益」说明加大间距 |
| 21 | 待支付/收银台 | 顶部 logo 用 `logo2.png`(杜康印章) |
| 22 | 门店详情 | 「使用规则」红色,置于「门店详情」上方;详情正文限高可滚动 |
| 23 | 客户端版本号 | `package.json` + `client-version.ts`**3.5.4**(「我的」页展示) |
---
## 3. 兼容规则(线上)
- 不改 `/api/v1`**只增字段,不删旧字段语义**。
- 旧客户端不传 `skuId`
- ≥1 个可售 SKU → 默认(或第一个)可售 SKU
- **没有任何可售 SKU(未回填)→ 回落 SPU 字段,照常下单**(禁止再报「商品暂无可售规格」)
- `skuId`(新客户端选规格)→ 按该 SKU 校验。
- 旧 admin `PUT /admin/products/:id` 不传规格:仅同步**唯一**默认 SKU(多规格时不同步,防误改);不同步覆盖已生成的 DK 码。
- SPU 上 `sku_code` / `barcode_69` 去掉唯一约束,唯一下沉到 `common_product_sku`SPU 列保留为默认 SKU 冗余。
- 订单 `sku_id` 可空;无规格快照走商品 69 码 / 价格。
- ≥1 个可售 SKU → 默认(或第一个)可售 SKU
- **0 个可售 SKU → 回落 SPU,照常下单**
- 新客户端`skuId` → 按该 SKU 校验。
- 旧 admin 不传规格:仅同步**唯一**默认 SKU;不覆盖已生成的 DK 码。
- SPU 上 `sku_code` / `barcode_69` 唯一约束下沉到 SKUSPU 列保留冗余。
## 发版一并执行
---
按顺序在**目标环境库**执行(先测试后生产)。本机 `npx ts-node …` 只改本地 `.env` 库,不会自动打线上。
## 4. 发版与生产执行记录
1. **规格表** `server/dukang-api/prisma/migrate-product-sku-v354.sql`
建 spec/sku 表,订单加 `sku_id` / `sale_unit` / `bottles_per_unit`
2. **回填默认 SKU**
`cd server/dukang-api && npx ts-node prisma/backfill-product-skus.ts`
尚无 SKU 的商品各建 1 条默认瓶装 SKU(码用 DK)。
3. **SKU 主图列** `server/dukang-api/prisma/migrate-sku-image.sql`
```sql
ALTER TABLE `common_product_sku`
ADD COLUMN `image_url` VARCHAR(512) NULL AFTER `sort_order`;
```
4. **SKU 码改 DK**(生产须在服务器用 `.env.production` 的 `DATABASE_URL`
`npx dotenv -e .env.production -- npx ts-node prisma/rewrite-sku-codes-dk.ts`
已是 `DK`+数字的不动;`JZ-10` / `QX-001` 等会改。**不改 69 码、订单、价格。**
5. **发票品类列**(同批次)`server/dukang-api/prisma/migrate-invoice-category.sql`
```sql
ALTER TABLE `user_invoice`
ADD COLUMN `invoice_category` VARCHAR(16) NOT NULL DEFAULT 'LIQUOR' AFTER `invoice_kind`;
```
6. 发布 API + mini-user + admin-web。
**此时不要给商品加第二规格**,等新小程序上线后再配「单瓶 / 整箱」。
按序在目标库执行(先测后产)。本机脚本只打本地 `.env`
## 起购与物流
| 步骤 | 动作 | 生产状态(2026-08-21 |
|------|------|------------------------|
| 1 | `migrate-product-sku-v354.sql` / Prisma sync | ✅ `db push` 已对齐 |
| 2 | `backfill-product-skus.ts` | ✅ 回填 9 个默认 SKU(扫 10 商品) |
| 3 | `migrate-sku-image.sql` / schema `image_url` | ✅ |
| 4 | `rewrite-sku-codes-dk.ts` | ✅ 13 条均已 DK,改写 0 |
| 5 | `migrate-invoice-category.sql` | ✅ schema 已含 |
| 6 | 发 API + mini-user H5 + admin | ✅ `mini-user 200` / `api 200` |
| 7 | 微信小程序 weapp 上传 | ⚠️ 需单独上传后「我的」页才见 v3.5.4 |
运营注意:新包上线前**不要**给商品加第二规格;上线后再配「单瓶 / 整箱」。
---
## 5. 起购与物流
- `bottleQty = quantity × bottlesPerUnit`
- 城市起购阈值仍是瓶;箱装 SKU`bottlesPerUnit=6`)数量 1 即可过同城 2 / 跨城 6
- 大单拦截、承运商 `goodsNum` 使用瓶当量
- 城市起购仍按瓶;箱装(`bottlesPerUnit=6`)数量 1 即可过同城 2 / 跨城 6
- 大单拦截、承运商 `goodsNum` 用瓶当量
## 关键表摘要
---
## 6. 关键表 / 字段摘要
- `common_product_spec_attr` / `common_product_spec_value`
- `common_product_sku``sale_unit`=`BOTTLE|BOX``bottles_per_unit``image_url` 可选
- `common_product_sku``sale_unit``bottles_per_unit``image_url`
- `common_product_sku_spec`
- `user_order.sku_id` / `sale_unit` / `bottles_per_unit`
- `user_invoice.invoice_category``LIQUOR` 酒水类 / `CATERING` 餐饮类;票种 C 端固定增值税普通发票
- `user_invoice.invoice_category`
## SKU 码与 69 码
---
- SKU 码:服务端生成 `DK000001` 起,后台只展示。
- 每个规格必须填写**互不相同**的 69 码(全局不可与其它商品 SKU 冲突)。
- 总部「规格与 SKU」点「填写」弹窗编辑 69 码 / 价 / 履约 / 主图。
## 7. 关键路径(便于排查)
## 权益与小程序 UI(同批次)
| 域 | 路径 |
|----|------|
| Prisma / 脚本 | `server/dukang-api/prisma/migrate-product-sku-v354.sql``backfill-product-skus.ts``rewrite-sku-codes-dk.ts``migrate-sku-image.sql``migrate-invoice-category.sql` |
| 规格工具 | `server/.../catalog/product-sku.util.ts` |
| Admin 规格 | `apps/admin-web/src/components/ProductSpecsEditor.tsx` |
| C 端详情 | `apps/mini-user/src/pages/product-detail/` |
| 版本号 | `apps/mini-user/src/lib/client-version.ts` |
| 门店详情 | `apps/mini-user/src/pages/store-detail/` |
| 发票 | `apps/mini-user/src/pages/invoice-apply/``invoice-titles/` |
| 位置 | 变更 |
|------|------|
| 门店详情等 | 「好客权益券」→「好客权益」 |
| 首页商品角标 `CouponBadge` | 纯文案 **「享{amount}好客权益」**,无门店 icon |
| 商品详情 | 规格区与「好客权益」说明之间加大间距 |
| 待支付 / 收银台 | 顶部 logo 使用 `public/images/logo2.png`(杜康印章) |
| 门店详情 | 「使用规则」四字红色,放在「门店详情」**上面**;门店详情正文限高,超出上下滚动 |
| 发票申请 | 票种写死增值税普通发票;类型选酒水类/餐饮类;申请备注;抬头邮箱必填打 `*` |
---
其它页 `BenefitFigure`(我的/权益/核销等)仍保留门店核销图标,仅首页角标去 icon。
## 8. 验收清单
## 验收
- [ ] 未配规格:旧小程序/H5/代下单路径与现网一致(无 SKU 也能下单)
- [ ] 多规格:详情选规格后价格/权益/履约/主图变化
- [ ] 整箱 SKU:数量 1 过起购;订单快照 `bottles_per_unit=6`
- [ ] `GET /catalog/products/:id` 仍含 `id/name/price/spec/skuCode/...`
- [ ] 小程序无「好客权益券」字样;首页角标为「享{金额}好客权益」且无门店 icon
- [ ] 后台 SKU 码为 DK 开头且不可手填;每规格独立 69 码与主图
- [ ] 门店详情「使用规则」红色且在门店详情上方;门店详情超长可滚动
- [ ] 待支付页顶部为 logo2 印章
- [ ] 未配规格:旧端下单与现网一致(无 SKU 也能下)
- [ ] 多规格:选规格后价格/权益/履约/主图变化;漏选 400
- [ ] 整箱:数量 1 过起购;订单 `bottles_per_unit=6`
- [ ] 详情 API 仍含 `id/name/price/spec/skuCode/...`
- [ ] 后台 SKU 码 DK 开头不可手填;每规格独立 69 码与主图
- [ ] 无「好客权益券」;首页角标「享{金额}好客权益」无门店 icon
- [ ] 门店详情「使用规则」红色且在详情上方;详情超长可滚
- [ ] 待支付页为 logo2 印章
- [ ] 发票:普票固定 + 酒水/餐饮品类 + 邮箱必填
- [ ] 「我的」页版本 **杜康好客 v3.5.4**(需 weapp 新包)