Jelajahi Sumber

开发接口

jinshihui 2 hari lalu
induk
melakukan
6683708206

+ 39 - 0
nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/TOrderController.java

@@ -145,6 +145,45 @@ public class TOrderController extends BaseController {
         }
     }
 
+
+    /**
+     * 取消订单申请
+     *
+     * 业务流程:
+     * 1. 用户在订单详情页点击"取消订单"按钮
+     * 2. 填写退单原因(必填,最多50字符)
+     * 3. 提交申请
+     * 4. 系统创建退单申请记录,状态为待审核
+     * 5. 等待客服审核
+     *
+     * 请求参数示例:
+     * {
+     *   "cId": "订单ID",
+     *   "cNote": "退单原因"
+     * }
+     *
+     * @param order 订单对象,必须包含cId(订单ID)和cNote(退单原因)
+     * @return R 成功返回"申请已提交,等待客服审核"
+     */
+    @Log(title = "取消订单申请", businessType = BusinessType.UPDATE)
+    @ApiOperation("取消订单申请")
+    @RequestMapping(value = "wx/applyCancle", method = RequestMethod.POST)
+    public R applyCancle(@RequestBody TOrder order) {
+        try {
+            log.info("收到退单申请请求,订单ID:{},退单原因:{}", order.getcId(), order.getcNote());
+            // 调用服务层处理退单申请
+            orderService.applyCancle(order);
+            // 返回成功提示
+            return R.ok("您的申请已提交,客服审核中,请注意接听客服电话:19936963696");
+        } catch (ServiceException s) {
+            log.error("退单申请失败:{}", s.getMessage());
+            return R.fail(s.getMessage());
+        } catch (Exception e) {
+            log.error("退单申请系统异常", e);
+            return R.fail("系统异常,请稍后重试");
+        }
+    }
+
     /**
      * 取消订单(用户操作的接口)
      *

+ 141 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/CancelOrderApplication.java

@@ -0,0 +1,141 @@
+package com.ylx.massage.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Data
+@TableName("t_cancel_order_application")
+public class CancelOrderApplication implements Serializable {
+
+
+    private static final long serialVersionUID = -791497428662364669L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(type = IdType.ASSIGN_ID)
+    private String id;
+
+    /**
+     * 订单ID
+     */
+    private String orderId;
+
+    /**
+     * 订单号
+     */
+    private String orderNo;
+
+    /**
+     * 微信用户ID
+     */
+    private String openId;
+
+    /**
+     * 用户姓名
+     */
+    private String userName;
+
+    /**
+     * 用户手机号
+     */
+    private String userPhone;
+
+    /**
+     * 技师ID
+     */
+    private String techId;
+
+    /**
+     * 技师姓名
+     */
+    private String techName;
+
+    /**
+     * 技师昵称
+     */
+    private String techNickName;
+
+    /**
+     * 服务项目名称
+     */
+    private String projectName;
+
+    /**
+     * 服务时长(分钟)
+     */
+    private String serviceDuration;
+
+    /**
+     * 订单金额(元)
+     */
+    private BigDecimal orderAmount;
+
+    /**
+     * 退款金额(元)
+     */
+    private BigDecimal refundAmount;
+
+    /**
+     * 审核状态(0:待审核,1:已审核,2:已拒绝)
+     */
+    private Integer auditStatus;
+
+    /**
+     * 申请时间
+     */
+    private LocalDateTime applicationTime;
+
+    /**
+     * 退单原因(申请备注)
+     */
+    private String cancelOrderReason;
+
+     /**
+     * 审核人ID
+     */
+    private String auditUserId;
+
+     /**
+     * 审核人姓名
+     */
+    private String auditUserName;
+
+     /**
+     * 审核时间
+     */
+    private LocalDateTime auditTime;
+
+     /**
+     * 审核备注
+     */
+    private String auditRemark;
+
+     /**
+     * 退单处理时间
+     */
+    private LocalDateTime cancelOrderProcessTime;
+
+     /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+     /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+     /**
+     * 删除状态(0:正常,1:已删除)
+     */
+    @TableLogic
+    private Integer isDelete;
+}

+ 7 - 3
nightFragrance-massage/src/main/java/com/ylx/massage/domain/TWxUser.java

@@ -27,15 +27,19 @@ public class TWxUser implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
-
+    /**
+     * 主键
+     */
     @TableId("id")
     @ApiModelProperty("Id")
     private String id;
+
+
     /**
-     * 微信小程序openId
+     * 用户的openId
      */
     @TableField("c_openid")
