From 3e210fac9492b90e21ca9bf76c1d9a8fda1f4388 Mon Sep 17 00:00:00 2001
From: rk <94314517@qq.com>
Date: 星期三, 13 五月 2026 11:32:17 +0800
Subject: [PATCH] 代码生成

---
 server/services/src/main/java/com/doumee/service/business/DriverInfoService.java            |    6 
 server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java   |  428 ++++++++++--
 server/services/src/main/java/com/doumee/dao/vo/ShopPerformanceVO.java                      |   31 
 server/services/src/main/java/com/doumee/dao/business/model/MemberCoupon.java               |  134 +++
 server/services/src/main/java/com/doumee/dao/dto/DataBoardQueryDTO.java                     |   25 
 server/services/src/main/java/com/doumee/dao/vo/RevenueTrendVO.java                         |   22 
 server/services/src/main/java/com/doumee/dao/vo/DataBoardVO.java                            |   32 
 server/services/src/main/java/com/doumee/service/business/ShopInfoService.java              |    6 
 server/web/src/main/java/com/doumee/api/web/ConfigApi.java                                  |   14 
 server/admin/src/main/java/com/doumee/api/business/DriverInfoController.java                |    1 
 server/admin/src/main/java/com/doumee/api/business/DataBoardController.java                 |   55 +
 server/services/src/main/java/com/doumee/config/jwt/WebMvcConfig.java                       |   12 
 server/services/src/main/java/com/doumee/dao/business/model/DriverInfo.java                 |    3 
 server/services/src/main/java/com/doumee/core/constants/Constants.java                      |   23 
 server/services/src/main/java/com/doumee/dao/vo/OrderTrendVO.java                           |   21 
 server/services/src/main/java/com/doumee/dao/business/MemberCouponMapper.java               |    7 
 server/services/src/main/java/com/doumee/service/business/impl/ShopInfoServiceImpl.java     |   60 +
 server/services/src/main/java/com/doumee/service/business/impl/DataBoardServiceImpl.java    |  338 +++++++++
 server/admin/src/main/java/com/doumee/api/business/MemberCouponController.java              |   77 ++
 server/services/src/main/java/com/doumee/dao/vo/MemberTrendVO.java                          |   18 
 server/admin/src/main/java/com/doumee/api/business/CouponController.java                    |   85 ++
 server/services/src/main/java/com/doumee/service/business/DataBoardService.java             |   19 
 server/services/src/main/java/com/doumee/dao/business/model/Coupon.java                     |  106 +++
 server/services/src/main/java/com/doumee/dao/business/CouponMapper.java                     |    7 
 server/services/src/main/java/com/doumee/service/business/impl/MemberCouponServiceImpl.java |  149 ++++
 server/services/src/main/java/com/doumee/service/business/impl/CouponServiceImpl.java       |  169 ++++
 server/services/src/main/java/com/doumee/dao/vo/LuggageTypeItem.java                        |   21 
 server/services/db/db_change.sql                                                            |   72 ++
 server/services/src/main/java/com/doumee/dao/business/model/Orders.java                     |    6 
 server/services/src/main/java/com/doumee/service/business/CouponService.java                |   28 
 server/services/src/main/java/com/doumee/service/business/MemberCouponService.java          |   26 
 server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java       |   66 +
 32 files changed, 1,957 insertions(+), 110 deletions(-)

diff --git a/server/admin/src/main/java/com/doumee/api/business/CouponController.java b/server/admin/src/main/java/com/doumee/api/business/CouponController.java
new file mode 100644
index 0000000..2596d01
--- /dev/null
+++ b/server/admin/src/main/java/com/doumee/api/business/CouponController.java
@@ -0,0 +1,85 @@
+package com.doumee.api.business;
+
+import com.doumee.api.BaseController;
+import com.doumee.core.annotation.pr.PreventRepeat;
+import com.doumee.core.model.ApiResponse;
+import com.doumee.core.model.PageData;
+import com.doumee.core.model.PageWrap;
+import com.doumee.dao.business.model.Coupon;
+import com.doumee.service.business.CouponService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Api(tags = "浼樻儬鍒哥鐞�")
+@RestController
+@RequestMapping("/business/coupon")
+public class CouponController extends BaseController {
+
+    @Autowired
+    private CouponService couponService;
+
+    @PreventRepeat
+    @ApiOperation("鏂板缓")
+    @PostMapping("/create")
+    @RequiresPermissions("business:coupon:create")
+    public ApiResponse create(@RequestBody Coupon coupon) {
+        return ApiResponse.success(couponService.create(coupon));
+    }
+
+    @ApiOperation("鏍规嵁ID鍒犻櫎")
+    @GetMapping("/delete/{id}")
+    @RequiresPermissions("business:coupon:delete")
+    public ApiResponse deleteById(@PathVariable Integer id) {
+        couponService.deleteById(id);
+        return ApiResponse.success(null);
+    }
+
+    @ApiOperation("鎵归噺鍒犻櫎")
+    @GetMapping("/delete/batch")
+    @RequiresPermissions("business:coupon:delete")
+    public ApiResponse deleteByIdInBatch(@RequestParam String ids) {
+        String[] idArray = ids.split(",");
+        List<Integer> idList = new ArrayList<>();
+        for (String id : idArray) {
+            idList.add(Integer.valueOf(id));
+        }
+        couponService.deleteByIdInBatch(idList);
+        return ApiResponse.success(null);
+    }
+
+    @ApiOperation("鏍规嵁ID淇敼")
+    @PostMapping("/updateById")
+    @RequiresPermissions("business:coupon:update")
+    public ApiResponse updateById(@RequestBody Coupon coupon) {
+        couponService.updateById(coupon);
+        return ApiResponse.success(null);
+    }
+
+    @ApiOperation("淇敼鐘舵��")
+    @PostMapping("/updateStatus")
+    @RequiresPermissions("business:coupon:update")
+    public ApiResponse updateStatus(@RequestBody Coupon coupon) {
+        couponService.updateStatus(coupon);
+        return ApiResponse.success(null);
+    }
+
+    @ApiOperation("鍒嗛〉鏌ヨ")
+    @PostMapping("/page")
+    @RequiresPermissions("business:coupon:query")
+    public ApiResponse<PageData<Coupon>> findPage(@RequestBody PageWrap<Coupon> pageWrap) {
+        return ApiResponse.success(couponService.findPage(pageWrap));
+    }
+
+    @ApiOperation("鏍规嵁ID鏌ヨ")
+    @GetMapping("/{id}")
+    @RequiresPermissions("business:coupon:query")
+    public ApiResponse findById(@PathVariable Integer id) {
+        return ApiResponse.success(couponService.findById(id));
+    }
+}
diff --git a/server/admin/src/main/java/com/doumee/api/business/DataBoardController.java b/server/admin/src/main/java/com/doumee/api/business/DataBoardController.java
new file mode 100644
index 0000000..16c866c
--- /dev/null
+++ b/server/admin/src/main/java/com/doumee/api/business/DataBoardController.java
@@ -0,0 +1,55 @@
+package com.doumee.api.business;
+
+import com.doumee.api.BaseController;
+import com.doumee.core.model.ApiResponse;
+import com.doumee.dao.dto.DataBoardQueryDTO;
+import com.doumee.dao.vo.*;
+import com.doumee.service.business.DataBoardService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@Api(tags = "鏁版嵁鐪嬫澘")
+@RestController
+@RequestMapping("/business/dataBoard")
+public class DataBoardController extends BaseController {
+
+    @Autowired
+    private DataBoardService dataBoardService;
+
+    @ApiOperation("缁忚惀鐪嬫澘")
+    @PostMapping("/overview")
+    public ApiResponse<DataBoardVO> overview(@RequestBody DataBoardQueryDTO query) {
+        return ApiResponse.success(dataBoardService.overview(query));
+    }
+
+    @ApiOperation("杩�30澶╀細鍛樻敞鍐岃秼鍔�")
+    @PostMapping("/memberTrend")
+    public ApiResponse<List<MemberTrendVO>> memberTrend() {
+        return ApiResponse.success(dataBoardService.memberTrend());
+    }
+
+    @ApiOperation("杩�30澶╄鍗曡秼鍔�")
+    @PostMapping("/orderTrend")
+    public ApiResponse<List<OrderTrendVO>> orderTrend() {
+        return ApiResponse.success(dataBoardService.orderTrend());
+    }
+
+    @ApiOperation("杩�30澶╄惀鏀惰秼鍔�")
+    @PostMapping("/revenueTrend")
+    public ApiResponse<List<RevenueTrendVO>> revenueTrend() {
+        return ApiResponse.success(dataBoardService.revenueTrend());
+    }
+
+    @ApiOperation("闂ㄥ簵涓氱哗缁熻")
+    @PostMapping("/shopPerformance")
+    public ApiResponse<ShopPerformanceVO> shopPerformance(@RequestBody DataBoardQueryDTO query) {
+        return ApiResponse.success(dataBoardService.shopPerformance(query));
+    }
+}
diff --git a/server/admin/src/main/java/com/doumee/api/business/DriverInfoController.java b/server/admin/src/main/java/com/doumee/api/business/DriverInfoController.java
index e196dda..771a7d2 100644
--- a/server/admin/src/main/java/com/doumee/api/business/DriverInfoController.java
+++ b/server/admin/src/main/java/com/doumee/api/business/DriverInfoController.java
@@ -131,6 +131,7 @@
         DriverInfo query = new DriverInfo();
         query.setAuditStatus(3);
         query.setDeleted(0);
+        query.setVersionType(0);
         return ApiResponse.success(driverInfoService.findList(query));
     }
 
diff --git a/server/admin/src/main/java/com/doumee/api/business/MemberCouponController.java b/server/admin/src/main/java/com/doumee/api/business/MemberCouponController.java
new file mode 100644
index 0000000..893f1a7
--- /dev/null
+++ b/server/admin/src/main/java/com/doumee/api/business/MemberCouponController.java
@@ -0,0 +1,77 @@
+package com.doumee.api.business;
+
+import com.doumee.api.BaseController;
+import com.doumee.core.annotation.pr.PreventRepeat;
+import com.doumee.core.model.ApiResponse;
+import com.doumee.core.model.PageData;
+import com.doumee.core.model.PageWrap;
+import com.doumee.dao.business.model.MemberCoupon;
+import com.doumee.service.business.MemberCouponService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Api(tags = "鐢ㄦ埛浼樻儬鍒哥鐞�")
+@RestController
+@RequestMapping("/business/memberCoupon")
+public class MemberCouponController extends BaseController {
+
+    @Autowired
+    private MemberCouponService memberCouponService;
+
+    @PreventRepeat
+    @ApiOperation("鏂板缓")
+    @PostMapping("/create")
+    @RequiresPermissions("business:memberCoupon:create")
+    public ApiResponse create(@RequestBody MemberCoupon memberCoupon) {
+        return ApiResponse.success(memberCouponService.create(memberCoupon));
+    }
+
+    @ApiOperation("鏍规嵁ID鍒犻櫎")
+    @GetMapping("/delete/{id}")
+    @RequiresPermissions("business:memberCoupon:delete")
+    public ApiResponse deleteById(@PathVariable Integer id) {
+        memberCouponService.deleteById(id);
+        return ApiResponse.success(null);
+    }
+
+    @ApiOperation("鎵归噺鍒犻櫎")
+    @GetMapping("/delete/batch")
+    @RequiresPermissions("business:memberCoupon:delete")
+    public ApiResponse deleteByIdInBatch(@RequestParam String ids) {
+        String[] idArray = ids.split(",");
+        List<Integer> idList = new ArrayList<>();
+        for (String id : idArray) {
+            idList.add(Integer.valueOf(id));
+        }
+        memberCouponService.deleteByIdInBatch(idList);
+        return ApiResponse.success(null);
+    }
+
+    @ApiOperation("鏍规嵁ID淇敼")
+    @PostMapping("/updateById")
+    @RequiresPermissions("business:memberCoupon:update")
+    public ApiResponse updateById(@RequestBody MemberCoupon memberCoupon) {
+        memberCouponService.updateById(memberCoupon);
+        return ApiResponse.success(null);
+    }
+
+    @ApiOperation("鍒嗛〉鏌ヨ")
+    @PostMapping("/page")
+    @RequiresPermissions("business:memberCoupon:query")
+    public ApiResponse<PageData<MemberCoupon>> findPage(@RequestBody PageWrap<MemberCoupon> pageWrap) {
+        return ApiResponse.success(memberCouponService.findPage(pageWrap));
+    }
+
+    @ApiOperation("鏍规嵁ID鏌ヨ")
+    @GetMapping("/{id}")
+    @RequiresPermissions("business:memberCoupon:query")
+    public ApiResponse findById(@PathVariable Integer id) {
+        return ApiResponse.success(memberCouponService.findById(id));
+    }
+}
diff --git a/server/services/db/db_change.sql b/server/services/db/db_change.sql
index e9ce016..17ff86d 100644
--- a/server/services/db/db_change.sql
+++ b/server/services/db/db_change.sql
@@ -5,6 +5,78 @@
 
 
 -- ============================================================
