# Web端商户提现记录查询接口文档

## 模块概述

本模块提供提现记录查询功能，支持按时间范围、提现状态等条件筛选提现记录，并提供分页查询和统计信息。

---

## 接口信息

### 提现记录查询

#### 接口详情

- **接口名称**: 提现记录查询
- **接口路径**: `GET /incomeManage/getCashOutRecordList`
- **请求方式**: GET
- **接口描述**: 查询指定门店的提现记录，支持按时间范围和提现状态筛选，返回分页数据和统计信息
- **登录验证**: ✅ 需要（使用 `@LoginRequired` 注解）

---

## 请求参数

| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|--------|------|------|------|--------|
| storeId | Integer | 是 | 门店ID | 103 |
| cashOutStartTime | String | 否 | 开始时间（格式：yyyy-MM-dd） | 2025-11-10 |
| cashOutEndTime | String | 否 | 结束时间（格式：yyyy-MM-dd） | 2025-11-11 |
| paymentStatus | String | 否 | 提现状态 | 1 |
| page | Integer | 否 | 页码，默认1 | 1 |
| size | Integer | 否 | 每页条数，默认10 | 10 |

### 参数说明

#### paymentStatus（提现状态）
- `1`: 待审核
- `2`: 审核不通过
- `3`: 已通过
- `4`: 已打款
- `5`: 打款失败
- 不传：查询所有状态

#### 时间范围
- **cashOutStartTime**: 查询此日期（含）之后创建的提现记录
- **cashOutEndTime**: 查询此日期（含）之前创建的提现记录
- 不传时间参数：查询所有时间的记录

---

## 请求示例

### 示例1: 查询所有提现记录

```http
GET /incomeManage/getCashOutRecordList?storeId=103&page=1&size=10
```

```bash
curl "http://localhost:8080/incomeManage/getCashOutRecordList?storeId=103&page=1&size=10" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

---

### 示例2: 按时间范围查询

```http
GET /incomeManage/getCashOutRecordList?storeId=103&cashOutStartTime=2025-11-10&cashOutEndTime=2025-11-11&page=1&size=10
```

```bash
curl "http://localhost:8080/incomeManage/getCashOutRecordList?storeId=103&cashOutStartTime=2025-11-10&cashOutEndTime=2025-11-11&page=1&size=10" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

---

### 示例3: 查询待审核记录

```http
GET /incomeManage/getCashOutRecordList?storeId=103&paymentStatus=1&page=1&size=10
```