-    @ApiModelProperty("微信小程序openId")
+    @ApiModelProperty("用户的openId")
     private String cOpenid;
 
     /**

+ 15 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/enums/OrderStatusEnum.java

@@ -54,6 +54,21 @@ public enum OrderStatusEnum {
      */
     COMPLETE(5, "已完成"),
 
+    /**
+     * 退单待审核
+     */
+    CANCEL_APPLICATION_PENDING(6, "退单待审核"),
+
+    /**
+     * 退单审核通过
+     */
+    CANCEL_APPLICATION_PASS(7, "退单审核通过"),
+
+    /**
+     * 退单审核拒绝
+     */
+    CANCEL_APPLICATION_REFUSE(8, "退单审核拒绝"),
+
     /**
      * 待付款
      */

+ 15 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/mapper/CancelOrderApplicationMapper.java

@@ -0,0 +1,15 @@
+package com.ylx.massage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ylx.massage.domain.CancelOrderApplication;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 退单申请Mapper接口
+ *
+ * @author claude
+ * @date 2025-01-14
+ */
+@Mapper
+public interface CancelOrderApplicationMapper extends BaseMapper<CancelOrderApplication> {
+}

+ 30 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/service/CancelOrderApplicationService.java

@@ -0,0 +1,30 @@
+package com.ylx.massage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ylx.massage.domain.CancelOrderApplication;
+
+/**
+ * 退单申请服务接口
+ *
+ * @author claude
+ * @date 2025-01-14
+ */
+public interface CancelOrderApplicationService extends IService<CancelOrderApplication> {
+
+    /**
+     * 创建退单申请
+     *
+     * @param orderId 订单ID
+     * @param cancelReason 退单原因
+     * @return 申请记录ID
+     */
+    String createApplication(String orderId, String cancelReason);
+
+    /**
+     * 根据订单ID查询最新的退单申请
+     *
+     * @param orderId 订单ID
+     * @return 退单申请记录
+     */
+    CancelOrderApplication getLatestByOrderId(String orderId);
+}

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

@@ -86,4 +86,11 @@ public interface TOrderService extends IService<TOrder> {
      * @return 技师当天可预约时间VO
      */
     TechnicianAvailabilityVo getTechnicianAvailability(String technicianId, String dateStr);
+
+    /**
+     * 申请取消订单(退单申请)
+     * @param order 订单对象,需要包含cId(订单ID)和退单原因
+     * @return 申请结果
+     */
+    Boolean applyCancle(TOrder order);
 }

+ 215 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/CancelOrderApplicationServiceImpl.java