+-- 2026/05/13 浼樻儬鍒镐俊鎭〃
+-- ============================================================
+CREATE TABLE `coupon` (
+  `ID` int NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+  `CREATOR` int DEFAULT NULL COMMENT '鍒涘缓浜虹紪鐮�',
+  `CREATE_DATE` datetime DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+  `EDITOR` int DEFAULT NULL COMMENT '鏇存柊浜虹紪鐮�',
+  `EDIT_DATE` datetime DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+  `ISDELETED` int DEFAULT NULL COMMENT '鏄惁鍒犻櫎0鍚� 1鏄�',
+  `STATUS` int DEFAULT NULL COMMENT '鐘舵�� 0鍚敤 1绂佺敤',
+  `REMARK` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+  `NAME` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+  `INFO` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇存槑',
+  `TYPE` int DEFAULT NULL COMMENT '绫诲瀷0骞冲彴浼樻儬鍒� ',
+  `LIMIT_PRICE` BIGINT DEFAULT NULL COMMENT '婊¢锛堝垎锛�',
+  `PRICE` BIGINT DEFAULT NULL COMMENT '浼樻儬閲戦锛堝垎锛�',
+  `PUSH_DAYS` int DEFAULT NULL COMMENT '鎺ㄩ�佸悗棰嗗彇鏈夋晥澶╂暟',
+  `VALID_DAYS` int DEFAULT NULL COMMENT '棰嗗彇鍚庢湁鏁堝ぉ鏁�',
+  `GET_METHOD` int DEFAULT NULL COMMENT '棰嗗彇鏂瑰紡 0棰嗗彇',
+  `USE_TYPE` int DEFAULT NULL COMMENT '浣跨敤绫诲瀷锛�0=鍥哄畾鏃堕暱锛�',
+  `COUPON_TYPE` int DEFAULT NULL COMMENT '浼樻儬鍒哥被鍨嬶細0=婊″噺鍒革紱',
+  PRIMARY KEY (`ID`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='浼樻儬鍒镐俊鎭〃';
+
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `MODULE`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:coupon:create', '鏂板缓浼樻儬鍒�', '浼樻儬鍒哥鐞�', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `MODULE`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:coupon:delete', '鍒犻櫎浼樻儬鍒�', '浼樻儬鍒哥鐞�', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `MODULE`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:coupon:update', '淇敼浼樻儬鍒�', '浼樻儬鍒哥鐞�', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `MODULE`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:coupon:query', '鏌ヨ浼樻儬鍒�', '浼樻儬鍒哥鐞�', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
+
+
+-- ============================================================
+-- 2026/05/13 鐢ㄦ埛浼樻儬鍒歌〃
+-- ============================================================
+CREATE TABLE `member_coupon` (
+  `ID` int NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+  `CREATOR` int DEFAULT NULL COMMENT '鍒涘缓浜虹紪鐮�',
+  `CREATE_DATE` datetime DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+  `EDITOR` int DEFAULT NULL COMMENT '鏇存柊浜虹紪鐮�',
+  `EDIT_DATE` datetime DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+  `ISDELETED` int DEFAULT NULL COMMENT '鏄惁鍒犻櫎0鍚� 1鏄�',
+  `REMARK` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+  `COUPON_ID` int DEFAULT NULL COMMENT '浼樻儬鍒镐富閿叧鑱旇〃',
+  `MEMBER_ID` int DEFAULT NULL COMMENT '鐢ㄦ埛缂栫爜锛堝叧鑱攎ember琛級',
+  `STATUS` int DEFAULT NULL COMMENT '鐘舵�侊細0=寰呴鍙栵紱1=宸查鍙栵紱2=宸蹭娇鐢紱98=鏈鍙栧凡杩囨湡锛�99=宸茶繃鏈燂紱',
+  `VALID_DATE` datetime DEFAULT NULL COMMENT '棰嗗彇鏈夋晥鏈熸椂闂�',
+  `START_DATE` datetime DEFAULT NULL COMMENT '鏈夋晥鏈熷紑濮嬫椂闂�',
+  `END_DATE` datetime DEFAULT NULL COMMENT '鏈夋晥鏈熺粨鏉熸椂闂�',
+  `USE_DATE` datetime DEFAULT NULL COMMENT '浣跨敤鏃堕棿',
+  `ORDER_ID` int DEFAULT NULL COMMENT '鍏宠仈璁㈠崟涓婚敭',
+  `NAME` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+  `INFO` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇存槑',
+  `TYPE` int DEFAULT NULL COMMENT '绫诲瀷 0骞冲彴浼樻儬鍒� ',
+  `LIMIT_PRICE` BIGINT DEFAULT NULL COMMENT '婊¢锛堝垎锛�',
+  `PRICE` BIGINT DEFAULT NULL COMMENT '浼樻儬閲戦锛堝垎锛�',
+  `GET_METHOD` int DEFAULT NULL COMMENT '棰嗗彇鏂瑰紡 0棰嗗彇',
+  `COUPON_TYPE` int DEFAULT NULL COMMENT '浼樻儬鍒哥被鍨嬶細0=婊″噺鍒革紱',
+  `PUSH_DAYS` int DEFAULT NULL COMMENT '鎺ㄩ�佸悗棰嗗彇鏈夋晥澶╂暟',
+  `VALID_DAYS` int DEFAULT NULL COMMENT '棰嗗彇鍚庢湁鏁堝ぉ鏁�',
+  PRIMARY KEY (`ID`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='鐢ㄦ埛浼樻儬鍒�';
+
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `MODULE`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:memberCoupon:create', '鏂板缓鐢ㄦ埛浼樻儬鍒�', '鐢ㄦ埛浼樻儬鍒�', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `MODULE`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:memberCoupon:delete', '鍒犻櫎鐢ㄦ埛浼樻儬鍒�', '鐢ㄦ埛浼樻儬鍒�', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `MODULE`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:memberCoupon:update', '淇敼鐢ㄦ埛浼樻儬鍒�', '鐢ㄦ埛浼樻儬鍒�', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
+INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `MODULE`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:memberCoupon:query', '鏌ヨ鐢ㄦ埛浼樻儬鍒�', '鐢ㄦ埛浼樻儬鍒�', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
+
+-- ============================================================
+-- 2026/05/12 璁㈠崟澧炲姞鏄惁杞崲璁㈠崟瀛楁
+-- ============================================================
+ALTER TABLE `orders` ADD COLUMN `IS_CONVERTED` INT DEFAULT 0 COMMENT '鏄惁杞崲璁㈠崟锛�0=鍚︼紱1=鏄紙寮傚湴杞氨鍦帮級' AFTER `TYPE`;
+
+-- ============================================================
 -- 2026/05/11 鍙告満鐗堟湰绫诲瀷瀛楁
 -- ============================================================
 ALTER TABLE `driver_info` ADD COLUMN `VERSION_TYPE` INT DEFAULT 0 COMMENT '鍙告満鐗堟湰绫诲瀷锛�0=姝e紡鐗堟湰锛�1=鍙樻洿鐗堟湰';
diff --git a/server/services/src/main/java/com/doumee/config/jwt/WebMvcConfig.java b/server/services/src/main/java/com/doumee/config/jwt/WebMvcConfig.java
index 3b9f99d..1e96639 100644
--- a/server/services/src/main/java/com/doumee/config/jwt/WebMvcConfig.java
+++ b/server/services/src/main/java/com/doumee/config/jwt/WebMvcConfig.java
@@ -7,6 +7,7 @@
 import com.doumee.core.constants.Constants;
 import com.doumee.core.constants.ResponseStatus;
 import com.doumee.core.exception.BusinessException;
+import com.doumee.dao.business.model.DriverInfo;
 import com.doumee.dao.business.model.Member;
 import com.doumee.dao.business.model.ShopInfo;
 import io.jsonwebtoken.JwtException;
@@ -194,9 +195,14 @@
             if(StringUtils.isBlank(tokenRedis)){
                 throw new BusinessException(ResponseStatus.BE_OVERDUE);
             }
-            Integer memberId = getTokenId(token);
+            Integer driverId = getTokenId(token);
+            //鏌ヨ鍙告満淇℃伅
+            Integer memberId = dao.queryForObject(" select COALESCE(member_id,0)  from driver_info where VERSION_TYPE = 0 and  id  = ?", Integer.class, driverId);
+            if(Objects.isNull(memberId)||Constants.equalsInteger(memberId,Constants.ZERO)){
+                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"鍙告満淇℃伅淇℃伅鍑洪敊");
+            }
             Integer isDeleted = dao.queryForObject(" select COALESCE(DELETED,1)  from member where user_type = 1 and   id  = ?", Integer.class, memberId);
-            if(isDeleted== Constants.ONE){
+            if(isDeleted == Constants.ONE){
                 throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"鍙告満淇℃伅宸插垹闄�,璇疯仈绯荤鐞嗗憳");
             }
             Integer isForbidden = dao.queryForObject(" select COALESCE(STATUS,0)  from member where user_type = 1 and  id  = ?", Integer.class, memberId);
@@ -205,7 +211,7 @@
             }
             Integer count = dao.queryForObject("select count(1) from member where  user_type = 1  and id  = ?", Integer.class, memberId);
             if (count != null && count > 0) {
-                request.setAttribute(JwtTokenUtil.DRIVER_ID, memberId);
+                request.setAttribute(JwtTokenUtil.DRIVER_ID, driverId);
                 return true;
             }else{
                 throw new BusinessException(ResponseStatus.BE_OVERDUE.getCode(),"鍙告満淇℃伅鍑洪敊");
diff --git a/server/services/src/main/java/com/doumee/core/constants/Constants.java b/server/services/src/main/java/com/doumee/core/constants/Constants.java
index 77059bc..e14d0a0 100644
--- a/server/services/src/main/java/com/doumee/core/constants/Constants.java
+++ b/server/services/src/main/java/com/doumee/core/constants/Constants.java
@@ -335,8 +335,8 @@
     public enum OrderLogType {
         createOrder(1, "鍒涘缓璁㈠崟", "浼氬憳鍒涘缓瀵勫瓨璁㈠崟锛岃鍗曠紪鍙枫�恵param}銆�"),
         payOrder(1, "璁㈠崟鏀粯", "浼氬憳鏀粯鎴愬姛锛屾敮浠橀噾棰濄�恵param}銆戝厓"),
-        urgent(2, "骞冲彴鍔犳��", "骞冲彴鍔犳�ワ紝濂栧姳閲戙�恵param}銆戝厓"),
-        assignDriver(3, "骞冲彴鎸囨淳", "骞冲彴鎸囨淳鍙告満銆恵param}銆戞帴鍗曪紝濂栧姳閲戙�恵param1}銆戝厓"),
+        urgent(2, "骞冲彴鍔犳��", "骞冲彴鍔犳�ワ紝鍔犳�ヨ垂銆恵param}銆戝厓"),
+        assignDriver(3, "骞冲彴鎸囨淳", "骞冲彴鎸囨淳鍙告満銆恵param}銆戞帴鍗曪紝鍔犳�ヨ垂銆恵param1}銆戝厓"),
         memberCancel(4, "浼氬憳鍙栨秷璁㈠崟", "{param}"),
         driverCancel(4, "鍙告満鍙栨秷璁㈠崟", "{param}"),
         systemCancel(4, "绯荤粺鑷姩鍙栨秷", "{param}"),
@@ -385,6 +385,25 @@
 
 
     /**
+     * 浼樻儬鍒哥姸鎬�
+     */
+    @Getter
+    @AllArgsConstructor
+    public enum CouponStatus {
+        waitClaim(0, "寰呴鍙�"),
+        claimed(1, "宸查鍙�"),
+        used(2, "宸蹭娇鐢�"),
+        expiredUnclaimed(98, "鏈鍙栧凡杩囨湡"),
+        expired(99, "宸茶繃鏈�")
+        ;
+        private final int status;
+        private final String desc;
+
+        public int getKey() { return status; }
+        public String getValue() { return desc; }
+    }
+
+    /**
      * 璁㈠崟鐘舵�侊紙灏卞湴/寮傚湴缁熶竴锛�
      * 灏卞湴瀵勫瓨: 0鈫�1鈫�2鈫�3鈫�(6)鈫�7 / 96~99
      * 寮傚湴瀵勫瓨: 0鈫�1鈫�2鈫�3鈫�4鈫�5鈫�(6)鈫�7 / 96~99
diff --git a/server/services/src/main/java/com/doumee/dao/business/CouponMapper.java b/server/services/src/main/java/com/doumee/dao/business/CouponMapper.java
new file mode 100644
index 0000000..86853ac
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/dao/business/CouponMapper.java
@@ -0,0 +1,7 @@
+package com.doumee.dao.business;
+
+import com.doumee.dao.business.model.Coupon;
+import com.github.yulichang.base.MPJBaseMapper;
+
+public interface CouponMapper extends MPJBaseMapper<Coupon> {
+}
diff --git a/server/services/src/main/java/com/doumee/dao/business/MemberCouponMapper.java b/server/services/src/main/java/com/doumee/dao/business/MemberCouponMapper.java
new file mode 100644
index 0000000..78ec757
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/dao/business/MemberCouponMapper.java
@@ -0,0 +1,7 @@
+package com.doumee.dao.business;
+
+import com.doumee.dao.business.model.MemberCoupon;
+import com.github.yulichang.base.MPJBaseMapper;
+
+public interface MemberCouponMapper extends MPJBaseMapper<MemberCoupon> {
+}
diff --git a/server/services/src/main/java/com/doumee/dao/business/model/Coupon.java b/server/services/src/main/java/com/doumee/dao/business/model/Coupon.java
new file mode 100644
index 0000000..26249f8
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/dao/business/model/Coupon.java
@@ -0,0 +1,106 @@
+package com.doumee.dao.business.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.doumee.core.annotation.excel.ExcelColumn;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@ApiModel("浼樻儬鍒镐俊鎭〃")
+@TableName("`coupon`")
+public class Coupon {
+
+    @TableId(type = IdType.AUTO)
+    @ApiModelProperty(value = "涓婚敭", example = "1")
+    @ExcelColumn(name = "涓婚敭")
+    private Integer id;
+
+    @ApiModelProperty(value = "鍒涘缓浜虹紪鐮�", example = "1")
+    @ExcelColumn(name = "鍒涘缓浜虹紪鐮�")
+    private Integer creator;
+
+    @ApiModelProperty(value = "鍒涘缓鏃堕棿")
+    @ExcelColumn(name = "鍒涘缓鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createDate;
+
+    @ApiModelProperty(value = "鏇存柊浜虹紪鐮�", example = "1")
+    @ExcelColumn(name = "鏇存柊浜虹紪鐮�")
+    private Integer editor;
+
+    @ApiModelProperty(value = "鏇存柊鏃堕棿")
+    @ExcelColumn(name = "鏇存柊鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date editDate;
+
+    @ApiModelProperty(value = "鏄惁鍒犻櫎 0鍚� 1鏄�", example = "0")
+    @ExcelColumn(name = "鏄惁鍒犻櫎")
+    private Integer isdeleted;
+
+    @ApiModelProperty(value = "鐘舵�� 0鍚敤 1绂佺敤", example = "0")
+    @ExcelColumn(name = "鐘舵��")
+    private Integer status;
+
+    @ApiModelProperty(value = "澶囨敞")
+    @ExcelColumn(name = "澶囨敞")
+    private String remark;
+
+    @ApiModelProperty(value = "鍚嶇О")
+    @ExcelColumn(name = "鍚嶇О")
+    private String name;
+
+    @ApiModelProperty(value = "璇存槑")
+    @ExcelColumn(name = "璇存槑")
+    private String info;
+
+    @ApiModelProperty(value = "绫诲瀷 0骞冲彴浼樻儬鍒�", example = "0")
+    @ExcelColumn(name = "绫诲瀷")
+    private Integer type;
+
+    @ApiModelProperty(value = "婊¢锛堝垎锛�")
+    @ExcelColumn(name = "婊¢")
+    private Long limitPrice;
+
+    @ApiModelProperty(value = "浼樻儬閲戦锛堝垎锛�")
+    @ExcelColumn(name = "浼樻儬閲戦")
+    private Long price;
+
+    @ApiModelProperty(value = "鎺ㄩ�佸悗棰嗗彇鏈夋晥澶╂暟", example = "7")
+    @ExcelColumn(name = "鎺ㄩ�佸悗棰嗗彇鏈夋晥澶╂暟")
+    private Integer pushDays;
+
+    @ApiModelProperty(value = "棰嗗彇鍚庢湁鏁堝ぉ鏁�", example = "30")
+    @ExcelColumn(name = "棰嗗彇鍚庢湁鏁堝ぉ鏁�")
+    private Integer validDays;
+
+    @ApiModelProperty(value = "棰嗗彇鏂瑰紡 0棰嗗彇", example = "0")
+    @ExcelColumn(name = "棰嗗彇鏂瑰紡")
+    private Integer getMethod;
+
+    @ApiModelProperty(value = "浣跨敤绫诲瀷锛�0=鍥哄畾鏃堕暱", example = "0")
+    @ExcelColumn(name = "浣跨敤绫诲瀷")
+    private Integer useType;
+
+    @ApiModelProperty(value = "浼樻儬鍒哥被鍨嬶細0=婊″噺鍒�", example = "0")
+    @ExcelColumn(name = "浼樻儬鍒哥被鍨�")
+    private Integer couponType;
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "淇敼浜哄悕绉�")
+    private String editorName;
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "棰嗗彇鏁伴噺")
+    private Long claimCount;
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "浣跨敤鏁伴噺")
+    private Long usedCount;
+}
diff --git a/server/services/src/main/java/com/doumee/dao/business/model/DriverInfo.java b/server/services/src/main/java/com/doumee/dao/business/model/DriverInfo.java
index abecd83..dabf76e 100644
--- a/server/services/src/main/java/com/doumee/dao/business/model/DriverInfo.java
+++ b/server/services/src/main/java/com/doumee/dao/business/model/DriverInfo.java
@@ -246,4 +246,7 @@
     @ApiModelProperty(value = "鍏宠仈姝e紡鐗堟湰鍙告満涓婚敭锛堝彉鏇寸増鏈娇鐢級", example = "1")
     private Integer relationDriverId;
 
+    @TableField(exist = false)
+    @ApiModelProperty(value = "鏄惁瀛樺湪瀹℃壒閫氳繃鐨勬寮忕増鏈�:true=鏈夛紱false=鏃�")
+    private Boolean hasApprovedOfficial;
 }
diff --git a/server/services/src/main/java/com/doumee/dao/business/model/MemberCoupon.java b/server/services/src/main/java/com/doumee/dao/business/model/MemberCoupon.java
new file mode 100644
index 0000000..b47dc2c
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/dao/business/model/MemberCoupon.java
@@ -0,0 +1,134 @@
+package com.doumee.dao.business.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.doumee.core.annotation.excel.ExcelColumn;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@ApiModel("鐢ㄦ埛浼樻儬鍒�")
+@TableName("`member_coupon`")
+public class MemberCoupon {
+
+    @TableId(type = IdType.AUTO)
+    @ApiModelProperty(value = "涓婚敭", example = "1")
+    @ExcelColumn(name = "涓婚敭")
+    private Integer id;
+
+    @ApiModelProperty(value = "鍒涘缓浜虹紪鐮�", example = "1")
+    @ExcelColumn(name = "鍒涘缓浜虹紪鐮�")
+    private Integer creator;
+
+    @ApiModelProperty(value = "鍒涘缓鏃堕棿")
+    @ExcelColumn(name = "鍒涘缓鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createDate;
+
+    @ApiModelProperty(value = "鏇存柊浜虹紪鐮�", example = "1")
+    @ExcelColumn(name = "鏇存柊浜虹紪鐮�")
+    private Integer editor;
+
+    @ApiModelProperty(value = "鏇存柊鏃堕棿")
+    @ExcelColumn(name = "鏇存柊鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date editDate;
+
+    @ApiModelProperty(value = "鏄惁鍒犻櫎 0鍚� 1鏄�", example = "0")
+    @ExcelColumn(name = "鏄惁鍒犻櫎")
+    private Integer isdeleted;
+
+    @ApiModelProperty(value = "澶囨敞")
+    @ExcelColumn(name = "澶囨敞")
+    private String remark;
+
+    @ApiModelProperty(value = "浼樻儬鍒镐富閿叧鑱旇〃", example = "1")
+    @ExcelColumn(name = "浼樻儬鍒镐富閿�")
+    private Integer couponId;
+
+    @ApiModelProperty(value = "鐢ㄦ埛缂栫爜锛堝叧鑱攎ember琛級", example = "1")
+    @ExcelColumn(name = "鐢ㄦ埛缂栫爜")
+    private Integer memberId;
+
+    @ApiModelProperty(value = "鐘舵�侊細0=寰呴鍙栵紱1=宸查鍙栵紱2=宸蹭娇鐢紱98=鏈鍙栧凡杩囨湡锛�99=宸茶繃鏈�", example = "0")
+    @ExcelColumn(name = "鐘舵��")
+    private Integer status;
+
+    @ApiModelProperty(value = "棰嗗彇鏈夋晥鏈熸椂闂�")
+    @ExcelColumn(name = "棰嗗彇鏈夋晥鏈熸椂闂�")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date validDate;
+
+    @ApiModelProperty(value = "鏈夋晥鏈熷紑濮嬫椂闂�")
+    @ExcelColumn(name = "鏈夋晥鏈熷紑濮嬫椂闂�")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date startDate;
+
+    @ApiModelProperty(value = "鏈夋晥鏈熺粨鏉熸椂闂�")
+    @ExcelColumn(name = "鏈夋晥鏈熺粨鏉熸椂闂�")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date endDate;
+
+    @ApiModelProperty(value = "浣跨敤鏃堕棿")
+    @ExcelColumn(name = "浣跨敤鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date useDate;
+
+    @ApiModelProperty(value = "鍏宠仈璁㈠崟涓婚敭", example = "1")
+    @ExcelColumn(name = "鍏宠仈璁㈠崟涓婚敭")
+    private Integer orderId;
+
+    @ApiModelProperty(value = "鍚嶇О")
+    @ExcelColumn(name = "鍚嶇О")
+    private String name;
+
+    @ApiModelProperty(value = "璇存槑")
+    @ExcelColumn(name = "璇存槑")
+    private String info;
+
+    @ApiModelProperty(value = "绫诲瀷 0骞冲彴浼樻儬鍒�", example = "0")
+    @ExcelColumn(name = "绫诲瀷")
+    private Integer type;
+
+    @ApiModelProperty(value = "婊¢锛堝垎锛�")
+    @ExcelColumn(name = "婊¢")
+    private Long limitPrice;
+
+    @ApiModelProperty(value = "浼樻儬閲戦锛堝垎锛�")
+    @ExcelColumn(name = "浼樻儬閲戦")
+    private Long price;
+
+    @ApiModelProperty(value = "棰嗗彇鏂瑰紡 0棰嗗彇", example = "0")
+    @ExcelColumn(name = "棰嗗彇鏂瑰紡")
+    private Integer getMethod;
+
+    @ApiModelProperty(value = "浼樻儬鍒哥被鍨嬶細0=婊″噺鍒�", example = "0")
+    @ExcelColumn(name = "浼樻儬鍒哥被鍨�")
+    private Integer couponType;
+
+    @ApiModelProperty(value = "鎺ㄩ�佸悗棰嗗彇鏈夋晥澶╂暟", example = "7")
+    @ExcelColumn(name = "鎺ㄩ�佸悗棰嗗彇鏈夋晥澶╂暟")
+    private Integer pushDays;
+
+    @ApiModelProperty(value = "棰嗗彇鍚庢湁鏁堝ぉ鏁�", example = "30")
+    @ExcelColumn(name = "棰嗗彇鍚庢湁鏁堝ぉ鏁�")
+    private Integer validDays;
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "浼氬憳濮撳悕")
+    private String memberName;
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "浼氬憳鐢佃瘽")
+    private String memberTelephone;
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "浼氬憳鏄电О")
+    private String memberNickName;
+}
diff --git a/server/services/src/main/java/com/doumee/dao/business/model/Orders.java b/server/services/src/main/java/com/doumee/dao/business/model/Orders.java
index ad38d6f..769335c 100644
--- a/server/services/src/main/java/com/doumee/dao/business/model/Orders.java
+++ b/server/services/src/main/java/com/doumee/dao/business/model/Orders.java
@@ -61,6 +61,9 @@
     @ExcelColumn(name = "瀵勫瓨鏂瑰紡", valueMapping = "0=灏卞湴瀛樺彇;1=寮傚湴瀛樺彇;")
     private Integer type;
 
+    @ApiModelProperty(value = "鏄惁杞崲璁㈠崟锛�0=鍚︼紱1=鏄紙寮傚湴杞氨鍦帮級", example = "0")
+    private Integer isConverted;
+
     @ApiModelProperty(value = "鏄惁蹇呴』鏈汉绛炬敹锛�0=鍚︼紱1=鏄�", example = "0")
     @ExcelColumn(name = "鏈汉绛炬敹", valueMapping = "0=鍚�;1=鏄�;")
     private Integer selfTake;
@@ -230,11 +233,10 @@
     private Long declaredFee;
 
     @ApiModelProperty(value = "鍔犳�ヨ垂鐢紙鍒嗭級")
-    @ExcelColumn(name = "鍔犳�ヨ垂鐢�")
     private Long urgentAmount;
 
     @ApiModelProperty(value = "骞冲彴濂栧姳鍙告満璐圭敤锛堝垎锛�")
-    @ExcelColumn(name = "骞冲彴濂栧姳鍙告満璐圭敤")
+    @ExcelColumn(name = "鍔犳�ヨ垂鐢�")
     private Long platformRewardAmount;
 
     @ApiModelProperty(value = "鎸囨淳鍙告満鐢ㄦ埛涓婚敭锛坢ember:id锛�")
diff --git a/server/services/src/main/java/com/doumee/dao/dto/DataBoardQueryDTO.java b/server/services/src/main/java/com/doumee/dao/dto/DataBoardQueryDTO.java
new file mode 100644
index 0000000..b1e5a3e
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/dao/dto/DataBoardQueryDTO.java
@@ -0,0 +1,25 @@
+package com.doumee.dao.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@ApiModel("鏁版嵁鐪嬫澘鏌ヨ鏉′欢")
+public class DataBoardQueryDTO implements Serializable {
+
+    @ApiModelProperty(value = "寮�濮嬫椂闂�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date startDate;
+
+    @ApiModelProperty(value = "缁撴潫鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date endDate;
+
+    @ApiModelProperty(value = "闂ㄥ簵涓婚敭锛堝彲閫夛級")
+    private Integer shopId;
+}
diff --git a/server/services/src/main/java/com/doumee/dao/vo/DataBoardVO.java b/server/services/src/main/java/com/doumee/dao/vo/DataBoardVO.java
new file mode 100644
index 0000000..6aecd8a
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/dao/vo/DataBoardVO.java
@@ -0,0 +1,32 @@
+package com.doumee.dao.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+@ApiModel("缁忚惀鐪嬫澘鏁版嵁")
+public class DataBoardVO implements Serializable {
+
+    @ApiModelProperty(value = "浼氬憳鎬绘暟")
+    private Long memberCount;
+
+    @ApiModelProperty(value = "闂ㄥ簵鎬绘暟")
+    private Long shopCount;
+
+    @ApiModelProperty(value = "鍙告満鎬绘暟")
+    private Long driverCount;
+
+    @ApiModelProperty(value = "鍛ㄦ湡鎬昏鍗曟暟")
+    private Long orderCount;
+
+    @ApiModelProperty(value = "鍛ㄦ湡钀ユ敹鎬婚噾棰濓紙鍏冿級")
+    private BigDecimal totalRevenue;
+
+    @ApiModelProperty(value = "琛屾潕绫诲瀷鍗犳瘮")
+    private List<LuggageTypeItem> luggageTypeList;
+}
diff --git a/server/services/src/main/java/com/doumee/dao/vo/LuggageTypeItem.java b/server/services/src/main/java/com/doumee/dao/vo/LuggageTypeItem.java
new file mode 100644
index 0000000..01304a7
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/dao/vo/LuggageTypeItem.java
@@ -0,0 +1,21 @@
+package com.doumee.dao.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+@ApiModel("琛屾潕绫诲瀷鍗犳瘮椤�")
+public class LuggageTypeItem implements Serializable {
+
+    @ApiModelProperty(value = "绫诲瀷鍚嶇О")
+    private String luggageName;
+
+    @ApiModelProperty(value = "璁㈠崟鏁�")
+    private Long orderCount;
+
+    @ApiModelProperty(value = "琛屾潕鏁�")
+    private Long luggageCount;
+}
diff --git a/server/services/src/main/java/com/doumee/dao/vo/MemberTrendVO.java b/server/services/src/main/java/com/doumee/dao/vo/MemberTrendVO.java
new file mode 100644
index 0000000..6dd70ea
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/dao/vo/MemberTrendVO.java
@@ -0,0 +1,18 @@
+package com.doumee.dao.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+@ApiModel("浼氬憳娉ㄥ唽瓒嬪娍椤�")
+public class MemberTrendVO implements Serializable {
+
+    @ApiModelProperty(value = "鏃ユ湡")
+    private String date;
+
+    @ApiModelProperty(value = "娉ㄥ唽鏁伴噺")
+    private Long count;
+}
diff --git a/server/services/src/main/java/com/doumee/dao/vo/OrderTrendVO.java b/server/services/src/main/java/com/doumee/dao/vo/OrderTrendVO.java
new file mode 100644
index 0000000..6490d58
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/dao/vo/OrderTrendVO.java
@@ -0,0 +1,21 @@
+package com.doumee.dao.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+@ApiModel("璁㈠崟瓒嬪娍椤�")
+public class OrderTrendVO implements Serializable {
+
+    @ApiModelProperty(value = "鏃ユ湡")
+    private String date;
+
+    @ApiModelProperty(value = "灏卞湴瀵勫瓨鏁伴噺")
+    private Long localCount;
+
+    @ApiModelProperty(value = "寮傚湴瀵勫瓨鏁伴噺")
+    private Long remoteCount;
+}
diff --git a/server/services/src/main/java/com/doumee/dao/vo/RevenueTrendVO.java b/server/services/src/main/java/com/doumee/dao/vo/RevenueTrendVO.java
new file mode 100644
index 0000000..ce93776
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/dao/vo/RevenueTrendVO.java
@@ -0,0 +1,22 @@
+package com.doumee.dao.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+@ApiModel("钀ユ敹瓒嬪娍椤�")
+public class RevenueTrendVO implements Serializable {
+
+    @ApiModelProperty(value = "鏃ユ湡")
+    private String date;
+
+    @ApiModelProperty(value = "灏卞湴瀵勫瓨钀ユ敹閲戦锛堝厓锛�")
+    private BigDecimal localRevenue;
+
+    @ApiModelProperty(value = "寮傚湴瀵勫瓨钀ユ敹閲戦锛堝厓锛�")
+    private BigDecimal remoteRevenue;
+}
diff --git a/server/services/src/main/java/com/doumee/dao/vo/ShopPerformanceVO.java b/server/services/src/main/java/com/doumee/dao/vo/ShopPerformanceVO.java
new file mode 100644
index 0000000..03780fd
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/dao/vo/ShopPerformanceVO.java
@@ -0,0 +1,31 @@
+package com.doumee.dao.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+@ApiModel("闂ㄥ簵涓氱哗鎶ヨ〃")
+public class ShopPerformanceVO implements Serializable {
+
+    @ApiModelProperty(value = "鎬昏鍗曟暟锛堢姸鎬�1-6锛�")
+    private Long totalOrderCount;
+
+    @ApiModelProperty(value = "钀ユ敹鎬婚噾棰濓紙鍏冿級")
+    private BigDecimal totalRevenue;
+
+    @ApiModelProperty(value = "宸插畬鎴愯鍗曟暟锛堢姸鎬�=7锛�")
+    private Long completedCount;
+
+    @ApiModelProperty(value = "宸查��娆捐鍗曟暟")
+    private Long refundedCount;
+
+    @ApiModelProperty(value = "璁㈠崟瀹屾垚鐜囷紙濡�44.32琛ㄧず44.32%锛�")
+    private BigDecimal completionRate;
+
+    @ApiModelProperty(value = "璁㈠崟閫�娆剧巼锛堝44.32琛ㄧず44.32%锛�")
+    private BigDecimal refundRate;
+}
diff --git a/server/services/src/main/java/com/doumee/service/business/CouponService.java b/server/services/src/main/java/com/doumee/service/business/CouponService.java
new file mode 100644
index 0000000..e4f9df9
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/service/business/CouponService.java
@@ -0,0 +1,28 @@
+package com.doumee.service.business;
+
+import com.doumee.core.model.PageData;
+import com.doumee.core.model.PageWrap;
+import com.doumee.dao.business.model.Coupon;
+
+import java.util.List;
+
+public interface CouponService {
+
+    Integer create(Coupon coupon);
+
+    void deleteById(Integer id);
+
+    void deleteByIdInBatch(List<Integer> ids);
+
+    void updateById(Coupon coupon);
+
+    void updateStatus(Coupon coupon);
+
+    Coupon findById(Integer id);
+
+    List<Coupon> findList(Coupon coupon);
+
+    PageData<Coupon> findPage(PageWrap<Coupon> pageWrap);
+
+    long count(Coupon coupon);
+}
diff --git a/server/services/src/main/java/com/doumee/service/business/DataBoardService.java b/server/services/src/main/java/com/doumee/service/business/DataBoardService.java
new file mode 100644
index 0000000..d80d982
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/service/business/DataBoardService.java
@@ -0,0 +1,19 @@
+package com.doumee.service.business;
+
+import com.doumee.dao.dto.DataBoardQueryDTO;
+import com.doumee.dao.vo.*;
+
+import java.util.List;
+
+public interface DataBoardService {
+
+    DataBoardVO overview(DataBoardQueryDTO query);
+
+    List<MemberTrendVO> memberTrend();
+
+    List<OrderTrendVO> orderTrend();
+
+    List<RevenueTrendVO> revenueTrend();
+
+    ShopPerformanceVO shopPerformance(DataBoardQueryDTO query);
+}
diff --git a/server/services/src/main/java/com/doumee/service/business/DriverInfoService.java b/server/services/src/main/java/com/doumee/service/business/DriverInfoService.java
index 8edff6d..5d49dd5 100644
--- a/server/services/src/main/java/com/doumee/service/business/DriverInfoService.java
+++ b/server/services/src/main/java/com/doumee/service/business/DriverInfoService.java
@@ -314,4 +314,10 @@
      */
     void registerJpushAlias(Integer driverId, String jpushAlias);
 
+    /**
+     * 鍒濆鍖栧巻鍙插徃鏈哄彉鏇寸増鏈暟鎹�
+     * @return 澶勭悊鏁伴噺
+     */
+    int initChangeVersions();
+
 }
diff --git a/server/services/src/main/java/com/doumee/service/business/MemberCouponService.java b/server/services/src/main/java/com/doumee/service/business/MemberCouponService.java
new file mode 100644
index 0000000..8d1cda4
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/service/business/MemberCouponService.java
@@ -0,0 +1,26 @@
+package com.doumee.service.business;
+
+import com.doumee.core.model.PageData;
+import com.doumee.core.model.PageWrap;
+import com.doumee.dao.business.model.MemberCoupon;
+
+import java.util.List;
+
+public interface MemberCouponService {
+
+    Integer create(MemberCoupon memberCoupon);
+
+    void deleteById(Integer id);
+
+    void deleteByIdInBatch(List<Integer> ids);
+
+    void updateById(MemberCoupon memberCoupon);
+
+    MemberCoupon findById(Integer id);
+
+    List<MemberCoupon> findList(MemberCoupon memberCoupon);
+
+    PageData<MemberCoupon> findPage(PageWrap<MemberCoupon> pageWrap);
+
+    long count(MemberCoupon memberCoupon);
+}
diff --git a/server/services/src/main/java/com/doumee/service/business/ShopInfoService.java b/server/services/src/main/java/com/doumee/service/business/ShopInfoService.java
index b569e27..aae5706 100644
--- a/server/services/src/main/java/com/doumee/service/business/ShopInfoService.java
+++ b/server/services/src/main/java/com/doumee/service/business/ShopInfoService.java
@@ -225,4 +225,10 @@
      */
     void maintainPrinterSn(ShopPrinterDTO dto);
 
+    /**
+     * 鍒濆鍖栧巻鍙查棬搴楀彉鏇寸増鏈暟鎹�
+     * @return 澶勭悊鏁伴噺
+     */
+    int initChangeVersions();
+
 }
diff --git a/server/services/src/main/java/com/doumee/service/business/impl/CouponServiceImpl.java b/server/services/src/main/java/com/doumee/service/business/impl/CouponServiceImpl.java
new file mode 100644
index 0000000..a30b3d9
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/service/business/impl/CouponServiceImpl.java
@@ -0,0 +1,169 @@
+package com.doumee.service.business.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.doumee.core.constants.Constants;
+import com.doumee.core.constants.ResponseStatus;
+import com.doumee.core.exception.BusinessException;
+import com.doumee.core.model.LoginUserInfo;
+import com.doumee.core.model.PageData;
+import com.doumee.core.model.PageWrap;
+import com.doumee.core.utils.Utils;
+import com.doumee.dao.business.CouponMapper;
+import com.doumee.dao.business.model.Coupon;
+import com.doumee.service.business.CouponService;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+
+@Service
+public class CouponServiceImpl implements CouponService {
+
+    @Autowired
+    private CouponMapper couponMapper;
+
+    @Override
+    @Transactional(rollbackFor = {Exception.class, BusinessException.class})
+    public Integer create(Coupon coupon) {
+        validateCoupon(coupon);
+        LoginUserInfo loginUserInfo = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
+        coupon.setIsdeleted(Constants.ZERO);
+        coupon.setCreateDate(new Date());
+        coupon.setCreator(loginUserInfo.getId());
+        coupon.setEditDate(new Date());
+        coupon.setEditor(loginUserInfo.getId());
+        // 榛樿椤�
+        coupon.setType(Constants.ZERO);
+        coupon.setCouponType(Objects.isNull(coupon.getCouponType()) ? Constants.ZERO : coupon.getCouponType());
+        coupon.setGetMethod(Objects.isNull(coupon.getGetMethod()) ? Constants.ZERO : coupon.getGetMethod());
+        couponMapper.insert(coupon);
+        return coupon.getId();
+    }
+
+    @Override
+    public void deleteById(Integer id) {
+        couponMapper.update(new UpdateWrapper<Coupon>().lambda()
+                .set(Coupon::getIsdeleted, Constants.ONE)
+                .eq(Coupon::getId, id));
+    }
+
+    @Override
+    public void deleteByIdInBatch(List<Integer> ids) {
+        if (CollectionUtils.isEmpty(ids)) {
+            return;
+        }
+        for (Integer id : ids) {
+            this.deleteById(id);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = {Exception.class, BusinessException.class})
+    public void updateById(Coupon coupon) {
+        if (Objects.isNull(coupon) || Objects.isNull(coupon.getId())) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST);
+        }
+        validateCoupon(coupon);
+        LoginUserInfo loginUserInfo = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
+        coupon.setEditDate(new Date());
+        coupon.setEditor(loginUserInfo.getId());
+        couponMapper.updateById(coupon);
+    }
+
+    @Override
+    public void updateStatus(Coupon coupon) {
+        if (Objects.isNull(coupon) || Objects.isNull(coupon.getId()) || Objects.isNull(coupon.getStatus())) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST);
+        }
+        LoginUserInfo loginUserInfo = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
+        Coupon update = new Coupon();
+        update.setId(coupon.getId());
+        update.setStatus(coupon.getStatus());
+        update.setEditDate(new Date());
+        update.setEditor(loginUserInfo.getId());
+        couponMapper.updateById(update);
+    }
+
+    @Override
+    public Coupon findById(Integer id) {
+        MPJLambdaWrapper<Coupon> wrapper = new MPJLambdaWrapper<>();
+        wrapper.selectAll(Coupon.class)
+                .select("(SELECT COUNT(*) FROM member_coupon mc WHERE mc.COUPON_ID = t.ID AND mc.ISDELETED = 0 AND mc.STATUS IN (1,2,99)) AS CLAIM_COUNT")
+                .select("(SELECT COUNT(*) FROM member_coupon mc WHERE mc.COUPON_ID = t.ID AND mc.ISDELETED = 0 AND mc.STATUS = 2) AS USED_COUNT")
+                .eq(Coupon::getId, id)
+                .eq(Coupon::getIsdeleted, Constants.ZERO);
+        Coupon coupon = couponMapper.selectJoinOne(Coupon.class, wrapper);
+        if (Objects.isNull(coupon)) {
+            throw new BusinessException(ResponseStatus.DATA_EMPTY);
+        }
+        return coupon;
+    }
+
+    @Override
+    public List<Coupon> findList(Coupon coupon) {
+        QueryWrapper<Coupon> wrapper = new QueryWrapper<>(coupon);
+        return couponMapper.selectList(wrapper);
+    }
+
+    @Override
+    public PageData<Coupon> findPage(PageWrap<Coupon> pageWrap) {
+        IPage<Coupon> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
+        MPJLambdaWrapper<Coupon> wrapper = new MPJLambdaWrapper<>();
+        Utils.MP.blankToNull(pageWrap.getModel());
+        pageWrap.getModel().setIsdeleted(Constants.ZERO);
+        wrapper.selectAll(Coupon.class)
+                .select("u.USERNAME AS EDITOR_NAME")
+                .select("(SELECT COUNT(*) FROM member_coupon mc WHERE mc.COUPON_ID = t.ID AND mc.ISDELETED = 0 AND mc.STATUS IN (1,2,99)) AS CLAIM_COUNT")
+                .select("(SELECT COUNT(*) FROM member_coupon mc WHERE mc.COUPON_ID = t.ID AND mc.ISDELETED = 0 AND mc.STATUS = 2) AS USED_COUNT")
+                .innerJoin("system_user u ON u.ID = t.EDITOR")
+                .eq(Coupon::getIsdeleted, Constants.ZERO);
+        if (pageWrap.getModel().getStatus() != null) {
+            wrapper.eq(Coupon::getStatus, pageWrap.getModel().getStatus());
+        }
+        if (pageWrap.getModel().getName() != null) {
+            wrapper.like(Coupon::getName, pageWrap.getModel().getName());
+        }
+        wrapper.orderByDesc(Coupon::getId);
+        return PageData.from(couponMapper.selectJoinPage(page, Coupon.class, wrapper));
+    }
+
+    @Override
+    public long count(Coupon coupon) {
+        QueryWrapper<Coupon> wrapper = new QueryWrapper<>(coupon);
+        return couponMapper.selectCount(wrapper);
+    }
+
+    private void validateCoupon(Coupon coupon) {
+        if (Objects.isNull(coupon) || StringUtils.isBlank(coupon.getName())) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "浼樻儬鍒稿悕绉颁笉鑳戒负绌�");
+        }
+        if (Objects.isNull(coupon.getLimitPrice()) || coupon.getLimitPrice() <= 0) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "婊¢蹇呴』澶т簬0");
+        }
+        if (Objects.isNull(coupon.getPrice()) || coupon.getPrice() <= 0) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "浼樻儬閲戦蹇呴』澶т簬0");
+        }
+        if (coupon.getPrice() >= coupon.getLimitPrice()) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "浼樻儬閲戦蹇呴』灏忎簬婊¢");
+        }
+        if (Objects.isNull(coupon.getPushDays()) || coupon.getPushDays() < 1) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鎺ㄩ�佸悗棰嗗彇鏈夋晥澶╂暟蹇呴』澶т簬绛変簬1澶�");
+        }
+        if (Objects.isNull(coupon.getValidDays()) || coupon.getValidDays() < 1) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "棰嗗彇鍚庢湁鏁堝ぉ鏁板繀椤诲ぇ浜庣瓑浜�1澶�");
+        }
+        if (Objects.isNull(coupon.getStatus())) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鐘舵�佷笉鑳戒负绌�");
+        }
+    }
+}
diff --git a/server/services/src/main/java/com/doumee/service/business/impl/DataBoardServiceImpl.java b/server/services/src/main/java/com/doumee/service/business/impl/DataBoardServiceImpl.java
new file mode 100644
index 0000000..819b776
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/service/business/impl/DataBoardServiceImpl.java
@@ -0,0 +1,338 @@
+package com.doumee.service.business.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.doumee.core.constants.Constants;
+import com.doumee.core.utils.Utils;
+import com.doumee.dao.business.*;
+import com.doumee.dao.business.model.*;
+import com.doumee.dao.dto.DataBoardQueryDTO;
+import com.doumee.dao.vo.*;
+import com.doumee.service.business.DataBoardService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class DataBoardServiceImpl implements DataBoardService {
+
+    @Autowired
+    private MemberMapper memberMapper;
+    @Autowired
+    private ShopInfoMapper shopInfoMapper;
+    @Autowired
+    private DriverInfoMapper driverInfoMapper;
+    @Autowired
+    private OrdersMapper ordersMapper;
+    @Autowired
+    private OrdersDetailMapper ordersDetailMapper;
+    @Autowired
+    private OtherOrdersMapper otherOrdersMapper;
+    @Autowired
+    private OrdersRefundMapper ordersRefundMapper;
+
+    @Override
+    public DataBoardVO overview(DataBoardQueryDTO query) {
+        DataBoardVO vo = new DataBoardVO();
+        // 浼氬憳鎬绘暟锛堜笉鍙楁椂闂�/闂ㄥ簵褰卞搷锛�
+        vo.setMemberCount(memberMapper.selectCount(new QueryWrapper<Member>().lambda()
+                .eq(Member::getDeleted, Constants.ZERO)
+                .eq(Member::getStatus, Constants.ZERO)));
+        // 闂ㄥ簵鎬绘暟锛坅uditStatus=3 姝e紡鐗堟湰锛�
+        vo.setShopCount(shopInfoMapper.selectCount(new QueryWrapper<ShopInfo>().lambda()
+                .eq(ShopInfo::getAuditStatus, Constants.THREE)
+                .eq(ShopInfo::getVersionType, Constants.ZERO)
+                .eq(ShopInfo::getDeleted, Constants.ZERO)));
+        // 鍙告満鎬绘暟锛坅uditStatus=3 姝e紡鐗堟湰锛�
+        vo.setDriverCount(driverInfoMapper.selectCount(new QueryWrapper<DriverInfo>().lambda()
+                .eq(DriverInfo::getAuditStatus, Constants.THREE)
+                .eq(DriverInfo::getVersionType, Constants.ZERO)
+                .eq(DriverInfo::getDeleted, Constants.ZERO)));
+
+        // 鍛ㄦ湡鎬昏鍗曟暟
+        vo.setOrderCount(ordersMapper.selectCount(buildOrderQueryWrapper(query)));
+
+        // 鍛ㄦ湡钀ユ敹
+        List<Orders> orders = ordersMapper.selectList(buildOrderQueryWrapper(query));
+        long orderRevenue = 0L;
+        for (Orders o : orders) {
+            long pay = o.getPayAmount() != null ? o.getPayAmount() : 0L;
+            long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L;
+            long overdue = (o.getOverdueStatus() != null && o.getOverdueStatus() == 2 && o.getOverdueAmount() != null)
+                    ? o.getOverdueAmount() : 0L;
+            orderRevenue += pay - refund + overdue;
+        }
+        // 鍔犱笂閫炬湡璐圭敤璁㈠崟锛圤therOrders type=2锛�
+        QueryWrapper<OtherOrders> otherQw = new QueryWrapper<>();
+        otherQw.lambda()
+                .eq(OtherOrders::getType, 2)
+                .eq(OtherOrders::getPayStatus, Constants.ONE)
+                .eq(OtherOrders::getDeleted, Constants.ZERO);
+        if (query.getStartDate() != null) {
+            otherQw.lambda().ge(OtherOrders::getPayTime, query.getStartDate());
+        }
+        if (query.getEndDate() != null) {
+            otherQw.lambda().le(OtherOrders::getPayTime, Utils.Date.getEnd(query.getEndDate()));
+        }
+        List<OtherOrders> otherOrders = otherOrdersMapper.selectList(otherQw);
+        long otherRevenue = otherOrders.stream()
+                .mapToLong(o -> o.getPayAccount() != null ? o.getPayAccount() : 0L).sum();
+        vo.setTotalRevenue(BigDecimal.valueOf(orderRevenue + otherRevenue)
+                .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
+
+        // 琛屾潕绫诲瀷鍗犳瘮
+        List<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
+        List<LuggageTypeItem> luggageTypeList = new ArrayList<>();
+        if (!orderIds.isEmpty()) {
+            List<OrdersDetail> details = ordersDetailMapper.selectList(new QueryWrapper<OrdersDetail>().lambda()
+                    .in(OrdersDetail::getOrderId, orderIds)
+                    .eq(OrdersDetail::getDeleted, Constants.ZERO));
+            Map<String, List<OrdersDetail>> grouped = details.stream()
+                    .filter(d -> StringUtils.isNotBlank(d.getLuggageName()))
+                    .collect(Collectors.groupingBy(OrdersDetail::getLuggageName));
+            for (Map.Entry<String, List<OrdersDetail>> entry : grouped.entrySet()) {
+                LuggageTypeItem item = new LuggageTypeItem();
+                item.setLuggageName(entry.getKey());
+                item.setOrderCount((long) entry.getValue().stream().map(OrdersDetail::getOrderId).distinct().count());
+                item.setLuggageCount((long) entry.getValue().stream()
+                        .mapToInt(d -> d.getNum() != null ? d.getNum() : 0).sum());
+                luggageTypeList.add(item);
+            }
+        }
+        vo.setLuggageTypeList(luggageTypeList);
+        return vo;
+    }
+
+    @Override
+    public List<MemberTrendVO> memberTrend() {
+        Date startDate = get30DaysAgoStart();
+        List<Member> members = memberMapper.selectList(new QueryWrapper<Member>().lambda()
+                .eq(Member::getDeleted, Constants.ZERO)
+                .eq(Member::getStatus, Constants.ZERO)
+                .ge(Member::getCreateTime, startDate));
+
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        Map<String, Long> map = members.stream()
+                .collect(Collectors.groupingBy(m -> sdf.format(m.getCreateTime()), Collectors.counting()));
+
+        return buildDailyList(startDate, (date) -> {
+            MemberTrendVO vo = new MemberTrendVO();
+            vo.setDate(date);
+            vo.setCount(map.getOrDefault(date, 0L));
+            return vo;
+        });
+    }
+
+    @Override
+    public List<OrderTrendVO> orderTrend() {
+        Date startDate = get30DaysAgoStart();
+        List<Orders> orders = ordersMapper.selectList(new QueryWrapper<Orders>().lambda()
+                .eq(Orders::getDeleted, Constants.ZERO)
+                .in(Orders::getStatus,
+                                Constants.OrderStatus.waitDeposit.getKey(),
+                                Constants.OrderStatus.deposited.getKey(),
+                                Constants.OrderStatus.accepted.getKey(),
+                                Constants.OrderStatus.delivering.getKey(),
+                                Constants.OrderStatus.arrived.getKey(),
+                                Constants.OrderStatus.overdue.getKey())
+                .ge(Orders::getCreateTime, startDate));
+
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        Map<String, List<Orders>> grouped = orders.stream()
+                .collect(Collectors.groupingBy(o -> sdf.format(o.getCreateTime())));
+
+        return buildDailyList(startDate, (date) -> {
+            List<Orders> dayOrders = grouped.getOrDefault(date, Collections.emptyList());
+            OrderTrendVO vo = new OrderTrendVO();
+            vo.setDate(date);
+            vo.setLocalCount(dayOrders.stream().filter(o -> Constants.equalsInteger(o.getType(), Constants.ZERO)).count());
+            vo.setRemoteCount(dayOrders.stream().filter(o -> Constants.equalsInteger(o.getType(), Constants.ONE)).count());
+            return vo;
+        });
+    }
+
+    @Override
+    public List<RevenueTrendVO> revenueTrend() {
+        Date startDate = get30DaysAgoStart();
+
+        List<Orders> orders = ordersMapper.selectList(new QueryWrapper<Orders>().lambda()
+                .eq(Orders::getDeleted, Constants.ZERO)
+                .in(Orders::getStatus,
+                                Constants.OrderStatus.waitDeposit.getKey(),
+                                Constants.OrderStatus.deposited.getKey(),
+                                Constants.OrderStatus.accepted.getKey(),
+                                Constants.OrderStatus.delivering.getKey(),
+                                Constants.OrderStatus.arrived.getKey(),
+                                Constants.OrderStatus.overdue.getKey())
+                .ge(Orders::getCreateTime, startDate));
+
+        List<OtherOrders> otherOrders = otherOrdersMapper.selectList(new QueryWrapper<OtherOrders>().lambda()
+                .eq(OtherOrders::getType, 2)
+                .eq(OtherOrders::getPayStatus, Constants.ONE)
+                .eq(OtherOrders::getDeleted, Constants.ZERO)
+                .ge(OtherOrders::getPayTime, startDate));
+
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        Map<String, Long> localOrderRevenue = new HashMap<>();
+        Map<String, Long> remoteOrderRevenue = new HashMap<>();
+        for (Orders o : orders) {
+            String date = sdf.format(o.getCreateTime());
+            long pay = o.getPayAmount() != null ? o.getPayAmount() : 0L;
+            long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L;
+            long overdue = (o.getOverdueStatus() != null && o.getOverdueStatus() == 2 && o.getOverdueAmount() != null)
+                    ? o.getOverdueAmount() : 0L;
+            long rev = pay - refund + overdue;
+            if (Constants.equalsInteger(o.getType(), Constants.ZERO)) {
+                localOrderRevenue.merge(date, rev, Long::sum);
+            } else {
+                remoteOrderRevenue.merge(date, rev, Long::sum);
+            }
+        }
+
+        Map<String, Long> otherRevenueMap = new HashMap<>();
+        for (OtherOrders oo : otherOrders) {
+            String date = sdf.format(oo.getPayTime());
+            long amt = oo.getPayAccount() != null ? oo.getPayAccount() : 0L;
+            otherRevenueMap.merge(date, amt, Long::sum);
+        }
+
+        return buildDailyList(startDate, (date) -> {
+            RevenueTrendVO vo = new RevenueTrendVO();
+            vo.setDate(date);
+            long local = localOrderRevenue.getOrDefault(date, 0L) + otherRevenueMap.getOrDefault(date, 0L);
+            long remote = remoteOrderRevenue.getOrDefault(date, 0L);
+            vo.setLocalRevenue(BigDecimal.valueOf(local).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
+            vo.setRemoteRevenue(BigDecimal.valueOf(remote).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
+            return vo;
+        });
+    }
+
+    @Override
+    public ShopPerformanceVO shopPerformance(DataBoardQueryDTO query) {
+        ShopPerformanceVO vo = new ShopPerformanceVO();
+
+        // 1. 鎬昏鍗曟暟 + 钀ユ敹锛坰tatus 1-6锛�
+        QueryWrapper<Orders> qw = buildOrderQueryWrapper(query);
+        List<Orders> orders = ordersMapper.selectList(qw);
+        vo.setTotalOrderCount((long) orders.size());
+
+        long revenue = 0L;
+        for (Orders o : orders) {
+            long pay = o.getPayAmount() != null ? o.getPayAmount() : 0L;
+            long overdue = o.getOverdueAmount() != null ? o.getOverdueAmount() : 0L;
+            long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L;
+            revenue += pay + overdue - refund;
+        }
+        vo.setTotalRevenue(BigDecimal.valueOf(Math.max(revenue, 0L))
+                .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
+
+        // 2. 宸插畬鎴愯鍗曟暟锛坰tatus=7锛屽悓绛夌瓫閫夋潯浠讹級
+        QueryWrapper<Orders> completedQw = new QueryWrapper<>();
+        completedQw.lambda()
+                .eq(Orders::getDeleted, Constants.ZERO)
+                .eq(Orders::getStatus, Constants.OrderStatus.finished.getKey());
+        if (query.getStartDate() != null) {
+            completedQw.lambda().ge(Orders::getCreateTime, query.getStartDate());
+        }
+        if (query.getEndDate() != null) {
+            completedQw.lambda().le(Orders::getCreateTime, Utils.Date.getEnd(query.getEndDate()));
+        }
+        if (query.getShopId() != null) {
+            completedQw.lambda().and(w -> w.eq(Orders::getDepositShopId, query.getShopId())
+                    .or().eq(Orders::getTakeShopId, query.getShopId()));
+        }
+        vo.setCompletedCount(ordersMapper.selectCount(completedQw));
+
+        // 3. 宸查��娆捐鍗曟暟锛坥rders_refund status=1 鐨勫幓閲嶈鍗曟暟锛�
+        List<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
+        if (!orderIds.isEmpty()) {
+            QueryWrapper<OrdersRefund> refundQw = new QueryWrapper<>();
+            refundQw.lambda()
+                    .in(OrdersRefund::getOrderId, orderIds)
+                    .eq(OrdersRefund::getStatus, Constants.ONE)
+                    .eq(OrdersRefund::getDeleted, Constants.ZERO);
+            List<OrdersRefund> refundRecords = ordersRefundMapper.selectList(refundQw);
+            long refundedOrderCount = refundRecords.stream()
+                    .map(OrdersRefund::getOrderId).distinct().count();
+            vo.setRefundedCount(refundedOrderCount);
+        } else {
+            vo.setRefundedCount(0L);
+        }
+
+        // 4. 璁㈠崟瀹屾垚鐜� & 閫�娆剧巼锛堝垎姣� = status 1-6 + status 7锛�
+        long totalCount = vo.getTotalOrderCount() + vo.getCompletedCount();
+        if (totalCount > 0) {
+            BigDecimal hundred = BigDecimal.valueOf(100);
+            vo.setCompletionRate(BigDecimal.valueOf(vo.getCompletedCount())
+                    .multiply(hundred).divide(BigDecimal.valueOf(totalCount), 2, RoundingMode.HALF_UP));
+            vo.setRefundRate(BigDecimal.valueOf(vo.getRefundedCount())
+                    .multiply(hundred).divide(BigDecimal.valueOf(totalCount), 2, RoundingMode.HALF_UP));
+        } else {
+            vo.setCompletionRate(BigDecimal.ZERO);
+            vo.setRefundRate(BigDecimal.ZERO);
+        }
+
+        return vo;
+    }
+
+    // ========== 绉佹湁鏂规硶 ==========
+
+    private QueryWrapper<Orders> buildOrderQueryWrapper(DataBoardQueryDTO query) {
+        QueryWrapper<Orders> qw = new QueryWrapper<>();
+        qw.lambda()
+                .eq(Orders::getDeleted, Constants.ZERO)
+                .in(Orders::getStatus,
+                        Constants.OrderStatus.waitDeposit.getKey(),
+                        Constants.OrderStatus.deposited.getKey(),
+                        Constants.OrderStatus.accepted.getKey(),
+                        Constants.OrderStatus.delivering.getKey(),
+                        Constants.OrderStatus.arrived.getKey(),
+                        Constants.OrderStatus.overdue.getKey());
+        if (query.getStartDate() != null) {
+            qw.lambda().ge(Orders::getCreateTime, query.getStartDate());
+        }
+        if (query.getEndDate() != null) {
+            qw.lambda().le(Orders::getCreateTime, Utils.Date.getEnd(query.getEndDate()));
+        }
+        if (query.getShopId() != null) {
+            qw.lambda().and(w -> w.eq(Orders::getDepositShopId, query.getShopId())
+                    .or().eq(Orders::getTakeShopId, query.getShopId()));
+        }
+        return qw;
+    }
+
+    private Date get30DaysAgoStart() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(Calendar.HOUR_OF_DAY, 0);
+        cal.set(Calendar.MINUTE, 0);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        cal.add(Calendar.DAY_OF_MONTH, -29);
+        return cal.getTime();
+    }
+
+    @FunctionalInterface
+    private interface DailyVOBuilder<T> {
+        T build(String date);
+    }
+
+    private <T> List<T> buildDailyList(Date startDate, DailyVOBuilder<T> builder) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        List<T> result = new ArrayList<>();
+        Calendar loop = Calendar.getInstance();
+        loop.setTime(startDate);
+        Calendar end = Calendar.getInstance();
+        while (!loop.after(end)) {
+            result.add(builder.build(sdf.format(loop.getTime())));
+            loop.add(Calendar.DAY_OF_MONTH, 1);
+        }
+        return result;
+    }
+}
diff --git a/server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java b/server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java
index 8c8d14b..84659b7 100644
--- a/server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java
+++ b/server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java
@@ -259,6 +259,10 @@
         if (pageWrap.getModel().getStatus() != null) {
             queryWrapper.eq(DriverInfo::getStatus, pageWrap.getModel().getStatus());
         }
+        // 鐗堟湰
+        if (pageWrap.getModel().getVersionType() != null) {
+            queryWrapper.eq(DriverInfo::getVersionType, pageWrap.getModel().getVersionType());
+        }
         // 瀹℃壒鐘舵��
         if (pageWrap.getModel().getAuditStatus() != null) {
             queryWrapper.eq(DriverInfo::getAuditStatus, pageWrap.getModel().getAuditStatus());
@@ -356,7 +360,7 @@
 
         Date now = new Date();
         Member member;
-
+        DriverInfo driverInfo = new DriverInfo();
         if (Objects.nonNull(existMember)) {
             // 宸叉湁鍙告満璐﹀彿锛岀洿鎺ョ櫥褰�
             if (!Constants.equalsInteger(existMember.getStatus(), Constants.ZERO)) {
@@ -398,8 +402,6 @@
             memberMapper.insert(member);
 
             // 鍒涘缓鍙告満鍩虹淇℃伅
-            DriverInfo driverInfo = new DriverInfo();
-            driverInfo.setId(member.getId());
             driverInfo.setDeleted(Constants.ZERO);
             driverInfo.setCreateTime(now);
             driverInfo.setUpdateTime(now);
@@ -415,7 +417,7 @@
 
         // 3. 鐢熸垚token杩斿洖
         AccountResponse accountResponse = new AccountResponse();
-        accountResponse.setToken(JwtTokenUtil.generateTokenForRedis(member.getId(), Constants.ONE, JSONObject.toJSONString(member), redisTemplate));
+        accountResponse.setToken(JwtTokenUtil.generateTokenForRedis(driverInfo.getId(), Constants.ONE, JSONObject.toJSONString(member), redisTemplate));
         accountResponse.setMember(member);
         return accountResponse;
     }
@@ -439,6 +441,13 @@
         if (!Constants.equalsInteger(member.getStatus(), Constants.ZERO)) {
             throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "璐﹀彿宸插仠鐢紝璇疯仈绯荤鐞嗗憳");
         }
+        // 鑾峰彇鍙告満琛ㄤ俊鎭�
+        DriverInfo driverInfo = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda().eq(DriverInfo::getMemberId, member.getId())
+                .eq(DriverInfo::getDeleted, Constants.ZERO).eq(DriverInfo::getVersionType,Constants.ZERO).last("limit 1")
+        );
+        if(Objects.isNull(driverInfo)){
+            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "鍙告満璐﹀彿涓嶅瓨鍦�");
+        }
         // 鏍¢獙瀵嗙爜
         String encryptPwd = secure.encryptPassword(password, member.getSalt());
         if (!encryptPwd.equals(member.getPassword())) {
@@ -449,9 +458,8 @@
                 .set(Member::getLoginTime, new Date())
                 .setSql("login_times = login_times + 1")
                 .eq(Member::getId, member.getId()));
-
         AccountResponse accountResponse = new AccountResponse();
-        accountResponse.setToken(JwtTokenUtil.generateTokenForRedis(member.getId(), Constants.ONE, JSONObject.toJSONString(member), redisTemplate));
+        accountResponse.setToken(JwtTokenUtil.generateTokenForRedis(driverInfo.getId(), Constants.ONE, JSONObject.toJSONString(member), redisTemplate));
         accountResponse.setMember(member);
         return accountResponse;
     }
