From cf1d82548a1bd8155ffe9b486df8167aa9e63a7d Mon Sep 17 00:00:00 2001
From: rk <94314517@qq.com>
Date: 星期四, 02 七月 2026 09:19:06 +0800
Subject: [PATCH] 功能开发

---
 server/services/src/main/java/com/doumee/core/wx/WxMiniUtilService.java                     |    4 
 server/services/src/main/java/com/doumee/dao/business/vo/DashboardVO.java                   |   63 +++++++
 server/services/src/main/java/com/doumee/service/business/impl/ReportServiceImpl.java       |   23 ++
 server/services/src/main/java/com/doumee/core/douyin/dto/DouyinPrepareParam.java            |    2 
 server/services/src/main/java/com/doumee/core/douyin/dto/DouyinBoundProduct.java            |   22 ++
 server/platform/src/main/java/com/doumee/api/business/ReportController.java                 |   56 ++++++
 server/services/src/main/java/com/doumee/core/douyin/DouyinClient.java                      |   54 +++++-
 server/services/src/main/java/com/doumee/dao/business/vo/PackageSourceStatVO.java           |   37 ++++
 server/services/src/main/java/com/doumee/dao/business/web/request/GoodsorderBackDTO.java    |    2 
 server/services/src/main/java/com/doumee/service/business/GoodsorderService.java            |    9 
 server/services/src/main/resources/application-dev.yml                                      |   16 
 server/web/src/main/java/com/doumee/api/web/AccountApi.java                                 |   12 +
 server/services/src/main/java/com/doumee/dao/business/model/DouyinVerifyRecord.java         |    4 
 server/services/src/main/java/com/doumee/dao/business/vo/DouyinVerifyRecordPageVO.java      |    3 
 server/web/src/main/java/com/doumee/api/web/DouyinApi.java                                  |   22 ++
 server/services/src/main/java/com/doumee/dao/business/vo/BikeUsageStatVO.java               |   30 +++
 server/web/src/main/java/com/doumee/api/web/ManagerApi.java                                 |   35 +++
 server/services/src/main/java/com/doumee/dao/business/web/response/HomeResponse.java        |    3 
 server/services/src/main/java/com/doumee/service/business/DouyinVerifyService.java          |   26 ++
 server/services/src/main/java/com/doumee/service/business/impl/DouyinVerifyServiceImpl.java |   61 +++++-
 server/services/src/main/java/com/doumee/service/business/MemberService.java                |    9 +
 server/services/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java       |    8 
 server/services/src/main/java/com/doumee/dao/business/vo/BikeIncomeStatVO.java              |    3 
 server/services/src/main/java/com/doumee/service/business/impl/GoodsorderServiceImpl.java   |   22 ++
 24 files changed, 486 insertions(+), 40 deletions(-)

diff --git a/server/platform/src/main/java/com/doumee/api/business/ReportController.java b/server/platform/src/main/java/com/doumee/api/business/ReportController.java
new file mode 100644
index 0000000..fbed45d
--- /dev/null
+++ b/server/platform/src/main/java/com/doumee/api/business/ReportController.java
@@ -0,0 +1,56 @@
+package com.doumee.api.business;
+
+import com.doumee.api.BaseController;
+import com.doumee.core.model.ApiResponse;
+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.PackageSourceStatVO;
+import com.doumee.service.business.ReportService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 鏁版嵁鎶ヨ〃(绠$悊绔柊澧�:杩�30澶╂敹鐩� / 杞﹁締浣跨敤鎯呭喌 / 濂楅鏉ユ簮 / 缁煎悎鐪嬫澘)銆�
+ * <p>涓嶅仛鑿滃崟/鎸夐挳绾ф潈闄愰檺鍒�:鏃� @RequiresPermissions,浠呭彈 Shiro authc 鐧诲綍鏍¢獙淇濇姢,鐧诲綍鍚庡彴鍗冲彲璁块棶銆�
+ * <p>Service 澶嶇敤 services 妯″潡 {@link ReportService}(涓� web 绔� /web/report 鍚屾簮)銆�
+ *
+ * @author rk
+ * @date 2026/06/26
+ */
+@Api(tags = "鏁版嵁鎶ヨ〃(绠$悊绔�)")
+@RestController
+@RequestMapping("/business/report")
+public class ReportController extends BaseController {
+
+    @Autowired
+    private ReportService reportService;
+
+    @ApiOperation("杩�30澶╂敹鐩婄粺璁�(鎸夋棩鏌辩姸鍥�+绱+鐜瘮/鍚屾瘮)")
+    @GetMapping("/incomeStat30")
+    public ApiResponse<IncomeStatVO> incomeStat30() {
+        return ApiResponse.success(reportService.incomeStat30());
+    }
+
+    @ApiOperation("杞﹁締浣跨敤鎯呭喌:鑷杞�/鐢靛姩杞﹀悇鑷娇鐢ㄤ腑涓庣┖闂叉暟閲�")
+    @GetMapping("/bikeUsageStat")
+    public ApiResponse<BikeUsageStatVO> bikeUsageStat() {
+        return ApiResponse.success(reportService.bikeUsageStat());
+    }
+
+    @ApiOperation("濂楅閿�鍞潵婧�:鏈湀/鏈勾缁村害,鎶栭煶鍏戞崲涓庡皬绋嬪簭璐拱鏁伴噺")
+    @GetMapping("/packageSourceStat")
+    public ApiResponse<PackageSourceStatVO> packageSourceStat() {
+        return ApiResponse.success(reportService.packageSourceStat());
+    }
+
+    @ApiOperation("缁煎悎鐪嬫澘:鏈湀/鏄ㄦ棩/浠婃棩鏀剁泭涓庤鍗曟暟,杞﹁締鎬绘暟/浣跨敤涓�/绌洪棽")
+    @GetMapping("/dashboard")
+    public ApiResponse<DashboardVO> dashboard() {
+        return ApiResponse.success(reportService.dashboard());
+    }
+}
diff --git a/server/services/src/main/java/com/doumee/core/douyin/DouyinClient.java b/server/services/src/main/java/com/doumee/core/douyin/DouyinClient.java
index 8f7b418..460e443 100644
--- a/server/services/src/main/java/com/doumee/core/douyin/DouyinClient.java
+++ b/server/services/src/main/java/com/doumee/core/douyin/DouyinClient.java
@@ -27,6 +27,7 @@
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
 
