Преглед на файлове

用户端订单详情页面接口开发

郭子栋 преди 1 ден
родител
ревизия
5e11ecb443

+ 6 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/mapper/MaProjectMapper.java

@@ -12,6 +12,7 @@ import com.ylx.project.domain.bookMerchant.dto.BookMerchantDTO;
 import com.ylx.project.domain.bookMerchant.vo.BookMerchantVO;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 
 /**
  * 服务项目Mapper接口
@@ -80,4 +81,9 @@ public interface MaProjectMapper extends BaseMapper<MaProject> {
     Page<MassageAllMerchantsVo> getMassageAllMerchants(@Param("page") Page<MassageAllMerchantsVo> page, @Param("dto") MassageAllMerchantsDto dto);
 
     Page<BookMerchantVO> selectMerchantList(@Param("page") Page<BookMerchantVO> page, @Param("dto") BookMerchantDTO dto);
+    /**
+     * 根据业务项目ID和商户ID查询项目
+     */
+    @Select("SELECT * FROM ma_project WHERE project_id = #{projectId} AND merchant_id = #{merchantId} AND is_delete = 0 LIMIT 1")
+    MaProject selectByProjectIdAndMerchantId(@Param("projectId") Long projectId, @Param("merchantId") Long merchantId);
 }

+ 2 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/mapper/MaTeProjectMapper.java

@@ -2,9 +2,11 @@ package com.ylx.massage.mapper;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ylx.massage.domain.MaProject;
 import com.ylx.massage.domain.MaTeProject;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 
 import java.util.List;
 

+ 11 - 4
nightFragrance-massage/src/main/java/com/ylx/order/controller/OrderController.java

@@ -6,16 +6,15 @@ import com.ylx.order.domain.dto.OrderDateQueryDTO;
 import com.ylx.order.domain.dto.OrderDeleteDTO;
 import com.ylx.order.domain.dto.OrderSubmitDTO;
 import com.ylx.order.domain.vo.OrderDateQueryVo;
+import com.ylx.order.domain.vo.OrderDetailVO;
 import com.ylx.order.service.TOrderService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import java.util.Map;
@@ -52,4 +51,12 @@ public class OrderController {
         orderService.logicDeleteOrder(dto.getId());
         return R.ok("删除成功");
     }
+
+
+    @ApiOperation("根据订单ID查询订单详情")
+    @GetMapping("/detail/{orderId}")
+    public R<OrderDetailVO> getOrderDetailById(
+            @PathVariable @ApiParam(value = "订单ID", required = true, example = "1") Long orderId) {
+        return R.ok(orderService.getOrderDetailById(orderId));
+    }
 }

+ 21 - 0
nightFragrance-massage/src/main/java/com/ylx/order/domain/dto/OrderDetailDTO.java

@@ -0,0 +1,21 @@
+package com.ylx.order.domain.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 类描述:订单详情
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/9 8:56
+ */
+@Data
+public class OrderDetailDTO {
+
+    @NotNull(message = "订单id不能为空")
+    @ApiModelProperty("主键ID")
+    private Long id;
+}

+ 133 - 0
nightFragrance-massage/src/main/java/com/ylx/order/domain/vo/OrderDetailVO.java