@@ -460,7 +468,7 @@
 
     @Override
     @Transactional
-    public void submitVerify(Integer memberId, DriverVerifyRequest request) {
+    public void submitVerify(Integer driverId, DriverVerifyRequest request) {
         // 鍙傛暟鍩虹鏍¢獙
         if (StringUtils.isAnyBlank(request.getName(), request.getIdcard(), request.getLivePlace(),
                 request.getCarCode(), request.getIdcardImg(), request.getIdcardImgBack())) {
@@ -472,19 +480,6 @@
         // 韬唤璇佸彿鏍煎紡鏍¢獙锛�18浣嶏紝鏈�鍚庝竴浣嶅彲涓篨锛�
         if (!request.getIdcard().matches("^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dXx]$")) {
             throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "韬唤璇佸彿鏍煎紡涓嶆纭�");
-        }
-        // 鏌ヨ鍙告満淇℃伅
-        DriverInfo driverInfo = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
-                .eq(DriverInfo::getMemberId, memberId)
-                .eq(DriverInfo::getDeleted, Constants.ZERO)
-                .last("limit 1"));
-        if (Objects.isNull(driverInfo)) {
-            throw new BusinessException(ResponseStatus.DATA_EMPTY);
-        }
-        // 鐘舵�佹牎楠岋細auditStatus=null(鏈彁浜�)鎴朼uditStatus=2(瀹℃壒椹冲洖)鍙彁浜よ璇�
-        if (driverInfo.getAuditStatus() != null
-                && !(Constants.equalsInteger(driverInfo.getAuditStatus(), Constants.TWO)||Constants.equalsInteger(driverInfo.getAuditStatus(), 99))) {
-            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "褰撳墠鐘舵�佷笉鍏佽鎻愪氦璁よ瘉");
         }
         // 鏍规嵁杞﹁締绫诲瀷鍒ゆ柇鏄惁闇�瑕侀┚椹惰瘉
         Category category = categoryMapper.selectById(request.getCarType());