+import java.io.InputStream;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.net.URLDecoder;
@@ -277,15 +278,50 @@
             return objectId;
         }
         try {
-            HttpURLConnection conn = (HttpURLConnection) new URL(input).openConnection();
-            conn.setInstanceFollowRedirects(true);
-            conn.setRequestMethod("GET");
-            conn.setConnectTimeout(5000);
-            conn.setReadTimeout(5000);
-            conn.connect();
-            String finalUrl = conn.getURL().toString();
-            conn.disconnect();
-            return extractObjectId(finalUrl);
+            // 鎵嬪姩璺熼殢閲嶅畾鍚�:HttpURLConnection 鑷姩閲嶅畾鍚戜笉璺ㄥ崗璁�(http鈫攈ttps)涓� getURL() 鏇存柊涓嶇ǔ瀹�,
+            // 鏀逛负閫愯烦璇诲彇 Location 澶�,鏈�缁堜粠钀藉湴闀块摼閲屾彁鍙� object_id
+            String current = input;
+            int maxRedirects = 5;
+            for (int i = 0; i < maxRedirects; i++) {
+                HttpURLConnection conn = (HttpURLConnection) new URL(current).openConnection();
+                conn.setInstanceFollowRedirects(false); // 鎵嬪姩璺熼殢
+                conn.setRequestMethod("GET");
+                conn.setRequestProperty("User-Agent", "Mozilla/5.0");
+                conn.setConnectTimeout(5000);
+                conn.setReadTimeout(5000);
+                int code = conn.getResponseCode();
+                String location = conn.getHeaderField("Location");
+                // 蹇呴』璇诲彇骞跺叧闂敊璇�/杈撳叆娴�,鍚﹀垯杩炴帴璧勬簮娉勬紡
+                try (InputStream is = (code >= 400) ? conn.getErrorStream() : conn.getInputStream()) {
+                    if (is != null) {
+                        // 涓嶉渶瑕佸唴瀹�,浠呮秷璐规祦浠ラ噴鏀捐繛鎺�
+                        byte[] buf = new byte[1024];
+                        while (is.read(buf) > 0) {
+                            // drain
+                        }
+                    }
+                }
+                if (code == HttpURLConnection.HTTP_MOVED_PERM
+                        || code == HttpURLConnection.HTTP_MOVED_TEMP
+                        || code == HttpURLConnection.HTTP_SEE_OTHER
+                        || code == 307 || code == 308) {
+                    if (StringUtils.isBlank(location)) {
+                        // 閲嶅畾鍚戜絾鏃� Location,鏃犳硶缁х画
+                        return null;
+                    }
+                    current = location;
+                    continue;
+                }
+                // 闈為噸瀹氬悜:鐢ㄦ渶缁� URL 鎻愬彇 object_id
+                String resolved = location != null ? location : conn.getURL().toString();
+                objectId = extractObjectId(resolved);
+                if (objectId == null) {
+                    log.warn("瑙f瀽鎶栭煶鐭摼鏈彁鍙栧埌 object_id,input={},final={}", input, resolved);
+                }
+                return objectId;
+            }
+            log.warn("瑙f瀽鎶栭煶鐭摼瓒呰繃鏈�澶ч噸瀹氬悜娆℃暟,input={}", input);
+            return null;
         } catch (Exception e) {
             log.error("瑙f瀽鎶栭煶鐭摼寮傚父:{}", input, e);
             return null;
diff --git a/server/services/src/main/java/com/doumee/core/douyin/dto/DouyinBoundProduct.java b/server/services/src/main/java/com/doumee/core/douyin/dto/DouyinBoundProduct.java
new file mode 100644
index 0000000..e359155
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/core/douyin/dto/DouyinBoundProduct.java
@@ -0,0 +1,22 @@
+package com.doumee.core.douyin.dto;
+
+import com.doumee.dao.business.model.Discount;
+import com.doumee.dao.business.model.DouyinProduct;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * 鎶栭煶鍒告牳閿�鍓嶆牎楠岀粨鏋�:鎵胯浇 skuId 鍙嶆煡鍒扮殑鎶栭煶鍟嗗搧 + 缁戝畾鐨勬湰鍦板椁愩��
+ * <p>scanVerify 鍦ㄦ牳閿�鍓嶆牎楠屾椂涓�娆℃�ф煡鍑�,璺ㄥ眰閫忎紶缁� verify 寮�鍗�,閬垮厤閲嶅鏌ヨ銆�
+ *
+ * @author rk
+ * @date 2026/06/26
+ */
+@Data
+@AllArgsConstructor
+public class DouyinBoundProduct {
+    /** 鎶栭煶鍟嗗搧(鐢ㄤ簬鍥炲~鏍搁攢璁板綍鐨勫晢鍝佸揩鐓�:productId/productName) */
+    private DouyinProduct product;
+    /** 缁戝畾鐨勬湰鍦板椁�(鐢ㄤ簬寮�閫氬椁愬崱:discountMember 鎷疯礉婧�) */
+    private Discount discount;
+}
diff --git a/server/services/src/main/java/com/doumee/core/douyin/dto/DouyinPrepareParam.java b/server/services/src/main/java/com/doumee/core/douyin/dto/DouyinPrepareParam.java
index a1ab6d6..afddd27 100644
--- a/server/services/src/main/java/com/doumee/core/douyin/dto/DouyinPrepareParam.java
+++ b/server/services/src/main/java/com/doumee/core/douyin/dto/DouyinPrepareParam.java
@@ -20,6 +20,6 @@
     @ApiModelProperty(value = "鍒哥爜鏄庢枃(鎵嬪姩杈撳叆鍦烘櫙),涓� qrContent 浜岄�変竴")
     private String code;
 
-    @ApiModelProperty(value = "鏍搁攢鎶栭煶闂ㄥ簵ID", required = true)
+    @ApiModelProperty(value = "鏍搁攢鎶栭煶闂ㄥ簵ID")
     private String poiId;
 }
diff --git a/server/services/src/main/java/com/doumee/core/wx/WxMiniUtilService.java b/server/services/src/main/java/com/doumee/core/wx/WxMiniUtilService.java
index 3800317..4b638d9 100644
--- a/server/services/src/main/java/com/doumee/core/wx/WxMiniUtilService.java
+++ b/server/services/src/main/java/com/doumee/core/wx/WxMiniUtilService.java
@@ -80,8 +80,8 @@
         request.setSubMchid(WxMiniConfig.wxProperties.getSubMchId());
         request.setNotifyUrl(WxMiniConfig.wxProperties.getRefundNotifyUrl());
         AmountReq amountReq = new AmountReq();
-        amountReq.setTotal(refundDTO.getTotalAmount().longValue());
-        amountReq.setRefund(refundDTO.getRefundAmount().longValue());
+        amountReq.setTotal(1L);//refundDTO.getTotalAmount().longValue());
+        amountReq.setRefund(1L);//refundDTO.getRefundAmount().longValue());
         amountReq.setCurrency("CNY");
         request.setAmount(amountReq);
         try {
diff --git a/server/services/src/main/java/com/doumee/dao/business/model/DouyinVerifyRecord.java b/server/services/src/main/java/com/doumee/dao/business/model/DouyinVerifyRecord.java
index a1be3d0..58422d0 100644
--- a/server/services/src/main/java/com/doumee/dao/business/model/DouyinVerifyRecord.java
+++ b/server/services/src/main/java/com/doumee/dao/business/model/DouyinVerifyRecord.java
@@ -98,4 +98,8 @@
 
     @ApiModelProperty(value = "鏄惁宸插垹闄� 0鏈垹闄� 1宸插垹闄�")
     private Integer isdeleted;
+
+    /** 鏍搁攢寮�閫氱殑濂楅鍗¤鎯�(闈炴暟鎹簱瀛楁,scanVerify 杩斿洖鏃堕檮甯�,渚涘墠绔睍绀哄椁愪俊鎭�) */
+    @com.baomidou.mybatisplus.annotation.TableField(exist = false)
+    private DiscountMember packageInfo;
 }
diff --git a/server/services/src/main/java/com/doumee/dao/business/vo/BikeIncomeStatVO.java b/server/services/src/main/java/com/doumee/dao/business/vo/BikeIncomeStatVO.java
index ac2b4e7..9083fe9 100644
--- a/server/services/src/main/java/com/doumee/dao/business/vo/BikeIncomeStatVO.java
+++ b/server/services/src/main/java/com/doumee/dao/business/vo/BikeIncomeStatVO.java
@@ -28,4 +28,7 @@
 
     @ApiModelProperty(value = "鏀跺叆閲戦(鍏�)")
     private BigDecimal income;
+
+    @ApiModelProperty(value = "璇ヨ溅鍨嬬殑杞﹁締鏁伴噺(bikes 琛ㄦ湭鍒犻櫎)")
+    private Long bikeCount;
 }
