本模块提供提现记录查询功能,支持按时间范围、提现状态等条件筛选提现记录,并提供分页查询和统计信息。
GET /incomeManage/getCashOutRecordList@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 |
1: 待审核2: 审核不通过3: 已通过4: 已打款5: 打款失败GET /incomeManage/getCashOutRecordList?storeId=103&page=1&size=10
curl "http://localhost:8080/incomeManage/getCashOutRecordList?storeId=103&page=1&size=10" \
-H "Authorization: Bearer YOUR_TOKEN"
GET /incomeManage/getCashOutRecordList?storeId=103&cashOutStartTime=2025-11-10&cashOutEndTime=2025-11-11&page=1&size=10
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"
GET /incomeManage/getCashOutRecordList?storeId=103&paymentStatus=1&page=1&size=10
curl "http://localhost:8080/incomeManage/getCashOutRecordList?storeId=103&paymentStatus=1&page=1&size=10" \
-H "Authorization: Bearer YOUR_TOKEN"
GET /incomeManage/getCashOutRecordList?storeId=103&cashOutStartTime=2025-11-10&cashOutEndTime=2025-11-11&paymentStatus=4&page=1&size=10
{
"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 | 提现记录总数 |
| 字段名 | 类型 | 说明 |
|---|---|---|
| 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){
"code": 500,
"success": false,
"data": null,
"msg": "查询失败:门店ID不能为空"
}
{
"code": 500,
"success": false,
"data": null,
"msg": "请先登录"
}
{
"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. 返回结果 │
│ 返回分页数据和统计信息 │
└─────────────────────────────────────────────┘
-- 使用自定义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说明:
store_user 表获取结算账户信息settlement_account 字段逻辑:
alipay_account(支付宝账号)phone(手机号)scor = store_cash_out_record,su = store_user-- 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);
| 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 |
// 仅统计状态为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);
说明:
paymentStatus = 1(待审核)状态的记录总金额RoundingMode.DOWN(向下取整)请求:
GET /incomeManage/getCashOutRecordList?storeId=103&page=1&size=10
响应:
{
"code": 200,
"data": {
"cashOutRecordList": [...], // 第1页,10条记录
"cashOutAllMoney": 500.00, // 所有待审核记录总金额
"cashOutNum": 25 // 所有记录总数
}
}
说明:
cashOutAllMoney 仅统计状态为"待审核"的记录总金额请求:
GET /incomeManage/getCashOutRecordList?storeId=103&cashOutStartTime=2025-11-10&cashOutEndTime=2025-11-11&page=1&size=10
响应:
{
"code": 200,
"data": {
"cashOutRecordList": [...],
"cashOutAllMoney": 200.00, // 2025-11-10至2025-11-11期间待审核记录的总金额
"cashOutNum": 5 // 期间的总记录数
}
}
说明:
cashOutAllMoney 仅统计该时间范围内待审核状态的记录请求:
GET /incomeManage/getCashOutRecordList?storeId=103&paymentStatus=1&page=1&size=10
响应:
{
"code": 200,
"data": {
"cashOutRecordList": [...],
"cashOutAllMoney": 300.00, // 待审核记录总金额
"cashOutNum": 3 // 待审核记录总数
}
}
说明: 只返回待审核状态的提现记录,cashOutAllMoney 统计所有待审核记录的总金额
请求:
GET /incomeManage/getCashOutRecordList?storeId=103&cashOutStartTime=2025-11-01&cashOutEndTime=2025-11-30&paymentStatus=4&page=1&size=10
响应:
{
"code": 200,
"data": {
"cashOutRecordList": [...],
"cashOutAllMoney": 0.00, // 11月已打款记录中待审核的总金额(0元,因为已打款状态不是待审核)
"cashOutNum": 10 // 11月已打款记录总数
}
}
说明:
cashOutAllMoney 只统计待审核状态,而查询条件是已打款状态,所以 cashOutAllMoney 为0前置条件: 指定条件下无记录
请求:
GET /incomeManage/getCashOutRecordList?storeId=103&paymentStatus=5&page=1&size=10
响应:
{
"code": 200,
"data": {
"cashOutRecordList": [],
"cashOutAllMoney": 0.00,
"cashOutNum": 0
}
}
ListToPage.setPage() 进行内存分页cashOutRecordList 只包含当前页的记录cashOutNum 统计所有记录,cashOutAllMoney 仅统计待审核状态的记录cashOutNum)场景: 共25条记录,每页10条
统计信息:
cashOutNum = 25 (所有页的总记录数)cashOutAllMoney = 所有25条记录中待审核状态的总金额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();
}
}
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>
);
}
请求:
GET /incomeManage/getCashOutRecordList?storeId=103&page=1&size=10
预期结果:
请求:
GET /incomeManage/getCashOutRecordList?storeId=103&cashOutStartTime=2025-11-10&cashOutEndTime=2025-11-11
预期结果:
请求:
GET /incomeManage/getCashOutRecordList?storeId=103&paymentStatus=1
预期结果:
请求:
GET /incomeManage/getCashOutRecordList?storeId=999999&page=1&size=10
预期结果:
{
"cashOutRecordList": [],
"cashOutAllMoney": 0.00,
"cashOutNum": 0
}
前置条件: 共25条记录
请求:
GET /incomeManage/getCashOutRecordList?storeId=103&page=3&size=10
预期结果:
cashOutNum 仍为25cashOutAllMoney 为所有25条记录中待审核状态的总金额yyyy-MM-dd00:00:0023:59:59cashOutNum 统计所有记录,cashOutAllMoney 仅统计待审核状态-- 推荐的复合索引
ALTER TABLE store_cash_out_record
ADD INDEX idx_store_status_time (store_id, payment_status, created_time);
-- 好处:
-- 1. 覆盖最常用的查询条件
-- 2. 支持排序优化
-- 3. 提升查询速度
现状: 内存分页(查全部->分页)
优化方案:
// 使用MyBatis-Plus的分页插件
IPage<StoreCashOutRecord> page = new Page<>(pageNum, pageSize);
IPage<StoreCashOutRecord> result = storeCashOutRecordMapper.selectPage(page, wrapper);
优点:
// Redis缓存热点数据
@Cacheable(value = "cashOutRecordList",
key = "#storeId + ':' + #page + ':' + #size")
public Object getCashOutRecordList(...) {
// ...
}
alien-store/alienStore/storeCashOutRecord/getCashOutRecordListStoreCashOutRecordControllerStoreCashOutRecordService.getCashOutRecordList()alien-store-platform/incomeManage/getCashOutRecordListIncomeManageControllerIncomeManageService.getCashOutRecordList()| 项目 | app端 | web端 | 说明 |
|---|---|---|---|
| 接口路径 | /getCashOutRecordList |
/getCashOutRecordList |
保持一致 |
| 请求方式 | GET | GET | 保持一致 |
| 参数名称 | 一致 | 一致 | 完全相同 |
| 返回格式 | StoreCashOutRecordVo | StoreCashOutRecordVo | 保持一致 |
| 业务逻辑 | ✅ | ✅ | 完全复用 |
| 登录验证 | ❌ 无 | ✅ 有 | 增加验证 |
| 日志记录 | 基础 | 详细 | 增强日志 |
StoreCashOutRecordMapper.selectCashoutRecordList() - 自定义查询方法,LEFT JOIN store_userStoreCashOutRecord - 提现记录实体(包含 settlementAccount 字段)StoreCashOutRecordVo - 提现记录VOListToPage - 手动分页工具@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 注解定义SQLstore_user 获取结算账户${ew.customSqlSegment} 动态拼接WHERE、ORDER BY等条件答案: 所有符合条件且状态为"待审核"(paymentStatus=1)记录的总金额,不是当前页。
注意: 从2025-11-20开始,只统计待审核状态的提现金额,与app端逻辑保持一致。
答案: 目前不支持,需要多次调用接口分别查询。
答案: 不需要。可以只传开始时间、只传结束时间,或都不传。
答案: 内存分页。先查询所有记录,再在内存中分页。
答案: totalPages = Math.ceil(cashOutNum / size)
答案: 向下取整更保守,避免显示金额大于实际金额。
答案:
store_user 表查询alipay_account(支付宝账号)phone(手机号)IF(su.alipay_account IS NOT NULL, su.alipay_account, su.phone)答案:
selectCashoutRecordList 是自定义Mapper方法,使用了表别名(scor)QueryWrapper 配合字符串字段名(如 "scor.store_id")LambdaQueryWrapper 无法使用表别名逻辑更新(重要):
selectCashoutRecordList 代替 selectListstore_user 表,获取结算账户信息(settlementAccount)QueryWrapper 使用表别名 scor(以配合自定义SQL)delete_flag = 0 条件(软删除过滤)cashOutAllMoney 计算逻辑,仅统计 paymentStatus = 1(待审核)状态的记录变更原因:
影响范围:
settlementAccount(结算账户)store_user 表,可能影响性能(建议添加索引)cashOutAllMoney 仅统计待审核状态的提现总金额涉及文件:
IncomeManageServiceImpl.java - 更新 getCashOutRecordList 方法(line 352-390)StoreCashOutRecordMapper.java - 使用 selectCashoutRecordList 方法新增接口:
GET /incomeManage/getCashOutRecordList - 提现记录查询核心功能:
涉及文件:
IncomeManageController.java - 更新IncomeManageService.java - 更新IncomeManageServiceImpl.java - 更新代码质量:
与原接口一致性:
开发人员: ssk
文档版本: v1.0
最后更新: 2025-11-19
维护人员: ssk