# 根据手机号获取商户用户信息接口文档

## 概述

本文档描述了从 `alien-store`（app端商户）迁移到 `alien-store-platform`（web端商户）的根据手机号获取商户用户信息接口。

## 接口详情

### 根据手机号获取商户用户信息

**接口描述**：根据商户手机号查询商户用户的完整信息，包括基本信息、账户状态、余额等，如果用户处于注销中状态，会返回注销倒计时。

#### 原接口
- **服务**：alien-store（app端商户）
- **路径**：`GET /alienStore/store/user/getUserByPhone?phone=15242687180`
- **Controller**：`StoreUserController.getUserByPhone()`
- **Service**：`StoreUserServiceImpl.getUserByPhone()`

#### 新接口
- **服务**：alien-store-platform（web端商户）
- **路径**：`GET /alienStorePlatform/merchantUser/getMerchantByPhone?phone=15242687180`
- **Controller**：`MerchantUserController.getMerchantByPhone()`
- **Service**：`MerchantUserServiceImpl.getMerchantByPhone()`

#### 请求参数

**Query 参数**：

| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| phone | String | 是 | 商户手机号 |

**请求示例**：

```
GET /alienStorePlatform/merchantUser/getMerchantByPhone?phone=15242687180
```

#### 响应参数

**成功响应（用户存在）**：

```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "id": 123,
    "phone": "15242687180",
    "name": "张三",
    "nickName": "店铺老板",
    "headImg": "https://example.com/avatar.jpg",
    "accountBlurb": "这是一家优质店铺",
    "storeId": 102,
    "status": 1,
    "money": 10000,
    "moneyStr": "100.00",
    "payPassword": "******",
    "idCard": "410***********1234",
    "realName": "张三",
    "logoutFlag": 0,
    "logoutTime": null,
    "logoutReason": null,
    "countdown": 0,
    "createdTime": "2024-01-01 10:00:00",
    "updatedTime": "2025-01-15 14:30:00"
  },
  "success": true
}
```

**成功响应（用户不存在）**：

```json
{
  "code": 500,
  "msg": "手机号不存在",
  "data": null,
  "success": false
}
```

**成功响应（用户注销中）**：

```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "id": 123,
    "phone": "15242687180",
    "name": "张三",
    "status": -1,
    "money": 10000,
    "moneyStr": "100.00",
    "logoutFlag": 1,
    "logoutTime": "2025-01-15 10:00:00",
    "logoutReason": "个人原因",
    "countdown": 518400000,
    "createdTime": "2024-01-01 10:00:00",
    "updatedTime": "2025-01-15 10:00:00"
  },
  "success": true
}
```

**失败响应（查询错误）**：

```json
{
  "code": 500,
  "msg": "{错误信息}",
  "data": null,
  "success": false
}
```

#### 响应字段说明

##### 基本信息字段

| 字段名 | 类型 | 说明 |
|--------|------|------|
| id | Integer | 商户用户ID |
| phone | String | 手机号 |
| name | String | 真实姓名 |
| nickName | String | 昵称 |
| headImg | String | 头像URL |
| accountBlurb | String | 账户简介 |
| storeId | Integer | 绑定的店铺ID |
| idCard | String | 身份证号 |
| realName | String | 实名 |

##### 状态相关字段

| 字段名 | 类型 | 说明 |
|--------|------|------|
| status | Integer | 账户状态（-1:注销中, 1:正常, 0:禁用）|
| logoutFlag | Integer | 注销标记（0:正常, 1:已申请注销）|
| logoutTime | DateTime | 注销申请时间 |
| logoutReason | String | 注销原因 |
| countdown | Long | 注销倒计时（毫秒），仅当status=-1时有值 |

##### 财务相关字段

| 字段名 | 类型 | 说明 |
|--------|------|------|
| money | Integer | 账户余额（单位：分）|
| moneyStr | String | 账户余额（单位：元，格式化后）|
| payPassword | String | 支付密码（脱敏）|

##### 时间相关字段

| 字段名 | 类型 | 说明 |
|--------|------|------|
| createdTime | DateTime | 创建时间 |
| updatedTime | DateTime | 更新时间 |

#### 业务逻辑

##### 1. 用户查询

```java
LambdaQueryWrapper<StoreUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(StoreUser::getPhone, phone);
StoreUser user = storeUserMapper.selectOne(queryWrapper);
```

- 根据手机号查询 `store_user` 表
- 使用 MyBatis-Plus 的 LambdaQueryWrapper
- 查询条件：`phone` 字段精确匹配

##### 2. 用户不存在处理

```java
if (user == null) {
    return new StoreUserVo();  // 返回空对象
}
```

- 如果查询结果为空，返回空的 `StoreUserVo` 对象
- Controller 层判断 `id` 是否为空，返回"手机号不存在"

##### 3. 注销倒计时计算（仅当 status=-1）