```bash
curl "http://localhost:8080/incomeManage/getCashOutRecordList?storeId=103&paymentStatus=1&page=1&size=10" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

---

### 示例4: 组合查询

```http
GET /incomeManage/getCashOutRecordList?storeId=103&cashOutStartTime=2025-11-10&cashOutEndTime=2025-11-11&paymentStatus=4&page=1&size=10
```

---

## 响应参数

### 成功响应

```json
{
    "code": 200,
    "success": true,
    "data": {
        "cashOutRecordList": [
            {
                "id": 1001,
                "storeId": 103,
                "storeUserId": 114,
                "money": 50000,
                "commission": 0,
                "cashOutType": 0,
                "paymentStatus": 1,
                "orderNo": "TX20251119001",
                "aliOrderNo": null,
                "paymentDate": "2025-11-19 10:30:00",
                "payDate": "2025-11-19 10:30:00",
                "settlementAccount": "13800138000",
                "failReason": null,
                "deleteFlag": 0,
                "createdTime": "2025-11-19 10:30:00",
                "updatedTime": "2025-11-19 10:30:00"
            },
            {
                "id": 1000,
                "storeId": 103,
                "storeUserId": 114,
                "money": 30000,
                "commission": 0,
                "cashOutType": 0,
                "paymentStatus": 4,
                "orderNo": "TX20251118001",
                "aliOrderNo": "2025111822001234567890123456",
                "paymentDate": "2025-11-18 15:20:00",
                "payDate": "2025-11-18 15:25:00",
                "settlementAccount": "alipay@example.com",
                "failReason": null,
                "deleteFlag": 0,
                "createdTime": "2025-11-18 15:20:00",
                "updatedTime": "2025-11-18 15:25:00"
            }
        ],
        "cashOutAllMoney": 800.00,
        "cashOutNum": 15
    },
    "msg": "操作成功"
}
```

### 响应字段说明

#### 外层字段

| 字段名 | 类型 | 说明 |
|--------|------|------|
| data.cashOutRecordList | Array | 提现记录列表（当前页） |
| data.cashOutAllMoney | BigDecimal | 提现总金额（仅统计待审核状态，单位：元） |
| data.cashOutNum | Integer | 提现记录总数 |

#### cashOutRecordList 字段

| 字段名 | 类型 | 说明 |
|--------|------|------|
| id | Long | 提现记录ID |
| storeId | Integer | 门店ID |
| storeUserId | Integer | 用户ID |
| money | Integer | 提现金额（单位：分） |
| commission | Integer | 手续费（单位：分） |
| cashOutType | Integer | 提现类型（0-全部提现） |
| paymentStatus | Integer | 提现状态 |
| orderNo | String | 提现订单号 |
| aliOrderNo | String | 支付宝订单号 |
| paymentDate | Date | 申请时间 |
| payDate | Date | 打款时间 |
| failReason | String | 失败原因 |
| settlementAccount | String | 结算账户（支付宝账号或手机号） |
| deleteFlag | Integer | 删除标识 |
| createdTime | Date | 创建时间 |
| updatedTime | Date | 更新时间 |

**⚠️ 重要字段说明**:
- `settlementAccount`: 通过 LEFT JOIN `store_user` 表查询得到
  - 优先使用商户的支付宝账号（`alipay_account`）
  - 如果没有支付宝账号，则使用手机号（`phone`）

---

### 失败响应

#### 1. 参数错误

```json
{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "查询失败：门店ID不能为空"
}
```

#### 2. 未登录或登录过期

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

#### 3. 系统异常

```json
{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "查询失败：{异常信息}"
}
```

---

## 业务逻辑说明

### 查询流程

```
┌─────────────────────────────────────────────┐
│  1. 接收查询参数                              │
│  - storeId (必填)                            │
│  - cashOutStartTime (可选)                   │
│  - cashOutEndTime (可选)                     │
│  - paymentStatus (可选)                      │
│  - page, size (分页)                         │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  2. 构建查询条件                              │
│  wrapper.eq(storeId)                         │
│  IF paymentStatus != null                    │
│    wrapper.eq(paymentStatus)                 │
│  IF cashOutEndTime != null                   │
│    wrapper.le(createdTime, endTime 23:59:59) │
│  IF cashOutStartTime != null                 │
│    wrapper.ge(createdTime, startTime 00:00:00)│
│  wrapper.orderByDesc(createdTime)            │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  3. 查询所有符合条件的记录                    │
│  List<StoreCashOutRecord> recordList         │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  4. 手动分页                                  │
│  IPage page = ListToPage.setPage(list, p, s)│
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  5. 构建返回VO                                │
│  vo.cashOutRecordList = page.getRecords()    │
│  vo.cashOutAllMoney = sum(money[status=1]) ÷ 100 │
│  vo.cashOutNum = list.size()                 │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  6. 返回结果                                  │
│  返回分页数据和统计信息                       │
└─────────────────────────────────────────────┘
```

### 查询条件说明

#### 1. 必填条件
- **storeId**: 门店ID（必须）

#### 2. 可选条件（AND关系）
- **paymentStatus**: 提现状态筛选
- **cashOutStartTime**: 开始时间（含当天 00:00:00）
- **cashOutEndTime**: 结束时间（含当天 23:59:59）

#### 3. 排序规则
- 按创建时间倒序排序（最新的在前）

---

## 数据库查询

### 查询SQL

```sql
-- 使用自定义Mapper方法 selectCashoutRecordList
SELECT scor.*, 
       IF(su.alipay_account IS NOT NULL, su.alipay_account, su.phone) AS settlement_account