@@ -515,8 +510,66 @@
             throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "鍏朵粬璧勬枡鐓х墖鏈�澶氫笂浼�3寮�");
         }
 
-        // 鏇存柊鍙告満淇℃伅
+        // 鏌ヨ姝e紡鐗堟湰鍙告満
+        DriverInfo official = driverInfoMapper.selectById(driverId);
+        if (Objects.isNull(official) || Constants.equalsInteger(official.getDeleted(), Constants.ONE)) {
+            throw new BusinessException(ResponseStatus.DATA_EMPTY);
+        }
+        Integer memberId = official.getMemberId();
+
         Date now = new Date();
+
+        // 鏌ヨ璇ヤ細鍛樻渶鏂扮殑鍙樻洿鐗堟湰
+        QueryWrapper<DriverInfo> changeQw = new QueryWrapper<>();
+        changeQw.lambda()
+                .eq(DriverInfo::getMemberId, memberId)
+                .eq(DriverInfo::getVersionType, Constants.ONE)
+                .eq(DriverInfo::getDeleted, Constants.ZERO)
+                .orderByDesc(DriverInfo::getCreateTime)
+                .last("limit 1");
+        DriverInfo changeVersion = driverInfoMapper.selectOne(changeQw);
+
+        if (changeVersion == null) {
+            // 棣栨璁よ瘉锛氭洿鏂版寮忕増鏈� + 鍒涘缓鍙樻洿鐗堟湰
+            applyDriverFieldsFromUpdate(official.getId(), request, now);
+            deleteDriverAttachments(official.getId());
+            saveDriverAttachments(official.getId(), request, now);
+            // 閲嶆柊璇诲彇鏇存柊鍚庣殑姝e紡鐗堟湰锛屽啀鍒涘缓鍙樻洿鐗堟湰
+            DriverInfo updatedOfficial = driverInfoMapper.selectById(official.getId());
+            createDriverChangeVersion(updatedOfficial, official.getId(), now);
+        } else if (Constants.equalsInteger(changeVersion.getAuditStatus(), Constants.THREE)) {
+            // auditStatus=3锛氱敓鎴愭柊鐨勫彉鏇寸増鏈�
+            Integer relationId = changeVersion.getRelationDriverId() != null
+                    ? changeVersion.getRelationDriverId() : official.getId();
+            DriverInfo newChange = new DriverInfo();
+            applyDriverFieldsFromNew(newChange, request, official, now);
+            newChange.setVersionType(Constants.ONE);
+            newChange.setRelationDriverId(relationId);
+            newChange.setAuditStatus(Constants.ZERO);
+            newChange.setStatus(Constants.ZERO);
+            newChange.setDeleted(Constants.ZERO);
+            newChange.setCreateTime(now);
+            newChange.setUpdateTime(now);
+            newChange.setMemberId(memberId);
+            newChange.setTelephone(official.getTelephone());
+            newChange.setJpushAlias(official.getJpushAlias());
+            driverInfoMapper.insert(newChange);
+            saveDriverAttachments(newChange.getId(), request, now);
+        } else {
+            // auditStatus=0/2锛氱洿鎺ユ洿鏂板彉鏇寸増鏈�
+            applyDriverFieldsFromUpdate(changeVersion.getId(), request, now);
+            deleteDriverAttachments(changeVersion.getId());
+            saveDriverAttachments(changeVersion.getId(), request, now);
+        }
+
+        // 鏇存柊浼氬憳鍙告満璁よ瘉鐘舵�佷负璁よ瘉涓�
+        memberMapper.update(new UpdateWrapper<Member>().lambda()
+                .set(Member::getBusinessStatus, Constants.ONE)
+                .set(Member::getUpdateTime, now)
+                .eq(Member::getId, memberId));
+    }
+
+    private void applyDriverFieldsFromUpdate(Integer driverId, DriverVerifyRequest request, Date now) {
         driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
                 .set(DriverInfo::getName, request.getName())
                 .set(DriverInfo::getIdcard, request.getIdcard())
@@ -536,39 +589,129 @@
                 .set(DriverInfo::getAuditStatus, Constants.ZERO)
                 .set(DriverInfo::getAuditRemark, null)
                 .set(DriverInfo::getAuditTime, null)
-                .eq(DriverInfo::getId, driverInfo.getId()));
+                .eq(DriverInfo::getId, driverId));
+    }
 