```java
if (user.getStatus() == -1) {
    // 获取注销申请时间
    LocalDateTime logoutDateTime = user.getLogoutTime()
            .toInstant()
            .atZone(ZoneId.systemDefault())
            .toLocalDateTime();
    
    // 计算7天后的时间（冷静期结束时间）
    LocalDateTime futureDateTime = logoutDateTime.plusDays(7);
    
    // 获取当前时间
    LocalDateTime nowDateTime = LocalDateTime.now();
    
    // 计算剩余时间
    Duration duration = Duration.between(nowDateTime, futureDateTime);
    
    // 转换为毫秒
    long countdownMillis = duration.toMillis();
    
    storeUserVo.setCountdown(countdownMillis);
}
```

**注销倒计时说明**：
- **触发条件**：`status = -1`（账户注销中）
- **计算逻辑**：
  - 冷静期：7天
  - 起始时间：`logoutTime`（注销申请时间）
  - 结束时间：`logoutTime + 7天`
  - 倒计时：`结束时间 - 当前时间`
- **单位**：毫秒（milliseconds）
- **示例**：
  - 注销申请时间：2025-01-15 10:00:00
  - 冷静期结束时间：2025-01-22 10:00:00
  - 当前时间：2025-01-16 10:00:00
  - 倒计时：6天 = 518400000毫秒

##### 4. 金额格式转换

```java
String moneyStr = new BigDecimal(user.getMoney())
        .divide(new BigDecimal(100), 2, RoundingMode.DOWN)
        .toString();
storeUserVo.setMoneyStr(moneyStr);
```

- **输入**：`money` 字段（单位：分，Integer类型）
- **输出**：`moneyStr` 字段（单位：元，String类型）
- **转换规则**：
  - 除以100转换为元
  - 保留2位小数
  - 舍入模式：DOWN（向下舍入）
- **示例**：
  - `money = 10000` → `moneyStr = "100.00"`
  - `money = 12345` → `moneyStr = "123.45"`
  - `money = 12346` → `moneyStr = "123.46"`

##### 5. 返回结果

- 使用 `BeanUtils.copyProperties()` 复制用户基本信息
- 设置 `moneyStr` 字段
- 如果是注销中状态，设置 `countdown` 字段
- 返回完整的 `StoreUserVo` 对象

---

## 业务场景

### 场景 1：正常用户查询

**请求**：
```
GET /alienStorePlatform/merchantUser/getMerchantByPhone?phone=15242687180
```

**用户状态**：
- `status = 1`（正常）
- `logoutFlag = 0`（未申请注销）

**响应特点**：
- ✅ 返回完整用户信息
- ✅ `countdown` 为 0（未计算）
- ✅ `moneyStr` 为格式化后的金额

---

### 场景 2：注销中的用户

**请求**：
```
GET /alienStorePlatform/merchantUser/getMerchantByPhone?phone=15242687180
```

**用户状态**：
- `status = -1`（注销中）
- `logoutFlag = 1`（已申请注销）
- `logoutTime = 2025-01-15 10:00:00`

**响应特点**：
- ✅ 返回完整用户信息
- ✅ `countdown` 为剩余冷静期时间（毫秒）
- ⚠️ 用户在冷静期内可以撤销注销
- ⚠️ 冷静期结束后账户将被永久注销

---

### 场景 3：用户不存在

**请求**：
```
GET /alienStorePlatform/merchantUser/getMerchantByPhone?phone=99999999999
```

**响应**：
```json
{
  "code": 500,
  "msg": "手机号不存在",
  "data": null,
  "success": false
}
```

---

## 数据库表结构

### store_user（商户用户表）

| 字段名 | 类型 | 说明 |
|--------|------|------|
| id | INT | 主键，自增 |
| phone | VARCHAR(11) | 手机号（唯一） |
| name | VARCHAR(50) | 真实姓名 |
| nick_name | VARCHAR(50) | 昵称 |
| head_img | VARCHAR(255) | 头像URL |
| account_blurb | TEXT | 账户简介 |
| store_id | INT | 绑定的店铺ID |
| status | INT | 账户状态（-1:注销中, 0:禁用, 1:正常） |
| money | INT | 账户余额（单位：分） |
| pay_password | VARCHAR(100) | 支付密码（加密） |
| id_card | VARCHAR(18) | 身份证号 |
| real_name | VARCHAR(50) | 实名 |
| logout_flag | INT | 注销标记（0:正常, 1:已申请注销） |
| logout_time | DATETIME | 注销申请时间 |
| logout_reason | VARCHAR(255) | 注销原因 |
| delete_flag | INT | 删除标记（0:未删除, 1:已删除） |
| created_time | DATETIME | 创建时间 |
| updated_time | DATETIME | 更新时间 |

**重要索引**：
- PRIMARY KEY (`id`)
- UNIQUE KEY `uk_phone` (`phone`)

---

## 相关文件

### Controller 层
- `alien-store-platform/src/main/java/shop/alien/storeplatform/controller/MerchantUserController.java`

### Service 层
- `alien-store-platform/src/main/java/shop/alien/storeplatform/service/MerchantUserService.java`
- `alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/MerchantUserServiceImpl.java`

### Entity/Mapper 层
- `alien-entity/src/main/java/shop/alien/entity/store/StoreUser.java`
- `alien-entity/src/main/java/shop/alien/entity/store/vo/StoreUserVo.java`
- `alien-entity/src/main/java/shop/alien/mapper/StoreUserMapper.java`

