skyline 3 tháng trước cách đây
mục cha
commit
de25e04cfc
43 tập tin đã thay đổi với 2137 bổ sung1203 xóa
  1. 1 32
      haha-admin/pom.xml
  2. 93 2
      haha-admin/src/main/java/com/haha/admin/config/GlobalExceptionHandler.java
  3. 33 243
      haha-admin/src/main/java/com/haha/admin/controller/DeviceController.java
  4. 30 224
      haha-admin/src/main/java/com/haha/admin/controller/OrderController.java
  5. 33 214
      haha-admin/src/main/java/com/haha/admin/controller/ProductController.java
  6. 127 263
      haha-admin/src/main/java/com/haha/admin/controller/ShopController.java
  7. 32 0
      haha-admin/src/main/java/com/haha/admin/dto/DeviceQueryDTO.java
  8. 42 0
      haha-admin/src/main/java/com/haha/admin/dto/OrderQueryDTO.java
  9. 42 0
      haha-admin/src/main/java/com/haha/admin/dto/PageQueryDTO.java
  10. 32 0
      haha-admin/src/main/java/com/haha/admin/dto/ProductQueryDTO.java
  11. 27 0
      haha-admin/src/main/java/com/haha/admin/dto/ShopQueryDTO.java
  12. 13 12
      haha-common/pom.xml
  13. 60 0
      haha-common/src/main/java/com/haha/common/constant/CommonConstants.java
  14. 82 0
      haha-common/src/main/java/com/haha/common/constant/DeviceConstants.java
  15. 78 0
      haha-common/src/main/java/com/haha/common/constant/OrderConstants.java
  16. 46 0
      haha-common/src/main/java/com/haha/common/constant/SyncConstants.java
  17. 74 0
      haha-common/src/main/java/com/haha/common/enums/CommonStatus.java
  18. 126 0
      haha-common/src/main/java/com/haha/common/utils/EntityLabelUtils.java
  19. 91 0
      haha-common/src/main/java/com/haha/common/vo/PageResult.java
  20. 61 0
      haha-common/src/main/java/com/haha/common/vo/StatusLabel.java
  21. 6 7
      haha-entity/pom.xml
  22. 18 9
      haha-entity/src/main/java/com/haha/entity/Order.java
  23. 0 7
      haha-mapper/pom.xml
  24. 19 0
      haha-mapper/src/main/java/com/haha/mapper/OrderMapper.java
  25. 1 26
      haha-miniapp/pom.xml
  26. 93 2
      haha-miniapp/src/main/java/com/haha/miniapp/config/GlobalExceptionHandler.java
  27. 0 16
      haha-sdk/pom.xml
  28. 1 8
      haha-service/pom.xml
  29. 8 0
      haha-service/src/main/java/com/haha/service/AdminService.java
  30. 57 0
      haha-service/src/main/java/com/haha/service/DeviceService.java
  31. 44 0
      haha-service/src/main/java/com/haha/service/OrderService.java
  32. 65 0
      haha-service/src/main/java/com/haha/service/ProductService.java
  33. 24 0
      haha-service/src/main/java/com/haha/service/ShopService.java
  34. 20 5
      haha-service/src/main/java/com/haha/service/impl/AdminServiceImpl.java
  35. 8 13
      haha-service/src/main/java/com/haha/service/impl/DataSyncServiceImpl.java
  36. 174 9
      haha-service/src/main/java/com/haha/service/impl/DeviceServiceImpl.java
  37. 5 4
      haha-service/src/main/java/com/haha/service/impl/NewProductApplyServiceImpl.java
  38. 145 1
      haha-service/src/main/java/com/haha/service/impl/OrderServiceImpl.java
  39. 144 0
      haha-service/src/main/java/com/haha/service/impl/ProductServiceImpl.java
  40. 77 63
      haha-service/src/main/java/com/haha/service/impl/ShopReplenisherServiceImpl.java
  41. 72 37
      haha-service/src/main/java/com/haha/service/impl/ShopServiceImpl.java
  42. 7 6
      haha-service/src/main/java/com/haha/service/impl/StockRecordServiceImpl.java
  43. 26 0
      pom.xml

+ 1 - 32
haha-admin/pom.xml

@@ -11,24 +11,16 @@
         <relativePath>../pom.xml</relativePath>
     </parent>
 
-    <groupId>com.haha</groupId>
     <artifactId>haha-admin</artifactId>
-    <version>0.0.1-SNAPSHOT</version>
     <name>haha-admin</name>
     <description>运营平台后端</description>
 
-
-
     <dependencies>
-        <!-- 内部模块依赖 -->
+        <!-- 依赖Service模块 -->
         <dependency>
             <groupId>com.haha</groupId>
             <artifactId>haha-service</artifactId>
         </dependency>
-        <dependency>
-            <groupId>com.haha</groupId>
-            <artifactId>haha-common</artifactId>
-        </dependency>
 
         <!-- Spring Boot 核心依赖 -->
         <dependency>
@@ -50,17 +42,6 @@
             <groupId>com.mysql</groupId>
             <artifactId>mysql-connector-j</artifactId>
         </dependency>
-        <dependency>
-            <groupId>com.baomidou</groupId>
-            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
-        </dependency>
-
-        <!-- 工具类 -->
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-            <optional>true</optional>
-        </dependency>
 
         <!-- Redis 依赖 -->
         <dependency>
@@ -68,12 +49,6 @@
             <artifactId>spring-boot-starter-data-redis</artifactId>
         </dependency>
 
-        <!-- FastJson -->
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>fastjson</artifactId>
-        </dependency>
-
         <!-- Sa-Token 认证框架 -->
         <dependency>
             <groupId>cn.dev33</groupId>
@@ -86,12 +61,6 @@
             <artifactId>sa-token-redis-jackson</artifactId>
         </dependency>
 
-        <!-- Spring Security Crypto (用于BCrypt密码加密) -->
-        <dependency>
-            <groupId>org.springframework.security</groupId>
-            <artifactId>spring-security-crypto</artifactId>
-        </dependency>
-
         <!-- 提供 Redis 连接池 -->
         <dependency>
             <groupId>org.apache.commons</groupId>

+ 93 - 2
haha-admin/src/main/java/com/haha/admin/config/GlobalExceptionHandler.java

@@ -1,22 +1,46 @@
 package com.haha.admin.config;
 
 import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.exception.NotPermissionException;
+import com.haha.common.exception.BusinessException;
 import com.haha.common.vo.Result;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.BindException;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
 import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
 
+import java.util.stream.Collectors;
+
+/**
+ * 全局异常处理器
+ * 统一处理各类异常,返回规范的响应格式
+ */
 @Slf4j
 @RestControllerAdvice
 public class GlobalExceptionHandler {
 
+    /**
+     * 处理业务异常
+     */
+    @ExceptionHandler(BusinessException.class)
+    public Result<Void> handleBusinessException(BusinessException e) {
+        log.warn("业务异常: code={}, message={}", e.getCode(), e.getMessage());
+        return Result.error(e.getCode(), e.getMessage());
+    }
+
     /**
      * 处理 Sa-Token 未登录异常
      */
     @ExceptionHandler(NotLoginException.class)
+    @ResponseStatus(HttpStatus.UNAUTHORIZED)
     public Result<Void> handleNotLoginException(NotLoginException e) {
         log.warn("未登录异常: {}", e.getMessage());
-        // 根据异常类型返回不同的错误信息
         String message;
         if (e.getType().equals(NotLoginException.NOT_TOKEN)) {
             message = "未提供token";
@@ -30,12 +54,79 @@ public class GlobalExceptionHandler {
         return Result.error(401, message);
     }
 
+    /**
+     * 处理 Sa-Token 无权限异常
+     */
+    @ExceptionHandler(NotPermissionException.class)
+    @ResponseStatus(HttpStatus.FORBIDDEN)
+    public Result<Void> handleNotPermissionException(NotPermissionException e) {
+        log.warn("无权限异常: {}", e.getMessage());
+        return Result.error(403, "无访问权限");
+    }
+
+    /**
+     * 处理参数校验异常(@Valid)
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    public Result<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
+        String message = e.getBindingResult().getFieldErrors().stream()
+                .map(FieldError::getDefaultMessage)
+                .collect(Collectors.joining(", "));
+        log.warn("参数校验失败: {}", message);
+        return Result.error(400, message);
+    }
+
+    /**
+     * 处理参数绑定异常
+     */
+    @ExceptionHandler(BindException.class)
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    public Result<Void> handleBindException(BindException e) {
+        String message = e.getBindingResult().getFieldErrors().stream()
+                .map(FieldError::getDefaultMessage)
+                .collect(Collectors.joining(", "));
+        log.warn("参数绑定失败: {}", message);
+        return Result.error(400, message);
+    }
+
+    /**
+     * 处理缺少必需参数异常
+     */
+    @ExceptionHandler(MissingServletRequestParameterException.class)
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    public Result<Void> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
+        log.warn("缺少必需参数: {}", e.getParameterName());
+        return Result.error(400, "缺少必需参数: " + e.getParameterName());
+    }
+
+    /**
+     * 处理参数类型不匹配异常
+     */
+    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    public Result<Void> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
+        log.warn("参数类型不匹配: {}={}", e.getName(), e.getValue());
+        return Result.error(400, "参数类型错误: " + e.getName());
+    }
+
+    /**
+     * 处理非法参数异常
+     */
+    @ExceptionHandler(IllegalArgumentException.class)
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    public Result<Void> handleIllegalArgumentException(IllegalArgumentException e) {
+        log.warn("非法参数: {}", e.getMessage());
+        return Result.error(400, e.getMessage());
+    }
+
     /**
      * 处理其他所有异常
      */
     @ExceptionHandler(Exception.class)
+    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
     public Result<Void> handleException(Exception e) {
         log.error("系统异常: {}", e.getMessage(), e);
-        return Result.error(500, "系统内部错误");
+        return Result.error(500, "系统繁忙,请稍后重试");
     }
 }

+ 33 - 243
haha-admin/src/main/java/com/haha/admin/controller/DeviceController.java

@@ -1,20 +1,17 @@
 package com.haha.admin.controller;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.haha.admin.dto.DeviceQueryDTO;
 import com.haha.common.annotation.Log;
 import com.haha.common.enums.OperationType;
+import com.haha.common.vo.PageResult;
 import com.haha.common.vo.Result;
 import com.haha.entity.Device;
-import com.haha.entity.Shop;
 import com.haha.service.DeviceService;
-import com.haha.service.ShopService;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -23,80 +20,29 @@ import java.util.Map;
 @Slf4j
 @RestController
 @RequestMapping("/devices")