-        // 鍒犻櫎鏃х殑鐓х墖璁板綍
-        multifileMapper.delete(new QueryWrapper<Multifile>().lambda()
-                .eq(Multifile::getObjId, driverInfo.getId())
-                .in(Multifile::getObjType, 6, 7, 8));
+    private void applyDriverFieldsFromNew(DriverInfo driver, DriverVerifyRequest request, DriverInfo official, Date now) {
+        driver.setName(request.getName());
+        driver.setIdcard(request.getIdcard());
+        driver.setMaritalStatus(request.getMaritalStatus());
+        driver.setAreaId(request.getAreaId());
+        driver.setLivePlace(request.getLivePlace());
+        driver.setCarCode(request.getCarCode());
+        driver.setCarType(request.getCarType());
+        driver.setCarColor(request.getCarColor());
+        driver.setCardStartDate(request.getCardStartDate());
+        driver.setCardEndDate(request.getCardEndDate());
+        driver.setIdcardImg(request.getIdcardImg());
+        driver.setIdcardImgBack(request.getIdcardImgBack());
+        driver.setAliAccount(request.getAliAccount());
+        driver.setAliName(request.getAliName());
+    }
 
-        // 淇濆瓨杞﹁締鐓х墖 objType=6
-        saveMultifileList(driverInfo.getId(), 6, request.getCarImgUrls(), now);
-        // 淇濆瓨椹鹃┒璇佺収鐗� objType=7
+    private void saveDriverAttachments(Integer driverId, DriverVerifyRequest request, Date now) {
+        saveMultifileList(driverId, 6, request.getCarImgUrls(), now);
         if (!CollectionUtils.isEmpty(request.getLicenseImgUrls())) {
-            saveMultifileList(driverInfo.getId(), 7, request.getLicenseImgUrls(), now);
+            saveMultifileList(driverId, 7, request.getLicenseImgUrls(), now);
         }
-        // 淇濆瓨鍏朵粬璧勬枡鐓х墖 objType=8
         if (!CollectionUtils.isEmpty(request.getOtherImgUrls())) {
-            saveMultifileList(driverInfo.getId(), 8, request.getOtherImgUrls(), now);
+            saveMultifileList(driverId, 8, request.getOtherImgUrls(), now);
         }
+    }
 