diff --git a/server/services/src/main/java/com/doumee/dao/business/vo/BikeUsageStatVO.java b/server/services/src/main/java/com/doumee/dao/business/vo/BikeUsageStatVO.java
new file mode 100644
index 0000000..e9eebf3
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/dao/business/vo/BikeUsageStatVO.java
@@ -0,0 +1,30 @@
+package com.doumee.dao.business.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 杞﹁締浣跨敤鎯呭喌 VO(绠$悊绔姤琛�:鑷杞�/鐢靛姩杞� 脳 浣跨敤涓�/绌洪棽)銆�
+ * <p>鍙e緞:bikes 鏈垹闄よ溅杈�,type=0 鑷杞� / 1 鐢靛姩杞�;
+ * status=0 绌洪棽 / 1 浣跨敤涓�,3 绂佺敤杞﹁締涓嶈鍏ャ��
+ *
+ * @author rk
+ * @date 2026/06/26
+ */
+@Data
+@ApiModel("杞﹁締浣跨敤鎯呭喌")
+public class BikeUsageStatVO {
+
+    @ApiModelProperty(value = "鑷杞︾┖闂叉暟閲�(status=0)")
+    private Long bikeIdle;
+
+    @ApiModelProperty(value = "鑷杞︿娇鐢ㄤ腑鏁伴噺(status=1)")
+    private Long bikeInUse;
+
+    @ApiModelProperty(value = "鐢靛姩杞︾┖闂叉暟閲�(status=0)")
+    private Long eleBikeIdle;
+
+    @ApiModelProperty(value = "鐢靛姩杞︿娇鐢ㄤ腑鏁伴噺(status=1)")
+    private Long eleBikeInUse;
+}
diff --git a/server/services/src/main/java/com/doumee/dao/business/vo/DashboardVO.java b/server/services/src/main/java/com/doumee/dao/business/vo/DashboardVO.java
new file mode 100644
index 0000000..9abb8b6
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/dao/business/vo/DashboardVO.java
@@ -0,0 +1,63 @@
+package com.doumee.dao.business.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 缁煎悎鐪嬫澘 VO(绠$悊绔姤琛�:鏀剁泭 + 璁㈠崟鏁� + 杞﹁締 + 瀹㈡埛鏁�)銆�
+ * <p>鍙e緞:
+ * <ul>
+ *   <li>鏀剁泭:goodsorder type=0 鎶奸噾 + status=4 宸茬粨绠� 鐨� closeMoney 涔嬪拰(鍒嗏啋鍏�),鍚� incomeStat</li>
+ *   <li>璁㈠崟鏁�:goodsorder payStatus=1 宸叉敮浠樿鍗曡鏁�</li>
+ *   <li>杞﹁締:鏈垹闄よ溅杈嗘�绘暟</li>
+ *   <li>瀹㈡埛鏁�:鎬讳細鍛�=鏈垹闄ゅ叏閮�;浠婃棩/鏄ㄦ棩鏂板鎸� member.create_date 钀藉湪瀵瑰簲鍖洪棿</li>
+ * </ul>
+ *
+ * @author rk
+ * @date 2026/06/26
+ */
+@Data
+@ApiModel("缁煎悎鐪嬫澘")
+public class DashboardVO {
+
+    // ---------------- 鏀剁泭(鍏�) ----------------
+
+    @ApiModelProperty(value = "鏈湀鏀剁泭(鍏�)")
+    private BigDecimal monthIncome;
+
+    @ApiModelProperty(value = "鏄ㄦ棩鏀剁泭(鍏�)")
+    private BigDecimal yesterdayIncome;
+
+    @ApiModelProperty(value = "浠婃棩鏀剁泭(鍏�)")
+    private BigDecimal todayIncome;
+
+    // ---------------- 璁㈠崟鏁� ----------------
+
+    @ApiModelProperty(value = "鏈湀璁㈠崟鏁�(宸叉敮浠�)")
+    private Long monthOrderCount;
+
+    @ApiModelProperty(value = "鏄ㄦ棩璁㈠崟鏁�(宸叉敮浠�)")
+    private Long yesterdayOrderCount;
+
+    @ApiModelProperty(value = "浠婃棩璁㈠崟鏁�(宸叉敮浠�)")
+    private Long todayOrderCount;
+
+    // ---------------- 杞﹁締 ----------------
+
+    @ApiModelProperty(value = "杞﹁締鎬绘暟(鏈垹闄�)")
+    private Long totalBikeCount;
+
+    // ---------------- 瀹㈡埛鏁� ----------------
+
+    @ApiModelProperty(value = "瀹㈡埛鎬绘暟(鏈垹闄や細鍛樻�绘暟)")
+    private Long totalMemberCount;
+
+    @ApiModelProperty(value = "鏄ㄦ棩鏂板瀹㈡埛(create_date 钀藉湪鏄ㄦ棩)")
+    private Long yesterdayNewMember;
+
+    @ApiModelProperty(value = "浠婃棩鏂板瀹㈡埛(create_date 鈮� 浠婃棩0鐐�)")
+    private Long todayNewMember;
+}
diff --git a/server/services/src/main/java/com/doumee/dao/business/vo/DouyinVerifyRecordPageVO.java b/server/services/src/main/java/com/doumee/dao/business/vo/DouyinVerifyRecordPageVO.java
index 0499e70..50d8bb5 100644
--- a/server/services/src/main/java/com/doumee/dao/business/vo/DouyinVerifyRecordPageVO.java
+++ b/server/services/src/main/java/com/doumee/dao/business/vo/DouyinVerifyRecordPageVO.java
@@ -63,6 +63,9 @@
     @ApiModelProperty(value = "鍏戞崲浜�(member.name,鏍搁攢鎿嶄綔浜�=璐拱浼氬憳鏈汉)")
     private String exchangerName;
 
+    @ApiModelProperty(value = "濂楅浣跨敤娆℃暟(璇ュ椁愬崱鍏宠仈鐨� member_rides 璁板綍鏁�;0=鏈娇鐢�)")
+    private Long useCount;
+
     @ApiModelProperty(value = "鐘舵�佹枃妗�(宸插厬鎹�/宸叉挙閿�/鏍搁攢澶辫触)")
     private String statusName;
 }
diff --git a/server/services/src/main/java/com/doumee/dao/business/vo/PackageSourceStatVO.java b/server/services/src/main/java/com/doumee/dao/business/vo/PackageSourceStatVO.java
new file mode 100644
index 0000000..303bc03
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/dao/business/vo/PackageSourceStatVO.java
@@ -0,0 +1,37 @@
+package com.doumee.dao.business.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 濂楅閿�鍞潵婧愮粺璁� VO(绠$悊绔姤琛�:鏈湀/鏈勾 脳 鎶栭煶鍏戞崲/灏忕▼搴忚喘涔�)銆�
+ * <p>鍙e緞:goodsorder type=1 濂楅鍗¤喘涔般�乸ayStatus=1 宸叉敮浠�;
+ * 鎶栭煶鍏戞崲 = payWay 2,灏忕▼搴忚喘涔� = payWay 0(寰俊);鎸� pay_date 闄愬畾鏈湀/鏈勾銆�
+ *
+ * @author rk
+ * @date 2026/06/26
+ */
+@Data
+@ApiModel("濂楅閿�鍞潵婧愮粺璁�")
+public class PackageSourceStatVO {
+
+    @ApiModelProperty(value = "鏈湀濂楅閿�鍞潵婧�")
+    private PeriodCount month;
+
+    @ApiModelProperty(value = "鏈勾濂楅閿�鍞潵婧�")
+    private PeriodCount year;
+
+    /**
+     * 鍗曚釜鏃舵鐨勫椁愰攢鍞潵婧愯鏁�(鎶栭煶鍏戞崲 / 灏忕▼搴忚喘涔�)銆�
+     */
+    @Data
+    @ApiModel("濂楅閿�鍞潵婧愯鏁�")
+    public static class PeriodCount {
+        @ApiModelProperty(value = "鎶栭煶鍏戞崲鏁伴噺(payWay=2)")
+        private Long douyinCount;
+
+        @ApiModelProperty(value = "灏忕▼搴忚喘涔版暟閲�(payWay=0 寰俊)")
+        private Long miniCount;
+    }
+}
diff --git a/server/services/src/main/java/com/doumee/dao/business/web/request/GoodsorderBackDTO.java b/server/services/src/main/java/com/doumee/dao/business/web/request/GoodsorderBackDTO.java
index 4322d84..149717a 100644
--- a/server/services/src/main/java/com/doumee/dao/business/web/request/GoodsorderBackDTO.java
+++ b/server/services/src/main/java/com/doumee/dao/business/web/request/GoodsorderBackDTO.java
@@ -19,7 +19,7 @@
     @ApiModelProperty(value = "閫�娆鹃噾棰�")
     private BigDecimal money;
 