@@ -0,0 +1,133 @@
+package com.ylx.order.domain.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 类描述:
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/9 8:58
+ */
+@Data
+public class OrderDetailVO {
+
+    /**
+     * 订单状态
+     */
+    @ApiModelProperty("订单状态")
+    private Integer orderStatus;
+
+    /**
+     * 订单状态中文
+     */
+    @ApiModelProperty("订单状态中文")
+    private String orderStatusName;
+
+    /**
+     * 商户头像
+     */
+    @ApiModelProperty("商户头像")
+    private String merchantAvatar;
+
+
+    /**
+     * 服务次数
+     */
+    @ApiModelProperty("服务次数")
+    private Integer serviceNum;
+
+    /**
+     * 评分
+     */
+    @ApiModelProperty("评分")
+    private Integer star;
+
+    /**
+     * 简介
+     */
+    @ApiModelProperty("简介")
+    private String brief;
+
+    /**
+     * 项目名称
+     */
+    @ApiModelProperty("项目名称")
+    private String projectName;
+
+    /**
+     * 项目时长
+     */
+    @ApiModelProperty("项目时长")
+    private Integer projectDuration;
+    /**
+     * 项目亮点
+     */
+    @ApiModelProperty("项目亮点")
+    private String highlight;
+
+    /**
+     * 最终应付/实付金额
+     */
+    @ApiModelProperty("最终应付/实付金额")
+    private BigDecimal finalAmount;
+
+    @ApiModelProperty("预约开始时间")
+    private String appointmentStartTime;
+
+    @ApiModelProperty("预约结束时间")
+    private String appointmentEndTime;
+
+    @ApiModelProperty("预约时间范围(格式化,示例:5月12日 16:00-18:00)")
+    private String appointmentTimeRange;
+
+    @ApiModelProperty("详细服务地址")
+    private String contactAddresInfo;
+
+    /**
+     * 联系信息:王先生,188****5555
+     */
+    @ApiModelProperty("联系信息")
+    private String contactInfo;
+
+    /**
+     * 订单价格
+     */
+    @ApiModelProperty("订单价格")
+    private BigDecimal basePrice;
+
+    /**
+     * 交通费
+     */
+    @ApiModelProperty("交通费")
+    private BigDecimal trafficFee;
+
+    /**
+     * 优惠券抵扣金额
+     */
+    @ApiModelProperty("优惠券抵扣金额")
+    private BigDecimal  couponDiscount;
+
+    @ApiModelProperty("订单号")
+    private String orderNo;
+
+    @ApiModelProperty("下单时间")
+    private String createTime;
+
+    @ApiModelProperty("付款时间")
+    private String  paidTime;
+
+    @ApiModelProperty("付款方式")
+    private Integer paymentMethod;
+
+    @ApiModelProperty("付款方式中文")
+    private String paymentMethodName;
+
+    @ApiModelProperty("订单状态流转列表")
+    private List<OrderStatusFlowVO> orderStatusFlowList;
+}

+ 21 - 0
nightFragrance-massage/src/main/java/com/ylx/order/domain/vo/OrderStatusFlowVO.java

@@ -0,0 +1,21 @@
+package com.ylx.order.domain.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 类描述:订单流转状态记录VO
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/9 9:21
+ */
+@Data
+public class OrderStatusFlowVO {
+
+    @ApiModelProperty("订单状态名称")
+    private String statusName;
+
+    @ApiModelProperty("创建时间")
+    private String createTime;
+}

+ 11 - 0
nightFragrance-massage/src/main/java/com/ylx/order/enums/PaymentMethodEnum.java

@@ -16,4 +16,15 @@ public enum PaymentMethodEnum {
         this.code = code;
         this.info = info;
     }
+    public static String getNameByCode(Integer code) {
+        if (code == null) {
+            return "";
+        }
+        for (PaymentMethodEnum method : values()) {
+            if (method.code.equals(code)) {
+                return method.info;
+            }
+        }
+        return "";
+    }
 }

+ 8 - 0
nightFragrance-massage/src/main/java/com/ylx/order/service/TOrderService.java

@@ -13,6 +13,7 @@ import com.ylx.order.domain.dto.OrderDateQueryDTO;
 import com.ylx.order.domain.dto.OrderSubmitDTO;
 import com.ylx.order.domain.dto.OrderUpdateStatusDTO;
 import com.ylx.order.domain.vo.OrderDateQueryVo;
+import com.ylx.order.domain.vo.OrderDetailVO;
 
 import java.math.BigDecimal;
 import java.util.Date;
@@ -176,4 +177,11 @@ public interface TOrderService extends IService<TOrder> {
      * @param dto
      */
     void updateOrderStatus(OrderUpdateStatusDTO dto);
+
+    /**
+     * 根据订单ID查询订单详情
+     * @param orderId 订单主键ID
+     * @return 订单详情VO
+     */
+    OrderDetailVO getOrderDetailById(Long orderId);
 }

+ 179 - 1
nightFragrance-massage/src/main/java/com/ylx/order/service/impl/TOrderServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+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;
@@ -12,14 +13,18 @@ import com.ylx.common.core.domain.model.WxLoginUser;
 import com.ylx.common.exception.ServiceException;
 import com.ylx.common.utils.DateUtils;
 import com.ylx.common.utils.SecurityUtils;
+import com.ylx.common.utils.StringUtils;
 import com.ylx.common.weixinPay.enums.WxPayTypeEnum;
 import com.ylx.common.weixinPay.service.WxPayV3Service;
+import com.ylx.massage.domain.MaProject;
 import com.ylx.massage.domain.MaTechnician;
 import com.ylx.massage.domain.TAddress;
 import com.ylx.massage.domain.TWxUser;
 import com.ylx.massage.domain.vo.HomeBlock;
 import com.ylx.massage.domain.vo.OrderVerificationVo;
 import com.ylx.massage.domain.vo.TechnicianAvailabilityVo;
