# Web端商户收入汇总统计接口文档
## 模块概述
本接口提供收入数据的汇总统计功能,一次性返回可提现金额、今日收益、已入账总数、未入账总数四项关键数据,方便前端首页展示。
---
## 接口信息
### 收入汇总统计
#### 接口详情
- **接口名称**: 收入汇总统计
- **接口路径**: `GET /incomeManage/getIncomeSummary`
- **请求方式**: GET
- **接口描述**: 一次性查询可提现金额、今日收益、已入账金额/数量、未入账金额/数量
- **登录验证**: ✅ 需要(通过 JWT token 自动获取店铺ID)
- **数据来源**: 复用三个现有接口的业务逻辑
---
## 业务逻辑说明
### 数据来源接口
本接口整合了以下三个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天内的收入 |
---
### 数据计算规则
#### **1. 可提现金额**
```java
// 查询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
```
**说明**:
- ✅ 只统计4-27天前的收入(已到提现账期)
- ✅ 减去已申请但未到账的提现金额
- ✅ payment_status: 1-待审核, 3-已通过
---
#### **2. 今日收益**
```java
// 查询今天的收入总和
todayIncome = SUM(money WHERE created_time BETWEEN '今日 00:00:00' AND '今日 23:59:59')
```
**说明**:
- ✅ 统计当天所有收入
- ✅ 包含所有收入类型(优惠券、代金券、团购券等)
---
#### **3. 未入账(近3天)**
```java
// 查询近3天未绑定提现的收入
notPaidMoney = SUM(money WHERE created_time > (NOW() - 3天)
AND cash_out_id IS NULL)
notPaidCount = COUNT(*)
```
**说明**:
- ✅ 统计近3天的收入
- ✅ 未绑定提现记录
- ✅ 还未到提现账期
---
#### **4. 已入账(4-27天)**
```java
// 查询4-27天前的收入
paidMoney = SUM(money WHERE created_time BETWEEN (NOW() - 27天) AND (NOW() - 4天))
paidCount = COUNT(*)
```
**说明**:
- ✅ 统计4-27天前的收入
- ✅ 已到提现账期
- ✅ 可以申请提现
---
## 请求参数
**无参数**
从 JWT token 自动获取店铺ID(`storeId`)
---
## 请求示例
```http
GET /incomeManage/getIncomeSummary
Headers:
Authorization: Bearer YOUR_JWT_TOKEN
```
```bash
curl -X GET "http://localhost:8080/incomeManage/getIncomeSummary" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
```
---
## 响应参数
### 成功响应
```json
{
"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 | 提示信息 |
#### data 字段详细说明
| 字段名 | 类型 | 单位 | 说明 |
|--------|------|------|------|
| **balance** | String | 元 | 账户总余额 |
| **cashOutMoney** | String | 元 | 可提现金额(4-27天内可提现的收入) |
| **todayIncome** | String | 元 | 今日收益(当天所有收入) |
| **notPaidMoney** | String | 元 | 未入账金额(近3天的收入) |
| **notPaidCount** | Integer | 条 | 未入账记录数 |
| **notPaidDateRange** | String | - | 未入账时间范围 |
| **paidMoney** | String | 元 | 已入账金额(4-27天的收入) |
| **paidCount** | Integer | 条 | 已入账记录数 |
| **paidDateRange** | String | - | 已入账时间范围 |
---
### 失败响应
#### 1. 未登录或 token 无效
```json
{
"code": 500,
"success": false,
"data": null,
"msg": "请先登录"
}
```
#### 2. 查询异常
```json
{
"code": 500,
"success": false,
"data": null,
"msg": "查询失败:{异常信息}"
}
```
---
## 业务场景
### 场景 1: 首页数据展示
**业务需求**: 商户登录后,首页需要展示收入概况的关键数据
**请求**:
```http
GET /incomeManage/getIncomeSummary
Headers:
Authorization: Bearer VALID_TOKEN
```
**响应**:
```json
{
"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笔) │
└────────────────────────────────────────┘
```
---
### 场景 2: 数据刷新
**业务需求**: 用户下拉刷新或手动刷新收入数据
**请求**:
```http
GET /incomeManage/getIncomeSummary
Headers:
Authorization: Bearer VALID_TOKEN
```
**业务逻辑**:
- ✅ 重新计算所有统计数据
- ✅ 返回最新的收入概况
- ✅ 前端更新展示
---
### 场景 3: 定时刷新
**业务需求**: 前端每隔一定时间自动刷新数据
**实现方式**:
```javascript
setInterval(() => {
fetchIncomeSummary();
}, 60000); // 每分钟刷新一次
```
---
## 数据关系说明
### 金额之间的关系
```
账户余额 (balance)
= 历史所有收入 - 已提现金额
可提现金额 (cashOutMoney)
= 4-27天内未绑定提现的收入
- 待审核的提现金额
- 已通过的提现金额
今日收益 (todayIncome)
= 今天所有收入
未入账 (notPaidMoney)
= 近3天未绑定提现的收入
(还未到提现账期)
已入账 (paidMoney)
= 4-27天的收入
(已到提现账期,可以提现)
```
---
### 时间范围关系
```
时间轴: ←────────────────────────────────→
-27天 -4天 -3天 今天
已入账: ├─────┤
4-27天
未入账: ├──┤
3天内
今日收益: │
今天
```
---
## 前端集成示例
### Vue.js 示例
```javascript
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);
}
}
}
```
---
### React 示例
```javascript
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 (
}
/>
}
/>
}
/>
{summary.paidDateRange}
);
}
```
---
## 测试用例
### 测试场景1: 正常查询
**前置条件**:
- 用户已登录
- 店铺ID=103
- 有收入记录
**执行步骤**:
1. 发送请求: `GET /incomeManage/getIncomeSummary`
**预期结果**:
- 返回成功
- `balance` > 0
- `cashOutMoney` >= 0
- `todayIncome` >= 0
- `notPaidMoney` >= 0, `notPaidCount` >= 0
- `paidMoney` >= 0, `paidCount` >= 0
- 包含时间范围字段
---
### 测试场景2: 无收入记录
**前置条件**:
- 用户已登录
- 新店铺,无任何收入
**执行步骤**:
1. 发送请求: `GET /incomeManage/getIncomeSummary`
**预期结果**:
- 返回成功
- 所有金额字段 = "0.00"
- 所有数量字段 = 0
---
### 测试场景3: 只有今日收入
**前置条件**:
- 用户已登录
- 只有今天有收入记录
**执行步骤**:
1. 发送请求: `GET /incomeManage/getIncomeSummary`
**预期结果**:
- `todayIncome` > 0
- `notPaidMoney` > 0(今天的收入也在3天内)
- `paidMoney` = 0(没有4-27天前的收入)
---
## 常见问题
### Q1: 为什么可提现金额比已入账金额少?
**答案**:
- 可提现金额 = 已入账金额 - 待审核的提现 - 已通过的提现
- 如果有提现申请在审核中或已通过,会从可提现金额中扣除
---
### Q2: 今日收益会计入未入账吗?
**答案**: 会的。
- 今日收益统计当天所有收入
- 未入账统计近3天的收入(包括今天)
- 所以今日收益会包含在未入账中
---
### Q3: 账户余额和可提现金额有什么区别?
**答案**:
- **账户余额**: 所有历史收入 - 已提现金额(总余额)
- **可提现金额**: 4-27天内可以立即提现的金额(扣除审核中的提现)
---
### Q4: 已入账的收入一定可以提现吗?
**答案**: 不一定。
- 已入账 = 4-27天前的收入(已到账期)
- 可提现金额 = 已入账 - 审核中的提现 - 已通过的提现
- 如果已有提现申请,可提现金额会相应减少
---
### Q5: 时间范围是如何计算的?
**答案**:
- **未入账**: 当前时间 - 3天 ~ 当前时间
- **已入账**: 当前时间 - 27天 ~ 当前时间 - 4天
- 时间范围会随着查询时间动态变化
---
## 注意事项
### 1. 数据实时性
- ⚠️ 数据基于查询时刻实时计算
- ⚠️ 建议前端设置定时刷新(如每分钟)
- ⚠️ 或提供手动刷新按钮
### 2. 金额单位
- ⚠️ 数据库存储单位:**分**
- ⚠️ 接口返回单位:**元**(保留2位小数)
- ⚠️ 转换公式:元 = 分 / 100
### 3. 时间范围
- ⚠️ 时间范围是动态的,基于当前时间计算
- ⚠️ 未入账:3天内
- ⚠️ 已入账:4-27天
- ⚠️ 可提现:4-27天内未绑定提现的
### 4. 性能考虑
- ⚠️ 涉及多次数据库查询
- ⚠️ 建议适当缓存(如Redis,5分钟过期)
- ⚠️ 避免频繁调用
---
## 性能优化建议
### 1. 缓存方案
```java
@Cacheable(value = "incomeSummary", key = "#storeId", unless = "#result == null")
public Map getIncomeSummary(Integer storeId) {
// ... 查询逻辑
}
```
**配置**:
```yaml
spring:
cache:
type: redis
redis:
time-to-live: 300000 # 5分钟过期
```
---
### 2. 异步查询
```java
// 使用CompletableFuture并行查询
CompletableFuture balanceFuture = CompletableFuture.supplyAsync(() -> getBalance(storeId));
CompletableFuture todayIncomeFuture = CompletableFuture.supplyAsync(() -> getTodayIncome(storeId));
CompletableFuture