From 4c8535b9f263a3b398832b7a588abbdd5ebe38f4 Mon Sep 17 00:00:00 2001
From: rk <94314517@qq.com>
Date: 星期一, 29 六月 2026 13:51:50 +0800
Subject: [PATCH] 功能开发

---
 server/接口变更说明.txt                                                                     |   16 ++++
 server/services/src/main/java/com/doumee/service/business/impl/ReportServiceImpl.java |  173 +++++++++++++++++++++++++++++++++++++++++++
 server/services/src/main/java/com/doumee/service/business/ReportService.java          |   34 ++++++++
 3 files changed, 223 insertions(+), 0 deletions(-)

diff --git a/server/services/src/main/java/com/doumee/service/business/ReportService.java b/server/services/src/main/java/com/doumee/service/business/ReportService.java
index 4438117..d1d5baf 100644
--- a/server/services/src/main/java/com/doumee/service/business/ReportService.java
+++ b/server/services/src/main/java/com/doumee/service/business/ReportService.java
@@ -3,11 +3,14 @@
 import com.doumee.core.model.PageData;
 import com.doumee.core.model.PageWrap;
 import com.doumee.dao.business.vo.BikeIncomeStatVO;
+import com.doumee.dao.business.vo.BikeUsageStatVO;
+import com.doumee.dao.business.vo.DashboardVO;
 import com.doumee.dao.business.vo.IncomeStatVO;
 import com.doumee.dao.business.vo.OperationCenterVO;
 import com.doumee.dao.business.vo.OperationOrderVO;
 import com.doumee.dao.business.vo.OrderRidesDetailVO;
 import com.doumee.dao.business.vo.OverviewStatVO;
+import com.doumee.dao.business.vo.PackageSourceStatVO;
 import com.doumee.dao.business.web.request.BikeIncomeQueryDTO;
 import com.doumee.dao.business.web.request.OperationOrderQueryDTO;
 
@@ -68,4 +71,35 @@
      * @return 楠戣璁板綍涓庤建杩硅鎯�(鍚溅杈嗙被鍨嬨�佹槸鍚︽湁杞ㄨ抗銆侀獞琛屽垪琛ㄥ強姣忔潯涓嬫寕鐨勮建杩圭偣)
      */
     OrderRidesDetailVO orderRidesDetail(String orderId);
+
+    /**
+     * 杩�30澶╂敹鐩婄粺璁�(鍥哄畾30澶�,鏃犻渶鍏ュ弬):鎸夋棩鏌辩姸鍥� + 绱 + 鐜瘮/鍚屾瘮銆�
+     * <p>鍙e緞鍚� {@link #incomeStat},鍐呴儴浠� dateType=3(杩�30澶�)璋冪敤銆�
+     *
+     * @return 杩�30澶╂敹鐩婄粺璁$粨鏋�
+     */
+    IncomeStatVO incomeStat30();
+
+    /**
+     * 杞﹁締浣跨敤鎯呭喌:鑷杞�/鐢靛姩杞﹀悇鑷殑浣跨敤涓�(status=1)涓庣┖闂�(status=0)鏁伴噺銆�
+     * <p>绂佺敤杞﹁締(status=3)涓嶈鍏ャ��
+     *
+     * @return 杞﹁締浣跨敤鎯呭喌
+     */
+    BikeUsageStatVO bikeUsageStat();
+
+    /**
+     * 濂楅閿�鍞潵婧愮粺璁�:鏈湀/鏈勾缁村害涓�,鎶栭煶鍏戞崲(payWay=2)涓庡皬绋嬪簭璐拱(payWay=0)鐨勫椁愭暟銆�
+     * <p>鍙e緞:goodsorder type=1 濂楅鍗¤喘涔般�乸ayStatus=1 宸叉敮浠樸��
+     *
+     * @return 濂楅閿�鍞潵婧愮粺璁�
+     */
+    PackageSourceStatVO packageSourceStat();
+
+    /**
+     * 缁煎悎鐪嬫澘:鏈湀/鏄ㄦ棩/浠婃棩鏀剁泭涓庤鍗曟暟銆佽溅杈嗘�绘暟/浣跨敤涓�/绌洪棽,瀹㈡埛鏁扮浉鍏虫殏鎼佺疆銆�
+     *
+     * @return 缁煎悎鐪嬫澘鏁版嵁
+     */
+    DashboardVO dashboard();
 }
