|
|
@@ -0,0 +1,930 @@
|
|
|
+# Web端商户重置到刚注册状态接口文档
|
|
|
+
|
|
|
+## 模块概述
|
|
|
+
|
|
|
+本接口提供一键重置功能,可以将商户状态退回到刚注册时的初始状态,清理所有入住申请、订单、优惠券、验券、消息等相关数据。适用于测试环境或商户需要重新申请入住的场景。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 接口信息
|
|
|
+
|
|
|
+### 重置商户到刚注册状态
|
|
|
+
|
|
|
+#### 接口详情
|
|
|
+
|
|
|
+- **接口名称**: 重置商户到刚注册状态
|
|
|
+- **接口路径**: `POST /merchantUser/resetToInitialStatus`
|
|
|
+- **请求方式**: POST
|
|
|
+- **接口描述**: 一键清理入住申请、订单、优惠券、验券、消息等数据,解绑店铺,将商户退回到刚注册的初始状态
|
|
|
+- **登录验证**: ✅ 需要(通过 JWT token 自动获取用户ID)
|
|
|
+- **事务保护**: ✅ 使用 @Transactional 保证原子性
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 业务逻辑说明
|
|
|
+
|
|
|
+### 重置操作内容
|
|
|
+
|
|
|
+在商户申请入住及业务运营时,系统会进行以下数据变更:
|
|
|
+
|
|
|
+#### **入住申请相关**:
|
|
|
+1. ✅ **store_info 表** - 新增店铺记录
|
|
|
+2. ✅ **store_user 表** - 更新 storeId、name、idCard
|
|
|
+3. ✅ **store_img 表** - 新增图片记录(营业执照、合同、经营许可证)
|
|
|
+4. ✅ **tag_store_relation 表** - 新增店铺标签关系
|
|
|
+5. ✅ **life_notice 表** - 新增入住申请通知
|
|
|
+
|
|
|
+#### **业务运营相关**:
|
|
|
+6. ✅ **life_user_order 表** - 订单记录(用户购买团购券、代金券的订单)
|
|
|
+7. ✅ **order_coupon_middle 表** - 验券记录(订单-优惠券中间表)
|
|
|
+8. ✅ **life_coupon 表** - 团购券(店铺发布的团购券)
|
|
|
+9. ✅ **life_discount_coupon 表** - 代金券(店铺发布的代金券)
|
|
|
+10. ✅ **life_discount_coupon_user 表** - 用户领取的优惠券
|
|
|
+11. ✅ **life_notice 表** - 所有通知消息(订单、优惠券、系统通知等)
|
|
|
+
|
|
|
+#### **其他**:
|
|
|
+12. ⚠️ **Redis** - 地理位置信息(需手动清理)
|
|
|
+
|
|
|
+**重置接口会清理以上所有数据,恢复到刚注册状态。**
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 重置流程
|
|
|
+
|
|
|
+```
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 1. 获取当前登录用户 │
|
|
|
+│ userId = LoginUserUtil.getCurrentUserId() │
|
|
|
+│ storeUser = selectById(userId) │
|
|
|
+└─────────────────┬───────────────────────────┘
|
|
|
+ ↓
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 2. 检查是否有关联店铺 │
|
|
|
+│ IF storeId == null │
|
|
|
+│ 返回成功(无需重置) │
|
|
|
+└─────────────────┬───────────────────────────┘
|
|
|
+ ↓
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 3. 删除店铺图片 │
|
|
|
+│ DELETE FROM store_img │
|
|
|
+│ WHERE store_id = ? AND img_type IN (14,15,25)│
|
|
|
+│ - 14: 营业执照 │
|
|
|
+│ - 15: 合同图片 │
|
|
|
+│ - 25: 经营许可证 │
|
|
|
+└─────────────────┬───────────────────────────┘
|
|
|
+ ↓
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 4. 删除店铺标签关系 │
|
|
|
+│ DELETE FROM tag_store_relation │
|
|
|
+│ WHERE store_id = ? │
|
|
|
+└─────────────────┬───────────────────────────┘
|
|
|
+ ↓
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 5. 删除店铺信息 │
|
|
|
+│ DELETE FROM store_info │
|
|
|
+│ WHERE id = ? │
|
|
|
+└─────────────────┬───────────────────────────┘
|
|
|
+ ↓
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 6. 清理入住申请通知 │
|
|
|
+│ DELETE FROM life_notice │
|
|
|
+│ WHERE receiver_id = 'store_手机号' │
|
|
|
+│ AND title = '入住店铺申请' │
|
|
|
+└─────────────────┬───────────────────────────┘
|
|
|
+ ↓
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 7. 查询该店铺的所有订单ID │
|
|
|
+│ SELECT id FROM life_user_order │
|
|
|
+│ WHERE store_id = ? │
|
|
|
+└─────────────────┬───────────────────────────┘
|
|
|
+ ↓
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 8. 删除订单-优惠券中间表(验券记录) │
|
|
|
+│ DELETE FROM order_coupon_middle │
|
|
|
+│ WHERE order_id IN (订单ID列表) │
|
|
|
+└─────────────────┬───────────────────────────┘
|
|
|
+ ↓
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 9. 删除该店铺的所有订单记录 │
|
|
|
+│ DELETE FROM life_user_order │
|
|
|
+│ WHERE store_id = ? │
|
|
|
+└─────────────────┬───────────────────────────┘
|
|
|
+ ↓
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 10. 删除该店铺发布的团购券 │
|
|
|
+│ DELETE FROM life_coupon │
|
|
|
+│ WHERE store_id = ? │
|
|
|
+└─────────────────┬───────────────────────────┘
|
|
|
+ ↓
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 11. 删除该店铺发布的代金券 │
|
|
|
+│ DELETE FROM life_discount_coupon │
|
|
|
+│ WHERE store_id = ? │
|
|
|
+└─────────────────┬───────────────────────────┘
|
|
|
+ ↓
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 12. 删除用户领取的优惠券 │
|
|
|
+│ DELETE FROM life_discount_coupon_user │
|
|
|
+│ WHERE user_id = ? │
|
|
|
+└─────────────────┬───────────────────────────┘
|
|
|
+ ↓
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 13. 清理所有通知消息 │
|
|
|
+│ DELETE FROM life_notice │
|
|
|
+│ WHERE receiver_id = 'store_手机号' │
|
|
|
+└─────────────────┬───────────────────────────┘
|
|
|
+ ↓
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 14. 重置用户信息 │
|
|
|
+│ UPDATE store_user SET │
|
|
|
+│ store_id = NULL, │
|
|
|
+│ name = NULL, │
|
|
|
+│ id_card = NULL │
|
|
|
+│ WHERE id = ? │
|
|
|
+└─────────────────┬───────────────────────────┘
|
|
|
+ ↓
|
|
|
+┌─────────────────────────────────────────────┐
|
|
|
+│ 15. 返回结果 │
|
|
|
+│ 返回成功:"已退回到刚注册状态" │
|
|
|
+└─────────────────────────────────────────────┘
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 请求参数
|
|
|
+
|
|
|
+**无参数**
|
|
|
+
|
|
|
+从 JWT token 自动获取当前登录用户的 userId。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 请求示例
|
|
|
+
|
|
|
+```http
|
|
|
+POST /merchantUser/resetToInitialStatus
|
|
|
+Headers:
|
|
|
+ Authorization: Bearer YOUR_JWT_TOKEN
|
|
|
+ Content-Type: application/json
|
|
|
+```
|
|
|
+
|
|
|
+```bash
|
|
|
+curl -X POST "http://localhost:8080/merchantUser/resetToInitialStatus" \
|
|
|
+ -H "Authorization: Bearer YOUR_JWT_TOKEN" \
|
|
|
+ -H "Content-Type: application/json"
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 响应参数
|
|
|
+
|
|
|
+### 成功响应
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "code": 200,
|
|
|
+ "success": true,
|
|
|
+ "data": true,
|
|
|
+ "msg": "重置成功,已退回到刚注册状态"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 响应字段说明
|
|
|
+
|
|
|
+| 字段名 | 类型 | 说明 |
|
|
|
+|--------|------|------|
|
|
|
+| code | Integer | 状态码(200-成功) |
|
|
|
+| success | Boolean | 是否成功 |
|
|
|
+| data | Boolean | 重置结果(true-成功) |
|
|
|
+| msg | String | 提示信息 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 失败响应
|
|
|
+
|
|
|
+#### 1. 未登录或 token 无效
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "code": 500,
|
|
|
+ "success": false,
|
|
|
+ "data": null,
|
|
|
+ "msg": "请先登录"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### 2. 用户不存在
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "code": 500,
|
|
|
+ "success": false,
|
|
|
+ "data": null,
|
|
|
+ "msg": "重置失败:用户不存在"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### 3. 数据库操作失败
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "code": 500,
|
|
|
+ "success": false,
|
|
|
+ "data": null,
|
|
|
+ "msg": "重置失败:{异常信息}"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 数据库操作详情
|
|
|
+
|
|
|
+### 1. 删除店铺图片
|
|
|
+
|
|
|
+```sql
|
|
|
+DELETE FROM store_img
|
|
|
+WHERE store_id = ?
|
|
|
+ AND img_type IN (14, 15, 25)
|
|
|
+```
|
|
|
+
|
|
|
+**img_type 说明**:
|
|
|
+- `14`: 营业执照图片
|
|
|
+- `15`: 合同图片
|
|
|
+- `25`: 经营许可证图片
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 2. 删除店铺标签关系
|
|
|
+
|
|
|
+```sql
|
|
|
+DELETE FROM tag_store_relation
|
|
|
+WHERE store_id = ?
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 3. 删除店铺信息
|
|
|
+
|
|
|
+```sql
|
|
|
+DELETE FROM store_info
|
|
|
+WHERE id = ?
|
|
|
+```
|
|
|
+
|
|
|
+**影响范围**:
|
|
|
+- 店铺名称、地址、联系方式
|
|
|
+- 经营板块、经营种类
|
|
|
+- 审批状态、店铺状态
|
|
|
+- 抽成比例、经纬度等
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 4. 清理入住申请通知
|
|
|
+
|
|
|
+```sql
|
|
|
+DELETE FROM life_notice
|
|
|
+WHERE receiver_id = ?
|
|
|
+ AND title = '入住店铺申请'
|
|
|
+```
|
|
|
+
|
|
|
+**receiver_id 格式**: `store_{手机号}`
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 5. 查询店铺的所有订单ID
|
|
|
+
|
|
|
+```sql
|
|
|
+SELECT id
|
|
|
+FROM life_user_order
|
|
|
+WHERE store_id = ?
|
|
|
+```
|
|
|
+
|
|
|
+**用途**: 获取订单ID列表,用于后续删除验券记录
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 6. 删除验券记录(订单-优惠券中间表)
|
|
|
+
|
|
|
+```sql
|
|
|
+DELETE FROM order_coupon_middle
|
|
|
+WHERE order_id IN (订单ID列表)
|
|
|
+```
|
|
|
+
|
|
|
+**说明**:
|
|
|
+- 必须先查询订单ID,因为 `order_coupon_middle` 表没有 `store_id` 字段
|
|
|
+- 通过 `order_id` 关联删除
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 7. 删除订单记录
|
|
|
+
|
|
|
+```sql
|
|
|
+DELETE FROM life_user_order
|
|
|
+WHERE store_id = ?
|
|
|
+```
|
|
|
+
|
|
|
+**影响范围**:
|
|
|
+- 团购券订单
|
|
|
+- 代金券订单
|
|
|
+- 会员卡订单
|
|
|
+- 所有订单状态(待支付、已支付、已使用、已退款等)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 8. 删除团购券
|
|
|
+
|
|
|
+```sql
|
|
|
+DELETE FROM life_coupon
|
|
|
+WHERE store_id = ?
|
|
|
+```
|
|
|
+
|
|
|
+**影响范围**:
|
|
|
+- 店铺发布的所有团购券
|
|
|
+- 包括上架、下架、已售罄等所有状态
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 9. 删除代金券
|
|
|
+
|
|
|
+```sql
|
|
|
+DELETE FROM life_discount_coupon
|
|
|
+WHERE store_id = ?
|
|
|
+```
|
|
|
+
|
|
|
+**影响范围**:
|
|
|
+- 店铺发布的所有代金券
|
|
|
+- 包括所有状态的代金券
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 10. 删除用户领取的优惠券
|
|
|
+
|
|
|
+```sql
|
|
|
+DELETE FROM life_discount_coupon_user
|
|
|
+WHERE user_id = ?
|
|
|
+```
|
|
|
+
|
|
|
+**说明**: 删除商户用户本人领取的优惠券
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 11. 清理所有通知消息
|
|
|
+
|
|
|
+```sql
|
|
|
+DELETE FROM life_notice
|
|
|
+WHERE receiver_id = ?
|
|
|
+```
|
|
|
+
|
|
|
+**receiver_id 格式**: `store_{手机号}`
|
|
|
+
|
|
|
+**影响范围**:
|
|
|
+- 入住申请通知
|
|
|
+- 订单通知
|
|
|
+- 优惠券通知
|
|
|
+- 系统通知
|
|
|
+- 所有其他通知
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 12. 重置用户信息
|
|
|
+
|
|
|
+```sql
|
|
|
+UPDATE store_user
|
|
|
+SET store_id = NULL,
|
|
|
+ name = NULL,
|
|
|
+ id_card = NULL,
|
|
|
+ alipay_account = NULL
|
|
|
+WHERE id = ?
|
|
|
+```
|
|
|
+
|
|
|
+**技术实现**:
|
|
|
+```java
|
|
|
+// 使用 LambdaUpdateWrapper 显式设置为 null
|
|
|
+LambdaUpdateWrapper<StoreUser> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
+updateWrapper.eq(StoreUser::getId, userId)
|
|
|
+ .set(StoreUser::getStoreId, null)
|
|
|
+ .set(StoreUser::getName, null)
|
|
|
+ .set(StoreUser::getIdCard, null)
|
|
|
+ .set(StoreUser::getAlipayAccount, null);
|
|
|
+storeUserMapper.update(null, updateWrapper);
|
|
|
+```
|
|
|
+
|
|
|
+**为什么不能用 `updateById`?**
|
|
|
+- ❌ `updateById(entity)` 默认会忽略 null 值
|
|
|
+- ✅ 必须使用 `UpdateWrapper.set()` 显式设置为 null
|
|
|
+- ✅ 调用 `update(null, wrapper)` 来执行更新
|
|
|
+
|
|
|
+**字段说明**:
|
|
|
+- `store_id`: 解绑店铺关联
|
|
|
+- `name`: 清空联系人姓名(入住时填写)
|
|
|
+- `id_card`: 清空身份证号(入住时填写)
|
|
|
+- `alipay_account`: 清空支付宝账号(入住时填写)
|
|
|
+
|
|
|
+**保留字段**:
|
|
|
+- `phone`: 手机号(注册信息)
|
|
|
+- `head_img`: 头像
|
|
|
+- `money`: 账户余额
|
|
|
+- `pay_password`: 支付密码
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 业务场景
|
|
|
+
|
|
|
+### 场景 1: 正常重置(已申请入住)
|
|
|
+
|
|
|
+**前置条件**:
|
|
|
+- 用户已注册
|
|
|
+- 已提交入住申请
|
|
|
+- storeId 不为空
|
|
|
+
|
|
|
+**请求**:
|
|
|
+```http
|
|
|
+POST /merchantUser/resetToInitialStatus
|
|
|
+Headers:
|
|
|
+ Authorization: Bearer VALID_TOKEN
|
|
|
+```
|
|
|
+
|
|
|
+**响应**:
|
|
|
+```json
|
|
|
+{
|
|
|
+ "code": 200,
|
|
|
+ "success": true,
|
|
|
+ "data": true,
|
|
|
+ "msg": "重置成功,已退回到刚注册状态"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**数据库变化**:
|
|
|
+- ❌ 删除 store_info 记录
|
|
|
+- ❌ 删除 store_img 记录
|
|
|
+- ❌ 删除 tag_store_relation 记录
|
|
|
+- ❌ 删除 life_notice 记录(入住申请)
|
|
|
+- ❌ 删除 life_user_order 记录(所有订单)
|
|
|
+- ❌ 删除 order_coupon_middle 记录(验券记录)
|
|
|
+- ❌ 删除 life_coupon 记录(团购券)
|
|
|
+- ❌ 删除 life_discount_coupon 记录(代金券)
|
|
|
+- ❌ 删除 life_discount_coupon_user 记录(用户优惠券)
|
|
|
+- ❌ 删除所有 life_notice 记录(所有通知)
|
|
|
+- ✅ store_user.store_id = NULL
|
|
|
+- ✅ store_user.name = NULL
|
|
|
+- ✅ store_user.id_card = NULL
|
|
|
+- ✅ store_user.alipay_account = NULL
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 场景 2: 重置(未申请入住)
|
|
|
+
|
|
|
+**前置条件**:
|
|
|
+- 用户已注册
|
|
|
+- 未提交入住申请
|
|
|
+- storeId 为空
|
|
|
+
|
|
|
+**请求**:
|
|
|
+```http
|
|
|
+POST /merchantUser/resetToInitialStatus
|
|
|
+Headers:
|
|
|
+ Authorization: Bearer VALID_TOKEN
|
|
|
+```
|
|
|
+
|
|
|
+**响应**:
|
|
|
+```json
|
|
|
+{
|
|
|
+ "code": 200,
|
|
|
+ "success": true,
|
|
|
+ "data": true,
|
|
|
+ "msg": "重置成功,已退回到刚注册状态"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**说明**: 用户未关联店铺,无需清理,直接返回成功。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 场景 3: 未登录访问
|
|
|
+
|
|
|
+**请求**:
|
|
|
+```http
|
|
|
+POST /merchantUser/resetToInitialStatus
|
|
|
+```
|
|
|
+
|
|
|
+**响应**:
|
|
|
+```json
|
|
|
+{
|
|
|
+ "code": 500,
|
|
|
+ "success": false,
|
|
|
+ "data": null,
|
|
|
+ "msg": "请先登录"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 前端集成示例
|
|
|
+
|
|
|
+### Vue.js 示例
|
|
|
+
|
|
|
+```javascript
|
|
|
+export default {
|
|
|
+ methods: {
|
|
|
+ async resetToInitialStatus() {
|
|
|
+ // 1. 确认提示
|
|
|
+ const confirmed = await this.$confirm(
|
|
|
+ '此操作将删除所有入住申请数据,恢复到刚注册状态,是否继续?',
|
|
|
+ '确认重置',
|
|
|
+ {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }
|
|
|
+ ).catch(() => false);
|
|
|
+
|
|
|
+ if (!confirmed) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 发送请求
|
|
|
+ try {
|
|
|
+ const response = await this.$axios.post('/merchantUser/resetToInitialStatus');
|
|
|
+
|
|
|
+ if (response.data.success) {
|
|
|
+ this.$message.success('重置成功');
|
|
|
+ // 刷新页面或跳转
|
|
|
+ this.$router.push('/register-success');
|
|
|
+ } else {
|
|
|
+ this.$message.error(response.data.msg);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('重置失败:', error);
|
|
|
+ this.$message.error('重置失败,请稍后重试');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### React 示例
|
|
|
+
|
|
|
+```javascript
|
|
|
+import { useState } from 'react';
|
|
|
+import axios from 'axios';
|
|
|
+import { Modal } from 'antd';
|
|
|
+
|
|
|
+function ResetButton() {
|
|
|
+ const [loading, setLoading] = useState(false);
|
|
|
+
|
|
|
+ const handleReset = () => {
|
|
|
+ Modal.confirm({
|
|
|
+ title: '确认重置',
|
|
|
+ content: '此操作将删除所有入住申请数据,恢复到刚注册状态,是否继续?',
|
|
|
+ okText: '确定',
|
|
|
+ cancelText: '取消',
|
|
|
+ okType: 'danger',
|
|
|
+ onOk: async () => {
|
|
|
+ setLoading(true);
|
|
|
+ try {
|
|
|
+ const response = await axios.post('/merchantUser/resetToInitialStatus');
|
|
|
+
|
|
|
+ if (response.data.success) {
|
|
|
+ alert('重置成功');
|
|
|
+ // 刷新或跳转
|
|
|
+ window.location.href = '/register-success';
|
|
|
+ } else {
|
|
|
+ alert(response.data.msg);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('重置失败:', error);
|
|
|
+ alert('重置失败,请稍后重试');
|
|
|
+ } finally {
|
|
|
+ setLoading(false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ return (
|
|
|
+ <button onClick={handleReset} disabled={loading}>
|
|
|
+ {loading ? '重置中...' : '重置到刚注册状态'}
|
|
|
+ </button>
|
|
|
+ );
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 测试用例
|
|
|
+
|
|
|
+### 测试场景1: 正常重置
|
|
|
+
|
|
|
+**前置条件**:
|
|
|
+- 用户已登录
|
|
|
+- 已申请入住
|
|
|
+- store_id 不为空
|
|
|
+
|
|
|
+**执行步骤**:
|
|
|
+1. 提交重置请求
|
|
|
+2. 检查响应
|
|
|
+
|
|
|
+**预期结果**:
|
|
|
+- 返回成功
|
|
|
+- store_info 记录被删除
|
|
|
+- store_img 记录被删除
|
|
|
+- tag_store_relation 记录被删除
|
|
|
+- life_notice 相关记录被删除
|
|
|
+- store_user.store_id = NULL
|
|
|
+- store_user.name = NULL
|
|
|
+- store_user.id_card = NULL
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 测试场景2: 未入住用户重置
|
|
|
+
|
|
|
+**前置条件**:
|
|
|
+- 用户已登录
|
|
|
+- 未申请入住
|
|
|
+- store_id 为空
|
|
|
+
|
|
|
+**执行步骤**:
|
|
|
+1. 提交重置请求
|
|
|
+
|
|
|
+**预期结果**:
|
|
|
+- 返回成功
|
|
|
+- 无数据删除操作
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 测试场景3: 事务回滚测试
|
|
|
+
|
|
|
+**前置条件**:
|
|
|
+- 模拟数据库异常
|
|
|
+
|
|
|
+**执行步骤**:
|
|
|
+1. 提交重置请求
|
|
|
+2. 在删除过程中触发异常
|
|
|
+
|
|
|
+**预期结果**:
|
|
|
+- 返回失败
|
|
|
+- 所有数据操作回滚
|
|
|
+- 数据库状态不变
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 常见问题
|
|
|
+
|
|
|
+### Q1: 重置后哪些数据会被保留?
|
|
|
+
|
|
|
+**答案**:
|
|
|
+- ✅ **保留**: 手机号、头像、账户余额、支付密码
|
|
|
+- ❌ **清除**: 店铺关联、入住申请数据、店铺图片、订单、优惠券、验券记录、通知消息、支付宝账号
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Q2: 重置操作会影响账户余额吗?
|
|
|
+
|
|
|
+**答案**: 不会。账户余额、支付密码等财务相关信息不受影响。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Q3: 为什么 `updateById` 无法将字段设置为 null?
|
|
|
+
|
|
|
+**答案**:
|
|
|
+- ❌ MyBatis-Plus 的 `updateById(entity)` 默认会**忽略 null 值**
|
|
|
+- ✅ 必须使用 `LambdaUpdateWrapper.set(field, null)` 显式设置
|
|
|
+- ✅ 正确用法:
|
|
|
+```java
|
|
|
+LambdaUpdateWrapper<StoreUser> wrapper = new LambdaUpdateWrapper<>();
|
|
|
+wrapper.eq(StoreUser::getId, userId)
|
|
|
+ .set(StoreUser::getStoreId, null)
|
|
|
+ .set(StoreUser::getName, null);
|
|
|
+storeUserMapper.update(null, wrapper);
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Q4: 重置后可以重新申请入住吗?
|
|
|
+
|
|
|
+**答案**: 可以。重置后用户状态恢复到刚注册时,可以重新提交入住申请。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Q5: 重置操作是否支持事务回滚?
|
|
|
+
|
|
|
+**答案**: 支持。使用 `@Transactional` 注解,任何异常都会导致所有操作回滚。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Q6: Redis 中的地理位置信息会被清理吗?
|
|
|
+
|
|
|
+**答案**: 不会自动清理。如需清理 Redis 数据,需要额外调用相关清理接口。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Q7: 多次重置会有问题吗?
|
|
|
+
|
|
|
+**答案**: 不会。第一次重置后,storeId 已为空,后续重置会直接返回成功,不会执行删除操作。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Q8: 支付宝账号会被清除吗?
|
|
|
+
|
|
|
+**答案**:
|
|
|
+- ✅ **v1.2 及以上**: 会被清除(入住时可能填写的支付宝账号)
|
|
|
+- ❌ **v1.1 及以下**: 不会被清除
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 注意事项
|
|
|
+
|
|
|
+### 1. 数据不可恢复
|
|
|
+
|
|
|
+- ⚠️ **重要**: 重置操作会物理删除数据,不可恢复
|
|
|
+- ⚠️ **建议**: 仅在测试环境或确需重新申请时使用
|
|
|
+- ⚠️ **生产环境**: 谨慎使用,建议增加二次确认
|
|
|
+
|
|
|
+### 2. 事务保护
|
|
|
+
|
|
|
+- ✅ 使用 `@Transactional` 保证原子性
|
|
|
+- ✅ 任何步骤失败都会回滚
|
|
|
+- ✅ 保证数据一致性
|
|
|
+
|
|
|
+### 3. 权限控制
|
|
|
+
|
|
|
+- ⚠️ 需要登录验证
|
|
|
+- ⚠️ 只能重置自己的数据
|
|
|
+- ⚠️ 无法重置他人账户
|
|
|
+
|
|
|
+### 4. MyBatis-Plus 注意事项
|
|
|
+
|
|
|
+- ⚠️ **不能使用 `updateById` 设置 null 值**
|
|
|
+- ✅ 必须使用 `LambdaUpdateWrapper.set(field, null)`
|
|
|
+- ✅ 调用 `update(null, wrapper)` 执行更新
|
|
|
+
|
|
|
+### 5. Redis 数据
|
|
|
+
|
|
|
+- ⚠️ Redis 地理位置信息需额外清理
|
|
|
+- ⚠️ 可能需要调用其他清理接口
|
|
|
+
|
|
|
+### 6. 业务影响
|
|
|
+
|
|
|
+- ⚠️ 清理所有入住申请数据
|
|
|
+- ⚠️ 清理所有订单、优惠券、验券记录
|
|
|
+- ⚠️ 解绑店铺关联
|
|
|
+- ⚠️ 清理个人信息(姓名、身份证、支付宝账号)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 安全建议
|
|
|
+
|
|
|
+### 1. 二次确认
|
|
|
+
|
|
|
+```java
|
|
|
+// 前端实现二次确认
|
|
|
+const confirmed = await this.$confirm('确认重置?', '警告', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+### 2. 操作日志
|
|
|
+
|
|
|
+```java
|
|
|
+// 建议记录重置操作日志
|
|
|
+OperationLog log = new OperationLog();
|
|
|
+log.setUserId(userId);
|
|
|
+log.setOperation("RESET_TO_INITIAL_STATUS");
|
|
|
+log.setDetails("重置商户到刚注册状态");
|
|
|
+log.setIp(request.getRemoteAddr());
|
|
|
+operationLogMapper.insert(log);
|
|
|
+```
|
|
|
+
|
|
|
+### 3. 权限限制
|
|
|
+
|
|
|
+```java
|
|
|
+// 生产环境建议添加角色限制
|
|
|
+@PreAuthorize("hasRole('ADMIN') or hasRole('TEST_USER')")
|
|
|
+public boolean resetToInitialStatus()
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 清理范围汇总
|
|
|
+
|
|
|
+### 会被清理的数据
|
|
|
+
|
|
|
+| 表名 | 清理条件 | 说明 |
|
|
|
+|------|---------|------|
|
|
|
+| store_info | id = storeId | 店铺信息 |
|
|
|
+| store_img | store_id = storeId AND img_type IN (14,15,25) | 入住图片 |
|
|
|
+| tag_store_relation | store_id = storeId | 店铺标签 |
|
|
|
+| life_notice | receiver_id = 'store_{phone}' | 所有通知消息 |
|
|
|
+| life_user_order | store_id = storeId | 所有订单记录 |
|
|
|
+| order_coupon_middle | order_id IN (订单ID列表) | 验券记录 |
|
|
|
+| life_coupon | store_id = storeId | 团购券 |
|
|
|
+| life_discount_coupon | store_id = storeId | 代金券 |
|
|
|
+| life_discount_coupon_user | user_id = userId | 用户优惠券 |
|
|
|
+| store_user | store_id/name/id_card/alipay_account 设为NULL | 解绑并清空 |
|
|
|
+
|
|
|
+### 不会被清理的数据
|
|
|
+
|
|
|
+| 表名 | 保留字段 | 说明 |
|
|
|
+|------|---------|------|
|
|
|
+| store_user | phone | 手机号 |
|
|
|
+| store_user | head_img | 头像 |
|
|
|
+| store_user | money | 账户余额 |
|
|
|
+| store_user | pay_password | 支付密码 |
|
|
|
+| Redis | geo:stores | 地理位置(需手动清理) |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 更新日志
|
|
|
+
|
|
|
+### 2025-11-21 (v1.2)
|
|
|
+
|
|
|
+**Bug 修复**:
|
|
|
+- 🐛 修复 `updateById` 无法将字段设置为 null 的问题
|
|
|
+- ✅ 改用 `LambdaUpdateWrapper.set(field, null)` 显式设置
|
|
|
+- ✅ 正确清空 storeId、name、idCard、alipayAccount
|
|
|
+
|
|
|
+**功能优化**:
|
|
|
+- ✅ 新增清空支付宝账号(alipayAccount)
|
|
|
+- ✅ 确保所有字段都能正确设置为 null
|
|
|
+
|
|
|
+**技术说明**:
|
|
|
+```java
|
|
|
+// ❌ 错误用法(不生效)
|
|
|
+StoreUser user = new StoreUser();
|
|
|
+user.setId(userId);
|
|
|
+user.setStoreId(null);
|
|
|
+storeUserMapper.updateById(user); // null 值会被忽略
|
|
|
+
|
|
|
+// ✅ 正确用法
|
|
|
+LambdaUpdateWrapper<StoreUser> wrapper = new LambdaUpdateWrapper<>();
|
|
|
+wrapper.eq(StoreUser::getId, userId)
|
|
|
+ .set(StoreUser::getStoreId, null); // 显式设置为 null
|
|
|
+storeUserMapper.update(null, wrapper);
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 2025-11-21 (v1.1)
|
|
|
+
|
|
|
+**功能增强**:
|
|
|
+- ✅ 新增订单数据清理(life_user_order)
|
|
|
+- ✅ 新增验券记录清理(order_coupon_middle)
|
|
|
+- ✅ 新增团购券清理(life_coupon)
|
|
|
+- ✅ 新增代金券清理(life_discount_coupon)
|
|
|
+- ✅ 新增用户优惠券清理(life_discount_coupon_user)
|
|
|
+- ✅ 增强通知清理(清理所有通知,不仅限入住申请)
|
|
|
+
|
|
|
+**清理范围扩展**:
|
|
|
+- 从原来的 **5 个表** 扩展到 **10 个表**
|
|
|
+- 覆盖入住申请 + 业务运营全流程数据
|
|
|
+
|
|
|
+**技术优化**:
|
|
|
+- ✅ 先查询订单ID列表,再删除验券记录(避免直接关联删除错误)
|
|
|
+- ✅ 优化删除顺序,避免外键约束问题
|
|
|
+- ✅ 详细日志记录每个步骤的删除数量
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 2025-11-20 (v1.0)
|
|
|
+
|
|
|
+**新增接口**:
|
|
|
+- ✅ `POST /merchantUser/resetToInitialStatus` - 重置商户到刚注册状态
|
|
|
+
|
|
|
+**核心功能**:
|
|
|
+- ✅ 删除店铺信息(store_info)
|
|
|
+- ✅ 删除店铺图片(store_img: 营业执照、合同、经营许可证)
|
|
|
+- ✅ 删除店铺标签(tag_store_relation)
|
|
|
+- ✅ 清理入住通知(life_notice)
|
|
|
+- ✅ 重置用户信息(store_user: storeId、name、idCard)
|
|
|
+- ✅ 事务保护(@Transactional)
|
|
|
+- ✅ 详细日志记录
|
|
|
+- ✅ 完善异常处理
|
|
|
+
|
|
|
+**适用场景**:
|
|
|
+- ✅ 测试环境快速重置
|
|
|
+- ✅ 商户需要重新申请入住
|
|
|
+- ✅ 入住申请数据清理
|
|
|
+
|
|
|
+**涉及文件**:
|
|
|
+- `MerchantUserController.java` - 新增 `resetToInitialStatus` 接口
|
|
|
+- `MerchantUserService.java` - 新增方法定义
|
|
|
+- `MerchantUserServiceImpl.java` - 新增方法实现
|
|
|
+
|
|
|
+**代码质量**:
|
|
|
+- ✅ Linter检查:无错误
|
|
|
+- ✅ 日志记录:详细
|
|
|
+- ✅ 异常处理:完善
|
|
|
+- ✅ 代码注释:完整
|
|
|
+- ✅ 事务管理:正确
|
|
|
+
|
|
|
+**开发人员**: ssk
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+**文档版本**: v1.2
|
|
|
+**最后更新**: 2025-11-21
|
|
|
+**维护人员**: ssk
|
|
|
+
|