FROM store_cash_out_record scor
LEFT JOIN store_user su ON su.store_id = scor.store_id AND su.delete_flag = 0
WHERE scor.store_id = ?
  AND scor.delete_flag = 0
  AND (scor.payment_status = ? OR ? IS NULL)
  AND (scor.created_time <= ? OR ? IS NULL)
  AND (scor.created_time >= ? OR ? IS NULL)
ORDER BY scor.created_time DESC
```

**SQL说明**:
- 🔔 使用 LEFT JOIN 关联 `store_user` 表获取结算账户信息
- 📌 `settlement_account` 字段逻辑：
  - 优先返回 `alipay_account`（支付宝账号）
  - 如果为空，返回 `phone`（手机号）
- 🔄 表别名：`scor` = store_cash_out_record，`su` = store_user

### 索引建议

```sql
-- store_cash_out_record 表索引
ALTER TABLE store_cash_out_record 
ADD INDEX idx_store_status_time (store_id, payment_status, created_time);

-- store_user 表索引（用于LEFT JOIN）
ALTER TABLE store_user
ADD INDEX idx_store_id_delete (store_id, delete_flag);
```

---

## 提现状态说明

### payment_status 状态值

| Status | 名称 | 描述 | 可查询 |
|--------|------|------|--------|
| 1 | 待审核 | 提现申请已提交，等待管理员审核 | ✅ |
| 2 | 审核不通过 | 管理员拒绝提现申请 | ✅ |
| 3 | 已通过 | 管理员审核通过，等待打款 | ✅ |
| 4 | 已打款 | 支付宝转账成功 | ✅ |
| 5 | 打款失败 | 支付宝转账失败 | ✅ |

### 状态流转

```
1(待审核) ──审核通过──→ 3(已通过) ──打款成功──→ 4(已打款)
    │                       │
    │                       └──打款失败──→ 5(打款失败)
    │
    └──审核拒绝──→ 2(审核不通过)
```

---

## 金额计算规则

### 金额单位转换

| 数据库存储（分） | 显示（元） | 转换公式 |
|------------------|-----------|----------|
| 50000 | 500.00 | money ÷ 100 |
| 30000 | 300.00 | money ÷ 100 |
| 80000 | 800.00 | money ÷ 100 |

### cashOutAllMoney 计算

```java
// 仅统计状态为1-待审核的记录总金额
int totalMoney = recordList.stream()
    .filter(item -> "1".equals(item.getPaymentStatus().toString()))
    .mapToInt(StoreCashOutRecord::getMoney)
    .sum();

// 转换为元（向下取整）
BigDecimal cashOutAllMoney = new BigDecimal(totalMoney)
    .divide(new BigDecimal(100), 2, RoundingMode.DOWN);