---

## 测试建议

### 测试用例 1：查询正常用户

```bash
curl -X GET "http://localhost:8080/alienStorePlatform/merchantUser/getMerchantByPhone?phone=15242687180"
```

**期望结果**：
- 返回完整用户信息
- `status = 1`
- `logoutFlag = 0`
- `countdown = 0`
- `moneyStr` 格式正确（如："100.00"）

---

### 测试用例 2：查询注销中的用户

**前置条件**：
- 用户已申请注销
- `status = -1`
- `logoutTime` 在过去7天内

```bash
curl -X GET "http://localhost:8080/alienStorePlatform/merchantUser/getMerchantByPhone?phone=15242687180"
```

**期望结果**：
- 返回用户信息
- `status = -1`
- `logoutFlag = 1`
- `countdown > 0`（倒计时为正数）
- `logoutTime` 和 `logoutReason` 有值

---

### 测试用例 3：查询不存在的用户

```bash
curl -X GET "http://localhost:8080/alienStorePlatform/merchantUser/getMerchantByPhone?phone=99999999999"
```

**期望结果**：
```json
{
  "code": 500,
  "msg": "手机号不存在",
  "data": null,
  "success": false
}
```

---

### 测试用例 4：金额格式验证

**测试不同金额值的转换**：

| 原始值（分） | 期望值（元） |
|-------------|-------------|
| 0 | "0.00" |
| 100 | "1.00" |
| 12345 | "123.45" |
| 99999 | "999.99" |

---

### 测试用例 5：注销倒计时计算

**场景**：用户在不同时间点查询倒计时

| 注销申请时间 | 查询时间 | 期望倒计时 |
|-------------|---------|----------|
| 2025-01-15 10:00:00 | 2025-01-16 10:00:00 | 6天 = 518400000ms |
| 2025-01-15 10:00:00 | 2025-01-22 09:00:00 | 1小时 = 3600000ms |
| 2025-01-15 10:00:00 | 2025-01-22 10:00:00 | 0ms（冷静期结束） |
| 2025-01-15 10:00:00 | 2025-01-23 10:00:00 | 负数（已超期） |

---

## 注意事项

### 1. 账户状态说明

| status 值 | 状态 | 说明 |
|-----------|------|------|
| -1 | 注销中 | 冷静期内，可撤销注销 |
| 0 | 禁用 | 账户被管理员禁用 |
| 1 | 正常 | 账户正常使用 |

### 2. 注销冷静期机制

- ⚠️ **冷静期时长**：7天（从申请注销时间开始计算）
- ⚠️ **冷静期内**：
  - 账户 `status = -1`
  - `logoutFlag = 1`
  - 用户可以撤销注销申请
  - 返回 `countdown` 倒计时（毫秒）
- ⚠️ **冷静期结束后**：
  - 账户将被永久注销
  - 所有数据将被清除
  - 无法恢复

### 3. 金额字段处理

- ⚠️ **存储单位**：分（Integer）
- ⚠️ **展示单位**：元（String）
- ⚠️ **转换规则**：
  - 分 ÷ 100 = 元
  - 保留2位小数
  - 向下舍入（RoundingMode.DOWN）
- ⚠️ **示例**：10000分 = 100.00元

### 4. 手机号查询

- ⚠️ **查询字段**：`phone`（手机号字段）
- ⚠️ **唯一性**：手机号在数据库中是唯一的
- ⚠️ **查询结果**：
  - 如果存在：返回唯一的用户记录
  - 如果不存在：返回 `null`

### 5. 空对象处理

```java
if (user == null) {
    return new StoreUserVo();  // 返回空对象，不是null
}
```

- Service 层返回空对象（不是 `null`）
- Controller 层通过 `id` 字段判断是否为空
- 避免空指针异常

### 6. 时区处理

```java
LocalDateTime localDateTime = logoutTime
    .toInstant()
    .atZone(ZoneId.systemDefault())
    .toLocalDateTime();
```

- 使用系统默认时区
- 确保时间计算的准确性
- 避免时区转换错误

---

## 接口对比

| 功能 | 原接口（alien-store） | 新接口（alien-store-platform） |
|------|----------------------|-------------------------------|
| 根据手机号查询 | `/alienStore/store/user/getUserByPhone` | `/alienStorePlatform/merchantUser/getMerchantByPhone` |
| 返回类型 | `R<StoreUser>` | `R<StoreUserVo>` |

**主要变化**：
- ✅ 接口路径更符合web端命名规范
- ✅ Controller和Service命名更清晰（`MerchantUser`）
- ✅ 返回类型统一为 `StoreUserVo`（扩展字段更丰富）
- ✅ 代码结构更清晰，注释更完善

---

## 版本记录

| 版本 | 日期 | 说明 | 作者 |
|------|------|------|------|
| 1.0.0 | 2025-01-xx | 初始版本，迁移商户用户查询功能 | ssk |

---

## 联系方式

如有问题，请联系：
- 开发团队：Alien Cloud Team
- 邮箱：dev@alien.shop