@@ -0,0 +1,215 @@
+package com.ylx.massage.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ylx.common.exception.ServiceException;
+import com.ylx.common.utils.StringUtils;
+import com.ylx.massage.domain.CancelOrderApplication;
+import com.ylx.massage.domain.TJs;
+import com.ylx.massage.domain.TOrder;
+import com.ylx.massage.domain.TWxUser;
+import com.ylx.massage.enums.OrderStatusEnum;
+import com.ylx.massage.service.CancelOrderApplicationService;
+import com.ylx.massage.service.TJsService;
+import com.ylx.massage.service.TOrderService;
+import com.ylx.massage.service.TWxUserService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * 退单申请服务实现类
+ *
+ * @author claude
+ * @date 2025-01-14
+ */
+@Slf4j
+@Service
+public class CancelOrderApplicationServiceImpl extends ServiceImpl<com.ylx.massage.mapper.CancelOrderApplicationMapper, CancelOrderApplication>
+        implements CancelOrderApplicationService {
+
+    @Autowired
+    private TOrderService orderService;
+
+    @Autowired
+    private TJsService jsService;
+
+    @Autowired
+    private TWxUserService wxUserService;
+
+    /**
+     * 创建退单申请
+     *
+     * @param orderId 订单ID
+     * @param cancelReason 退单原因
+     * @return String 申请记录ID
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String createApplication(String orderId, String cancelReason) {
+        log.info("开始创建退单申请,订单ID:{},退单原因:{}", orderId, cancelReason);
+
+        // 1. 参数校验
+        if (StringUtils.isEmpty(orderId)) {
+            throw new ServiceException("订单ID不能为空");
+        }
+        if (StringUtils.isEmpty(cancelReason)) {
+            throw new ServiceException("退单原因不能为空");
+        }
+        if (cancelReason.length() > 50) {
+            throw new ServiceException("退单原因不能超过50个字符");
+        }
+
+        // 2. 查询订单信息
+        TOrder order = orderService.getById(orderId);
+        if (order == null) {
+            throw new ServiceException("订单不存在");
+        }
+
+        // 3. 校验订单状态 - 只有进行中的订单才能申请退单
+        // 进行中状态包括: 待接单(0)、已接单(1)、已出发(6)、已到达(2)、服务中(3)
+        Integer currentStatus = order.getnStatus();
+        if (!isOrderInProgress(currentStatus)) {
+            throw new ServiceException("当前订单状态不允许申请退单,只有进行中的订单可以申请退单");
+        }
+
+        // 4. 检查是否已有待审核的退单申请
+        CancelOrderApplication existingApplication = getLatestByOrderId(orderId);
+        if (existingApplication != null && existingApplication.getAuditStatus() == 0) {
+            throw new ServiceException("该订单已有待审核的退单申请,请勿重复提交");
+        }
+
+
+        // 6. 查询技师信息
+        TJs technician = null;
+        if (StringUtils.isNotEmpty(order.getcJsId())) {
+            technician = jsService.getById(order.getcJsId());
+        }
+
+        // 7. 构建退单申请记录
+        CancelOrderApplication application = new CancelOrderApplication();
+        application.setOrderId(order.getcId());
+        application.setOrderNo(order.getOrderNo());
+        application.setOpenId(order.getcOpenId());
+        application.setUserName(order.getcName());
+        application.setUserPhone(order.getcPhone());
+        application.setTechId(order.getcJsId());
+        application.setTechName(technician != null ? technician.getcName() : null);
+        application.setTechNickName(technician != null ? technician.getcNickName() : null);
+
+        // 从订单明细中提取项目名称
+        String projectName = extractProjectName(order);
+        application.setProjectName(projectName);
+
+        // 计算已服务时长
+        String serviceDuration = calculateServiceDuration(order);
+        application.setServiceDuration(serviceDuration);
+
+        // 设置金额
+        application.setOrderAmount(order.getTotalPrice() != null ? order.getTotalPrice() : BigDecimal.ZERO);
+        //application.setRefundAmount(order.getTotalPrice() != null ? order.getTotalPrice() : BigDecimal.ZERO);
+
+        // 设置申请信息
+        application.setAuditStatus(0); // 0:待审核
+        application.setApplicationTime(LocalDateTime.now());
+        application.setCancelOrderReason(cancelReason);
+
+        // 设置创建时间
+        application.setCreateTime(LocalDateTime.now());
+        application.setUpdateTime(LocalDateTime.now());
+        application.setIsDelete(0);
+
+        // 8. 保存退单申请记录
+        boolean saved = this.save(application);
+        if (!saved) {
+            throw new ServiceException("创建退单申请失败");
+        }
+        log.info("退单申请创建成功,申请ID:{},订单ID:{}", application.getId(), orderId);
+        return application.getId();
+    }
+
+    /**
+     * 根据订单ID查询最新的退单申请
+     *
+     * @param orderId 订单ID
+     * @return CancelOrderApplication 退单申请记录
+     */
+    @Override
+    public CancelOrderApplication getLatestByOrderId(String orderId) {
+        LambdaQueryWrapper<CancelOrderApplication> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(CancelOrderApplication::getOrderId, orderId)
+                .orderByDesc(CancelOrderApplication::getCreateTime)
+                .last("LIMIT 1");
+        return this.getOne(wrapper);
+    }
+
+    /**
+     * 判断订单是否为进行中状态
+     * 进行中状态包括: 待接单(0)、已接单(1)、已出发(6)、已到达(2)、服务中(3)
+     *
+     * @param status 订单状态
+     * @return true-进行中,false-非进行中
+     */
+    private boolean isOrderInProgress(Integer status) {
+        return status != null &&
+                (status.equals(OrderStatusEnum.WAIT_JD.getCode()) ||      // 待接单
+                        status.equals(OrderStatusEnum.RECEIVED_ORDER.getCode()) ||  // 已接单
+                        status.equals(OrderStatusEnum.DEPART.getCode()) ||          // 已出发
+                        status.equals(OrderStatusEnum.ARRIVED.getCode()) ||         // 已到达
+                        status.equals(OrderStatusEnum.SERVICE.getCode()));           // 服务中
+    }
+
+    /**
+     * 从订单中提取项目名称
+     *
+     * @param order 订单对象
+     * @return String 项目名称
+     */
+    private String extractProjectName(TOrder order) {
+        try {
+            if (order.getcGoods() != null && !order.getcGoods().isEmpty()) {
+                // cGoods是JSONArray,解析第一个项目的名称
+                return order.getcGoods().getJSONObject(0).getString("cTitle");
+            }
+        } catch (Exception e) {
+            log.warn("解析订单项目名称失败,订单ID:{}", order.getcId(), e);
+        }
+        return null;
+    }
+
+    /**
+     * 计算已服务时长(分钟)
+     *
+     * @param order 订单对象
+     * @return String服务时长字符串,如"40分钟"
+     */
+    private String calculateServiceDuration(TOrder order) {
+        try {
+            LocalDateTime startTime = order.getStartTime();
+            LocalDateTime endTime = order.getEndTime();
+
+            if (startTime != null && endTime != null) {
+                long minutes = Duration.between(startTime, endTime).toMinutes();
+                if (minutes > 0) {
+                    return minutes + "分钟";
+                }
+            } else if (startTime != null) {
+                // 如果只有开始时间,计算到现在的时长
+                long minutes = Duration.between(startTime, LocalDateTime.now()).toMinutes();
+                if (minutes > 0) {
+                    return minutes + "分钟";
+                }
+            }
+        } catch (Exception e) {
+            log.warn("计算服务时长失败,订单ID:{}", order.getcId(), e);
+        }
+        return "0分钟";
+    }
+}