```

**说明**: 
- 🔔 **重要变更（2025-11-20）**: 仅统计 `paymentStatus = 1`（待审核）状态的记录总金额
- ⚠️ 统计的是所有符合条件且状态为待审核的记录，不是当前页
- 使用 `RoundingMode.DOWN`（向下取整）

---

## 业务场景

### 场景 1: 查询所有提现记录

**请求**:
```http
GET /incomeManage/getCashOutRecordList?storeId=103&page=1&size=10
```

**响应**:
```json
{
    "code": 200,
    "data": {
        "cashOutRecordList": [...],  // 第1页，10条记录
        "cashOutAllMoney": 500.00,   // 所有待审核记录总金额
        "cashOutNum": 25              // 所有记录总数
    }
}
```

**说明**: 
- 不传任何筛选条件，返回该门店的所有提现记录
- `cashOutAllMoney` 仅统计状态为"待审核"的记录总金额

---

### 场景 2: 查询指定时间范围

**请求**:
```http
GET /incomeManage/getCashOutRecordList?storeId=103&cashOutStartTime=2025-11-10&cashOutEndTime=2025-11-11&page=1&size=10
```

**响应**:
```json
{
    "code": 200,
    "data": {
        "cashOutRecordList": [...],
        "cashOutAllMoney": 200.00,  // 2025-11-10至2025-11-11期间待审核记录的总金额
        "cashOutNum": 5              // 期间的总记录数
    }
}
```

**说明**: 
- 只返回指定时间范围内的提现记录
- `cashOutAllMoney` 仅统计该时间范围内待审核状态的记录

---

### 场景 3: 查询待审核记录

**请求**:
```http
GET /incomeManage/getCashOutRecordList?storeId=103&paymentStatus=1&page=1&size=10
```

**响应**:
```json
{
    "code": 200,
    "data": {
        "cashOutRecordList": [...],
        "cashOutAllMoney": 300.00,  // 待审核记录总金额
        "cashOutNum": 3              // 待审核记录总数
    }
}
```

**说明**: 只返回待审核状态的提现记录，`cashOutAllMoney` 统计所有待审核记录的总金额

---

### 场景 4: 组合查询

**请求**:
```http
GET /incomeManage/getCashOutRecordList?storeId=103&cashOutStartTime=2025-11-01&cashOutEndTime=2025-11-30&paymentStatus=4&page=1&size=10
```

**响应**:
```json
{
    "code": 200,
    "data": {
        "cashOutRecordList": [...],
        "cashOutAllMoney": 0.00,     // 11月已打款记录中待审核的总金额（0元，因为已打款状态不是待审核）
        "cashOutNum": 10              // 11月已打款记录总数
    }
}
```

**说明**: 
- 查询11月已打款的提现记录
- ⚠️ **注意**: 由于 `cashOutAllMoney` 只统计待审核状态，而查询条件是已打款状态，所以 `cashOutAllMoney` 为0

---

### 场景 5: 空结果

**前置条件**: 指定条件下无记录

**请求**:
```http
GET /incomeManage/getCashOutRecordList?storeId=103&paymentStatus=5&page=1&size=10
```

**响应**:
```json
{
    "code": 200,
    "data": {
        "cashOutRecordList": [],
        "cashOutAllMoney": 0.00,
        "cashOutNum": 0
    }
}
```

---

## 分页说明

### 分页逻辑

1. **查询全部**: 首先查询所有符合条件的记录
2. **手动分页**: 使用 `ListToPage.setPage()` 进行内存分页
3. **返回当前页**: `cashOutRecordList` 只包含当前页的记录
4. **统计全部**: `cashOutNum` 统计所有记录，`cashOutAllMoney` 仅统计待审核状态的记录

### 分页参数

- **page**: 页码，从1开始
- **size**: 每页条数，默认10
- **total**: 总记录数（返回值中的 `cashOutNum`）

### 分页示例

**场景**: 共25条记录，每页10条

- **第1页** (page=1, size=10): 显示第1-10条
- **第2页** (page=2, size=10): 显示第11-20条
- **第3页** (page=3, size=10): 显示第21-25条

**统计信息**: 
- `cashOutNum = 25` （所有页的总记录数）
- `cashOutAllMoney` = 所有25条记录中待审核状态的总金额

---

## 前端集成示例

### Vue.js 示例

```javascript
export default {
    data() {
        return {
            storeId: 103,
            cashOutStartTime: '',
            cashOutEndTime: '',
            paymentStatus: '',
            page: 1,
            size: 10,
            cashOutRecordList: [],
            cashOutAllMoney: 0,
            cashOutNum: 0
        };
    },
    methods: {
        async getCashOutRecordList() {
            try {
                const params = {
                    storeId: this.storeId,
                    page: this.page,
                    size: this.size
                };
                
                // 可选参数
                if (this.cashOutStartTime) {
                    params.cashOutStartTime = this.cashOutStartTime;
                }
                if (this.cashOutEndTime) {
                    params.cashOutEndTime = this.cashOutEndTime;
                }
                if (this.paymentStatus) {
                    params.paymentStatus = this.paymentStatus;
                }
                
                const response = await this.$axios.get('/incomeManage/getCashOutRecordList', { params });
                
                if (response.data.success) {
                    const data = response.data.data;
                    this.cashOutRecordList = data.cashOutRecordList;
                    this.cashOutAllMoney = data.cashOutAllMoney;
                    this.cashOutNum = data.cashOutNum;
                }
            } catch (error) {
                console.error('查询失败:', error);
                this.$message.error('查询失败');
            }
        },
        
        // 翻页
        handlePageChange(page) {
            this.page = page;
            this.getCashOutRecordList();
        }
    },
    mounted() {
        this.getCashOutRecordList();
    }
}
```

---

### React 示例

```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';

