diff --git a/README.md b/README.md
index 69bb4366..d09e9ef9 100644
--- a/README.md
+++ b/README.md
@@ -163,24 +163,9 @@ public class SimplePayOrderTest {
## 🛣️ 路线图
> 当前处于功能开发阶段,部分功能可能会有调整,`V2.1.0`时将作为正式生产可用版本进行发布,之后会保证系统版本非大版本升级时,API接口和数据接口向前兼容
-[**开发进度和任务池**](/_doc/Task.md)
-
-[**更新记录**](/_doc/ChangeLog.md)
-
-### 2.0.X版本:
-- [x] 对账比对功能实现
-- [ ] 支持转账、分账操作
-- [ ] 云闪付支付支持
-- [ ] 支付宝和微信增加V3版本接口支持
-- [ ] 消息通知支持消息中间件模式
-
-### 2.1.X版本:
-- [ ] 增加账户金额表
-- [ ] 增加统计管理
-- [ ] 支持微信消息通知
-- [ ] 支持钉钉消息通知
-- [ ] 新增支付单预警功能, 处理支付单与网关状态不一致且无法自动修复的情况
+[**当前开发进度和任务池**](/_doc/Task.md)
+[**历史更新记录**](/_doc/ChangeLog.md)
## 🥂 Bootx 项目合集
- Bootx-Platform:单体版脚手架 [Gitee地址](https://gitee.com/bootx/bootx-platform)
@@ -197,7 +182,7 @@ QQ扫码加入QQ交流群
微信扫码加入微信交流群
-
+
## 🍻 鸣谢
diff --git a/_doc/Task.md b/_doc/Task.md
index 3f322585..66f6c9be 100644
--- a/_doc/Task.md
+++ b/_doc/Task.md
@@ -1,10 +1,15 @@
-
2.0.4:
- [ ] 支付流程也改为先落库后支付情况, 避免极端情况导致掉单
- [ ] 首页驾驶舱功能: 各通道收入和支付情况
+ - [x] 第一排: (数字格式)显示今日收入、支出金额,支付总订单数量、退款总订单数, 时间分支分为: 今日金额/昨日金额/七天内金额
+ - [x] 第二排: (折线图)显示各通道支付分为支付金额和退款,时间分为: 今日金额/昨日金额/七天内金额
+ - [x] 第三排: (饼图)显示各通道各支付方式数量和占比, 时间分为: 今日金额/昨日金额/七天内金额
+- [ ] 报表功能
+ - [ ] 各通道收入和支付情况
- [ ] 微信新增V3版本接口
- [ ] 增加转账功能
- [ ] 云闪付支持对账功能
+- [ ] 结算台DEMO增加云闪付示例
2.0.x 版本内容
- [ ] 统一关闭接口增加使用撤销关闭订单
diff --git a/daxpay-single/daxpay-single-admin/src/main/java/cn/bootx/platform/daxpay/admin/controller/report/CockpitReportController.java b/daxpay-single/daxpay-single-admin/src/main/java/cn/bootx/platform/daxpay/admin/controller/report/CockpitReportController.java
new file mode 100644
index 00000000..526dd9f1
--- /dev/null
+++ b/daxpay-single/daxpay-single-admin/src/main/java/cn/bootx/platform/daxpay/admin/controller/report/CockpitReportController.java
@@ -0,0 +1,75 @@
+package cn.bootx.platform.daxpay.admin.controller.report;
+
+import cn.bootx.platform.common.core.annotation.IgnoreAuth;
+import cn.bootx.platform.common.core.rest.Res;
+import cn.bootx.platform.common.core.rest.ResResult;
+import cn.bootx.platform.common.core.util.ValidationUtil;
+import cn.bootx.platform.daxpay.service.core.report.service.CockpitReportService;
+import cn.bootx.platform.daxpay.service.dto.report.ChannelLineReport;
+import cn.bootx.platform.daxpay.service.param.report.CockpitReportQuery;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import org.springdoc.api.annotations.ParameterObject;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 驾驶舱接口
+ * @author xxm
+ * @since 2024/3/17
+ */
+@IgnoreAuth// TODO 测试用, 后续删除
+@Tag(name = "驾驶舱接口")
+@RestController
+@RequestMapping("/report/cockpit")
+@RequiredArgsConstructor
+public class CockpitReportController {
+ private final CockpitReportService cockpitReportService;
+
+ @Operation(summary = "支付金额(分)")
+ @GetMapping("/getPayAmount")
+ public ResResult getPayAmount(@ParameterObject CockpitReportQuery query){
+ ValidationUtil.validateParam(query);
+ return Res.ok(cockpitReportService.getPayAmount(query));
+ }
+
+ @Operation(summary = "退款金额(分)")
+ @GetMapping("/getRefundAmount")
+ public ResResult getRefundAmount(@ParameterObject CockpitReportQuery query){
+ ValidationUtil.validateParam(query);
+ return Res.ok(cockpitReportService.getRefundAmount(query));
+ }
+
+ @Operation(summary = "支付订单数量")
+ @GetMapping("/getPayOrderCount")
+ public ResResult getPayOrderCount(@ParameterObject CockpitReportQuery query){
+ ValidationUtil.validateParam(query);
+ return Res.ok(cockpitReportService.getPayOrderCount(query));
+ }
+
+ @Operation(summary = "退款订单数量")
+ @GetMapping("/getRefundOrderCount")
+ public ResResult getRefundOrderCount(@ParameterObject CockpitReportQuery query){
+ ValidationUtil.validateParam(query);
+ return Res.ok(cockpitReportService.getRefundOrderCount(query));
+ }
+
+ @Operation(summary = "支付通道折线图")
+ @GetMapping("/getPayChannelLine")
+ public ResResult> getPayChannelLine(@ParameterObject CockpitReportQuery query){
+ ValidationUtil.validateParam(query);
+ return Res.ok(cockpitReportService.getPayChannelLine(query));
+ }
+
+ @Operation(summary = "退款通道折线图")
+ @GetMapping("/getRefundChannelLine")
+ public ResResult> getRefundChannelLine(@ParameterObject CockpitReportQuery query){
+ ValidationUtil.validateParam(query);
+ return Res.ok(cockpitReportService.getRefundChannelLine(query));
+ }
+
+}
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/report/dao/CockpitReportMapper.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/report/dao/CockpitReportMapper.java
new file mode 100644
index 00000000..0654abcd
--- /dev/null
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/report/dao/CockpitReportMapper.java
@@ -0,0 +1,48 @@
+package cn.bootx.platform.daxpay.service.core.report.dao;
+
+import cn.bootx.platform.daxpay.service.core.report.entity.ChannelOrderLine;
+import cn.bootx.platform.daxpay.service.param.report.CockpitReportQuery;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 查询报表
+ * @author xxm
+ * @since 2024/3/17
+ */
+@Mapper
+public interface CockpitReportMapper {
+
+ /**
+ * 获取支付金额
+ */
+ Integer getPayAmount(CockpitReportQuery query);
+
+ /**
+ * 获取退款金额
+ */
+ Integer getRefundAmount(CockpitReportQuery query);
+
+ /**
+ * 获取支付订单数量
+ */
+ Integer getPayOrderCount(CockpitReportQuery query);
+
+ /**
+ * 获取退款订单数量
+ */
+ Integer getRefundOrderCount(CockpitReportQuery query);
+
+ /**
+ * 支付通道订单折线图
+ */
+ List getPayChannelLine(CockpitReportQuery query);
+
+ /**
+ * 退款通道订单折线图
+ */
+ List getRefundChannelLine(CockpitReportQuery query);
+
+
+}
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/report/entity/ChannelOrderLine.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/report/entity/ChannelOrderLine.java
new file mode 100644
index 00000000..aefdc54e
--- /dev/null
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/report/entity/ChannelOrderLine.java
@@ -0,0 +1,25 @@
+package cn.bootx.platform.daxpay.service.core.report.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * 通道订单折线图
+ * @author xxm
+ * @since 2024/3/17
+ */
+@Data
+@Accessors(chain = true)
+@Schema(title = "通道订单折线图")
+public class ChannelOrderLine {
+
+ @Schema(description = "通道编码")
+ private String channel;
+
+ @Schema(description = "订单金额")
+ private Integer count;
+
+ @Schema(description = "订单数量")
+ private Integer sum;
+}
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/report/entity/ChannelProportionPie.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/report/entity/ChannelProportionPie.java
new file mode 100644
index 00000000..2d0762fa
--- /dev/null
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/report/entity/ChannelProportionPie.java
@@ -0,0 +1,29 @@
+package cn.bootx.platform.daxpay.service.core.report.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * 支付通道占比饼图
+ * @author xxm
+ * @since 2024/3/17
+ */
+@Data
+@Accessors(chain = true)
+@Schema(title = "支付通道占比饼图")
+public class ChannelProportionPie {
+
+ @Schema(description = "通道编码")
+ private String code;
+
+ @Schema(description = "通道名称")
+ private String name;
+
+ @Schema(description = "占比")
+ private Double proportion;
+
+ @Schema(description = "数量")
+ private Integer count;
+
+}
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/report/service/CockpitReportService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/report/service/CockpitReportService.java
new file mode 100644
index 00000000..3432a730
--- /dev/null
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/report/service/CockpitReportService.java
@@ -0,0 +1,108 @@
+package cn.bootx.platform.daxpay.service.core.report.service;
+
+import cn.bootx.platform.common.core.function.CollectorsFunction;
+import cn.bootx.platform.daxpay.code.PayChannelEnum;
+import cn.bootx.platform.daxpay.service.core.report.dao.CockpitReportMapper;
+import cn.bootx.platform.daxpay.service.core.report.entity.ChannelOrderLine;
+import cn.bootx.platform.daxpay.service.dto.report.ChannelLineReport;
+import cn.bootx.platform.daxpay.service.param.report.CockpitReportQuery;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 驾驶舱接口
+ * @author xxm
+ * @since 2024/3/15
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class CockpitReportService {
+
+ private final CockpitReportMapper cockpitReportMapper;
+
+ /**
+ * 支付金额(分)
+ */
+ public Integer getPayAmount(CockpitReportQuery query){
+ // 获取支付成功的订单
+ return cockpitReportMapper.getPayAmount(query);
+ }
+
+ /**
+ * 退款金额(分)
+ */
+ public Integer getRefundAmount(CockpitReportQuery query){
+ return cockpitReportMapper.getRefundAmount(query);
+ }
+
+ /**
+ * 支付订单数量
+ */
+ public Integer getPayOrderCount(CockpitReportQuery query){
+ return cockpitReportMapper.getPayOrderCount(query);
+ }
+
+ /**
+ * 退款订单数量
+ */
+ public Integer getRefundOrderCount(CockpitReportQuery query){
+ return cockpitReportMapper.getRefundOrderCount(query);
+ }
+
+ /**
+ * (折线图)显示各通道支付分为支付金额和订单数,
+ */
+ public List getPayChannelLine(CockpitReportQuery query){
+ Map lineMap = cockpitReportMapper.getPayChannelLine(query)
+ .stream()
+ .collect(Collectors.toMap(ChannelOrderLine::getChannel, Function.identity(), CollectorsFunction::retainLatest));
+ // 根据系统中有的通道编码,获取对应的通道名称
+ return Arrays.stream(PayChannelEnum.values())
+ .map(e->{
+ ChannelOrderLine channelOrderLine = lineMap.get(e.getCode());
+ ChannelLineReport channelLineReport = new ChannelLineReport()
+ .setChannelCode(e.getCode())
+ .setChannelName(e.getName());
+ if (Objects.isNull(channelOrderLine)){
+ channelLineReport.setOrderAmount(0).setOrderCount(0);
+ } else {
+ channelLineReport.setOrderAmount(channelOrderLine.getCount())
+ .setOrderCount(channelOrderLine.getSum());
+ }
+ return channelLineReport;
+ }).collect(Collectors.toList());
+ }
+
+ /**
+ * (折线图)显示各通道退款金额和订单数,
+ */
+ public List getRefundChannelLine(CockpitReportQuery query){
+ Map lineMap = cockpitReportMapper.getRefundChannelLine(query)
+ .stream()
+ .collect(Collectors.toMap(ChannelOrderLine::getChannel, Function.identity(), CollectorsFunction::retainLatest));
+ // 根据系统中有的通道编码,获取对应的通道名称
+ return Arrays.stream(PayChannelEnum.values())
+ .map(e->{
+ ChannelOrderLine channelOrderLine = lineMap.get(e.getCode());
+ ChannelLineReport channelLineReport = new ChannelLineReport()
+ .setChannelCode(e.getCode())
+ .setChannelName(e.getName());
+ if (Objects.isNull(channelOrderLine)){
+ channelLineReport.setOrderAmount(0).setOrderCount(0);
+ } else {
+ channelLineReport.setOrderAmount(channelOrderLine.getCount())
+ .setOrderCount(channelOrderLine.getSum());
+ }
+ return channelLineReport;
+ }).collect(Collectors.toList());
+ }
+}
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/report/ChannelLineReport.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/report/ChannelLineReport.java
new file mode 100644
index 00000000..10c7e96f
--- /dev/null
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/report/ChannelLineReport.java
@@ -0,0 +1,29 @@
+package cn.bootx.platform.daxpay.service.dto.report;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * 支付通道折线图报表
+ * @author xxm
+ * @since 2024/3/17
+ */
+@Data
+@Accessors(chain = true)
+@Schema(title = "支付通道折线图报表")
+public class ChannelLineReport {
+
+ @Schema(description = "支付通道编码")
+ private String channelCode;
+
+ @Schema(description = "支付通道名称")
+ private String channelName;
+
+ @Schema(description = "订单金额")
+ private Integer orderAmount;
+
+ @Schema(description = "订单数量")
+ private Integer orderCount;
+
+}
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/report/CockpitReportQuery.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/report/CockpitReportQuery.java
new file mode 100644
index 00000000..0c59ce38
--- /dev/null
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/report/CockpitReportQuery.java
@@ -0,0 +1,35 @@
+package cn.bootx.platform.daxpay.service.param.report;
+
+import cn.hutool.core.date.DatePattern;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+/**
+ * 驾驶舱报表查询参数
+ * @author xxm
+ * @since 2024/3/15
+ */
+@Data
+@Accessors(chain = true)
+@Schema(title = "驾驶舱报表查询参数")
+public class CockpitReportQuery {
+
+ @NotNull(message = "开始时间不得为空")
+ @Schema(description = "开始时间")
+ @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
+ @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
+ private LocalDateTime startTime;
+
+ @NotNull(message = "开始时间不得为空")
+ @Schema(description = "开始时间")
+ @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
+ @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
+ private LocalDateTime endTime;
+
+}
diff --git a/daxpay-single/daxpay-single-service/src/main/resources/mapper/report/CockpitReportMapper.xml b/daxpay-single/daxpay-single-service/src/main/resources/mapper/report/CockpitReportMapper.xml
new file mode 100644
index 00000000..ffba7400
--- /dev/null
+++ b/daxpay-single/daxpay-single-service/src/main/resources/mapper/report/CockpitReportMapper.xml
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+