Sfoglia il codice sorgente

订单模块代码优化

wangzhijun 1 mese fa
parent
commit
8cbdedfe4c

+ 4 - 2
nightFragrance-massage/src/main/java/com/ylx/order/constant/OrderConstant.java

@@ -12,10 +12,12 @@ public class OrderConstant {
     public static final String DICT_UNIT_TYPE = "unit_type";
     /** 用户类型 2-商户 */
     public static final Integer USER_TYPE_MERCHANT = 2;
-    /** 商户地址类型 1门店 2虚拟 */
-    public static final Integer ADDR_TYPE_SHOP = 1;
+    /** 商户地址类型 1 真实地址 2 虚拟地址 */
+    public static final Integer ADDR_TYPE_REAL = 1;
     public static final Integer ADDR_TYPE_VIRTUAL = 2;
 
     /** 商户地址类型 1默认 */
     public static final Integer ADDR_DEFAULT_YES = 1;
+
+    public static final int PHONE_TAIL_LENGTH = 4;
 }

+ 38 - 92
nightFragrance-massage/src/main/java/com/ylx/order/service/impl/TOrderServiceImpl.java

@@ -8,10 +8,10 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result;
 import com.ylx.address.domain.TAddress;
 import com.ylx.address.service.TAddressService;
+import com.ylx.base.BaseServiceImpl;
 import com.ylx.common.core.domain.entity.SysDictData;
 import com.ylx.common.core.domain.model.WxLoginUser;
 import com.ylx.common.exception.ServiceException;
@@ -50,8 +50,6 @@ import com.ylx.shopingfundsdetail.domain.vo.ShoppingFundsDetailAddDto;
 import com.ylx.shopingfundsdetail.enums.ShoppingFundsExpenseTypeEnum;
 import com.ylx.shopingfundsdetail.service.ShoppingFundsDetailService;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -76,7 +74,7 @@ import static com.ylx.order.constant.OrderConstant.*;
  */
 @Service
 @Slf4j
