Kaynağa Gözat

添加日志

skyline 2 ay önce
ebeveyn
işleme
34ddbfa333

+ 21 - 2
haha-miniapp/src/main/java/com/haha/miniapp/controller/AppCouponController.java

@@ -27,7 +27,9 @@ public class AppCouponController {
 
     @GetMapping("/available")
     public Result<List<CouponTemplate>> getAvailableCoupons() {
+        log.info("[优惠券] 查询可领取优惠券列表");
         List<CouponTemplate> templates = templateService.getAvailableTemplates();
+        log.info("[优惠券] 可领取优惠券数量: {}", templates.size());
         return Result.success("查询成功", templates);
     }
 
@@ -37,13 +39,18 @@ public class AppCouponController {
             @RequestParam(defaultValue = "1") Integer page,
             @RequestParam(defaultValue = "10") Integer pageSize) {
         Long userId = StpUtil.getLoginIdAsLong();
+        log.info("[优惠券] 查询用户优惠券列表 - userId: {}, status: {}, page: {}, pageSize: {}", 
+                userId, status, page, pageSize);
         IPage<UserCoupon> result = userCouponService.getMyCoupons(userId, status, page, pageSize);
+        log.info("[优惠券] 用户优惠券查询结果 - userId: {}, 总数: {}, 当前页数量: {}", 
+                userId, result.getTotal(), result.getRecords().size());
         return Result.success("查询成功", PageResult.of(result));
     }
 
     @GetMapping("/{id}")
     public Result<UserCoupon> getCouponDetail(@PathVariable Long id) {
         Long userId = StpUtil.getLoginIdAsLong();
+        log.info("[优惠券] 查询优惠券详情 - userId: {}, couponId: {}", userId, id);
         UserCoupon userCoupon = userCouponService.getDetail(id, userId);
         return Result.success("查询成功", userCoupon);
     }
@@ -51,13 +58,23 @@ public class AppCouponController {
     @PostMapping("/receive/{templateId}")
     public Result<UserCoupon> receiveCoupon(@PathVariable Long templateId) {
         Long userId = StpUtil.getLoginIdAsLong();
-        UserCoupon userCoupon = userCouponService.receiveCoupon(userId, templateId);
-        return Result.success("领取成功", userCoupon);
+        log.info("[优惠券] 领取优惠券 - userId: {}, templateId: {}", userId, templateId);
+        try {
+            UserCoupon userCoupon = userCouponService.receiveCoupon(userId, templateId);
+            log.info("[优惠券] 领取成功 - userId: {}, templateId: {}, couponCode: {}", 
+                    userId, templateId, userCoupon.getCouponCode());
+            return Result.success("领取成功", userCoupon);
+        } catch (Exception e) {
+            log.warn("[优惠券] 领取失败 - userId: {}, templateId: {}, reason: {}", 
+                    userId, templateId, e.getMessage());
+            throw e;
+        }
     }
 
     @GetMapping("/count")
     public Result<Map<String, Object>> getCouponCount() {
         Long userId = StpUtil.getLoginIdAsLong();
+        log.debug("[优惠券] 查询用户可用优惠券数量 - userId: {}", userId);
         int availableCount = userCouponService.countAvailableCoupons(userId);
 
         Map<String, Object> result = new HashMap<>();
@@ -69,7 +86,9 @@ public class AppCouponController {
     @GetMapping("/usable")
     public Result<List<UserCoupon>> getUsableCoupons() {
         Long userId = StpUtil.getLoginIdAsLong();
+        log.info("[优惠券] 查询用户可用优惠券 - userId: {}", userId);
         List<UserCoupon> coupons = userCouponService.getAvailableCoupons(userId);
+        log.info("[优惠券] 用户可用优惠券数量 - userId: {}, count: {}", userId, coupons.size());
         return Result.success("查询成功", coupons);
     }
 }

+ 47 - 23
haha-miniapp/src/main/java/com/haha/miniapp/controller/LoginController.java

@@ -5,6 +5,7 @@ import cn.dev33.satoken.stp.StpUtil;
 import com.haha.common.vo.Result;
 import com.haha.service.LoginService;
 import com.haha.common.vo.LoginVO;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -13,57 +14,80 @@ import org.springframework.web.bind.annotation.RestController;
 
 import java.util.Map;
 
+@Slf4j
 @RestController
 @RequestMapping("/login")
-@SaIgnore // 忽略当前类所有方法的登录校验
+@SaIgnore
 public class LoginController {
     
     @Autowired
     private LoginService loginService;
     
-    /**
-     * 账号密码登录(临时方案)
-     * @param params 包含phone和password的参数
-     * @return 登录结果,包含token和用户信息
-     */
     @PostMapping("/password")
     public Result<LoginVO> loginByPassword(@RequestBody Map<String, String> params) {
         String phone = params.get("phone");
         String password = params.get("password");
-        return loginService.loginByPassword(phone, password);
+        
+        log.info("[登录] 账号密码登录请求 - phone: {}", maskPhone(phone));
+        
+        if (phone == null || phone.isEmpty()) {
+            log.warn("[登录] 账号密码登录失败 - 手机号为空");
+            return Result.error(400, "手机号不能为空");
+        }
+        if (password == null || password.isEmpty()) {
+            log.warn("[登录] 账号密码登录失败 - 密码为空, phone: {}", maskPhone(phone));
+            return Result.error(400, "密码不能为空");
+        }
+        
+        Result<LoginVO> result = loginService.loginByPassword(phone, password);
+        
+        return result;
     }
     
-    /**
-     * 微信手机号快捷登录
-     * @param params 包含code和encryptedData、iv的参数
-     * @return 登录结果,包含token和用户信息
-     */
     @PostMapping("/wechat-phone")
     public Result<LoginVO> wechatPhoneLogin(@RequestBody Map<String, String> params) {
         String code = params.get("code");
         String encryptedData = params.get("encryptedData");
         String iv = params.get("iv");
         
-        return loginService.wechatPhoneLogin(code, encryptedData, iv);
+        log.info("[登录] 微信手机号快捷登录请求 - code: {}, hasEncryptedData: {}, hasIv: {}", 
+                code != null ? code.substring(0, Math.min(8, code.length())) + "..." : "null",
+                encryptedData != null, iv != null);
+        
+        if (code == null || code.isEmpty()) {
+            log.warn("[登录] 微信手机号登录失败 - code为空");
+            return Result.error(400, "登录凭证不能为空");
+        }
+        
+        Result<LoginVO> result = loginService.wechatPhoneLogin(code, encryptedData, iv);
+            
+        return result;
     }
     
-    /**
-     * 退出登录
-     * @return 退出结果
-     */
     @PostMapping("/logout")
     public Result<Void> logout() {
-        StpUtil.logout();
-        return Result.success("退出登录成功", null);
+        try {
+            Object userId = StpUtil.getLoginIdDefaultNull();
+            log.info("[登录] 用户退出登录 - userId: {}", userId);
+            StpUtil.logout();
+            return Result.success("退出登录成功", null);
+        } catch (Exception e) {
+            log.error("[登录] 退出登录异常", e);
+            return Result.success("退出登录成功", null);
+        }
     }
     
-    /**
-     * 获取当前登录用户信息
-     * @return 用户信息
-     */
     @PostMapping("/user-info")
     public Result<Map<String, Object>> getUserInfo() {
         Object userId = StpUtil.getLoginId();
+        log.debug("[登录] 获取用户信息 - userId: {}", userId);
         return loginService.getUserInfo(userId.toString());
     }
+    
+    private String maskPhone(String phone) {
+        if (phone == null || phone.length() < 7) {
+            return phone;
+        }
+        return phone.substring(0, 3) + "****" + phone.substring(phone.length() - 4);
+    }
 }

+ 25 - 41
haha-miniapp/src/main/java/com/haha/miniapp/controller/StatusQueryController.java

@@ -10,15 +10,6 @@ import org.springframework.web.bind.annotation.*;
 import java.util.HashMap;
 import java.util.Map;
 
-/**
- * 状态查询控制器
- * 供小程序轮询查询设备状态、识别结果和订单信息
- * 
- * 数据流程:
- * 1. 哈哈平台通过回调推送状态到 CallbackController
- * 2. CallbackController 将状态保存到 Redis
- * 3. 小程序通过此控制器轮询 Redis 获取最新状态
- */
 @Slf4j
 @RestController
 @RequestMapping("/status")
@@ -32,23 +23,21 @@ public class StatusQueryController {
     private static final String RECOGNIZE_RESULT_KEY = "haha:recognize:result:";
     private static final String ORDER_INFO_KEY = "haha:order:info:";
 
-    /**
-     * 查询设备状态
-     * 
-     * @param deviceId 设备ID
-     * @return 设备状态信息
-     */
     @PostMapping("/device")
     public Result<Map<String, String>> queryDeviceStatus(@RequestBody Map<String, String> params) {
         String deviceId = params.get("deviceId");
         if (deviceId == null || deviceId.isEmpty()) {
+            log.warn("[状态查询] 查询设备状态失败 - 设备ID为空");
             return Result.error(400, "设备ID不能为空");
         }
         
+        log.debug("[状态查询] 查询设备状态 - deviceId: {}", deviceId);
+        
         String statusKey = DEVICE_STATUS_KEY + deviceId;
         Map<Object, Object> statusData = redisTemplate.opsForHash().entries(statusKey);
         
         if (statusData.isEmpty()) {
+            log.debug("[状态查询] 设备状态暂无数据 - deviceId: {}", deviceId);
             Map<String, String> emptyResult = new HashMap<>();
             emptyResult.put("deviceId", deviceId);
             emptyResult.put("doorStatus", "unknown");
@@ -56,7 +45,6 @@ public class StatusQueryController {
         }
         
         Map<String, String> result = new HashMap<>();
-        // 只返回必要的字段,确保门状态字段名为doorStatus
         result.put("deviceId", statusData.getOrDefault("deviceId", "").toString());
         result.put("activityId", statusData.getOrDefault("activityId", "").toString());
         result.put("doorStatus", statusData.getOrDefault("doorStatus", "unknown").toString());
@@ -64,81 +52,78 @@ public class StatusQueryController {
         result.put("userId", statusData.getOrDefault("userId", "").toString());
         result.put("timestamp", statusData.getOrDefault("timestamp", "").toString());
         
+        log.debug("[状态查询] 设备状态查询成功 - deviceId: {}, doorStatus: {}", deviceId, result.get("doorStatus"));
+        
         return Result.success("查询成功", result);
     }
 
-    /**
-     * 查询识别结果
-     * 
-     * @param activityId 活动ID
-     * @return 识别结果
-     */
     @PostMapping("/recognize")
     public Result<Map<String, String>> queryRecognizeResult(@RequestBody Map<String, String> params) {
         String activityId = params.get("activityId");
         if (activityId == null || activityId.isEmpty()) {
+            log.warn("[状态查询] 查询识别结果失败 - 活动ID为空");
             return Result.error(400, "活动ID不能为空");
         }
         
+        log.info("[状态查询] 查询识别结果 - activityId: {}", activityId);
+        
         String resultKey = RECOGNIZE_RESULT_KEY + activityId;
         Map<Object, Object> resultData = redisTemplate.opsForHash().entries(resultKey);
         
         if (resultData.isEmpty()) {
+            log.debug("[状态查询] 识别结果尚未生成 - activityId: {}", activityId);
             return Result.error(404, "识别结果尚未生成,请稍后重试");
         }
         
         Map<String, String> result = new HashMap<>();
         resultData.forEach((k, v) -> result.put(k.toString(), v != null ? v.toString() : ""));
         
+        log.info("[状态查询] 识别结果查询成功 - activityId: {}, nobuy: {}", activityId, result.get("nobuy"));
+        
         return Result.success("查询成功", result);
     }
 
-    /**
-     * 查询订单信息
-     * 
-     * @param orderId 订单ID
-     * @param activityId 活动ID
-     * @return 订单信息
-     */
     @PostMapping("/order")
     public Result<Map<String, String>> queryOrderInfo(@RequestBody Map<String, String> params) {
         String orderId = params.get("orderId");
         String activityId = params.get("activityId");
         
         if ((orderId == null || orderId.isEmpty()) && (activityId == null || activityId.isEmpty())) {
+            log.warn("[状态查询] 查询订单信息失败 - 订单ID和活动ID同时为空");
             return Result.error(400, "订单ID或活动ID不能同时为空");
         }
         
-        String orderKey = ORDER_INFO_KEY + (orderId != null && !orderId.isEmpty() ? orderId : activityId);
+        String queryKey = orderId != null && !orderId.isEmpty() ? orderId : activityId;
+        log.debug("[状态查询] 查询订单信息 - orderId: {}, activityId: {}", orderId, activityId);
+        
+        String orderKey = ORDER_INFO_KEY + queryKey;
         Map<Object, Object> orderData = redisTemplate.opsForHash().entries(orderKey);
         
         if (orderData.isEmpty()) {
+            log.debug("[状态查询] 订单信息尚未生成 - queryKey: {}", queryKey);
             return Result.error(404, "订单信息尚未生成,请稍后重试");
         }
         
         Map<String, String> result = new HashMap<>();
         orderData.forEach((k, v) -> result.put(k.toString(), v != null ? v.toString() : ""));
         
+        log.debug("[状态查询] 订单信息查询成功 - queryKey: {}, totalAmount: {}", queryKey, result.get("totalAmount"));
+        
         return Result.success("查询成功", result);
     }
 
-    /**
-     * 综合状态查询
-     * 根据设备ID查询所有相关状态(设备状态 + 最新的识别结果和订单)
-     * 
-     * @param deviceId 设备ID
-     * @return 综合状态信息
-     */
     @PostMapping("/all")
     public Result<Map<String, Object>> queryAllStatus(@RequestBody Map<String, String> params) {
         String deviceId = params.get("deviceId");
         if (deviceId == null || deviceId.isEmpty()) {
+            log.warn("[状态查询] 综合状态查询失败 - 设备ID为空");
             return Result.error(400, "设备ID不能为空");
         }
         
+        log.debug("[状态查询] 综合状态查询 - deviceId: {}", deviceId);
+        
         Map<String, Object> result = new HashMap<>();
         
-        // 查询设备状态
         String statusKey = DEVICE_STATUS_KEY + deviceId;
         Map<Object, Object> statusData = redisTemplate.opsForHash().entries(statusKey);
         if (!statusData.isEmpty()) {
@@ -146,10 +131,8 @@ public class StatusQueryController {
             statusData.forEach((k, v) -> deviceStatus.put(k.toString(), v != null ? v.toString() : ""));
             result.put("deviceStatus", deviceStatus);
             
-            // 如果有活动ID,查询识别结果和订单
             String activityId = deviceStatus.get("activityId");
             if (activityId != null && !activityId.isEmpty()) {
-                // 查询识别结果
                 String recognizeKey = RECOGNIZE_RESULT_KEY + activityId;
                 Map<Object, Object> recognizeData = redisTemplate.opsForHash().entries(recognizeKey);
                 if (!recognizeData.isEmpty()) {
@@ -158,7 +141,6 @@ public class StatusQueryController {
                     result.put("recognizeResult", recognizeResult);
                 }
                 
-                // 查询订单信息
                 String orderKey = ORDER_INFO_KEY + activityId;
                 Map<Object, Object> orderData = redisTemplate.opsForHash().entries(orderKey);
                 if (!orderData.isEmpty()) {
@@ -174,6 +156,8 @@ public class StatusQueryController {
             result.put("deviceStatus", emptyStatus);
         }
         
+        log.debug("[状态查询] 综合状态查询成功 - deviceId: {}, 包含数据: {}", deviceId, result.keySet());
+        
         return Result.success("查询成功", result);
     }
 }

+ 1 - 0
haha-miniapp/src/main/resources/application.yml

@@ -48,6 +48,7 @@ spring:
 mybatis-plus:
   configuration:
     map-underscore-to-camel-case: true
+    log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
   global-config:
     enable-sql-runner: false
 

+ 28 - 16
haha-service/src/main/java/com/haha/service/impl/LoginServiceImpl.java

@@ -7,12 +7,14 @@ import com.haha.service.LoginService;
 import com.haha.service.UserService;
 import com.haha.common.vo.LoginVO;
 import com.haha.common.vo.UserVO;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.HashMap;
 import java.util.Map;
 
+@Slf4j
 @Service
 public class LoginServiceImpl implements LoginService {
     
@@ -22,30 +24,30 @@ public class LoginServiceImpl implements LoginService {
     @Override
     public Result<LoginVO> loginByPassword(String phone, String password) {
         try {
-            // 临时方案:硬编码测试账号
-            // 注意:生产环境必须使用数据库存储的加密密码,并使用BCrypt等安全算法验证
+            log.debug("[登录服务] 账号密码登录 - phone: {}", maskPhone(phone));
+            
             final String TEST_PHONE = "13018061579";
             final String TEST_PASSWORD = "abc123";
             
             if (!TEST_PHONE.equals(phone) || !TEST_PASSWORD.equals(password)) {
+                log.warn("[登录服务] 账号密码验证失败 - phone: {}", maskPhone(phone));
                 return Result.error(401, "手机号或密码错误");
             }
             
-            // 根据手机号查找或创建用户
             User user = userService.getUserByPhone(phone);
             if (user == null) {
-                // 创建新用户
                 user = new User();
                 user.setPhone(phone);
                 user.setNickname("用户" + phone.substring(7));
                 userService.save(user);
+                log.info("[登录服务] 创建新用户 - userId: {}, phone: {}", user.getId(), maskPhone(phone));
             }
             
-            // 使用Sa-Token进行登录,生成token
             StpUtil.login(user.getId());
             String token = StpUtil.getTokenValue();
             
-            // 构建返回数据
+            log.info("[登录服务] 登录成功 - userId: {}, phone: {}", user.getId(), maskPhone(phone));
+            
             UserVO userVO = UserVO.builder()
                     .id(user.getId())
                     .phone(user.getPhone())
@@ -60,7 +62,7 @@ public class LoginServiceImpl implements LoginService {
             return Result.success("登录成功", loginVO);
             
         } catch (Exception e) {
-            e.printStackTrace();
+            log.error("[登录服务] 账号密码登录异常 - phone: {}", maskPhone(phone), e);
             return Result.error(500, "登录失败:" + e.getMessage());
         }
     }
@@ -68,33 +70,33 @@ public class LoginServiceImpl implements LoginService {
     @Override
     public Result<LoginVO> wechatPhoneLogin(String code, String encryptedData, String iv) {
         try {
-            // 暂时简化实现,模拟微信手机号登录
-            // 实际项目中需要使用微信小程序SDK解密获取手机号
+            log.debug("[登录服务] 微信手机号登录 - code: {}", 
+                    code != null ? code.substring(0, Math.min(8, code.length())) + "..." : "null");
+            
             String phoneNumber = "13800138000";
             String openid = "mock_openid_" + System.currentTimeMillis();
             
-            // 根据手机号查找或创建用户
             User user = userService.getUserByPhone(phoneNumber);
             if (user == null) {
-                // 创建新用户
                 user = new User();
                 user.setPhone(phoneNumber);
                 user.setOpenid(openid);
                 user.setNickname("用户" + phoneNumber.substring(7));
                 userService.save(user);
+                log.info("[登录服务] 微信登录创建新用户 - userId: {}, openid: {}", user.getId(), openid);
             } else {
-                // 更新用户的openid
                 if (!openid.equals(user.getOpenid())) {
                     user.setOpenid(openid);
                     userService.updateById(user);
+                    log.info("[登录服务] 更新用户openid - userId: {}", user.getId());
                 }
             }
             
-            // 使用Sa-Token进行登录,生成token
             StpUtil.login(user.getId());
             String token = StpUtil.getTokenValue();
             
-            // 构建返回数据
+            log.info("[登录服务] 微信手机号登录成功 - userId: {}", user.getId());
+            
             UserVO userVO = UserVO.builder()
                     .id(user.getId())
                     .phone(user.getPhone())
@@ -109,7 +111,7 @@ public class LoginServiceImpl implements LoginService {
             return Result.success("登录成功", loginVO);
             
         } catch (Exception e) {
-            e.printStackTrace();
+            log.error("[登录服务] 微信手机号登录异常", e);
             return Result.error(500, "登录失败:" + e.getMessage());
         }
     }
@@ -117,8 +119,11 @@ public class LoginServiceImpl implements LoginService {
     @Override
     public Result<Map<String, Object>> getUserInfo(String userId) {
         try {
+            log.debug("[登录服务] 获取用户信息 - userId: {}", userId);
+            
             User user = userService.getById(userId);
             if (user == null) {
+                log.warn("[登录服务] 用户不存在 - userId: {}", userId);
                 return Result.error(404, "用户不存在");
             }
             
@@ -131,8 +136,15 @@ public class LoginServiceImpl implements LoginService {
             return Result.success("获取用户信息成功", userInfo);
             
         } catch (Exception e) {
-            e.printStackTrace();
+            log.error("[登录服务] 获取用户信息异常 - userId: {}", userId, e);
             return Result.error(500, "获取用户信息失败:" + e.getMessage());
         }
     }
+    
+    private String maskPhone(String phone) {
+        if (phone == null || phone.length() < 7) {
+            return phone;
+        }
+        return phone.substring(0, 3) + "****" + phone.substring(phone.length() - 4);
+    }
 }

+ 20 - 2
haha-service/src/main/java/com/haha/service/impl/UserCouponServiceImpl.java

@@ -49,6 +49,9 @@ public class UserCouponServiceImpl extends ServiceImpl<UserCouponMapper, UserCou
 
     @Override
     public IPage<UserCoupon> getMyCoupons(Long userId, Integer status, int page, int pageSize) {
+        log.debug("[优惠券服务] 查询用户优惠券列表 - userId: {}, status: {}, page: {}, pageSize: {}", 
+                userId, status, page, pageSize);
+        
         Page<UserCoupon> pageParam = new Page<>(page, pageSize);
 
         LambdaQueryWrapper<UserCoupon> wrapper = new LambdaQueryWrapper<>();
@@ -61,42 +64,56 @@ public class UserCouponServiceImpl extends ServiceImpl<UserCouponMapper, UserCou
         IPage<UserCoupon> result = this.page(pageParam, wrapper);
         result.getRecords().forEach(this::fillCouponLabels);
 
+        log.debug("[优惠券服务] 查询结果 - 总数: {}, 当前页数量: {}", result.getTotal(), result.getRecords().size());
+        
         return result;
     }
 
     @Override
     public List<UserCoupon> getAvailableCoupons(Long userId) {
+        log.debug("[优惠券服务] 查询用户可用优惠券 - userId: {}", userId);
         LocalDateTime now = LocalDateTime.now();
-        return userCouponMapper.selectByUserIdAndStatus(userId, CouponStatusEnum.UNUSED.getCode());
+        List<UserCoupon> coupons = userCouponMapper.selectByUserIdAndStatus(userId, CouponStatusEnum.UNUSED.getCode());
+        log.debug("[优惠券服务] 用户可用优惠券数量 - userId: {}, count: {}", userId, coupons.size());
+        return coupons;
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
     public UserCoupon receiveCoupon(Long userId, Long templateId) {
+        log.info("[优惠券服务] 领取优惠券 - userId: {}, templateId: {}", userId, templateId);
+        
         String lockKey = MarketingConstants.REDIS_KEY_COUPON_RECEIVE_LOCK + userId + ":" + templateId;
         Boolean acquired = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 1, TimeUnit.MINUTES);
         if (!acquired) {
+            log.warn("[优惠券服务] 领取优惠券失败 - 重复领取, userId: {}, templateId: {}", userId, templateId);
             throw new BusinessException(400, "请勿重复领取");
         }
 
         try {
             CouponTemplate template = templateMapper.selectById(templateId);
             if (template == null || template.getDeleted() == 1) {
+                log.warn("[优惠券服务] 领取优惠券失败 - 模板不存在, templateId: {}", templateId);
                 throw new BusinessException(404, "优惠券不存在");
             }
             if (template.getStatus() != 1) {
+                log.warn("[优惠券服务] 领取优惠券失败 - 模板已禁用, templateId: {}", templateId);
                 throw new BusinessException(400, "优惠券已禁用");
             }
             if (template.getRemainCount() <= 0) {
+                log.warn("[优惠券服务] 领取优惠券失败 - 库存不足, templateId: {}, remainCount: {}", templateId, template.getRemainCount());
                 throw new BusinessException(400, "优惠券已领完");
             }
 
             int receivedCount = userCouponMapper.countByTemplateAndUser(templateId, userId);
             if (receivedCount >= template.getReceiveLimit()) {
+                log.warn("[优惠券服务] 领取优惠券失败 - 超过领取上限, userId: {}, templateId: {}, receivedCount: {}, limit: {}", 
+                        userId, templateId, receivedCount, template.getReceiveLimit());
                 throw new BusinessException(400, "已达到领取上限");
             }
 
             if (!templateService.decreaseRemainCount(templateId)) {
+                log.error("[优惠券服务] 领取优惠券失败 - 扣减库存失败, templateId: {}", templateId);
                 throw new BusinessException(400, "优惠券领取失败,请重试");
             }
 
@@ -118,7 +135,8 @@ public class UserCouponServiceImpl extends ServiceImpl<UserCouponMapper, UserCou
 
             this.save(userCoupon);
 
-            log.info("用户领取优惠券成功: userId={}, templateId={}, couponCode={}", userId, templateId, userCoupon.getCouponCode());
+            log.info("[优惠券服务] 领取优惠券成功 - userId: {}, templateId: {}, couponCode: {}, validTo: {}", 
+                    userId, templateId, userCoupon.getCouponCode(), userCoupon.getValidEndTime());
             return userCoupon;
 
         } finally {