Browse Source

docs(api): 添加商户用户信息和店铺收益相关接口文档

- 创建根据手机号获取商户用户信息接口文档
- 创建获取店铺今日收益接口文档
- 创建获取店铺今日订单数接口文档
- 详细描述接口路径、请求参数和响应格式- 添加业务逻辑说明和数据库表结构信息
- 提供测试用例和注意事项说明
- 对比原接口与新接口的差异
- 补充金额计算和时间处理的相关细节
wxd 1 tháng trước cách đây
mục cha
commit
1da1d12c38

+ 536 - 0
alien-store-platform/doc/API_MERCHANT_USER.md

@@ -0,0 +1,536 @@
+# 根据手机号获取商户用户信息接口文档
+
+## 概述
+
+本文档描述了从 `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
+

+ 531 - 0
alien-store-platform/doc/API_TODAY_INCOME.md

@@ -0,0 +1,531 @@
+# 获取店铺今日收益接口文档
+
+## 概述
+
+本文档描述了从 `alien-store`(app端商户)迁移到 `alien-store-platform`(web端商户)的获取店铺今日收益接口。
+
+## 接口详情
+
+### 获取店铺今日收益
+
+**接口描述**:查询指定店铺在当天(00:00:00 至 23:59:59)的总收益,包括所有收入类型(代金券、团购等),返回格式化后的金额(单位:元)。
+
+#### 原接口
+- **服务**:alien-store(app端商户)
+- **路径**:`GET /alienStore/storeIncomeDetailsRecord/todayIncome?storeId=102`
+- **Controller**:`StoreIncomeDetailsRecordController.todayIncome()`
+- **Service**:`StoreIncomeDetailsRecordServiceImpl.todayIncome()`
+
+#### 新接口
+- **服务**:alien-store-platform(web端商户)
+- **路径**:`GET /alienStorePlatform/storeManage/getTodayIncome?storeId=102`
+- **Controller**:`StoreManageController.getTodayIncome()`
+- **Service**:`StoreManageServiceImpl.getTodayIncome()`
+
+#### 请求参数
+
+**Query 参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| storeId | Integer | 是 | 店铺ID |
+
+**请求示例**:
+
+```
+GET /alienStorePlatform/storeManage/getTodayIncome?storeId=102
+```
+
+#### 响应参数
+
+**成功响应**:
+
+```json
+{
+  "code": 200,
+  "msg": "查询成功",
+  "data": "1234.56",
+  "success": true
+}
+```
+
+**说明**:
+- `data` 字段为字符串类型
+- 单位:元(人民币)
+- 格式:保留两位小数
+- 示例值:
+  - `"0.00"` - 今日无收益
+  - `"123.45"` - 今日收益123.45元
+  - `"10000.00"` - 今日收益10000元
+
+**失败响应**:
+
+```json
+{
+  "code": 500,
+  "msg": "{错误信息}",
+  "data": null,
+  "success": false
+}
+```
+
+#### 业务逻辑
+
+##### 1. 查询今日收入记录
+
+```java
+LambdaQueryWrapper<StoreIncomeDetailsRecord> wrapper = new LambdaQueryWrapper<>();
+LocalDate today = LocalDate.now();
+
+wrapper.eq(StoreIncomeDetailsRecord::getStoreId, storeId)
+       .ge(StoreIncomeDetailsRecord::getCreatedTime, today + " 00:00:00")
+       .le(StoreIncomeDetailsRecord::getCreatedTime, today + " 23:59:59");
+
+List<StoreIncomeDetailsRecord> incomeList = storeIncomeDetailsRecordMapper.selectList(wrapper);
+```
+
+**查询条件**:
+- **storeId**:店铺ID精确匹配
+- **createdTime**:
+  - 大于等于(>=):今日 00:00:00
+  - 小于等于(<=):今日 23:59:59
+- **deleteFlag**:自动过滤已删除记录(MyBatis-Plus逻辑删除)
+
+**时间范围说明**:
+- 以数据库服务器时间为准
+- 包含今日的所有时刻(00:00:00 - 23:59:59)
+- 跨天的收入记录按 `createdTime` 归属日期
+
+##### 2. 计算总收益
+
+```java
+int totalIncome = 0;
+if (incomeList != null && !incomeList.isEmpty()) {
+    totalIncome = incomeList.stream()
+            .mapToInt(StoreIncomeDetailsRecord::getMoney)
+            .sum();
+}
+```
+
+**计算规则**:
+- 遍历所有今日收入记录
+- 累加 `money` 字段(单位:分)
+- 包含所有收入类型:
+  - 代金券收入(incomeType=1)
+  - 团购收入(incomeType=2)
+  - 其他收入(incomeType=0或其他值)
+
+**空值处理**:
+- 如果今日无收入记录 → `totalIncome = 0`
+- 如果查询结果为空列表 → `totalIncome = 0`
+
+##### 3. 金额格式转换
+
+```java
+String incomeStr = new BigDecimal(totalIncome)
+        .divide(new BigDecimal(100), 2, RoundingMode.DOWN)
+        .toString();
+```
+
+**转换规则**:
+- **输入**:`totalIncome`(单位:分,int类型)
+- **输出**:`incomeStr`(单位:元,String类型)
+- **转换公式**:分 ÷ 100 = 元
+- **精度**:保留2位小数
+- **舍入模式**:DOWN(向下舍入/截断)
+
+**示例**:
+
+| 原始值(分) | 转换后(元) | 说明 |
+|-------------|-------------|------|
+| 0 | "0.00" | 无收益 |
+| 100 | "1.00" | 1元 |
+| 12345 | "123.45" | 123.45元 |
+| 123456 | "1234.56" | 1234.56元 |
+| 99999 | "999.99" | 999.99元 |
+| 1000099 | "10000.99" | 10000.99元 |
+
+**舍入示例**:
+
+| 原始值(分) | DOWN模式 | HALF_UP模式(对比)|
+|-------------|----------|-------------------|
+| 12344 | "123.44" | "123.44" |
+| 12345 | "123.45" | "123.45" |
+| 12346 | "123.46" | "123.46" |
+
+注:本接口使用 DOWN 模式,直接截断小数部分,不进行四舍五入。
+
+---
+
+## 数据库表结构
+
+### store_income_details_record(商户收入明细表)
+
+| 字段名 | 类型 | 说明 |
+|--------|------|------|
+| id | INT | 主键,自增 |
+| store_id | INT | 店铺ID |
+| income_type | INT | 收入类型(0:全部, 1:代金, 2:团购)|
+| business_id | INT | 业务ID(优惠券ID或团购ID)|
+| money | INT | 收入金额(单位:分)|
+| commission | INT | 手续费(单位:分)|
+| user_order_id | INT | 用户订单ID |
+| cash_out_id | INT | 提现记录ID(提现后才有值)|
+| delete_flag | INT | 删除标记(0:未删除, 1:已删除)|
+| created_time | DATETIME | 创建时间(收益到账时间)|
+| updated_time | DATETIME | 更新时间 |
+
+**重要索引**:
+- PRIMARY KEY (`id`)
+- INDEX `idx_store_created` (`store_id`, `created_time`)
+- INDEX `idx_created_time` (`created_time`)
+
+**说明**:
+- `money` 字段存储的是收入金额(不含手续费)
+- `commission` 字段存储的是平台手续费
+- 实际到账金额 = `money` - `commission`
+- 本接口统计的是 `money` 字段总和(收入金额)
+
+---
+
+## 业务场景
+
+### 场景 1:正常查询今日收益
+
+**请求**:
+```
+GET /alienStorePlatform/storeManage/getTodayIncome?storeId=102
+```
+
+**数据库数据**(假设今天是2025-01-15):
+
+| id | store_id | income_type | money(分)| created_time |
+|----|----------|-------------|-----------|--------------|
+| 1  | 102      | 1           | 5000      | 2025-01-15 10:30:00 |
+| 2  | 102      | 2           | 8000      | 2025-01-15 14:20:00 |
+| 3  | 102      | 1           | 3456      | 2025-01-15 18:45:00 |
+
+**计算过程**:
+1. 查询今日收入记录:3条
+2. 累加金额:5000 + 8000 + 3456 = 16456(分)
+3. 转换为元:16456 ÷ 100 = 164.56(元)
+
+**响应**:
+```json
+{
+  "code": 200,
+  "msg": "查询成功",
+  "data": "164.56",
+  "success": true
+}
+```
+
+---
+
+### 场景 2:今日无收益
+
+**请求**:
+```
+GET /alienStorePlatform/storeManage/getTodayIncome?storeId=102
+```
+
+**数据库数据**:
+- 今日(2025-01-15)无收入记录
+
+**响应**:
+```json
+{
+  "code": 200,
+  "msg": "查询成功",
+  "data": "0.00",
+  "success": true
+}
+```
+
+---
+
+### 场景 3:跨天收益统计
+
+**说明**:收益按 `created_time` 归属日期
+
+**数据库数据**:
+
+| id | store_id | money(分)| created_time |
+|----|----------|-----------|--------------|
+| 1  | 102      | 5000      | 2025-01-14 23:59:59 |
+| 2  | 102      | 8000      | 2025-01-15 00:00:00 |
+| 3  | 102      | 3456      | 2025-01-15 23:59:59 |
+| 4  | 102      | 2000      | 2025-01-16 00:00:00 |
+
+**2025-01-15 的收益**:
+- 包含记录:id=2, id=3
+- 总金额:8000 + 3456 = 11456(分)= 114.56(元)
+
+**响应**(查询日期:2025-01-15):
+```json
+{
+  "code": 200,
+  "msg": "查询成功",
+  "data": "114.56",
+  "success": true
+}
+```
+
+---
+
+### 场景 4:包含不同收入类型
+
+**数据库数据**:
+
+| id | store_id | income_type | money(分)| created_time | 说明 |
+|----|----------|-------------|-----------|--------------|------|
+| 1  | 102      | 1           | 5000      | 2025-01-15 10:00:00 | 代金券 |
+| 2  | 102      | 2           | 8000      | 2025-01-15 14:00:00 | 团购 |
+| 3  | 102      | 0           | 2000      | 2025-01-15 18:00:00 | 其他 |
+
+**统计结果**:
+- 所有类型都统计:5000 + 8000 + 2000 = 15000(分)= 150.00(元)
+
+**响应**:
+```json
+{
+  "code": 200,
+  "msg": "查询成功",
+  "data": "150.00",
+  "success": true
+}
+```
+
+---
+
+## 相关文件
+
+### Controller 层
+- `alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StoreManageController.java`
+
+### Service 层
+- `alien-store-platform/src/main/java/shop/alien/storeplatform/service/StoreManageService.java`
+- `alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StoreManageServiceImpl.java`
+
+### Entity/Mapper 层
+- `alien-entity/src/main/java/shop/alien/entity/store/StoreIncomeDetailsRecord.java`
+- `alien-entity/src/main/java/shop/alien/mapper/StoreIncomeDetailsRecordMapper.java`
+
+---
+
+## 测试建议
+
+### 测试用例 1:正常查询
+
+**前置条件**:
+- 店铺ID存在
+- 今日有收入记录
+
+```bash
+curl -X GET "http://localhost:8080/alienStorePlatform/storeManage/getTodayIncome?storeId=102"
+```
+
+**期望结果**:
+- 返回今日总收益(元)
+- 格式:字符串,保留两位小数
+- 示例:`"123.45"`
+
+---
+
+### 测试用例 2:今日无收益
+
+**前置条件**:
+- 店铺ID存在
+- 今日无收入记录
+
+```bash
+curl -X GET "http://localhost:8080/alienStorePlatform/storeManage/getTodayIncome?storeId=102"
+```
+
+**期望结果**:
+```json
+{
+  "code": 200,
+  "data": "0.00",
+  "success": true
+}
+```
+
+---
+
+### 测试用例 3:跨天查询
+
+**测试步骤**:
+1. 在 23:50 查询今日收益
+2. 在 00:10 查询今日收益(第二天)
+3. 对比两次结果
+
+**期望结果**:
+- 两次查询结果不同
+- 第二次查询应该是新的一天的收益
+
+---
+
+### 测试用例 4:多种收入类型
+
+**前置条件**:
+- 今日有代金券收入
+- 今日有团购收入
+- 今日有其他类型收入
+
+**期望结果**:
+- 返回所有类型收入的总和
+
+---
+
+### 测试用例 5:金额格式验证
+
+**验证不同金额的格式化**:
+
+| 数据库值(分) | API返回(元) |
+|---------------|--------------|
+| 0 | "0.00" |
+| 1 | "0.01" |
+| 10 | "0.10" |
+| 100 | "1.00" |
+| 999 | "9.99" |
+| 12345 | "123.45" |
+| 1000000 | "10000.00" |
+
+---
+
+## 注意事项
+
+### 1. 时间范围
+
+- ⚠️ **查询范围**:今日 00:00:00 至 23:59:59
+- ⚠️ **时区**:使用数据库服务器时间
+- ⚠️ **跨天处理**:按 `created_time` 归属日期,不受查询时间影响
+
+### 2. 金额单位
+
+- ⚠️ **数据库存储**:分(Integer)
+- ⚠️ **接口返回**:元(String)
+- ⚠️ **转换规则**:分 ÷ 100 = 元
+- ⚠️ **精度**:保留2位小数
+- ⚠️ **舍入模式**:DOWN(向下截断)
+
+### 3. 收入类型
+
+本接口统计所有收入类型:
+
+| income_type | 说明 |
+|-------------|------|
+| 0 | 全部/其他 |
+| 1 | 代金券 |
+| 2 | 团购 |
+
+- ⚠️ 不区分收入类型,全部统计
+- ⚠️ 如需按类型统计,需要调用其他接口
+
+### 4. 手续费处理
+
+- ⚠️ 本接口统计的是 `money` 字段(收入金额)
+- ⚠️ **不扣除** `commission` 字段(手续费)
+- ⚠️ 实际到账金额需要减去手续费
+
+**示例**:
+```
+收入金额(money): 10000分 = 100.00元
+手续费(commission): 300分 = 3.00元
+实际到账: 9700分 = 97.00元
+
+本接口返回: "100.00"(收入金额)
+```
+
+### 5. 逻辑删除
+
+- ⚠️ MyBatis-Plus 自动过滤 `delete_flag=1` 的记录
+- ⚠️ 已删除的收入记录不会被统计
+- ⚠️ 确保业务逻辑正确处理删除标记
+
+### 6. 性能优化
+
+**数据库索引**:
+```sql
+CREATE INDEX idx_store_created ON store_income_details_record(store_id, created_time);
+```
+
+**查询优化**:
+- ✅ 使用复合索引(store_id + created_time)
+- ✅ 时间范围查询使用字符串拼接(与数据库格式一致)
+- ✅ Stream API 高效计算总和
+
+### 7. 数据一致性
+
+- ⚠️ 收益数据可能存在延迟(如T+3到账)
+- ⚠️ 本接口统计的是 `created_time`(记录创建时间)
+- ⚠️ 实际收益到账时间可能与统计时间不同
+
+---
+
+## 接口对比
+
+| 功能 | 原接口(alien-store) | 新接口(alien-store-platform) |
+|------|----------------------|-------------------------------|
+| 今日收益 | `/alienStore/storeIncomeDetailsRecord/todayIncome` | `/alienStorePlatform/storeManage/getTodayIncome` |
+| Controller | `StoreIncomeDetailsRecordController` | `StoreManageController` |
+| Service | `StoreIncomeDetailsRecordService` | `StoreManageService` |
+
+**主要变化**:
+- ✅ 接口路径更符合web端命名规范
+- ✅ 整合到 `StoreManageController` 统一管理
+- ✅ 代码注释更完善,逻辑更清晰
+
+---
+
+## 扩展功能建议
+
+### 1. 按收入类型统计
+
+```java
+public Map<Integer, String> getTodayIncomeByType(Integer storeId) {
+    // 按 incomeType 分组统计
+}
+```
+
+### 2. 查询指定日期收益
+
+```java
+public String getIncomeByDate(Integer storeId, String date) {
+    // 查询指定日期的收益
+}
+```
+
+### 3. 查询日期范围收益
+
+```java
+public String getIncomeByDateRange(Integer storeId, String startDate, String endDate) {
+    // 查询日期范围的总收益
+}
+```
+
+### 4. 今日收益明细
+
+```java
+public List<StoreIncomeDetailsRecord> getTodayIncomeDetails(Integer storeId) {
+    // 返回今日所有收入记录
+}
+```
+
+---
+
+## 版本记录
+
+| 版本 | 日期 | 说明 | 作者 |
+|------|------|------|------|
+| 1.0.0 | 2025-01-xx | 初始版本,迁移今日收益查询功能 | ssk |
+
+---
+
+## 联系方式
+
+如有问题,请联系:
+- 开发团队:Alien Cloud Team
+- 邮箱:dev@alien.shop
+

+ 279 - 0
alien-store-platform/doc/API_TODAY_ORDER_COUNT.md

@@ -0,0 +1,279 @@
+# 店铺今日订单数接口文档
+
+## 接口信息
+
+### 接口名称
+获取店铺今日订单数
+
+### 接口路径
+`GET /storeManage/getTodayOrderCount`
+
+### 接口描述
+查询指定店铺今日的有效订单数量(排除待支付、已取消、已过期状态的订单)
+
+---
+
+## 请求参数
+
+### Query 参数
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| storeId | Integer | 是 | 店铺ID |
+
+### 请求示例
+
+```http
+GET /storeManage/getTodayOrderCount?storeId=102
+```
+
+---
+
+## 响应参数
+
+### 响应数据结构
+
+```json
+{
+    "code": 200,
+    "success": true,
+    "data": 15,
+    "msg": "查询成功"
+}
+```
+
+### 响应字段说明
+
+| 字段名 | 类型 | 说明 |
+|--------|------|------|
+| code | Integer | 响应状态码,200表示成功 |
+| success | Boolean | 是否成功 |
+| data | Integer | 今日有效订单数量 |
+| msg | String | 响应消息 |
+
+---
+
+## 业务逻辑说明
+
+### 1. 订单统计规则
+- **时间范围**:当天 00:00:00 至 23:59:59
+- **排除状态**:
+  - 待支付 (0)
+  - 已取消 (4)
+  - 已过期 (3)
+- **包含状态**:
+  - 已支付/待使用 (1)
+  - 已核销 (2)
+  - 已退款 (5)
+  - 退款失败 (6)
+  - 已完成 (7)
+
+### 2. 查询条件
+```java
+// 查询今日的订单
+wrapper.eq(LifeUserOrder::getStoreId, storeId)
+       .notIn(LifeUserOrder::getStatus, 
+              OrderStatusEnum.CANCEL.getStatus(),      // 4-已取消
+              OrderStatusEnum.WAIT_PAY.getStatus(),    // 0-待支付
+              OrderStatusEnum.EXPIRE.getStatus())      // 3-已过期
+       .between(LifeUserOrder::getBuyTime, 
+                today + " 00:00:00", 
+                today + " 23:59:59");
+```
+
+### 3. 数据来源
+- **数据表**:`life_user_order`
+- **关联实体**:`LifeUserOrder`
+- **Mapper**:`LifeUserOrderMapper`
+
+---
+
+## 技术实现
+
+### Controller 层
+**文件路径**:`alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StoreManageController.java`
+
+```java
+@ApiOperation("获取店铺今日订单数")
+@ApiOperationSupport(order = 6)
+@ApiImplicitParams({
+    @ApiImplicitParam(name = "storeId", value = "店铺ID", 
+                     dataType = "Integer", paramType = "query", required = true)
+})
+@GetMapping("/getTodayOrderCount")
+public R<Integer> getTodayOrderCount(@RequestParam("storeId") Integer storeId) {
+    log.info("StoreManageController.getTodayOrderCount?storeId={}", storeId);
+    try {
+        Integer count = storeManageService.getTodayOrderCount(storeId);
+        return R.data(count, "查询成功");
+    } catch (Exception e) {
+        log.error("StoreManageController.getTodayOrderCount ERROR: {}", 
+                 e.getMessage(), e);
+        return R.fail(e.getMessage());
+    }
+}
+```
+
+### Service 层
+**文件路径**:`alien-store-platform/src/main/java/shop/alien/storeplatform/service/StoreManageService.java`
+
+```java
+/**
+ * 获取店铺今日订单数
+ *
+ * @param storeId 店铺ID
+ * @return 今日订单数
+ */
+Integer getTodayOrderCount(Integer storeId);
+```
+
+### Service 实现层
+**文件路径**:`alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StoreManageServiceImpl.java`
+
+```java
+@Override
+public Integer getTodayOrderCount(Integer storeId) {
+    log.info("StoreManageServiceImpl.getTodayOrderCount - 查询店铺今日订单数: storeId={}", 
+             storeId);
+    
+    // 1. 构建查询条件
+    LambdaQueryWrapper<LifeUserOrder> wrapper = new LambdaQueryWrapper<>();
+    LocalDate today = LocalDate.now();
+    
+    // 2. 查询今日的订单,排除待支付、已取消、已过期状态
+    wrapper.eq(LifeUserOrder::getStoreId, storeId)
+           .notIn(LifeUserOrder::getStatus, 
+                  OrderStatusEnum.CANCEL.getStatus(), 
+                  OrderStatusEnum.WAIT_PAY.getStatus(), 
+                  OrderStatusEnum.EXPIRE.getStatus())
+           .between(LifeUserOrder::getBuyTime, 
+                    today + " 00:00:00", 
+                    today + " 23:59:59");
+    
+    // 3. 统计订单数量
+    Integer count = lifeUserOrderMapper.selectCount(wrapper);
+    
+    log.info("StoreManageServiceImpl.getTodayOrderCount - 查询完成: storeId={}, 今日订单数={}", 
+             storeId, count);
+    return count;
+}
+```
+
+---
+
+## 依赖注入
+
+### Service 实现类新增依赖
+```java
+private final LifeUserOrderMapper lifeUserOrderMapper;
+```
+
+### 新增导入
+```java
+import shop.alien.entity.store.LifeUserOrder;
+import shop.alien.util.common.constant.OrderStatusEnum;
+```
+
+---
+
+## 原接口对比
+
+### 原接口信息
+- **服务**:alien-store(app端商户)
+- **路径**:`/alienStore/storeIncomeDetailsRecord/todayOrderCount`
+- **Controller**:`StoreIncomeDetailsRecordController`
+- **Service**:`StoreIncomeDetailsRecordService`
+
+### 新接口信息
+- **服务**:alien-store-platform(web端商户)
+- **路径**:`/storeManage/getTodayOrderCount`
+- **Controller**:`StoreManageController`
+- **Service**:`StoreManageService`
+
+### 命名对比
+| 原接口 | 新接口 | 说明 |
+|--------|--------|------|
+| todayOrderCount | getTodayOrderCount | 符合web端命名规范 |
+| /storeIncomeDetailsRecord/ | /storeManage/ | 统一归类到店铺管理模块 |
+
+---
+
+## 错误处理
+
+### 异常情况
+1. **参数错误**:storeId 为空或无效
+2. **数据库异常**:查询失败
+
+### 错误响应示例
+```json
+{
+    "code": 500,
+    "success": false,
+    "data": null,
+    "msg": "查询失败:数据库连接异常"
+}
+```
+
+---
+
+## 测试建议
+
+### 测试场景
+1. **正常场景**:查询有订单的店铺
+2. **空数据场景**:查询今日无订单的店铺(应返回0)
+3. **边界场景**:查询不存在的店铺ID(应返回0)
+4. **状态过滤**:验证待支付、已取消、已过期订单是否被排除
+
+### 测试数据
+```sql
+-- 查询店铺今日订单(用于验证)
+SELECT 
+    COUNT(*) AS order_count
+FROM life_user_order
+WHERE store_id = 102
+  AND status NOT IN (0, 3, 4)  -- 排除待支付、已过期、已取消
+  AND buy_time BETWEEN '2025-11-12 00:00:00' AND '2025-11-12 23:59:59'
+  AND delete_flag = 0;
+```
+
+---
+
+## 相关接口
+
+- **今日收益接口**:`GET /storeManage/getTodayIncome`
+- **店铺详情接口**:`GET /storeManage/getStoreDetail`
+- **店铺入住申请**:`POST /storeManage/applyStore`
+
+---
+
+## 注意事项
+
+1. **订单状态枚举**:使用 `OrderStatusEnum` 确保状态码一致性
+2. **时间范围**:使用 `LocalDate.now()` 获取当天日期,确保时区正确
+3. **性能优化**:订单数量统计使用 `selectCount` 而非查询全部数据
+4. **逻辑删除**:MyBatis-Plus 自动处理 `delete_flag` 字段
+5. **日志记录**:记录查询参数和结果,便于问题追踪
+
+---
+
+## 更新日志
+
+### 2025-11-12
+- ✅ 完成接口迁移:从 alien-store 迁移到 alien-store-platform
+- ✅ Controller 层:添加 `getTodayOrderCount` 接口
+- ✅ Service 层:添加 `getTodayOrderCount` 方法定义
+- ✅ Service 实现层:实现今日订单数查询逻辑
+- ✅ 依赖注入:添加 `LifeUserOrderMapper` 和 `OrderStatusEnum` 导入
+- ✅ Linter 检查:无错误
+- ✅ 业务逻辑:完全复用原接口逻辑
+- ✅ 命名规范:符合web端命名规范
+
+---
+
+## 开发者信息
+
+- **迁移时间**:2025-11-12
+- **原服务**:alien-store(app端商户)
+- **目标服务**:alien-store-platform(web端商户)
+- **技术栈**:Spring Boot + MyBatis-Plus + Java 8
+

+ 49 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/controller/MerchantUserController.java

@@ -0,0 +1,49 @@
+package shop.alien.storeplatform.controller;
+
+import io.swagger.annotations.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.vo.StoreUserVo;
+import shop.alien.storeplatform.service.MerchantUserService;
+
+/**
+ * web端商户用户管理控制器
+ *
+ * @author ssk
+ * @since 2025-01-xx
+ */
+@Slf4j
+@Api(tags = {"web端商户用户管理"})
+@ApiSort(5)
+@CrossOrigin
+@RestController
+@RequestMapping("/merchantUser")
+@RequiredArgsConstructor
+public class MerchantUserController {
+
+    private final MerchantUserService merchantUserService;
+
+    @ApiOperation("根据手机号获取商户用户信息")
+    @ApiOperationSupport(order = 1)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "String", paramType = "query", required = true)
+    })
+    @GetMapping("/getMerchantByPhone")
+    public R<StoreUserVo> getMerchantByPhone(@RequestParam("phone") String phone) {
+        log.info("MerchantUserController.getMerchantByPhone?phone={}", phone);
+        try {
+            StoreUserVo result = merchantUserService.getMerchantByPhone(phone);
+            if (result != null && result.getId() != null) {
+                return R.data(result);
+            }
+            return R.fail("手机号不存在");
+        } catch (Exception e) {
+            log.error("MerchantUserController.getMerchantByPhone ERROR: {}", e.getMessage(), e);
+            return R.fail(e.getMessage());
+        }
+    }
+}
+
+

+ 22 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/service/MerchantUserService.java

@@ -0,0 +1,22 @@
+package shop.alien.storeplatform.service;
+
+import shop.alien.entity.store.vo.StoreUserVo;
+
+/**
+ * web端商户用户管理服务接口
+ *
+ * @author ssk
+ * @since 2025-01-xx
+ */
+public interface MerchantUserService {
+
+    /**
+     * 根据手机号获取商户用户信息
+     *
+     * @param phone 手机号
+     * @return StoreUserVo
+     */
+    StoreUserVo getMerchantByPhone(String phone);
+}
+
+

+ 95 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/MerchantUserServiceImpl.java

@@ -0,0 +1,95 @@
+package shop.alien.storeplatform.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import shop.alien.entity.store.StoreUser;
+import shop.alien.entity.store.vo.StoreUserVo;
+import shop.alien.mapper.StoreUserMapper;
+import shop.alien.storeplatform.service.MerchantUserService;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+
+/**
+ * web端商户用户管理服务实现类
+ *
+ * @author ssk
+ * @since 2025-01-xx
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class MerchantUserServiceImpl implements MerchantUserService {
+
+    private final StoreUserMapper storeUserMapper;
+
+    @Override
+    public StoreUserVo getMerchantByPhone(String phone) {
+        log.info("MerchantUserServiceImpl.getMerchantByPhone - 查询商户用户: phone={}", phone);
+        
+        // 1. 根据手机号查询商户用户
+        LambdaQueryWrapper<StoreUser> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(StoreUser::getPhone, phone);
+        StoreUser user = storeUserMapper.selectOne(queryWrapper);
+        
+        StoreUserVo storeUserVo = new StoreUserVo();
+        
+        // 2. 如果用户不存在,返回空对象
+        if (user == null) {
+            log.warn("MerchantUserServiceImpl.getMerchantByPhone - 商户用户不存在: phone={}", phone);
+            return storeUserVo;
+        }
+        
+        // 3. 如果用户状态为注销中(status=-1),计算注销倒计时
+        if (user.getStatus() == -1) {
+            try {
+                // 将注销时间转换为LocalDateTime
+                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);
+                log.info("MerchantUserServiceImpl.getMerchantByPhone - 商户用户注销中,倒计时: {}毫秒", countdownMillis);
+            } catch (Exception e) {
+                log.error("MerchantUserServiceImpl.getMerchantByPhone - 计算注销倒计时失败: {}", e.getMessage(), e);
+                storeUserVo.setCountdown(0L);
+            }
+        }
+        
+        // 4. 复制用户基本信息
+        BeanUtils.copyProperties(user, storeUserVo);
+        
+        // 5. 转换金额格式(分转元,保留两位小数)
+        if (storeUserVo.getMoney() != null) {
+            String moneyStr = new BigDecimal(storeUserVo.getMoney())
+                    .divide(new BigDecimal(100), 2, RoundingMode.DOWN)
+                    .toString();
+            storeUserVo.setMoneyStr(moneyStr);
+        }
+        
+        log.info("MerchantUserServiceImpl.getMerchantByPhone - 查询完成: phone={}, userId={}", 
+                phone, user.getId());
+        return storeUserVo;
+    }
+}
+
+