-    @ApiModelProperty(value = "閫�娆鹃噾棰�")
+    @ApiModelProperty(value = "閫�娆捐鏄�")
     private String reason;
 
     @ApiModelProperty(value = "濂楅鍗¢��娆剧被鍨� 0閫�璐ч��娆� 1浠呴��娆�")
diff --git a/server/services/src/main/java/com/doumee/dao/business/web/response/HomeResponse.java b/server/services/src/main/java/com/doumee/dao/business/web/response/HomeResponse.java
index 486d7ab..d2ced6f 100644
--- a/server/services/src/main/java/com/doumee/dao/business/web/response/HomeResponse.java
+++ b/server/services/src/main/java/com/doumee/dao/business/web/response/HomeResponse.java
@@ -2,6 +2,7 @@
 
 import com.doumee.dao.business.model.Ad;
 import com.doumee.dao.business.model.Discount;
+import com.doumee.dao.business.model.DiscountMember;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
@@ -74,6 +75,8 @@
     @ApiModelProperty(value = "鐢佃溅杩愯惀鍖哄煙")
     private String eleBusinessArea;
 
+    @ApiModelProperty(value = "褰撳墠浼氬憳鏈夋晥濂楅(鏈�澶�10鏉�,鎸夎幏寰楁椂闂村�掑簭)")
+    private List<DiscountMember> validDiscountList;
 
 
 }
diff --git a/server/services/src/main/java/com/doumee/service/business/DouyinVerifyService.java b/server/services/src/main/java/com/doumee/service/business/DouyinVerifyService.java
index d336b75..fc98200 100644
--- a/server/services/src/main/java/com/doumee/service/business/DouyinVerifyService.java
+++ b/server/services/src/main/java/com/doumee/service/business/DouyinVerifyService.java
@@ -1,6 +1,7 @@
 package com.doumee.service.business;
 
 import com.doumee.core.douyin.dto.DouyinBaseResp;
+import com.doumee.core.douyin.dto.DouyinBoundProduct;
 import com.doumee.core.douyin.dto.DouyinCancelParam;
 import com.doumee.core.douyin.dto.DouyinPrepareParam;
 import com.doumee.core.douyin.dto.DouyinPrepareResp;
@@ -30,12 +31,37 @@
     DouyinVerifyRecord verify(DouyinVerifyParam param, String operator);
 
     /**
+     * 楠屽埜(鏍搁攢),浣跨敤璋冪敤鏂瑰凡鏍¢獙濂界殑濂楅缁戝畾缁撴灉(scanVerify 鏍搁攢鍓嶆牎楠屽悗璋冪敤)銆�
+     * <p>鏍搁攢鎴愬姛鍚庣洿鎺ョ敤 boundProduct 寮�閫氬椁�,涓嶅啀閲嶅鏌ヨ鍟嗗搧/濂楅銆�
+     * @param param        鏍搁攢鍏ュ弬
+     * @param operator     鎿嶄綔浜篒D
+     * @param boundProduct 鏍搁攢鍓嶅凡鏍¢獙鐨勬姈闊冲晢鍝� + 鏈湴濂楅(scanVerify 浼犲叆)
+     */
+    DouyinVerifyRecord verify(DouyinVerifyParam param, String operator, DouyinBoundProduct boundProduct);
+
+    /**
+     * 鏍搁攢鍓嶆牎楠�:鎸� skuId 鏍¢獙鎶栭煶鍟嗗搧鍦ㄥ簱涓斿凡缁戝畾鏈夋晥鏈湴濂楅銆�
+     * <p>scanVerify 鍦ㄦ牳閿�鍓嶈皟鐢�,澶辫触鎶涗笟鍔″紓甯�(鍒稿皻鏈牳閿�,閬垮厤鎶栭煶宸叉牳閿�浣嗘湰鍦版湭寮�鍗$殑涓嶄竴鑷�)銆�
+     * @param skuId 鏍搁攢鍒稿搴旂殑鎶栭煶 SKU ID
+     * @return 鎶栭煶鍟嗗搧 + 缁戝畾鐨勬湰鍦板椁�(渚� verify 寮�鍗″鐢�)
+     */
+    DouyinBoundProduct resolveBoundProduct(String skuId);
+
+    /**
      * 鎾ら攢鏍搁攢(鏍搁攢鍚� 1 灏忔椂鍐�),鏇存柊璁板綍鎾ら攢鐘舵��
      * @param operator 鎿嶄綔浜篒D(鐢辫皟鐢ㄧ浼犲叆,web 绔彇鐧诲綍浼氬憳ID)
      */
     DouyinVerifyRecord cancel(DouyinCancelParam param, String operator);
 
     /**
+     * 鎸� discountMemberId 鎶婂椁愬崱璇︽儏濉埌 record.packageInfo(scanVerify 灞曠ず鐢�)銆�
+     * <p>鏃犲椁愬崱ID鎴栨煡涓嶅埌鏃�,packageInfo 缃� null,涓嶅奖鍝嶄富娴佺▼銆�
+     *
+     * @param record 鏍搁攢璁板綍(鍚� discountMemberId)
+     */
+    void fillPackageInfo(DouyinVerifyRecord record);
+
+    /**
      * 鏍搁攢璁板綍鍒嗛〉(web 绔皬绋嬪簭鑷敤,绠�鍗曞垎椤�)
      */
     PageData<DouyinVerifyRecord> findPage(PageWrap<DouyinVerifyRecord> pageWrap);
diff --git a/server/services/src/main/java/com/doumee/service/business/GoodsorderService.java b/server/services/src/main/java/com/doumee/service/business/GoodsorderService.java
index a63ecaa..c8fb0ca 100644
--- a/server/services/src/main/java/com/doumee/service/business/GoodsorderService.java
+++ b/server/services/src/main/java/com/doumee/service/business/GoodsorderService.java
@@ -172,9 +172,16 @@
     void forceCloseGoodsorder(String orderId);
 
     /**
-     * 閫�娆�
+     * 閫�娆�(鐧诲綍浜轰粠 Shiro 涓婁笅鏂囧彇,platform 绔敤)
      */
     void backGoodsorder(GoodsorderBackDTO goodsorderBackDTO);
+
+    /**
+     * 閫�娆�(鐧诲綍浜虹敱璋冪敤鏂逛紶鍏�,web 绔� JWT 鍦烘櫙鐢�,creator=缁戝畾鐨勭鐞嗗憳ID)
+     * @param goodsorderBackDTO 閫�娆惧叆鍙�
+     * @param creator           鎿嶄綔浜篒D(閫�娆惧崟 + 濂楅鎿嶄綔鏃ュ織鐨� creator)
+     */
+    void backGoodsorder(GoodsorderBackDTO goodsorderBackDTO, String creator);
     List<MemberRides> getMemberRidesForClose(String orderid );
     /**
      * 鑾峰彇鍙��娆句俊鎭�
diff --git a/server/services/src/main/java/com/doumee/service/business/MemberService.java b/server/services/src/main/java/com/doumee/service/business/MemberService.java
index bc36b2a..2d1a8c5 100644
--- a/server/services/src/main/java/com/doumee/service/business/MemberService.java
+++ b/server/services/src/main/java/com/doumee/service/business/MemberService.java
@@ -143,4 +143,13 @@
     AccountResponse wxPhone(WxPhoneRequest wxPhoneRequest);
 
     UserResponse getUserInfo(String memberId);
+
+    /**
+     * 閫�鍑虹櫥褰�:娓呯┖褰撳墠浼氬憳鎵嬫満鍙�(缃┖涓�)銆�
+     * <p>JWT 鏃犵姸鎬�,鏃犳硶鍚婇攢 token;娓� phone 鍚庝細鍛樺洖鍒版湭鎺堟潈鎵嬫満鍙风姸鎬�,
+     * 涓嬫杩涘叆闇�閲嶆柊 wxLogin + wxPhone銆�
+     *
+     * @param memberId 浼氬憳ID
+     */
+    void clearPhone(String memberId);
 }