function CashOutRecordList() {
    const [storeId] = useState(103);
    const [cashOutStartTime, setCashOutStartTime] = useState('');
    const [cashOutEndTime, setCashOutEndTime] = useState('');
    const [paymentStatus, setPaymentStatus] = useState('');
    const [page, setPage] = useState(1);
    const [size] = useState(10);
    const [data, setData] = useState({
        cashOutRecordList: [],
        cashOutAllMoney: 0,
        cashOutNum: 0
    });
    
    const getCashOutRecordList = async () => {
        try {
            const params = {
                storeId,
                page,
                size,
                ...(cashOutStartTime && { cashOutStartTime }),
                ...(cashOutEndTime && { cashOutEndTime }),
                ...(paymentStatus && { paymentStatus })
            };
            
            const response = await axios.get('/incomeManage/getCashOutRecordList', { params });
            
            if (response.data.success) {
                setData(response.data.data);
            }
        } catch (error) {
            console.error('查询失败:', error);
        }
    };
    
    useEffect(() => {
        getCashOutRecordList();
    }, [page, cashOutStartTime, cashOutEndTime, paymentStatus]);
    
    return (
        <div>
            <h2>提现记录</h2>
            <p>总记录数: {data.cashOutNum}</p>
            <p>总金额: ¥{data.cashOutAllMoney}</p>
            
            <ul>
                {data.cashOutRecordList.map(record => (
                    <li key={record.id}>
                        订单号: {record.orderNo} - 金额: ¥{(record.money / 100).toFixed(2)} - 状态: {record.paymentStatus}
                    </li>
                ))}
            </ul>
        </div>
    );
}
```

---

## 测试用例

### 测试场景1: 正常查询

**请求**:
```http
GET /incomeManage/getCashOutRecordList?storeId=103&page=1&size=10
```

**预期结果**:
- 返回提现记录列表
- 包含统计信息（总金额、总数）
- 按创建时间倒序排序

---

### 测试场景2: 时间范围查询

**请求**:
```http
GET /incomeManage/getCashOutRecordList?storeId=103&cashOutStartTime=2025-11-10&cashOutEndTime=2025-11-11
```

**预期结果**:
- 只返回2025-11-10至2025-11-11的记录
- 包含这两天 00:00:00 到 23:59:59 的记录

---

### 测试场景3: 状态筛选

**请求**:
```http
GET /incomeManage/getCashOutRecordList?storeId=103&paymentStatus=1
```

**预期结果**:
- 只返回待审核状态的记录
- 其他状态的记录不返回

---

### 测试场景4: 空结果

**请求**:
```http
GET /incomeManage/getCashOutRecordList?storeId=999999&page=1&size=10
```

**预期结果**:
```json
{
    "cashOutRecordList": [],
    "cashOutAllMoney": 0.00,
    "cashOutNum": 0
}
```

---

### 测试场景5: 分页测试

**前置条件**: 共25条记录

**请求**:
```http
GET /incomeManage/getCashOutRecordList?storeId=103&page=3&size=10
```

**预期结果**:
- 返回第21-25条记录（5条）
- `cashOutNum` 仍为25
- `cashOutAllMoney` 为所有25条记录中待审核状态的总金额

---

## 注意事项

### 1. 时间范围

- ⚠️ **时间格式**: 必须是 `yyyy-MM-dd`
- ⚠️ **开始时间**: 自动补充 `00:00:00`
- ⚠️ **结束时间**: 自动补充 `23:59:59`
- ⚠️ **时区**: 使用服务器时区

### 2. 分页逻辑

- ⚠️ **查询全部**: 先查询所有符合条件的记录
- ⚠️ **内存分页**: 在内存中进行分页
- ⚠️ **性能考虑**: 大数据量时可能影响性能
- ⚠️ **统计准确**: `cashOutNum` 统计所有记录，`cashOutAllMoney` 仅统计待审核状态

### 3. 金额单位

- ⚠️ **数据库**: 分（Integer）
- ⚠️ **接口返回**: 元（BigDecimal，保留2位小数）
- ⚠️ **舍入模式**: DOWN（向下取整）

### 4. 提现状态

- ⚠️ **状态值**: 字符串类型
- ⚠️ **可选参数**: 不传则查询所有状态
- ⚠️ **多状态**: 目前不支持，需多次调用

### 5. 查询性能

- ⚠️ **索引**: 确保有合适的索引
- ⚠️ **数据量**: 建议限制时间范围
- ⚠️ **缓存**: 考虑使用Redis缓存热点数据

---

## 性能优化建议

### 1. 数据库索引

```sql
-- 推荐的复合索引
ALTER TABLE store_cash_out_record 
ADD INDEX idx_store_status_time (store_id, payment_status, created_time);