+import com.ylx.massage.mapper.MaProjectMapper;
+import com.ylx.massage.mapper.MaTechnicianMapper;
 import com.ylx.massage.service.CouponService;
 import com.ylx.massage.service.IMaTechnicianService;
 import com.ylx.massage.service.TAddressService;
@@ -31,9 +36,10 @@ import com.ylx.order.domain.dto.OrderDateQueryDTO;
 import com.ylx.order.domain.dto.OrderSubmitDTO;
 import com.ylx.order.domain.dto.OrderUpdateStatusDTO;
 import com.ylx.order.domain.vo.OrderDateQueryVo;
+import com.ylx.order.domain.vo.OrderDetailVO;
+import com.ylx.order.domain.vo.OrderStatusFlowVO;
 import com.ylx.order.enums.OrderStatusEnum;
 import com.ylx.order.enums.PaymentMethodEnum;
-import com.ylx.order.mapper.OrderStatusFlowMapper;
 import com.ylx.order.mapper.TOrderMapper;
 import com.ylx.order.service.OrderStatusFlowService;
 import com.ylx.order.service.TOrderService;
@@ -50,6 +56,7 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.annotation.Resource;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.format.DateTimeFormatter;
@@ -63,7 +70,9 @@ import java.util.stream.Collectors;
 @Service
 @Slf4j
 public class TOrderServiceImpl extends ServiceImpl<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");
     private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("M月d日");
     private final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");
     @Resource
@@ -86,6 +95,11 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
     @Resource
     private OrderStatusFlowService orderStatusFlowService;
 
+    @Resource
+    private MaTechnicianMapper maTechnicianMapper;
+
+    @Resource
+    private MaProjectMapper maProjectMapper;
     @Override
     public TOrder addOrder(TOrder order) {
         return null;
@@ -572,4 +586,168 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
             throw new ServiceException("支付服务异常,请稍后重试");
         }
     }