diff --git a/server/services/src/main/java/com/doumee/service/business/impl/DouyinVerifyServiceImpl.java b/server/services/src/main/java/com/doumee/service/business/impl/DouyinVerifyServiceImpl.java
index fc14eb8..6211902 100644
--- a/server/services/src/main/java/com/doumee/service/business/impl/DouyinVerifyServiceImpl.java
+++ b/server/services/src/main/java/com/doumee/service/business/impl/DouyinVerifyServiceImpl.java
@@ -9,6 +9,7 @@
 import com.doumee.core.constants.ResponseStatus;
 import com.doumee.core.douyin.DouyinClient;
 import com.doumee.core.douyin.dto.DouyinBaseResp;
+import com.doumee.core.douyin.dto.DouyinBoundProduct;
 import com.doumee.core.douyin.dto.DouyinCancelParam;
 import com.doumee.core.douyin.dto.DouyinCancelReq;
 import com.doumee.core.douyin.dto.DouyinCancelResp;
@@ -135,7 +136,7 @@
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public DouyinVerifyRecord verify(DouyinVerifyParam param, String operator) {
+    public DouyinVerifyRecord verify(DouyinVerifyParam param, String operator, DouyinBoundProduct boundProduct) {
         // 鍏ュ弬鏍¢獙
         if (param == null || StringUtils.isBlank(param.getVerifyToken())) {
             throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "verifyToken 涓嶈兘涓虹┖");
@@ -153,6 +154,10 @@
         if (StringUtils.isBlank(param.getSkuId())) {
             // 鏃� skuId 鍒欐棤娉曞弽鏌ュ椁�(鏍搁攢杩斿洖鏈韩涓嶅惈鍟嗗搧鏍囪瘑),鐩存帴鎷︽埅
             throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "skuId 涓嶈兘涓虹┖");
+        }
+        if (boundProduct == null || boundProduct.getProduct() == null || boundProduct.getDiscount() == null) {
+            // 鍏滃簳:濂楅缁戝畾缁撴灉缂哄け(scanVerify 搴斿凡鏍¢獙,杩欓噷闃� NPE)
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鏈壘鍒拌鍒稿搴旂殑鏈湴濂楅,璇峰厛鍦ㄧ鐞嗙缁戝畾");
         }
         Date now = new Date();
 
@@ -204,8 +209,16 @@
         }
 
         // 鏍搁攢鎴愬姛:涓哄綋鍓嶇櫥褰曚汉寮�閫氬椁�(浠讳竴姝ュけ璐� 鈫� 鏁村崟鍥炴粴)
-        openDiscountForVerify(rec, param, operator);
+        // 娉�:scanVerify 宸插湪鏍搁攢鍓嶆牎楠岃繃濂楅缁戝畾骞堕�忎紶缁撴灉,杩欓噷涓嶅啀閲嶅鏌ヨ
+        openDiscountForVerify(rec, param, boundProduct, operator);
         return rec;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public DouyinVerifyRecord verify(DouyinVerifyParam param, String operator) {
+        // 鏃犻鏍¢獙缁撴灉鐨勫吋瀹瑰叆鍙�:鏍搁攢鍓嶅厛鏍¢獙濂楅缁戝畾(鏍搁攢鍔ㄤ綔鍦ㄩ噸杞藉唴瀹屾垚)
+        return verify(param, operator, resolveBoundProduct(param.getSkuId()));
     }
 
     /**
@@ -215,19 +228,23 @@
      *
      * @param rec      鏍搁攢璁板綍(鍚� originCode/certificateId 绛夋姈闊虫爣璇�,寮�閫氬悗鍥炲~濂楅鍗D)
      * @param param    鏍搁攢鍏ュ弬(鍚� skuId 鍙嶆煡濂楅銆乸ayAmount 蹇収)
+     * @param boundProduct 鏍搁攢鍓嶅凡鏍¢獙鐨勬姈闊冲晢鍝� + 鏈湴濂楅(閬垮厤閲嶅鏌ヨ)
      * @param operator 鎿嶄綔浜� = 濂楅褰掑睘浜�(web 绔櫥褰曚細鍛� id)
      */