-- 好处：
-- 1. 覆盖最常用的查询条件
-- 2. 支持排序优化
-- 3. 提升查询速度
```

### 2. 分页优化

**现状**: 内存分页（查全部->分页）

**优化方案**:
```java
// 使用MyBatis-Plus的分页插件
IPage<StoreCashOutRecord> page = new Page<>(pageNum, pageSize);
IPage<StoreCashOutRecord> result = storeCashOutRecordMapper.selectPage(page, wrapper);
```

**优点**:
- 数据库层面分页
- 只查询当前页数据
- 性能更好

### 3. 缓存策略

```java
// Redis缓存热点数据
@Cacheable(value = "cashOutRecordList", 
           key = "#storeId + ':' + #page + ':' + #size")
public Object getCashOutRecordList(...) {
    // ...
}
```

---

## 迁移说明

### 原接口（app端）

- **服务**: `alien-store`
- **路径**: `/alienStore/storeCashOutRecord/getCashOutRecordList`
- **Controller**: `StoreCashOutRecordController`
- **Service**: `StoreCashOutRecordService.getCashOutRecordList()`

### 新接口（web端）

- **服务**: `alien-store-platform`
- **路径**: `/incomeManage/getCashOutRecordList`
- **Controller**: `IncomeManageController`
- **Service**: `IncomeManageService.getCashOutRecordList()`

### 差异说明

| 项目 | app端 | web端 | 说明 |
|------|-------|-------|------|
| 接口路径 | `/getCashOutRecordList` | `/getCashOutRecordList` | 保持一致 |
| 请求方式 | GET | GET | 保持一致 |
| 参数名称 | 一致 | 一致 | 完全相同 |
| 返回格式 | StoreCashOutRecordVo | StoreCashOutRecordVo | 保持一致 |
| 业务逻辑 | ✅ | ✅ | 完全复用 |
| 登录验证 | ❌ 无 | ✅ 有 | 增加验证 |
| 日志记录 | 基础 | 详细 | 增强日志 |

### 复用的核心组件

1. **Mapper**: 
   - `StoreCashOutRecordMapper.selectCashoutRecordList()` - 自定义查询方法，LEFT JOIN store_user
2. **Entity**: 
   - `StoreCashOutRecord` - 提现记录实体（包含 settlementAccount 字段）
   - `StoreCashOutRecordVo` - 提现记录VO
3. **Util**: 
   - `ListToPage` - 手动分页工具

### 自定义Mapper SQL

```java
@Select("select scor.*, If(su.alipay_account is not null,su.alipay_account,su.phone) settlementAccount\n" +
        "from store_cash_out_record scor\n" +
        "left join store_user su on su.store_id = scor.store_id and su.delete_flag = 0\n" +
        "${ew.customSqlSegment}")