+
+    /**
+     * 根据订单ID查询订单详情
+     */
+    @Override
+    public OrderDetailVO getOrderDetailById(Long orderId) {
+        if (orderId == null || orderId <= 0) {
+            throw new ServiceException("订单ID无效");
+        }
+
+        // 1. 根据ID查询订单主表
+        TOrder order = this.baseMapper.selectById(orderId);
+        if (order == null || order.getIsDelete() == 1) {
+            throw new ServiceException("订单不存在,订单ID:" + orderId);
+        }
+
+        // 2. 查询订单状态流转记录
+        LambdaQueryWrapper<OrderStatusFlow> flowWrapper = Wrappers.<OrderStatusFlow>lambdaQuery()
+                .eq(OrderStatusFlow::getOrderId, order.getId())
+                .orderByAsc(OrderStatusFlow::getCreateTime);
+        List<OrderStatusFlow> flowList = orderStatusFlowService.getBaseMapper().selectList(flowWrapper);
+
+        // 3. 组装VO
+        return buildOrderDetailVO(order, flowList);
+    }
+    /**
+     * 将订单实体和流转记录转换为详情VO
+     */
+    private OrderDetailVO buildOrderDetailVO(TOrder order, List<OrderStatusFlow> flowList) {
+        OrderDetailVO vo = new OrderDetailVO();
+
+        // 基础订单信息
+        vo.setOrderStatus(order.getStatus());
+        vo.setOrderStatusName(OrderStatusEnum.getInfoByCode(order.getStatus()));
+        vo.setMerchantAvatar(order.getMerchantAvatar());
+        // 1. 获取服务次数(从项目表获取 projectUsersNum)
+        Integer serviceNum = null;
+        if (order.getProjectId() != null && order.getMerchantId() != null) {
+            MaProject project = maProjectMapper.selectByProjectIdAndMerchantId(
+                    order.getProjectId(),
+                    order.getMerchantId()
+            );
+            if (project != null && project.getProjectUsersNum() != null) {
+                serviceNum = project.getProjectUsersNum().intValue();
+            }
+        }
+        vo.setServiceNum(serviceNum);
+
+        // 查询技师表
+        if (order.getMerchantId() != null) {
+            // merchantId 为 Long,技师表 id 为 Integer,需转换
+            MaTechnician technician = maTechnicianMapper.selectById(order.getMerchantId().intValue());
+            if (technician != null) {
+                //评分
+                vo.setStar(technician.getNStar());
+                //简介
+                vo.setBrief(technician.getTeBrief());
+            } else {
+                log.warn("技师信息不存在,merchantId: {}", order.getMerchantId());
+            }
+        } else {
+            // 无 merchantId,字段置空(或可后续扩展)
+            vo.setStar(null);
+            vo.setBrief(null);
+        }
+
+        vo.setProjectName(order.getProjectName());
+        vo.setProjectDuration(order.getProjectDuration());
+        vo.setHighlight(order.getHighlight());
+        vo.setFinalAmount(order.getFinalAmount());
+        vo.setBasePrice(order.getBasePrice());
+        vo.setTrafficFee(order.getTrafficFee());
+        vo.setCouponDiscount(order.getCouponDiscount());
+        vo.setOrderNo(order.getOrderNo());
+
+        // 时间处理
+        if (order.getAppointmentStartTime() != null) {
+            LocalDateTime start = order.getAppointmentStartTime();
+            // 预约结束时间 = 开始时间 + 项目时长(分钟)
+            LocalDateTime end = start.plusMinutes(order.getProjectDuration() == null ? 0 : order.getProjectDuration());
+
+            // 原始格式
+            vo.setAppointmentStartTime(start.format(DATE_TIME_FORMATTER));
+            vo.setAppointmentEndTime(end.format(DATE_TIME_FORMATTER));
+
+            // 生成“5月12日 16:00-18:00”格式
+            String timeRange = formatAppointmentTimeRange(start, end);
+            vo.setAppointmentTimeRange(timeRange);
+        }
+        if (order.getCreateTime() != null) {
+            vo.setCreateTime(DATE_FORMAT.format(order.getCreateTime()));
+        }
+        if (order.getPaidTime() != null) {
+            vo.setPaidTime(order.getPaidTime().format(DATE_TIME_FORMATTER));
+        }
+
+        vo.setContactAddresInfo(order.getContactAddressInfo());
+        // 联系信息组合:姓名 + 手机号(中间4位脱敏)
+        String contactInfo = buildContactInfo(order.getContactPersonName(), order.getContactPhoneNumber());
+        vo.setContactInfo(contactInfo);
+
+        vo.setPaymentMethod(order.getPaymentMethod());
+        vo.setPaymentMethodName(PaymentMethodEnum.getNameByCode(order.getPaymentMethod()));
+
+        // 订单状态流转列表转换
+        List<OrderStatusFlowVO> flowVOList = flowList.stream()
+                .map(this::convertToFlowVO)
+                .sorted(Comparator.comparing(OrderStatusFlowVO::getCreateTime))
+                .collect(Collectors.toList());
+        vo.setOrderStatusFlowList(flowVOList);
+
+        return vo;
+    }
+    /**
+     * 格式化预约时间范围
+     * @param start 预约开始时间
+     * @param end   预约结束时间
+     * @return 示例:5月12日 16:00-18:00
+     */
+    private String formatAppointmentTimeRange(LocalDateTime start, LocalDateTime end) {
+        if (start == null) {
+            return "";
+        }
+        // 日期格式:M月d日(不带年份,同一年内)
+        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("M月d日");
+        String dateStr = start.format(dateFormatter);
+        // 时间格式:HH:mm
+        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");
+        String startTime = start.format(timeFormatter);
+        String endTime = (end != null) ? end.format(timeFormatter) : "";
+        return dateStr + " " + startTime + "-" + endTime;
+    }
+    /**
+     * 构建联系信息(姓名 + 脱敏手机号)
+     * 示例:王先生,188****5555
+     */
+    private String buildContactInfo(String name, String phone) {
+        if (!StringUtils.hasText(name) && !StringUtils.hasText(phone)) {
+            return "";
+        }
+        String maskedPhone = "";
+        if (StringUtils.hasText(phone) && phone.length() >= 11) {
+            maskedPhone = phone.substring(0, 3) + "****" + phone.substring(7);
+        } else if (StringUtils.hasText(phone)) {
+            maskedPhone = phone; // 长度不足则直接显示
+        }
+        if (StringUtils.hasText(name)) {
+            return name + "," + maskedPhone;
+        } else {
+            return maskedPhone;
+        }
+    }
+
+    /**
+     * 将 OrderStatusFlow 转换为 OrderStatusFlowVO
+     */
+    private OrderStatusFlowVO convertToFlowVO(OrderStatusFlow flow) {
+        OrderStatusFlowVO vo = new OrderStatusFlowVO();
+        vo.setStatusName(OrderStatusEnum.getInfoByCode(flow.getStatus()));
+        if (flow.getCreateTime() != null) {
+            vo.setCreateTime(DATE_FORMAT.format(flow.getCreateTime()));
+        }
+        return vo;
+    }
 }