+@RequiredArgsConstructor
 public class DeviceController {
 
-    @Autowired
-    private DeviceService deviceService;
-
-    @Autowired
-    private ShopService shopService;
+    private final DeviceService deviceService;
 
     /**
      * 分页查询设备列表
-     * @param params 查询参数
+     * @param queryDTO 查询参数
      * @return 设备列表
      */
     @GetMapping("/list")
-    public Result<Map<String, Object>> list(@RequestParam Map<String, Object> params) {
-        try {
-            // 分页参数
-            int page = 1;
-            int pageSize = 10;
-
-            Object pageObj = params.get("page");
-            if (pageObj != null && !pageObj.toString().isEmpty()) {
-                page = Integer.parseInt(pageObj.toString());
-            }
-
-            Object pageSizeObj = params.get("pageSize");
-            if (pageSizeObj != null && !pageSizeObj.toString().isEmpty()) {
-                pageSize = Integer.parseInt(pageSizeObj.toString());
-            }
-
-            // 查询条件
-            String deviceId = (String) params.get("deviceId");
-            String storeName = (String) params.get("storeName");
-            Long shopId = null;
-            Object shopIdObj = params.get("shopId");
-            if (shopIdObj != null && !shopIdObj.toString().isEmpty()) {
-                shopId = Long.valueOf(shopIdObj.toString());
-            }
-            Integer status = null;
-            Object statusObj = params.get("status");
-            if (statusObj != null && !statusObj.toString().isEmpty()) {
-                status = Integer.valueOf(statusObj.toString());
-            }
-
-            // 构建查询条件
-            LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
-            wrapper.like(deviceId != null && !deviceId.isEmpty(), Device::getDeviceId, deviceId)
-                   .eq(shopId != null, Device::getShopId, shopId)
-                   .eq(status != null, Device::getStatus, status);
-            
-            // 按创建时间倒序
-            wrapper.orderByDesc(Device::getCreateTime);
-
-            // 分页查询
-            Page<Device> pageResult = new Page<>(page, pageSize);
-            IPage<Device> devicePage = deviceService.page(pageResult, wrapper);
-
-            // 填充额外字段
-            for (Device device : devicePage.getRecords()) {
-                fillDeviceLabels(device);
-            }
-
-            Map<String, Object> data = new HashMap<>();
-            data.put("list", devicePage.getRecords());
-            data.put("total", devicePage.getTotal());
-            data.put("pageSize", devicePage.getSize());
-            data.put("currentPage", devicePage.getCurrent());
-
-            return Result.success("查询成功", data);
-
-        } catch (Exception e) {
-            log.error("查询设备列表失败: {}", e.getMessage(), e);
-            return Result.error(500, "查询设备列表失败: " + e.getMessage());
-        }
+    public Result<PageResult<Device>> list(DeviceQueryDTO queryDTO) {
+        queryDTO.validate();
+
+        IPage<Device> devicePage = deviceService.getPage(
+                queryDTO.getPage(),
+                queryDTO.getPageSize(),
+                queryDTO.getDeviceId(),
+                queryDTO.getShopId(),
+                queryDTO.getStatus()
+        );
+
+        return Result.success("查询成功", PageResult.of(devicePage));
     }
 
     /**
@@ -106,17 +52,11 @@ public class DeviceController {
      */
     @GetMapping("/{id}")
     public Result<Device> getById(@PathVariable Long id) {
-        try {
-            Device device = deviceService.getById(id);
-            if (device == null) {
-                return Result.error(404, "设备不存在");
-            }
-            fillDeviceLabels(device);
-            return Result.success("查询成功", device);
-        } catch (Exception e) {
-            log.error("查询设备详情失败: deviceId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "查询设备详情失败: " + e.getMessage());
+        Device device = deviceService.getDetailById(id);
+        if (device == null) {
+            return Result.error(404, "设备不存在");
         }
+        return Result.success("查询成功", device);
     }
 
     /**
@@ -125,34 +65,8 @@ public class DeviceController {
      */
     @GetMapping("/statistics")
     public Result<Map<String, Object>> getStatistics() {
-        try {
-            Map<String, Object> statistics = new HashMap<>();
-
-            // 总设备数
-            long total = deviceService.count();
-            statistics.put("total", total);
-
-            // 在线设备数 (status = 1 为正常/在线)
-            long online = deviceService.lambdaQuery()
-                    .eq(Device::getStatus, 1)
-                    .count();
-            statistics.put("online", online);
-
-            // 离线设备数
-            long offline = total - online;
-            statistics.put("offline", offline);
-
-            // TODO: 后续从订单服务获取销售额数据
-            statistics.put("totalSales", "0.00");
-            statistics.put("todaySales", "0.00");
-            statistics.put("avgTemperature", "0.0");
-
-            return Result.success("查询成功", statistics);
-
-        } catch (Exception e) {
-            log.error("查询设备统计失败: {}", e.getMessage(), e);
-            return Result.error(500, "查询设备统计失败: " + e.getMessage());
-        }
+        Map<String, Object> statistics = deviceService.getStatistics();
+        return Result.success("查询成功", statistics);
     }
 
     /**
@@ -164,26 +78,9 @@ public class DeviceController {
     @Log(module = "设备管理", operation = OperationType.OTHER, summary = "远程开门")
     @PostMapping("/{id}/open")
     public Result<Void> openDoor(@PathVariable Long id, @RequestBody Map<String, Object> params) {
-        try {
-            Device device = deviceService.getById(id);
-            if (device == null) {
-                return Result.error(404, "设备不存在");
-            }
-
-            String deviceId = device.getDeviceId();
-            String doorIndex = (String) params.getOrDefault("doorIndex", "A");
-            
-            log.info("远程开门: deviceId={}, doorIndex={}", deviceId, doorIndex);
-            
-            // TODO: 调用SDK发送开门指令
-            // hahaClient.getDeviceApi().openDoor(deviceId, ...);
-            
-            return Result.success("开门指令已发送", null);
-
-        } catch (Exception e) {
-            log.error("远程开门失败: deviceId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "远程开门失败: " + e.getMessage());
-        }
+        String doorIndex = (String) params.getOrDefault("doorIndex", "A");
+        boolean success = deviceService.openDoor(id, doorIndex);
+        return success ? Result.success("开门指令已发送", null) : Result.error(500, "开门失败");
     }
 
     /**
@@ -194,23 +91,9 @@ public class DeviceController {
      */
     @PutMapping("/{id}/temperature")
     public Result<Void> setTemperature(@PathVariable Long id, @RequestBody Map<String, Object> params) {
-        try {
-            Device device = deviceService.getById(id);
-            if (device == null) {
-                return Result.error(404, "设备不存在");
-            }
-
-            Double temperature = Double.valueOf(params.get("temperature").toString());
-            log.info("设置温度: deviceId={}, temperature={}", device.getDeviceId(), temperature);
-            
-            // TODO: 调用SDK设置温度
-            
-            return Result.success("温度设置成功", null);
-
-        } catch (Exception e) {
-            log.error("设置温度失败: deviceId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "设置温度失败: " + e.getMessage());
-        }
+        Double temperature = Double.valueOf(params.get("temperature").toString());
+        boolean success = deviceService.setTemperature(id, temperature);
+        return success ? Result.success("温度设置成功", null) : Result.error(500, "设置失败");
     }
 
     /**
@@ -221,101 +104,8 @@ public class DeviceController {
      */
     @PutMapping("/{id}/volume")
     public Result<Void> setVolume(@PathVariable Long id, @RequestBody Map<String, Object> params) {
-        try {
-            Device device = deviceService.getById(id);
-            if (device == null) {
-                return Result.error(404, "设备不存在");
-            }
-
-            Integer volume = Integer.valueOf(params.get("volume").toString());
-            log.info("设置音量: deviceId={}, volume={}", device.getDeviceId(), volume);
-            
-            // TODO: 调用SDK设置音量
-            
-            return Result.success("音量设置成功", null);
-
-        } catch (Exception e) {
-            log.error("设置音量失败: deviceId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "设置音量失败: " + e.getMessage());
-        }
-    }
-
-    /**
-     * 填充设备标签字段
-     * @param device 设备对象
-     */
-    private void fillDeviceLabels(Device device) {
-        // 设备状态标签
-        if (device.getStatus() != null) {
-            switch (device.getStatus()) {
-                case 1:
-                    device.setStatusLabel("正常");
-                    device.setStatusColor("success");
-                    device.setIsOnline(true);
-                    break;
-                case 2:
-                    device.setStatusLabel("冻结");
-                    device.setStatusColor("warning");
-                    device.setIsOnline(false);
-                    break;
-                case 3:
-                    device.setStatusLabel("离线");
-                    device.setStatusColor("info");
-                    device.setIsOnline(false);
-                    break;
-                case 4:
-                    device.setStatusLabel("维护中");
-                    device.setStatusColor("danger");
-                    device.setIsOnline(false);
-                    break;
-                default:
-                    device.setStatusLabel("未知");
-                    device.setStatusColor("info");
-                    device.setIsOnline(false);
-            }
-        }
-        
-        // 填充门店信息
-        if (device.getShopId() != null && device.getShopName() == null) {
-            Shop shop = shopService.getById(device.getShopId());
-            if (shop != null) {
-                device.setShopName(shop.getName());
-                if (device.getAddress() == null) {
-                    device.setAddress(shop.getAddress());
-                }
-            }
-        }
-        
-        // 默认值
-        if (device.getShopName() == null) {
-            device.setShopName("默认门店");
-        }
-        if (device.getAddress() == null) {
-            device.setAddress("-");
-        }
-        if (device.getDeviceTypeLabel() == null) {
-            device.setDeviceTypeLabel("智能柜");
-        }
-        if (device.getTemperature() == null) {
-            device.setTemperature("0.0");
-        }
-        if (device.getVolume() == null) {
-            device.setVolume(8);
-        }
-        if (device.getDoorCount() == null) {
-            device.setDoorCount(1);
-        }
-        if (device.getLayerCount() == null) {
-            device.setLayerCount(5);
-        }
-        if (device.getTotalSales() == null) {
-            device.setTotalSales("0.00");
-        }
-        if (device.getTodaySales() == null) {
-            device.setTodaySales("0.00");
-        }
-        if (device.getOrderCount() == null) {
-            device.setOrderCount(0);
-        }
+        Integer volume = Integer.valueOf(params.get("volume").toString());
+        boolean success = deviceService.setVolume(id, volume);
+        return success ? Result.success("音量设置成功", null) : Result.error(500, "设置失败");
     }
 }

+ 30 - 224
haha-admin/src/main/java/com/haha/admin/controller/OrderController.java

@@ -1,25 +1,18 @@
 package com.haha.admin.controller;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.haha.admin.dto.OrderQueryDTO;
 import com.haha.common.annotation.Log;
 import com.haha.common.enums.OperationType;
+import com.haha.common.vo.PageResult;
 import com.haha.common.vo.Result;
 import com.haha.entity.Order;
 import com.haha.service.OrderService;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.CacheControl;
-import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.util.HashMap;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 
 /**
  * 订单管理控制器
@@ -27,86 +20,32 @@ import java.util.concurrent.TimeUnit;
 @Slf4j
 @RestController
 @RequestMapping("/order")
+@RequiredArgsConstructor
 public class OrderController {
 
-    @Autowired
-    private OrderService orderService;
+    private final OrderService orderService;
 
     /**
      * 分页查询订单列表
-     * @param params 查询参数
+     * @param queryDTO 查询参数
      * @return 订单列表
      */
     @GetMapping("/list")
-    public Result<Map<String, Object>> list(@RequestParam Map<String, Object> params) {
-        try {
-            // 分页参数(处理空字符串)
-            int page = 1;
-            int pageSize = 10;
-
-            Object pageObj = params.get("page");
-            if (pageObj != null && !pageObj.toString().isEmpty()) {
-                page = Integer.parseInt(pageObj.toString());
-            }
-
-            Object pageSizeObj = params.get("pageSize");
-            if (pageSizeObj != null && !pageSizeObj.toString().isEmpty()) {
-                pageSize = Integer.parseInt(pageSizeObj.toString());
-            }
-
-            // 查询条件
-            String orderNo = (String) params.get("orderNo");
-            String deviceId = (String) params.get("deviceId");
-            String payStatus = (String) params.get("payStatus");
-            Integer status = null;
-            Object statusObj = params.get("status");
-            if (statusObj != null && !statusObj.toString().isEmpty()) {
-                status = Integer.valueOf(statusObj.toString());
-            }
-            String startDate = (String) params.get("startDate");
-            String endDate = (String) params.get("endDate");
-
-            // 构建查询条件
-            LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
-            wrapper.like(orderNo != null && !orderNo.isEmpty(), Order::getOrderNo, orderNo)
-                   .like(deviceId != null && !deviceId.isEmpty(), Order::getDeviceId, deviceId)
-                   .eq(payStatus != null && !payStatus.isEmpty(), Order::getPayStatus, payStatus)
-                   .eq(status != null, Order::getStatus, status);
-
-            // 时间范围查询
-            if (startDate != null && !startDate.isEmpty()) {
-                LocalDateTime startDateTime = LocalDate.parse(startDate).atStartOfDay();
-                wrapper.ge(Order::getCreateTime, startDateTime);
-            }
-            if (endDate != null && !endDate.isEmpty()) {
-                LocalDateTime endDateTime = LocalDate.parse(endDate).atTime(LocalTime.MAX);
-                wrapper.le(Order::getCreateTime, endDateTime);
-            }
-
-            // 按创建时间倒序
-            wrapper.orderByDesc(Order::getCreateTime);
-
-            // 分页查询
-            Page<Order> pageResult = new Page<>(page, pageSize);
-            IPage<Order> orderPage = orderService.page(pageResult, wrapper);
-
-            // 填充标签字段
-            for (Order order : orderPage.getRecords()) {
-                fillOrderLabels(order);
-            }
-
-            Map<String, Object> data = new HashMap<>();
-            data.put("list", orderPage.getRecords());
-            data.put("total", orderPage.getTotal());
-            data.put("pageSize", orderPage.getSize());
-            data.put("currentPage", orderPage.getCurrent());
-
-            return Result.success("查询成功", data);
-
-        } catch (Exception e) {
-            log.error("查询订单列表失败: {}", e.getMessage(), e);
-            return Result.error(500, "查询订单列表失败: " + e.getMessage());
-        }
+    public Result<PageResult<Order>> list(OrderQueryDTO queryDTO) {
+        queryDTO.validate();
+        
+        IPage<Order> orderPage = orderService.getPage(
+                queryDTO.getPage(), 
+                queryDTO.getPageSize(),
+                queryDTO.getOrderNo(),
+                queryDTO.getDeviceId(),
+                queryDTO.getPayStatus(),
+                queryDTO.getStatus(),
+                queryDTO.getStartDate(),
+                queryDTO.getEndDate()
+        );
+
+        return Result.success("查询成功", PageResult.of(orderPage));
     }
 
     /**
@@ -116,17 +55,11 @@ public class OrderController {
      */
     @GetMapping("/{id}")
     public Result<Order> getById(@PathVariable Long id) {
-        try {
-            Order order = orderService.getById(id);
-            if (order == null) {
-                return Result.error(404, "订单不存在");
-            }
-            fillOrderLabels(order);
-            return Result.success("查询成功", order);
-        } catch (Exception e) {
-            log.error("查询订单详情失败: orderId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "查询订单详情失败: " + e.getMessage());
+        Order order = orderService.getDetailById(id);
+        if (order == null) {
+            return Result.error(404, "订单不存在");
         }
+        return Result.success("查询成功", order);
     }
 
     /**
@@ -135,72 +68,8 @@ public class OrderController {
      */
     @GetMapping("/statistics")
     public Result<Map<String, Object>> getStatistics() {
-        try {
-            Map<String, Object> statistics = new HashMap<>();
-
-            // 总订单数
-            long totalOrders = orderService.count();
-            statistics.put("totalOrders", totalOrders);
-
-            // 今日订单数
-            LocalDateTime todayStart = LocalDate.now().atStartOfDay();
-            long todayOrders = orderService.lambdaQuery()
-                    .ge(Order::getCreateTime, todayStart)
-                    .count();
-            statistics.put("todayOrders", todayOrders);
-
-            // 各状态订单数
-            long unpaidOrders = orderService.lambdaQuery()
-                    .eq(Order::getPayStatus, Order.PAY_STATUS_未支付)
-                    .count();
-            statistics.put("unpaidOrders", unpaidOrders);
-
-            long completedOrders = orderService.lambdaQuery()
-                    .eq(Order::getStatus, Order.ORDER_STATUS_已完成)
-                    .count();
-            statistics.put("completedOrders", completedOrders);
-
-            long cancelledOrders = orderService.lambdaQuery()
-                    .eq(Order::getStatus, Order.ORDER_STATUS_已取消)
-                    .count();
-            statistics.put("cancelledOrders", cancelledOrders);
-
-            long refundOrders = orderService.lambdaQuery()
-                    .eq(Order::getPayStatus, Order.PAY_STATUS_已退款)
-                    .count();
-            statistics.put("refundOrders", refundOrders);
-
-            // 总销售额(已完成订单)
-            Double totalAmount = orderService.lambdaQuery()
-                    .eq(Order::getStatus, Order.ORDER_STATUS_已完成)
-                    .eq(Order::getPayStatus, Order.PAY_STATUS_已支付)
-                    .list()
-                    .stream()
-                    .mapToDouble(Order::getTotalAmount)
-                    .sum();
-            statistics.put("totalAmount", String.format("%.2f", totalAmount));
-
-            // 今日销售额
-            Double todayAmount = orderService.lambdaQuery()
-                    .ge(Order::getCreateTime, todayStart)
-                    .eq(Order::getStatus, Order.ORDER_STATUS_已完成)
-                    .eq(Order::getPayStatus, Order.PAY_STATUS_已支付)
-                    .list()
-                    .stream()
-                    .mapToDouble(Order::getTotalAmount)
-                    .sum();
-            statistics.put("todayAmount", String.format("%.2f", todayAmount));
-
-            // 平均订单金额
-            double averageAmount = completedOrders > 0 ? totalAmount / completedOrders : 0;
-            statistics.put("averageAmount", String.format("%.2f", averageAmount));
-
-            return Result.success("查询成功", statistics);
-
-        } catch (Exception e) {
-            log.error("查询订单统计失败: {}", e.getMessage(), e);
-            return Result.error(500, "查询订单统计失败: " + e.getMessage());
-        }
+        Map<String, Object> statistics = orderService.getStatistics();
+        return Result.success("查询成功", statistics);
     }
 
     /**
@@ -212,71 +81,8 @@ public class OrderController {
     @Log(module = "订单管理", operation = OperationType.UPDATE, summary = "订单退款")
     @PostMapping("/{id}/refund")
     public Result<Void> refund(@PathVariable Long id, @RequestBody Map<String, Object> params) {
-        try {
-            Order order = orderService.getById(id);
-            if (order == null) {
-                return Result.error(404, "订单不存在");
-            }
-
-            // 检查订单状态
-            if (!Order.PAY_STATUS_已支付.equals(order.getPayStatus())) {
-                return Result.error(400, "只有已支付的订单才能退款");
-            }
-
-            String reason = (String) params.get("reason");
-            log.info("订单退款: orderId={}, orderNo={}, reason={}", id, order.getOrderNo(), reason);
-
-            // 更新支付状态为已退款
-            boolean success = orderService.updatePayStatus(order.getOrderNo(), Order.PAY_STATUS_已退款);
-
-            if (success) {
-                return Result.success("退款成功", null);
-            } else {
-                return Result.error(500, "退款失败");
-            }
-
-        } catch (Exception e) {
-            log.error("订单退款失败: orderId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "退款失败: " + e.getMessage());
-        }
-    }
-
-    /**
-     * 填充订单标签字段
-     * @param order 订单对象
-     */
-    private void fillOrderLabels(Order order) {
-        // 填充支付状态标签
-        switch (order.getPayStatus()) {
-            case Order.PAY_STATUS_未支付:
-                order.setPayStatusLabel("未支付");
-                break;
-            case Order.PAY_STATUS_已支付:
-                order.setPayStatusLabel("已支付");
-                break;
-            case Order.PAY_STATUS_已退款:
-                order.setPayStatusLabel("已退款");
-                break;
-            default:
-                order.setPayStatusLabel("未知");
-        }
-
-        // 填充订单状态标签
-        switch (order.getStatus()) {
-            case Order.ORDER_STATUS_已取消:
-                order.setStatusLabel("已取消");
-                break;
-            case Order.ORDER_STATUS_待支付:
-                order.setStatusLabel("待支付");
-                break;
-            case Order.ORDER_STATUS_已完成:
-                order.setStatusLabel("已完成");
-                break;
-            case Order.ORDER_STATUS_已关闭:
-                order.setStatusLabel("已关闭");
-                break;
-            default:
-                order.setStatusLabel("未知");
-        }
+        String reason = (String) params.get("reason");
+        boolean success = orderService.refund(id, reason);
+        return success ? Result.success("退款成功", null) : Result.error(500, "退款失败");
     }
 }

+ 33 - 214
haha-admin/src/main/java/com/haha/admin/controller/ProductController.java

@@ -1,19 +1,17 @@
 package com.haha.admin.controller;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.haha.admin.dto.ProductQueryDTO;
 import com.haha.common.annotation.Log;
 import com.haha.common.enums.OperationType;
+import com.haha.common.vo.PageResult;
 import com.haha.common.vo.Result;
 import com.haha.entity.Product;
 import com.haha.service.ProductService;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
-import java.time.LocalDateTime;
-import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -22,75 +20,30 @@ import java.util.Map;
 @Slf4j
 @RestController
 @RequestMapping("/products")
+@RequiredArgsConstructor
 public class ProductController {
 
-    @Autowired
-    private ProductService productService;
+    private final ProductService productService;
 
     /**
      * 分页查询商品列表
-     * @param params 查询参数
+     * @param queryDTO 查询参数
      * @return 商品列表
      */
     @GetMapping("/list")
-    public Result<Map<String, Object>> list(@RequestParam Map<String, Object> params) {
-        try {
-            // 分页参数
-            int page = 1;
-            int pageSize = 10;
-
-            Object pageObj = params.get("page");
-            if (pageObj != null && !pageObj.toString().isEmpty()) {
-                page = Integer.parseInt(pageObj.toString());
-            }
-
-            Object pageSizeObj = params.get("pageSize");
-            if (pageSizeObj != null && !pageSizeObj.toString().isEmpty()) {
-                pageSize = Integer.parseInt(pageSizeObj.toString());
-            }
-
-            // 查询条件
-            String name = (String) params.get("name");
-            String barcode = (String) params.get("barcode");
-            String category = (String) params.get("category");
-            Integer syncStatus = null;
-            Object syncStatusObj = params.get("syncStatus");
-            if (syncStatusObj != null && !syncStatusObj.toString().isEmpty()) {
-                syncStatus = Integer.valueOf(syncStatusObj.toString());
-            }
-
-            // 构建查询条件
-            LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<>();
-            wrapper.like(name != null && !name.isEmpty(), Product::getName, name)
-                   .like(barcode != null && !barcode.isEmpty(), Product::getBarcode, barcode)
-                   .eq(category != null && !category.isEmpty(), Product::getType, category)
-                   .eq(syncStatus != null, Product::getSyncStatus, syncStatus)
-                   .eq(Product::getIsDeleted, 0);  // 只查询未删除的
-
-            // 按创建时间倒序
-            wrapper.orderByDesc(Product::getCreateTime);
-
-            // 分页查询
-            Page<Product> pageResult = new Page<>(page, pageSize);
-            IPage<Product> productPage = productService.page(pageResult, wrapper);
-
-            // 填充额外字段
-            for (Product product : productPage.getRecords()) {
-                fillProductLabels(product);
-            }
-
-            Map<String, Object> data = new HashMap<>();
-            data.put("list", productPage.getRecords());
-            data.put("total", productPage.getTotal());
-            data.put("pageSize", productPage.getSize());
-            data.put("currentPage", productPage.getCurrent());
-
-            return Result.success("查询成功", data);
-
-        } catch (Exception e) {
-            log.error("查询商品列表失败: {}", e.getMessage(), e);
-            return Result.error(500, "查询商品列表失败: " + e.getMessage());
-        }
+    public Result<PageResult<Product>> list(ProductQueryDTO queryDTO) {
+        queryDTO.validate();
+
+        IPage<Product> productPage = productService.getPage(
+                queryDTO.getPage(),
+                queryDTO.getPageSize(),
+                queryDTO.getName(),
+                queryDTO.getBarcode(),
+                queryDTO.getCategory(),
+                queryDTO.getSyncStatus()
+        );
+
+        return Result.success("查询成功", PageResult.of(productPage));
     }
 
     /**
@@ -100,17 +53,11 @@ public class ProductController {
      */
     @GetMapping("/{id}")
     public Result<Product> getById(@PathVariable Long id) {
-        try {
-            Product product = productService.getById(id);
-            if (product == null) {
-                return Result.error(404, "商品不存在");
-            }
-            fillProductLabels(product);
-            return Result.success("查询成功", product);
-        } catch (Exception e) {
-            log.error("查询商品详情失败: productId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "查询商品详情失败: " + e.getMessage());
+        Product product = productService.getDetailById(id);
+        if (product == null) {
+            return Result.error(404, "商品不存在");
         }
+        return Result.success("查询成功", product);
     }
 
     /**
@@ -119,28 +66,8 @@ public class ProductController {
      */
     @GetMapping("/statistics")
     public Result<Map<String, Object>> getStatistics() {
-        try {
-            Map<String, Object> statistics = new HashMap<>();
-
-            // 总商品数(未删除)
-            long totalProducts = productService.lambdaQuery()
-                    .eq(Product::getIsDeleted, 0)
-                    .count();
-            statistics.put("totalProducts", totalProducts);
-
-            // 已同步商品数
-            long syncedProducts = productService.lambdaQuery()
-                    .eq(Product::getIsDeleted, 0)
-                    .eq(Product::getSyncStatus, 2)
-                    .count();
-            statistics.put("syncedProducts", syncedProducts);
-
-            return Result.success("查询成功", statistics);
-
-        } catch (Exception e) {
-            log.error("查询商品统计失败: {}", e.getMessage(), e);
-            return Result.error(500, "查询商品统计失败: " + e.getMessage());
-        }
+        Map<String, Object> statistics = productService.getStatistics();
+        return Result.success("查询成功", statistics);
     }
 
     /**
@@ -151,22 +78,8 @@ public class ProductController {
     @Log(module = "商品管理", operation = OperationType.INSERT, summary = "添加商品")
     @PostMapping
     public Result<Product> add(@RequestBody Product product) {
-        try {
-            product.setIsDeleted(0);
-            product.setSyncStatus(0);
-            product.setCreateTime(LocalDateTime.now());
-            product.setUpdateTime(LocalDateTime.now());
-
-            boolean success = productService.save(product);
-            if (success) {
-                return Result.success("添加成功", product);
-            } else {
-                return Result.error(500, "添加失败");
-            }
-        } catch (Exception e) {
-            log.error("添加商品失败: {}", e.getMessage(), e);
-            return Result.error(500, "添加商品失败: " + e.getMessage());
-        }
+        Product saved = productService.add(product);
+        return Result.success("添加成功", saved);
     }
 
     /**
@@ -178,25 +91,8 @@ public class ProductController {
     @Log(module = "商品管理", operation = OperationType.UPDATE, summary = "编辑商品")
     @PutMapping("/{id}")
     public Result<Product> update(@PathVariable Long id, @RequestBody Product product) {
-        try {
-            Product existing = productService.getById(id);
-            if (existing == null) {
-                return Result.error(404, "商品不存在");
-            }
-
-            product.setId(id);
-            product.setUpdateTime(LocalDateTime.now());
-
-            boolean success = productService.updateById(product);
-            if (success) {
-                return Result.success("更新成功", product);
-            } else {
-                return Result.error(500, "更新失败");
-            }
-        } catch (Exception e) {
-            log.error("更新商品失败: productId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "更新商品失败: " + e.getMessage());
-        }
+        Product saved = productService.edit(id, product);
+        return Result.success("更新成功", saved);
     }
 
     /**
@@ -207,22 +103,8 @@ public class ProductController {
     @Log(module = "商品管理", operation = OperationType.DELETE, summary = "删除商品")
     @DeleteMapping("/{id}")
     public Result<Void> delete(@PathVariable Long id) {
-        try {
-            Product product = productService.getById(id);
-            if (product == null) {
-                return Result.error(404, "商品不存在");
-            }
-
-            // 软删除
-            product.setIsDeleted(1);
-            product.setUpdateTime(LocalDateTime.now());
-            productService.updateById(product);
-
-            return Result.success("删除成功", null);
-        } catch (Exception e) {
-            log.error("删除商品失败: productId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "删除商品失败: " + e.getMessage());
-        }
+        boolean success = productService.softDelete(id);
+        return success ? Result.success("删除成功", null) : Result.error(500, "删除失败");
     }
 
     /**
@@ -233,70 +115,7 @@ public class ProductController {
     @Log(module = "商品管理", operation = OperationType.SYNC, summary = "同步商品")
     @PostMapping("/{id}/sync")
     public Result<Void> sync(@PathVariable Long id) {
-        try {
-            Product product = productService.getById(id);
-            if (product == null) {
-                return Result.error(404, "商品不存在");
-            }
-
-            log.info("同步商品到哈哈平台: productId={}, name={}", id, product.getName());
-
-            // TODO: 调用SDK同步商品到哈哈平台
-
-            // 更新同步状态
-            productService.updateSyncStatus(id, 2);
-
-            return Result.success("同步成功", null);
-        } catch (Exception e) {
-            log.error("同步商品失败: productId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "同步商品失败: " + e.getMessage());
-        }
-    }
-
-    /**
-     * 填充商品标签字段
-     * @param product 商品对象
-     */
-    private void fillProductLabels(Product product) {
-        // 同步状态标签
-        if (product.getSyncStatus() != null) {
-            switch (product.getSyncStatus()) {
-                case 0:
-                    product.setSyncStatusLabel("未同步");
-                    product.setSyncStatusColor("info");
-                    break;
-                case 1:
-                    product.setSyncStatusLabel("同步中");
-                    product.setSyncStatusColor("warning");
-                    break;
-                case 2:
-                    product.setSyncStatusLabel("已同步");
-                    product.setSyncStatusColor("success");
-                    break;
-                case 3:
-                    product.setSyncStatusLabel("同步失败");
-                    product.setSyncStatusColor("danger");
-                    break;
-                default:
-                    product.setSyncStatusLabel("未知");
-                    product.setSyncStatusColor("info");
-            }
-        }
-
-        // 图片URL
-        if (product.getImageUrl() == null && product.getPic() != null) {
-            product.setImageUrl(product.getPic());
-        }
-
-        // 默认值
-        if (product.getCategory() == null) {
-            product.setCategory(product.getType());
-        }
-        if (product.getPrice() == null && product.getRetailPrice() != null) {
-            product.setPrice(product.getRetailPrice());
-        }
-        if (product.getCost() == null && product.getCostPrice() != null) {
-            product.setCost(product.getCostPrice());
-        }
+        boolean success = productService.syncToHaha(id);
+        return success ? Result.success("同步成功", null) : Result.error(500, "同步失败");
     }
 }

+ 127 - 263
haha-admin/src/main/java/com/haha/admin/controller/ShopController.java

@@ -1,9 +1,10 @@
 package com.haha.admin.controller;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.haha.admin.dto.ShopQueryDTO;
 import com.haha.common.annotation.Log;
 import com.haha.common.enums.OperationType;
+import com.haha.common.vo.PageResult;
 import com.haha.common.vo.Result;
 import com.haha.entity.Shop;
 import com.haha.entity.Device;
@@ -13,8 +14,8 @@ import com.haha.service.ShopService;
 import com.haha.service.DeviceService;
 import com.haha.service.ShopReplenisherService;
 import com.haha.service.AdminService;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.HashMap;
@@ -27,55 +28,31 @@ import java.util.Map;
 @Slf4j
 @RestController
 @RequestMapping("/shops")
+@RequiredArgsConstructor
 public class ShopController {
 
-    @Autowired
-    private ShopService shopService;
-
-    @Autowired
-    private DeviceService deviceService;
-
-    @Autowired
-    private ShopReplenisherService shopReplenisherService;
-
-    @Autowired
-    private AdminService adminService;
+    private final ShopService shopService;
+    private final DeviceService deviceService;
+    private final ShopReplenisherService shopReplenisherService;
+    private final AdminService adminService;
 
     /**
      * 分页查询门店列表
-     * @param params 查询参数
+     * @param queryDTO 查询参数
      * @return 门店列表
      */
     @GetMapping("/list")
-    public Result<Map<String, Object>> list(@RequestParam Map<String, Object> params) {
-        try {
-            int page = 1;
-            int pageSize = 10;
-
-            Object pageObj = params.get("page");
-            if (pageObj != null && !pageObj.toString().isEmpty()) {
-                page = Integer.parseInt(pageObj.toString());
-            }
-
-            Object pageSizeObj = params.get("pageSize");
-            if (pageSizeObj != null && !pageSizeObj.toString().isEmpty()) {
-                pageSize = Integer.parseInt(pageSizeObj.toString());
-            }
-
-            IPage<Shop> shopPage = shopService.getPage(page, pageSize, params);
-
-            Map<String, Object> data = new HashMap<>();
-            data.put("list", shopPage.getRecords());
-            data.put("total", shopPage.getTotal());
-            data.put("pageSize", shopPage.getSize());
-            data.put("currentPage", shopPage.getCurrent());
-
-            return Result.success("查询成功", data);
-
-        } catch (Exception e) {
-            log.error("查询门店列表失败: {}", e.getMessage(), e);
-            return Result.error(500, "查询门店列表失败: " + e.getMessage());
-        }
+    public Result<PageResult<Shop>> list(ShopQueryDTO queryDTO) {
+        queryDTO.validate();
+        
+        Map<String, Object> params = new HashMap<>();
+        params.put("name", queryDTO.getName());
+        params.put("city", queryDTO.getCity());
+        params.put("status", queryDTO.getStatus());
+        
+        IPage<Shop> shopPage = shopService.getPage(queryDTO.getPage(), queryDTO.getPageSize(), params);
+
+        return Result.success("查询成功", PageResult.of(shopPage));
     }
 
     /**
@@ -85,16 +62,11 @@ public class ShopController {
      */
     @GetMapping("/{id}")
     public Result<Shop> getById(@PathVariable Long id) {
-        try {
-            Shop shop = shopService.getShopWithStats(id);
-            if (shop == null) {
-                return Result.error(404, "门店不存在");
-            }
-            return Result.success("查询成功", shop);
-        } catch (Exception e) {
-            log.error("查询门店详情失败: id={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "查询门店详情失败: " + e.getMessage());
+        Shop shop = shopService.getShopWithStats(id);
+        if (shop == null) {
+            return Result.error(404, "门店不存在");
         }
+        return Result.success("查询成功", shop);
     }
 
     /**
@@ -103,13 +75,8 @@ public class ShopController {
      */
     @GetMapping("/statistics")
     public Result<Map<String, Object>> getStatistics() {
-        try {
-            Map<String, Object> statistics = shopService.getStatistics();
-            return Result.success("查询成功", statistics);
-        } catch (Exception e) {
-            log.error("查询门店统计失败: {}", e.getMessage(), e);
-            return Result.error(500, "查询门店统计失败: " + e.getMessage());
-        }
+        Map<String, Object> statistics = shopService.getStatistics();
+        return Result.success("查询成功", statistics);
     }
 
     /**
@@ -118,13 +85,8 @@ public class ShopController {
      */
     @GetMapping("/enabled")
     public Result<List<Map<String, Object>>> getEnabledShops() {
-        try {
-            List<Map<String, Object>> shops = shopService.getAllEnabledShops();
-            return Result.success("查询成功", shops);
-        } catch (Exception e) {
-            log.error("查询启用门店失败: {}", e.getMessage(), e);
-            return Result.error(500, "查询启用门店失败: " + e.getMessage());
-        }
+        List<Map<String, Object>> shops = shopService.getAllEnabledShops();
+        return Result.success("查询成功", shops);
     }
 
     /**
@@ -135,13 +97,8 @@ public class ShopController {
     @Log(module = "门店管理", operation = OperationType.INSERT, summary = "新增门店")
     @PostMapping
     public Result<Shop> create(@RequestBody Shop shop) {
-        try {
-            Shop created = shopService.createShop(shop);
-            return Result.success("创建成功", created);
-        } catch (Exception e) {
-            log.error("创建门店失败: {}", e.getMessage(), e);
-            return Result.error(500, "创建门店失败: " + e.getMessage());
-        }
+        Shop created = shopService.createShop(shop);
+        return Result.success("创建成功", created);
     }
 
     /**
@@ -153,14 +110,9 @@ public class ShopController {
     @Log(module = "门店管理", operation = OperationType.UPDATE, summary = "编辑门店")
     @PutMapping("/{id}")
     public Result<Shop> update(@PathVariable Long id, @RequestBody Shop shop) {
-        try {
-            shop.setId(id);
-            Shop updated = shopService.updateShop(shop);
-            return Result.success("更新成功", updated);
-        } catch (Exception e) {
-            log.error("更新门店失败: id={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "更新门店失败: " + e.getMessage());
-        }
+        shop.setId(id);
+        Shop updated = shopService.updateShop(shop);
+        return Result.success("更新成功", updated);
     }
 
     /**
@@ -171,23 +123,18 @@ public class ShopController {
     @Log(module = "门店管理", operation = OperationType.DELETE, summary = "删除门店")
     @DeleteMapping("/{id}")
     public Result<String> delete(@PathVariable Long id) {
-        try {
-            // 检查门店是否有设备
-            Shop shop = shopService.getShopWithStats(id);
-            if (shop == null) {
-                return Result.error(404, "门店不存在");
-            }
-            
-            if (shop.getDeviceCount() != null && shop.getDeviceCount() > 0) {
-                return Result.error(400, "该门店下存在设备,无法删除");
-            }
-            
-            shopService.removeById(id);
-            return Result.success("删除成功");
-        } catch (Exception e) {
-            log.error("删除门店失败: id={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "删除门店失败: " + e.getMessage());
+        // 检查门店是否有设备
+        Shop shop = shopService.getShopWithStats(id);
+        if (shop == null) {
+            return Result.error(404, "门店不存在");
+        }
+        
+        if (shop.getDeviceCount() != null && shop.getDeviceCount() > 0) {
+            return Result.error(400, "该门店下存在设备,无法删除");
         }
+        
+        shopService.removeById(id);
+        return Result.success("删除成功");
     }
 
     /**
@@ -199,18 +146,13 @@ public class ShopController {
     @Log(module = "门店管理", operation = OperationType.UPDATE, summary = "切换门店状态")
     @PutMapping("/{id}/status")
     public Result<String> toggleStatus(@PathVariable Long id, @RequestBody Map<String, Object> params) {
-        try {
-            Integer status = Integer.valueOf(params.get("status").toString());
-            boolean result = shopService.toggleStatus(id, status);
-            
-            if (result) {
-                return Result.success("状态更新成功");
-            } else {
-                return Result.error(500, "状态更新失败");
-            }
-        } catch (Exception e) {
-            log.error("切换门店状态失败: id={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "切换门店状态失败: " + e.getMessage());
+        Integer status = Integer.valueOf(params.get("status").toString());
+        boolean result = shopService.toggleStatus(id, status);
+        
+        if (result) {
+            return Result.success("状态更新成功");
+        } else {
+            return Result.error(500, "状态更新失败");
         }
     }
 
@@ -221,13 +163,8 @@ public class ShopController {
      */
     @GetMapping("/{id}/devices")
     public Result<List<Map<String, Object>>> getDevices(@PathVariable Long id) {
-        try {
-            List<Map<String, Object>> devices = shopService.getDevicesByShopId(id);
-            return Result.success("查询成功", devices);
-        } catch (Exception e) {
-            log.error("查询门店设备失败: id={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "查询门店设备失败: " + e.getMessage());
-        }
+        List<Map<String, Object>> devices = shopService.getDevicesByShopId(id);
+        return Result.success("查询成功", devices);
     }
 
     /**
@@ -239,17 +176,12 @@ public class ShopController {
     @Log(module = "门店管理", operation = OperationType.UPDATE, summary = "关联设备到门店")
     @PostMapping("/{id}/devices")
     public Result<String> linkDevice(@PathVariable Long id, @RequestBody Map<String, Object> params) {
-        try {
-            Long deviceId = Long.valueOf(params.get("deviceId").toString());
-            boolean result = shopService.linkDevice(id, deviceId);
-            if (result) {
-                return Result.success("关联成功");
-            } else {
-                return Result.error(500, "关联失败");
-            }
-        } catch (Exception e) {
-            log.error("关联设备失败: shopId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "关联失败: " + e.getMessage());
+        Long deviceId = Long.valueOf(params.get("deviceId").toString());
+        boolean result = shopService.linkDevice(id, deviceId);
+        if (result) {
+            return Result.success("关联成功");
+        } else {
+            return Result.error(500, "关联失败");
         }
     }
 
@@ -262,24 +194,19 @@ public class ShopController {
     @Log(module = "门店管理", operation = OperationType.UPDATE, summary = "批量关联设备到门店")
     @PostMapping("/{id}/devices/batch")
     public Result<Map<String, Object>> batchLinkDevices(@PathVariable Long id, @RequestBody Map<String, Object> params) {
-        try {
-            @SuppressWarnings("unchecked")
-            List<Integer> deviceIdInts = (List<Integer>) params.get("deviceIds");
-            List<Long> deviceIds = deviceIdInts.stream()
-                    .map(Integer::longValue)
-                    .toList();
-            
-            int count = shopService.batchLinkDevices(id, deviceIds);
-            
-            Map<String, Object> result = new HashMap<>();
-            result.put("success", count);
-            result.put("total", deviceIds.size());
-            
-            return Result.success("批量关联完成", result);
-        } catch (Exception e) {
-            log.error("批量关联设备失败: shopId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "批量关联失败: " + e.getMessage());
-        }
+        @SuppressWarnings("unchecked")
+        List<Integer> deviceIdInts = (List<Integer>) params.get("deviceIds");
+        List<Long> deviceIds = deviceIdInts.stream()
+                .map(Integer::longValue)
+                .toList();
+        
+        int count = shopService.batchLinkDevices(id, deviceIds);
+        
+        Map<String, Object> result = new HashMap<>();
+        result.put("success", count);
+        result.put("total", deviceIds.size());
+        
+        return Result.success("批量关联完成", result);
     }
 
     /**
@@ -291,16 +218,11 @@ public class ShopController {
     @Log(module = "门店管理", operation = OperationType.UPDATE, summary = "移除门店设备关联")
     @DeleteMapping("/{id}/devices/{deviceId}")
     public Result<String> unlinkDevice(@PathVariable Long id, @PathVariable Long deviceId) {
-        try {
-            boolean result = shopService.unlinkDevice(id, deviceId);
-            if (result) {
-                return Result.success("移除成功");
-            } else {
-                return Result.error(500, "移除失败");
-            }
-        } catch (Exception e) {
-            log.error("移除设备失败: shopId={}, deviceId={}, error={}", id, deviceId, e.getMessage(), e);
-            return Result.error(500, "移除失败: " + e.getMessage());
+        boolean result = shopService.unlinkDevice(id, deviceId);
+        if (result) {
+            return Result.success("移除成功");
+        } else {
+            return Result.error(500, "移除失败");
         }
     }
 
@@ -313,24 +235,19 @@ public class ShopController {
     @Log(module = "门店管理", operation = OperationType.UPDATE, summary = "批量移除设备关联")
     @DeleteMapping("/{id}/devices/batch")
     public Result<Map<String, Object>> batchUnlinkDevices(@PathVariable Long id, @RequestBody Map<String, Object> params) {
-        try {
-            @SuppressWarnings("unchecked")
-            List<Integer> deviceIdInts = (List<Integer>) params.get("deviceIds");
-            List<Long> deviceIds = deviceIdInts.stream()
-                    .map(Integer::longValue)
-                    .toList();
-            
-            int count = shopService.batchUnlinkDevices(id, deviceIds);
-            
-            Map<String, Object> result = new HashMap<>();
-            result.put("success", count);
-            result.put("total", deviceIds.size());
-            
-            return Result.success("批量移除完成", result);
-        } catch (Exception e) {
-            log.error("批量移除设备失败: shopId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "批量移除失败: " + e.getMessage());
-        }
+        @SuppressWarnings("unchecked")
+        List<Integer> deviceIdInts = (List<Integer>) params.get("deviceIds");
+        List<Long> deviceIds = deviceIdInts.stream()
+                .map(Integer::longValue)
+                .toList();
+        
+        int count = shopService.batchUnlinkDevices(id, deviceIds);
+        
+        Map<String, Object> result = new HashMap<>();
+        result.put("success", count);
+        result.put("total", deviceIds.size());
+        
+        return Result.success("批量移除完成", result);
     }
 
     /**
@@ -339,13 +256,8 @@ public class ShopController {
      */
     @GetMapping("/unlinked-devices")
     public Result<List<Device>> getUnlinkedDevices() {
-        try {
-            List<Device> devices = deviceService.getUnlinkedDevices();
-            return Result.success("查询成功", devices);
-        } catch (Exception e) {
-            log.error("查询未关联设备失败: error={}", e.getMessage(), e);
-            return Result.error(500, "查询失败: " + e.getMessage());
-        }
+        List<Device> devices = deviceService.getUnlinkedDevices();
+        return Result.success("查询成功", devices);
     }
 
     // ==================== 补货员管理 ====================
@@ -357,13 +269,8 @@ public class ShopController {
      */
     @GetMapping("/{id}/replenishers")
     public Result<List<ShopReplenisher>> getReplenishers(@PathVariable Long id) {
-        try {
-            List<ShopReplenisher> replenishers = shopReplenisherService.getReplenishersByShopId(id);
-            return Result.success("查询成功", replenishers);
-        } catch (Exception e) {
-            log.error("查询补货员失败: shopId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "查询失败: " + e.getMessage());
-        }
+        List<ShopReplenisher> replenishers = shopReplenisherService.getReplenishersByShopId(id);
+        return Result.success("查询成功", replenishers);
     }
 
     /**
@@ -375,13 +282,8 @@ public class ShopController {
     @Log(module = "门店管理", operation = OperationType.INSERT, summary = "添加门店补货员")
     @PostMapping("/{id}/replenishers")
     public Result<String> addReplenisher(@PathVariable Long id, @RequestBody Map<String, Object> params) {
-        try {
-            Long adminId = Long.valueOf(params.get("adminId").toString());
-            return shopReplenisherService.addReplenisher(id, adminId);
-        } catch (Exception e) {
-            log.error("添加补货员失败: shopId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "添加失败: " + e.getMessage());
-        }
+        Long adminId = Long.valueOf(params.get("adminId").toString());
+        return shopReplenisherService.addReplenisher(id, adminId);
     }
 
     /**
@@ -393,24 +295,19 @@ public class ShopController {
     @Log(module = "门店管理", operation = OperationType.INSERT, summary = "批量添加门店补货员")
     @PostMapping("/{id}/replenishers/batch")
     public Result<Map<String, Object>> batchAddReplenishers(@PathVariable Long id, @RequestBody Map<String, Object> params) {
-        try {
-            @SuppressWarnings("unchecked")
-            List<Integer> adminIdInts = (List<Integer>) params.get("adminIds");
-            List<Long> adminIds = adminIdInts.stream()
-                    .map(Integer::longValue)
-                    .toList();
-
-            int count = shopReplenisherService.batchAddReplenishers(id, adminIds);
-
-            Map<String, Object> result = new HashMap<>();
-            result.put("success", count);
-            result.put("total", adminIds.size());
-
-            return Result.success("批量添加完成", result);
-        } catch (Exception e) {
-            log.error("批量添加补货员失败: shopId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "批量添加失败: " + e.getMessage());
-        }
+        @SuppressWarnings("unchecked")
+        List<Integer> adminIdInts = (List<Integer>) params.get("adminIds");
+        List<Long> adminIds = adminIdInts.stream()
+                .map(Integer::longValue)
+                .toList();
+
+        int count = shopReplenisherService.batchAddReplenishers(id, adminIds);
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("success", count);
+        result.put("total", adminIds.size());
+
+        return Result.success("批量添加完成", result);
     }
 
     /**
@@ -422,12 +319,7 @@ public class ShopController {
     @Log(module = "门店管理", operation = OperationType.DELETE, summary = "移除门店补货员")
     @DeleteMapping("/{id}/replenishers/{adminId}")
     public Result<String> removeReplenisher(@PathVariable Long id, @PathVariable Long adminId) {
-        try {
-            return shopReplenisherService.removeReplenisher(id, adminId);
-        } catch (Exception e) {
-            log.error("移除补货员失败: shopId={}, adminId={}, error={}", id, adminId, e.getMessage(), e);
-            return Result.error(500, "移除失败: " + e.getMessage());
-        }
+        return shopReplenisherService.removeReplenisher(id, adminId);
     }
 
     /**
@@ -439,29 +331,19 @@ public class ShopController {
     @Log(module = "门店管理", operation = OperationType.DELETE, summary = "批量移除门店补货员")
     @DeleteMapping("/{id}/replenishers/batch")
     public Result<Map<String, Object>> batchRemoveReplenishers(@PathVariable Long id, @RequestBody Map<String, Object> params) {
-        try {
-            @SuppressWarnings("unchecked")
-            List<Integer> adminIdInts = (List<Integer>) params.get("adminIds");
-            List<Long> adminIds = adminIdInts.stream()
-                    .map(Integer::longValue)
-                    .toList();
-
-            // 执行批量删除
-            LambdaQueryWrapper<ShopReplenisher> wrapper = new LambdaQueryWrapper<>();
-            wrapper.eq(ShopReplenisher::getShopId, id)
-                    .in(ShopReplenisher::getAdminId, adminIds);
-            int count = (int) shopReplenisherService.count(wrapper);
-            shopReplenisherService.remove(wrapper);
-
-            Map<String, Object> result = new HashMap<>();
-            result.put("success", count);
-            result.put("total", adminIds.size());
-
-            return Result.success("批量移除完成", result);
-        } catch (Exception e) {
-            log.error("批量移除补货员失败: shopId={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "批量移除失败: " + e.getMessage());
-        }
+        @SuppressWarnings("unchecked")
+        List<Integer> adminIdInts = (List<Integer>) params.get("adminIds");
+        List<Long> adminIds = adminIdInts.stream()
+                .map(Integer::longValue)
+                .toList();
+
+        int count = shopReplenisherService.batchRemoveReplenishers(id, adminIds);
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("success", count);
+        result.put("total", adminIds.size());
+
+        return Result.success("批量移除完成", result);
     }
 
     /**
@@ -473,13 +355,8 @@ public class ShopController {
     @Log(module = "门店管理", operation = OperationType.UPDATE, summary = "更新补货员状态")
     @PutMapping("/replenishers/{id}/status")
     public Result<String> updateReplenisherStatus(@PathVariable Long id, @RequestBody Map<String, Object> params) {
-        try {
-            Integer status = Integer.valueOf(params.get("status").toString());
-            return shopReplenisherService.updateStatus(id, status);
-        } catch (Exception e) {
-            log.error("更新补货员状态失败: id={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "更新失败: " + e.getMessage());
-        }
+        Integer status = Integer.valueOf(params.get("status").toString());
+        return shopReplenisherService.updateStatus(id, status);
     }
 
     /**
@@ -488,20 +365,7 @@ public class ShopController {
      */
     @GetMapping("/available-users")
     public Result<List<Admin>> getAvailableUsers(@RequestParam(required = false) String keyword) {
-        try {
-            LambdaQueryWrapper<Admin> wrapper = new LambdaQueryWrapper<>();
-            wrapper.eq(Admin::getStatus, 1); // 只查询正常状态的管理员
-            if (keyword != null && !keyword.isEmpty()) {
-                wrapper.and(w -> w.like(Admin::getRealName, keyword)
-                        .or().like(Admin::getPhone, keyword)
-                        .or().like(Admin::getUsername, keyword));
-            }
-            wrapper.orderByDesc(Admin::getCreateTime);
-            List<Admin> admins = adminService.list(wrapper);
-            return Result.success("查询成功", admins);
-        } catch (Exception e) {
-            log.error("查询可选管理员失败: error={}", e.getMessage(), e);
-            return Result.error(500, "查询失败: " + e.getMessage());
-        }
+        List<Admin> admins = adminService.getAvailableAdmins(keyword);
+        return Result.success("查询成功", admins);
     }
 }

+ 32 - 0
haha-admin/src/main/java/com/haha/admin/dto/DeviceQueryDTO.java

@@ -0,0 +1,32 @@
+package com.haha.admin.dto;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 设备查询DTO
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class DeviceQueryDTO extends PageQueryDTO {
+    
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+    
+    /**
+     * 门店ID
+     */
+    private Long shopId;
+    
+    /**
+     * 状态
+     */
+    private Integer status;
+    
+    /**
+     * 门店名称(模糊查询)
+     */
+    private String storeName;
+}

+ 42 - 0
haha-admin/src/main/java/com/haha/admin/dto/OrderQueryDTO.java

@@ -0,0 +1,42 @@
+package com.haha.admin.dto;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 订单查询DTO
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class OrderQueryDTO extends PageQueryDTO {
+    
+    /**
+     * 订单号
+     */
+    private String orderNo;
+    
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+    
+    /**
+     * 支付状态
+     */
+    private String payStatus;
+    
+    /**
+     * 订单状态
+     */
+    private Integer status;
+    
+    /**
+     * 开始日期
+     */
+    private String startDate;
+    
+    /**
+     * 结束日期
+     */
+    private String endDate;
+}

+ 42 - 0
haha-admin/src/main/java/com/haha/admin/dto/PageQueryDTO.java

@@ -0,0 +1,42 @@
+package com.haha.admin.dto;
+
+import lombok.Data;
+
+/**
+ * 分页查询基础DTO
+ */
+@Data
+public class PageQueryDTO {
+    
+    /**
+     * 当前页码,默认第1页
+     */
+    private Integer page = 1;
+    
+    /**
+     * 每页条数,默认10条
+     */
+    private Integer pageSize = 10;
+    
+    /**
+     * 获取偏移量
+     */
+    public int getOffset() {
+        return (page - 1) * pageSize;
+    }
+    
+    /**
+     * 校验并修正分页参数
+     */
+    public void validate() {
+        if (page == null || page < 1) {
+            page = 1;
+        }
+        if (pageSize == null || pageSize < 1) {
+            pageSize = 10;
+        }
+        if (pageSize > 100) {
+            pageSize = 100;  // 限制最大每页条数
+        }
+    }
+}

+ 32 - 0
haha-admin/src/main/java/com/haha/admin/dto/ProductQueryDTO.java

@@ -0,0 +1,32 @@
+package com.haha.admin.dto;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 商品查询DTO
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ProductQueryDTO extends PageQueryDTO {
+    
+    /**
+     * 商品名称
+     */
+    private String name;
+    
+    /**
+     * 条形码
+     */
+    private String barcode;
+    
+    /**
+     * 分类
+     */
+    private String category;
+    
+    /**
+     * 同步状态
+     */
+    private Integer syncStatus;
+}

+ 27 - 0
haha-admin/src/main/java/com/haha/admin/dto/ShopQueryDTO.java

@@ -0,0 +1,27 @@
+package com.haha.admin.dto;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 门店查询DTO
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ShopQueryDTO extends PageQueryDTO {
+    
+    /**
+     * 门店名称(模糊查询)
+     */
+    private String name;
+    
+    /**
+     * 城市
+     */
+    private String city;
+    
+    /**
+     * 状态:0-禁用,1-启用
+     */
+    private Integer status;
+}

+ 13 - 12
haha-common/pom.xml

@@ -16,29 +16,30 @@
     <description>公共模块 - 通用工具类和响应结果类</description>
 
     <dependencies>
-        <!-- Lombok -->
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-            <optional>true</optional>
-        </dependency>
-
         <!-- FastJson -->
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>fastjson</artifactId>
         </dependency>
 
-        <!-- Spring Web (用于HTTP相关工具) -->
+        <!-- Hutool 工具包 -->
         <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-web</artifactId>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+        </dependency>
+
+        <!-- MyBatis Plus (用于分页等) - provided scope -->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
             <scope>provided</scope>
         </dependency>
 
+        <!-- Spring Web (用于HTTP相关工具) - provided scope -->
         <dependency>
-            <groupId>cn.hutool</groupId>
-            <artifactId>hutool-all</artifactId>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+            <scope>provided</scope>
         </dependency>
     </dependencies>
 

+ 60 - 0
haha-common/src/main/java/com/haha/common/constant/CommonConstants.java

@@ -0,0 +1,60 @@
+package com.haha.common.constant;
+
+/**
+ * 通用状态常量
+ */
+public final class CommonConstants {
+    
+    private CommonConstants() {}
+    
+    // ==================== 通用状态 ====================
+    
+    /**
+     * 启用状态
+     */
+    public static final int STATUS_ENABLED = 1;
+    
+    /**
+     * 禁用状态
+     */
+    public static final int STATUS_DISABLED = 0;
+    
+    /**
+     * 禁用状态(管理员专用)
+     */
+    public static final int ADMIN_STATUS_DISABLED = 2;
+    
+    // ==================== 删除标记 ====================
+    
+    /**
+     * 未删除
+     */
+    public static final int NOT_DELETED = 0;
+    
+    /**
+     * 已删除
+     */
+    public static final int DELETED = 1;
+    
+    // ==================== 默认值 ====================
+    
+    /**
+     * 默认页码
+     */
+    public static final int DEFAULT_PAGE = 1;
+    
+    /**
+     * 默认每页条数
+     */
+    public static final int DEFAULT_PAGE_SIZE = 10;
+    
+    /**
+     * 最大每页条数
+     */
+    public static final int MAX_PAGE_SIZE = 100;
+    
+    /**
+     * 默认密码
+     */
+    public static final String DEFAULT_PASSWORD = "123456";
+}

+ 82 - 0
haha-common/src/main/java/com/haha/common/constant/DeviceConstants.java

@@ -0,0 +1,82 @@
+package com.haha.common.constant;
+
+/**
+ * 设备相关常量
+ */
+public final class DeviceConstants {
+    
+    private DeviceConstants() {}
+    
+    // ==================== 设备状态 ====================
+    
+    /**
+     * 设备状态:正常/在线
+     */
+    public static final int STATUS_ONLINE = 1;
+    
+    /**
+     * 设备状态:冻结
+     */
+    public static final int STATUS_FROZEN = 2;
+    
+    /**
+     * 设备状态:离线
+     */
+    public static final int STATUS_OFFLINE = 3;
+    
+    /**
+     * 设备状态:维护中
+     */
+    public static final int STATUS_MAINTENANCE = 4;
+    
+    // ==================== 门索引 ====================
+    
+    /**
+     * 默认门索引
+     */
+    public static final String DEFAULT_DOOR_INDEX = "A";
+    
+    /**
+     * A门
+     */
+    public static final String DOOR_A = "A";
+    
+    /**
+     * B门
+     */
+    public static final String DOOR_B = "B";
+    
+    /**
+     * C门
+     */
+    public static final String DOOR_C = "C";
+    
+    // ==================== 设备类型 ====================
+    
+    /**
+     * 设备类型:智能柜
+     */
+    public static final String TYPE_SMART_CABINET = "智能柜";
+    
+    // ==================== 状态描述 ====================
+    
+    /**
+     * 获取设备状态描述
+     */
+    public static String getStatusDesc(int status) {
+        return switch (status) {
+            case STATUS_ONLINE -> "正常";
+            case STATUS_FROZEN -> "冻结";
+            case STATUS_OFFLINE -> "离线";
+            case STATUS_MAINTENANCE -> "维护中";
+            default -> "未知";
+        };
+    }
+    
+    /**
+     * 判断设备是否在线
+     */
+    public static boolean isOnline(Integer status) {
+        return status != null && status == STATUS_ONLINE;
+    }
+}

+ 78 - 0
haha-common/src/main/java/com/haha/common/constant/OrderConstants.java

@@ -0,0 +1,78 @@
+package com.haha.common.constant;
+
+/**
+ * 订单相关常量
+ */
+public final class OrderConstants {
+    
+    private OrderConstants() {}
+    
+    // ==================== 订单状态 ====================
+    
+    /**
+     * 订单状态:已取消
+     */
+    public static final int STATUS_CANCELLED = 0;
+    
+    /**
+     * 订单状态:待支付
+     */
+    public static final int STATUS_PENDING_PAYMENT = 1;
+    
+    /**
+     * 订单状态:已完成
+     */
+    public static final int STATUS_COMPLETED = 2;
+    
+    /**
+     * 订单状态:已关闭
+     */
+    public static final int STATUS_CLOSED = 3;
+    
+    // ==================== 支付状态 ====================
+    
+    /**
+     * 支付状态:未支付
+     */
+    public static final String PAY_STATUS_UNPAID = "UNPAID";
+    
+    /**
+     * 支付状态:已支付
+     */
+    public static final String PAY_STATUS_PAID = "PAID";
+    
+    /**
+     * 支付状态:已退款
+     */
+    public static final String PAY_STATUS_REFUND = "REFUND";
+    
+    // ==================== 状态描述 ====================
+    
+    /**
+     * 获取订单状态描述
+     */
+    public static String getStatusDesc(int status) {
+        return switch (status) {
+            case STATUS_CANCELLED -> "已取消";
+            case STATUS_PENDING_PAYMENT -> "待支付";
+            case STATUS_COMPLETED -> "已完成";
+            case STATUS_CLOSED -> "已关闭";
+            default -> "未知";
+        };
+    }
+    
+    /**
+     * 获取支付状态描述
+     */
+    public static String getPayStatusDesc(String payStatus) {
+        if (payStatus == null) {
+            return "未知";
+        }
+        return switch (payStatus) {
+            case PAY_STATUS_UNPAID -> "未支付";
+            case PAY_STATUS_PAID -> "已支付";
+            case PAY_STATUS_REFUND -> "已退款";
+            default -> "未知";
+        };
+    }
+}

+ 46 - 0
haha-common/src/main/java/com/haha/common/constant/SyncConstants.java

@@ -0,0 +1,46 @@
+package com.haha.common.constant;
+
+/**
+ * 同步相关常量
+ */
+public final class SyncConstants {
+    
+    private SyncConstants() {}
+    
+    // ==================== 同步状态 ====================
+    
+    /**
+     * 同步状态:未同步
+     */
+    public static final int STATUS_NOT_SYNCED = 0;
+    
+    /**
+     * 同步状态:同步中
+     */
+    public static final int STATUS_SYNCING = 1;
+    
+    /**
+     * 同步状态:已同步
+     */
+    public static final int STATUS_SYNCED = 2;
+    
+    /**
+     * 同步状态:同步失败
+     */
+    public static final int STATUS_SYNC_FAILED = 3;
+    
+    // ==================== 状态描述 ====================
+    
+    /**
+     * 获取同步状态描述
+     */
+    public static String getStatusDesc(int status) {
+        return switch (status) {
+            case STATUS_NOT_SYNCED -> "未同步";
+            case STATUS_SYNCING -> "同步中";
+            case STATUS_SYNCED -> "已同步";
+            case STATUS_SYNC_FAILED -> "同步失败";
+            default -> "未知";
+        };
+    }
+}

+ 74 - 0
haha-common/src/main/java/com/haha/common/enums/CommonStatus.java

@@ -0,0 +1,74 @@
+package com.haha.common.enums;
+
+import com.haha.common.vo.StatusLabel;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 通用状态枚举
+ * 用于各种实体的状态标识
+ */
+public enum CommonStatus {
+    
+    /**
+     * 启用/正常
+     */
+    ENABLED(1, "启用", "success"),
+    
+    /**
+     * 禁用
+     */
+    DISABLED(0, "禁用", "danger");
+    
+    private final int code;
+    private final String label;
+    private final String color;
+    
+    CommonStatus(int code, String label, String color) {
+        this.code = code;
+        this.label = label;
+        this.color = color;
+    }
+    
+    public int getCode() {
+        return code;
+    }
+    
+    public String getLabel() {
+        return label;
+    }
+    
+    public String getColor() {
+        return color;
+    }
+    
+    /**
+     * 获取状态标签
+     */
+    public StatusLabel getStatusLabel() {
+        return new StatusLabel(label, color);
+    }
+    
+    /**
+     * 根据状态码获取标签
+     */
+    public static StatusLabel getLabelByCode(Integer code) {
+        if (code == null) {
+            return StatusLabel.info("未知");
+        }
+        for (CommonStatus status : values()) {
+            if (status.code == code) {
+                return status.getStatusLabel();
+            }
+        }
+        return StatusLabel.info("未知");
+    }
+    
+    /**
+     * 判断是否为启用状态
+     */
+    public static boolean isEnabled(Integer status) {
+        return status != null && status == ENABLED.code;
+    }
+}

+ 126 - 0
haha-common/src/main/java/com/haha/common/utils/EntityLabelUtils.java

@@ -0,0 +1,126 @@
+package com.haha.common.utils;
+
+import com.haha.common.constant.CommonConstants;
+import com.haha.common.constant.DeviceConstants;
+import com.haha.common.constant.OrderConstants;
+import com.haha.common.constant.SyncConstants;
+import com.haha.common.vo.StatusLabel;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+
+/**
+ * 实体标签填充工具类
+ * 用于统一处理实体的状态标签填充逻辑
+ */
+public class EntityLabelUtils {
+
+    /**
+     * 状态映射配置
+     */
+    private static final Map<String, Map<Integer, StatusLabel>> STATUS_MAPPING = new HashMap<>();
+    
+    static {
+        // 通用状态映射(启用/禁用)
+        Map<Integer, StatusLabel> commonStatus = new HashMap<>();
+        commonStatus.put(CommonConstants.STATUS_ENABLED, StatusLabel.success("启用"));
+        commonStatus.put(CommonConstants.STATUS_DISABLED, StatusLabel.danger("禁用"));
+        STATUS_MAPPING.put("common", commonStatus);
+        
+        // 设备状态映射
+        Map<Integer, StatusLabel> deviceStatus = new HashMap<>();
+        deviceStatus.put(DeviceConstants.STATUS_ONLINE, StatusLabel.success("正常"));
+        deviceStatus.put(DeviceConstants.STATUS_FROZEN, StatusLabel.warning("冻结"));
+        deviceStatus.put(DeviceConstants.STATUS_OFFLINE, StatusLabel.info("离线"));
+        deviceStatus.put(DeviceConstants.STATUS_MAINTENANCE, StatusLabel.danger("维护中"));
+        STATUS_MAPPING.put("device", deviceStatus);
+        
+        // 同步状态映射
+        Map<Integer, StatusLabel> syncStatus = new HashMap<>();
+        syncStatus.put(SyncConstants.STATUS_NOT_SYNCED, StatusLabel.info("未同步"));
+        syncStatus.put(SyncConstants.STATUS_SYNCING, StatusLabel.warning("同步中"));
+        syncStatus.put(SyncConstants.STATUS_SYNCED, StatusLabel.success("已同步"));
+        syncStatus.put(SyncConstants.STATUS_SYNC_FAILED, StatusLabel.danger("同步失败"));
+        STATUS_MAPPING.put("sync", syncStatus);
+        
+        // 订单状态映射
+        Map<Integer, StatusLabel> orderStatus = new HashMap<>();
+        orderStatus.put(OrderConstants.STATUS_CANCELLED, StatusLabel.danger("已取消"));
+        orderStatus.put(OrderConstants.STATUS_PENDING_PAYMENT, StatusLabel.warning("待支付"));
+        orderStatus.put(OrderConstants.STATUS_COMPLETED, StatusLabel.success("已完成"));
+        orderStatus.put(OrderConstants.STATUS_CLOSED, StatusLabel.info("已关闭"));
+        STATUS_MAPPING.put("order", orderStatus);
+    }
+    
+    /**
+     * 获取状态标签
+     *
+     * @param type   状态类型(common/device/sync/order)
+     * @param status 状态值
+     * @return 状态标签
+     */
+    public static StatusLabel getStatusLabel(String type, Integer status) {
+        if (status == null) {
+            return StatusLabel.info("未知");
+        }
+        Map<Integer, StatusLabel> mapping = STATUS_MAPPING.get(type);
+        if (mapping == null) {
+            return StatusLabel.info("未知");
+        }
+        return mapping.getOrDefault(status, StatusLabel.info("未知"));
+    }
+    
+    /**
+     * 获取支付状态标签(字符串类型)
+     *
+     * @param payStatus 支付状态码
+     * @return 状态标签
+     */
+    public static StatusLabel getPayStatusLabel(String payStatus) {
+        if (payStatus == null) {
+            return StatusLabel.info("未知");
+        }
+        return switch (payStatus) {
+            case OrderConstants.PAY_STATUS_UNPAID -> StatusLabel.warning("未支付");
+            case OrderConstants.PAY_STATUS_PAID -> StatusLabel.success("已支付");
+            case OrderConstants.PAY_STATUS_REFUND -> StatusLabel.danger("已退款");
+            default -> StatusLabel.info("未知");
+        };
+    }
+    
+    /**
+     * 填充实体的状态标签
+     *
+     * @param entity         实体对象
+     * @param statusGetter   状态获取函数
+     * @param labelSetter    标签设置函数
+     * @param colorSetter    颜色设置函数
+     * @param statusType     状态类型
+     * @param <T>            实体类型
+     */
+    public static <T> void fillStatusLabel(T entity,
+                                           Function<T, Integer> statusGetter,
+                                           BiConsumer<T, String> labelSetter,
+                                           BiConsumer<T, String> colorSetter,
+                                           String statusType) {
+        if (entity == null) {
+            return;
+        }
+        Integer status = statusGetter.apply(entity);
+        StatusLabel label = getStatusLabel(statusType, status);
+        labelSetter.accept(entity, label.getLabel());
+        colorSetter.accept(entity, label.getColor());
+    }
+    
+    /**
+     * 注册自定义状态映射
+     *
+     * @param type    状态类型
+     * @param mapping 状态映射
+     */
+    public static void registerStatusMapping(String type, Map<Integer, StatusLabel> mapping) {
+        STATUS_MAPPING.put(type, mapping);
+    }
+}

+ 91 - 0
haha-common/src/main/java/com/haha/common/vo/PageResult.java

@@ -0,0 +1,91 @@
+package com.haha.common.vo;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 分页响应结果
+ * 统一的分页数据返回格式
+ *
+ * @param <T> 数据类型
+ */
+@Data
+public class PageResult<T> implements Serializable {
+    
+    private static final long serialVersionUID = 1L;
+    
+    /**
+     * 数据列表
+     */
+    private List<T> list;
+    
+    /**
+     * 总记录数
+     */
+    private long total;
+    
+    /**
+     * 每页条数
+     */
+    private long pageSize;
+    
+    /**
+     * 当前页码
+     */
+    private long currentPage;
+    
+    /**
+     * 总页数
+     */
+    private long totalPages;
+
+    public PageResult() {
+    }
+
+    public PageResult(List<T> list, long total, long pageSize, long currentPage) {
+        this.list = list;
+        this.total = total;
+        this.pageSize = pageSize;
+        this.currentPage = currentPage;
+        this.totalPages = pageSize > 0 ? (total + pageSize - 1) / pageSize : 0;
+    }
+
+    /**
+     * 从MyBatis-Plus的IPage转换
+     *
+     * @param page IPage对象
+     * @param <T>  数据类型
+     * @return PageResult
+     */
+    public static <T> PageResult<T> of(IPage<T> page) {
+        PageResult<T> result = new PageResult<>();
+        result.setList(page.getRecords());
+        result.setTotal(page.getTotal());
+        result.setPageSize(page.getSize());
+        result.setCurrentPage(page.getCurrent());
+        result.setTotalPages(page.getPages());
+        return result;
+    }
+
+    /**
+     * 从MyBatis-Plus的IPage转换(带数据转换)
+     *
+     * @param page   IPage对象
+     * @param mapper 数据转换函数
+     * @param <T>    原始数据类型
+     * @param <R>    转换后数据类型
+     * @return PageResult
+     */
+    public static <T, R> PageResult<R> of(IPage<T> page, java.util.function.Function<T, R> mapper) {
+        PageResult<R> result = new PageResult<>();
+        result.setList(page.getRecords().stream().map(mapper).toList());
+        result.setTotal(page.getTotal());
+        result.setPageSize(page.getSize());
+        result.setCurrentPage(page.getCurrent());
+        result.setTotalPages(page.getPages());
+        return result;
+    }
+}

+ 61 - 0
haha-common/src/main/java/com/haha/common/vo/StatusLabel.java

@@ -0,0 +1,61 @@
+package com.haha.common.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 状态标签VO
+ * 用于前端展示状态的颜色和文本
+ */
+@Data
+public class StatusLabel implements Serializable {
+    
+    private static final long serialVersionUID = 1L;
+    
+    /**
+     * 状态文本
+     */
+    private String label;
+    
+    /**
+     * 状态颜色(success/warning/danger/info)
+     */
+    private String color;
+    
+    public StatusLabel() {
+    }
+    
+    public StatusLabel(String label, String color) {
+        this.label = label;
+        this.color = color;
+    }
+    
+    /**
+     * 创建成功状态
+     */
+    public static StatusLabel success(String label) {
+        return new StatusLabel(label, "success");
+    }
+    
+    /**
+     * 创建警告状态
+     */
+    public static StatusLabel warning(String label) {
+        return new StatusLabel(label, "warning");
+    }
+    
+    /**
+     * 创建危险状态
+     */
+    public static StatusLabel danger(String label) {
+        return new StatusLabel(label, "danger");
+    }
+    
+    /**
+     * 创建信息状态
+     */
+    public static StatusLabel info(String label) {
+        return new StatusLabel(label, "info");
+    }
+}

+ 6 - 7
haha-entity/pom.xml

@@ -16,17 +16,16 @@
     <description>实体模块 - 数据库实体类</description>
 
     <dependencies>
-        <!-- MyBatis Plus -->
+        <!-- haha-common 常量模块 -->
         <dependency>
-            <groupId>com.baomidou</groupId>
-            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
+            <groupId>com.haha</groupId>
+            <artifactId>haha-common</artifactId>
         </dependency>
 
-        <!-- Lombok -->
+        <!-- MyBatis Plus -->
         <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-            <optional>true</optional>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
         </dependency>
 
         <!-- FastJson -->

+ 18 - 9
haha-entity/src/main/java/com/haha/entity/Order.java

@@ -4,6 +4,7 @@ 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.haha.common.constant.OrderConstants;
 import lombok.Data;
 import java.io.Serializable;
 import java.time.LocalDateTime;
@@ -12,15 +13,23 @@ import java.time.LocalDateTime;
 @TableName("t_order")
 public class Order implements Serializable {
 
-    public static final String PAY_STATUS_未支付 = "UNPAID";
-    public static final String PAY_STATUS_已支付 = "PAID";
-    public static final String PAY_STATUS_已退款 = "REFUND";
-
-    // 订单状态:0-已取消,1-待支付,2-已完成,3-已关闭
-    public static final int ORDER_STATUS_已取消 = 0;
-    public static final int ORDER_STATUS_待支付 = 1;
-    public static final int ORDER_STATUS_已完成 = 2;
-    public static final int ORDER_STATUS_已关闭 = 3;
+    // ==================== 支付状态常量(已废弃,请使用 OrderConstants) ====================
+    @Deprecated
+    public static final String PAY_STATUS_未支付 = OrderConstants.PAY_STATUS_UNPAID;
+    @Deprecated
+    public static final String PAY_STATUS_已支付 = OrderConstants.PAY_STATUS_PAID;
+    @Deprecated
+    public static final String PAY_STATUS_已退款 = OrderConstants.PAY_STATUS_REFUND;
+
+    // ==================== 订单状态常量(已废弃,请使用 OrderConstants) ====================
+    @Deprecated
+    public static final int ORDER_STATUS_已取消 = OrderConstants.STATUS_CANCELLED;
+    @Deprecated
+    public static final int ORDER_STATUS_待支付 = OrderConstants.STATUS_PENDING_PAYMENT;
+    @Deprecated
+    public static final int ORDER_STATUS_已完成 = OrderConstants.STATUS_COMPLETED;
+    @Deprecated
+    public static final int ORDER_STATUS_已关闭 = OrderConstants.STATUS_CLOSED;
 
     private static final long serialVersionUID = 1L;
 

+ 0 - 7
haha-mapper/pom.xml

@@ -27,13 +27,6 @@
             <groupId>com.baomidou</groupId>
             <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
         </dependency>
-
-        <!-- Lombok -->
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-            <optional>true</optional>
-        </dependency>
     </dependencies>
 
 </project>

+ 19 - 0
haha-mapper/src/main/java/com/haha/mapper/OrderMapper.java

@@ -2,6 +2,25 @@ package com.haha.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.haha.entity.Order;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.time.LocalDateTime;
 
 public interface OrderMapper extends BaseMapper<Order> {
+    
+    /**
+     * 统计已完成订单的销售总额
+     * 
+     * @param startDate 开始时间(null表示统计全部)
+     * @return 销售总额
+     */
+    @Select("<script>" +
+            "SELECT COALESCE(SUM(total_amount), 0) FROM t_order " +
+            "WHERE status = 2 AND pay_status = 'PAID' " +
+            "<if test='startDate != null'>" +
+            "AND create_time &gt;= #{startDate} " +
+            "</if>" +
+            "</script>")
+    Double sumCompletedOrderAmount(@Param("startDate") LocalDateTime startDate);
 }

+ 1 - 26
haha-miniapp/pom.xml

@@ -11,24 +11,16 @@
         <relativePath>../pom.xml</relativePath>
     </parent>
 
-    <groupId>com.haha</groupId>
     <artifactId>haha-miniapp</artifactId>
-    <version>0.0.1-SNAPSHOT</version>
     <name>haha-miniapp</name>
     <description>智能视觉售卖机系统 - 用户端小程序后端</description>
 
-
-
     <dependencies>
-        <!-- 内部模块依赖 -->
+        <!-- 依赖Service模块 -->
         <dependency>
             <groupId>com.haha</groupId>
             <artifactId>haha-service</artifactId>
         </dependency>
-        <dependency>
-            <groupId>com.haha</groupId>
-            <artifactId>haha-common</artifactId>
-        </dependency>
 
         <!-- Spring Boot 核心依赖 -->
         <dependency>
@@ -50,17 +42,6 @@
             <groupId>com.mysql</groupId>
             <artifactId>mysql-connector-j</artifactId>
         </dependency>
-        <dependency>
-            <groupId>com.baomidou</groupId>
-            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
-        </dependency>
-
-        <!-- 工具类 -->
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-            <optional>true</optional>
-        </dependency>
 
         <!-- Redis 依赖 -->
         <dependency>
@@ -68,12 +49,6 @@
             <artifactId>spring-boot-starter-data-redis</artifactId>
         </dependency>
 
-        <!-- FastJson -->
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>fastjson</artifactId>
-        </dependency>
-
         <!-- Sa-Token 认证框架 -->
         <dependency>
             <groupId>cn.dev33</groupId>

+ 93 - 2
haha-miniapp/src/main/java/com/haha/miniapp/config/GlobalExceptionHandler.java

@@ -1,22 +1,46 @@
 package com.haha.miniapp.config;
 
 import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.exception.NotPermissionException;
+import com.haha.common.exception.BusinessException;
 import com.haha.common.vo.Result;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.BindException;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
 import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
 
+import java.util.stream.Collectors;
+
+/**
+ * 全局异常处理器
+ * 统一处理各类异常,返回规范的响应格式
+ */
 @Slf4j
 @RestControllerAdvice
 public class GlobalExceptionHandler {
 
+    /**
+     * 处理业务异常
+     */
+    @ExceptionHandler(BusinessException.class)
+    public Result<Void> handleBusinessException(BusinessException e) {
+        log.warn("业务异常: code={}, message={}", e.getCode(), e.getMessage());
+        return Result.error(e.getCode(), e.getMessage());
+    }
+
     /**
      * 处理 Sa-Token 未登录异常
      */
     @ExceptionHandler(NotLoginException.class)
+    @ResponseStatus(HttpStatus.UNAUTHORIZED)
     public Result<Void> handleNotLoginException(NotLoginException e) {
         log.warn("未登录异常: {}", e.getMessage());
-        // 根据异常类型返回不同的错误信息
         String message;
         if (e.getType().equals(NotLoginException.NOT_TOKEN)) {
             message = "未提供token";
@@ -30,12 +54,79 @@ public class GlobalExceptionHandler {
         return Result.error(401, message);
     }
 
+    /**
+     * 处理 Sa-Token 无权限异常
+     */
+    @ExceptionHandler(NotPermissionException.class)
+    @ResponseStatus(HttpStatus.FORBIDDEN)
+    public Result<Void> handleNotPermissionException(NotPermissionException e) {
+        log.warn("无权限异常: {}", e.getMessage());
+        return Result.error(403, "无访问权限");
+    }
+
+    /**
+     * 处理参数校验异常(@Valid)
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    public Result<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
+        String message = e.getBindingResult().getFieldErrors().stream()
+                .map(FieldError::getDefaultMessage)
+                .collect(Collectors.joining(", "));
+        log.warn("参数校验失败: {}", message);
+        return Result.error(400, message);
+    }
+
+    /**
+     * 处理参数绑定异常
+     */
+    @ExceptionHandler(BindException.class)
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    public Result<Void> handleBindException(BindException e) {
+        String message = e.getBindingResult().getFieldErrors().stream()
+                .map(FieldError::getDefaultMessage)
+                .collect(Collectors.joining(", "));
+        log.warn("参数绑定失败: {}", message);
+        return Result.error(400, message);
+    }
+
+    /**
+     * 处理缺少必需参数异常
+     */
+    @ExceptionHandler(MissingServletRequestParameterException.class)
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    public Result<Void> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
+        log.warn("缺少必需参数: {}", e.getParameterName());
+        return Result.error(400, "缺少必需参数: " + e.getParameterName());
+    }
+
+    /**
+     * 处理参数类型不匹配异常
+     */
+    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    public Result<Void> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
+        log.warn("参数类型不匹配: {}={}", e.getName(), e.getValue());
+        return Result.error(400, "参数类型错误: " + e.getName());
+    }
+
+    /**
+     * 处理非法参数异常
+     */
+    @ExceptionHandler(IllegalArgumentException.class)
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    public Result<Void> handleIllegalArgumentException(IllegalArgumentException e) {
+        log.warn("非法参数: {}", e.getMessage());
+        return Result.error(400, e.getMessage());
+    }
+
     /**
      * 处理其他所有异常
      */
     @ExceptionHandler(Exception.class)
+    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
     public Result<Void> handleException(Exception e) {
         log.error("系统异常: {}", e.getMessage(), e);
-        return Result.error(500, "系统内部错误");
+        return Result.error(500, "系统繁忙,请稍后重试");
     }
 }

+ 0 - 16
haha-sdk/pom.xml

@@ -17,39 +17,23 @@
     <name>haha-sdk</name>
     <description>哈哈零售系统 Java SDK</description>
 
-    <properties>
-        <okhttp.version>4.12.0</okhttp.version>
-        <fastjson2.version>2.0.53</fastjson2.version>
-        <slf4j.version>2.0.9</slf4j.version>
-    </properties>
-
     <dependencies>
         <!-- HTTP Client -->
         <dependency>
             <groupId>com.squareup.okhttp3</groupId>
             <artifactId>okhttp</artifactId>
-            <version>${okhttp.version}</version>
         </dependency>
 
         <!-- JSON Processing -->
         <dependency>
             <groupId>com.alibaba.fastjson2</groupId>
             <artifactId>fastjson2</artifactId>
-            <version>${fastjson2.version}</version>
-        </dependency>
-
-        <!-- Utils -->
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-            <scope>provided</scope>
         </dependency>
 
         <!-- Logging -->
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
-            <version>${slf4j.version}</version>
         </dependency>
     </dependencies>
 

+ 1 - 8
haha-service/pom.xml

@@ -34,7 +34,7 @@
             <artifactId>haha-sdk</artifactId>
         </dependency>
 
-        <!-- Spring Boot Web -->
+        <!-- Spring Boot Web - provided scope -->
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
@@ -77,13 +77,6 @@
             <artifactId>pagehelper</artifactId>
         </dependency>
 
-        <!-- Lombok -->
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-            <optional>true</optional>
-        </dependency>
-
         <!-- Spring Security Crypto (BCrypt密码加密) -->
         <dependency>
             <groupId>org.springframework.security</groupId>

+ 8 - 0
haha-service/src/main/java/com/haha/service/AdminService.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.haha.common.vo.Result;
 import com.haha.entity.Admin;
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -58,4 +59,11 @@ public interface AdminService extends IService<Admin> {
      * @return 统计数据
      */
     Result<Map<String, Object>> getStatistics();
+    
+    /**
+     * 获取可选的管理员列表(用于添加补货员)
+     * @param keyword 搜索关键字
+     * @return 管理员列表
+     */
+    List<Admin> getAvailableAdmins(String keyword);
 }

+ 57 - 0
haha-service/src/main/java/com/haha/service/DeviceService.java

@@ -1,13 +1,70 @@
 package com.haha.service;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.haha.entity.Device;
 import com.haha.common.vo.OpenDoorVO;
 import com.haha.sdk.exception.HahaException;
 
 import java.util.List;
+import java.util.Map;
 
 public interface DeviceService extends IService<Device> {
+    
+    /**
+     * 分页查询设备列表
+     *
+     * @param page     页码
+     * @param pageSize 每页条数
+     * @param deviceId 设备ID(模糊)
+     * @param shopId   门店ID
+     * @param status   状态
+     * @return 分页结果
+     */
+    IPage<Device> getPage(int page, int pageSize, String deviceId, Long shopId, Integer status);
+    
+    /**
+     * 获取设备详情(带标签填充)
+     *
+     * @param id 设备ID
+     * @return 设备详情
+     */
+    Device getDetailById(Long id);
+    
+    /**
+     * 获取设备统计数据
+     *
+     * @return 统计数据
+     */
+    Map<String, Object> getStatistics();
+    
+    /**
+     * 远程开门
+     *
+     * @param id       设备ID
+     * @param doorIndex 门索引
+     * @return 是否成功
+     */
+    boolean openDoor(Long id, String doorIndex);
+    
+    /**
+     * 设置温度
+     *
+     * @param id          设备ID
+     * @param temperature 温度值
+     * @return 是否成功
+     */
+    boolean setTemperature(Long id, Double temperature);
+    
+    /**
+     * 设置音量
+     *
+     * @param id     设备ID
+     * @param volume 音量值
+     * @return 是否成功
+     */
+    boolean setVolume(Long id, Integer volume);
+    
     List<Device> getNearbyDevices(Double longitude, Double latitude, Double distance);
     Device getDeviceBySn(String deviceId);
     boolean updateDeviceStatus(String deviceId, Integer status);

+ 44 - 0
haha-service/src/main/java/com/haha/service/OrderService.java

@@ -1,10 +1,54 @@
 package com.haha.service;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.haha.entity.Order;
+
 import java.util.List;
+import java.util.Map;
 
 public interface OrderService extends IService<Order> {
+    
+    /**
+     * 分页查询订单列表
+     *
+     * @param page     页码
+     * @param pageSize 每页条数
+     * @param orderNo  订单号
+     * @param deviceId 设备ID
+     * @param payStatus 支付状态
+     * @param status   订单状态
+     * @param startDate 开始日期
+     * @param endDate   结束日期
+     * @return 分页结果
+     */
+    IPage<Order> getPage(int page, int pageSize, String orderNo, String deviceId, 
+                         String payStatus, Integer status, String startDate, String endDate);
+    
+    /**
+     * 获取订单详情(带标签填充)
+     *
+     * @param id 订单ID
+     * @return 订单详情
+     */
+    Order getDetailById(Long id);
+    
+    /**
+     * 获取订单统计数据
+     *
+     * @return 统计数据
+     */
+    Map<String, Object> getStatistics();
+    
+    /**
+     * 订单退款
+     *
+     * @param orderId 订单ID
+     * @param reason  退款原因
+     * @return 是否成功
+     */
+    boolean refund(Long orderId, String reason);
+    
     List<Order> getOrderListByUserId(Long userId, Integer status);
     boolean cancelOrder(Long orderId);
     boolean updateOrderStatus(Long orderId, Integer status);

+ 65 - 0
haha-service/src/main/java/com/haha/service/ProductService.java

@@ -1,11 +1,76 @@
 package com.haha.service;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.haha.entity.Product;
+
 import java.util.List;
+import java.util.Map;
 
 public interface ProductService extends IService<Product> {
     
+    /**
+     * 分页查询商品列表
+     *
+     * @param page       页码
+     * @param pageSize   每页条数
+     * @param name       商品名称
+     * @param barcode    条码
+     * @param category   分类
+     * @param syncStatus 同步状态
+     * @return 分页结果
+     */
+    IPage<Product> getPage(int page, int pageSize, String name, String barcode, 
+                           String category, Integer syncStatus);
+    
+    /**
+     * 获取商品详情(带标签填充)
+     *
+     * @param id 商品ID
+     * @return 商品详情
+     */
+    Product getDetailById(Long id);
+    
+    /**
+     * 获取商品统计数据
+     *
+     * @return 统计数据
+     */
+    Map<String, Object> getStatistics();
+    
+    /**
+     * 添加商品
+     *
+     * @param product 商品信息
+     * @return 添加后的商品
+     */
+    Product add(Product product);
+    
+    /**
+     * 编辑商品
+     *
+     * @param id      商品ID
+     * @param product 商品信息
+     * @return 编辑后的商品
+     */
+    Product edit(Long id, Product product);
+    
+    /**
+     * 删除商品(软删除)
+     *
+     * @param id 商品ID
+     * @return 是否成功
+     */
+    boolean softDelete(Long id);
+    
+    /**
+     * 同步商品到哈哈平台
+     *
+     * @param id 商品ID
+     * @return 是否成功
+     */
+    boolean syncToHaha(Long id);
+    
     /**
      * 根据设备ID获取商品列表
      */

+ 24 - 0
haha-service/src/main/java/com/haha/service/ShopService.java

@@ -22,6 +22,30 @@ public interface ShopService extends IService<Shop> {
      */
     IPage<Shop> getPage(int page, int pageSize, Map<String, Object> params);
 
+    /**
+     * 根据门店名称查询(支持模糊)
+     *
+     * @param name 门店名称
+     * @return 门店列表
+     */
+    List<Shop> queryByName(String name);
+
+    /**
+     * 根据城市查询门店
+     *
+     * @param city 城市
+     * @return 门店列表
+     */
+    List<Shop> queryByCity(String city);
+
+    /**
+     * 根据状态查询门店
+     *
+     * @param status 状态
+     * @return 门店列表
+     */
+    List<Shop> queryByStatus(Integer status);
+
     /**
      * 查询门店详情(带设备统计)
      *

+ 20 - 5
haha-service/src/main/java/com/haha/service/impl/AdminServiceImpl.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.haha.common.constant.CommonConstants;
 import com.haha.common.vo.Result;
 import com.haha.entity.Admin;
 import com.haha.mapper.AdminMapper;
@@ -15,6 +16,7 @@ import org.springframework.util.StringUtils;
 
 import java.time.LocalDateTime;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -83,14 +85,14 @@ public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements
             }
 
             // 设置默认值
-            admin.setStatus(1); // 默认正常状态
+            admin.setStatus(CommonConstants.STATUS_ENABLED); // 默认正常状态
             admin.setCreateTime(LocalDateTime.now());
             admin.setUpdateTime(LocalDateTime.now());
 
             // BCrypt加密密码
             String password = admin.getPassword();
             if (!StringUtils.hasText(password)) {
-                password = "123456"; // 默认密码
+                password = CommonConstants.DEFAULT_PASSWORD;
             }
             admin.setPassword(passwordEncoder.encode(password));
 
@@ -171,7 +173,7 @@ public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements
 
             // BCrypt加密密码
             if (!StringUtils.hasText(newPassword)) {
-                newPassword = "123456"; // 默认密码
+                newPassword = CommonConstants.DEFAULT_PASSWORD;
             }
             admin.setPassword(passwordEncoder.encode(newPassword));
             admin.setUpdateTime(LocalDateTime.now());
@@ -195,11 +197,11 @@ public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements
             statistics.put("total", total);
 
             // 正常状态管理员数
-            long active = this.count(new LambdaQueryWrapper<Admin>().eq(Admin::getStatus, 1));
+            long active = this.count(new LambdaQueryWrapper<Admin>().eq(Admin::getStatus, CommonConstants.STATUS_ENABLED));
             statistics.put("active", active);
 
             // 禁用状态管理员数
-            long disabled = this.count(new LambdaQueryWrapper<Admin>().eq(Admin::getStatus, 2));
+            long disabled = this.count(new LambdaQueryWrapper<Admin>().eq(Admin::getStatus, CommonConstants.ADMIN_STATUS_DISABLED));
             statistics.put("disabled", disabled);
 
             // 今日登录数(暂时返回0,后续可通过Redis统计)
@@ -212,4 +214,17 @@ public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements
             return Result.error(500, "获取统计数据失败: " + e.getMessage());
         }
     }
+
+    @Override
+    public List<Admin> getAvailableAdmins(String keyword) {
+        LambdaQueryWrapper<Admin> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(Admin::getStatus, CommonConstants.STATUS_ENABLED); // 只查询正常状态的管理员
+        if (StringUtils.hasText(keyword)) {
+            wrapper.and(w -> w.like(Admin::getRealName, keyword)
+                    .or().like(Admin::getPhone, keyword)
+                    .or().like(Admin::getUsername, keyword));
+        }
+        wrapper.orderByDesc(Admin::getCreateTime);
+        return this.list(wrapper);
+    }
 }

+ 8 - 13
haha-service/src/main/java/com/haha/service/impl/DataSyncServiceImpl.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.haha.common.exception.BusinessException;
 import com.haha.entity.Device;
 import com.haha.entity.Product;
 import com.haha.entity.SyncLog;
@@ -17,8 +18,8 @@ import com.haha.sdk.model.DeviceInfo;
 import com.haha.service.DataSyncService;
 import com.haha.service.DeviceService;
 import com.haha.service.ProductService;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -32,19 +33,13 @@ import java.util.Map;
  */
 @Slf4j
 @Service
+@RequiredArgsConstructor
 public class DataSyncServiceImpl extends ServiceImpl<SyncRecordMapper, SyncRecord> implements DataSyncService {
 
-    @Autowired
-    private HahaClient hahaClient;
-
-    @Autowired
-    private DeviceService deviceService;
-
-    @Autowired
-    private ProductService productService;
-
-    @Autowired
-    private SyncLogMapper syncLogMapper;
+    private final HahaClient hahaClient;
+    private final DeviceService deviceService;
+    private final ProductService productService;
+    private final SyncLogMapper syncLogMapper;
 
     /**
      * 同步状态常量
@@ -371,7 +366,7 @@ public class DataSyncServiceImpl extends ServiceImpl<SyncRecordMapper, SyncRecor
         log.debug("同步商品: {} - {}", code, name);
 
         if (code == null || code.isEmpty()) {
-            throw new RuntimeException("商品编码为空");
+            throw new BusinessException(400, "商品编码为空");
         }
 
         // 查询本地是否已存在该商品

+ 174 - 9
haha-service/src/main/java/com/haha/service/impl/DeviceServiceImpl.java

@@ -1,35 +1,137 @@
 package com.haha.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.haha.common.constant.DeviceConstants;
+import com.haha.common.constant.OrderConstants;
 import com.haha.common.exception.BusinessException;
+import com.haha.common.utils.EntityLabelUtils;
 import com.haha.entity.Device;
 import com.haha.entity.Order;
+import com.haha.entity.Shop;
 import com.haha.mapper.DeviceMapper;
 import com.haha.service.DeviceService;
 import com.haha.service.OrderService;
+import com.haha.service.ShopService;
 import com.haha.common.utils.OrderUtils;
 import com.haha.common.vo.OpenDoorVO;
 import com.haha.sdk.HahaClient;
 import com.haha.sdk.exception.HahaException;
 import com.haha.sdk.model.DeviceOnlineStatus;
 import com.haha.sdk.model.OpenDoorResult;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 @Slf4j
 @Service
+@RequiredArgsConstructor
 public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {
 
-    @Autowired
-    private HahaClient hahaClient;
+    private final HahaClient hahaClient;
+    private final OrderService orderService;
+    private final ShopService shopService;
 
-    @Autowired
-    private OrderService orderService;
+    @Override
+    public IPage<Device> getPage(int page, int pageSize, String deviceId, Long shopId, Integer status) {
+        LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
+        
+        wrapper.like(deviceId != null && !deviceId.isEmpty(), Device::getDeviceId, deviceId)
+               .eq(shopId != null, Device::getShopId, shopId)
+               .eq(status != null, Device::getStatus, status)
+               .orderByDesc(Device::getCreateTime);
+
+        IPage<Device> devicePage = this.page(new Page<>(page, pageSize), wrapper);
+        
+        // 填充额外字段
+        devicePage.getRecords().forEach(this::fillDeviceLabels);
+        
+        return devicePage;
+    }
+
+    @Override
+    public Device getDetailById(Long id) {
+        Device device = this.getById(id);
+        if (device == null) {
+            return null;
+        }
+        fillDeviceLabels(device);
+        return device;
+    }
+
+    @Override
+    public Map<String, Object> getStatistics() {
+        Map<String, Object> statistics = new HashMap<>();
+
+        // 总设备数
+        long total = this.count();
+        statistics.put("total", total);
+
+        // 在线设备数
+        long online = this.lambdaQuery()
+                .eq(Device::getStatus, DeviceConstants.STATUS_ONLINE)
+                .count();
+        statistics.put("online", online);
+
+        // 离线设备数
+        statistics.put("offline", total - online);
+
+        // TODO: 后续从订单服务获取销售额数据
+        statistics.put("totalSales", "0.00");
+        statistics.put("todaySales", "0.00");
+        statistics.put("avgTemperature", "0.0");
+
+        return statistics;
+    }
+
+    @Override
+    public boolean openDoor(Long id, String doorIndex) {
+        Device device = this.getById(id);
+        if (device == null) {
+            throw new BusinessException(404, "设备不存在");
+        }
+        
+        log.info("远程开门: deviceId={}, doorIndex={}", device.getDeviceId(), doorIndex);
+        
+        // TODO: 调用SDK发送开门指令
+        
+        return true;
+    }
+
+    @Override
+    public boolean setTemperature(Long id, Double temperature) {
+        Device device = this.getById(id);
+        if (device == null) {
+            throw new BusinessException(404, "设备不存在");
+        }
+        
+        log.info("设置温度: deviceId={}, temperature={}", device.getDeviceId(), temperature);
+        
+        // TODO: 调用SDK设置温度
+        
+        return true;
+    }
+
+    @Override
+    public boolean setVolume(Long id, Integer volume) {
+        Device device = this.getById(id);
+        if (device == null) {
+            throw new BusinessException(404, "设备不存在");
+        }
+        
+        log.info("设置音量: deviceId={}, volume={}", device.getDeviceId(), volume);
+        
+        // TODO: 调用SDK设置音量
+        
+        return true;
+    }
 
     @Override
     public List<Device> getNearbyDevices(Double longitude, Double latitude, Double distance) {
@@ -75,7 +177,7 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
 
         // 如果是多门单开设备,默认打开A门
         if (multiDoorType != null && multiDoorType > 0) {
-            doorIndex = "A";
+            doorIndex = DeviceConstants.DOOR_A;
             log.info("设备 {} 是多门单开设备,类型: {},将打开A门", deviceId, multiDoorType);
         }
 
@@ -92,8 +194,8 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
 //         order.setOutTradeNo(""); todo 收到支付完成的通知时更新为支付订单号
         order.setUserId(userId);
         order.setDeviceId(deviceId);
-        order.setStatus(Order.ORDER_STATUS_待支付);
-        order.setPayStatus(Order.PAY_STATUS_未支付);
+        order.setStatus(OrderConstants.STATUS_PENDING_PAYMENT);
+        order.setPayStatus(OrderConstants.PAY_STATUS_UNPAID);
         order.setCreateTime(LocalDateTime.now());
 
         boolean saved = orderService.save(order);
@@ -109,7 +211,7 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
             .activityId(openResult.getActivityId())
             .userId(openResult.getUserId())
             .deviceId(deviceId)
-            .doorIndex(doorIndex != null ? doorIndex : "A")
+            .doorIndex(doorIndex != null ? doorIndex : DeviceConstants.DEFAULT_DOOR_INDEX)
             .build();
     }
 
@@ -155,4 +257,67 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
         wrapper.orderByDesc(Device::getCreateTime);
         return this.list(wrapper);
     }
+
+    /**
+     * 填充设备标签字段
+     */
+    private void fillDeviceLabels(Device device) {
+        // 设备状态标签
+        if (device.getStatus() != null) {
+            var statusLabel = EntityLabelUtils.getStatusLabel("device", device.getStatus());
+            device.setStatusLabel(statusLabel.getLabel());
+            device.setStatusColor(statusLabel.getColor());
+            device.setIsOnline(DeviceConstants.isOnline(device.getStatus()));
+        }
+        
+        // 填充门店信息
+        if (device.getShopId() != null && device.getShopName() == null) {
+            Shop shop = shopService.getById(device.getShopId());
+            if (shop != null) {
+                device.setShopName(shop.getName());
+                if (device.getAddress() == null) {
+                    device.setAddress(shop.getAddress());
+                }
+            }
+        }
+        
+        // 设置默认值
+        setDefaultValues(device);
+    }
+    
+    /**
+     * 设置设备默认值
+     */
+    private void setDefaultValues(Device device) {
+        if (device.getShopName() == null) {
+            device.setShopName("默认门店");
+        }
+        if (device.getAddress() == null) {
+            device.setAddress("-");
+        }
+        if (device.getDeviceTypeLabel() == null) {
+            device.setDeviceTypeLabel(DeviceConstants.TYPE_SMART_CABINET);
+        }
+        if (device.getTemperature() == null) {
+            device.setTemperature("0.0");
+        }
+        if (device.getVolume() == null) {
+            device.setVolume(8);
+        }
+        if (device.getDoorCount() == null) {
+            device.setDoorCount(1);
+        }
+        if (device.getLayerCount() == null) {
+            device.setLayerCount(5);
+        }
+        if (device.getTotalSales() == null) {
+            device.setTotalSales("0.00");
+        }
+        if (device.getTodaySales() == null) {
+            device.setTodaySales("0.00");
+        }
+        if (device.getOrderCount() == null) {
+            device.setOrderCount(0);
+        }
+    }
 }

+ 5 - 4
haha-service/src/main/java/com/haha/service/impl/NewProductApplyServiceImpl.java

@@ -5,13 +5,14 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.haha.common.exception.BusinessException;
 import com.haha.entity.NewProductApply;
 import com.haha.mapper.NewProductApplyMapper;
 import com.haha.sdk.HahaClient;
 import com.haha.sdk.exception.HahaException;
 import com.haha.service.NewProductApplyService;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
@@ -26,10 +27,10 @@ import java.util.Map;
  */
 @Slf4j
 @Service
+@RequiredArgsConstructor
 public class NewProductApplyServiceImpl extends ServiceImpl<NewProductApplyMapper, NewProductApply> implements NewProductApplyService {
 
-    @Autowired
-    private HahaClient hahaClient;
+    private final HahaClient hahaClient;
 
     @Override
     public IPage<NewProductApply> getPage(int page, int pageSize, Map<String, Object> params) {
@@ -163,7 +164,7 @@ public class NewProductApplyServiceImpl extends ServiceImpl<NewProductApplyMappe
             apply.setStatus(0);
             apply.setUpdateTime(LocalDateTime.now());
             updateById(apply);
-            throw new RuntimeException("新品申请提交失败: " + e.getMessage());
+            throw new BusinessException(500, "新品申请提交失败: " + e.getMessage());
         }
         
         return apply.getId();

+ 145 - 1
haha-service/src/main/java/com/haha/service/impl/OrderServiceImpl.java

@@ -1,16 +1,146 @@
 package com.haha.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.haha.common.constant.OrderConstants;
+import com.haha.common.exception.BusinessException;
+import com.haha.common.utils.EntityLabelUtils;
 import com.haha.entity.Order;
 import com.haha.mapper.OrderMapper;
 import com.haha.service.OrderService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
+@Slf4j
 @Service
+@RequiredArgsConstructor
 public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
 
+    @Override
+    public IPage<Order> getPage(int page, int pageSize, String orderNo, String deviceId, 
+                                 String payStatus, Integer status, String startDate, String endDate) {
+        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
+        
+        // 构建查询条件
+        wrapper.like(orderNo != null && !orderNo.isEmpty(), Order::getOrderNo, orderNo)
+               .like(deviceId != null && !deviceId.isEmpty(), Order::getDeviceId, deviceId)
+               .eq(payStatus != null && !payStatus.isEmpty(), Order::getPayStatus, payStatus)
+               .eq(status != null, Order::getStatus, status);
+
+        // 时间范围查询
+        if (startDate != null && !startDate.isEmpty()) {
+            LocalDateTime startDateTime = LocalDate.parse(startDate).atStartOfDay();
+            wrapper.ge(Order::getCreateTime, startDateTime);
+        }
+        if (endDate != null && !endDate.isEmpty()) {
+            LocalDateTime endDateTime = LocalDate.parse(endDate).atTime(LocalTime.MAX);
+            wrapper.le(Order::getCreateTime, endDateTime);
+        }
+
+        // 按创建时间倒序
+        wrapper.orderByDesc(Order::getCreateTime);
+
+        // 分页查询
+        IPage<Order> orderPage = this.page(new Page<>(page, pageSize), wrapper);
+        
+        // 填充标签字段
+        orderPage.getRecords().forEach(this::fillOrderLabels);
+        
+        return orderPage;
+    }
+
+    @Override
+    public Order getDetailById(Long id) {
+        Order order = this.getById(id);
+        if (order == null) {
+            return null;
+        }
+        fillOrderLabels(order);
+        return order;
+    }
+
+    @Override
+    public Map<String, Object> getStatistics() {
+        Map<String, Object> statistics = new HashMap<>();
+        LocalDateTime todayStart = LocalDate.now().atStartOfDay();
+
+        // 总订单数
+        long totalOrders = this.count();
+        statistics.put("totalOrders", totalOrders);
+
+        // 今日订单数
+        long todayOrders = this.lambdaQuery()
+                .ge(Order::getCreateTime, todayStart)
+                .count();
+        statistics.put("todayOrders", todayOrders);
+
+        // 各状态订单数
+        long unpaidOrders = this.lambdaQuery()
+                .eq(Order::getPayStatus, OrderConstants.PAY_STATUS_UNPAID)
+                .count();
+        statistics.put("unpaidOrders", unpaidOrders);
+
+        long completedOrders = this.lambdaQuery()
+                .eq(Order::getStatus, OrderConstants.STATUS_COMPLETED)
+                .count();
+        statistics.put("completedOrders", completedOrders);
+
+        long cancelledOrders = this.lambdaQuery()
+                .eq(Order::getStatus, OrderConstants.STATUS_CANCELLED)
+                .count();
+        statistics.put("cancelledOrders", cancelledOrders);
+
+        long refundOrders = this.lambdaQuery()
+                .eq(Order::getPayStatus, OrderConstants.PAY_STATUS_REFUND)
+                .count();
+        statistics.put("refundOrders", refundOrders);
+
+        // 总销售额(使用SQL聚合优化性能)
+        Double totalAmount = baseMapper.sumCompletedOrderAmount(null);
+        statistics.put("totalAmount", String.format("%.2f", totalAmount != null ? totalAmount : 0));
+
+        // 今日销售额
+        Double todayAmount = baseMapper.sumCompletedOrderAmount(todayStart);
+        statistics.put("todayAmount", String.format("%.2f", todayAmount != null ? todayAmount : 0));
+
+        // 平均订单金额
+        double averageAmount = completedOrders > 0 ? (totalAmount != null ? totalAmount : 0) / completedOrders : 0;
+        statistics.put("averageAmount", String.format("%.2f", averageAmount));
+
+        return statistics;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean refund(Long orderId, String reason) {
+        Order order = this.getById(orderId);
+        if (order == null) {
+            throw new BusinessException(404, "订单不存在");
+        }
+
+        // 检查订单状态
+        if (!OrderConstants.PAY_STATUS_PAID.equals(order.getPayStatus())) {
+            throw new BusinessException(400, "只有已支付的订单才能退款");
+        }
+
+        log.info("订单退款: orderId={}, orderNo={}, reason={}", orderId, order.getOrderNo(), reason);
+
+        // 更新支付状态为已退款
+        return this.updatePayStatus(order.getOrderNo(), OrderConstants.PAY_STATUS_REFUND);
+    }
+
     @Override
     public List<Order> getOrderListByUserId(Long userId, Integer status) {
         if (status != null) {
@@ -22,7 +152,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
 
     @Override
     public boolean cancelOrder(Long orderId) {
-        return lambdaUpdate().eq(Order::getId, orderId).set(Order::getStatus, 2).update();
+        return lambdaUpdate().eq(Order::getId, orderId).set(Order::getStatus, OrderConstants.STATUS_CANCELLED).update();
     }
 
     @Override
@@ -44,4 +174,18 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
     public boolean updatePayStatus(String orderNo, String payStatus) {
         return lambdaUpdate().eq(Order::getOrderNo, orderNo).set(Order::getPayStatus, payStatus).update();
     }
+
+    /**
+     * 填充订单标签字段
+     */
+    private void fillOrderLabels(Order order) {
+        if (order.getPayStatus() != null) {
+            var payLabel = EntityLabelUtils.getPayStatusLabel(order.getPayStatus());
+            order.setPayStatusLabel(payLabel.getLabel());
+        }
+        if (order.getStatus() != null) {
+            var statusLabel = EntityLabelUtils.getStatusLabel("order", order.getStatus());
+            order.setStatusLabel(statusLabel.getLabel());
+        }
+    }
 }

+ 144 - 0
haha-service/src/main/java/com/haha/service/impl/ProductServiceImpl.java

@@ -1,17 +1,133 @@
 package com.haha.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.haha.common.constant.CommonConstants;
+import com.haha.common.constant.SyncConstants;
+import com.haha.common.exception.BusinessException;
+import com.haha.common.utils.EntityLabelUtils;
 import com.haha.entity.Product;
 import com.haha.mapper.ProductMapper;
 import com.haha.service.ProductService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
+@Slf4j
 @Service
+@RequiredArgsConstructor
 public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
 
+    @Override
+    public IPage<Product> getPage(int page, int pageSize, String name, String barcode, 
+                                   String category, Integer syncStatus) {
+        LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<>();
+        
+        wrapper.like(name != null && !name.isEmpty(), Product::getName, name)
+               .like(barcode != null && !barcode.isEmpty(), Product::getBarcode, barcode)
+               .eq(category != null && !category.isEmpty(), Product::getType, category)
+               .eq(syncStatus != null, Product::getSyncStatus, syncStatus)
+               .eq(Product::getIsDeleted, CommonConstants.NOT_DELETED)
+               .orderByDesc(Product::getCreateTime);
+
+        IPage<Product> productPage = this.page(new Page<>(page, pageSize), wrapper);
+        
+        // 填充额外字段
+        productPage.getRecords().forEach(this::fillProductLabels);
+        
+        return productPage;
+    }
+
+    @Override
+    public Product getDetailById(Long id) {
+        Product product = this.getById(id);
+        if (product == null) {
+            return null;
+        }
+        fillProductLabels(product);
+        return product;
+    }
+
+    @Override
+    public Map<String, Object> getStatistics() {
+        Map<String, Object> statistics = new HashMap<>();
+
+        // 总商品数(未删除)
+        long totalProducts = this.lambdaQuery()
+                .eq(Product::getIsDeleted, CommonConstants.NOT_DELETED)
+                .count();
+        statistics.put("totalProducts", totalProducts);
+
+        // 已同步商品数
+        long syncedProducts = this.lambdaQuery()
+                .eq(Product::getIsDeleted, CommonConstants.NOT_DELETED)
+                .eq(Product::getSyncStatus, SyncConstants.STATUS_SYNCED)
+                .count();
+        statistics.put("syncedProducts", syncedProducts);
+
+        return statistics;
+    }
+
+    @Override
+    public Product add(Product product) {
+        product.setIsDeleted(CommonConstants.NOT_DELETED);
+        product.setSyncStatus(SyncConstants.STATUS_NOT_SYNCED);
+        product.setCreateTime(LocalDateTime.now());
+        product.setUpdateTime(LocalDateTime.now());
+        
+        this.save(product);
+        return product;
+    }
+
+    @Override
+    public Product edit(Long id, Product product) {
+        Product existing = this.getById(id);
+        if (existing == null) {
+            throw new BusinessException(404, "商品不存在");
+        }
+        
+        product.setId(id);
+        product.setUpdateTime(LocalDateTime.now());
+        
+        this.updateById(product);
+        return product;
+    }
+
+    @Override
+    public boolean softDelete(Long id) {
+        Product product = this.getById(id);
+        if (product == null) {
+            throw new BusinessException(404, "商品不存在");
+        }
+        
+        product.setIsDeleted(CommonConstants.DELETED);
+        product.setUpdateTime(LocalDateTime.now());
+        
+        return this.updateById(product);
+    }
+
+    @Override
+    public boolean syncToHaha(Long id) {
+        Product product = this.getById(id);
+        if (product == null) {
+            throw new BusinessException(404, "商品不存在");
+        }
+        
+        log.info("同步商品到哈哈平台: productId={}, name={}", id, product.getName());
+
+        // TODO: 调用SDK同步商品到哈哈平台
+
+        // 更新同步状态
+        return this.updateSyncStatus(id, SyncConstants.STATUS_SYNCED);
+    }
+
     @Override
     public List<Product> getProductListBydeviceId(String deviceId) {
         // 这里需要实现根据设备SN获取商品列表的逻辑,暂时返回所有商品
@@ -48,4 +164,32 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
                 .set(Product::getSyncTime, LocalDateTime.now())
                 .update();
     }
+
+    /**
+     * 填充商品标签字段
+     */
+    private void fillProductLabels(Product product) {
+        // 同步状态标签
+        if (product.getSyncStatus() != null) {
+            var statusLabel = EntityLabelUtils.getStatusLabel("sync", product.getSyncStatus());
+            product.setSyncStatusLabel(statusLabel.getLabel());
+            product.setSyncStatusColor(statusLabel.getColor());
+        }
+
+        // 图片URL
+        if (product.getImageUrl() == null && product.getPic() != null) {
+            product.setImageUrl(product.getPic());
+        }
+
+        // 默认值
+        if (product.getCategory() == null) {
+            product.setCategory(product.getType());
+        }
+        if (product.getPrice() == null && product.getRetailPrice() != null) {
+            product.setPrice(product.getRetailPrice());
+        }
+        if (product.getCost() == null && product.getCostPrice() != null) {
+            product.setCost(product.getCostPrice());
+        }
+    }
 }

+ 77 - 63
haha-service/src/main/java/com/haha/service/impl/ShopReplenisherServiceImpl.java

@@ -2,14 +2,15 @@ package com.haha.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.haha.common.exception.BusinessException;
 import com.haha.common.vo.Result;
 import com.haha.entity.ShopReplenisher;
 import com.haha.entity.Admin;
 import com.haha.mapper.ShopReplenisherMapper;
 import com.haha.service.ShopReplenisherService;
 import com.haha.service.AdminService;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -22,13 +23,11 @@ import java.util.List;
  */
 @Slf4j
 @Service
+@RequiredArgsConstructor
 public class ShopReplenisherServiceImpl extends ServiceImpl<ShopReplenisherMapper, ShopReplenisher> implements ShopReplenisherService {
 
-    @Autowired
-    private ShopReplenisherMapper shopReplenisherMapper;
-
-    @Autowired
-    private AdminService adminService;
+    private final ShopReplenisherMapper shopReplenisherMapper;
+    private final AdminService adminService;
 
     @Override
     public List<ShopReplenisher> getReplenishersByShopId(Long shopId) {
@@ -49,70 +48,87 @@ public class ShopReplenisherServiceImpl extends ServiceImpl<ShopReplenisherMappe
     }
 
     @Override
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     public Result<String> addReplenisher(Long shopId, Long adminId) {
-        try {
+        // 检查管理员是否存在
+        Admin admin = adminService.getById(adminId);
+        if (admin == null) {
+            throw new BusinessException(404, "管理员不存在");
+        }
+
+        // 检查是否已存在
+        int count = shopReplenisherMapper.countByShopIdAndAdminId(shopId, adminId);
+        if (count > 0) {
+            throw new BusinessException(400, "该管理员已是此门店的补货员");
+        }
+
+        // 创建关联
+        ShopReplenisher replenisher = new ShopReplenisher();
+        replenisher.setShopId(shopId);
+        replenisher.setAdminId(adminId);
+        replenisher.setStatus(1);
+        replenisher.setCreateTime(LocalDateTime.now());
+        replenisher.setUpdateTime(LocalDateTime.now());
+
+        boolean success = this.save(replenisher);
+        return success ? Result.success("添加成功") : Result.error(500, "添加失败");
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int batchAddReplenishers(Long shopId, List<Long> adminIds) {
+        if (adminIds == null || adminIds.isEmpty()) {
+            return 0;
+        }
+        
+        List<ShopReplenisher> toAdd = new ArrayList<>();
+        LocalDateTime now = LocalDateTime.now();
+        
+        for (Long adminId : adminIds) {
             // 检查管理员是否存在
             Admin admin = adminService.getById(adminId);
             if (admin == null) {
-                return Result.error(404, "管理员不存在");
+                log.warn("管理员不存在: adminId={}", adminId);
+                continue;
             }
-
+            
             // 检查是否已存在
             int count = shopReplenisherMapper.countByShopIdAndAdminId(shopId, adminId);
             if (count > 0) {
-                return Result.error(400, "该管理员已是此门店的补货员");
+                log.warn("该管理员已是此门店的补货员: shopId={}, adminId={}", shopId, adminId);
+                continue;
             }
-
-            // 创建关联
+            
             ShopReplenisher replenisher = new ShopReplenisher();
             replenisher.setShopId(shopId);
             replenisher.setAdminId(adminId);
             replenisher.setStatus(1);
-            replenisher.setCreateTime(LocalDateTime.now());
-            replenisher.setUpdateTime(LocalDateTime.now());
-
-            boolean success = this.save(replenisher);
-            return success ? Result.success("添加成功") : Result.error(500, "添加失败");
-
-        } catch (Exception e) {
-            log.error("添加补货员失败: shopId={}, adminId={}, error={}", shopId, adminId, e.getMessage(), e);
-            return Result.error(500, "添加失败: " + e.getMessage());
+            replenisher.setCreateTime(now);
+            replenisher.setUpdateTime(now);
+            toAdd.add(replenisher);
         }
-    }
-
-    @Override
-    @Transactional
-    public int batchAddReplenishers(Long shopId, List<Long> adminIds) {
-        int successCount = 0;
-        for (Long adminId : adminIds) {
-            Result<String> result = addReplenisher(shopId, adminId);
-            if (result.getCode() == 200) {
-                successCount++;
-            }
+        
+        if (!toAdd.isEmpty()) {
+            this.saveBatch(toAdd);
         }
-        return successCount;
+        
+        log.info("批量添加补货员完成: shopId={}, 总数={}, 成功={}", shopId, adminIds.size(), toAdd.size());
+        return toAdd.size();
     }
 
     @Override
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     public Result<String> removeReplenisher(Long shopId, Long adminId) {
-        try {
-            LambdaQueryWrapper<ShopReplenisher> wrapper = new LambdaQueryWrapper<>();
-            wrapper.eq(ShopReplenisher::getShopId, shopId)
-                    .eq(ShopReplenisher::getAdminId, adminId);
-
-            boolean success = this.remove(wrapper);
-            return success ? Result.success("移除成功") : Result.error(500, "移除失败");
+        LambdaQueryWrapper<ShopReplenisher> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(ShopReplenisher::getShopId, shopId)
+                .eq(ShopReplenisher::getAdminId, adminId);
 
-        } catch (Exception e) {
-            log.error("移除补货员失败: shopId={}, adminId={}, error={}", shopId, adminId, e.getMessage(), e);
-            return Result.error(500, "移除失败: " + e.getMessage());
-        }
+        boolean success = this.remove(wrapper);
+        return success ? Result.success("移除成功") : Result.error(500, "移除失败");
     }
 
     @Override
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     public int batchRemoveReplenishers(Long shopId, List<Long> adminIds) {
         if (adminIds == null || adminIds.isEmpty()) {
             return 0;
@@ -122,28 +138,26 @@ public class ShopReplenisherServiceImpl extends ServiceImpl<ShopReplenisherMappe
         wrapper.eq(ShopReplenisher::getShopId, shopId)
                 .in(ShopReplenisher::getAdminId, adminIds);
 
-        return (int) this.count(wrapper);
+        long count = this.count(wrapper);
+        this.remove(wrapper);
+        
+        log.info("批量移除补货员完成: shopId={}, 总数={}, 成功={}", shopId, adminIds.size(), count);
+        return (int) count;
     }
 
     @Override
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     public Result<String> updateStatus(Long id, Integer status) {
-        try {
-            ShopReplenisher replenisher = this.getById(id);
-            if (replenisher == null) {
-                return Result.error(404, "记录不存在");
-            }
-
-            replenisher.setStatus(status);
-            replenisher.setUpdateTime(LocalDateTime.now());
+        ShopReplenisher replenisher = this.getById(id);
+        if (replenisher == null) {
+            throw new BusinessException(404, "记录不存在");
+        }
 
-            boolean success = this.updateById(replenisher);
-            return success ? Result.success("状态更新成功") : Result.error(500, "状态更新失败");
+        replenisher.setStatus(status);
+        replenisher.setUpdateTime(LocalDateTime.now());
 
-        } catch (Exception e) {
-            log.error("更新补货员状态失败: id={}, error={}", id, e.getMessage(), e);
-            return Result.error(500, "更新失败: " + e.getMessage());
-        }
+        boolean success = this.updateById(replenisher);
+        return success ? Result.success("状态更新成功") : Result.error(500, "状态更新失败");
     }
 
     @Override

+ 72 - 37
haha-service/src/main/java/com/haha/service/impl/ShopServiceImpl.java

@@ -5,13 +5,14 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.haha.common.exception.BusinessException;
 import com.haha.entity.Device;
 import com.haha.entity.Shop;
 import com.haha.mapper.ShopMapper;
 import com.haha.service.DeviceService;
 import com.haha.service.ShopService;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
@@ -26,13 +27,11 @@ import java.util.Map;
  */
 @Slf4j
 @Service
+@RequiredArgsConstructor
 public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements ShopService {
 
-    @Autowired
-    private ShopMapper shopMapper;
-
-    @Autowired
-    private DeviceService deviceService;
+    private final ShopMapper shopMapper;
+    private final DeviceService deviceService;
 
     @Override
     public IPage<Shop> getPage(int page, int pageSize, Map<String, Object> params) {
@@ -69,6 +68,30 @@ public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements Sh
         return shopPage;
     }
 
+    @Override
+    public List<Shop> queryByName(String name) {
+        return this.lambdaQuery()
+                .like(StringUtils.hasText(name), Shop::getName, name)
+                .orderByDesc(Shop::getCreateTime)
+                .list();
+    }
+
+    @Override
+    public List<Shop> queryByCity(String city) {
+        return this.lambdaQuery()
+                .eq(StringUtils.hasText(city), Shop::getCity, city)
+                .orderByDesc(Shop::getCreateTime)
+                .list();
+    }
+
+    @Override
+    public List<Shop> queryByStatus(Integer status) {
+        return this.lambdaQuery()
+                .eq(status != null, Shop::getStatus, status)
+                .orderByDesc(Shop::getCreateTime)
+                .list();
+    }
+
     @Override
     public Shop getShopWithStats(Long id) {
         Map<String, Object> map = shopMapper.selectShopWithStats(id);
@@ -147,7 +170,7 @@ public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements Sh
     public Shop updateShop(Shop shop) {
         Shop existShop = this.getById(shop.getId());
         if (existShop == null) {
-            throw new RuntimeException("门店不存在");
+            throw new BusinessException(404, "门店不存在");
         }
         
         shop.setUpdateTime(LocalDateTime.now());
@@ -168,7 +191,7 @@ public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements Sh
     public boolean toggleStatus(Long id, Integer status) {
         Shop shop = this.getById(id);
         if (shop == null) {
-            throw new RuntimeException("门店不存在");
+            throw new BusinessException(404, "门店不存在");
         }
         
         LambdaUpdateWrapper<Shop> wrapper = new LambdaUpdateWrapper<>();
@@ -239,13 +262,13 @@ public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements Sh
         // 检查门店是否存在
         Shop shop = this.getById(shopId);
         if (shop == null) {
-            throw new RuntimeException("门店不存在");
+            throw new BusinessException(404, "门店不存在");
         }
         
         // 检查设备是否存在
         Device device = deviceService.getById(deviceId);
         if (device == null) {
-            throw new RuntimeException("设备不存在");
+            throw new BusinessException(404, "设备不存在");
         }
         
         // 如果设备已关联到其他门店,先解除关联
@@ -265,17 +288,27 @@ public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements Sh
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public int batchLinkDevices(Long shopId, List<Long> deviceIds) {
-        int count = 0;
-        for (Long deviceId : deviceIds) {
-            try {
-                if (linkDevice(shopId, deviceId)) {
-                    count++;
-                }
-            } catch (Exception e) {
-                log.error("设备关联门店失败: deviceId={}, error={}", deviceId, e.getMessage());
-            }
+        if (deviceIds == null || deviceIds.isEmpty()) {
+            return 0;
+        }
+        
+        // 检查门店是否存在
+        Shop shop = this.getById(shopId);
+        if (shop == null) {
+            throw new BusinessException(404, "门店不存在");
         }
+        
+        // 批量更新设备的门店关联
+        LambdaUpdateWrapper<Device> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.in(Device::getId, deviceIds)
+               .set(Device::getShopId, shopId)
+               .set(Device::getUpdateTime, LocalDateTime.now());
+        
+        boolean success = deviceService.update(wrapper);
+        int count = success ? deviceIds.size() : 0;
+        
         log.info("批量关联设备完成: shopId={}, 总数={}, 成功={}", shopId, deviceIds.size(), count);
         return count;
     }
@@ -285,11 +318,11 @@ public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements Sh
         // 检查设备是否属于该门店
         Device device = deviceService.getById(deviceId);
         if (device == null) {
-            throw new RuntimeException("设备不存在");
+            throw new BusinessException(404, "设备不存在");
         }
         
         if (!shopId.equals(device.getShopId())) {
-            throw new RuntimeException("该设备不属于当前门店");
+            throw new BusinessException(400, "该设备不属于当前门店");
         }
         
         // 解除关联
@@ -304,17 +337,22 @@ public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements Sh
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public int batchUnlinkDevices(Long shopId, List<Long> deviceIds) {
-        int count = 0;
-        for (Long deviceId : deviceIds) {
-            try {
-                if (unlinkDevice(shopId, deviceId)) {
-                    count++;
-                }
-            } catch (Exception e) {
-                log.error("设备解除关联失败: deviceId={}, error={}", deviceId, e.getMessage());
-            }
+        if (deviceIds == null || deviceIds.isEmpty()) {
+            return 0;
         }
+        
+        // 批量解除设备关联
+        LambdaUpdateWrapper<Device> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.eq(Device::getShopId, shopId)
+               .in(Device::getId, deviceIds)
+               .set(Device::getShopId, null)
+               .set(Device::getUpdateTime, LocalDateTime.now());
+        
+        boolean success = deviceService.update(wrapper);
+        int count = success ? deviceIds.size() : 0;
+        
         log.info("批量解除关联完成: shopId={}, 总数={}, 成功={}", shopId, deviceIds.size(), count);
         return count;
     }
@@ -342,13 +380,10 @@ public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements Sh
      */
     private void fillShopLabels(Shop shop) {
         if (shop.getStatus() != null) {
-            if (shop.getStatus() == 1) {
-                shop.setStatusLabel("启用");
-                shop.setStatusColor("success");
-            } else {
-                shop.setStatusLabel("禁用");
-                shop.setStatusColor("danger");
-            }
+            com.haha.common.vo.StatusLabel label = 
+                com.haha.common.utils.EntityLabelUtils.getStatusLabel("common", shop.getStatus());
+            shop.setStatusLabel(label.getLabel());
+            shop.setStatusColor(label.getColor());
         }
     }
 }

+ 7 - 6
haha-service/src/main/java/com/haha/service/impl/StockRecordServiceImpl.java

@@ -5,11 +5,12 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.haha.common.exception.BusinessException;
 import com.haha.entity.StockRecord;
 import com.haha.mapper.StockRecordMapper;
 import com.haha.service.StockRecordService;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
@@ -22,11 +23,11 @@ import java.util.Map;
  */
 @Slf4j
 @Service
+@RequiredArgsConstructor
 public class StockRecordServiceImpl extends ServiceImpl<StockRecordMapper, StockRecord>
         implements StockRecordService {
 
-    @Autowired
-    private StockRecordMapper stockRecordMapper;
+    private final StockRecordMapper stockRecordMapper;
 
     @Override
     public IPage<StockRecord> getPage(int page, int pageSize, Map<String, Object> params) {
@@ -101,7 +102,7 @@ public class StockRecordServiceImpl extends ServiceImpl<StockRecordMapper, Stock
     public void startActivity(Long recordId) {
         StockRecord record = getById(recordId);
         if (record == null) {
-            throw new RuntimeException("上货记录不存在");
+            throw new BusinessException(404, "上货记录不存在");
         }
 
         record.setStatus(1); // 进行中
@@ -115,7 +116,7 @@ public class StockRecordServiceImpl extends ServiceImpl<StockRecordMapper, Stock
     public void completeActivity(Long recordId, Integer totalItems, Integer totalQuantity, String activityId) {
         StockRecord record = getById(recordId);
         if (record == null) {
-            throw new RuntimeException("上货记录不存在");
+            throw new BusinessException(404, "上货记录不存在");
         }
 
         record.setStatus(2); // 已完成
@@ -134,7 +135,7 @@ public class StockRecordServiceImpl extends ServiceImpl<StockRecordMapper, Stock
     public void cancelActivity(Long recordId) {
         StockRecord record = getById(recordId);
         if (record == null) {
-            throw new RuntimeException("上货记录不存在");
+            throw new BusinessException(404, "上货记录不存在");
         }
 
         record.setStatus(3); // 已取消

+ 26 - 0
pom.xml

@@ -31,8 +31,10 @@
         <hutool.version>5.8.28</hutool.version>
         <satoken.version>1.39.0</satoken.version>
         <fastjson.version>2.0.45</fastjson.version>
+        <fastjson2.version>2.0.53</fastjson2.version>
         <pagehelper.version>5.3.3</pagehelper.version>
         <aspectj.version>1.9.22</aspectj.version>
+        <okhttp.version>4.12.0</okhttp.version>
     </properties>
 
     <dependencyManagement>
@@ -67,6 +69,13 @@
                 <version>${fastjson.version}</version>
             </dependency>
 
+            <!-- FastJson2 -->
+            <dependency>
+                <groupId>com.alibaba.fastjson2</groupId>
+                <artifactId>fastjson2</artifactId>
+                <version>${fastjson2.version}</version>
+            </dependency>
+
             <!-- Sa-Token -->
             <dependency>
                 <groupId>cn.dev33</groupId>
@@ -93,6 +102,13 @@
                 <version>${aspectj.version}</version>
             </dependency>
 
+            <!-- OkHttp -->
+            <dependency>
+                <groupId>com.squareup.okhttp3</groupId>
+                <artifactId>okhttp</artifactId>
+                <version>${okhttp.version}</version>
+            </dependency>
+
             <!-- 内部模块 -->
             <dependency>
                 <groupId>com.haha</groupId>
@@ -122,6 +138,16 @@
         </dependencies>
     </dependencyManagement>
 
+    <!-- 公共依赖 - 所有子模块自动继承 -->
+    <dependencies>
+        <!-- Lombok - 所有模块都需要 -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+
     <build>
         <pluginManagement>
             <plugins>