31-收入汇总统计接口.md 18 KB

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. 可提现金额

// 查询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. 今日收益

// 查询今天的收入总和
todayIncome = SUM(money WHERE created_time BETWEEN '今日 00:00:00' AND '今日 23:59:59')

说明:

  • ✅ 统计当天所有收入
  • ✅ 包含所有收入类型(优惠券、代金券、团购券等)

3. 未入账(近3天)

// 查询近3天未绑定提现的收入
notPaidMoney = SUM(money WHERE created_time > (NOW() - 3天) 
                              AND cash_out_id IS NULL)
notPaidCount = COUNT(*)

说明:

  • ✅ 统计近3天的收入
  • ✅ 未绑定提现记录
  • ✅ 还未到提现账期

4. 已入账(4-27天)

// 查询4-27天前的收入
paidMoney = SUM(money WHERE created_time BETWEEN (NOW() - 27天) AND (NOW() - 4天))
paidCount = COUNT(*)

说明:

  • ✅ 统计4-27天前的收入
  • ✅ 已到提现账期
  • ✅ 可以申请提现

请求参数

无参数

从 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 提示信息

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 无效

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

2. 查询异常

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

业务场景

场景 1: 首页数据展示

业务需求: 商户登录后,首页需要展示收入概况的关键数据

请求:

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笔)              │
└────────────────────────────────────────┘

场景 2: 数据刷新

业务需求: 用户下拉刷新或手动刷新收入数据

请求:

GET /incomeManage/getIncomeSummary
Headers:
  Authorization: Bearer VALID_TOKEN

业务逻辑:

  • ✅ 重新计算所有统计数据
  • ✅ 返回最新的收入概况
  • ✅ 前端更新展示

场景 3: 定时刷新

业务需求: 前端每隔一定时间自动刷新数据

实现方式:

setInterval(() => {
    fetchIncomeSummary();
}, 60000);  // 每分钟刷新一次

数据关系说明

金额之间的关系

账户余额 (balance)
    = 历史所有收入 - 已提现金额

可提现金额 (cashOutMoney)
    = 4-27天内未绑定提现的收入 
    - 待审核的提现金额 
    - 已通过的提现金额

今日收益 (todayIncome)
    = 今天所有收入

未入账 (notPaidMoney)
    = 近3天未绑定提现的收入
    (还未到提现账期)

已入账 (paidMoney)
    = 4-27天的收入
    (已到提现账期,可以提现)

时间范围关系

时间轴: ←────────────────────────────────→
       -27天  -4天  -3天  今天

已入账:  ├─────┤
         4-27天

未入账:          ├──┤
                3天内

今日收益:             │
                    今天

前端集成示例

Vue.js 示例

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 示例

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>
    );
}

测试用例

测试场景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. 缓存方案

@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分钟过期

2. 异步查询

// 使用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();

更新日志

2025-11-21 (v1.0)

新增接口:

  • GET /incomeManage/getIncomeSummary - 收入汇总统计

核心功能:

  • ✅ 一次性返回4项关键数据
  • ✅ 账户余额
  • ✅ 可提现金额
  • ✅ 今日收益
  • ✅ 已入账/未入账金额和数量

数据来源:

  • 复用三个现有接口的业务逻辑
  • /accountBalance - 可提现金额
  • /todayIncome - 今日收益
  • /noYetPayment - 已入账/未入账

涉及文件:

  • IncomeManageController.java - 新增 getIncomeSummary 接口
  • IncomeManageService.java - 新增方法定义
  • IncomeManageServiceImpl.java - 新增方法实现

代码质量:

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

开发人员: ssk


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