3bc856fc95
- image.ts 中 getCompressedImageUrl 增加缓存,避免列表重渲染时重复计算压缩 URL - shopGoods 页面用原生 img 标签替换 antdv a-image,支持浏览器懒加载减少首屏网络压力 - shopGoods 页面数据加载流程优化,取消表格自动首屏加载,改为手动触发,合并请求避免重复调用 - 首屏分类数据延迟加载,不阻塞首屏渲染,提升页面响应速度 - search.vue 中用 onMounted 替代 watch immediate,防止首次入场重复触发请求 - 新增商品封面图样式,保证图片大小固定且样式统一
130 lines
7.3 KiB
Markdown
130 lines
7.3 KiB
Markdown
# 运费模板「不发货地区(排除地区)」接口方案
|
||
|
||
> 目标:支持商家配置"除部分偏远地区外,全国均可配送"的场景,避免逐个添加可配送省份。
|
||
> 前端代码库:guilixu-admin(shop 模块接口走 MODULES_API_URL,即 mp-java 的 shop 模块)
|
||
|
||
---
|
||
|
||
## 一、现状(改造前)
|
||
|
||
- 一条 `shop_express_template_detail` = 一种配送区域 + 一套运费规则。
|
||
- 当前**只能选 1 个省市组合**,字段为 `province_id` + `city_id`(单值)。
|
||
- 不选 = 默认全国。
|
||
- **无任何排除/不发货逻辑**。
|
||
|
||
## 二、需求(改造后)
|
||
|
||
配送区域支持两种模式:
|
||
|
||
| 模式 | 含义 | 典型场景 |
|
||
|------|------|----------|
|
||
| 白名单(指定配送) | 只发列表中的地区 | 仅发江浙沪 |
|
||
| 黑名单(指定不发货) | 发列表外的所有地区 | 除新疆/西藏/港澳台外全国发 |
|
||
|
||
新增「不发货地区」配置:商家框选不发货的省/市,保存后这些地区下单时报"暂不配送"。
|
||
|
||
## 三、数据库变更
|
||
|
||
`shop_express_template_detail` 表新增两个字段(存储方案选型见下方说明):
|
||
|
||
> **存储方案选型:推荐逗号分隔单字段,不新建关联表。**
|
||
> 理由:① 本业务查询模式是「模板→明细」,非「地区→模板」,无需按地区反查;② 排除地区通常仅几个省,VARCHAR(2000) 足够;③ 改动最小、前端直接透传编码字符串、可快速上线满足客户急迫配置需求。若未来需「按地区统计运费模板」等报表,再迁关联表。
|
||
|
||
```sql
|
||
ALTER TABLE shop_express_template_detail
|
||
ADD COLUMN region_mode TINYINT NOT NULL DEFAULT 0 COMMENT '配送区域模式: 0=全国, 1=指定配送(白名单), 2=指定不发货(黑名单)',
|
||
ADD COLUMN region_ids VARCHAR(2000) DEFAULT NULL COMMENT '地区编码列表(与regions-data.json一致),逗号分隔,如 110000,120000。region_mode=1或2时有效';
|
||
```
|
||
|
||
- `region_mode=0`(全国):`region_ids` 为空,兼容旧"不选=全国"行为。
|
||
- `region_mode=1/2`:`region_ids` 存选中的地区编码(省/市/区 6 位编码,与前端 `regions-data.json` 的 `value` 一致)。
|
||
|
||
### 旧数据兼容
|
||
|
||
历史数据 `province_id` / `city_id` 保留不删。迁移建议:
|
||
- 旧数据 `region_mode` 默认置 `1`,`region_ids` = `province_id[,city_id]`(有 city 才拼)。
|
||
- 前端编辑时若检测到旧字段(无 `region_mode`),按 `province_id/city_id` 回显到白名单模式。
|
||
|
||
## 四、region_ids 存储与匹配规则
|
||
|
||
- 存**最小选中粒度**编码:用户选到省只存省码,选到市存市码(省码可推导,不必冗余存)。
|
||
- 编码前缀关系:区码 `110101` ⊃ 市码 `110100` ⊃ 省码 `110000`。
|
||
- 匹配算法(下单时使用):
|
||
- 收货地址解析出 省码 / 市码 / 区码。
|
||
- 命中判断:`region_ids` 中包含收货地的 省码 **或** 市码 **或** 区码 即视为命中该条明细。
|
||
- 推荐:前端提交时统一存**省+市两级**(不存区),简化逻辑;如需区县级排除再加。
|
||
|
||
## 五、下单配送校验逻辑(后端 + 小程序端双重校验)
|
||
|
||
```
|
||
收货地址 → 解析 {provinceCode, cityCode, districtCode}
|
||
|
||
1. 查该商品运费模板下所有 detail 明细
|
||
2. 遍历所有 region_mode=2(黑名单) 明细:
|
||
若 收货地省/市/区码 任一 ∈ 该明细.region_ids
|
||
→ 直接判定【不配送】,返回 "该地区暂不配送"
|
||
3. 若无黑名单命中,按现有逻辑选运费明细:
|
||
- region_mode=0(全国) 明细 → 匹配
|
||
- region_mode=1(白名单) 明细 → 收货地码 ∈ region_ids 才匹配
|
||
4. 无任何明细匹配 → 不配送(或走默认模板,按业务定)
|
||
```
|
||
|
||
> 优先级:**黑名单排除 > 白名单/全国匹配**。即一旦落入不发货列表,直接不可下单。
|
||
|
||
## 六、接口变更
|
||
|
||
涉及接口(mp-java `ShopExpressTemplateDetailController`):
|
||
|
||
| 接口 | METHOD & PATH | 变更 |
|
||
|------|---------------|------|
|
||
| 新增明细 | POST `/shop/shop-express-template-detail` | 入参加 `regionMode`、`regionIds` |
|
||
| 修改明细 | PUT `/shop/shop-express-template-detail` | 入参加 `regionMode`、`regionIds` |
|
||
| 明细详情 | GET `/shop/shop-express-template-detail/{id}` | 出参加 `regionMode`、`regionIds` |
|
||
| 明细列表 | GET `/shop/shop-express-template-detail/page` | 出参加 `regionMode`、`regionIds` |
|
||
|
||
入参示例(新增):
|
||
```json
|
||
{
|
||
"templateId": 12,
|
||
"type": true,
|
||
"regionMode": 2,
|
||
"regionIds": "650000,540000,810000,820000,710000",
|
||
"firstNum": "1",
|
||
"firstAmount": "0",
|
||
"extraNum": "1",
|
||
"extraAmount": "0",
|
||
"status": 0,
|
||
"sortNumber": 100
|
||
}
|
||
```
|
||
|
||
## 七、需后端确认的问题 —— 已确认(2026-08-06 后端已实现)
|
||
|
||
> 落地仓库:**guilixu-java**(不是 mp-java;两边 shop 模块原本字节一致,本次只改 guilixu-java)。
|
||
|
||
| # | 问题 | 结论 |
|
||
|---|------|------|
|
||
| 1 | 编码 vs 名称 | **存编码**。6 位行政区划码,与 `regions-data.json` 的 `value` 一致。 |
|
||
| 2 | 粒度 | **省/市/区三级都支持**。前端建议只提交省+市两级;后端匹配时省/市/区任一命中即算命中。 |
|
||
| 3 | 黑白名单优先级 | **确认:黑名单命中即不可下单**,优先级高于白名单/全国。允许同一模板下多种模式共存。 |
|
||
| 4 | 旧数据迁移 | **由后端 SQL 一次性迁移**,见 `sql/shop_express_template_detail_region.sql`。经核查现网 `province_id/city_id` 存的就是 6 位区划码(如 150000/150200),可直接拼接,无需映射表。 |
|
||
| 5 | 下单校验落点 | **后端统一做**,已接入 `OrderBusinessService.createOrder()` 第 3.2 步,防绕过。小程序端可另做前置提示。 |
|
||
| 6 | 多模板 | **按租户维度跨模板取并集**。因 `shop_goods` 目前未与运费模板建立关联字段,按"本店除偏远地区外全国发货"的语义处理;后续商品绑定模板后可加 `templateId` 过滤。 |
|
||
|
||
### 后端实现要点(前端需知)
|
||
|
||
- **新增字段**:`regionMode`(Integer) + `regionIds`(String),已贯通 page / list / get / save / update 全部接口,直接传即可。
|
||
- **`regionIds` 格式**:逗号分隔的 6 位编码字符串,如 `"650000,540000,810000,820000,710000"`。
|
||
- **`regionMode` 取值**:`0`=全国、`1`=指定配送(白名单)、`2`=指定不发货(黑名单)。**默认 0**。
|
||
- **列表筛选**:`regionMode` 支持精确筛选;`regionIds` 支持模糊包含筛选。
|
||
- **旧数据回显**:迁移 SQL 已把历史行刷成 `regionMode=1` + `regionIds`,前端**无需**再兼容 `province_id/city_id` 回显逻辑。
|
||
- **地址名称→编码**:后端 `RegionCodeResolver` 负责把 `shop_user_address` 里的省/市/区**名称**翻译成编码(该表只存名称不存编码)。已处理 `新疆维吾尔自治区`↔`新疆`、`北京市`↔`北京` 等后缀归一化。
|
||
- **拦截文案**:命中时后端抛 `BusinessException`,接口返回形如 `"新疆维吾尔自治区暂不配送,请更换收货地址"`,前端直接展示 message 即可。
|
||
- **放行兜底**:地址解析不出行政区划编码时(境外地址等)**放行不拦截**,避免误伤。
|
||
|
||
> ⚠️ 上线顺序:必须**先执行** `sql/shop_express_template_detail_region.sql`,再发布后端,否则查询会报未知列。
|
||
|
||
---
|
||
|
||
*前端侧对应改造:新建 `RegionsTransfer` 双栏选择组件 + 改造 `shopExpressTemplateDetailEdit.vue` 增加模式切换 + 列表回显。*
|