# 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 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 ( ); } ``` --- ## 测试用例 ### 测试场景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 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 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