diff --git a/server/services/src/main/java/com/doumee/service/business/impl/ReportServiceImpl.java b/server/services/src/main/java/com/doumee/service/business/impl/ReportServiceImpl.java
index da298bd..8f85057 100644
--- a/server/services/src/main/java/com/doumee/service/business/impl/ReportServiceImpl.java
+++ b/server/services/src/main/java/com/doumee/service/business/impl/ReportServiceImpl.java
@@ -22,6 +22,8 @@
 import com.doumee.dao.business.model.MemberRides;
 import com.doumee.dao.business.model.MemberRidesTrack;
 import com.doumee.dao.business.vo.BikeIncomeStatVO;
+import com.doumee.dao.business.vo.BikeUsageStatVO;
+import com.doumee.dao.business.vo.DashboardVO;
 import com.doumee.dao.business.vo.IncomeDailyVO;
 import com.doumee.dao.business.vo.IncomeStatVO;
 import com.doumee.dao.business.vo.OperationCenterVO;
@@ -30,6 +32,7 @@
 import com.doumee.dao.business.vo.OrderRideTrackVO;
 import com.doumee.dao.business.vo.OrderRidesDetailVO;
 import com.doumee.dao.business.vo.OverviewStatVO;
+import com.doumee.dao.business.vo.PackageSourceStatVO;
 import com.doumee.dao.business.web.request.BikeIncomeQueryDTO;
 import com.doumee.dao.business.web.request.OperationOrderQueryDTO;
 import com.doumee.service.business.ReportService;
@@ -41,6 +44,7 @@
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
@@ -89,6 +93,9 @@
 
     /** 鐧惧垎姣斿熀鏁�(澧為暱鐜� = (鏈湡 - 瀵规瘮鏈�) / 瀵规瘮鏈� 脳 100) */
     private static final BigDecimal PERCENT_BASE = new BigDecimal("100");
+
+    /** 鏀粯鏂瑰紡:鎶栭煶鍒告牳閿�(濂楅閿�鍞潵婧愯瘑鍒敤) */
+    private static final int PAY_WAY_DOUYIN = 2;
 
     @Override
     public OverviewStatVO overview() {
@@ -617,4 +624,170 @@
         }
         return "鏈煡";
     }
