|
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+# 店铺商品列表 — 技术方案
|
|
|
2
|
+
|
|
|
3
|
+> **依据:** 《商品列表功能需求.md》v1.0
|
|
|
4
|
+> **关联:** 《关联需求分析.md》v1.5;平台《商品审核技术方案》v1.0、《商品分类技术方案》v1.2、《商品服务管理技术方案》v1.0.1;商家《店铺商品分类技术方案》(`biz_goods_category` 本店二级)
|
|
|
5
|
+> **范围:** 商家端 **当前店铺** 商品列表、检索、发品、编辑、提交上架、下架、删除;**复用** 平台商品主表与状态机,**不另建** 商家商品表。
|
|
|
6
|
+> **原则:** `goods_status` 仅经 submit / audit / offShelf 变更(P17);`X-Shop-Id` 店铺上下文;批量含非法状态 **整批失败**。
|
|
|
7
|
+
|
|
|
8
|
+---
|
|
|
9
|
+
|
|
|
10
|
+## 1. 技术架构
|
|
|
11
|
+
|
|
|
12
|
+| 项 | 选型 |
|
|
|
13
|
+|----|------|
|
|
|
14
|
+| 基础框架 | RuoYi **v3.9.2**(`springboot2` 分支) |
|
|
|
15
|
+| 数据库 | **MySQL 5.7.39** |
|
|
|
16
|
+| ORM / 权限 | MyBatis;`@PreAuthorize`;`AjaxResult` / `TableDataInfo` |
|
|
|
17
|
+| 店铺上下文 | `SellerShopContextInterceptor` + 请求头 **`X-Shop-Id`**;会话内记住所选店铺(Redis token) |
|
|
|
18
|
+| 编号 | Redis 自增 `agri:goods:sn:{yyyyMMdd}` |
|
|
|
19
|
+| 日志 | 增删改、提交上架、下架 `@Log` |
|
|
|
20
|
+
|
|
|
21
|
+### 1.1 与平台侧边界
|
|
|
22
|
+
|
|
|
23
|
+| 维度 | 平台 · 商品审核/管理 | 本模块 · 商家商品列表 |
|
|
|
24
|
+|------|----------------------|----------------------|
|
|
|
25
|
+| 表 | **`biz_goods` 同源** | 同表,`shop_id` 限定当前店 |
|
|
|
26
|
+| 状态机 | `IGoodsService.auditGoods` / `offShelfPlatform` | `submitGoods` / `offShelfSeller` |
|
|
|
27
|
+| 列表范围 | `goods_status <> '0'` | **含未上架(0)** 五态全展示 |
|
|
|
28
|
+| 路径 | `/agri/goods` | **`/agri/seller/goods`** |
|
|
|
29
|
+| 权限前缀 | `agri:goods:*` | **`agri:seller:goods:*`** |
|
|
|
30
|
+
|
|
|
31
|
+> **定稿:** 商家端与平台 **同一套** `IGoodsService` 实现,避免双轨状态逻辑(对齐《商品审核技术方案》§1)。
|
|
|
32
|
+
|
|
|
33
|
+### 1.2 业务链
|
|
|
34
|
+
|
|
|
35
|
+```text
|
|
|
36
|
+GET /agri/seller/context → 前端缓存 shopId(X-Shop-Id)
|
|
|
37
|
+ ↓
|
|
|
38
|
+biz_shop_global_config.default_audit_pass
|
|
|
39
|
+ ↓
|
|
|
40
|
+biz_goods(shop_id = 当前店铺)
|
|
|
41
|
+ ├── 保存 POST/PUT → status=0 未上架
|
|
|
42
|
+ ├── 提交上架 PUT .../submit → status=1 或 2
|
|
|
43
|
+ ├── 平台 audit(/agri/goods/audit)→ 1→2|3
|
|
|
44
|
+ └── 下架 PUT .../offShelf → 2→4
|
|
|
45
|
+ ↓
|
|
|
46
|
+biz_goods_service_snapshot(保存商品时写快照)
|
|
|
47
|
+ ↓
|
|
|
48
|
+biz_goods_category
|
|
|
49
|
+ ├── category_id → shop_id IS NULL 的二级(平台「商品分类」)
|
|
|
50
|
+ └── shop_category_id → shop_id = 当前店 的二级(「店铺商品分类」)
|
|
|
51
|
+```
|
|
|
52
|
+
|
|
|
53
|
+| 关联模块 | 协作 |
|
|
|
54
|
+|----------|------|
|
|
|
55
|
+| **商品审核** | 商家 submit 后进入平台待审队列;驳回原因商家详情可读 |
|
|
|
56
|
+| **商品分类** | `category_id` ← `ICategoryFacade.listPlatformLevel2Options()` |
|
|
|
57
|
+| **店铺商品分类** | `shop_category_id` ← `IShopGoodsCategoryFacade.listOptionsByShopId()` |
|
|
|
58
|
+| **商品服务** | 发品多选 ← `IGoodsServiceFacade`;保存写快照 |
|
|
|
59
|
+| **店铺设置** | `IShopGlobalConfigFacade.getDefaultAuditPass()` 决定 submit 目标态 |
|
|
|
60
|
+| **订单管理** | 下架前校验 **O10 未完成订单**(待实现,`IOrderFacade`) |
|
|
|
61
|
+| **店铺管理** | `IGoodsFacade.hasBlockingGoodsForShopDelete` 删店前置 |
|
|
|
62
|
+
|
|
|
63
|
+### 1.3 模块落位
|
|
|
64
|
+
|
|
|
65
|
+```text
|
|
|
66
|
+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/GoodsSubmitBatchDTO.java # 待实现 · 批量提交
|
|
|
75
|
+├── dto/GoodsOffShelfDTO.java # 复用 · 批量下架
|
|
|
76
|
+├── dto/GoodsDeleteDTO.java # 待实现 · 批量删除
|
|
|
77
|
+├── mapper/BizGoodsMapper.java
|
|
|
78
|
+├── support/GoodsSnGenerator.java
|
|
|
79
|
+├── support/GoodsStatusUtils.java
|
|
|
80
|
+├── facade/IGoodsFacade.java # 删店/分类删校验
|
|
|
81
|
+└── constant/GoodsConstants.java
|
|
|
82
|
+
|
|
|
83
|
+resources/mapper/goods/BizGoodsMapper.xml
|
|
|
84
|
+sql/biz_goods.sql
|
|
|
85
|
+sql/biz_goods_service_snapshot.sql
|
|
|
86
|
+sql/biz_goods_shop_category_id.sql # shop_category_id 增量 DDL
|
|
|
87
|
+sql/agri_seller_goods_menu.sql # 商家菜单
|
|
|
88
|
+```
|
|
|
89
|
+
|
|
|
90
|
+**店铺上下文(已有):** `com.ruoyi.web.modules.store` → `SellerShopContextController`(`/agri/seller/context`)。
|
|
|
91
|
+
|
|
|
92
|
+---
|
|
|
93
|
+
|
|
|
94
|
+## 2. 数据库设计
|
|
|
95
|
+
|
|
|
96
|
+### 2.1 表复用与分工
|
|
|
97
|
+
|
|
|
98
|
+| 表名 | 本模块用途 |
|
|
|
99
|
+|------|------------|
|
|
|
100
|
+| **`biz_goods`** | 商品主表;商家 CRUD + 状态字段 |
|
|
|
101
|
+| **`biz_goods_service_snapshot`** | 发品勾选服务的 **展示快照** |
|
|
|
102
|
+| `biz_goods_category` | join 分类路径;**不** 由本模块维护 |
|
|
|
103
|
+| `biz_shop` | 店铺上下文、删店 join |
|
|
|
104
|
+| `biz_shop_global_config` | 全局默认审核开关 |
|
|
|
105
|
+
|
|
|
106
|
+**无商家独立商品表。**
|
|
|
107
|
+
|
|
|
108
|
+### 2.2 `biz_goods` 字段(本模块相关)
|
|
|
109
|
+
|
|
|
110
|
+| 字段 | 类型 | 说明 |
|
|
|
111
|
+|------|------|------|
|
|
|
112
|
+| goods_id | bigint PK | |
|
|
|
113
|
+| shop_id | bigint NOT NULL | **创建时写入当前店铺**;不可 UPDATE 换店 |
|
|
|
114
|
+| category_id | bigint NOT NULL | **平台二级分类**(`biz_goods_category`,`shop_id IS NULL`) |
|
|
|
115
|
+| shop_category_id | bigint NULL | **店铺商品分类**(`biz_goods_category` 本店二级);可空 |
|
|
|
116
|
+| goods_sn | varchar(32) UK | Redis 生成,全平台唯一 |
|
|
|
117
|
+| goods_name | varchar(200) | |
|
|
|
118
|
+| main_pic | varchar(512) | 主图 URL |
|
|
|
119
|
+| detail_content | text | 详情(首期 JSON/HTML 字符串) |
|
|
|
120
|
+| sale_price | decimal(10,2) | **首期单规格** 售价 |
|
|
|
121
|
+| stock | int | **首期单规格** 库存 |
|
|
|
122
|
+| sales_count | int DEFAULT 0 | 销量(订单模块回写,本模块只读) |
|
|
|
123
|
+| goods_status | char(1) | **0** 未上架 **1** 待审核 **2** 出售中 **3** 审核失败 **4** 已下架 |
|
|
|
124
|
+| reject_reason | varchar(500) | 平台驳回原因 |
|
|
|
125
|
+| submit_time | datetime | 首次 submit 时间 |
|
|
|
126
|
+| audit_time | datetime | 审核时间 |
|
|
|
127
|
+| off_shelf_time | datetime | 下架时间 |
|
|
|
128
|
+| del_flag | char(1) | 0 存在 2 逻辑删除 |
|
|
|
129
|
+| create_by / create_time / update_by / update_time | | 审计 |
|
|
|
130
|
+
|
|
|
131
|
+**首期未落库、后续扩展(需求 §8 完整表单):** 多图、重量、条码、关键词、简述、多规格 SKU、运费模版、属性项等 → 见 §2.5,**不阻塞 v1.0 列表/单规格发品**。
|
|
|
132
|
+
|
|
|
133
|
+### 2.3 增量 DDL
|
|
|
134
|
+
|
|
|
135
|
+```sql
|
|
|
136
|
+-- sql/biz_goods_shop_category_id.sql
|
|
|
137
|
+ALTER TABLE `biz_goods`
|
|
|
138
|
+ ADD COLUMN `shop_category_id` bigint(20) DEFAULT NULL COMMENT '店铺商品分类ID(本店二级 biz_goods_category)' AFTER `category_id`,
|
|
|
139
|
+ ADD KEY `idx_shop_category_id` (`shop_category_id`, `del_flag`);
|
|
|
140
|
+```
|
|
|
141
|
+
|
|
|
142
|
+完整建表见 `sql/biz_goods.sql`。
|
|
|
143
|
+
|
|
|
144
|
+### 2.4 `biz_goods_service_snapshot`
|
|
|
145
|
+
|
|
|
146
|
+| 字段 | 说明 |
|
|
|
147
|
+|------|------|
|
|
|
148
|
+| goods_id | FK 逻辑 |
|
|
|
149
|
+| service_id | 来源 `biz_goods_service` |
|
|
|
150
|
+| service_name / service_intro / service_icon | **快照** |
|
|
|
151
|
+| sort_no | 展示顺序 |
|
|
|
152
|
+
|
|
|
153
|
+保存商品时 **先删后插** 该商品全部快照行。
|
|
|
154
|
+
|
|
|
155
|
+### 2.5 扩展表(非 v1.0 · 概要)
|
|
|
156
|
+
|
|
|
157
|
+| 表(规划) | 用途 |
|
|
|
158
|
+|------------|------|
|
|
|
159
|
+| `biz_goods_pic` | 多图 gallery |
|
|
|
160
|
+| `biz_goods_sku` | 多规格 SKU(市场价、库存) |
|
|
|
161
|
+| `biz_goods_freight` | 固定运费 / 运费模版 ID |
|
|
|
162
|
+| `biz_goods_attr` | 属性项/规格项键值 |
|
|
|
163
|
+
|
|
|
164
|
+v1.0 **仅** 使用主表 `sale_price`/`stock`/`main_pic`/`detail_content`。
|
|
|
165
|
+
|
|
|
166
|
+### 2.6 索引
|
|
|
167
|
+
|
|
|
168
|
+| 索引 | 字段 | 用途 |
|
|
|
169
|
+|------|------|------|
|
|
|
170
|
+| uk_goods_sn | goods_sn | 编号唯一 |
|
|
|
171
|
+| idx_shop_status | shop_id, goods_status, del_flag | 商家列表 + 状态 Tab |
|
|
|
172
|
+| idx_category_id | category_id, del_flag | 分类检索 |
|
|
|
173
|
+| idx_shop_category_id | shop_category_id, del_flag | 店铺分类删校验 |
|
|
|
174
|
+| idx_submit_time | submit_time | 待审核排序(平台侧) |
|
|
|
175
|
+
|
|
|
176
|
+### 2.7 商家列表 SQL 约定
|
|
|
177
|
+
|
|
|
178
|
+```sql
|
|
|
179
|
+WHERE g.del_flag = '0'
|
|
|
180
|
+ AND g.shop_id = #{shopId} -- 强制当前店铺(GL1)
|
|
|
181
|
+ -- 含 goods_status='0',与平台列表不同
|
|
|
182
|
+```
|
|
|
183
|
+
|
|
|
184
|
+### 2.8 字典
|
|
|
185
|
+
|
|
|
186
|
+| dict_type | 说明 |
|
|
|
187
|
+|-----------|------|
|
|
|
188
|
+| goods_status | 0~4 状态展示 |
|
|
|
189
|
+
|
|
|
190
|
+---
|
|
|
191
|
+
|
|
|
192
|
+## 3. 状态机(Service)
|
|
|
193
|
+
|
|
|
194
|
+> 与《商品审核技术方案》§3、《关联需求分析》§5.4 **同源**。
|
|
|
195
|
+
|
|
|
196
|
+| 操作 | 方法 | 执行方 | 前置 status | 结果 status |
|
|
|
197
|
+|------|------|--------|-------------|-------------|
|
|
|
198
|
+| 保存(新建) | `insertSellerGoods` | 商家 | — | **0** |
|
|
|
199
|
+| 保存(编辑) | `updateSellerGoods` | 商家 | 0/1/2/3/4 | **不变** |
|
|
|
200
|
+| 提交上架 | `submitGoods` | 商家 | 0/3/4 | **1** 或 **2**¹ |
|
|
|
201
|
+| 审核通过 | `auditGoods` | 平台 | 1 | 2 |
|
|
|
202
|
+| 审核驳回 | `auditGoods` | 平台 | 1 | 3 |
|
|
|
203
|
+| 下架 | `offShelfSeller` / `offShelfPlatform` | 商家/平台 | 2 | 4 |
|
|
|
204
|
+| 删除 | `deleteSellerGoods`² | 商家 | 0/3/4 | del_flag=2 |
|
|
|
205
|
+
|
|
|
206
|
+¹ `default_audit_pass='1'` → **2**,否则 **1**。
|
|
|
207
|
+² **待实现**;出售中/待审核 **阻断**。
|
|
|
208
|
+
|
|
|
209
|
+**禁止:** 请求体携带 `goodsStatus` 直接改态(`rejectGoodsStatusInBody`)。
|
|
|
210
|
+
|
|
|
211
|
+**批量策略:** `submit` / `offShelf` / `delete` 均 **先全量校验** → 任一失败 `GoodsBatchOperationException`,**零行** 更新。
|
|
|
212
|
+
|
|
|
213
|
+---
|
|
|
214
|
+
|
|
|
215
|
+## 4. 跨模块 Facade
|
|
|
216
|
+
|
|
|
217
|
+| 接口 | 提供方 | 本模块用法 |
|
|
|
218
|
+|------|--------|------------|
|
|
|
219
|
+| `ICategoryFacade` | 分类 | `listPlatformLevel2Options()` — 发品「商品分类」 |
|
|
|
220
|
+| `IShopGoodsCategoryFacade` | 店铺商品分类 | `listOptionsByShopId(shopId, visibleOnly)` — 「店铺商品分类」 |
|
|
|
221
|
+| `IGoodsServiceFacade` | 商品服务 | `listAllEnabled` / `listDefaultShow`;删服务前 `existsByServiceId` |
|
|
|
222
|
+| `IShopGlobalConfigFacade` | 店铺设置 | `getDefaultAuditPass()` |
|
|
|
223
|
+| `IShopFacade` | 店铺 | 删店时 `assertShopMaintable` |
|
|
|
224
|
+| `IGoodsFacade` | 商品 | `hasBlockingGoodsForShopDelete`;`existsByShopCategoryId` |
|
|
|
225
|
+| `IOrderFacade`³ | 订单 | `hasUnfinishedOrderByGoodsId(goodsId)` — 下架前置 |
|
|
|
226
|
+
|
|
|
227
|
+³ 订单模块 Facade,下架 O10 校验 **待对接**。
|
|
|
228
|
+
|
|
|
229
|
+---
|
|
|
230
|
+
|
|
|
231
|
+## 5. 接口设计
|
|
|
232
|
+
|
|
|
233
|
+**公共约定**
|
|
|
234
|
+
|
|
|
235
|
+| 项 | 说明 |
|
|
|
236
|
+|----|------|
|
|
|
237
|
+| 基路径 | `/agri/seller/goods` |
|
|
|
238
|
+| 请求头 | **`X-Shop-Id`**:当前店铺 ID(除 `/agri/seller/context` 外 `/agri/seller/**` 必传) |
|
|
|
239
|
+| 分页 | `pageNum` / `pageSize` → `TableDataInfo` |
|
|
|
240
|
+| 权限 | `@PreAuthorize("@ss.hasPermi('agri:seller:goods:…')")` |
|
|
|
241
|
+| 批量失败 | `code!=200`,`data.reasons[]` 明细 |
|
|
|
242
|
+
|
|
|
243
|
+---
|
|
|
244
|
+
|
|
|
245
|
+### 5.1 商品列表 `GET /agri/seller/goods/list`
|
|
|
246
|
+
|
|
|
247
|
+| 项 | 说明 |
|
|
|
248
|
+|----|------|
|
|
|
249
|
+| 权限 | `agri:seller:goods:list` |
|
|
|
250
|
+| 店铺 | `SellerShopContext.getShopId()`,与 header 一致 |
|
|
|
251
|
+
|
|
|
252
|
+**Query:**
|
|
|
253
|
+
|
|
|
254
|
+| 参数 | 说明 |
|
|
|
255
|
+|------|------|
|
|
|
256
|
+| goodsSn | 编号模糊 |
|
|
|
257
|
+| goodsName | 名称模糊 |
|
|
|
258
|
+| categoryId | **平台** 二级分类 ID |
|
|
|
259
|
+| goodsStatusQuery | 0/1/2/3/4;不传查全部 |
|
|
|
260
|
+| keyword | 可选;sn+name 组合模糊 |
|
|
|
261
|
+
|
|
|
262
|
+**`rows`(GoodsListVO):**
|
|
|
263
|
+
|
|
|
264
|
+| 字段 | 说明 |
|
|
|
265
|
+|------|------|
|
|
|
266
|
+| goodsId, goodsSn, goodsName, mainPic | |
|
|
|
267
|
+| salePrice, salesCount | 售价、销量 |
|
|
|
268
|
+| stock | 可选列 |
|
|
|
269
|
+| goodsStatus, goodsStatusLabel | 字典 goods_status |
|
|
|
270
|
+| categoryPath | 一级 > 二级(平台分类) |
|
|
|
271
|
+| shopCategoryName | 可选;店铺商品分类名 |
|
|
|
272
|
+
|
|
|
273
|
+**排序:** 默认 `create_time DESC`(待审核 Tab 可前端传参或扩展 `orderBy=submitTime`)。
|
|
|
274
|
+
|
|
|
275
|
+---
|
|
|
276
|
+
|
|
|
277
|
+### 5.2 商品详情 `GET /agri/seller/goods/{goodsId}`
|
|
|
278
|
+
|
|
|
279
|
+| 项 | 说明 |
|
|
|
280
|
+|----|------|
|
|
|
281
|
+| 权限 | `agri:seller:goods:query` |
|
|
|
282
|
+| 校验 | `goods_id` 须属 **当前 shop_id** |
|
|
|
283
|
+
|
|
|
284
|
+**`data`(GoodsDetailVO):**
|
|
|
285
|
+
|
|
|
286
|
+| 字段 | 说明 |
|
|
|
287
|
+|------|------|
|
|
|
288
|
+| 列表字段 | 同 §5.1 |
|
|
|
289
|
+| shopId, categoryId, shopCategoryId | |
|
|
|
290
|
+| detailContent, stock | |
|
|
|
291
|
+| rejectReason, submitTime, auditTime, offShelfTime | |
|
|
|
292
|
+| services[] | 服务快照列表 |
|
|
|
293
|
+| canSubmit, canOffShelf, canDelete, canEdit | 前端按钮态(可选) |
|
|
|
294
|
+
|
|
|
295
|
+---
|
|
|
296
|
+
|
|
|
297
|
+### 5.3 添加商品 `POST /agri/seller/goods`
|
|
|
298
|
+
|
|
|
299
|
+| 项 | 说明 |
|
|
|
300
|
+|----|------|
|
|
|
301
|
+| 权限 | `agri:seller:goods:add` |
|
|
|
302
|
+| 日志 | title=商家商品 |
|
|
|
303
|
+
|
|
|
304
|
+**Body(GoodsSaveDTO · v1.0):**
|
|
|
305
|
+
|
|
|
306
|
+```json
|
|
|
307
|
+{
|
|
|
308
|
+ "categoryId": 1002,
|
|
|
309
|
+ "shopCategoryId": 2005,
|
|
|
310
|
+ "goodsName": "复合肥 50kg",
|
|
|
311
|
+ "mainPic": "/profile/upload/2026/05/01/a.jpg",
|
|
|
312
|
+ "detailContent": "<p>详情</p>",
|
|
|
313
|
+ "salePrice": 128.00,
|
|
|
314
|
+ "stock": 500,
|
|
|
315
|
+ "serviceIds": [1, 3]
|
|
|
316
|
+}
|
|
|
317
|
+```
|
|
|
318
|
+
|
|
|
319
|
+| 校验 | 说明 |
|
|
|
320
|
+|------|------|
|
|
|
321
|
+| categoryId | 须为 **平台二级** 有效分类 |
|
|
|
322
|
+| shopCategoryId | 若传,须属 **当前店** 二级分类 |
|
|
|
323
|
+| serviceIds | 须全部存在于未删除服务目录 |
|
|
|
324
|
+| goodsStatus | **禁止** 传入 |
|
|
|
325
|
+
|
|
|
326
|
+**响应:** `{ "goodsId": 10001 }`;落库 `goods_status='0'`,生成 `goods_sn`。
|
|
|
327
|
+
|
|
|
328
|
+---
|
|
|
329
|
+
|
|
|
330
|
+### 5.4 编辑商品 `PUT /agri/seller/goods`
|
|
|
331
|
+
|
|
|
332
|
+| 项 | 说明 |
|
|
|
333
|
+|----|------|
|
|
|
334
|
+| 权限 | `agri:seller:goods:edit` |
|
|
|
335
|
+| Body | 同 §5.3 + **goodsId** 必填 |
|
|
|
336
|
+
|
|
|
337
|
+- **不修改** `goods_status`、`shop_id`、`goods_sn`。
|
|
|
338
|
+- 各状态均可编辑(P14);保存后刷新服务快照。
|
|
|
339
|
+
|
|
|
340
|
+---
|
|
|
341
|
+
|
|
|
342
|
+### 5.5 提交上架
|
|
|
343
|
+
|
|
|
344
|
+#### 5.5.1 单独 `PUT /agri/seller/goods/{goodsId}/submit`
|
|
|
345
|
+
|
|
|
346
|
+| 项 | 说明 |
|
|
|
347
|
+|----|------|
|
|
|
348
|
+| 权限 | `agri:seller:goods:edit` |
|
|
|
349
|
+| 前置 | status ∈ {0, 3, 4} |
|
|
|
350
|
+
|
|
|
351
|
+**响应 data:**
|
|
|
352
|
+
|
|
|
353
|
+```json
|
|
|
354
|
+{
|
|
|
355
|
+ "goodsId": 10001,
|
|
|
356
|
+ "goodsStatus": "1",
|
|
|
357
|
+ "goodsStatusLabel": "待审核"
|
|
|
358
|
+}
|
|
|
359
|
+```
|
|
|
360
|
+
|
|
|
361
|
+#### 5.5.2 批量 `PUT /agri/seller/goods/submit`(待实现)
|
|
|
362
|
+
|
|
|
363
|
+**Body:** `{ "goodsIds": [10001, 10002] }`
|
|
|
364
|
+规则:含非 {0,3,4} → **整批失败**。
|
|
|
365
|
+
|
|
|
366
|
+---
|
|
|
367
|
+
|
|
|
368
|
+### 5.6 下架
|
|
|
369
|
+
|
|
|
370
|
+#### 5.6.1 单独 `PUT /agri/seller/goods/{goodsId}/offShelf`
|
|
|
371
|
+
|
|
|
372
|
+| 项 | 说明 |
|
|
|
373
|
+|----|------|
|
|
|
374
|
+| 权限 | `agri:seller:goods:offshelf` |
|
|
|
375
|
+| 前置 | status=2;**无 O10 未完成订单**(待实现) |
|
|
|
376
|
+
|
|
|
377
|
+#### 5.6.2 批量 `PUT /agri/seller/goods/offShelf`
|
|
|
378
|
+
|
|
|
379
|
+| 项 | 说明 |
|
|
|
380
|
+|----|------|
|
|
|
381
|
+| 权限 | `agri:seller:goods:offshelf` |
|
|
|
382
|
+| Body | 复用 `GoodsOffShelfDTO`:`{ "goodsIds": [10001] }` |
|
|
|
383
|
+
|
|
|
384
|
+失败:`GoodsBatchOperationException` → `{ "reasons": ["仅出售中商品可下架:G20260501001"] }`。
|
|
|
385
|
+
|
|
|
386
|
+---
|
|
|
387
|
+
|
|
|
388
|
+### 5.7 删除
|
|
|
389
|
+
|
|
|
390
|
+#### 5.7.1 单独 `DELETE /agri/seller/goods/{goodsId}`(待实现)
|
|
|
391
|
+
|
|
|
392
|
+| 项 | 说明 |
|
|
|
393
|
+|----|------|
|
|
|
394
|
+| 权限 | `agri:seller:goods:remove` |
|
|
|
395
|
+| 前置 | status ∈ {0, 3, 4} |
|
|
|
396
|
+
|
|
|
397
|
+逻辑删除:`del_flag='2'`;同步删快照(可选保留历史)。
|
|
|
398
|
+
|
|
|
399
|
+#### 5.7.2 批量 `DELETE /agri/seller/goods/{goodsIds}`(待实现)
|
|
|
400
|
+
|
|
|
401
|
+路径:`goodsIds=1,2,3`;含不可删状态 → **整批失败**。
|
|
|
402
|
+
|
|
|
403
|
+---
|
|
|
404
|
+
|
|
|
405
|
+### 5.8 发品辅助下拉
|
|
|
406
|
+
|
|
|
407
|
+| 方法 | 路径 | 权限 | 说明 |
|
|
|
408
|
+|------|------|------|------|
|
|
|
409
|
+| GET | `/agri/seller/goods/categoryOptions` | `list` | 平台二级「商品分类」`ICategoryFacade.listPlatformLevel2Options()` |
|
|
|
410
|
+| GET | `/agri/seller/goods/shopCategoryOptions` | `list` | 本店二级「店铺商品分类」`IShopGoodsCategoryFacade.listOptionsByShopId(shopId, false)` **待加** |
|
|
|
411
|
+| GET | `/agri/seller/goods/serviceOptions` | `list` | `{ all: [], defaultShow: [] }` |
|
|
|
412
|
+
|
|
|
413
|
+---
|
|
|
414
|
+
|
|
|
415
|
+### 5.9 与平台接口对照
|
|
|
416
|
+
|
|
|
417
|
+| 能力 | 商家(本方案) | 平台 |
|
|
|
418
|
+|------|----------------|------|
|
|
|
419
|
+| 列表 | `GET /agri/seller/goods/list`(含 status=0) | `GET /agri/goods/list`(status≠0) |
|
|
|
420
|
+| 详情 | `GET /agri/seller/goods/{id}` | `GET /agri/goods/{id}` |
|
|
|
421
|
+| 保存 | POST/PUT `/agri/seller/goods` | — |
|
|
|
422
|
+| 提交上架 | PUT `.../submit` | — |
|
|
|
423
|
+| 审核 | — | PUT `/agri/goods/audit` |
|
|
|
424
|
+| 下架 | PUT `.../offShelf` | PUT `/agri/goods/offShelf` |
|
|
|
425
|
+| 删除 | DELETE `.../{id}` | — |
|
|
|
426
|
+
|
|
|
427
|
+---
|
|
|
428
|
+
|
|
|
429
|
+## 6. Service 核心逻辑摘要
|
|
|
430
|
+
|
|
|
431
|
+```text
|
|
|
432
|
+insertSellerGoods
|
|
|
433
|
+ → requireShopId
|
|
|
434
|
+ → validateSaveFields + assertPlatformCategoryLevel2(categoryId)
|
|
|
435
|
+ → assertShopCategoryIfPresent(shopCategoryId)
|
|
|
436
|
+ → goodsSn = GoodsSnGenerator.next()
|
|
|
437
|
+ → insert status=0
|
|
|
438
|
+ → saveServiceSnapshots
|
|
|
439
|
+
|
|
|
440
|
+submitGoods
|
|
|
441
|
+ → status in (0,3,4)
|
|
|
442
|
+ → target = defaultAuditPass ? 2 : 1
|
|
|
443
|
+ → updateSubmitStatus(首次写 submit_time)
|
|
|
444
|
+
|
|
|
445
|
+offShelfSeller
|
|
|
446
|
+ → offShelfBatch(shopId 限定)
|
|
|
447
|
+ → [待] orderFacade 校验 O10
|
|
|
448
|
+ → status 2 → 4,写 off_shelf_time
|
|
|
449
|
+
|
|
|
450
|
+deleteSellerGoods [待]
|
|
|
451
|
+ → status in (0,3,4)
|
|
|
452
|
+ → logic delete
|
|
|
453
|
+```
|
|
|
454
|
+
|
|
|
455
|
+**分类校验口径:**
|
|
|
456
|
+
|
|
|
457
|
+| 字段 | SQL 条件 |
|
|
|
458
|
+|------|----------|
|
|
|
459
|
+| category_id | `biz_goods_category.category_id`,`shop_id IS NULL`,`parent_id > 0` |
|
|
|
460
|
+| shop_category_id | `biz_goods_category.category_id`,`shop_id = #{shopId}`,`parent_id > 0` |
|
|
|
461
|
+
|
|
|
462
|
+---
|
|
|
463
|
+
|
|
|
464
|
+## 7. 权限与菜单
|
|
|
465
|
+
|
|
|
466
|
+| 权限标识 | 说明 |
|
|
|
467
|
+|----------|------|
|
|
|
468
|
+| agri:seller:goods:list | 列表、下拉 |
|
|
|
469
|
+| agri:seller:goods:query | 详情 |
|
|
|
470
|
+| agri:seller:goods:add | 新增 |
|
|
|
471
|
+| agri:seller:goods:edit | 编辑、提交上架 |
|
|
|
472
|
+| agri:seller:goods:offshelf | 下架 |
|
|
|
473
|
+| agri:seller:goods:remove | 删除 |
|
|
|
474
|
+
|
|
|
475
|
+**菜单 SQL:** `sql/agri_seller_goods_menu.sql`
|
|
|
476
|
+**组件路径:** `agri/seller/goods/index`(发品/编辑可 `goods/form`)。
|
|
|
477
|
+
|
|
|
478
|
+---
|
|
|
479
|
+
|
|
|
480
|
+## 8. 实现分期
|
|
|
481
|
+
|
|
|
482
|
+| 阶段 | 内容 | 状态 |
|
|
|
483
|
+|------|------|------|
|
|
|
484
|
+| **v1.0** | 列表/详情/单规格 CRUD/单独 submit·offShelf/服务快照/平台分类与服务下拉 | **已实现** |
|
|
|
485
|
+| **v1.0 补全** | `shop_category_id` 字段 + 店铺分类下拉 + 删除 + 批量 submit/offShelf/delete + 下架 O10 校验 | **待实现** |
|
|
|
486
|
+| **v1.x** | 多图、多规格 SKU、运费、属性模版引用、关键词检索扩展 | 规划 |
|
|
|
487
|
+
|
|
|
488
|
+---
|
|
|
489
|
+
|
|
|
490
|
+## 9. 测试要点
|
|
|
491
|
+
|
|
|
492
|
+| 编号 | 场景 |
|
|
|
493
|
+|------|------|
|
|
|
494
|
+| T1 | 未传 `X-Shop-Id` → 业务失败 |
|
|
|
495
|
+| T2 | 列表仅返回当前店商品 |
|
|
|
496
|
+| T3 | 保存 → status=0;body 带 goodsStatus → 拒收 |
|
|
|
497
|
+| T4 | submit:免审关→1,免审开→2 |
|
|
|
498
|
+| T5 | 待审核/出售中 edit 保存 → 状态不变 |
|
|
|
499
|
+| T6 | 批量 submit 含 status=2 → 整批失败 |
|
|
|
500
|
+| T7 | 下架非出售中 → 失败 |
|
|
|
501
|
+| T8 | 删除出售中 → 失败 |
|
|
|
502
|
+| T9 | 跨店 goodsId → MSG_NOT_OWNER |
|
|
|
503
|
+| T10 | 服务快照:保存后详情与目录变更隔离 |
|
|
|
504
|
+
|
|
|
505
|
+---
|
|
|
506
|
+
|
|
|
507
|
+## 10. 修订记录
|
|
|
508
|
+
|
|
|
509
|
+| 版本 | 说明 |
|
|
|
510
|
+|------|------|
|
|
|
511
|
+| **v1.0** | 首版:商家商品列表技术方案;复用 biz_goods 与平台状态机;接口/DDL 与实现对齐并标注待办 |
|
|
|
512
|
+
|
|
|
513
|
+---
|
|
|
514
|
+
|
|
|
515
|
+*文档版本:v1.0 · 关联《商品列表功能需求.md》v1.1、《商品审核技术方案.md》、《商品分类技术方案.md》v1.2、《商品服务管理技术方案.md》v1.0.1、《店铺商品分类技术方案.md》v1.1 · 技术栈 RuoYi v3.9.2-springboot2 + MySQL 5.7.39。*
|