29-重置到刚注册状态接口.md 26 KB

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 表 - 新增入住申请通知

业务运营相关:

  1. life_user_order 表 - 订单记录(用户购买团购券、代金券的订单)
  2. order_coupon_middle 表 - 验券记录(订单-优惠券中间表)
  3. life_coupon 表 - 团购券(店铺发布的团购券)
  4. life_discount_coupon 表 - 代金券(店铺发布的代金券)
  5. life_discount_coupon_user 表 - 用户领取的优惠券
  6. life_notice 表 - 所有通知消息(订单、优惠券、系统通知等)

其他:

  1. ⚠️ 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。


请求示例

POST /merchantUser/resetToInitialStatus
Headers:
  Authorization: Bearer YOUR_JWT_TOKEN
  Content-Type: application/json
curl -X POST "http://localhost:8080/merchantUser/resetToInitialStatus" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json"

响应参数

成功响应

{
    "code": 200,
    "success": true,
    "data": true,
    "msg": "重置成功,已退回到刚注册状态"
}

响应字段说明

字段名 类型 说明
code Integer 状态码(200-成功)
success Boolean 是否成功
data Boolean 重置结果(true-成功)
msg String 提示信息

失败响应

1. 未登录或 token 无效

{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "请先登录"
}

2. 用户不存在

{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "重置失败:用户不存在"
}

3. 数据库操作失败

{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "重置失败:{异常信息}"
}

数据库操作详情

1. 删除店铺图片

DELETE FROM store_img
WHERE store_id = ?
  AND img_type IN (14, 15, 25)

img_type 说明:

  • 14: 营业执照图片
  • 15: 合同图片
  • 25: 经营许可证图片

2. 删除店铺标签关系

DELETE FROM tag_store_relation
WHERE store_id = ?

3. 删除店铺信息

DELETE FROM store_info
WHERE id = ?

影响范围:

  • 店铺名称、地址、联系方式
  • 经营板块、经营种类
  • 审批状态、店铺状态
  • 抽成比例、经纬度等

4. 清理入住申请通知

DELETE FROM life_notice
WHERE receiver_id = ?
  AND title = '入住店铺申请'

receiver_id 格式: store_{手机号}


5. 查询店铺的所有订单ID

SELECT id
FROM life_user_order
WHERE store_id = ?

用途: 获取订单ID列表,用于后续删除验券记录


6. 删除验券记录(订单-优惠券中间表)

DELETE FROM order_coupon_middle
WHERE order_id IN (订单ID列表)

说明:

  • 必须先查询订单ID,因为 order_coupon_middle 表没有 store_id 字段
  • 通过 order_id 关联删除

7. 删除订单记录

DELETE FROM life_user_order
WHERE store_id = ?

影响范围:

  • 团购券订单
  • 代金券订单
  • 会员卡订单
  • 所有订单状态(待支付、已支付、已使用、已退款等)

8. 删除团购券

DELETE FROM life_coupon
WHERE store_id = ?

影响范围:

  • 店铺发布的所有团购券
  • 包括上架、下架、已售罄等所有状态

9. 删除代金券

DELETE FROM life_discount_coupon
WHERE store_id = ?

影响范围:

  • 店铺发布的所有代金券
  • 包括所有状态的代金券

10. 删除用户领取的优惠券

DELETE FROM life_discount_coupon_user
WHERE user_id = ?

说明: 删除商户用户本人领取的优惠券


11. 清理所有通知消息

DELETE FROM life_notice
WHERE receiver_id = ?

receiver_id 格式: store_{手机号}

影响范围:

  • 入住申请通知
  • 订单通知
  • 优惠券通知
  • 系统通知
  • 所有其他通知

12. 重置用户信息

UPDATE store_user
SET store_id = NULL,
    name = NULL,
    id_card = NULL,
    alipay_account = NULL
WHERE id = ?

技术实现:

// 使用 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 不为空

请求:

POST /merchantUser/resetToInitialStatus
Headers:
  Authorization: Bearer VALID_TOKEN

响应:

{
    "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 为空

请求:

POST /merchantUser/resetToInitialStatus
Headers:
  Authorization: Bearer VALID_TOKEN

响应:

{
    "code": 200,
    "success": true,
    "data": true,
    "msg": "重置成功,已退回到刚注册状态"
}

说明: 用户未关联店铺,无需清理,直接返回成功。


场景 3: 未登录访问

请求:

POST /merchantUser/resetToInitialStatus

响应:

{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "请先登录"
}

前端集成示例

Vue.js 示例

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 示例

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) 显式设置
  • ✅ 正确用法:

    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. 二次确认

// 前端实现二次确认
const confirmed = await this.$confirm('确认重置?', '警告', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
});

2. 操作日志

// 建议记录重置操作日志
OperationLog log = new OperationLog();
log.setUserId(userId);
log.setOperation("RESET_TO_INITIAL_STATUS");
log.setDetails("重置商户到刚注册状态");
log.setIp(request.getRemoteAddr());
operationLogMapper.insert(log);

3. 权限限制

// 生产环境建议添加角色限制
@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 receiverid = '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

技术说明:

// ❌ 错误用法(不生效)
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