本接口提供收入数据的汇总统计功能,一次性返回可提现金额、今日收益、已入账总数、未入账总数四项关键数据,方便前端首页展示。
GET /incomeManage/getIncomeSummary本接口整合了以下三个app端接口的数据:
| 数据项 | app端接口 | 业务逻辑 |
|---|---|---|
| 可提现金额 | /alienStore/storeIncomeDetailsRecord/accountBalance |
4-27天内未绑定提现的收入 - 待审核/已通过的提现金额 |
| 今日收益 | /alienStore/storeIncomeDetailsRecord/todayIncome |
当天00:00:00 ~ 23:59:59的收入总和 |
| 未入账 | /alienStore/storeIncomeDetailsRecord/noYetPayment?paymentType=0 |
近3天内未绑定提现的收入 |
| 已入账 | /alienStore/storeIncomeDetailsRecord/noYetPayment?paymentType=1 |
4-27天内的收入 |
// 查询4-27天内未绑定提现记录的收入
cashOutMoney = SUM(money WHERE created_time BETWEEN (NOW() - 27天) AND (NOW() - 4天)
AND cash_out_id IS NULL)
// 减去待审核和已通过的提现金额
totalCashOutAmount = SUM(money WHERE payment_status IN (1, 3) AND delete_flag = 0)
// 可提现金额
cashOutMoney = cashOutMoney - totalCashOutAmount
说明:
// 查询今天的收入总和
todayIncome = SUM(money WHERE created_time BETWEEN '今日 00:00:00' AND '今日 23:59:59')
说明:
// 查询近3天未绑定提现的收入
notPaidMoney = SUM(money WHERE created_time > (NOW() - 3天)
AND cash_out_id IS NULL)
notPaidCount = COUNT(*)
说明:
// 查询4-27天前的收入
paidMoney = SUM(money WHERE created_time BETWEEN (NOW() - 27天) AND (NOW() - 4天))
paidCount = COUNT(*)
说明:
无参数
从 JWT token 自动获取店铺ID(storeId)
GET /incomeManage/getIncomeSummary
Headers:
Authorization: Bearer YOUR_JWT_TOKEN
curl -X GET "http://localhost:8080/incomeManage/getIncomeSummary" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
{
"code": 200,
"success": true,
"data": {
"balance": "3580.50",
"cashOutMoney": "1256.80",
"todayIncome": "128.30",
"notPaidMoney": "385.60",
"notPaidCount": 12,
"notPaidDateRange": "2025-11-18 ~ 2025-11-21",
"paidMoney": "1580.20",
"paidCount": 45,
"paidDateRange": "2025-10-25 ~ 2025-11-17"
},
"msg": "操作成功"
}
| 字段名 | 类型 | 说明 |
|---|---|---|
| code | Integer | 状态码(200-成功) |
| success | Boolean | 是否成功 |
| data | Object | 汇总数据 |
| msg | String | 提示信息 |
| 字段名 | 类型 | 单位 | 说明 |
|---|---|---|---|
| balance | String | 元 | 账户总余额 |
| cashOutMoney | String | 元 | 可提现金额(4-27天内可提现的收入) |
| todayIncome | String | 元 | 今日收益(当天所有收入) |
| notPaidMoney | String | 元 | 未入账金额(近3天的收入) |
| notPaidCount | Integer | 条 | 未入账记录数 |
| notPaidDateRange | String | - | 未入账时间范围 |
| paidMoney | String | 元 | 已入账金额(4-27天的收入) |
| paidCount | Integer | 条 | 已入账记录数 |
| paidDateRange | String | - | 已入账时间范围 |
{
"code": 500,
"success": false,
"data": null,
"msg": "请先登录"
}
{
"code": 500,
"success": false,
"data": null,
"msg": "查询失败:{异常信息}"
}
业务需求: 商户登录后,首页需要展示收入概况的关键数据
请求:
GET /incomeManage/getIncomeSummary
Headers:
Authorization: Bearer VALID_TOKEN
响应:
{
"code": 200,
"success": true,
"data": {
"balance": "3580.50",
"cashOutMoney": "1256.80",
"todayIncome": "128.30",
"notPaidMoney": "385.60",
"notPaidCount": 12,
"paidMoney": "1580.20",
"paidCount": 45
}
}
前端展示:
┌────────────────────────────────────────┐
│ 收入概况 │
├────────────────────────────────────────┤
│ 账户余额: ¥3,580.50 │
│ 可提现金额: ¥1,256.80 │
│ 今日收益: ¥128.30 │
│ │
│ 未入账: ¥385.60 (12笔) │
│ 已入账: ¥1,580.20 (45笔) │
└────────────────────────────────────────┘
业务需求: 用户下拉刷新或手动刷新收入数据
请求:
GET /incomeManage/getIncomeSummary
Headers:
Authorization: Bearer VALID_TOKEN
业务逻辑:
业务需求: 前端每隔一定时间自动刷新数据
实现方式:
setInterval(() => {
fetchIncomeSummary();
}, 60000); // 每分钟刷新一次
账户余额 (balance)
= 历史所有收入 - 已提现金额
可提现金额 (cashOutMoney)
= 4-27天内未绑定提现的收入
- 待审核的提现金额
- 已通过的提现金额
今日收益 (todayIncome)
= 今天所有收入
未入账 (notPaidMoney)
= 近3天未绑定提现的收入
(还未到提现账期)
已入账 (paidMoney)
= 4-27天的收入
(已到提现账期,可以提现)
时间轴: ←────────────────────────────────→
-27天 -4天 -3天 今天
已入账: ├─────┤
4-27天
未入账: ├──┤
3天内
今日收益: │
今天
export default {
data() {
return {
summary: {
balance: '0.00',
cashOutMoney: '0.00',
todayIncome: '0.00',
notPaidMoney: '0.00',
notPaidCount: 0,
paidMoney: '0.00',
paidCount: 0,
notPaidDateRange: '',
paidDateRange: ''
},
loading: false
};
},
methods: {
async fetchIncomeSummary() {
this.loading = true;
try {
const response = await this.$axios.get('/incomeManage/getIncomeSummary');
if (response.data.success) {
this.summary = response.data.data;
this.$message.success('数据加载成功');
} else {
this.$message.error(response.data.msg);
}
} catch (error) {
console.error('查询失败:', error);
this.$message.error('数据加载失败,请稍后重试');
} finally {
this.loading = false;
}
},
// 格式化金额显示
formatMoney(amount) {
return '¥' + parseFloat(amount).toLocaleString('zh-CN', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
},
// 下拉刷新
onRefresh() {
this.fetchIncomeSummary();
}
},
mounted() {
this.fetchIncomeSummary();
// 每分钟自动刷新
this.timer = setInterval(() => {
this.fetchIncomeSummary();
}, 60000);
},
beforeDestroy() {
if (this.timer) {
clearInterval(this.timer);
}
}
}
import { useState, useEffect } from 'react';
import axios from 'axios';
import { Card, Statistic, Row, Col, Spin } from 'antd';
import { WalletOutlined, DollarOutlined, RiseOutlined } from '@ant-design/icons';
function IncomeSummary() {
const [summary, setSummary] = useState({
balance: '0.00',
cashOutMoney: '0.00',
todayIncome: '0.00',
notPaidMoney: '0.00',
notPaidCount: 0,
paidMoney: '0.00',
paidCount: 0
});
const [loading, setLoading] = useState(false);
const fetchData = async () => {
setLoading(true);
try {
const response = await axios.get('/incomeManage/getIncomeSummary');
if (response.data.success) {
setSummary(response.data.data);
}
} catch (error) {
console.error('查询失败:', error);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchData();
// 每分钟自动刷新
const timer = setInterval(fetchData, 60000);
return () => clearInterval(timer);
}, []);
return (
<Spin spinning={loading}>
<Row gutter={16}>
<Col span={6}>
<Card>
<Statistic
title="账户余额"
value={summary.balance}
prefix="¥"
precision={2}
valueStyle={{ color: '#3f8600' }}
suffix={<WalletOutlined />}
/>
</Card>
</Col>
<Col span={6}>
<Card>
<Statistic
title="可提现金额"
value={summary.cashOutMoney}
prefix="¥"
precision={2}
valueStyle={{ color: '#cf1322' }}
suffix={<DollarOutlined />}
/>
</Card>
</Col>
<Col span={6}>
<Card>
<Statistic
title="今日收益"
value={summary.todayIncome}
prefix="¥"
precision={2}
valueStyle={{ color: '#1890ff' }}
suffix={<RiseOutlined />}
/>
</Card>
</Col>
<Col span={6}>
<Card>
<Statistic
title="未入账"
value={summary.notPaidMoney}
prefix="¥"
precision={2}
suffix={`(${summary.notPaidCount}笔)`}
/>
</Card>
</Col>
</Row>
<Row gutter={16} style={{ marginTop: 16 }}>
<Col span={12}>
<Card>
<Statistic
title="已入账"
value={summary.paidMoney}
prefix="¥"
precision={2}
suffix={`(${summary.paidCount}笔)`}
/>
<p style={{ marginTop: 8, color: '#999' }}>
{summary.paidDateRange}
</p>
</Card>
</Col>
</Row>
</Spin>
);
}
前置条件:
执行步骤:
GET /incomeManage/getIncomeSummary预期结果:
balance > 0cashOutMoney >= 0todayIncome >= 0notPaidMoney >= 0, notPaidCount >= 0paidMoney >= 0, paidCount >= 0前置条件:
执行步骤:
GET /incomeManage/getIncomeSummary预期结果:
前置条件:
执行步骤:
GET /incomeManage/getIncomeSummary预期结果:
todayIncome > 0notPaidMoney > 0(今天的收入也在3天内)paidMoney = 0(没有4-27天前的收入)答案:
答案: 会的。
答案:
答案: 不一定。
答案:
@Cacheable(value = "incomeSummary", key = "#storeId", unless = "#result == null")
public Map<String, Object> getIncomeSummary(Integer storeId) {
// ... 查询逻辑
}
配置:
spring:
cache:
type: redis
redis:
time-to-live: 300000 # 5分钟过期
// 使用CompletableFuture并行查询
CompletableFuture<String> balanceFuture = CompletableFuture.supplyAsync(() -> getBalance(storeId));
CompletableFuture<String> todayIncomeFuture = CompletableFuture.supplyAsync(() -> getTodayIncome(storeId));
CompletableFuture<Map> notPaidFuture = CompletableFuture.supplyAsync(() -> getNotPaidData(storeId));
CompletableFuture<Map> paidFuture = CompletableFuture.supplyAsync(() -> getPaidData(storeId));
// 等待所有查询完成
CompletableFuture.allOf(balanceFuture, todayIncomeFuture, notPaidFuture, paidFuture).join();
新增接口:
GET /incomeManage/getIncomeSummary - 收入汇总统计核心功能:
数据来源:
/accountBalance - 可提现金额/todayIncome - 今日收益/noYetPayment - 已入账/未入账涉及文件:
IncomeManageController.java - 新增 getIncomeSummary 接口IncomeManageService.java - 新增方法定义IncomeManageServiceImpl.java - 新增方法实现代码质量:
开发人员: ssk
文档版本: v1.0
最后更新: 2025-11-21
维护人员: ssk