-    private void openDiscountForVerify(DouyinVerifyRecord rec, DouyinVerifyParam param, String operator) {
-        // 鈶� 鍙嶆煡濂楅:skuId 鈫� douyin_product_sku 鈫� product_id 鈫� douyin_product.out_id 鈫� discount
-        DouyinProduct product = resolveProduct(param.getSkuId());
-        Discount discount = resolveDiscount(product);
+    private void openDiscountForVerify(DouyinVerifyRecord rec, DouyinVerifyParam param,
+                                       DouyinBoundProduct boundProduct, String operator) {
+        // 鍟嗗搧 + 濂楅宸茬敱 scanVerify 鏍搁攢鍓嶆牎楠�(resolveBoundProduct)鏌ュ嚭骞堕�忎紶,鐩存帴浣跨敤
+        DouyinProduct product = boundProduct.getProduct();
+        Discount discount = boundProduct.getDiscount();
 
         Date now = new Date();
 
-        // 鈶� 闃查噸:鍚屼竴鍒哥爜宸蹭负璇ョ敤鎴峰紑杩囧椁愬崱鍒欒烦杩�(閬垮厤閲嶅鏍搁攢閲嶅紑)
+        // 鈶� 闃查噸:鍚屼竴鍒哥爜宸蹭负璇ョ敤鎴峰紑杩囥�屾甯搞�嶅椁愬崱鍒欒烦杩�(閬垮厤閲嶅鏍搁攢閲嶅紑)銆�
+        //    娉ㄦ剰:宸蹭綔搴�(status=1,濡傛挙閿�鏍搁攢鍚�)鐨勫崱涓嶅弬涓庨槻閲嶁�斺�旀挙閿�鍚庨噸鏂版牳閿�搴旀甯稿紑鏂板崱銆�
         DiscountMember existCard = discountMemberMapper.selectOne(new QueryWrapper<DiscountMember>().lambda()
                 .eq(DiscountMember::getCode, rec.getOriginCode())
                 .eq(DiscountMember::getMemberId, operator)
+                .eq(DiscountMember::getStatus, Constants.ZERO)
                 .eq(DiscountMember::getIsdeleted, Constants.ZERO)
                 .last("limit 1"));
         if (existCard != null) {
@@ -340,13 +357,23 @@
     private Discount resolveDiscount(DouyinProduct product) {
         Discount discount = discountMapper.selectOne(new QueryWrapper<Discount>().lambda()
                 .eq(Discount::getId, product.getOutId())
-                .eq(Discount::getStatus, Constants.ZERO)
                 .eq(Discount::getIsdeleted, Constants.ZERO)
                 .last("limit 1"));
         if (discount == null) {
             throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鏈壘鍒拌鍒稿搴旂殑鏈湴濂楅,璇峰厛鍦ㄧ鐞嗙缁戝畾");
         }
         return discount;
+    }
+
+    @Override
+    public DouyinBoundProduct resolveBoundProduct(String skuId) {
+        if (StringUtils.isBlank(skuId)) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "skuId 涓嶈兘涓虹┖");
+        }
+        // 澶嶇敤鏃㈡湁鏍¢獙閾捐矾:skuId 鈫� 鎶栭煶鍟嗗搧(鍦ㄥ簱 + 宸茬粦 out_id)鈫� 鏈湴濂楅(鏈夋晥)
+        DouyinProduct product = resolveProduct(skuId);
+        Discount discount = resolveDiscount(product);
+        return new DouyinBoundProduct(product, discount);
     }
 
     @Override
@@ -389,10 +416,13 @@
         rec.setRawResponse(respText);
         // 鎾ら攢澶辫触:鏇存柊璁板綍鎻忚堪鍚庢姏鍑�(璁板綍淇濈暀鍘熸牳閿�鐘舵��)
         if (!ok) {
+            // 澶辫触鍘熷洜:浼樺厛 extra.description,鏈� sub_description 鏃惰拷鍔�(sub_description 鏇村叿浣�)
             String desc = resp == null || resp.getExtra() == null ? "鏃犲搷搴�" : resp.getExtra().getDescription();
-            rec.setCancelMsg("鎾ら攢澶辫触:" + desc);
+            String subDesc = resp == null || resp.getExtra() == null ? null : resp.getExtra().getSubDescription();
+            String failMsg = StringUtils.isBlank(subDesc) ? desc : desc + ";" + subDesc;
+            rec.setCancelMsg("鎾ら攢澶辫触:" + failMsg);
             douyinVerifyRecordMapper.updateById(rec);
-            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鎾ら攢澶辫触:" + desc);
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鎾ら攢澶辫触:" + failMsg);
         }
         // 鎾ら攢鎴愬姛:缃挙閿�鐘舵�併�佹挙閿�鏃堕棿涓庢挙閿�浜�
         rec.setCancelStatus(Constants.DOUYIN_VERIFY_CANCEL_STATUS.DONE.getKey());
@@ -403,6 +433,15 @@
         // 鍚屾浣滃簾鏈湴宸插紑閫氱殑濂楅鍗�(闃叉鎶栭煶鎾ら攢鍚庡椁愪粛琚娇鐢�);鍙傜収 backGoodsorder 閫�鍗�
         cancelDiscountMember(rec, operator, now);
         return rec;
+    }
+
+    @Override
+    public void fillPackageInfo(DouyinVerifyRecord record) {
+        // 鏃犲椁愬崱ID鎴栨煡涓嶅埌鏃剁疆 null,涓嶅奖鍝嶄富娴佺▼(scanVerify 鐢ㄤ簬鍓嶇灞曠ず濂楅淇℃伅)
+        if (record == null || StringUtils.isBlank(record.getDiscountMemberId())) {
+            return;
+        }
+        record.setPackageInfo(discountMemberMapper.selectById(record.getDiscountMemberId()));
     }
 
     /**
@@ -495,6 +534,8 @@
                 .selectAs(DouyinProduct::getCategory, DouyinVerifyRecordPageVO::getCategory)
                 // 鎶栭煶鍒稿悕:discount_member.name(鏈湴寮�閫氬椁愬悕)
                 .selectAs(DiscountMember::getName, DouyinVerifyRecordPageVO::getCouponName)
+                // 濂楅浣跨敤娆℃暟:瀛愭煡璇㈢粺璁¤濂楅鍗″湪 member_rides 鐨勯獞琛岃褰曟暟(t 涓轰富琛� douyin_verify_record)
+                .select(" ( select count(1) from member_rides where discount_member_id = t.discount_member_id and isdeleted = 0 ) ", DouyinVerifyRecordPageVO::getUseCount)
                 // 涓夎〃 leftJoin:discount_member(缁� discount_member_id)鈫� member(缁� member_id);douyin_product(缁� product_id)
                 .leftJoin(DiscountMember.class, DiscountMember::getId, DouyinVerifyRecord::getDiscountMemberId)
                 .leftJoin(Member.class, Member::getId, DiscountMember::getMemberId)
diff --git a/server/services/src/main/java/com/doumee/service/business/impl/GoodsorderServiceImpl.java b/server/services/src/main/java/com/doumee/service/business/impl/GoodsorderServiceImpl.java
index 2846a2b..68a49e9 100644
--- a/server/services/src/main/java/com/doumee/service/business/impl/GoodsorderServiceImpl.java
+++ b/server/services/src/main/java/com/doumee/service/business/impl/GoodsorderServiceImpl.java
@@ -482,6 +482,13 @@
                 }
             }
         }
+        // 褰撳墠浼氬憳鏈夋晥濂楅(status=0 姝e父 + isdeleted=0),鎸夎幏寰楁椂闂�(createDate)鍊掑簭,鏈�澶�10鏉�
+        homeResponse.setValidDiscountList(discountMemberMapper.selectList(new QueryWrapper<DiscountMember>().lambda()
+                .eq(DiscountMember::getMemberId, memberId)
+                .eq(DiscountMember::getStatus, Constants.ZERO)
+                .eq(DiscountMember::getIsdeleted, Constants.ZERO)
+                .orderByDesc(DiscountMember::getCreateDate)
+                .last(" limit 10 ")));
         return homeResponse;
     }
 
@@ -977,7 +984,16 @@
 
     @Override
     public void backGoodsorder(GoodsorderBackDTO goodsorderBackDTO) {
+        // platform 绔�:鐧诲綍浜轰粠 Shiro 涓婁笅鏂囧彇,濮旀墭缁欏甫 creator 鐨勯噸杞芥柟娉�
         LoginUserInfo principal = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
+        if (Objects.isNull(principal) || StringUtils.isBlank(principal.getId())) {
+            throw new BusinessException(ResponseStatus.BE_OVERDUE);
+        }
+        backGoodsorder(goodsorderBackDTO, principal.getId());
+    }
+
+    @Override
+    public void backGoodsorder(GoodsorderBackDTO goodsorderBackDTO, String creator) {
         if(Objects.isNull(goodsorderBackDTO)
         || StringUtils.isBlank(goodsorderBackDTO.getOrderId())
                 || Objects.isNull(goodsorderBackDTO.getBackType())
@@ -1013,7 +1029,7 @@
             refundDTO.setRefundAmount(goodsorderBackDTO.getMoney().multiply(new BigDecimal(100)));
             refundDTO.setTotalAmount(goodsorder.getMoney());
             refundDTO.setMemberId(goodsorder.getMemberId());
-            refundDTO.setCreator(principal.getId());
+            refundDTO.setCreator(creator);
             refundDTO.setReason(goodsorderBackDTO.getReason());
             refundDTO.setType(Constants.REFUND_TYPE.BACK.getKey());
             //閫�璐ч��娆� 鏌ョ湅濂楅璁㈠崟鐘舵�� 鏇存柊璁㈠崟淇℃伅
@@ -1033,7 +1049,7 @@
                     //鎿嶄綔鏃ュ織
                     DiscountLog discountLog = new DiscountLog();
                     discountLog.setIsdeleted(Constants.ZERO);
-                    discountLog.setCreator(principal.getId());
+                    discountLog.setCreator(creator);
                     discountLog.setCreateDate(new Date());
                     discountLog.setDiscountMemberId(discountMember.getId());
                     discountLog.setType(Constants.ONE);
@@ -1361,7 +1377,7 @@
         request.setOutTradeNo(goodsorder.getId());
         request.setNotifyUrl(WxMiniConfig.wxProperties.getNotifyUrl());//杩欎釜鍥炶皟url蹇呴』鏄痟ttps寮�澶寸殑
         Amount amount = new Amount();
-        amount.setTotal(goodsorder.getMoney().intValue());
+        amount.setTotal(1);//goodsorder.getMoney().intValue());
         request.setAmount(amount);
 //        PrepayResponse res = WxMiniConfig.wxPayService.prepay(request);
             // 璺熶箣鍓嶄笅鍗曠ず渚嬩竴鏍凤紝濉厖棰勪笅鍗曞弬鏁�
diff --git a/server/services/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java b/server/services/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java
index 9154af3..dbd486b 100644
--- a/server/services/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java
+++ b/server/services/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java
@@ -417,5 +417,13 @@
         return userResponse;
     }
 
+    @Override
+    public void clearPhone(String memberId) {
+        // 閫�鍑虹櫥褰�:娓呯┖浼氬憳鎵嬫満鍙�(缃┖涓�),淇濈暀鍏朵粬淇℃伅(鍚� sysuser 缁戝畾)
+        memberMapper.update(null, new UpdateWrapper<Member>().lambda()
+                .set(Member::getPhone, StringUtils.EMPTY)
+                .eq(Member::getId, memberId));
+    }
+
 
 }
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 8f85057..500d6d9 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
@@ -155,7 +155,23 @@
             incomeByParam.merge(o.getParamId(), amount, BigDecimal::add);
         }
 
-        // 5. 缁勮缁撴灉:杞﹀瀷鍚� + 澶х被 + 鏀跺叆(鍒嗏啋鍏�,2浣�),鎸夋敹鍏ラ檷搴�
+        // 5. 鎸� paramId 缁熻姣忕被杞﹀瀷鐨勮溅杈嗘暟閲�(bikes 琛ㄦ湭鍒犻櫎),涓�娆″垎缁勬煡璇㈤伩鍏� N 娆� count
+        Map<String, Long> bikeCountByParam;
+        if (incomeByParam.isEmpty()) {
+            // 鏃犳湁鏀跺叆鐨勮溅鍨嬫椂璺宠繃鏌ヨ:绌洪泦鍚堜紶缁� in() 浼氱敓鎴� "IN ()",PostgreSQL 璇硶閿欒
+            bikeCountByParam = Collections.emptyMap();
+        } else {
+            bikeCountByParam = bikesMapper.selectList(
+                    new QueryWrapper<Bikes>().lambda()
+                            .select(Bikes::getParamId)
+                            .eq(Bikes::getIsdeleted, Constants.ZERO)
+                            .in(Bikes::getParamId, incomeByParam.keySet()))
+                    .stream()
+                    .filter(b -> b.getParamId() != null)
+                    .collect(Collectors.groupingBy(Bikes::getParamId, Collectors.counting()));
+        }
+
+        // 6. 缁勮缁撴灉:杞﹀瀷鍚� + 澶х被 + 鏀跺叆(鍒嗏啋鍏�,2浣�)+ 杞﹁締鏁�,鎸夋敹鍏ラ檷搴�
         List<BikeIncomeStatVO> result = new ArrayList<>();
         for (Map.Entry<String, BigDecimal> e : incomeByParam.entrySet()) {
             BaseParam param = paramMap.get(e.getKey());
@@ -164,6 +180,7 @@
             vo.setParamName(param == null ? "鏈煡杞﹀瀷" : param.getName());
             vo.setCategory(param == null ? "鏈煡" : categoryOf(param.getType()));
             vo.setIncome(e.getValue().divide(CENT_PER_YUAN, 2, BigDecimal.ROUND_HALF_UP));
+            vo.setBikeCount(bikeCountByParam.getOrDefault(e.getKey(), 0L));
             result.add(vo);
         }
         result.sort(Comparator.comparing(BikeIncomeStatVO::getIncome).reversed());
@@ -262,7 +279,7 @@
         BigDecimal totalCents = BigDecimal.ZERO;
         for (Goodsorder o : orders) {
             BigDecimal amount = o.getCloseMoney() == null ? BigDecimal.ZERO : o.getCloseMoney();
-            sumByDay.merge(DateUtil.getShortDateStr(o.getPayDate()), amount, BigDecimal::add);
+            sumByDay.merge(DateUtil.getDateLong(o.getPayDate()), amount, BigDecimal::add);
             totalCents = totalCents.add(amount);
         }
 
@@ -272,7 +289,7 @@
         List<IncomeDailyVO> dailyList = new ArrayList<>();
         for (Date d : DateUtil.getDateList(DateUtil.getStartOfDay(start), DateUtil.getStartOfDay(end))) {
             IncomeDailyVO vo = new IncomeDailyVO();
-            vo.setDate(DateUtil.getShortDateStr(d));
+            vo.setDate(DateUtil.getDateLong(d));
             BigDecimal daySum = sumByDay.getOrDefault(vo.getDate(), BigDecimal.ZERO);
             // 鍒嗏啋鍏�,2浣嶅皬鏁�
             vo.setIncome(daySum.divide(CENT_PER_YUAN, 2, BigDecimal.ROUND_HALF_UP));
diff --git a/server/services/src/main/resources/application-dev.yml b/server/services/src/main/resources/application-dev.yml
index ea92283..cbf46c8 100644
--- a/server/services/src/main/resources/application-dev.yml
+++ b/server/services/src/main/resources/application-dev.yml
@@ -52,14 +52,14 @@
     mchKey: W97N53Q71326D6JZ2E9HY5M4VT4BAC8S
 #    notifyUrl: http://xiaopiqiu3.natapp1.cc/api/wxPayNotify
 #    refundNotifyUrl: http://xiaopiqiu3.natapp1.cc/api/wxRefundNotify
-    notifyUrl: https://dmtest.ahapp.net/bike_h5_api/api/wxPayNotify
-    refundNotifyUrl: https://dmtest.ahapp.net/bike_h5_api/api/wxRefundNotify
-#    keyPath: /usr/local/aliConfig/bike/apiclient_cert.p12
-#    privateCertPath: /usr/local/aliConfig/bike/apiclient_cert.pem
-#    privateKeyPath: /usr/local/aliConfig/bike/apiclient_key.pem
-    keyPath: d://apiclient_cert.p12
-    privateCertPath: d://apiclient_cert.pem
-    privateKeyPath: d://apiclient_key.pem
+    notifyUrl: https://test.doumee.cn/bikeWeb/api/wxPayNotify
+    refundNotifyUrl: https://test.doumee.cn/bikeWeb/api/wxRefundNotify
+    keyPath: /usr/local/jars/bike/apiclient_cert.p12
+    privateCertPath: /usr/local/jars/bike/apiclient_cert.pem
+    privateKeyPath: /usr/local/jars/bike/apiclient_key.pem
+#    keyPath: d://apiclient_cert.p12
+#    privateCertPath: d://apiclient_cert.pem
+#    privateKeyPath: d://apiclient_key.pem
     #鏈嶅姟鍟�-------------end---
     existsSub: 1
     appSecret: 1ceb7c9dff3c4330d653adc3ca55ea24
diff --git a/server/web/src/main/java/com/doumee/api/web/AccountApi.java b/server/web/src/main/java/com/doumee/api/web/AccountApi.java
index 47e9c8d..ea8afae 100644
--- a/server/web/src/main/java/com/doumee/api/web/AccountApi.java
+++ b/server/web/src/main/java/com/doumee/api/web/AccountApi.java
@@ -107,6 +107,18 @@
         return  ApiResponse.success("鏌ヨ鎴愬姛",userResponse);
     }
 
+    @LoginRequired
+    @ApiOperation(value = "閫�鍑虹櫥褰�", notes = "娓呯┖褰撳墠浼氬憳鎵嬫満鍙�,涓嬫杩涘叆闇�閲嶆柊鎺堟潈")
+    @PostMapping("/logout")
+    @ApiImplicitParams({
+            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "鐢ㄦ埛token鍊�", required = true),
+    })
+    public ApiResponse logout() {
+        // JWT 鏃犵姸鎬�,鏃犳硶鍚婇攢 token;姝ゅ娓呯┖浼氬憳鎵嬫満鍙�,浣垮叾鍥炲埌鏈巿鏉冩墜鏈哄彿鐘舵��
+        memberService.clearPhone(getMemberId());
+        return ApiResponse.success("鎿嶄綔鎴愬姛");
+    }
+
 
     @ApiOperation(value = "娴嬭瘯鐢熸垚浜岀淮鐮�", notes = "灏忕▼搴忕")
     @GetMapping("/generateWXMiniCode")
diff --git a/server/web/src/main/java/com/doumee/api/web/DouyinApi.java b/server/web/src/main/java/com/doumee/api/web/DouyinApi.java
index 1559c60..be1cf40 100644
--- a/server/web/src/main/java/com/doumee/api/web/DouyinApi.java
+++ b/server/web/src/main/java/com/doumee/api/web/DouyinApi.java
@@ -7,6 +7,7 @@
 import com.doumee.core.constants.ResponseStatus;
 import com.doumee.core.douyin.DouyinClient;
 import com.doumee.core.douyin.dto.DouyinBaseResp;
+import com.doumee.core.douyin.dto.DouyinBoundProduct;
 import com.doumee.core.douyin.dto.DouyinPrepareParam;
 import com.doumee.core.douyin.dto.DouyinPrepareResp;
 import com.doumee.core.douyin.dto.DouyinShopPoiResp;
@@ -22,6 +23,8 @@
 import com.doumee.service.business.DouyinVerifyLogService;
 import com.doumee.service.business.DouyinVerifyService;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
@@ -88,6 +91,9 @@
     @PreventRepeat
     @ApiOperation("鎵爜涓�姝ユ牳閿�(楠屽埜鍑嗗 + 鏍搁攢鍚堝苟;鍓嶇鍙皟姝ゆ帴鍙�)")
     @PostMapping("/scanVerify")
+    @ApiImplicitParams({
+            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "鐢ㄦ埛token鍊�", required = true),
+    })
     public ApiResponse<DouyinVerifyRecord> scanVerify(@RequestBody DouyinPrepareParam param) {
         String apiPath = "/web/douyin/scanVerify";
         String memberId = getMemberId();
@@ -137,13 +143,19 @@
         verifyParam.setSkuId(cert.getSku().getSkuId());
         verifyParam.setPayAmount(cert.getAmount() == null ? null : cert.getAmount().getPayAmount());
 
-        // 鈶� 鏍搁攢 + 寮�濂楅(鍗曠嫭璁颁竴鏉� VERIFY 鏃ュ織)
+        // 鈶� 鏍搁攢鍓嶆牎楠�:鍟嗗搧鍦ㄥ簱 + 宸茬粦瀹氭湁鏁堝椁�;澶辫触鐩存帴鎷︽埅(鍒稿皻鏈牳閿�,閬垮厤鎶栭煶宸叉牳閿�浣嗘湰鍦版湭寮�鍗�)
+        DouyinBoundProduct boundProduct = douyinVerifyService.resolveBoundProduct(verifyParam.getSkuId());
+
+        // 鈶� 鏍搁攢 + 寮�濂楅(鍗曠嫭璁颁竴鏉� VERIFY 鏃ュ織)
         long verifyStart = System.currentTimeMillis();
         DouyinVerifyLog verifyLog = baseLog(Constants.DOUYIN_VERIFY_OPERATE_TYPE.VERIFY.getKey(), apiPath, verifyStart);
         verifyLog.setRawRequest(JSON.toJSONString(verifyParam));
         verifyLog.setPoiId(verifyParam.getPoiId());
         try {
-            DouyinVerifyRecord rec = douyinVerifyService.verify(verifyParam, memberId);
+            // 閫忎紶鏍搁攢鍓嶆牎楠岀粨鏋�,verify 鍐呬笉鍐嶉噸澶嶆煡璇㈠晢鍝�/濂楅
+            DouyinVerifyRecord rec = douyinVerifyService.verify(verifyParam, memberId, boundProduct);
+            // 闄勫甫鏈寮�閫氱殑濂楅鍗¤鎯�(渚涘墠绔牳閿�鍚庡睍绀哄椁愪俊鎭�)
+            douyinVerifyService.fillPackageInfo(rec);
             fillByRecord(verifyLog, rec);
             return ApiResponse.success(rec);
         } catch (Throwable e) {
@@ -173,6 +185,9 @@
     @LoginRequired
     @ApiOperation("鏍搁攢璁板綍鍒嗛〉")
     @PostMapping("/page")
+    @ApiImplicitParams({
+            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "鐢ㄦ埛token鍊�", required = true),
+    })
     public ApiResponse<PageData<DouyinVerifyRecord>> findPage(@RequestBody PageWrap<DouyinVerifyRecord> pageWrap) {
         return ApiResponse.success(douyinVerifyService.findPage(pageWrap));
     }
@@ -180,6 +195,9 @@
     @LoginRequired
     @ApiOperation("鏍搁攢璁板綍璇︽儏")
     @GetMapping("/{id}")
+    @ApiImplicitParams({
+            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "鐢ㄦ埛token鍊�", required = true),
+    })
     public ApiResponse<DouyinVerifyRecord> findById(@PathVariable String id) {
         return ApiResponse.success(douyinVerifyService.findById(id));
     }
diff --git a/server/web/src/main/java/com/doumee/api/web/ManagerApi.java b/server/web/src/main/java/com/doumee/api/web/ManagerApi.java
index 614e00b..bf499b2 100644
--- a/server/web/src/main/java/com/doumee/api/web/ManagerApi.java
+++ b/server/web/src/main/java/com/doumee/api/web/ManagerApi.java
@@ -10,6 +10,8 @@
 import com.doumee.core.model.PageData;
 import com.doumee.core.model.PageWrap;
 import com.doumee.dao.business.model.*;
+import com.doumee.dao.business.web.request.GoodsorderBackDTO;
+import com.doumee.dao.business.web.request.GoodsorderCanBanlanceDTO;
 import com.doumee.dao.business.web.response.UserResponse;
 import com.doumee.dao.system.dto.WebLoginDTO;
 import com.doumee.dao.system.model.SystemUser;
@@ -30,6 +32,7 @@
 import javax.servlet.http.HttpServletRequest;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Created by IntelliJ IDEA.
@@ -54,6 +57,9 @@
     private SystemLoginService systemLoginService;
     @Autowired
     private SystemUserService systemUserService;
+    /** 璁㈠崟閫�娆�/鍙��娆句俊鎭煡璇�(web 绔� JWT 鍦烘櫙) */
+    @Autowired
+    private GoodsorderService goodsorderService;
     @LoginRequired
     @PreventRepeat(limit = 10, lockTime = 10000)
     @ApiOperation("鐧诲綍绠$悊鍛樿处鍙�")