+
+    @Override
+    public IncomeStatVO incomeStat30() {
+        // 杩�30澶�(鍚粖澶╁叡30澶�),澶嶇敤 incomeStat 鏃㈡湁瀹炵幇涓庡彛寰�
+        BikeIncomeQueryDTO query = new BikeIncomeQueryDTO();
+        query.setDateType(3);
+        return incomeStat(query);
+    }
+
+    @Override
+    public BikeUsageStatVO bikeUsageStat() {
+        // status:0 绌洪棽 / 1 浣跨敤涓�;绂佺敤(3)涓嶈鍏�;type:0 鑷杞� / 1 鐢靛姩杞�
+        BikeUsageStatVO vo = new BikeUsageStatVO();
+        vo.setBikeIdle(countBikeByStatus(Constants.ZERO, Constants.ZERO));
+        vo.setBikeInUse(countBikeByStatus(Constants.ZERO, Constants.ONE));
+        vo.setEleBikeIdle(countBikeByStatus(Constants.ONE, Constants.ZERO));
+        vo.setEleBikeInUse(countBikeByStatus(Constants.ONE, Constants.ONE));
+        return vo;
+    }
+
+    /**
+     * 鎸夎溅杈嗙被鍨� + 鐘舵�佺粺璁℃湭鍒犻櫎杞﹁締鏁伴噺銆�
+     *
+     * @param type   杞﹁締绫诲瀷 0 鑷杞� / 1 鐢靛姩杞�
+     * @param status 杞﹁締鐘舵�� 0 绌洪棽 / 1 浣跨敤涓�
+     * @return 婊¤冻鏉′欢鐨勮溅杈嗘暟
+     */
+    private long countBikeByStatus(Integer type, Integer status) {
+        return bikesMapper.selectCount(
+                new QueryWrapper<Bikes>().lambda()
+                        .eq(Bikes::getType, type)
+                        .eq(Bikes::getStatus, status)
+                        .eq(Bikes::getIsdeleted, Constants.ZERO));
+    }
+
+    @Override
+    public PackageSourceStatVO packageSourceStat() {
+        // 鏈湀/鏈勾璧锋(pay_date 钀藉湪鍖洪棿鍐�);goodsorder type=1 濂楅鍗¤喘涔� + payStatus=1 宸叉敮浠�
+        Calendar cal = Calendar.getInstance();
+        Date monthStart = DateUtil.getStartOfDay(getFirstMs(cal, Calendar.MONTH));
+        Date monthEnd = DateUtil.getEndOfDay(new Date());
+        Date yearStart = DateUtil.getStartOfDay(getFirstMs(cal, Calendar.YEAR));
+        Date yearEnd = DateUtil.getEndOfDay(new Date());
+
+        PackageSourceStatVO vo = new PackageSourceStatVO();
+        vo.setMonth(countPackageSource(monthStart, monthEnd));
+        vo.setYear(countPackageSource(yearStart, yearEnd));
+        return vo;
+    }
+
+    /**
+     * 缁熻鎸囧畾鏃舵鍐呭椁愰攢鍞潵婧愭暟閲忋��
+     * <p>鎶栭煶鍏戞崲 = payWay 2,灏忕▼搴忚喘涔� = payWay 0(寰俊)銆�
+     *
+     * @param start 璧峰鏃堕棿(鍚�)
+     * @param end   缁撴潫鏃堕棿(鍚�)
+     * @return 鎶栭煶/灏忕▼搴忓椁愭暟閲�
+     */
+    private PackageSourceStatVO.PeriodCount countPackageSource(Date start, Date end) {
+        List<Goodsorder> orders = goodsorderMapper.selectList(
+                new QueryWrapper<Goodsorder>().lambda()
+                        .select(Goodsorder::getPayWay)
+                        .eq(Goodsorder::getType, Constants.ONE)
+                        .eq(Goodsorder::getPayStatus, Constants.ONE)
+                        .eq(Goodsorder::getIsdeleted, Constants.ZERO)
+                        .ge(Goodsorder::getPayDate, start)
+                        .le(Goodsorder::getPayDate, end));
+        long douyin = 0L;
+        long mini = 0L;
+        for (Goodsorder o : orders) {
+            if (o.getPayWay() == null) {
+                continue;
+            }
+            if (o.getPayWay() == PAY_WAY_DOUYIN) {
+                douyin++;
+            } else if (o.getPayWay() == Constants.ZERO) {
+                mini++;
+            }
+        }
+        PackageSourceStatVO.PeriodCount pc = new PackageSourceStatVO.PeriodCount();
+        pc.setDouyinCount(douyin);
+        pc.setMiniCount(mini);
+        return pc;
+    }
+
+    @Override
+    public DashboardVO dashboard() {
+        DashboardVO vo = new DashboardVO();
+
+        // 鍚勬椂娈佃捣姝�:鏈湀/鏄ㄦ棩/浠婃棩
+        Date now = new Date();
+        Calendar cal = Calendar.getInstance();
+        Date monthStart = DateUtil.getStartOfDay(getFirstMs(cal, Calendar.MONTH));
+        Date monthEnd = DateUtil.getEndOfDay(now);
+        Date yesterdayStart = DateUtil.getStartOfDay(DateUtil.increaseDay(now, -1));
+        Date yesterdayEnd = DateUtil.getEndOfDay(DateUtil.increaseDay(now, -1));
+        Date todayStart = DateUtil.getStartOfDay(now);
+        Date todayEnd = DateUtil.getEndOfDay(now);
+
+        // 鏀剁泭(鍙e緞鍚� incomeStat:type=0 鎶奸噾 + status=4 宸茬粨绠� 鐨� closeMoney),澶嶇敤 sumClosedMoney
+        vo.setMonthIncome(sumClosedMoney(monthStart, monthEnd));
+        vo.setYesterdayIncome(sumClosedMoney(yesterdayStart, yesterdayEnd));
+        vo.setTodayIncome(sumClosedMoney(todayStart, todayEnd));
+
+        // 璁㈠崟鏁�:宸叉敮浠�(payStatus=1)璁㈠崟璁℃暟
+        vo.setMonthOrderCount(countPaidOrders(monthStart, monthEnd));
+        vo.setYesterdayOrderCount(countPaidOrders(yesterdayStart, yesterdayEnd));
+        vo.setTodayOrderCount(countPaidOrders(todayStart, todayEnd));
+
+        // 杞﹁締:浠呰繑鍥炴湭鍒犻櫎鎬绘暟
+        vo.setTotalBikeCount((long) bikesMapper.selectCount(
+                new QueryWrapper<Bikes>().lambda().eq(Bikes::getIsdeleted, Constants.ZERO)));
+
+        // 瀹㈡埛鏁�:鎬讳細鍛�=鏈垹闄ゅ叏閮�;浠婃棩/鏄ㄦ棩鏂板鎸� create_date 钀藉湪瀵瑰簲鍖洪棿(涓� overview 鍙e緞涓�鑷�)
+        vo.setTotalMemberCount((long) memberMapper.selectCount(
+                new QueryWrapper<Member>().lambda().eq(Member::getIsdeleted, Constants.ZERO)));
+        vo.setYesterdayNewMember((long) memberMapper.selectCount(
+                new QueryWrapper<Member>().lambda()
+                        .eq(Member::getIsdeleted, Constants.ZERO)
+                        .ge(Member::getCreateDate, yesterdayStart)
+                        .le(Member::getCreateDate, yesterdayEnd)));
+        vo.setTodayNewMember((long) memberMapper.selectCount(
+                new QueryWrapper<Member>().lambda()
+                        .eq(Member::getIsdeleted, Constants.ZERO)
+                        .ge(Member::getCreateDate, todayStart)));
+        return vo;
+    }
+
+    /**
+     * 缁熻鎸囧畾鏃舵鍐呭凡鏀粯璁㈠崟鏁伴噺(payStatus=1)銆�
+     *
+     * @param start 璧峰鏃堕棿(鍚�)
+     * @param end   缁撴潫鏃堕棿(鍚�)
+     * @return 宸叉敮浠樿鍗曟暟
+     */
+    private long countPaidOrders(Date start, Date end) {
+        return goodsorderMapper.selectCount(
+                new QueryWrapper<Goodsorder>().lambda()
+                        .eq(Goodsorder::getPayStatus, Constants.ONE)
+                        .eq(Goodsorder::getIsdeleted, Constants.ZERO)
+                        .ge(Goodsorder::getPayDate, start)
+                        .le(Goodsorder::getPayDate, end));
+    }
+
+    /**
+     * 鍙栨湰鏈�/鏈勾绗竴澶╃殑鏃堕棿鍘熷��(鏃跺垎绉掑綊闆跺墠鐨勬绉�),鐢ㄤ簬鏋勯�犲尯闂磋捣濮嬨��
+     * <p>鐢� Calendar 鎶娿�屽綋鏈�1鏃� 00:00:00.000銆嶆垨銆屽綋骞�1鏈�1鏃� 00:00:00.000銆嶅彇鍑恒��
+     *
+     * @param cal   鏃ュ巻(浼氳淇敼)
+     * @param field Calendar.MONTH 鏈湀绗竴澶� / Calendar.YEAR 鏈勾绗竴澶�
+     * @return 鍖洪棿璧峰鏃堕棿
+     */
+    private Date getFirstMs(Calendar cal, int field) {
+        cal.setTime(new Date());
+        if (field == Calendar.MONTH) {
+            cal.set(Calendar.DAY_OF_MONTH, 1);
+        } else {
+            cal.set(Calendar.MONTH, Calendar.JANUARY);
+            cal.set(Calendar.DAY_OF_MONTH, 1);
+        }
+        cal.set(Calendar.HOUR_OF_DAY, 0);
+        cal.set(Calendar.MINUTE, 0);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        return cal.getTime();
+    }
 }