-public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> implements TOrderService {
+public class TOrderServiceImpl extends BaseServiceImpl<TOrderMapper, TOrder> implements TOrderService {
     private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
 
     private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@@ -99,35 +97,41 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
     private CouponService couponService;
     @Resource
     private WxPayV3Service wxPayV3Service;
-
     @Resource
     private OrderStatusFlowService orderStatusFlowService;
-
     @Resource
     private MaTechnicianMapper maTechnicianMapper;
-
     @Resource
     private MaProjectMapper maProjectMapper;
     @Resource
     private IAfterSalesServiceService afterSalesServiceService;
     @Resource
     private IMessageService messageService;
-
     @Resource
     private TGeoFenceService geoFenceService;
-
-    @Value("${ylx.sendSmsEnabled:false}")
-    private boolean sendSmsEnabled;
-
-    @Value("${ylx.fixedVerifyCode:123456}")
-    private String fixedVerifyCode;
-
     @Resource
     private IMaProjectFareSettingService maProjectFareSettingService;
-
     @Resource
     private RedisTemplate<String, String> redisTemplate;
 
+    private static final Map<Integer, String> unitDictCache = new HashMap<>();
+
+    static {
+        List<SysDictData> dictList = DictUtils.getSortedDictCache(DICT_UNIT_TYPE);
+        if (CollUtil.isNotEmpty(dictList)) {
+            dictList.forEach(dict -> {
+                try {
+                    Integer key = Integer.parseInt(dict.getDictValue());
+                    unitDictCache.put(key, dict.getDictLabel());
+                } catch (NumberFormatException e) {
+                    log.warn("单位字典值非数字,跳过该条记录:{}", dict);
+                }
+            });
+        } else {
+            log.warn("项目计量单位字典未加载,请检查配置:{}", DICT_UNIT_TYPE);
+        }
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Map<String, Object> submitOrder(OrderSubmitDTO dto) {
@@ -170,8 +174,6 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
         if (ObjectUtil.isNotNull(dto.getCouponId())) {
             // 计算抵扣金额
             couponDiscount = this.couponService.calculateDiscountAmount(dto.getCouponId(), openId, basePrice);
-            // 立即核销优惠券,保证与订单在同一事务中
-            this.couponService.useCoupon(dto.getCouponId(), openId, null, 1);
         }
 
         // 实付金额 = 商品原价 - 优惠券优惠 + 车费
@@ -249,7 +251,6 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
 
 
         // 5. 返回分页结果
-
         Page<OrderDateQueryVo> voPage = new Page<>(orderPage.getCurrent(), orderPage.getSize(), orderPage.getTotal());
         voPage.setRecords(voList);
 
@@ -347,7 +348,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
     private OrderDateQueryVo convertToVo(TOrder order) {
         OrderDateQueryVo vo = new OrderDateQueryVo();
         // 拷贝相同字段
-        BeanUtils.copyProperties(order, vo);
+        BeanUtil.copyProperties(order, vo);
         // 手动设置字段名不一致或需要特殊处理的
         vo.setOrderStatus(order.getStatus());
         vo.setOrderStatusName(getOrderStatusName(order.getStatus()));
@@ -422,11 +423,11 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
         order.setUserLatitude(address.getLatitude());
         order.setUserLongitude(address.getLongitude());
 
-        merchantAddressList.stream().filter(a -> a.getType() == 1).findFirst().ifPresent(addr -> {
+        merchantAddressList.stream().filter(a -> a.getType().equals(ADDR_TYPE_REAL)).findFirst().ifPresent(addr -> {
             order.setMerchantLongitude(addr.getLongitude());
             order.setMerchantLatitude(addr.getLatitude());
         });
-        merchantAddressList.stream().filter(a -> a.getType() == 2).findFirst().ifPresent(addr -> {
+        merchantAddressList.stream().filter(a -> a.getType().equals(ADDR_TYPE_VIRTUAL)).findFirst().ifPresent(addr -> {
             order.setVirtualLongitude(addr.getLongitude());
             order.setVirtualLatitude(addr.getLatitude());
         });
@@ -446,9 +447,12 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
      */
     private void handleBalancePayment(Long userId, BigDecimal finalAmount, TOrder order) {
         // 1. 数据库层面原子扣减余额,并校验余额是否充足
-        boolean deductSuccess = this.wxUserService.lambdaUpdate().setSql("d_balance = d_balance - " + finalAmount).eq(TWxUser::getId, userId)
-                // 防止余额超扣的核心:当前余额必须大于等于扣减金额
-                .apply("d_balance >= {0}", finalAmount).update();
+        boolean deductSuccess = wxUserService.lambdaUpdate()
+                .setSql("d_balance = d_balance - {0}")
+                .eq(TWxUser::getId, userId)
+                // 两个位置共用同一个参数,逗号传参
+                .apply("d_balance >= {0}", finalAmount)
+                .update();
 
         if (!deductSuccess) {
             throw new ServiceException("余额不足,扣款失败");
@@ -530,8 +534,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
 
         // 查询技师表
         if (order.getMerchantId() != null) {
-            // merchantId 为 Long,技师表 id 为 Integer,需转换
-            MaTechnician technician = maTechnicianMapper.selectById(order.getMerchantId().intValue());
+            MaTechnician technician = maTechnicianMapper.selectById(order.getMerchantId());
             if (technician != null) {
                 //评分
                 vo.setStar(technician.getNStar());
@@ -825,8 +828,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
     @Override
     public OrderCustomerPhoneVO getCustomerPhoneByOrderId(OrderPhoneQueryDTO dto) {
         // 1. 获取当前登录商户
-        WxLoginUser wxLoginUser = getCurrentWxLoginUser();
-        Long merchantId = Long.parseLong(wxLoginUser.getId());
+        Long merchantId = this.getCurrentUserId();
         Long orderId = dto.getOrderId();
 
         // 2. 查询订单:只查归属商户、未删除、手机号字段
@@ -1071,7 +1073,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
                 throw new ServiceException("仅【待出发】订单可签到,当前状态:" + ExecStatusEnum.getInfoByCode(execStatus));
             }
             // 上门签到:执行全部手机号校验、状态强限制、写入signTime
-            if (phoneTail.length() != 4 || !StrUtil.isNumeric(phoneTail)) {
+            if (phoneTail.length() != PHONE_TAIL_LENGTH || !StrUtil.isNumeric(phoneTail)) {
                 throw new ServiceException("手机号后4位必须为4位数字");
             }
             if (!PhoneUtils.matchPhoneTail4(order.getContactPhoneNumber(), phoneTail)) {
@@ -1097,8 +1099,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
     public Page<RecentMerchantVO> getRecentMerchants(RecentOrderQueryDTO dto) {
 
         // 1. 获取当前登录用户
-        WxLoginUser wxLoginUser = this.getCurrentWxLoginUser();
-        Long userId = Long.parseLong(wxLoginUser.getId());
+        Long userId = this.getCurrentUserId();
         dto.setUserId(userId);
 
         // 2. 构建分页对象
@@ -1161,15 +1162,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
 
         Integer standardDuration = project.getStandardDuration();
         Integer unitType = project.getUnitType();
-        String unitTypeName = "未知单位";
-        List<SysDictData> dictList = DictUtils.getSortedDictCache(DICT_UNIT_TYPE);
-        if (CollUtil.isNotEmpty(dictList) && ObjectUtil.isNotNull(unitType)) {
-            unitTypeName = dictList.stream()
-                    .filter(dict -> unitType.toString().equals(dict.getDictValue()))
-                    .map(SysDictData::getDictLabel)
-                    .findFirst()
-                    .orElse("未知单位");
-        }
+        String unitTypeName = unitDictCache.getOrDefault(unitType, "未知单位");
 
         Integer durationMinutes = convertToMinutes(standardDuration, unitType);
         if (ObjectUtil.isNull(durationMinutes) || durationMinutes <= 0) {
@@ -1177,7 +1170,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
         }
 
         // 2. 生成所有候选开始时间(半点粒度,步进30分钟)
-        List<LocalTime> candidateStarts = TimeSlotUtil.getAvailableTimeSlots(dto.getAppointmentDate(), 30);
+        List<LocalTime> candidateStarts = TimeSlotUtil.getAvailableTimeSlots(dto.getAppointmentDate(), APPOINT_BUFFER_MINUTES);
 
         // 3. 查询该商户当天的【有效占用】订单
         LocalDateTime dayStart = dto.getAppointmentDate().atStartOfDay();
@@ -1296,27 +1289,8 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
             return duration;
         }
 
-        // 2. 从字典缓存中获取数据(若依的 DictUtils 读取成本极低,无需自己做 DCL 锁)
-        List<SysDictData> dictList = DictUtils.getSortedDictCache(DICT_UNIT_TYPE);
-        if (CollUtil.isEmpty(dictList)) {
-            return duration;
-        }
-
-        // 3. 使用局部变量构建映射,彻底杜绝多线程并发修改 HashMap 的风险
-        Map<Integer, Integer> localCoeffMap = new HashMap<>(dictList.size());
-        for (SysDictData data : dictList) {
-            try {
-                int type = Integer.parseInt(data.getDictValue());
-                // 根据业务规则设置倍率
-                int ratio = (type == 1) ? 1 : 60;
-                localCoeffMap.put(type, ratio);
-            } catch (NumberFormatException e) {
-                log.warn("字典数据格式错误,跳过该条记录: {}", data);
-            }
-        }
-
-        // 4. 获取倍率并计算,默认倍率为 1(即不转换)
-        int factor = localCoeffMap.getOrDefault(unitType, 1);
+        // 2. 静态缓存已全局加载完成,直接判断
+        int factor = unitDictCache.containsKey(unitType) && unitType == 1 ? 1 : 60;
         return duration * factor;
     }
 
@@ -1350,15 +1324,6 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
         order.setPlatformIncome(platformIncome);
     }
 
-
-    private WxLoginUser getCurrentWxLoginUser() {
-        WxLoginUser loginUser = SecurityUtils.getWxLoginUser();
-        if (ObjectUtil.isNull(loginUser)) {
-            throw new ServiceException("用户未登录或登录已过期");
-        }
-        return loginUser;
-    }
-
     /**
      * 抽取公共校验逻辑:校验订单是否存在、是否被删除、是否属于当前商户
      */
@@ -1376,32 +1341,13 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
             throw new ServiceException("订单已被删除");
         }
 
-        if (ObjectUtil.notEqual(order.getMerchantId(), merchantId)) {
+        if (ObjectUtil.isNotNull(merchantId) && ObjectUtil.notEqual(order.getMerchantId(), merchantId)) {
             throw new ServiceException("您无权操作此订单");
         }
 
         return order;
     }
 
-    /**
-     * 校验验证码
-     *
-     * @param phone 手机号
-     * @param code  用户输入的验证码
-     * @return boolean 校验是否通过
-     */
-    private boolean validateVerifyCode(String phone, String code) {
-        if (sendSmsEnabled) {
-            // TODO: 从Redis或其他存储中获取真实发送的验证码进行校验
-            // String realCode = redisCache.getCacheObject("sms:bindPhone:" + phone);
-            // return code.equals(realCode);
-            return true;
-        } else {
-            // 使用写死的验证码进行校验
-            return fixedVerifyCode.equals(code);
-        }
-    }
-
     /**
      * 计算用户客户标签编码
      *