-        // 鏇存柊浼氬憳鍙告満璁よ瘉鐘舵�佷负璁よ瘉涓�
-        memberMapper.update(new UpdateWrapper<Member>().lambda()
-                .set(Member::getBusinessStatus, Constants.ONE)
-                .set(Member::getUpdateTime, now)
-                .eq(Member::getId, memberId));
+    private void deleteDriverAttachments(Integer driverId) {
+        multifileMapper.delete(new QueryWrapper<Multifile>().lambda()
+                .eq(Multifile::getObjId, driverId)
+                .in(Multifile::getObjType, 6, 7, 8));
+    }
+
+    private void createDriverChangeVersion(DriverInfo official, Integer officialId, Date now) {
+        DriverInfo change = new DriverInfo();
+        change.setName(official.getName());
+        change.setIdcard(official.getIdcard());
+        change.setMaritalStatus(official.getMaritalStatus());
+        change.setAreaId(official.getAreaId());
+        change.setLivePlace(official.getLivePlace());
+        change.setImgurl(official.getImgurl());
+        change.setCarType(official.getCarType());
+        change.setCarCode(official.getCarCode());
+        change.setCarColor(official.getCarColor());
+        change.setCardStartDate(official.getCardStartDate());
+        change.setCardEndDate(official.getCardEndDate());
+        change.setIdcardImg(official.getIdcardImg());
+        change.setIdcardImgBack(official.getIdcardImgBack());
+        change.setAliAccount(official.getAliAccount());
+        change.setAliName(official.getAliName());
+        change.setVersionType(Constants.ONE);
+        change.setRelationDriverId(officialId);
+        change.setMemberId(official.getMemberId());
+        change.setTelephone(official.getTelephone());
+        change.setOpenid(official.getOpenid());
+        change.setUnionid(official.getUnionid());
+        change.setJpushAlias(official.getJpushAlias());
+        change.setScore(official.getScore());
+        change.setDriverLevel(official.getDriverLevel());
+        change.setBalance(official.getBalance());
+        change.setTotalBalance(official.getTotalBalance());
+        change.setLongitude(official.getLongitude());
+        change.setLatitude(official.getLatitude());
+        change.setAuditStatus(official.getAuditStatus());
+        change.setStatus(official.getStatus());
+        change.setDeleted(official.getDeleted());
+        change.setCreateTime(now);
+        change.setUpdateTime(now);
+        driverInfoMapper.insert(change);
+
+        // 鎷疯礉闄勪欢
+        List<Multifile> originFiles = multifileMapper.selectList(new QueryWrapper<Multifile>().lambda()
+                .eq(Multifile::getObjId, officialId)
+                .eq(Multifile::getIsdeleted, Constants.ZERO)
+                .in(Multifile::getObjType, 6, 7, 8));
+        for (Multifile f : originFiles) {
+            Multifile copy = new Multifile();
+            copy.setCreator(f.getCreator());
+            copy.setCreateDate(now);
+            copy.setIsdeleted(Constants.ZERO);
+            copy.setName(f.getName());
+            copy.setInfo(f.getInfo());
+            copy.setObjId(change.getId());
+            copy.setType(f.getType());
+            copy.setObjType(f.getObjType());
+            copy.setFileurl(f.getFileurl());
+            copy.setSortnum(f.getSortnum());
+            multifileMapper.insert(copy);
+        }
     }
 
     @Override
     public DriverInfo getVerifyDetail(Integer memberId) {
+        // 浼樺厛鏌ヨ鏈�鏂扮殑鍙樻洿鐗堟湰
         DriverInfo driverInfo = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
-                .eq(DriverInfo::getId, memberId)
+                .eq(DriverInfo::getRelationDriverId, memberId)
+                .eq(DriverInfo::getVersionType, Constants.ONE)
                 .eq(DriverInfo::getDeleted, Constants.ZERO)
+                .orderByDesc(DriverInfo::getCreateTime)
                 .last("limit 1"));
         if (Objects.isNull(driverInfo)) {
+            // 鏃犲彉鏇寸増鏈垯鏌ユ寮忕増鏈�
+            driverInfo = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
+                    .eq(DriverInfo::getId, memberId)
+                    .eq(DriverInfo::getVersionType, Constants.ZERO)
+                    .eq(DriverInfo::getDeleted, Constants.ZERO)
+                    .last("limit 1"));
+        }
+        if (Objects.isNull(driverInfo)) {
             throw new BusinessException(ResponseStatus.DATA_EMPTY);
+        }
+        // 鏍囪鏄惁瀛樺湪瀹℃壒閫氳繃鐨勬寮忕増鏈�
+        if (driverInfo.getRelationDriverId() != null) {
+            DriverInfo official = driverInfoMapper.selectById(driverInfo.getRelationDriverId());
+            driverInfo.setHasApprovedOfficial(official != null
+                    && Constants.equalsInteger(official.getAuditStatus(), Constants.THREE));
+        } else if (Constants.equalsInteger(driverInfo.getVersionType(), Constants.ZERO)) {
+            driverInfo.setHasApprovedOfficial(Constants.equalsInteger(driverInfo.getAuditStatus(), Constants.THREE));
+        } else {
+            driverInfo.setHasApprovedOfficial(false);
         }
         // 鎷兼帴鍥剧墖鍓嶇紑
         String imgPrefix = "";
@@ -625,57 +768,142 @@
         if (Objects.isNull(auditDTO.getId()) || Objects.isNull(auditDTO.getAuditStatus())) {
             throw new BusinessException(ResponseStatus.BAD_REQUEST);
         }
-        DriverInfo driverInfo = driverInfoMapper.selectById(auditDTO.getId());
-        if (Objects.isNull(driverInfo)) {
+        // 瀹℃壒鐨勬槸鍙樻洿鐗堟湰
+        DriverInfo changeVersion = driverInfoMapper.selectById(auditDTO.getId());
+        if (Objects.isNull(changeVersion) || Constants.equalsInteger(changeVersion.getDeleted(), Constants.ONE)) {
             throw new BusinessException(ResponseStatus.DATA_EMPTY);
         }
-        // 鍙湁瀹℃壒鐘舵�佷负0(寰呭鎵�)涓斿凡濉啓璁よ瘉淇℃伅鎵嶈兘瀹℃壒
-        if (!Constants.equalsInteger(driverInfo.getAuditStatus(), Constants.ZERO)
-                || StringUtils.isBlank(driverInfo.getIdcard())) {
+        if (!Constants.equalsInteger(changeVersion.getAuditStatus(), Constants.ZERO)
+                || StringUtils.isBlank(changeVersion.getIdcard())) {
             throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "褰撳墠鐘舵�佷笉鍏佽瀹℃壒");
         }
+
         Date now = new Date();
-        // 瀹℃壒缁撴灉锛歛uditDTO.auditStatus 0=閫氳繃鈫抋uditStatus=1锛�1=鎷掔粷鈫抋uditStatus=2
+        // auditDTO.auditStatus: 0=閫氳繃鈫�3, 1=椹冲洖鈫�2
         Integer newAuditStatus;
         if (Constants.equalsInteger(auditDTO.getAuditStatus(), Constants.ZERO)) {
-            newAuditStatus = Constants.THREE;  // 瀹℃壒閫氳繃
-            // 瀹℃壒閫氳繃鏃跺徃鏈哄畾绾т负蹇呭~
+            newAuditStatus = Constants.THREE;
             if (auditDTO.getDriverLevel() == null || auditDTO.getDriverLevel() < 1 || auditDTO.getDriverLevel() > 5) {
                 throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "瀹℃壒閫氳繃鏃跺繀椤诲~鍐欏徃鏈哄畾绾�");
             }
         } else if (Constants.equalsInteger(auditDTO.getAuditStatus(), Constants.ONE)) {
-            newAuditStatus = Constants.TWO;  // 瀹℃壒椹冲洖
+            newAuditStatus = Constants.TWO;
         } else {
             throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "瀹℃壒鐘舵�佸弬鏁伴敊璇�");
         }
-        // 鏇存柊鍙告満瀹℃壒鐘舵��
-        driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
-                .set(DriverInfo::getAuditStatus, newAuditStatus)
-                .set(DriverInfo::getAuditTime, now)
-                .set(DriverInfo::getAuditRemark, auditDTO.getAuditRemark())
-                .set(DriverInfo::getAuditUser, auditDTO.getAuditUser())
-                .set(auditDTO.getDriverLevel() != null, DriverInfo::getDriverLevel, auditDTO.getDriverLevel())
-                .set(DriverInfo::getUpdateTime, now)
-                .eq(DriverInfo::getId, auditDTO.getId()));
-        // 鏇存柊浼氬憳鍙告満璁よ瘉鐘舵�侊細閫氳繃=2锛岄┏鍥�=3
-        Integer driverStatus = Constants.equalsInteger(newAuditStatus, Constants.ONE) ? Constants.TWO : Constants.THREE;
-        memberMapper.update(new UpdateWrapper<Member>().lambda()
-                .set(Member::getBusinessStatus, driverStatus)
-                .set(Member::getUpdateTime, now)
-                .eq(Member::getId, driverInfo.getMemberId()));
 
