Files
guilixu-admin/docs/运费模板-不发货地区-接口方案.md
T
gxwebsoft 3bc856fc95 feat(shopGoods): 优化商品列表加载及封面图性能
- image.ts 中 getCompressedImageUrl 增加缓存,避免列表重渲染时重复计算压缩 URL
- shopGoods 页面用原生 img 标签替换 antdv a-image,支持浏览器懒加载减少首屏网络压力
- shopGoods 页面数据加载流程优化,取消表格自动首屏加载,改为手动触发,合并请求避免重复调用
- 首屏分类数据延迟加载,不阻塞首屏渲染,提升页面响应速度
- search.vue 中用 onMounted 替代 watch immediate,防止首次入场重复触发请求
- 新增商品封面图样式,保证图片大小固定且样式统一
2026-08-06 17:19:15 +08:00

130 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 运费模板「不发货地区(排除地区)」接口方案
> 目标:支持商家配置"除部分偏远地区外,全国均可配送"的场景,避免逐个添加可配送省份。
> 前端代码库:guilixu-adminshop 模块接口走 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` 增加模式切换 + 列表回显。*