@@ -130,4 +136,33 @@
         return ApiResponse.success(list);
     }
 
+    @LoginRequired
+    @ApiOperation("鑾峰彇鍙��娆句俊鎭�")
+    @GetMapping("/getGoodsorderCanBanlanceDTO")
+    public ApiResponse<GoodsorderCanBanlanceDTO> getGoodsorderCanBanlanceDTO(@RequestParam String orderId) {
+        // 浠呮煡璇�,鏃犵櫥褰曚汉鍐欏叆;鏍¢獙绠$悊鍛�
+        UserResponse user = this.getUserResponse();
+        if (user.getSysuser() == null) {
+            throw new BusinessException(ResponseStatus.NOT_ALLOWED);
+        }
+        return ApiResponse.success(goodsorderService.getGoodsorderCanBanlanceDTO(orderId));
+    }
+
+    @PreventRepeat
+    @LoginRequired
+    @ApiOperation("閫�娆�")
+    @PostMapping("/backGoodsorder")
+    public ApiResponse backGoodsorder(@RequestBody GoodsorderBackDTO goodsorderBackDTO) {
+        // 閫�娆句负绠$悊鍛樻搷浣�:鏍¢獙宸茬粦瀹氱郴缁熺鐞嗗憳,creator 鍙� sysuser.id(涓� platform Shiro 鍙e緞涓�鑷�)
+        UserResponse user = this.getUserResponse();
+        if (user.getSysuser() == null) {
+            throw new BusinessException(ResponseStatus.NOT_ALLOWED);
+        }
+        if (Objects.nonNull(goodsorderBackDTO) && Objects.isNull(goodsorderBackDTO.getBackType())) {
+            goodsorderBackDTO.setBackType(Constants.ONE);
+        }
+        goodsorderService.backGoodsorder(goodsorderBackDTO, user.getSysuser().getId());
+        return ApiResponse.success(null);
+    }
+
 }

--
Gitblit v1.9.3