-        // 鐭俊閫氱煡
-        if (Constants.equalsInteger(newAuditStatus, Constants.ONE)) {
-            // 瀹℃壒閫氳繃
+        // 鏌ユ壘姝e紡鐗堟湰
+        Integer officialId = changeVersion.getRelationDriverId();
+        DriverInfo official = officialId != null ? driverInfoMapper.selectById(officialId) : null;
+        boolean hasApprovedOfficial = official != null
+                && Constants.equalsInteger(official.getAuditStatus(), Constants.THREE);
+
+        if (!hasApprovedOfficial) {
+            // 鍦烘櫙1锛氭寮忕増鏈湭瀹℃壒閫氳繃锛堥娆″鎵癸級
+            driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
+                    .set(DriverInfo::getAuditStatus, newAuditStatus)
+                    .set(DriverInfo::getAuditTime, now)
+                    .set(DriverInfo::getAuditRemark, auditDTO.getAuditRemark())
+                    .set(DriverInfo::getAuditUser, auditDTO.getAuditUser())
+                    .set(auditDTO.getDriverLevel() != null, DriverInfo::getDriverLevel, auditDTO.getDriverLevel())
+                    .set(DriverInfo::getUpdateTime, now)
+                    .eq(DriverInfo::getId, changeVersion.getId()));
+
+            // 鍚屾鏇存柊姝e紡鐗堟湰锛堝鎵圭姸鎬� + 鏁版嵁瀛楁锛�
+            if (official != null) {
+                syncDriverChangeToOfficial(changeVersion, official, auditDTO.getDriverLevel(), now);
+            }
+
+            // 鏇存柊浼氬憳鐘舵��
+            Integer driverStatus = Constants.equalsInteger(newAuditStatus, Constants.THREE) ? Constants.TWO : Constants.THREE;
+            memberMapper.update(new UpdateWrapper<Member>().lambda()
+                    .set(Member::getBusinessStatus, driverStatus)
+                    .set(Member::getUpdateTime, now)
+                    .eq(Member::getId, changeVersion.getMemberId()));
+
+            // 鐭俊閫氱煡
+            sendDriverAuditSms(changeVersion, newAuditStatus, auditDTO.getAuditRemark());
+        } else {
+            // 鍦烘櫙2锛氭寮忕増鏈凡瀹℃壒閫氳繃锛堝彉鏇村鎵癸級
+            if (Constants.equalsInteger(newAuditStatus, Constants.THREE)) {
+                // 瀹℃壒閫氳繃锛氬彉鏇寸増鏈爣璁癮uditStatus=3锛屽悓姝ユ暟鎹埌姝e紡鐗堟湰
+                driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
+                        .set(DriverInfo::getAuditStatus, Constants.THREE)
+                        .set(DriverInfo::getAuditTime, now)
+                        .set(DriverInfo::getAuditRemark, auditDTO.getAuditRemark())
+                        .set(DriverInfo::getAuditUser, auditDTO.getAuditUser())
+                        .set(DriverInfo::getDriverLevel, auditDTO.getDriverLevel())
+                        .set(DriverInfo::getUpdateTime, now)
+                        .eq(DriverInfo::getId, changeVersion.getId()));
+
+                // 鍚屾鍙樻洿鐗堟湰鏁版嵁鍒版寮忕増鏈�
+                syncDriverChangeToOfficial(changeVersion, official, auditDTO.getDriverLevel(), now);
+            } else {
+                // 瀹℃壒椹冲洖锛氫粎鏍囪鍙樻洿鐗堟湰
+                driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
+                        .set(DriverInfo::getAuditStatus, Constants.TWO)
+                        .set(DriverInfo::getAuditTime, now)
+                        .set(DriverInfo::getAuditRemark, auditDTO.getAuditRemark())
+                        .set(DriverInfo::getAuditUser, auditDTO.getAuditUser())
+                        .set(DriverInfo::getUpdateTime, now)
+                        .eq(DriverInfo::getId, changeVersion.getId()));
+            }
+        }
+    }
+
+    private void syncDriverChangeToOfficial(DriverInfo changeVersion, DriverInfo official, Integer driverLevel, Date now) {
+        official.setName(changeVersion.getName());
+        official.setIdcard(changeVersion.getIdcard());
+        official.setMaritalStatus(changeVersion.getMaritalStatus());
+        official.setAreaId(changeVersion.getAreaId());
+        official.setLivePlace(changeVersion.getLivePlace());
+        official.setCarType(changeVersion.getCarType());
+        official.setCarCode(changeVersion.getCarCode());
+        official.setCarColor(changeVersion.getCarColor());
+        official.setCardStartDate(changeVersion.getCardStartDate());
+        official.setCardEndDate(changeVersion.getCardEndDate());
+        official.setIdcardImg(changeVersion.getIdcardImg());
+        official.setIdcardImgBack(changeVersion.getIdcardImgBack());
+        official.setAliAccount(changeVersion.getAliAccount());
+        official.setAliName(changeVersion.getAliName());
+        if (driverLevel != null) {
+            official.setDriverLevel(driverLevel);
+        }
+        official.setUpdateTime(now);
+        driverInfoMapper.updateById(official);
+
+        // 鍚屾闄勪欢锛氬厛鍒犳寮忕増鏈棫闄勪欢锛屽啀浠庡彉鏇寸増鏈嫹璐�
+        deleteDriverAttachments(official.getId());
+        List<Multifile> changeFiles = multifileMapper.selectList(new QueryWrapper<Multifile>().lambda()
+                .eq(Multifile::getObjId, changeVersion.getId())
+                .eq(Multifile::getIsdeleted, Constants.ZERO)
+                .in(Multifile::getObjType, 6, 7, 8));
+        for (Multifile f : changeFiles) {
+            Multifile copy = new Multifile();
+            copy.setCreator(f.getCreator());
+            copy.setCreateDate(now);
+            copy.setIsdeleted(Constants.ZERO);
+            copy.setName(f.getName());
+            copy.setInfo(f.getInfo());
+            copy.setObjId(official.getId());
+            copy.setType(f.getType());
+            copy.setObjType(f.getObjType());
+            copy.setFileurl(f.getFileurl());
+            copy.setSortnum(f.getSortnum());
+            multifileMapper.insert(copy);
+        }
+    }
+
+    private void sendDriverAuditSms(DriverInfo driverInfo, Integer newAuditStatus, String auditRemark) {
+        if (Constants.equalsInteger(newAuditStatus, Constants.THREE)) {
             sendSmsNotify(driverInfo.getTelephone(),
                     Constants.SmsNotify.DRIVER_AUTH_APPROVED,
                     "driver", driverInfo.getName());
         } else if (Constants.equalsInteger(newAuditStatus, Constants.TWO)) {
-            // 瀹℃壒椹冲洖
             sendSmsNotify(driverInfo.getTelephone(),
                     Constants.SmsNotify.DRIVER_AUTH_REJECTED,
                     "driver", driverInfo.getName(),
-                    "reason", auditDTO.getAuditRemark() != null ? auditDTO.getAuditRemark() : "");
+                    "reason", auditRemark != null ? auditRemark : "");
         }
     }
 
@@ -829,7 +1057,8 @@
             throw new BusinessException(ResponseStatus.BAD_REQUEST);
         }
         DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
-                .eq(DriverInfo::getMemberId, memberId)
+                .eq(DriverInfo::getId, memberId)
+                .eq(DriverInfo::getVersionType, Constants.ZERO)
                 .eq(DriverInfo::getDeleted, Constants.ZERO)
                 .last("limit 1"));
         if (driver == null) {
@@ -844,12 +1073,13 @@
     }
 
     @Override
-    public void updateLocation(Integer memberId, Double longitude, Double latitude) {
+    public void updateLocation(Integer driverId, Double longitude, Double latitude) {
         if (longitude == null || latitude == null) {
             throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "缁忕含搴︿笉鑳戒负绌�");
         }
         DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
-                .eq(DriverInfo::getMemberId, memberId)
+                .eq(DriverInfo::getId, driverId)
+                .eq(DriverInfo::getVersionType, Constants.ZERO)
                 .eq(DriverInfo::getDeleted, Constants.ZERO)
                 .last("limit 1"));
         if (driver == null) {
@@ -862,9 +1092,10 @@
     }
 
     @Override
-    public DriverCenterVO getDriverCenterInfo(Integer memberId) {
+    public DriverCenterVO getDriverCenterInfo(Integer driveId) {
         DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
-                .eq(DriverInfo::getMemberId, memberId)
+                .eq(DriverInfo::getId, driveId)
+                .eq(DriverInfo::getVersionType, Constants.ZERO)
                 .eq(DriverInfo::getDeleted, Constants.ZERO)
                 .last("limit 1"));
         if (driver == null) {
@@ -940,6 +1171,7 @@
     public com.doumee.dao.vo.DriverStatsVO getDriverStats(Integer memberId) {
         DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
                 .eq(DriverInfo::getId, memberId)
+                .eq(DriverInfo::getVersionType, Constants.ZERO)
                 .eq(DriverInfo::getDeleted, Constants.ZERO)
                 .last("limit 1"));
         if (driver == null) {
@@ -990,7 +1222,8 @@
 
         // 1. 鑾峰彇鍙告満瀹氫綅
         DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
-                .eq(DriverInfo::getMemberId, memberId)
+                .eq(DriverInfo::getId, memberId)
+                .eq(DriverInfo::getVersionType, Constants.ZERO)
                 .eq(DriverInfo::getDeleted, Constants.ZERO)
                 .last("limit 1"));
         if (driver == null || driver.getLatitude() == null || driver.getLongitude() == null) {
@@ -1114,7 +1347,8 @@
 
         // 鑾峰彇鍙告満淇℃伅
         DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
-                .eq(DriverInfo::getMemberId, memberId)
+                .eq(DriverInfo::getId, memberId)
+                .eq(DriverInfo::getVersionType, Constants.ZERO)
                 .eq(DriverInfo::getDeleted, Constants.ZERO)
                 .last("limit 1"));
         if (driver == null) {
@@ -2107,8 +2341,12 @@
         }
         try {
             int lastIndex = token.lastIndexOf("_") + 1;
-            Integer memberId = Integer.valueOf(token.substring(lastIndex));
-            Member member = memberMapper.selectById(memberId);
+            Integer driverId = Integer.valueOf(token.substring(lastIndex));
+            DriverInfo driverInfo = driverInfoMapper.selectById(driverId);
+            if(Objects.isNull(driverInfo)){
+                return false;
+            }
+            Member member = memberMapper.selectById(driverInfo.getMemberId());
             return member != null
                     && !Constants.ONE.equals(member.getDeleted())
                     && !Constants.ONE.equals(member.getStatus())
@@ -2126,4 +2364,42 @@
         driverInfoMapper.updateById(update);
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int initChangeVersions() {
+        Date now = new Date();
+        // 1. 琛ュ叏 version_type 涓� NULL 鐨勮褰�
+        driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
+                .set(DriverInfo::getVersionType, Constants.ZERO)
+                .isNull(DriverInfo::getVersionType));
+
+        // 2. 鏌ヨ鎵�鏈夊凡鏈夊彉鏇寸増鏈殑 relationDriverId
+        List<DriverInfo> changeVersions = driverInfoMapper.selectList(new QueryWrapper<DriverInfo>().lambda()
+                .eq(DriverInfo::getVersionType, Constants.ONE)
+                .eq(DriverInfo::getDeleted, Constants.ZERO)
+                .ne(DriverInfo::getAuditStatus,99)
+                .select(DriverInfo::getRelationDriverId)
+                .isNotNull(DriverInfo::getRelationDriverId));
+        Set<Integer> existingRelationIds = changeVersions.stream()
+                .map(DriverInfo::getRelationDriverId)
+                .collect(Collectors.toSet());
+
+        // 3. 鏌ヨ鎵�鏈夋病鏈夊彉鏇寸増鏈殑姝e紡鐗堟湰鍙告満
+        QueryWrapper<DriverInfo> qw = new QueryWrapper<>();
+        qw.lambda()
+                .eq(DriverInfo::getVersionType, Constants.ZERO)
+                .eq(DriverInfo::getDeleted, Constants.ZERO);
+        List<DriverInfo> officialList = driverInfoMapper.selectList(qw);
+
+        int count = 0;
+        for (DriverInfo official : officialList) {
+            if (existingRelationIds.contains(official.getId())) {
+                continue;
+            }
+            createDriverChangeVersion(official, official.getId(), now);
+            count++;
+        }
+        return count;
+    }
+
 }
diff --git a/server/services/src/main/java/com/doumee/service/business/impl/MemberCouponServiceImpl.java b/server/services/src/main/java/com/doumee/service/business/impl/MemberCouponServiceImpl.java
new file mode 100644
index 0000000..a32d68b
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/service/business/impl/MemberCouponServiceImpl.java
@@ -0,0 +1,149 @@
+package com.doumee.service.business.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.doumee.core.constants.Constants;
+import com.doumee.core.constants.ResponseStatus;
+import com.doumee.core.exception.BusinessException;
+import com.doumee.core.model.LoginUserInfo;
+import com.doumee.core.model.PageData;
+import com.doumee.core.model.PageWrap;
+import com.doumee.core.utils.Utils;
+import com.doumee.dao.business.MemberCouponMapper;
+import com.doumee.dao.business.model.MemberCoupon;
+import com.doumee.dao.system.model.SystemUser;
+import com.doumee.service.business.MemberCouponService;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import org.apache.shiro.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+
+@Service
+public class MemberCouponServiceImpl implements MemberCouponService {
+
+    @Autowired
+    private MemberCouponMapper memberCouponMapper;
+
+    @Override
+    @Transactional(rollbackFor = {Exception.class, BusinessException.class})
+    public Integer create(MemberCoupon memberCoupon) {
+        if (Objects.isNull(memberCoupon) || Objects.isNull(memberCoupon.getCouponId()) || Objects.isNull(memberCoupon.getMemberId())) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST);
+        }
+        LoginUserInfo loginUserInfo = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
+        memberCoupon.setIsdeleted(Constants.ZERO);
+        memberCoupon.setCreateDate(new Date());
+        memberCoupon.setCreator(loginUserInfo.getId());
+        memberCoupon.setEditDate(new Date());
+        memberCoupon.setEditor(loginUserInfo.getId());
+        memberCouponMapper.insert(memberCoupon);
+        return memberCoupon.getId();
+    }
+
+    @Override
+    public void deleteById(Integer id) {
+        memberCouponMapper.update(new UpdateWrapper<MemberCoupon>().lambda()
+                .set(MemberCoupon::getIsdeleted, Constants.ONE)
+                .eq(MemberCoupon::getId, id));
+    }
+
+    @Override
+    public void deleteByIdInBatch(List<Integer> ids) {
+        if (CollectionUtils.isEmpty(ids)) {
+            return;
+        }
+        for (Integer id : ids) {
+            this.deleteById(id);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = {Exception.class, BusinessException.class})
+    public void updateById(MemberCoupon memberCoupon) {
+        if (Objects.isNull(memberCoupon) || Objects.isNull(memberCoupon.getId())) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST);
+        }
+        LoginUserInfo loginUserInfo = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
+        memberCoupon.setEditDate(new Date());
+        memberCoupon.setEditor(loginUserInfo.getId());
+        memberCouponMapper.updateById(memberCoupon);
+    }
+
+    @Override
+    public MemberCoupon findById(Integer id) {
+        MemberCoupon memberCoupon = memberCouponMapper.selectById(id);
+        if (Objects.isNull(memberCoupon)) {
+            throw new BusinessException(ResponseStatus.DATA_EMPTY);
+        }
+        return memberCoupon;
+    }
+
+    @Override
+    public List<MemberCoupon> findList(MemberCoupon memberCoupon) {
+        QueryWrapper<MemberCoupon> wrapper = new QueryWrapper<>(memberCoupon);
+        return memberCouponMapper.selectList(wrapper);
+    }
+
+    @Override
+    public PageData<MemberCoupon> findPage(PageWrap<MemberCoupon> pageWrap) {
+        IPage<MemberCoupon> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
+        MPJLambdaWrapper<MemberCoupon> queryWrapper = new MPJLambdaWrapper<>();
+        Utils.MP.blankToNull(pageWrap.getModel());
+        pageWrap.getModel().setIsdeleted(Constants.ZERO);
+        queryWrapper.selectAll(MemberCoupon.class)
+                .select("m.NAME AS MEMBER_NAME")
+                .select("m.TELEPHONE AS MEMBER_TELEPHONE")
+                .select("m.NICK_NAME AS MEMBER_NICK_NAME")
+                .leftJoin("member m ON m.ID = t.MEMBER_ID");
+        if (pageWrap.getModel().getId() != null) {
+            queryWrapper.eq(MemberCoupon::getId, pageWrap.getModel().getId());
+        }
+        if (pageWrap.getModel().getIsdeleted() != null) {
+            queryWrapper.eq(MemberCoupon::getIsdeleted, pageWrap.getModel().getIsdeleted());
+        }
+        if (pageWrap.getModel().getStatus() != null) {
+            queryWrapper.eq(MemberCoupon::getStatus, pageWrap.getModel().getStatus());
+        }
+        if (pageWrap.getModel().getCouponId() != null) {
+            queryWrapper.eq(MemberCoupon::getCouponId, pageWrap.getModel().getCouponId());
+        }
+        if (pageWrap.getModel().getMemberId() != null) {
+            queryWrapper.eq(MemberCoupon::getMemberId, pageWrap.getModel().getMemberId());
+        }
+        if (pageWrap.getModel().getOrderId() != null) {
+            queryWrapper.eq(MemberCoupon::getOrderId, pageWrap.getModel().getOrderId());
+        }
+        if (pageWrap.getModel().getType() != null) {
+            queryWrapper.eq(MemberCoupon::getType, pageWrap.getModel().getType());
+        }
+        if (pageWrap.getModel().getCouponType() != null) {
+            queryWrapper.eq(MemberCoupon::getCouponType, pageWrap.getModel().getCouponType());
+        }
+        if (pageWrap.getModel().getGetMethod() != null) {
+            queryWrapper.eq(MemberCoupon::getGetMethod, pageWrap.getModel().getGetMethod());
+        }
+        if (pageWrap.getModel().getName() != null) {
+            queryWrapper.like(MemberCoupon::getName, pageWrap.getModel().getName());
+        }
+        if (pageWrap.getModel().getCreateDate() != null) {
+            queryWrapper.ge(MemberCoupon::getCreateDate, Utils.Date.getStart(pageWrap.getModel().getCreateDate()));
+            queryWrapper.le(MemberCoupon::getCreateDate, Utils.Date.getEnd(pageWrap.getModel().getCreateDate()));
+        }
+        queryWrapper.orderByDesc(MemberCoupon::getId);
+        return PageData.from(memberCouponMapper.selectJoinPage(page, MemberCoupon.class, queryWrapper));
+    }
+
+    @Override
+    public long count(MemberCoupon memberCoupon) {
+        QueryWrapper<MemberCoupon> wrapper = new QueryWrapper<>(memberCoupon);
+        return memberCouponMapper.selectCount(wrapper);
+    }
+}
diff --git a/server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java b/server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java
index 13217de..7cba5c5 100644
--- a/server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java
+++ b/server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java
@@ -802,6 +802,7 @@
         orders.setDeleted(Constants.ZERO);
         orders.setCreateTime(now);
         orders.setUpdateTime(now);