List<StoreCashOutRecord> selectCashoutRecordList(@Param(Constants.WRAPPER) QueryWrapper<StoreCashOutRecord> wrapper);
```

**说明**:
- 使用 `@Select` 注解定义SQL
- LEFT JOIN `store_user` 获取结算账户
- `${ew.customSqlSegment}` 动态拼接WHERE、ORDER BY等条件

---

## 常见问题

### Q1: cashOutAllMoney 是当前页还是所有记录的总金额？

**答案**: 所有符合条件且状态为"待审核"（paymentStatus=1）记录的总金额，不是当前页。

**注意**: 从2025-11-20开始，只统计待审核状态的提现金额，与app端逻辑保持一致。

---

### Q2: 如何查询多个状态的记录？

**答案**: 目前不支持，需要多次调用接口分别查询。

---

### Q3: 时间参数必须都传吗？

**答案**: 不需要。可以只传开始时间、只传结束时间，或都不传。

---

### Q4: 分页是数据库分页还是内存分页？

**答案**: 内存分页。先查询所有记录，再在内存中分页。

---

### Q5: 如何获取总页数？

**答案**: `totalPages = Math.ceil(cashOutNum / size)`

---

### Q6: 金额为什么使用DOWN舍入模式？

**答案**: 向下取整更保守，避免显示金额大于实际金额。

---

### Q7: settlementAccount 是什么？如何获取的？

**答案**: 
- **settlementAccount** 是结算账户，用于显示商户的提现账户信息
- 获取逻辑：
  1. 通过 LEFT JOIN `store_user` 表查询
  2. 优先使用 `alipay_account`（支付宝账号）
  3. 如果支付宝账号为空，使用 `phone`（手机号）
- SQL: `IF(su.alipay_account IS NOT NULL, su.alipay_account, su.phone)`

---

### Q8: 为什么要用 QueryWrapper 而不是 LambdaQueryWrapper？

**答案**: 
- `selectCashoutRecordList` 是自定义Mapper方法，使用了表别名（`scor`）
- 需要使用 `QueryWrapper` 配合字符串字段名（如 `"scor.store_id"`）
- `LambdaQueryWrapper` 无法使用表别名

---

## 更新日志

### 2025-11-20

**逻辑更新（重要）**:
- 🔄 修改查询方法，使用 `selectCashoutRecordList` 代替 `selectList`
- ✅ 添加 LEFT JOIN `store_user` 表，获取结算账户信息（`settlementAccount`）
- ✅ 修改 `QueryWrapper` 使用表别名 `scor`（以配合自定义SQL）
- ✅ 添加 `delete_flag = 0` 条件（软删除过滤）
- 🔄 修改 `cashOutAllMoney` 计算逻辑，仅统计 `paymentStatus = 1`（待审核）状态的记录

**变更原因**:
- 同步app端完整业务逻辑
- 提现记录需要显示结算账户信息（支付宝账号或手机号）
- 需要过滤已删除的记录

**影响范围**:
- 响应字段新增 `settlementAccount`（结算账户）
- 查询会关联 `store_user` 表，可能影响性能（建议添加索引）
- `cashOutAllMoney` 仅统计待审核状态的提现总金额

**涉及文件**:
- `IncomeManageServiceImpl.java` - 更新 `getCashOutRecordList` 方法（line 352-390）
- `StoreCashOutRecordMapper.java` - 使用 `selectCashoutRecordList` 方法

---

### 2025-11-19

**新增接口**:
- ✅ `GET /incomeManage/getCashOutRecordList` - 提现记录查询

**核心功能**:
- ✅ 按门店ID查询提现记录
- ✅ 支持时间范围筛选
- ✅ 支持提现状态筛选
- ✅ 分页查询
- ✅ 统计总金额和总数
- ✅ 按创建时间倒序排序
- ✅ 详细日志记录
- ✅ 完善异常处理

**涉及文件**:
- `IncomeManageController.java` - 更新
- `IncomeManageService.java` - 更新
- `IncomeManageServiceImpl.java` - 更新

**代码质量**:
- ✅ Linter检查：无错误
- ✅ 日志记录：详细
- ✅ 异常处理：完善
- ✅ 代码注释：完整

**与原接口一致性**:
- ✅ 请求参数：完全相同
- ✅ 返回格式：完全相同
- ✅ 业务逻辑：完全复用

**开发人员**: ssk

---

**文档版本**: v1.0  
**最后更新**: 2025-11-19  
**维护人员**: ssk



