|
|
@@ -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;
|
|
|
+ }
|
|
|
}
|