+        orders.setIsConverted(Constants.ZERO);
 
         // 瀵勪欢淇℃伅
         orders.setDepositShopId(dto.getDepositShopId());
@@ -1216,7 +1217,6 @@
         com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<Orders> updateWrapper =
                 new UpdateWrapper<Orders>().lambda()
                 .eq(Orders::getId, order.getId())
-                .set(Orders::getIsUrgent, Constants.ONE)
                 .set(Orders::getPlatformRewardAmount, urgentFeeFen)
                 .set(Orders::getPlatformSmsNotified, Constants.ZERO) // 閲嶇疆閫氱煡鐘舵�佷负鏈�氱煡
                 .set(Orders::getPlatformSmsNotifiedTime, new Date()) // 閲嶇疆閫氱煡鍩哄噯鏃堕棿涓哄綋鍓�
@@ -1237,7 +1237,8 @@
         if (dto.getDriverId() != null) {
             // 鏍¢獙鍙告満淇℃伅
             DriverInfo driverInfo = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
-                    .eq(DriverInfo::getMemberId, dto.getDriverId())
+                    .eq(DriverInfo::getId, dto.getDriverId())
+                    .eq(DriverInfo::getVersionType, Constants.ZERO)
                     .eq(DriverInfo::getDeleted, Constants.ZERO)
                     .last("limit 1"));
             if (driverInfo == null) {
@@ -1258,13 +1259,10 @@
             updateWrapper.set(Orders::getAcceptType, 1); // 1=绯荤粺娲惧崟
             updateWrapper.set(Orders::getStatus, Constants.OrderStatus.accepted.getStatus());
 
-            Member driver = memberMapper.selectById(dto.getDriverId());
-            String driverName = driver != null ? driver.getName() : String.valueOf(dto.getDriverId());
-
             OrderLog driverLog = new OrderLog();
             driverLog.setOrderId(order.getId());
             driverLog.setTitle(Constants.OrderLogType.assignDriver.getTitle());
-            driverLog.setLogInfo(Constants.OrderLogType.assignDriver.format(driverName, dto.getUrgentFee().toPlainString()));
+            driverLog.setLogInfo(Constants.OrderLogType.assignDriver.format(driverInfo.getName(), dto.getUrgentFee().toPlainString()));
             driverLog.setObjType(Constants.OrderLogType.assignDriver.getStatus());
             driverLog.setOrderStatus(Constants.OrderStatus.accepted.getStatus());
             driverLog.setOptUserType(3);
@@ -2128,6 +2126,7 @@
             updateWrapper.lambda()
                     .eq(Orders::getId, order.getId())
                     .set(Orders::getType, Constants.ZERO)
+                    .set(Orders::getIsConverted, Constants.ONE)
                     .set(Orders::getTakeShopId, order.getDepositShopId())
                     .set(Orders::getTakeShopName, order.getDepositShopName())
                     .set(Orders::getTakeShopAddress, order.getDepositShopAddress())
@@ -3542,6 +3541,7 @@
                 new QueryWrapper<OrdersDetail>().lambda()
                         .eq(OrdersDetail::getOrderId, orderId)
                         .eq(OrdersDetail::getDeleted, Constants.ZERO));
+
         OverdueFeeVO overdueInfo = calculateOverdueFeeInternal(order, details);
 
         Date now = new Date();
@@ -3570,17 +3570,26 @@
                 int actualDays = calcActualDepositDays(now, order.getDepositTime());
                 order.setDepositDays(actualDays);
 
-                int estimatedDays = order.getEstimatedDepositDays() != null ? order.getEstimatedDepositDays() : 1;
-                int refundDays = estimatedDays - actualDays;
-                if (refundDays > 0) {
-                    // 閫�娆鹃噾棰� = 閫�娆惧ぉ鏁� 脳 危(鐗╁搧鍗曚环 脳 鏁伴噺)
-                    long dailyBaseFee = 0L;
-                    for (OrdersDetail d : details) {
-                        dailyBaseFee += (d.getUnitPrice() != null ? d.getUnitPrice() : 0L)
-                                * (d.getNum() != null ? d.getNum() : 0);
+                long dailyBaseFee = 0L;
+                for (OrdersDetail d : details) {
+                    dailyBaseFee += (d.getLocallyPrice() != null ? d.getLocallyPrice() : 0L)
+                            * (d.getNum() != null ? d.getNum() : 0);
+                }
+
+                if (Constants.equalsInteger(order.getIsConverted(), Constants.ONE)) {
+                    // 杞崲璁㈠崟锛氬疄闄呰垂鐢ㄤ笌宸蹭粯閲戦瀵规瘮
+                    long actualFee = (long) actualDays * dailyBaseFee;
+                    long payAmount = order.getPayAmount() != null ? order.getPayAmount() : 0L;
+                    if (actualFee < payAmount) {
+                        order.setRefundAmount(payAmount - actualFee);
                     }
-                    long refundAmount = (long) refundDays * dailyBaseFee;
-                    order.setRefundAmount(refundAmount);
+                } else {
+                    // 鏅�氳鍗曪細鎸夐璁″ぉ鏁颁笌瀹為檯澶╂暟宸绠楅��娆�
+                    int estimatedDays = order.getEstimatedDepositDays() != null ? order.getEstimatedDepositDays() : 1;
+                    int refundDays = estimatedDays - actualDays;
+                    if (refundDays > 0) {
+                        order.setRefundAmount((long) refundDays * dailyBaseFee);
+                    }
                 }
             }
 
@@ -3769,6 +3778,31 @@
 
         if (Constants.equalsInteger(order.getType(), Constants.ZERO)) {
             // ========== 灏卞湴瀵勫瓨 ==========
+
+            // 杞崲璁㈠崟锛堝紓鍦拌浆灏卞湴锛夛細鎸夊瘎瀛樻椂闂村埌褰撳墠鏃堕棿璁$畻瀹為檯璐圭敤
+            if (Constants.equalsInteger(order.getIsConverted(), Constants.ONE)) {
+                int actualDays = calcActualDepositDays(now, order.getDepositTime());
+                long actualFee = (long) actualDays * dailyBaseFee;
+                long payAmount = order.getPayAmount() != null ? order.getPayAmount() : 0L;
+
+                OverdueFeeVO vo = new OverdueFeeVO();
+                vo.setDailyBaseFee(dailyBaseFee);
+                if (actualFee <= payAmount) {
+                    // 瀹為檯璐圭敤 <= 宸蹭粯閲戦锛氭湭閫炬湡
+                    vo.setOverdue(false);
+                    vo.setOverdueDays(0);
+                    vo.setOverdueFee(0L);
+                } else {
+                    // 瀹為檯璐圭敤 > 宸蹭粯閲戦锛氶�炬湡锛屽樊浠蜂负閫炬湡璐圭敤
+                    int overDays = actualDays - (order.getEstimatedDepositDays() != null ? order.getEstimatedDepositDays() : 1);
+                    vo.setOverdue(true);
+                    vo.setOverdueDays(Math.max(overDays, 1));
+                    vo.setOverdueFee(actualFee - payAmount);
+                }
+                return vo;
+            }
+
+            // 鏅�氬氨鍦板瘎瀛�
             overdueDays = calcLocalOverdueDays(now, order.getExpectedTakeTime());
             overdueFee = (long) overdueDays * dailyBaseFee;
 
diff --git a/server/services/src/main/java/com/doumee/service/business/impl/ShopInfoServiceImpl.java b/server/services/src/main/java/com/doumee/service/business/impl/ShopInfoServiceImpl.java
index 149dd06..6e9b44d 100644
--- a/server/services/src/main/java/com/doumee/service/business/impl/ShopInfoServiceImpl.java
+++ b/server/services/src/main/java/com/doumee/service/business/impl/ShopInfoServiceImpl.java
@@ -194,6 +194,9 @@
         if (pageWrap.getModel().getUpdateUser() != null) {
             queryWrapper.lambda().eq(ShopInfo::getUpdateUser, pageWrap.getModel().getUpdateUser());
         }
+        if (pageWrap.getModel().getVersionType() != null) {
+            queryWrapper.lambda().eq(ShopInfo::getVersionType, pageWrap.getModel().getVersionType());
+        }
         if (pageWrap.getModel().getUpdateTime() != null) {
             queryWrapper.lambda().ge(ShopInfo::getUpdateTime, Utils.Date.getStart(pageWrap.getModel().getUpdateTime()));
             queryWrapper.lambda().le(ShopInfo::getUpdateTime, Utils.Date.getEnd(pageWrap.getModel().getUpdateTime()));
@@ -307,9 +310,6 @@
             // 鏈�鏂板彉鏇寸増鏈凡鏀粯鎶奸噾(status=3)锛氱敓鎴愭柊鐨勫彉鏇寸増鏈�
             Integer relationShopId = changeVersion.getRelationShopId();
 
-            // 鏍¢獙鎵嬫満鍙峰敮涓�鎬э紙鎺掗櫎姝e紡鐗堟湰鍜屽彉鏇寸増鏈級
-            checkTelephoneUnique(request.getTelephone(), relationShopId);
-
             String rawPassword = generateDefaultPassword(request.getTelephone());
             String salt = RandomStringUtils.randomAlphabetic(6);
             String encryptedPassword = Utils.Secure.encryptPassword(rawPassword, salt);
@@ -331,11 +331,6 @@
             saveShopAttachments(newChange.getId(), request, now);
         } else {
             // 鏈�鏂板彉鏇寸増鏈� status=0(寰呭鎵�) 鎴� 2(琚┏鍥�)锛氱洿鎺ユ洿鏂�
-            Integer relationShopId = changeVersion.getRelationShopId();
-
-            // 鏍¢獙鎵嬫満鍙峰敮涓�鎬�
-            checkTelephoneUnique(request.getTelephone(), relationShopId);
-
             String rawPassword = generateDefaultPassword(request.getTelephone());
             String salt = RandomStringUtils.randomAlphabetic(6);
             String encryptedPassword = Utils.Secure.encryptPassword(rawPassword, salt);
@@ -802,12 +797,18 @@
         changeShop.setAliName(origin.getAliName());
         changeShop.setDepositAmount(origin.getDepositAmount());
         changeShop.setRevenueShareConfig(origin.getRevenueShareConfig());
+        changeShop.setDeliveryArea(origin.getDeliveryArea());
+        changeShop.setScore(origin.getScore());
+        changeShop.setBalance(origin.getBalance());
+        changeShop.setTotalBalance(origin.getTotalBalance());
+        changeShop.setPayStatus(origin.getPayStatus());
         changeShop.setVersionType(Constants.ONE);
         changeShop.setRelationShopId(originShopId);
+        changeShop.setAuditStatus(origin.getAuditStatus());
         changeShop.setRegionMemberId(origin.getRegionMemberId());
         changeShop.setOpenid(origin.getOpenid());
-        changeShop.setStatus(Constants.ZERO);
-        changeShop.setDeleted(Constants.ZERO);
+        changeShop.setStatus(origin.getStatus());
+        changeShop.setDeleted(origin.getDeleted());
         changeShop.setCreateTime(now);
         changeShop.setUpdateTime(now);
         shopInfoMapper.insert(changeShop);
@@ -1582,7 +1583,7 @@
         if (shopInfo.getCompanyType() == null) {
             return;
         }
-        Areas areas = areasService.findById(shopInfo.getAreaId());
+        Areas areas = areasService.getById(shopInfo.getAreaId());
         PricingRule pricingRule = pricingRuleMapper.selectOne(new QueryWrapper<PricingRule>().lambda()
                 .eq(PricingRule::getDeleted, Constants.ZERO)
                 .eq(PricingRule::getType, Constants.THREE)
@@ -1726,4 +1727,41 @@
         log.info("瑙g粦鎴愬姛锛歿}", sn);
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int initChangeVersions() {
+        Date now = new Date();
+        // 1. 琛ュ叏 version_type 涓� NULL 鐨勮褰�
+        shopInfoMapper.update(new UpdateWrapper<ShopInfo>().lambda()
+                .set(ShopInfo::getVersionType, Constants.ZERO)
+                .isNull(ShopInfo::getVersionType));
+
+        // 2. 鏌ヨ鎵�鏈夊凡鏈夊彉鏇寸増鏈殑 relationShopId
+        List<ShopInfo> changeVersions = shopInfoMapper.selectList(new QueryWrapper<ShopInfo>().lambda()
+                .eq(ShopInfo::getVersionType, Constants.ONE)
+                .eq(ShopInfo::getDeleted, Constants.ZERO)
+                .select(ShopInfo::getRelationShopId)
+                .isNotNull(ShopInfo::getRelationShopId));
+        Set<Integer> existingRelationIds = changeVersions.stream()
+                .map(ShopInfo::getRelationShopId)
+                .collect(Collectors.toSet());
+
+        // 3. 鏌ヨ鎵�鏈夋病鏈夊彉鏇寸増鏈殑姝e紡鐗堟湰闂ㄥ簵
+        QueryWrapper<ShopInfo> qw = new QueryWrapper<>();
+        qw.lambda()
+                .eq(ShopInfo::getVersionType, Constants.ZERO)
+                .eq(ShopInfo::getDeleted, Constants.ZERO);
+        List<ShopInfo> officialList = shopInfoMapper.selectList(qw);
+
+        int count = 0;
+        for (ShopInfo official : officialList) {
+            if (existingRelationIds.contains(official.getId())) {
+                continue;
+            }
+            createChangeVersion(official, official.getId(), now);
+            count++;
+        }
+        return count;
+    }
+
 }
diff --git a/server/web/src/main/java/com/doumee/api/web/ConfigApi.java b/server/web/src/main/java/com/doumee/api/web/ConfigApi.java
index 17d2ddd..28485bf 100644
--- a/server/web/src/main/java/com/doumee/api/web/ConfigApi.java
+++ b/server/web/src/main/java/com/doumee/api/web/ConfigApi.java
@@ -77,6 +77,20 @@
     @Autowired
     private SystemDictDataBiz systemDictDataBiz;
 
+    @Autowired
+    private ShopInfoService shopInfoService;
+
+    @Autowired
+    private DriverInfoService driverInfoService;
+
+    @ApiOperation("鍒濆鍖栧巻鍙查棬搴�/鍙告満鍙樻洿鐗堟湰鏁版嵁")
+    @PostMapping("/initChangeVersions")
+    public ApiResponse<String> initChangeVersions() {
+        int shopCount = shopInfoService.initChangeVersions();
+        int driverCount = driverInfoService.initChangeVersions();
+        return ApiResponse.success("闂ㄥ簵鍒濆鍖� " + shopCount + " 鏉★紝鍙告満鍒濆鍖� " + driverCount + " 鏉�");
+    }
+
     @ApiOperation("鍏ㄩ儴鍖哄垝鏍戝舰鏌ヨ")
     @PostMapping("/treeList")
     public ApiResponse<List<Areas>> treeList (@RequestBody AreasDto pageWrap) {

--
Gitblit v1.9.3