+ 0 - 9
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TFareFreeRuleServiceImpl.java

@@ -141,15 +141,6 @@ public class TFareFreeRuleServiceImpl extends ServiceImpl<TFareFreeRuleMapper, T
                                     .build();
                             timeRangeVos.add(timeRangeVo);
                         }
-                        // 处理 TimeRange 类型(正常的类型)
-                        else if (item instanceof TFareFreeRule.TimeRange) {
-                            TFareFreeRule.TimeRange timeRange = (TFareFreeRule.TimeRange) item;
-                            TimeRangeVo timeRangeVo = TimeRangeVo.builder()
-                                    .startTime(timeRange.getStartTime())
-                                    .endTime(timeRange.getEndTime())
-                                    .build();
-                            timeRangeVos.add(timeRangeVo);
-                        }
                     } catch (Exception e) {
                         log.error("转换时间段失败,item类型:{},内容:{}", item.getClass().getName(), item, e);
                     }

+ 52 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TOrderServiceImpl.java

@@ -98,6 +98,9 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
     @Resource
     private OrderAllocationLogService allocationLogService;
 
+    @Resource
+    private CancelOrderApplicationService cancelOrderApplicationService;
+
     /**
      * 判断是否免车费
      * 时间段判断:
@@ -220,6 +223,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
         order.setLatitude(address.getLatitude());
         order.setLongitude(address.getLongitude());
         order.setcPhone(address.getPhone());
+        //设置用户姓名
         order.setcName(address.getUserName());
         order.setAtlasAdd(address.getAtlasAdd());
         order.setDeptId(js.getDeptId());
@@ -1256,4 +1260,52 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
         jsService.updateById(js);
     }
 
+    /**
+     * 申请取消订单(退单申请)
+     *
+     * 业务流程:
+     * 1. 校验订单状态(仅进行中的订单可申请退单)
+     * 2. 创建退单申请记录
+     * 3. 更新订单状态为"退单待审核"
+     *
+     * @param order 订单对象
+     * @return Boolean 申请结果
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean applyCancle(TOrder order) {
+        log.info("开始处理退单申请,订单ID:{}", order.getcId());
+
+        // 1. 参数校验
+        if (StringUtils.isBlank(order.getcId())) {
+            throw new ServiceException("订单ID不能为空");
+        }
+        if (StringUtils.isBlank(order.getcNote())) {
+            throw new ServiceException("退单原因不能为空");
+        }
+
+        // 2. 查询订单信息
+        TOrder existingOrder = this.getById(order.getcId());
+        if (existingOrder == null) {
+            throw new ServiceException("订单不存在");
+        }
+
+        // 3. 创建退单申请记录(内部会校验订单状态和其他业务规则)
+        String applicationId;
+        try {
+            applicationId = cancelOrderApplicationService.createApplication(existingOrder.getcId(), order.getcNote());
+            log.info("退单申请记录创建成功,申请ID:{}", applicationId);
+        } catch (ServiceException e) {
+            log.error("创建退单申请失败:{}", e.getMessage());
+            throw e;
+        }
+
+        // 4. 更新订单状态为"退单待审核"
+        existingOrder.setnStatus(OrderStatusEnum.CANCEL_APPLICATION_PENDING.getCode());
+        this.updateById(existingOrder);
+
+        log.info("退单申请处理完成,订单ID:{},申请ID:{}", existingOrder.getcId(), applicationId);
+        return Boolean.TRUE;
+    }
+
 }