diff --git "a/server/\346\216\245\345\217\243\345\217\230\346\233\264\350\257\264\346\230\216.txt" "b/server/\346\216\245\345\217\243\345\217\230\346\233\264\350\257\264\346\230\216.txt"
index 958d020..27a2dfe 100644
--- "a/server/\346\216\245\345\217\243\345\217\230\346\233\264\350\257\264\346\230\216.txt"
+++ "b/server/\346\216\245\345\217\243\345\217\230\346\233\264\350\257\264\346\230\216.txt"
@@ -29,6 +29,22 @@
   9. GET  /business/douyinProduct/{id}       鏍规嵁ID鏌ヨ(鍚玈KU)
   10. POST /business/douyinProduct/bindDiscount  缁戝畾/瑙g粦鏈湴濂楅
 
+鍥涖�佹暟鎹姤琛�(鏂版枃浠� ReportController,/business/report)
+     閴存潈:鏃� @RequiresPermissions,浠� Shiro 鐧诲綍鏍¢獙,鐧诲綍鍚庡彴鍗冲彲璁块棶銆�
+     Service 澶嶇敤 services 妯″潡 ReportService(涓� web 绔� /web/report 鍚屾簮)銆�
+  11. GET /business/report/incomeStat30       杩�30澶╂敹鐩婄粺璁�(鎸夋棩鏌辩姸鍥�+绱+鐜瘮/鍚屾瘮)
+  12. GET /business/report/bikeUsageStat      杞﹁締浣跨敤鎯呭喌(鑷杞�/鐢靛姩杞� 脳 浣跨敤涓�/绌洪棽;绂佺敤杞﹁締鎺掗櫎)
+  13. GET /business/report/packageSourceStat  濂楅閿�鍞潵婧�(鏈湀/鏈勾 脳 鎶栭煶鍏戞崲/灏忕▼搴忚喘涔�)
+  14. GET /business/report/dashboard          缁煎悎鐪嬫澘(鏈湀/鏄ㄦ棩/浠婃棩鏀剁泭+璁㈠崟鏁�+杞﹁締鎬绘暟+瀹㈡埛鏁�)
+
+     鍚勬帴鍙e嚭鍙傚瓧娈�:
+     路 incomeStat30       鈫� IncomeStatVO(dailyList/totalIncome/鐜瘮/鍚屾瘮),鍥哄畾杩�30澶�,鏃犲叆鍙�
+     路 bikeUsageStat      鈫� BikeUsageStatVO:bikeIdle/bikeInUse/eleBikeIdle/eleBikeInUse
+     路 packageSourceStat  鈫� PackageSourceStatVO:month{douyinCount,miniCount} + year{douyinCount,miniCount}
+     路 dashboard          鈫� DashboardVO:monthIncome/yesterdayIncome/todayIncome(鍏�)
+                                   + monthOrderCount/yesterdayOrderCount/todayOrderCount
+                                   + totalBikeCount + totalMemberCount/yesterdayNewMember/todayNewMember
+
 
 ============================================================
 

--
Gitblit v1.9.3