|
|
@@ -1,7 +1,7 @@
|
|
1
|
1
|
# 店铺商品列表 — 技术方案
|
|
2
|
2
|
|
|
3
|
|
-> **依据:** 《商品列表功能需求.md》v1.2
|
|
4
|
|
-> **关联:** 《关联需求分析.md》v1.6;平台《商品审核技术方案》v1.1、《商品分类技术方案》v1.3、《商品服务管理技术方案》v1.0.1;商家《店铺商品分类技术方案》(`biz_goods_category` 本店二级)
|
|
|
3
|
+> **依据:** 《商品列表功能需求.md》v1.3
|
|
|
4
|
+> **关联:** 《关联需求分析.md》v1.6;平台《商品审核技术方案》v1.1、《商品分类技术方案》v1.3、《商品服务管理技术方案》v1.0.1;商家《店铺商品分类技术方案》v1.2、《属性模版技术方案》v1.2
|
|
5
|
5
|
> **范围:** 商家端 **当前店铺** 商品列表、检索、发品、编辑、提交上架、下架、删除;**复用** 平台商品主表与状态机,**不另建** 商家商品表。
|
|
6
|
6
|
> **原则:** `goods_status` 仅经 submit / audit / offShelf 变更(P17);`X-Shop-Id` 店铺上下文;批量含非法状态 **整批失败**。
|
|
7
|
7
|
|
|
|
@@ -56,35 +56,78 @@ biz_goods_category
|
|
56
|
56
|
| **商品分类** | `category_id` ← `IPlatformCategoryService.selectPlatformLevel2Options()` |
|
|
57
|
57
|
| **店铺商品分类** | `shop_category_id` ← `IShopGoodsCategoryFacade.listOptionsByShopId()` |
|
|
58
|
58
|
| **商品服务** | 发品多选 ← `IGoodsServiceFacade`;保存写快照 |
|
|
|
59
|
+| **属性模版** | `attr_template_id` ← 保存时 `assertAttrTemplateIfPresent`;下拉 ← `/agri/seller/attrTemplate/options` 或 `IAttrTemplateFacade` |
|
|
59
|
60
|
| **店铺设置** | `IShopGlobalConfigFacade.getDefaultAuditPass()` 决定 submit 目标态 |
|
|
60
|
61
|
| **订单管理** | 下架前校验 **O10 未完成订单**(**待实现**,`IGoodsOrderFacade` 占位) |
|
|
61
|
|
-| **店铺管理** | `IGoodsFacade.hasBlockingGoodsForShopDelete` 删店前置 |
|
|
|
62
|
+| **店铺管理** | `IGoodsShopFacade.hasBlockingGoodsForShopDelete`(`GoodsFacadeImpl`)删店前置 |
|
|
62
|
63
|
|
|
63
|
64
|
### 1.3 模块落位
|
|
64
|
65
|
|
|
|
66
|
+**本模块包:** `com.ruoyi.web.modules.goods`
|
|
|
67
|
+
|
|
65
|
68
|
```text
|
|
66
|
69
|
baqing-shop/src/main/java/com/ruoyi/web/modules/goods/
|
|
67
|
|
-├── controller/SellerGoodsController.java # /agri/seller/goods(本方案)
|
|
68
|
|
-├── controller/GoodsController.java # 平台监管(已实现)
|
|
69
|
|
-├── controller/GoodsAuditController.java # 平台审核菜单(可选薄封装)
|
|
70
|
|
-├── service/IGoodsService.java
|
|
71
|
|
-├── service/impl/GoodsServiceImpl.java
|
|
72
|
|
-├── domain/BizGoods.java
|
|
73
|
|
-├── dto/GoodsSaveDTO.java
|
|
74
|
|
-├── dto/GoodsBatchIdsDTO.java # 批量提交 / 批量删除
|
|
75
|
|
-├── dto/GoodsOffShelfDTO.java # 批量下架
|
|
76
|
|
-├── mapper/BizGoodsMapper.java
|
|
77
|
|
-├── support/GoodsSnGenerator.java
|
|
78
|
|
-├── support/GoodsStatusUtils.java
|
|
79
|
|
-├── facade/IGoodsFacade.java # 删店/分类删校验
|
|
|
70
|
+├── controller/
|
|
|
71
|
+│ ├── SellerGoodsController.java # /agri/seller/goods(本方案)
|
|
|
72
|
+│ ├── GoodsController.java # /agri/goods(平台监管)
|
|
|
73
|
+│ └── GoodsAuditController.java # /agri/goodsAudit(平台审核菜单薄封装)
|
|
|
74
|
+├── service/
|
|
|
75
|
+│ ├── IGoodsService.java
|
|
|
76
|
+│ └── impl/GoodsServiceImpl.java # 商家 + 平台共用;注入 template 模块 Mapper 校验 attrTemplateId
|
|
|
77
|
+├── domain/
|
|
|
78
|
+│ ├── BizGoods.java
|
|
|
79
|
+│ └── BizGoodsServiceSnapshot.java
|
|
|
80
|
+├── dto/
|
|
|
81
|
+│ ├── GoodsSaveDTO.java
|
|
|
82
|
+│ ├── GoodsAuditDTO.java
|
|
|
83
|
+│ ├── GoodsBatchIdsDTO.java # 批量提交 / 批量删除
|
|
|
84
|
+│ └── GoodsOffShelfDTO.java # 批量下架
|
|
|
85
|
+├── vo/
|
|
|
86
|
+│ ├── GoodsListVO.java
|
|
|
87
|
+│ ├── GoodsDetailVO.java
|
|
|
88
|
+│ ├── GoodsServiceSnapshotVO.java
|
|
|
89
|
+│ └── GoodsPurchaseVO.java # C 端/采购 Facade 用
|
|
|
90
|
+├── mapper/
|
|
|
91
|
+│ ├── BizGoodsMapper.java
|
|
|
92
|
+│ └── BizGoodsServiceSnapshotMapper.java
|
|
|
93
|
+├── facade/
|
|
|
94
|
+│ ├── IGoodsOrderFacade.java # 下架 O10(DefaultGoodsOrderFacade 占位)
|
|
|
95
|
+│ ├── IGoodsPurchaseFacade.java
|
|
|
96
|
+│ └── impl/
|
|
|
97
|
+│ ├── GoodsFacadeImpl.java # 实现 category.IGoodsFacade、store.IGoodsShopFacade
|
|
|
98
|
+│ ├── DefaultGoodsOrderFacade.java
|
|
|
99
|
+│ ├── GoodsPurchaseFacadeImpl.java
|
|
|
100
|
+│ └── GoodsSnapshotFacadeImpl.java
|
|
|
101
|
+├── support/
|
|
|
102
|
+│ ├── GoodsSnGenerator.java
|
|
|
103
|
+│ ├── GoodsStatusUtils.java
|
|
|
104
|
+│ └── GoodsBatchResponseSupport.java
|
|
|
105
|
+├── exception/GoodsBatchOperationException.java
|
|
80
|
106
|
└── constant/GoodsConstants.java
|
|
81
|
107
|
|
|
82
|
|
-resources/mapper/goods/BizGoodsMapper.xml
|
|
83
|
|
-sql/biz_goods.sql # 含 shop_category_id 字段
|
|
|
108
|
+baqing-shop/src/main/resources/mapper/goods/
|
|
|
109
|
+├── BizGoodsMapper.xml
|
|
|
110
|
+└── BizGoodsServiceSnapshotMapper.xml
|
|
|
111
|
+
|
|
|
112
|
+sql/biz_goods.sql # 含 shop_category_id、attr_template_id
|
|
84
|
113
|
sql/biz_goods_service_snapshot.sql
|
|
85
|
114
|
```
|
|
86
|
115
|
|
|
87
|
|
-**店铺上下文(已有):** `com.ruoyi.web.modules.store` → `SellerShopContextController`(`/agri/seller/context`)。
|
|
|
116
|
+**跨模块依赖(接口与实现分离):**
|
|
|
117
|
+
|
|
|
118
|
+| 能力 | 接口位置 | 实现 / 调用 |
|
|
|
119
|
+|------|----------|-------------|
|
|
|
120
|
+| 删分类/模版/店前校验 | `category/facade/IGoodsFacade.java` | `goods/facade/impl/GoodsFacadeImpl.java` |
|
|
|
121
|
+| 店铺商品分类下拉 | `category/facade/IShopGoodsCategoryFacade.java` | `category/facade/impl/ShopGoodsCategoryFacadeImpl.java` |
|
|
|
122
|
+| 平台二级分类下拉 | `category/service/IPlatformCategoryService.java` | `SellerGoodsController` 或 `SellerPlatformCategoryController` |
|
|
|
123
|
+| 分类路径 | `category/facade/ICategoryFacade.java` | `CategoryFacadeImpl` |
|
|
|
124
|
+| 属性模版校验 | `template/mapper/BizGoodsAttrTemplateMapper.java` | `GoodsServiceImpl` 直接注入 |
|
|
|
125
|
+| 属性模版下拉 | `template/facade/IAttrTemplateFacade.java` | 前端亦可调 `/agri/seller/attrTemplate/options` |
|
|
|
126
|
+| 商品服务目录 | `goodsservice/facade/IGoodsServiceFacade.java` | 发品 `serviceOptions` |
|
|
|
127
|
+| 店铺上下文 | `category/support/SellerShopContext.java` | 拦截器 `SellerShopContextInterceptor` |
|
|
|
128
|
+| 店铺上下文 API | `store/controller/SellerShopContextController.java` | `GET /agri/seller/context` |
|
|
|
129
|
+
|
|
|
130
|
+**关联模块(并列包,非本模块源码):** `modules/category`、`modules/template`、`modules/goodsservice`、`modules/store`。
|
|
88
|
131
|
|
|
89
|
132
|
---
|
|
90
|
133
|
|
|
|
@@ -110,6 +153,7 @@ sql/biz_goods_service_snapshot.sql
|
|
110
|
153
|
| shop_id | bigint NOT NULL | **创建时写入当前店铺**;不可 UPDATE 换店 |
|
|
111
|
154
|
| category_id | bigint NOT NULL | **平台二级分类**(`biz_goods_category`,`shop_id IS NULL`) |
|
|
112
|
155
|
| shop_category_id | bigint NULL | **店铺商品分类**(`biz_goods_category` 本店二级);可空 |
|
|
|
156
|
+| attr_template_id | bigint NULL | **属性模版**(`biz_goods_attr_template` 本店);可空;删模版校验 |
|
|
113
|
157
|
| goods_sn | varchar(32) UK | Redis 生成,全平台唯一 |
|
|
114
|
158
|
| goods_name | varchar(200) | |
|
|
115
|
159
|
| main_pic | varchar(512) | 主图 URL |
|
|
|
@@ -125,7 +169,7 @@ sql/biz_goods_service_snapshot.sql
|
|
125
|
169
|
| del_flag | char(1) | 0 存在 2 逻辑删除 |
|
|
126
|
170
|
| create_by / create_time / update_by / update_time | | 审计 |
|
|
127
|
171
|
|
|
128
|
|
-**首期未落库、后续扩展(需求 §8 完整表单):** 多图、重量、条码、关键词、简述、多规格 SKU、运费模版、属性项等 → 见 §2.5,**不阻塞 v1.0 列表/单规格发品**。
|
|
|
172
|
+**首期未落库、后续扩展(需求 §8 完整表单):** 多图、重量、条码、关键词、简述、多规格 SKU、运费模版、**属性/规格键值(`biz_goods_attr`)** 等 → 见 §2.5;**`attr_template_id` 引用已实现**,不阻塞 v1.0 列表/单规格发品。
|
|
129
|
173
|
|
|
130
|
174
|
### 2.3 增量 DDL
|
|
131
|
175
|
|
|
|
@@ -134,6 +178,11 @@ sql/biz_goods_service_snapshot.sql
|
|
134
|
178
|
ALTER TABLE `biz_goods`
|
|
135
|
179
|
ADD COLUMN `shop_category_id` bigint(20) DEFAULT NULL COMMENT '店铺商品分类ID(本店二级 biz_goods_category)' AFTER `category_id`,
|
|
136
|
180
|
ADD KEY `idx_shop_category_id` (`shop_category_id`, `del_flag`);
|
|
|
181
|
+
|
|
|
182
|
+-- sql/biz_goods_attr_template.sql(商品侧扩展)
|
|
|
183
|
+ALTER TABLE `biz_goods`
|
|
|
184
|
+ ADD COLUMN `attr_template_id` bigint(20) DEFAULT NULL COMMENT '属性模版ID' AFTER `shop_category_id`,
|
|
|
185
|
+ ADD KEY `idx_attr_template_id` (`attr_template_id`, `del_flag`);
|
|
137
|
186
|
```
|
|
138
|
187
|
|
|
139
|
188
|
完整建表见 `sql/biz_goods.sql`。
|
|
|
@@ -168,6 +217,7 @@ v1.0 **仅** 使用主表 `sale_price`/`stock`/`main_pic`/`detail_content`。
|
|
168
|
217
|
| idx_shop_status | shop_id, goods_status, del_flag | 商家列表 + 状态 Tab |
|
|
169
|
218
|
| idx_category_id | category_id, del_flag | 分类检索 |
|
|
170
|
219
|
| idx_shop_category_id | shop_category_id, del_flag | 店铺分类删校验 |
|
|
|
220
|
+| idx_attr_template_id | attr_template_id, del_flag | 属性模版删校验 |
|
|
171
|
221
|
| idx_submit_time | submit_time | 待审核排序(平台侧) |
|
|
172
|
222
|
|
|
173
|
223
|
### 2.7 商家列表 SQL 约定
|
|
|
@@ -215,10 +265,12 @@ WHERE g.del_flag = '0'
|
|
215
|
265
|
|------|--------|------------|
|
|
216
|
266
|
| `IPlatformCategoryService` | 分类 | `selectPlatformLevel2Options()` — 发品「商品分类」 |
|
|
217
|
267
|
| `IShopGoodsCategoryFacade` | 店铺商品分类 | `listOptionsByShopId(shopId, visibleOnly)` — 「店铺商品分类」 |
|
|
|
268
|
+| `IAttrTemplateFacade` | 属性模版 | 发品下拉 `listOptionsByShopId`;删模版时 `IGoodsFacade.existsByAttrTemplateId` |
|
|
218
|
269
|
| `IGoodsServiceFacade` | 商品服务 | `listAllEnabled` / `listDefaultShow`;删服务前 `existsByServiceId` |
|
|
219
|
270
|
| `IShopGlobalConfigFacade` | 店铺设置 | `getDefaultAuditPass()` |
|
|
220
|
271
|
| `IShopFacade` | 店铺 | 删店时 `assertShopMaintable` |
|
|
221
|
|
-| `IGoodsFacade` | 商品 | `hasBlockingGoodsForShopDelete`;`existsByShopCategoryId` |
|
|
|
272
|
+| `IGoodsFacade` | 商品 | `existsByShopCategoryId`;`existsByAttrTemplateId`(接口在 **category**,实现在 **goods**) |
|
|
|
273
|
+| `IGoodsShopFacade` | 商品 | `hasBlockingGoodsForShopDelete`(`GoodsFacadeImpl`) |
|
|
222
|
274
|
| `IOrderFacade`³ | 订单 | `hasUnfinishedOrderByGoodsId(goodsId)` — 下架前置 |
|
|
223
|
275
|
|
|
224
|
276
|
³ 订单模块 Facade,下架 O10 校验 **待对接**。
|
|
|
@@ -284,6 +336,7 @@ WHERE g.del_flag = '0'
|
|
284
|
336
|
|------|------|
|
|
285
|
337
|
| 列表字段 | 同 §5.1 |
|
|
286
|
338
|
| shopId, categoryId, shopCategoryId | |
|
|
|
339
|
+| attrTemplateId, attrTemplateName | 选用模版 ID 与名称(详情回显) |
|
|
287
|
340
|
| detailContent, stock | |
|
|
288
|
341
|
| rejectReason, submitTime, auditTime, offShelfTime | |
|
|
289
|
342
|
| services[] | 服务快照列表 |
|
|
|
@@ -304,6 +357,7 @@ WHERE g.del_flag = '0'
|
|
304
|
357
|
{
|
|
305
|
358
|
"categoryId": 1002,
|
|
306
|
359
|
"shopCategoryId": 2005,
|
|
|
360
|
+ "attrTemplateId": 4,
|
|
307
|
361
|
"goodsName": "复合肥 50kg",
|
|
308
|
362
|
"mainPic": "/profile/upload/2026/05/01/a.jpg",
|
|
309
|
363
|
"detailContent": "<p>详情</p>",
|
|
|
@@ -317,6 +371,7 @@ WHERE g.del_flag = '0'
|
|
317
|
371
|
|------|------|
|
|
318
|
372
|
| categoryId | 须为 **平台二级** 有效分类 |
|
|
319
|
373
|
| shopCategoryId | 若传,须属 **当前店** 二级分类 |
|
|
|
374
|
+| attrTemplateId | 若传,须属 **当前店** 有效属性模版 |
|
|
320
|
375
|
| serviceIds | 须全部存在于未删除服务目录 |
|
|
321
|
376
|
| goodsStatus | **禁止** 传入 |
|
|
322
|
377
|
|
|
|
@@ -404,6 +459,9 @@ WHERE g.del_flag = '0'
|
|
404
|
459
|
| GET | `/agri/seller/goods/shopCategoryOptions` | `list` | 本店二级「店铺商品分类」`IShopGoodsCategoryFacade.listOptionsByShopId(shopId, false)` |
|
|
405
|
460
|
| GET | `/agri/seller/category/platformLevel2Options` | 同上 | 与上同源(分类模块只读入口,可选) |
|
|
406
|
461
|
| GET | `/agri/seller/goods/serviceOptions` | `list` | `{ all: [], defaultShow: [] }` |
|
|
|
462
|
+| GET | `/agri/seller/attrTemplate/options` | 属性模版模块 | 本店属性模版下拉(**非** goods 子路径;见《属性模版技术方案》§3.6) |
|
|
|
463
|
+
|
|
|
464
|
+> **规划(可选挂载):** `GET /agri/seller/goods/attrTemplateOptions` 委托 `IAttrTemplateFacade`,与上同源。
|
|
407
|
465
|
|
|
408
|
466
|
---
|
|
409
|
467
|
|
|
|
@@ -428,8 +486,9 @@ insertSellerGoods
|
|
428
|
486
|
→ requireShopId
|
|
429
|
487
|
→ validateSaveFields + assertPlatformCategoryLevel2(categoryId)
|
|
430
|
488
|
→ assertShopCategoryIfPresent(shopCategoryId)
|
|
|
489
|
+ → assertAttrTemplateIfPresent(attrTemplateId)
|
|
431
|
490
|
→ goodsSn = GoodsSnGenerator.next()
|
|
432
|
|
- → insert status=0
|
|
|
491
|
+ → insert status=0(含 attr_template_id)
|
|
433
|
492
|
→ saveServiceSnapshots
|
|
434
|
493
|
|
|
435
|
494
|
submitGoods
|
|
|
@@ -454,6 +513,9 @@ deleteSellerGoodsBatch
|
|
454
|
513
|
|------|----------|
|
|
455
|
514
|
| category_id | `biz_goods_category.category_id`,`shop_id IS NULL`,`parent_id > 0` |
|
|
456
|
515
|
| shop_category_id | `biz_goods_category.category_id`,`shop_id = #{shopId}`,`parent_id > 0` |
|
|
|
516
|
+| attr_template_id | `biz_goods_attr_template.template_id`,`shop_id = #{shopId}`,`del_flag = '0'` |
|
|
|
517
|
+
|
|
|
518
|
+**错误 msg(属性模版):** 无效或非本店模版 → `请选择本店有效属性模版`(`GoodsConstants.MSG_ATTR_TEMPLATE_INVALID`)。
|
|
457
|
519
|
|
|
458
|
520
|
---
|
|
459
|
521
|
|
|
|
@@ -479,8 +541,10 @@ deleteSellerGoodsBatch
|
|
479
|
541
|
|------|------|------|
|
|
480
|
542
|
| **v1.0** | 列表/详情/单规格 CRUD/单独 submit·offShelf/服务快照/平台分类与服务下拉 | **已实现** |
|
|
481
|
543
|
| **v1.0 补全** | `shop_category_id` + 店铺分类下拉 + 删除 + 批量 submit/offShelf/delete | **已实现** |
|
|
|
544
|
+| **v1.0 补全·模版引用** | `attr_template_id` 保存/详情回显 + 本店模版校验 | **已实现** |
|
|
482
|
545
|
| **v1.0 补全·O10** | 下架前未完成订单校验(`IGoodsOrderFacade`) | **待实现** |
|
|
483
|
|
-| **v1.x** | 多图、多规格 SKU、运费、属性模版引用、关键词检索扩展 | 规划 |
|
|
|
546
|
+| **v1.x** | 多图、多规格 SKU、运费、`biz_goods_attr` 写入、关键词检索扩展 | 规划 |
|
|
|
547
|
+| **v1.x·可选** | `/agri/seller/goods/attrTemplateOptions` 挂载 | 规划 |
|
|
484
|
548
|
|
|
485
|
549
|
---
|
|
486
|
550
|
|
|
|
@@ -498,6 +562,7 @@ deleteSellerGoodsBatch
|
|
498
|
562
|
| T8 | 删除出售中 → 失败 |
|
|
499
|
563
|
| T9 | 跨店 goodsId → MSG_NOT_OWNER |
|
|
500
|
564
|
| T10 | 服务快照:保存后详情与目录变更隔离 |
|
|
|
565
|
+| T11 | attrTemplateId:本店有效模版写入;跨店/无效 ID → 失败 |
|
|
501
|
566
|
|
|
502
|
567
|
---
|
|
503
|
568
|
|
|
|
@@ -507,7 +572,9 @@ deleteSellerGoodsBatch
|
|
507
|
572
|
|------|------|
|
|
508
|
573
|
| **v1.0** | 首版:商家商品列表技术方案;复用 biz_goods 与平台状态机;接口/DDL 与实现对齐并标注待办 |
|
|
509
|
574
|
| **v1.1** | 同步代码:v1.0 补全已实现;统一平台/店铺分类口径;O10 仍标待实现 |
|
|
|
575
|
+| **v1.2** | 同步 `attr_template_id`:GoodsSaveDTO/详情/Mapper/校验;下拉走属性模版模块 `/options` |
|
|
|
576
|
+| **v1.3** | §1.3 模块落位与代码对齐:`IGoodsFacade` 跨包、`template` 依赖、快照/订单 Facade |
|
|
510
|
577
|
|
|
511
|
578
|
---
|
|
512
|
579
|
|
|
513
|
|
-*文档版本:v1.1 · 关联《商品列表功能需求.md》v1.2、《商品审核技术方案.md》v1.1、《商品分类技术方案.md》v1.3、《商品服务管理技术方案.md》v1.0.1、《店铺商品分类技术方案.md》v1.1 · 技术栈 RuoYi v3.9.2-springboot2 + MySQL 5.7.39。*
|
|
|
580
|
+*文档版本:v1.3 · 关联《商品列表功能需求.md》v1.3、《商品审核技术方案.md》v1.1、《商品分类技术方案.md》v1.3、《商品服务管理技术方案.md》v1.0.1、《店铺商品分类技术方案.md》v1.2、《属性模版技术方案.md》v1.2 · 技术栈 RuoYi v3.9.2-springboot2 + MySQL 5.7.39。*
|