|
|
@@ -0,0 +1,1787 @@
|
|
|
+package shop.alien.lawyer.service.impl;
|
|
|
+
|
|
|
+import com.alibaba.fastjson2.JSONObject;
|
|
|
+import com.alibaba.nacos.common.utils.CollectionUtils;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang.math.RandomUtils;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
+import shop.alien.entity.result.R;
|
|
|
+import shop.alien.entity.store.*;
|
|
|
+import shop.alien.entity.store.dto.LawyerConsultationOrderDto;
|
|
|
+import shop.alien.entity.store.dto.PayStatusRequest;
|
|
|
+import shop.alien.entity.store.vo.LawyerConsultationOrderVO;
|
|
|
+import shop.alien.entity.store.vo.OrderRevenueVO;
|
|
|
+import shop.alien.entity.store.vo.WebSocketVo;
|
|
|
+import shop.alien.lawyer.config.WebSocketProcess;
|
|
|
+import shop.alien.lawyer.service.LawyerConsultationOrderService;
|
|
|
+import shop.alien.lawyer.service.LawyerUserService;
|
|
|
+import shop.alien.lawyer.service.OrderExpirationService;
|
|
|
+import shop.alien.lawyer.util.DateUtils;
|
|
|
+import shop.alien.mapper.*;
|
|
|
+import shop.alien.util.common.constant.LawyerStatusEnum;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 咨询订单 服务实现类
|
|
|
+ *
|
|
|
+ * @author system
|
|
|
+ * @since 2025-01-XX
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Transactional
|
|
|
+@Service
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class LawyerConsultationOrderServiceImpl extends ServiceImpl<LawyerConsultationOrderMapper, LawyerConsultationOrder> implements LawyerConsultationOrderService {
|
|
|
+
|
|
|
+ private final LawyerConsultationOrderMapper consultationOrderMapper;
|
|
|
+ private final LawyerUserService lawyerUserService;
|
|
|
+ private final LawyerServiceAreaMapper lawyerServiceAreaMapper;
|
|
|
+ private final LawyerUserMapper lawyerUserMapper;
|
|
|
+ private final LawyerExpertiseAreaMapper lawyerExpertiseAreaMapper;
|
|
|
+ private final OrderExpirationService orderExpirationService;
|
|
|
+// private final AliApi aliApi;
|
|
|
+ private final LawFirmMapper lawFirmMapper;
|
|
|
+ private final LifeNoticeMapper lifeNoticeMapper;
|
|
|
+ private final LifeUserMapper lifeUserMapper;
|
|
|
+ private final WebSocketProcess webSocketProcess;
|
|
|
+
|
|
|
+ private final LifeMessageMapper lifeMessageMapper;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 系统发送者ID
|
|
|
+ */
|
|
|
+ private static final String SYSTEM_SENDER_ID = "system";
|
|
|
+
|
|
|
+ @Value("${order.coefficients}")
|
|
|
+ private String coefficients;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<IPage<LawyerConsultationOrderVO>> getConsultationOrderList(int pageNum, int pageSize, String orderNumber,
|
|
|
+ Integer clientUserId, Integer lawyerUserId, String lawyerName, Integer orderStatus) {
|
|
|
+ log.info("LawyerConsultationOrderServiceImpl.getConsultationOrderList?pageNum={},pageSize={},orderNumber={},clientUserId={},lawyerUserId={},lawyerName={},orderStatus={}",
|
|
|
+ pageNum, pageSize, orderNumber, clientUserId, lawyerUserId, lawyerName, orderStatus);
|
|
|
+
|
|
|
+ // 創建分頁對象
|
|
|
+ Page<LawyerConsultationOrderVO> page = new Page<>(pageNum, pageSize);
|
|
|
+
|
|
|
+ // 如果按律師姓名搜索,先查詢匹配的律師ID列表
|
|
|
+ List<Integer> lawyerUserIds = null;
|
|
|
+ if (StringUtils.hasText(lawyerName)) {
|
|
|
+ LambdaQueryWrapper<LawyerUser> lawyerQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ lawyerQueryWrapper.eq(LawyerUser::getDeleteFlag, 0);
|
|
|
+ lawyerQueryWrapper.like(LawyerUser::getName, lawyerName);
|
|
|
+ List<LawyerUser> lawyerUsers = lawyerUserService.list(lawyerQueryWrapper);
|
|
|
+ if (lawyerUsers != null && !lawyerUsers.isEmpty()) {
|
|
|
+ lawyerUserIds = lawyerUsers.stream()
|
|
|
+ .map(LawyerUser::getId)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ } else {
|
|
|
+ // 如果沒有找到匹配的律師,返回空結果
|
|
|
+ Page<LawyerConsultationOrderVO> emptyPage = new Page<>(pageNum, pageSize);
|
|
|
+ emptyPage.setRecords(Collections.emptyList());
|
|
|
+ emptyPage.setTotal(0);
|
|
|
+ return R.data(emptyPage);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用JOIN查詢,直接聯查律師信息
|
|
|
+ IPage<LawyerConsultationOrderVO> voPage = consultationOrderMapper.getConsultationOrderListWithLawyer(
|
|
|
+ page, orderNumber, clientUserId, lawyerUserId, lawyerName, orderStatus, lawyerUserIds);
|
|
|
+
|
|
|
+ // 為待支付訂單計算倒計時(30分鐘有效期)
|
|
|
+ if (voPage != null && voPage.getRecords() != null) {
|
|
|
+ Date now = new Date();
|
|
|
+ long validitySeconds = 30 * 60; // 30分鐘 = 1800秒
|
|
|
+
|
|
|
+ for (LawyerConsultationOrderVO vo : voPage.getRecords()) {
|
|
|
+ // 僅對待支付訂單(orderStatus=0)計算倒計時
|
|
|
+ if (vo.getOrderStatus() != null && vo.getOrderStatus() == 0) {
|
|
|
+ Date orderTime = vo.getOrderTime();
|
|
|
+ if (orderTime != null) {
|
|
|
+ long elapsedSeconds = (now.getTime() - orderTime.getTime()) / 1000;
|
|
|
+ long remainingSeconds = validitySeconds - elapsedSeconds;
|
|
|
+ // 如果已過期,設置為0
|
|
|
+ vo.setCountdownSeconds(Math.max(0, remainingSeconds));
|
|
|
+ } else {
|
|
|
+ vo.setCountdownSeconds(0L);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 非待支付訂單,倒計時為null
|
|
|
+ vo.setCountdownSeconds(null);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return R.data(voPage);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 將訂單分頁結果轉換為VO並填充律師信息
|
|
|
+ */
|
|
|
+ private IPage<LawyerConsultationOrderVO> convertToVO(IPage<LawyerConsultationOrder> pageResult) {
|
|
|
+ // 創建VO分頁對象
|
|
|
+ Page<LawyerConsultationOrderVO> voPage = new Page<>(pageResult.getCurrent(), pageResult.getSize(), pageResult.getTotal());
|
|
|
+
|
|
|
+ List<LawyerConsultationOrder> records = pageResult.getRecords();
|
|
|
+ if (records == null || records.isEmpty()) {
|
|
|
+ voPage.setRecords(Collections.emptyList());
|
|
|
+ return voPage;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 收集所有律師ID
|
|
|
+ Set<Integer> lawyerUserIds = records.stream()
|
|
|
+ .map(LawyerConsultationOrder::getLawyerUserId)
|
|
|
+ .filter(id -> id != null)
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+
|
|
|
+ // 批量查詢律師信息
|
|
|
+ Map<Integer, LawyerUser> lawyerMap = new HashMap<>();
|
|
|
+ if (!lawyerUserIds.isEmpty()) {
|
|
|
+ LambdaQueryWrapper<LawyerUser> lawyerWrapper = new LambdaQueryWrapper<>();
|
|
|
+ lawyerWrapper.in(LawyerUser::getId, lawyerUserIds);
|
|
|
+ lawyerWrapper.eq(LawyerUser::getDeleteFlag, 0);
|
|
|
+ List<LawyerUser> lawyerUsers = lawyerUserService.list(lawyerWrapper);
|
|
|
+ if (lawyerUsers != null && !lawyerUsers.isEmpty()) {
|
|
|
+ lawyerMap = lawyerUsers.stream()
|
|
|
+ .collect(Collectors.toMap(LawyerUser::getId, lawyer -> lawyer, (k1, k2) -> k1));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 轉換為VO並填充律師信息
|
|
|
+ final Map<Integer, LawyerUser> finalLawyerMap = lawyerMap;
|
|
|
+ List<LawyerConsultationOrderVO> voList = records.stream()
|
|
|
+ .map(order -> {
|
|
|
+ LawyerConsultationOrderVO vo = new LawyerConsultationOrderVO();
|
|
|
+ // 複製訂單基本信息
|
|
|
+ BeanUtils.copyProperties(order, vo);
|
|
|
+
|
|
|
+ // 填充律師信息
|
|
|
+ LawyerUser lawyer = finalLawyerMap.get(order.getLawyerUserId());
|
|
|
+ if (lawyer != null) {
|
|
|
+ vo.setLawyerName(lawyer.getName());
|
|
|
+ vo.setLawyerPhone(lawyer.getPhone());
|
|
|
+ vo.setLawyerEmail(lawyer.getEmail());
|
|
|
+ vo.setLawyerCertificateNo(lawyer.getLawyerCertificateNo());
|
|
|
+ vo.setLawFirm(lawyer.getLawFirm());
|
|
|
+ vo.setPracticeYears(lawyer.getPracticeYears());
|
|
|
+ vo.setSpecialtyFields(lawyer.getSpecialtyFields());
|
|
|
+ vo.setCertificationStatus(lawyer.getCertificationStatus());
|
|
|
+ vo.setServiceScore(lawyer.getServiceScore());
|
|
|
+ vo.setServiceCount(lawyer.getServiceCount());
|
|
|
+ vo.setLawyerConsultationFee(lawyer.getConsultationFee());
|
|
|
+ vo.setProvince(lawyer.getProvince());
|
|
|
+ vo.setCity(lawyer.getCity());
|
|
|
+ vo.setDistrict(lawyer.getDistrict());
|
|
|
+ vo.setAddress(lawyer.getAddress());
|
|
|
+ vo.setHeadImg(lawyer.getHeadImg());
|
|
|
+ vo.setNickName(lawyer.getNickName());
|
|
|
+ vo.setPersonalIntroduction(lawyer.getPersonalIntroduction());
|
|
|
+ }
|
|
|
+
|
|
|
+ return vo;
|
|
|
+ })
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ voPage.setRecords(voList);
|
|
|
+ return voPage;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<LawyerConsultationOrder> addConsultationOrder(LawyerConsultationOrder consultationOrder) {
|
|
|
+ log.info("LawyerConsultationOrderServiceImpl.addConsultationOrder?consultationOrder={}", consultationOrder);
|
|
|
+ boolean result = this.save(consultationOrder);
|
|
|
+ if (result) {
|
|
|
+ return R.data(consultationOrder);
|
|
|
+ }
|
|
|
+ return R.fail("新增失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 编辑咨询订单
|
|
|
+ * <p>
|
|
|
+ * 编辑前会进行以下校验:
|
|
|
+ * 1. 参数校验:订单ID不能为空
|
|
|
+ * 2. 订单存在性校验:订单必须存在
|
|
|
+ * 3. 订单状态校验:已完成的订单不允许修改关键信息
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param consultationOrder 咨询订单
|
|
|
+ * @return 编辑结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public R<LawyerConsultationOrder> editConsultationOrder(LawyerConsultationOrder consultationOrder) {
|
|
|
+ Integer orderId = consultationOrder.getId();
|
|
|
+ log.info("开始编辑咨询订单,订单ID={}", orderId);
|
|
|
+
|
|
|
+ // 参数校验:订单ID不能为空
|
|
|
+ if (orderId == null) {
|
|
|
+ log.warn("编辑咨询订单失败:订单ID为空");
|
|
|
+ return R.fail("订单ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询订单信息,验证订单是否存在
|
|
|
+ LawyerConsultationOrder existingOrder = consultationOrderMapper.selectById(orderId);
|
|
|
+ if (existingOrder == null) {
|
|
|
+ log.warn("编辑咨询订单失败:订单不存在,订单ID={}", orderId);
|
|
|
+ return R.fail("订单不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 记录修改前的订单状态
|
|
|
+ Integer oldOrderStatus = existingOrder.getOrderStatus();
|
|
|
+ Integer oldPaymentStatus = existingOrder.getPaymentStatus();
|
|
|
+ Integer newOrderStatus = consultationOrder.getOrderStatus();
|
|
|
+ Integer newPaymentStatus = consultationOrder.getPaymentStatus();
|
|
|
+
|
|
|
+ log.info("编辑咨询订单,订单ID={}, 订单编号={}, 原订单状态={}, 新订单状态={}, 原支付状态={}, 新支付状态={}",
|
|
|
+ orderId, existingOrder.getOrderNumber(), oldOrderStatus, newOrderStatus,
|
|
|
+ oldPaymentStatus, newPaymentStatus);
|
|
|
+
|
|
|
+ // 订单状态校验:已完成的订单不允许修改关键信息(订单状态、支付状态、订单金额等)
|
|
|
+ Integer completedStatus = LawyerStatusEnum.COMPLETE.getStatus(); // 3:已完成
|
|
|
+ if (completedStatus.equals(oldOrderStatus)) {
|
|
|
+ // 如果订单已完成,只允许修改评价相关字段(rating, comment)
|
|
|
+ if (newOrderStatus != null && !newOrderStatus.equals(oldOrderStatus)) {
|
|
|
+ log.warn("编辑咨询订单失败:订单已完成,不允许修改订单状态,订单ID={}, 订单编号={}",
|
|
|
+ orderId, existingOrder.getOrderNumber());
|
|
|
+ return R.fail("订单已完成,不允许修改订单状态");
|
|
|
+ }
|
|
|
+ if (newPaymentStatus != null && !newPaymentStatus.equals(oldPaymentStatus)) {
|
|
|
+ log.warn("编辑咨询订单失败:订单已完成,不允许修改支付状态,订单ID={}, 订单编号={}",
|
|
|
+ orderId, existingOrder.getOrderNumber());
|
|
|
+ return R.fail("订单已完成,不允许修改支付状态");
|
|
|
+ }
|
|
|
+ if (consultationOrder.getOrderAmount() != null &&
|
|
|
+ !consultationOrder.getOrderAmount().equals(existingOrder.getOrderAmount())) {
|
|
|
+ log.warn("编辑咨询订单失败:订单已完成,不允许修改订单金额,订单ID={}, 订单编号={}",
|
|
|
+ orderId, existingOrder.getOrderNumber());
|
|
|
+ return R.fail("订单已完成,不允许修改订单金额");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 已取消的订单不允许修改为其他状态(除非是管理员操作,这里暂不限制)
|
|
|
+ Integer cancelStatus = LawyerStatusEnum.CANCEL.getStatus(); // 4:已取消
|
|
|
+ if (cancelStatus.equals(oldOrderStatus) && newOrderStatus != null &&
|
|
|
+ !cancelStatus.equals(newOrderStatus)) {
|
|
|
+ log.warn("编辑咨询订单警告:订单已取消,尝试修改订单状态,订单ID={}, 订单编号={}, 原状态={}, 新状态={}",
|
|
|
+ orderId, existingOrder.getOrderNumber(), oldOrderStatus, newOrderStatus);
|
|
|
+ // 这里可以根据业务需求决定是否允许,暂时允许修改
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果订单状态从待支付变为已支付,需要更新支付时间
|
|
|
+ Integer waitPayStatus = LawyerStatusEnum.WAIT_PAY.getStatus(); // 0:待支付
|
|
|
+ if (waitPayStatus.equals(oldOrderStatus) && newOrderStatus != null &&
|
|
|
+ !waitPayStatus.equals(newOrderStatus) && newPaymentStatus != null && newPaymentStatus == 1) {
|
|
|
+ if (consultationOrder.getPaymentTime() == null) {
|
|
|
+ consultationOrder.setPaymentTime(new Date());
|
|
|
+ log.info("订单状态从待支付变为已支付,自动设置支付时间,订单ID={}, 订单编号={}",
|
|
|
+ orderId, existingOrder.getOrderNumber());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置更新时间
|
|
|
+ consultationOrder.setUpdatedTime(new Date());
|
|
|
+
|
|
|
+ // 执行更新操作
|
|
|
+ boolean result = this.updateById(consultationOrder);
|
|
|
+ if (result) {
|
|
|
+ log.info("编辑咨询订单成功,订单ID={}, 订单编号={}, 原订单状态={}, 新订单状态={}",
|
|
|
+ orderId, existingOrder.getOrderNumber(), oldOrderStatus, newOrderStatus);
|
|
|
+ // 重新查询更新后的订单信息
|
|
|
+ LawyerConsultationOrder updatedOrder = consultationOrderMapper.selectById(orderId);
|
|
|
+ return R.data(updatedOrder != null ? updatedOrder : consultationOrder);
|
|
|
+ } else {
|
|
|
+ log.error("编辑咨询订单失败:数据库更新失败,订单ID={}, 订单编号={}",
|
|
|
+ orderId, existingOrder.getOrderNumber());
|
|
|
+ return R.fail("修改失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除咨询订单
|
|
|
+ * <p>
|
|
|
+ * 删除前会进行以下校验:
|
|
|
+ * 1. 参数校验:订单ID不能为空
|
|
|
+ * 2. 订单存在性校验:订单必须存在
|
|
|
+ * 3. 订单状态校验:进行中的订单不允许删除
|
|
|
+ * 4. 如果订单是待支付状态,会取消Redis中的支付超时计时器
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param id 订单ID
|
|
|
+ * @return 删除结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public R<Boolean> deleteConsultationOrder(Integer id) {
|
|
|
+ log.info("开始删除咨询订单,订单ID={}", id);
|
|
|
+
|
|
|
+ // 参数校验
|
|
|
+ if (id == null) {
|
|
|
+ log.warn("删除咨询订单失败:订单ID为空");
|
|
|
+ return R.fail("订单ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询订单信息
|
|
|
+ LawyerConsultationOrder order = consultationOrderMapper.selectById(id);
|
|
|
+ if (order == null) {
|
|
|
+ log.warn("删除咨询订单失败:订单不存在,订单ID={}", id);
|
|
|
+ return R.fail("订单不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查订单状态:进行中的订单不允许删除
|
|
|
+ Integer orderStatus = order.getOrderStatus();
|
|
|
+ Integer inProgressStatus = LawyerStatusEnum.INPROGRESS.getStatus(); // 2:进行中
|
|
|
+ if (inProgressStatus.equals(orderStatus)) {
|
|
|
+ log.warn("删除咨询订单失败:订单进行中,不允许删除,订单ID={}, 订单编号={}",
|
|
|
+ id, order.getOrderNumber());
|
|
|
+ return R.fail("订单进行中,不允许删除");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果订单是待支付状态,取消Redis中的订单支付超时计时
|
|
|
+ Integer waitPayStatus = LawyerStatusEnum.WAIT_PAY.getStatus(); // 0:待支付
|
|
|
+ if (waitPayStatus.equals(orderStatus) && order.getOrderNumber() != null) {
|
|
|
+ try {
|
|
|
+ orderExpirationService.cancelOrderPaymentTimeout(order.getOrderNumber());
|
|
|
+ log.info("已取消订单支付超时计时,订单编号={}", order.getOrderNumber());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("取消订单支付超时计时失败,订单编号={}", order.getOrderNumber(), e);
|
|
|
+ // 继续执行删除操作,不因取消计时器失败而中断
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 执行删除操作
|
|
|
+ boolean result = this.removeById(id);
|
|
|
+ if (result) {
|
|
|
+ log.info("删除咨询订单成功,订单ID={}, 订单编号={}", id, order.getOrderNumber());
|
|
|
+ return R.data(true, "删除成功");
|
|
|
+ } else {
|
|
|
+ log.error("删除咨询订单失败:数据库操作失败,订单ID={}, 订单编号={}", id, order.getOrderNumber());
|
|
|
+ return R.fail("删除失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*@Override
|
|
|
+ public R<Map<String, Object>> startConsultation(Integer lawyerId, String question, String sessionId, Integer clientUserId, Integer problemScenarioId) {
|
|
|
+ log.info("LawyerConsultationOrderServiceImpl.startConsultation?lawyerId={},question={},sessionId={},clientUserId={},problemScenarioId={}",
|
|
|
+ lawyerId, question, sessionId, clientUserId, problemScenarioId);
|
|
|
+
|
|
|
+ // 创建咨询订单
|
|
|
+ LawyerConsultationOrder order = new LawyerConsultationOrder();
|
|
|
+ order.setLawyerUserId(lawyerId);
|
|
|
+ order.setClientUserId(clientUserId);
|
|
|
+ order.setProblemScenarioId(problemScenarioId);
|
|
|
+ order.setProblemDescription(question);
|
|
|
+ order.setOrderStatus(0); // 待支付
|
|
|
+ order.setPaymentStatus(0); // 未支付
|
|
|
+
|
|
|
+ boolean saved = this.save(order);
|
|
|
+ if (!saved) {
|
|
|
+ return R.fail("创建咨询订单失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
+ result.put("consultationId", order.getId());
|
|
|
+ result.put("lawyerId", lawyerId);
|
|
|
+ result.put("status", "pending"); // pending(待响应), active(进行中), closed(已结束)
|
|
|
+ result.put("createTime", order.getCreatedTime() != null ?
|
|
|
+ new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(order.getCreatedTime()) : "");
|
|
|
+
|
|
|
+ return R.data(result);
|
|
|
+ }*/
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<LawyerConsultationOrderDto> consultNow(LawyerConsultationOrder lawyerConsultationOrder) {
|
|
|
+ log.info("LawyerConsultationOrderServiceImpl.consultNow?lawyerConsultationOrder={}", lawyerConsultationOrder);
|
|
|
+
|
|
|
+ // 参数校验
|
|
|
+ if (lawyerConsultationOrder == null) {
|
|
|
+ log.warn("创建咨询订单失败:订单信息为空");
|
|
|
+ return R.fail("订单信息不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ Integer clientUserId = lawyerConsultationOrder.getClientUserId();
|
|
|
+ Integer lawyerUserId = lawyerConsultationOrder.getLawyerUserId();
|
|
|
+ Integer orderAmount = lawyerConsultationOrder.getOrderAmount();
|
|
|
+
|
|
|
+ if (clientUserId == null || clientUserId <= 0) {
|
|
|
+ log.warn("创建咨询订单失败:客户端用户ID无效,clientUserId={}", clientUserId);
|
|
|
+ return R.fail("客户端用户ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (lawyerUserId == null || lawyerUserId <= 0) {
|
|
|
+ log.warn("创建咨询订单失败:律师用户ID无效,lawyerUserId={}", lawyerUserId);
|
|
|
+ return R.fail("律师用户ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (orderAmount == null || orderAmount <= 0) {
|
|
|
+ log.warn("创建咨询订单失败:订单金额无效,orderAmount={}", orderAmount);
|
|
|
+ return R.fail("订单金额不能为空且必须大于0");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建订单DTO对象
|
|
|
+ LawyerConsultationOrderDto order = new LawyerConsultationOrderDto();
|
|
|
+ Date now = new Date();
|
|
|
+
|
|
|
+ // 设置订单基本信息
|
|
|
+ order.setClientUserId(clientUserId);
|
|
|
+ order.setLawyerUserId(lawyerUserId);
|
|
|
+ order.setProblemScenarioId(lawyerConsultationOrder.getProblemScenarioId());
|
|
|
+ order.setProblemDescription(lawyerConsultationOrder.getProblemDescription());
|
|
|
+ order.setOrderAmount(orderAmount);
|
|
|
+ order.setAlipayNo(lawyerConsultationOrder.getAlipayNo());
|
|
|
+ order.setOrderStr(lawyerConsultationOrder.getOrderStr());
|
|
|
+ order.setPlaceId(lawyerConsultationOrder.getPlaceId());
|
|
|
+ order.setPayType(lawyerConsultationOrder.getPayType());
|
|
|
+
|
|
|
+ // 设置订单状态
|
|
|
+ order.setOrderStatus(0); // 待支付
|
|
|
+ order.setPaymentStatus(0); // 未支付
|
|
|
+ order.setOrderTime(now);
|
|
|
+ order.setCreatedTime(now);
|
|
|
+ order.setUpdatedTime(now);
|
|
|
+ order.setDeleteFlag(0);
|
|
|
+
|
|
|
+ // 生成订单编号:LAW + 年月日(8位数字)+ 随机5位数字
|
|
|
+ String orderNumber = generateOrderNumber();
|
|
|
+ order.setOrderNumber(orderNumber);
|
|
|
+ log.info("生成订单编号:orderNumber={}", orderNumber);
|
|
|
+
|
|
|
+ // 计算本单收益(平台收益)
|
|
|
+ Integer consultationFee = calculateConsultationFee(lawyerUserId, orderAmount);
|
|
|
+ order.setConsultationFee(consultationFee);
|
|
|
+ log.info("计算咨询费用:lawyerUserId={}, orderAmount={}, consultationFee={}",
|
|
|
+ lawyerUserId, orderAmount, consultationFee);
|
|
|
+
|
|
|
+ // 计算律师收益(订单金额-平台收益)
|
|
|
+ Integer lawyerEarnings = orderAmount - consultationFee;
|
|
|
+ order.setLawyerEarnings(lawyerEarnings);
|
|
|
+ // 插入订单
|
|
|
+ int insertCount = consultationOrderMapper.insertOrder(order);
|
|
|
+ if (insertCount > 0) {
|
|
|
+ log.info("创建咨询订单成功:orderNumber={}, orderId={}", orderNumber, order.getId());
|
|
|
+ return R.data(order);
|
|
|
+ } else {
|
|
|
+ log.error("创建咨询订单失败:数据库插入失败,orderNumber={}", orderNumber);
|
|
|
+ return R.fail("创建订单失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成订单编号
|
|
|
+ * <p>
|
|
|
+ * 格式:LAW + 年月日(8位数字)+ 随机5位数字
|
|
|
+ * 示例:LAW2025011512345
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @return 订单编号
|
|
|
+ */
|
|
|
+ private String generateOrderNumber() {
|
|
|
+ String dateStr = new SimpleDateFormat("yyyyMMdd").format(new Date());
|
|
|
+ String randomStr = String.format("%05d", RandomUtils.nextInt(100000));
|
|
|
+ return "LAW" + dateStr + randomStr;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算咨询费用(本单收益)
|
|
|
+ * <p>
|
|
|
+ * 根据律所的平台佣金比例计算咨询费用
|
|
|
+ * 如果律师没有关联律所或律所没有设置佣金比例,则使用默认佣金比例3%
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param lawyerUserId 律师用户ID
|
|
|
+ * @param orderAmount 订单金额(单位:分)
|
|
|
+ * @return 咨询费用(单位:分)
|
|
|
+ */
|
|
|
+ private Integer calculateConsultationFee(Integer lawyerUserId, Integer orderAmount) {
|
|
|
+ // 默认佣金比例:3%
|
|
|
+ float defaultCommissionRate = 3.0F;
|
|
|
+ float commissionRate = defaultCommissionRate;
|
|
|
+
|
|
|
+ // 查询律师信息
|
|
|
+ LawyerUser lawyerUser = lawyerUserMapper.selectById(lawyerUserId);
|
|
|
+ if (lawyerUser != null) {
|
|
|
+ // 获取律所信息
|
|
|
+ Integer firmId = lawyerUser.getFirmId();
|
|
|
+ if (firmId != null && firmId > 0) {
|
|
|
+ LawFirm lawyerFirm = lawFirmMapper.selectById(firmId);
|
|
|
+ if (lawyerFirm != null && lawyerFirm.getPlatformCommissionRatio() != null
|
|
|
+ && lawyerFirm.getPlatformCommissionRatio().floatValue() > 0) {
|
|
|
+ commissionRate = lawyerFirm.getPlatformCommissionRatio().floatValue();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算咨询费用:订单金额 * 佣金比例 / 100,四舍五入
|
|
|
+ int consultationFee = Math.round(orderAmount * commissionRate / 100);
|
|
|
+ return consultationFee;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<LawyerConsultationOrderDto> payStatus(PayStatusRequest request) {
|
|
|
+ log.info("LawyerConsultationOrderServiceImpl.payStatus?orderNumber={},paymentStatus={},orderStatus={}",
|
|
|
+ request.getOrderNumber(), request.getPaymentStatus(), request.getOrderStatus());
|
|
|
+
|
|
|
+ LawyerConsultationOrderDto order = new LawyerConsultationOrderDto();
|
|
|
+ if (null != request.getOrderStr()){
|
|
|
+ order.setOrderStr(request.getOrderStr());
|
|
|
+ }
|
|
|
+ if (null != request.getAlipayNo()){
|
|
|
+ order.setAlipayNo(request.getAlipayNo());
|
|
|
+ }
|
|
|
+ order.setOrderNumber(request.getOrderNumber());
|
|
|
+ order.setPaymentStatus(request.getPaymentStatus());
|
|
|
+ order.setOrderStatus(request.getOrderStatus());
|
|
|
+ order.setUpdatedTime(new Date());
|
|
|
+ order.setDeleteFlag(0);
|
|
|
+ order.setPaymentTime(new Date());
|
|
|
+ order.setStartTime(new Date());
|
|
|
+// LocalDateTime now = LocalDateTime.now();
|
|
|
+// LocalDateTime validityDateTime = now.plusDays(7)
|
|
|
+// .withHour(0)
|
|
|
+// .withMinute(0)
|
|
|
+// .withSecond(0)
|
|
|
+// .withNano(0);
|
|
|
+// order.setValidityPeriod(Date.from(validityDateTime.atZone(ZoneId.systemDefault()).toInstant()));
|
|
|
+// boolean result = this.updateById(order);
|
|
|
+ Integer result = consultationOrderMapper.updateOrder(order);
|
|
|
+
|
|
|
+ if (result > 0) {
|
|
|
+ return R.data(order);
|
|
|
+ }
|
|
|
+ return R.fail("失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据用户ID查询订单列表(包含律师信息)
|
|
|
+ *
|
|
|
+ * @param pageNum 页码
|
|
|
+ * @param pageSize 页容量
|
|
|
+ * @param userId 用户ID
|
|
|
+ * @param orderStatus 订单状态
|
|
|
+ * @param lawyerName 律师姓名(支持模糊查询)
|
|
|
+ * @return 分页订单列表
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> getConsultationOrderListById(int pageNum, int pageSize,
|
|
|
+ String userId, String orderStatus,
|
|
|
+ String lawyerName) {
|
|
|
+ log.info("查询咨询订单信息(律师端)- pageNum={}, pageSize={}, userId={}, orderStatus={}, lawyerName={}",
|
|
|
+ pageNum, pageSize, userId, orderStatus, lawyerName);
|
|
|
+
|
|
|
+ // 参数校验:用户ID不能为空
|
|
|
+ if (!StringUtils.hasText(userId)) {
|
|
|
+ log.warn("查询咨询订单信息失败:用户ID为空");
|
|
|
+ return buildEmptyResultMap(pageNum, pageSize);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建分页对象
|
|
|
+ Page<LawyerConsultationOrderVO> page = new Page<>(pageNum, pageSize);
|
|
|
+
|
|
|
+ // 构建查询条件
|
|
|
+ QueryWrapper<LawyerConsultationOrderVO> queryWrapper = buildOrderQueryWrapper(
|
|
|
+ lawyerName, orderStatus, userId);
|
|
|
+ QueryWrapper<LawyerConsultationOrderVO> statisticsWrapper = buildStatisticsQueryWrapper(
|
|
|
+ lawyerName, userId);
|
|
|
+
|
|
|
+ // 查询订单列表
|
|
|
+ IPage<LawyerConsultationOrderVO> voPage = consultationOrderMapper.getLawyerConsultationOrderList(
|
|
|
+ page, queryWrapper);
|
|
|
+
|
|
|
+ if (voPage != null) {
|
|
|
+ // 填充法律场景信息和倒计时
|
|
|
+ fillLegalSceneArea(voPage);
|
|
|
+ calculateCountdownForPendingOrders(voPage);
|
|
|
+
|
|
|
+ //填充未读消息
|
|
|
+ fillUnreadMessage(voPage,userId);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断工作日信息
|
|
|
+ calculateWorkDayInfo(voPage);
|
|
|
+
|
|
|
+
|
|
|
+ // 获取统计信息
|
|
|
+ statisticsWrapper.groupBy("lco.order_status");
|
|
|
+ List<Map<String, Object>> statisticsInfo = consultationOrderMapper.getLawyerStatisticsInfo(
|
|
|
+ statisticsWrapper);
|
|
|
+
|
|
|
+ // 构建状态统计Map并填充返回结果
|
|
|
+ Map<Integer, Integer> statusCountMap = buildStatusCountMap(statisticsInfo);
|
|
|
+ Map<String, Object> resultMap = buildOrderStatisticsResult(statusCountMap, voPage);
|
|
|
+
|
|
|
+ return resultMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建订单统计结果Map
|
|
|
+ *
|
|
|
+ * @param statusCountMap 状态统计Map
|
|
|
+ * @param voPage 订单分页对象
|
|
|
+ * @return 订单统计结果Map
|
|
|
+ */
|
|
|
+ private Map<String, Object> buildOrderStatisticsResult(Map<Integer, Integer> statusCountMap,
|
|
|
+ IPage<LawyerConsultationOrderVO> voPage) {
|
|
|
+ Map<String, Object> resultMap = new HashMap<>(16);
|
|
|
+
|
|
|
+ // 获取各状态订单数量
|
|
|
+ Integer waitPayStatus = LawyerStatusEnum.WAIT_PAY.getStatus();
|
|
|
+ int waitPayStatusCount = statusCountMap.getOrDefault(waitPayStatus, 0);
|
|
|
+
|
|
|
+ Integer waitAcceptStatus = LawyerStatusEnum.WAIT_ACCEPT.getStatus();
|
|
|
+ int waitAcceptStatusCount = statusCountMap.getOrDefault(waitAcceptStatus, 0);
|
|
|
+
|
|
|
+ Integer inProgressStatus = LawyerStatusEnum.INPROGRESS.getStatus();
|
|
|
+ int inProgressCount = statusCountMap.getOrDefault(inProgressStatus, 0);
|
|
|
+
|
|
|
+ Integer completeStatus = LawyerStatusEnum.COMPLETE.getStatus();
|
|
|
+ int completeCount = statusCountMap.getOrDefault(completeStatus, 0);
|
|
|
+
|
|
|
+ Integer cancelStatus = LawyerStatusEnum.CANCEL.getStatus();
|
|
|
+ int cancelStatusCount = statusCountMap.getOrDefault(cancelStatus, 0);
|
|
|
+
|
|
|
+ Integer refundedStatus = LawyerStatusEnum.REFUNDED.getStatus();
|
|
|
+ int refundedStatusCount = statusCountMap.getOrDefault(refundedStatus, 0);
|
|
|
+
|
|
|
+ // 计算订单总数
|
|
|
+ long totalOrderCount = (long) (waitPayStatusCount + waitAcceptStatusCount + inProgressCount
|
|
|
+ + completeCount + cancelStatusCount + refundedStatusCount);
|
|
|
+
|
|
|
+ // 填充返回结果
|
|
|
+ resultMap.put("lawyerWaitPayStatusOrderCount", waitPayStatusCount);
|
|
|
+ resultMap.put("lawyerWaitAcceptStatusOrderCount", waitAcceptStatusCount);
|
|
|
+ resultMap.put("lawyerInProgressOrderCount", inProgressCount);
|
|
|
+ resultMap.put("lawyerCompleteOrderCount", completeCount);
|
|
|
+ resultMap.put("lawyerCancelStatusOrderCount", cancelStatusCount);
|
|
|
+ resultMap.put("lawyerRefundedStatusOrderCount", refundedStatusCount);
|
|
|
+ resultMap.put("lawyerOrderCount", totalOrderCount);
|
|
|
+
|
|
|
+ // 设置订单列表
|
|
|
+ List<LawyerConsultationOrderVO> orderList = (voPage != null && voPage.getRecords() != null)
|
|
|
+ ? voPage.getRecords() : Collections.emptyList();
|
|
|
+ resultMap.put("lawyerConsultationOrderList", orderList);
|
|
|
+
|
|
|
+ return resultMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建状态统计Map
|
|
|
+ *
|
|
|
+ * @param statisticsInfo 统计信息列表
|
|
|
+ * @return 状态统计Map,key为订单状态,value为订单数量
|
|
|
+ */
|
|
|
+ private Map<Integer, Integer> buildStatusCountMap(List<Map<String, Object>> statisticsInfo) {
|
|
|
+ Map<Integer, Integer> statusCountMap = new HashMap<>(16);
|
|
|
+ if (CollectionUtils.isEmpty(statisticsInfo)) {
|
|
|
+ return statusCountMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (Map<String, Object> map : statisticsInfo) {
|
|
|
+ Object statusObj = map.get("order_status");
|
|
|
+ Object countObj = map.get("order_count");
|
|
|
+
|
|
|
+ if (statusObj == null || countObj == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ Integer status = (Integer) statusObj;
|
|
|
+ // COUNT(*) 返回类型可能是Long
|
|
|
+ Long countLong = (Long) countObj;
|
|
|
+ statusCountMap.put(status, countLong.intValue());
|
|
|
+ }
|
|
|
+
|
|
|
+ return statusCountMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建统计查询条件
|
|
|
+ *
|
|
|
+ * @param lawyerName 律师名称
|
|
|
+ * @param userId 客户端用户ID
|
|
|
+ * @return 统计查询条件包装器
|
|
|
+ */
|
|
|
+ private QueryWrapper<LawyerConsultationOrderVO> buildStatisticsQueryWrapper(String lawyerName,
|
|
|
+ String userId) {
|
|
|
+ QueryWrapper<LawyerConsultationOrderVO> queryWrapper = new QueryWrapper<>();
|
|
|
+ if (StringUtils.hasText(lawyerName)) {
|
|
|
+ queryWrapper.like("lu.name", lawyerName);
|
|
|
+ }
|
|
|
+ queryWrapper.eq("lco.client_user_id", userId);
|
|
|
+ queryWrapper.eq("lco.delete_flag", 0);
|
|
|
+ return queryWrapper;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建空结果Map
|
|
|
+ *
|
|
|
+ * @param pageNum 页码
|
|
|
+ * @param pageSize 页容量
|
|
|
+ * @return 空结果Map
|
|
|
+ */
|
|
|
+ private Map<String, Object> buildEmptyResultMap(int pageNum, int pageSize) {
|
|
|
+ Map<String, Object> resultMap = new HashMap<>(16);
|
|
|
+ Page<LawyerConsultationOrderVO> emptyPage = new Page<>(pageNum, pageSize);
|
|
|
+ emptyPage.setRecords(Collections.emptyList());
|
|
|
+ emptyPage.setTotal(0);
|
|
|
+ resultMap.put("lawyerWaitPayStatusOrderCount", 0);
|
|
|
+ resultMap.put("lawyerWaitAcceptStatusOrderCount", 0);
|
|
|
+ resultMap.put("lawyerInProgressOrderCount", 0);
|
|
|
+ resultMap.put("lawyerCompleteOrderCount", 0);
|
|
|
+ resultMap.put("lawyerCancelStatusOrderCount", 0);
|
|
|
+ resultMap.put("lawyerRefundedStatusOrderCount", 0);
|
|
|
+ resultMap.put("lawyerOrderCount", 0L);
|
|
|
+ resultMap.put("lawyerConsultationOrderList", Collections.emptyList());
|
|
|
+ return resultMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建订单查询条件
|
|
|
+ *
|
|
|
+ * @param lawyerName 律师名称
|
|
|
+ * @param orderStatus 订单状态
|
|
|
+ * @param userId 客户端用户ID
|
|
|
+ * @return 查询条件包装器
|
|
|
+ */
|
|
|
+ private QueryWrapper<LawyerConsultationOrderVO> buildOrderQueryWrapper(String lawyerName, String orderStatus,
|
|
|
+ String userId) {
|
|
|
+ QueryWrapper<LawyerConsultationOrderVO> queryWrapper = new QueryWrapper<>();
|
|
|
+
|
|
|
+ // 订单状态条件
|
|
|
+ if (StringUtils.hasText(orderStatus)) {
|
|
|
+ queryWrapper.in("lco.order_status", Collections.singletonList(orderStatus));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 律师名称条件
|
|
|
+ if (StringUtils.hasText(lawyerName)) {
|
|
|
+ queryWrapper.like("lu.name", lawyerName);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 客户端用户ID条件
|
|
|
+ queryWrapper.eq("lco.client_user_id", userId);
|
|
|
+
|
|
|
+ // 删除标记条件
|
|
|
+ queryWrapper.eq("lco.delete_flag", 0);
|
|
|
+
|
|
|
+ // 排序条件:按创建时间倒序
|
|
|
+ queryWrapper.orderByDesc("lco.created_time");
|
|
|
+ return queryWrapper;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据律师姓名查询律师ID列表
|
|
|
+ *
|
|
|
+ * @param lawyerName 律师姓名
|
|
|
+ * @return 律师ID列表
|
|
|
+ */
|
|
|
+ private List<Integer> queryLawyerIdsByName(String lawyerName) {
|
|
|
+ LambdaQueryWrapper<LawyerUser> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(LawyerUser::getDeleteFlag, 0)
|
|
|
+ .like(LawyerUser::getName, lawyerName);
|
|
|
+ List<LawyerUser> lawyerUsers = lawyerUserService.list(queryWrapper);
|
|
|
+
|
|
|
+ if (CollectionUtils.isEmpty(lawyerUsers)) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+
|
|
|
+ return lawyerUsers.stream()
|
|
|
+ .map(LawyerUser::getId)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 填充律师法律场景到订单VO列表
|
|
|
+ *
|
|
|
+ * @param voPage 订单VO分页对象
|
|
|
+ */
|
|
|
+ private void fillLegalSceneArea(IPage<LawyerConsultationOrderVO> voPage) {
|
|
|
+ List<LawyerConsultationOrderVO> orderList = voPage.getRecords();
|
|
|
+ if (CollectionUtils.isEmpty(orderList)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提取所有律师ID
|
|
|
+ List<Integer> lawyerIdList = orderList.stream()
|
|
|
+ .map(LawyerConsultationOrderVO::getLawyerUserId)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (CollectionUtils.isEmpty(lawyerIdList)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 批量查询法律场景
|
|
|
+ Map<String, List<String>> serviceAreaMap = getLawyerServiceArea(lawyerIdList);
|
|
|
+ if (serviceAreaMap.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 填充问题场景
|
|
|
+ orderList.forEach(order -> {
|
|
|
+ Integer lawyerUserId = order.getLawyerUserId();
|
|
|
+ if (lawyerUserId != null) {
|
|
|
+ String lawyerUserIdStr = String.valueOf(lawyerUserId);
|
|
|
+ List<String> serviceAreaList = serviceAreaMap.get(lawyerUserIdStr);
|
|
|
+ if (CollectionUtils.isNotEmpty(serviceAreaList)) {
|
|
|
+ order.setLawyerLegalProblemScenarioList(serviceAreaList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 填充未读消息数量
|
|
|
+ *
|
|
|
+ * @param voPage 订单VO分页对象
|
|
|
+ */
|
|
|
+ private void fillUnreadMessage(IPage<LawyerConsultationOrderVO> voPage,String userId) {
|
|
|
+ List<LawyerConsultationOrderVO> orderList = voPage.getRecords();
|
|
|
+ if (CollectionUtils.isEmpty(orderList)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提取所有律师ID,并加上lawyer_前缀
|
|
|
+ List<String> lawyerIdList = orderList.stream()
|
|
|
+ .map(LawyerConsultationOrderVO::getLawyerPhone)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .map(phone -> "lawyer_" + phone)
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (CollectionUtils.isEmpty(lawyerIdList)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ LifeUser lifeUser = lifeUserMapper.selectById(userId);
|
|
|
+ String phone = lifeUser.getUserPhone();
|
|
|
+
|
|
|
+ LambdaQueryWrapper<LifeMessage> lifeMessageLambdaQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ lifeMessageLambdaQueryWrapper.in(LifeMessage::getSenderId, lawyerIdList);
|
|
|
+ lifeMessageLambdaQueryWrapper.eq(LifeMessage::getDeleteFlag, 0);
|
|
|
+ lifeMessageLambdaQueryWrapper.eq(LifeMessage::getIsRead, 0);
|
|
|
+ lifeMessageLambdaQueryWrapper.eq(LifeMessage::getReceiverId, "user_" + phone);
|
|
|
+ List<LifeMessage> lifeMessageList = lifeMessageMapper.selectList(lifeMessageLambdaQueryWrapper);
|
|
|
+
|
|
|
+ // 按照senderId进行分组,返回senderId和数量的map
|
|
|
+ Map<String, Long> senderIdCountMap = new HashMap<>();
|
|
|
+ if(CollectionUtils.isNotEmpty(lifeMessageList)){
|
|
|
+ senderIdCountMap = lifeMessageList.stream()
|
|
|
+ .collect(Collectors.groupingBy(LifeMessage::getSenderId, Collectors.counting()));
|
|
|
+ }
|
|
|
+
|
|
|
+ for(LawyerConsultationOrderVO lawyerConsultationOrderVO : voPage.getRecords()){
|
|
|
+ String lawyerPhone = "lawyer_" + lawyerConsultationOrderVO.getLawyerPhone();
|
|
|
+ if(!senderIdCountMap.isEmpty() && senderIdCountMap.containsKey(lawyerPhone) && lawyerConsultationOrderVO.getOrderStatus() == 2){
|
|
|
+ long messageCount = senderIdCountMap.get(lawyerPhone);
|
|
|
+ lawyerConsultationOrderVO.setUnreadMessage(messageCount);
|
|
|
+ } else {
|
|
|
+ lawyerConsultationOrderVO.setUnreadMessage(0L);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量查询律师问题场景
|
|
|
+ *
|
|
|
+ * @param lawyerIdList 律师ID列表
|
|
|
+ * @return 律师问题场景Map,key为律师ID(String),value为问题场景名称列表
|
|
|
+ */
|
|
|
+ private Map<String, List<String>> getLawyerServiceArea(List<Integer> lawyerIdList) {
|
|
|
+ Map<String, List<String>> serviceAreaMap = new HashMap<>();
|
|
|
+ if (CollectionUtils.isEmpty(lawyerIdList)) {
|
|
|
+ return serviceAreaMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ QueryWrapper<LawyerServiceArea> wrapper = new QueryWrapper<>();
|
|
|
+ wrapper.in("lsa.lawyer_user_id", lawyerIdList)
|
|
|
+ .eq("lsa.delete_flag", 0)
|
|
|
+ .eq("lsa.status", 1);
|
|
|
+
|
|
|
+ List<Map<String, Object>> serviceAreaDataList = lawyerServiceAreaMapper.getLawyerLegalProblemScenarioList(wrapper);
|
|
|
+ if (CollectionUtils.isEmpty(serviceAreaDataList)) {
|
|
|
+ return serviceAreaMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (Map<String, Object> row : serviceAreaDataList) {
|
|
|
+ Object lawyerUserIdObj = row.get("lawyer_user_id");
|
|
|
+ if (lawyerUserIdObj == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ String lawyerUserId = String.valueOf(lawyerUserIdObj);
|
|
|
+ String scenarioName = (String) row.get("name");
|
|
|
+ String scenarioNameValue = StringUtils.hasText(scenarioName) ? scenarioName : "";
|
|
|
+
|
|
|
+ serviceAreaMap.computeIfAbsent(lawyerUserId, k -> new ArrayList<>())
|
|
|
+ .add(scenarioNameValue);
|
|
|
+ }
|
|
|
+
|
|
|
+ return serviceAreaMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取咨询订单详情
|
|
|
+ *
|
|
|
+ * @param lawyerOrderId 订单ID
|
|
|
+ * @return 咨询订单详情VO
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public LawyerConsultationOrderVO getConsultationOrderDetail(String lawyerOrderId) {
|
|
|
+ log.info("LawyerConsultationOrderServiceImpl.getConsultationOrderDetail?lawyerOrderId={}", lawyerOrderId);
|
|
|
+
|
|
|
+ LawyerConsultationOrderVO orderVO = new LawyerConsultationOrderVO();
|
|
|
+
|
|
|
+ // 参数校验
|
|
|
+ if (!StringUtils.hasText(lawyerOrderId)) {
|
|
|
+ return orderVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询订单信息
|
|
|
+ LawyerConsultationOrder order = consultationOrderMapper.selectById(lawyerOrderId);
|
|
|
+ if (order == null) {
|
|
|
+ return orderVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 复制订单基本信息
|
|
|
+ BeanUtils.copyProperties(order, orderVO);
|
|
|
+
|
|
|
+ // 查询并填充律师信息
|
|
|
+ Integer lawyerUserId = order.getLawyerUserId();
|
|
|
+ if (lawyerUserId != null) {
|
|
|
+ LawyerUser lawyerUser = lawyerUserMapper.selectById(lawyerUserId);
|
|
|
+ if (lawyerUser != null) {
|
|
|
+ fillLawyerInfo(orderVO, lawyerUser);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 查询律师问题场景
|
|
|
+ List<Integer> lawyerIdList = Collections.singletonList(lawyerUserId);
|
|
|
+ Map<String, List<String>> serviceAreaMap = getLawyerServiceArea(lawyerIdList);
|
|
|
+ String lawyerUserIdStr = String.valueOf(lawyerUserId);
|
|
|
+ if (!serviceAreaMap.isEmpty() && serviceAreaMap.containsKey(lawyerUserIdStr)) {
|
|
|
+ orderVO.setLawyerLegalProblemScenarioList(serviceAreaMap.get(lawyerUserIdStr));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return orderVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 取消律师咨询订单
|
|
|
+ * <p>
|
|
|
+ * 取消订单前会进行以下校验和处理:
|
|
|
+ * 1. 参数校验:订单ID不能为空
|
|
|
+ * 2. 订单存在性校验:订单必须存在
|
|
|
+ * 3. 订单状态校验:已取消或已完成的订单不允许再次取消
|
|
|
+ * 4. 如果订单是待支付状态,会取消Redis中的订单支付超时计时器
|
|
|
+ * 5. 根据订单状态更新为相应状态:
|
|
|
+ * - 待接单状态:更新为已退款状态
|
|
|
+ * - 待支付状态:更新为已取消状态
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param id 订单ID
|
|
|
+ * @return 是否取消成功,true表示成功,false表示失败
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public boolean cancelOrder(String id) {
|
|
|
+ log.info("开始取消订单,订单ID={}", id);
|
|
|
+
|
|
|
+ // 1. 参数校验
|
|
|
+ if (!StringUtils.hasText(id)) {
|
|
|
+ log.warn("取消订单失败:订单ID为空");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 查询订单信息
|
|
|
+ LawyerConsultationOrder order = consultationOrderMapper.selectById(id);
|
|
|
+ if (order == null) {
|
|
|
+ log.warn("取消订单失败:订单不存在,订单ID={}", id);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 订单状态校验
|
|
|
+ Integer orderStatus = order.getOrderStatus();
|
|
|
+ String orderNumber = order.getOrderNumber();
|
|
|
+ Integer cancelStatus = LawyerStatusEnum.CANCEL.getStatus();
|
|
|
+ Integer completedStatus = LawyerStatusEnum.COMPLETE.getStatus();
|
|
|
+ Integer waitAcceptStatus = LawyerStatusEnum.WAIT_ACCEPT.getStatus();
|
|
|
+ Integer waitPayStatus = LawyerStatusEnum.WAIT_PAY.getStatus();
|
|
|
+ Integer refundedStatus = LawyerStatusEnum.REFUNDED.getStatus();
|
|
|
+
|
|
|
+ // 3.1 检查订单是否已取消
|
|
|
+ if (cancelStatus.equals(orderStatus)) {
|
|
|
+ log.warn("取消订单失败:订单已取消,订单ID={}, 订单编号={}", id, orderNumber);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3.2 检查订单是否已完成
|
|
|
+ if (completedStatus.equals(orderStatus)) {
|
|
|
+ log.warn("取消订单失败:订单已完成,不允许取消,订单ID={}, 订单编号={}", id, orderNumber);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 如果订单是待支付状态,取消Redis中的订单支付超时计时器
|
|
|
+ if (waitPayStatus.equals(orderStatus) && StringUtils.hasText(orderNumber)) {
|
|
|
+ try {
|
|
|
+ orderExpirationService.cancelOrderPaymentTimeout(orderNumber);
|
|
|
+ log.info("已取消订单支付超时计时器,订单编号={}", orderNumber);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("取消订单支付超时计时器失败,订单编号={}", orderNumber, e);
|
|
|
+ // 继续执行取消订单操作,不因取消计时器失败而中断
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 根据订单状态更新为相应状态
|
|
|
+ Integer targetStatus = null;
|
|
|
+ if (waitAcceptStatus.equals(orderStatus)) {
|
|
|
+ // 待接单状态:更新为已退款状态
|
|
|
+ targetStatus = refundedStatus;
|
|
|
+ } else if (waitPayStatus.equals(orderStatus)) {
|
|
|
+ // 待支付状态:更新为已取消状态
|
|
|
+ targetStatus = cancelStatus;
|
|
|
+ } else {
|
|
|
+ log.warn("取消订单失败:订单状态不允许取消,订单ID={}, 订单编号={}, 订单状态={}",
|
|
|
+ id, orderNumber, orderStatus);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6. 更新订单状态
|
|
|
+ LambdaUpdateWrapper<LawyerConsultationOrder> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
+ updateWrapper.eq(LawyerConsultationOrder::getId, id)
|
|
|
+ .set(LawyerConsultationOrder::getOrderStatus, targetStatus)
|
|
|
+ .set(LawyerConsultationOrder::getUpdatedTime, new Date());
|
|
|
+
|
|
|
+ int updateCount = consultationOrderMapper.update(null, updateWrapper);
|
|
|
+ boolean success = updateCount > 0;
|
|
|
+
|
|
|
+ // 7. 记录操作结果
|
|
|
+ if (success) {
|
|
|
+ log.info("取消订单成功,订单ID={}, 订单编号={}, 原状态={}, 新状态={}",
|
|
|
+ id, orderNumber, orderStatus, targetStatus);
|
|
|
+ } else {
|
|
|
+ log.error("取消订单失败:更新数据库失败,订单ID={}, 订单编号={}, 原状态={}",
|
|
|
+ id, orderNumber, orderStatus);
|
|
|
+ }
|
|
|
+
|
|
|
+ return success;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询咨询订单信息(律师端)
|
|
|
+ *
|
|
|
+ * @param pageNum 页码
|
|
|
+ * @param pageSize 页容
|
|
|
+ * @param startDate 开始时间
|
|
|
+ * @param endDate 结束时间
|
|
|
+ * @param lawyerId 律师ID
|
|
|
+ * @return 订单信息Map,包含订单列表、总数、进行中数量、已完成数量
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> getLawyerConsultationOrderInfo(int pageNum, int pageSize, String startDate, String endDate, String clientUserName, String orderStatus, String lawyerId) {
|
|
|
+ log.info("LawyerConsultationOrderServiceImpl.getLawyerConsultationOrderInfo?pageNum={},pageSize={},startDate={},endDate={},clientUserName={},lawyerId={}",
|
|
|
+ pageNum, pageSize, startDate, endDate, clientUserName, lawyerId);
|
|
|
+
|
|
|
+ Map<String, Object> resultMap = new HashMap<>();
|
|
|
+
|
|
|
+ // 参数校验:律师ID不能为空
|
|
|
+ if (!StringUtils.hasText(lawyerId)) {
|
|
|
+ log.warn("查询咨询订单信息失败:律师ID为空");
|
|
|
+ Page<LawyerConsultationOrderVO> emptyPage = new Page<>(pageNum, pageSize);
|
|
|
+ emptyPage.setRecords(Collections.emptyList());
|
|
|
+ emptyPage.setTotal(0);
|
|
|
+ resultMap.put("lawyerOrderCount", 0L);
|
|
|
+ resultMap.put("lawyerInProgressOrderCount", 0);
|
|
|
+ resultMap.put("lawyerCompleteOrderCount", 0);
|
|
|
+ resultMap.put("lawyerConsultationOrderList", Collections.emptyList());
|
|
|
+ return resultMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建分页对象
|
|
|
+ Page<LawyerConsultationOrderVO> page = new Page<>(pageNum, pageSize);
|
|
|
+
|
|
|
+ // 构建查询条件:查询进行中(2)和已完成(3)状态的订单
|
|
|
+ QueryWrapper<LawyerConsultationOrderVO> queryWrapper = new QueryWrapper<>();
|
|
|
+ QueryWrapper<LawyerConsultationOrderVO> queryStatisticsWrapper = new QueryWrapper<>();
|
|
|
+
|
|
|
+ if (StringUtils.hasText(orderStatus)) {
|
|
|
+ queryWrapper.in("lco.order_status", Collections.singletonList(orderStatus));
|
|
|
+ } else {
|
|
|
+ queryWrapper.in("lco.order_status", Arrays.asList("2", "3"));
|
|
|
+ }
|
|
|
+ queryWrapper.eq("lco.lawyer_user_id", lawyerId);
|
|
|
+ queryStatisticsWrapper.eq("lco.lawyer_user_id", lawyerId);
|
|
|
+ if (StringUtils.hasText(clientUserName)) {
|
|
|
+ queryWrapper.like("lur.user_name", clientUserName);
|
|
|
+ queryStatisticsWrapper.like("lur.user_name", clientUserName);
|
|
|
+ }
|
|
|
+ queryWrapper.eq("lco.delete_flag", 0);
|
|
|
+ queryStatisticsWrapper.eq("lco.delete_flag", 0);
|
|
|
+ queryWrapper.orderByDesc("lco.created_time");
|
|
|
+ // 时间范围查询:如果开始时间和结束时间都存在,则进行范围查询
|
|
|
+ if (StringUtils.hasText(startDate) && StringUtils.hasText(endDate)) {
|
|
|
+ queryWrapper.between("lco.payment_time", startDate + " 00:00:00", endDate + " 23:59:59");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询订单列表
|
|
|
+ IPage<LawyerConsultationOrderVO> voPage = consultationOrderMapper.getLawyerConsultationOrderList(page, queryWrapper);
|
|
|
+
|
|
|
+ // 填充律师问题场景信息
|
|
|
+ if (voPage != null) {
|
|
|
+ fillLegalSceneArea(voPage);
|
|
|
+ // 为待支付订单计算倒计时(30分钟有效期)
|
|
|
+ calculateCountdownForPendingOrders(voPage);
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取统计信息
|
|
|
+ queryStatisticsWrapper.groupBy("lco.order_status");
|
|
|
+ List<Map<String, Object>> statisticsInfo = consultationOrderMapper.getLawyerStatisticsInfo(queryStatisticsWrapper);
|
|
|
+
|
|
|
+ Map<Integer, Integer> statusCountMap = new HashMap<>();
|
|
|
+ for (Map<String, Object> map : statisticsInfo) {
|
|
|
+ Integer status = (Integer) map.get("order_status");
|
|
|
+ Long countLong = (Long) map.get("order_count"); // COUNT(*) 返回类型可能是Long
|
|
|
+ statusCountMap.put(status, countLong.intValue());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 统计进行中订单数量
|
|
|
+ int inProgressCount = statusCountMap.getOrDefault(2, 0);
|
|
|
+ resultMap.put("lawyerInProgressOrderCount", inProgressCount);
|
|
|
+
|
|
|
+ // 统计已完成订单数量
|
|
|
+ int completeCount = statusCountMap.getOrDefault(3, 0);
|
|
|
+ resultMap.put("lawyerCompleteOrderCount", completeCount);
|
|
|
+
|
|
|
+ // 统计订单总数
|
|
|
+ resultMap.put("lawyerOrderCount", inProgressCount + completeCount);
|
|
|
+
|
|
|
+ // 设置订单列表
|
|
|
+ List<LawyerConsultationOrderVO> orderList = voPage != null && voPage.getRecords() != null
|
|
|
+ ? voPage.getRecords() : Collections.emptyList();
|
|
|
+ resultMap.put("lawyerConsultationOrderList", orderList);
|
|
|
+
|
|
|
+ return resultMap;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 为待支付订单计算倒计时(30分钟有效期)
|
|
|
+ *
|
|
|
+ * @param voPage 订单分页对象
|
|
|
+ */
|
|
|
+ private void calculateCountdownForPendingOrders(IPage<LawyerConsultationOrderVO> voPage) {
|
|
|
+ if (voPage == null || voPage.getRecords() == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ Date now = new Date();
|
|
|
+ long validitySeconds = 30 * 60; // 30分钟 = 1800秒
|
|
|
+
|
|
|
+ for (LawyerConsultationOrderVO vo : voPage.getRecords()) {
|
|
|
+ // 仅对待支付订单(orderStatus=0)计算倒计时
|
|
|
+ if (vo.getOrderStatus() != null && vo.getOrderStatus() == 0) {
|
|
|
+ Date orderTime = vo.getOrderTime();
|
|
|
+ if (orderTime != null) {
|
|
|
+ long elapsedSeconds = (now.getTime() - orderTime.getTime()) / 1000;
|
|
|
+ long remainingSeconds = validitySeconds - elapsedSeconds;
|
|
|
+ // 如果已过期,设置为0
|
|
|
+ vo.setCountdownSeconds(Math.max(0, remainingSeconds));
|
|
|
+ } else {
|
|
|
+ vo.setCountdownSeconds(0L);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 非待支付订单,倒计时为null
|
|
|
+ vo.setCountdownSeconds(null);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据工作日判断是否可以申请退款/举报
|
|
|
+ *
|
|
|
+ * @param voPage 订单分页对象
|
|
|
+ */
|
|
|
+ private void calculateWorkDayInfo(IPage<LawyerConsultationOrderVO> voPage) {
|
|
|
+ if (voPage == null || voPage.getRecords() == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ boolean isCanApplyRefund = DateUtils.getLastThreeWorkdaysRangeInfo(2);
|
|
|
+ boolean isCanApplyViolation = DateUtils.getLastThreeWorkdaysRangeInfo(3);
|
|
|
+
|
|
|
+ for (LawyerConsultationOrderVO vo : voPage.getRecords()) {
|
|
|
+ if(isCanApplyRefund){
|
|
|
+ vo.setIsCanApplyRefund("2");
|
|
|
+ } else {
|
|
|
+ vo.setIsCanApplyRefund("1");
|
|
|
+ }
|
|
|
+
|
|
|
+ if(isCanApplyViolation){
|
|
|
+ vo.setIsCanApplyViolation("2");
|
|
|
+ } else {
|
|
|
+ vo.setIsCanApplyViolation("1");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 填充律师信息到订单VO
|
|
|
+ *
|
|
|
+ * @param orderVO 订单VO对象
|
|
|
+ * @param lawyerUser 律师用户对象
|
|
|
+ */
|
|
|
+ private void fillLawyerInfo(LawyerConsultationOrderVO orderVO, LawyerUser lawyerUser) {
|
|
|
+ orderVO.setLawyerName(lawyerUser.getName());
|
|
|
+ orderVO.setLawyerPhone(lawyerUser.getPhone());
|
|
|
+ orderVO.setLawyerEmail(lawyerUser.getEmail());
|
|
|
+ orderVO.setLawyerCertificateNo(lawyerUser.getLawyerCertificateNo());
|
|
|
+ orderVO.setLawFirm(lawyerUser.getLawFirm());
|
|
|
+ orderVO.setPracticeYears(lawyerUser.getPracticeYears());
|
|
|
+ orderVO.setSpecialtyFields(lawyerUser.getSpecialtyFields());
|
|
|
+ orderVO.setCertificationStatus(lawyerUser.getCertificationStatus());
|
|
|
+ orderVO.setServiceCount(lawyerUser.getServiceCount());
|
|
|
+ orderVO.setServiceScore(lawyerUser.getServiceScore());
|
|
|
+ orderVO.setLawyerConsultationFee(lawyerUser.getConsultationFee());
|
|
|
+ orderVO.setProvince(lawyerUser.getProvince());
|
|
|
+ orderVO.setCity(lawyerUser.getCity());
|
|
|
+ orderVO.setDistrict(lawyerUser.getDistrict());
|
|
|
+ orderVO.setAddress(lawyerUser.getAddress());
|
|
|
+ orderVO.setHeadImg(lawyerUser.getHeadImg());
|
|
|
+ orderVO.setNickName(lawyerUser.getNickName());
|
|
|
+ orderVO.setPersonalIntroduction(lawyerUser.getPersonalIntroduction());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询律师订单列表
|
|
|
+ *
|
|
|
+ * @param clientUserId 用户id
|
|
|
+ * @param lawyerUserId 律师ID
|
|
|
+ * @return 订单列表
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public R<Map<String, String>> checkOrder(Integer clientUserId, Integer lawyerUserId) {
|
|
|
+ log.info("LawyerConsultationOrderController.checkOrder?clientUserId={},lawyerUserId{}", clientUserId, lawyerUserId);
|
|
|
+ List<LawyerConsultationOrder> orderDto = consultationOrderMapper.selectOrder(clientUserId, lawyerUserId);
|
|
|
+ if (CollectionUtils.isNotEmpty(orderDto)) {
|
|
|
+ return R.fail("您已存在咨询该律师的订单");
|
|
|
+ }
|
|
|
+ return R.success("可以咨询该律师");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取律师订单收益统计
|
|
|
+ * <p>
|
|
|
+ * 统计三个维度的收益数据:
|
|
|
+ * 1. 全部收益:所有已支付订单的订单总数和收益合计
|
|
|
+ * 2. 进行中:订单状态=2(进行中)且已支付的订单总数和收益合计
|
|
|
+ * 3. 已完成:订单状态=3(已完成)且已支付的订单总数和收益合计
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param lawyerConsultationOrderVO 律师用户ID
|
|
|
+ * @param lawyerConsultationOrderVO 开始时间(可选,用于筛选支付时间范围)
|
|
|
+ * @param lawyerConsultationOrderVO 结束时间(可选,用于筛选支付时间范围)
|
|
|
+ * @return 订单收益统计信息
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public R<Map<String, Object>> getOrderIncome(LawyerConsultationOrderVO lawyerConsultationOrderVO) {
|
|
|
+ log.info("LawyerConsultationOrderController.getOrderIncome?lawyerConsultationOrderVO{}", lawyerConsultationOrderVO);
|
|
|
+
|
|
|
+ // 参数校验
|
|
|
+ if (lawyerConsultationOrderVO.getLawyerUserId() == null) {
|
|
|
+ log.warn("查询订单收益失败:律师用户ID为空");
|
|
|
+ return R.fail("律师用户ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Object> resultMap = new HashMap<>();
|
|
|
+ OrderRevenueVO revenueVO = new OrderRevenueVO();
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 构建查询条件:查询已支付的订单(paymentStatus = 1)
|
|
|
+ LambdaQueryWrapper<LawyerConsultationOrder> allRevenueWrapper = new LambdaQueryWrapper<>();
|
|
|
+ allRevenueWrapper.eq(LawyerConsultationOrder::getLawyerUserId, lawyerConsultationOrderVO.getLawyerUserId())
|
|
|
+ .eq(LawyerConsultationOrder::getPaymentStatus, 1) // 已支付
|
|
|
+ .in(LawyerConsultationOrder::getOrderStatus, 2,3) // 订单状态=3(已完成)2(进行中)
|
|
|
+ .eq(LawyerConsultationOrder::getDeleteFlag, 0);
|
|
|
+
|
|
|
+ // 添加时间段筛选条件(根据支付时间)
|
|
|
+ if (lawyerConsultationOrderVO.getStartTimeNew() != null) {
|
|
|
+ allRevenueWrapper.ge(LawyerConsultationOrder::getPaymentTime, lawyerConsultationOrderVO.getStartTimeNew());
|
|
|
+ }
|
|
|
+ if (lawyerConsultationOrderVO.getEndTimeNew() != null) {
|
|
|
+ allRevenueWrapper.le(LawyerConsultationOrder::getPaymentTime, lawyerConsultationOrderVO.getEndTimeNew() );
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询全部已支付订单的统计
|
|
|
+ List<LawyerConsultationOrder> allPaidOrders = consultationOrderMapper.selectList(allRevenueWrapper);
|
|
|
+ long allOrderCount = allPaidOrders.size();
|
|
|
+ long allRevenue = allPaidOrders.stream()
|
|
|
+ .filter(order -> order.getOrderAmount() != null)
|
|
|
+ .mapToLong(LawyerConsultationOrder::getOrderAmount)
|
|
|
+ .sum();
|
|
|
+
|
|
|
+ long consultationFee = allPaidOrders.stream()
|
|
|
+ .filter(order -> order.getConsultationFee() != null)
|
|
|
+ .mapToLong(LawyerConsultationOrder::getConsultationFee)
|
|
|
+ .sum();
|
|
|
+
|
|
|
+ revenueVO.setAllOrderCount(allOrderCount);
|
|
|
+ revenueVO.setAllRevenue(allRevenue-consultationFee);
|
|
|
+
|
|
|
+
|
|
|
+ // 查询进行中订单的统计(orderStatus = 2 且已支付)
|
|
|
+ LambdaQueryWrapper<LawyerConsultationOrder> inProgressWrapper = new LambdaQueryWrapper<>();
|
|
|
+ inProgressWrapper.eq(LawyerConsultationOrder::getLawyerUserId, lawyerConsultationOrderVO.getLawyerUserId())
|
|
|
+ .eq(LawyerConsultationOrder::getOrderStatus, LawyerStatusEnum.INPROGRESS.getStatus()) // 2:进行中
|
|
|
+ .eq(LawyerConsultationOrder::getPaymentStatus, 1) // 已支付
|
|
|
+ .eq(LawyerConsultationOrder::getDeleteFlag, 0);
|
|
|
+
|
|
|
+ // 添加时间段筛选条件(根据支付时间)
|
|
|
+ if (lawyerConsultationOrderVO.getStartTimeNew() != null) {
|
|
|
+ inProgressWrapper.ge(LawyerConsultationOrder::getPaymentTime, lawyerConsultationOrderVO.getStartTimeNew());
|
|
|
+ }
|
|
|
+ if (lawyerConsultationOrderVO.getEndTimeNew() != null) {
|
|
|
+ inProgressWrapper.le(LawyerConsultationOrder::getPaymentTime, lawyerConsultationOrderVO.getEndTimeNew() );
|
|
|
+ }
|
|
|
+
|
|
|
+ List<LawyerConsultationOrder> inProgressOrders = consultationOrderMapper.selectList(inProgressWrapper);
|
|
|
+ long inProgressOrderCount = inProgressOrders.size();
|
|
|
+
|
|
|
+ long inProgressRevenue = inProgressOrders.stream()
|
|
|
+ .filter(order -> order.getOrderAmount() != null)
|
|
|
+ .mapToLong(LawyerConsultationOrder::getOrderAmount)
|
|
|
+ .sum();
|
|
|
+
|
|
|
+ long inProgressFee = inProgressOrders.stream()
|
|
|
+ .filter(order -> order.getConsultationFee() != null)
|
|
|
+ .mapToLong(LawyerConsultationOrder::getConsultationFee)
|
|
|
+ .sum();
|
|
|
+
|
|
|
+ revenueVO.setInProgressOrderCount(inProgressOrderCount);
|
|
|
+ revenueVO.setInProgressRevenue(inProgressRevenue-inProgressFee);
|
|
|
+
|
|
|
+
|
|
|
+ // 查询已完成订单的统计(orderStatus = 3 且已支付)
|
|
|
+ LambdaQueryWrapper<LawyerConsultationOrder> completedWrapper = new LambdaQueryWrapper<>();
|
|
|
+ completedWrapper.eq(LawyerConsultationOrder::getLawyerUserId, lawyerConsultationOrderVO.getLawyerUserId())
|
|
|
+ .eq(LawyerConsultationOrder::getOrderStatus, LawyerStatusEnum.COMPLETE.getStatus()) // 3:已完成
|
|
|
+ .eq(LawyerConsultationOrder::getPaymentStatus, 1) // 已支付
|
|
|
+ .eq(LawyerConsultationOrder::getDeleteFlag, 0);
|
|
|
+
|
|
|
+ // 添加时间段筛选条件(根据支付时间)
|
|
|
+ if (lawyerConsultationOrderVO.getStartTimeNew() != null) {
|
|
|
+ completedWrapper.ge(LawyerConsultationOrder::getPaymentTime, lawyerConsultationOrderVO.getStartTimeNew());
|
|
|
+ }
|
|
|
+ if (lawyerConsultationOrderVO.getEndTimeNew() != null) {
|
|
|
+ completedWrapper.le(LawyerConsultationOrder::getPaymentTime, lawyerConsultationOrderVO.getEndTimeNew() );
|
|
|
+ }
|
|
|
+
|
|
|
+ List<LawyerConsultationOrder> completedOrders = consultationOrderMapper.selectList(completedWrapper);
|
|
|
+ long completedOrderCount = completedOrders.size();
|
|
|
+ long completedRevenue = completedOrders.stream()
|
|
|
+ .filter(order -> order.getOrderAmount() != null)
|
|
|
+ .mapToLong(LawyerConsultationOrder::getOrderAmount)
|
|
|
+ .sum();
|
|
|
+
|
|
|
+ long completedFee = completedOrders.stream()
|
|
|
+ .filter(order -> order.getConsultationFee() != null)
|
|
|
+ .mapToLong(LawyerConsultationOrder::getConsultationFee)
|
|
|
+ .sum();
|
|
|
+
|
|
|
+ revenueVO.setCompletedOrderCount(completedOrderCount);
|
|
|
+ revenueVO.setCompletedRevenue(completedRevenue-completedFee);
|
|
|
+
|
|
|
+ // 构建返回结果
|
|
|
+ Map<String, Object> allRevenueMap = new HashMap<>();
|
|
|
+ allRevenueMap.put("name", "全部收益");
|
|
|
+ allRevenueMap.put("orderCount", revenueVO.getAllOrderCount());
|
|
|
+ allRevenueMap.put("totalRevenue", revenueVO.getAllRevenue());
|
|
|
+ resultMap.put("allRevenue", allRevenueMap);
|
|
|
+
|
|
|
+ Map<String, Object> inProgressMap = new HashMap<>();
|
|
|
+ inProgressMap.put("name", "进行中");
|
|
|
+ inProgressMap.put("orderCount", revenueVO.getInProgressOrderCount());
|
|
|
+ inProgressMap.put("totalRevenue", revenueVO.getInProgressRevenue());
|
|
|
+ resultMap.put("inProgress", inProgressMap);
|
|
|
+
|
|
|
+ Map<String, Object> completedMap = new HashMap<>();
|
|
|
+ completedMap.put("name", "已完成");
|
|
|
+ completedMap.put("orderCount", revenueVO.getCompletedOrderCount());
|
|
|
+ completedMap.put("totalRevenue", revenueVO.getCompletedRevenue());
|
|
|
+ resultMap.put("completed", completedMap);
|
|
|
+
|
|
|
+ log.info("查询订单收益成功,律师ID={}, 全部订单数={}, 全部收益={}, 进行中订单数={}, 进行中收益={}, 已完成订单数={}, 已完成收益={}",
|
|
|
+ lawyerConsultationOrderVO.getLawyerUserId(), allOrderCount, allRevenue, inProgressOrderCount, inProgressRevenue,
|
|
|
+ completedOrderCount, completedRevenue);
|
|
|
+
|
|
|
+ return R.data(resultMap);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("查询订单收益失败,律师ID={}", lawyerConsultationOrderVO.getLawyerUserId(), e);
|
|
|
+ return R.fail("查询订单收益失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 用户申请退款
|
|
|
+ * <p>
|
|
|
+ * 申请退款前会进行以下校验和处理:
|
|
|
+ * 1. 参数校验:用户ID和订单ID不能为空
|
|
|
+ * 2. 订单存在性校验:订单必须存在
|
|
|
+ * 3. 订单归属校验:订单必须属于该用户
|
|
|
+ * 4. 订单状态校验:只有进行中(2)和已完成(3)状态的订单可以申请退款
|
|
|
+ * 5. 退款状态校验:已申请退款的订单不允许重复申请
|
|
|
+ * 6. 更新订单的申请退款状态为已申请(1),并更新退款申请时间
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param clientUserId 客户端用户ID
|
|
|
+ * @param orderId 订单ID
|
|
|
+ * @return 申请退款结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public R<Boolean> applyRefund(String clientUserId, String orderId, String applyRefundReason) {
|
|
|
+ log.info("开始申请退款,用户ID={}, 订单ID={}", clientUserId, orderId);
|
|
|
+
|
|
|
+ // 1. 参数校验
|
|
|
+ if (!StringUtils.hasText(clientUserId)) {
|
|
|
+ log.warn("申请退款失败:用户ID为空或无效,clientUserId={}", clientUserId);
|
|
|
+ return R.fail("用户ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!StringUtils.hasText(orderId)) {
|
|
|
+ log.warn("申请退款失败:订单ID为空或无效,orderId={}", orderId);
|
|
|
+ return R.fail("订单ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 查询订单信息
|
|
|
+ LawyerConsultationOrder order = consultationOrderMapper.selectById(orderId);
|
|
|
+ if (order == null) {
|
|
|
+ log.warn("申请退款失败:订单不存在,订单ID={}", orderId);
|
|
|
+ return R.fail("订单不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 订单归属校验:订单必须属于该用户
|
|
|
+ if (!clientUserId.equals(order.getClientUserId().toString())) {
|
|
|
+ log.warn("申请退款失败:订单不属于该用户,订单ID={}, 订单用户ID={}, 请求用户ID={}",
|
|
|
+ orderId, order.getClientUserId(), clientUserId);
|
|
|
+ return R.fail("订单不属于该用户,无法申请退款");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 订单状态校验:只有进行中(2)和已完成(3)状态的订单可以申请退款
|
|
|
+ Integer orderStatus = order.getOrderStatus();
|
|
|
+ Integer inProgressStatus = LawyerStatusEnum.INPROGRESS.getStatus(); // 2:进行中
|
|
|
+ Integer completeStatus = LawyerStatusEnum.COMPLETE.getStatus(); // 3:已完成
|
|
|
+
|
|
|
+ if (!inProgressStatus.equals(orderStatus) && !completeStatus.equals(orderStatus)) {
|
|
|
+ log.warn("申请退款失败:订单状态不允许申请退款,订单ID={}, 订单编号={}, 订单状态={}",
|
|
|
+ orderId, order.getOrderNumber(), orderStatus);
|
|
|
+ return R.fail("只有进行中或已完成的订单可以申请退款");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 退款状态校验:已申请退款的订单不允许重复申请
|
|
|
+ String applyRefundStatus = order.getApplyRefundStatus();
|
|
|
+ String appliedStatus = "1"; // 1:已申请
|
|
|
+ String lawyerAgreedStatus = "3"; // 3:律师已同意
|
|
|
+ if (appliedStatus.equals(applyRefundStatus) || lawyerAgreedStatus.equals(applyRefundStatus)) {
|
|
|
+ log.warn("申请退款失败:订单已申请退款,不允许重复申请,订单ID={}, 订单编号={}, 退款状态={}",
|
|
|
+ orderId, order.getOrderNumber(), applyRefundStatus);
|
|
|
+ return R.fail("订单已申请退款,不允许重复申请");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6. 更新订单的申请退款状态为已申请(1),并更新退款申请时间
|
|
|
+ LambdaUpdateWrapper<LawyerConsultationOrder> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
+ updateWrapper.eq(LawyerConsultationOrder::getId, orderId)
|
|
|
+ .set(LawyerConsultationOrder::getApplyRefundStatus, appliedStatus)
|
|
|
+ .set(LawyerConsultationOrder::getApplyRefundTime, new Date())
|
|
|
+ .set(LawyerConsultationOrder::getUpdatedTime, new Date()).set(LawyerConsultationOrder::getApplyRefundReason, applyRefundReason);
|
|
|
+
|
|
|
+ int updateCount = consultationOrderMapper.update(null, updateWrapper);
|
|
|
+ boolean success = updateCount > 0;
|
|
|
+
|
|
|
+ // 7. 记录操作结果并发送通知
|
|
|
+ if (success) {
|
|
|
+ //设置订单超时退款时间
|
|
|
+ orderExpirationService.setOrderRefundTimeout(order.getOrderNumber(), 60 * Long.parseLong(coefficients));
|
|
|
+
|
|
|
+ log.info("申请退款成功,订单ID={}, 订单编号={}, 订单状态={}, 退款状态=已申请",
|
|
|
+ orderId, order.getOrderNumber(), orderStatus);
|
|
|
+
|
|
|
+ // 发送退款申请通知给申请人
|
|
|
+ sendRefundApplyNotice(order, clientUserId);
|
|
|
+
|
|
|
+ return R.data(true, "退款申请已提交,请等待律师处理");
|
|
|
+ } else {
|
|
|
+ log.error("申请退款失败:更新数据库失败,订单ID={}, 订单编号={}", orderId, order.getOrderNumber());
|
|
|
+ return R.fail("申请退款失败,请稍后重试");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 用户端完成订单
|
|
|
+ * <p>
|
|
|
+ * 完成订单前会进行以下校验和处理:
|
|
|
+ * 1. 参数校验:用户ID和订单ID不能为空
|
|
|
+ * 2. 订单存在性校验:订单必须存在
|
|
|
+ * 3. 订单归属校验:订单必须属于该用户
|
|
|
+ * 4. 订单状态校验:只有进行中(2)状态的订单可以完成
|
|
|
+ * 5. 更新订单状态为已完成(3),并更新完成时间
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param clientUserId 客户端用户ID
|
|
|
+ * @param orderId 订单ID
|
|
|
+ * @return 完成订单结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public R<Boolean> completeOrder(String clientUserId, String orderId) {
|
|
|
+ log.info("开始完成订单,用户ID={}, 订单ID={}", clientUserId, orderId);
|
|
|
+
|
|
|
+ // 1. 参数校验
|
|
|
+ if (StringUtils.isEmpty(clientUserId)) {
|
|
|
+ log.warn("完成订单失败:用户ID为空或无效,clientUserId={}", clientUserId);
|
|
|
+ return R.fail("用户ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (StringUtils.isEmpty(orderId)) {
|
|
|
+ log.warn("完成订单失败:订单ID为空或无效,orderId={}", orderId);
|
|
|
+ return R.fail("订单ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 查询订单信息
|
|
|
+ LawyerConsultationOrder order = consultationOrderMapper.selectById(orderId);
|
|
|
+ if (order == null) {
|
|
|
+ log.warn("完成订单失败:订单不存在,订单ID={}", orderId);
|
|
|
+ return R.fail("订单不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 订单归属校验:订单必须属于该用户
|
|
|
+ if (!clientUserId.equals(order.getClientUserId().toString())) {
|
|
|
+ log.warn("完成订单失败:订单不属于该用户,订单ID={}, 订单用户ID={}, 请求用户ID={}",
|
|
|
+ orderId, order.getClientUserId(), clientUserId);
|
|
|
+ return R.fail("订单不属于该用户,无法完成订单");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 订单状态校验:只有进行中(2)状态的订单可以完成
|
|
|
+ Integer orderStatus = order.getOrderStatus();
|
|
|
+ Integer inProgressStatus = LawyerStatusEnum.INPROGRESS.getStatus(); // 2:进行中
|
|
|
+ Integer completeStatus = LawyerStatusEnum.COMPLETE.getStatus(); // 3:已完成
|
|
|
+
|
|
|
+ if (!inProgressStatus.equals(orderStatus)) {
|
|
|
+ log.warn("完成订单失败:订单状态不允许完成,订单ID={}, 订单编号={}, 订单状态={}",
|
|
|
+ orderId, order.getOrderNumber(), orderStatus);
|
|
|
+ return R.fail("只有进行中的订单可以完成");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 更新订单状态为已完成(3),并更新咨询结束时间和更新时间
|
|
|
+ LambdaUpdateWrapper<LawyerConsultationOrder> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
+ Date now = new Date();
|
|
|
+ updateWrapper.eq(LawyerConsultationOrder::getId, orderId)
|
|
|
+ .set(LawyerConsultationOrder::getOrderStatus, completeStatus)
|
|
|
+ .set(LawyerConsultationOrder::getEndTime, now)
|
|
|
+ .set(LawyerConsultationOrder::getUpdatedTime, now);
|
|
|
+
|
|
|
+ int updateCount = consultationOrderMapper.update(null, updateWrapper);
|
|
|
+ boolean success = updateCount > 0;
|
|
|
+
|
|
|
+ // 6. 记录操作结果
|
|
|
+ if (success) {
|
|
|
+ log.info("完成订单成功,订单ID={}, 订单编号={}, 原状态={}, 新状态=已完成",
|
|
|
+ orderId, order.getOrderNumber(), orderStatus);
|
|
|
+ return R.data(true, "订单已完成");
|
|
|
+ } else {
|
|
|
+ log.error("完成订单失败:更新数据库失败,订单ID={}, 订单编号={}", orderId, order.getOrderNumber());
|
|
|
+ return R.fail("完成订单失败,请稍后重试");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取申请退款订单详情
|
|
|
+ * <p>
|
|
|
+ * 根据订单ID查询订单信息,用于退款申请详情展示
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param orderId 订单ID,不能为空
|
|
|
+ * @return 订单信息,如果订单ID为空或订单不存在则返回null
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public LawyerConsultationOrder getApplyRefundDetail(String orderId) {
|
|
|
+ log.info("开始查询申请退款订单详情,订单ID={}", orderId);
|
|
|
+
|
|
|
+ // 参数校验:订单ID不能为空
|
|
|
+ if (!StringUtils.hasText(orderId)) {
|
|
|
+ log.warn("查询申请退款订单详情失败:订单ID为空");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 查询订单信息
|
|
|
+ LawyerConsultationOrder order = consultationOrderMapper.selectById(orderId);
|
|
|
+ if (order == null) {
|
|
|
+ log.warn("查询申请退款订单详情失败:订单不存在,订单ID={}", orderId);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("查询申请退款订单详情成功,订单ID={}, 订单编号={}", orderId, order.getOrderNumber());
|
|
|
+ return order;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("查询申请退款订单详情异常,订单ID={}, 异常信息={}", orderId, e.getMessage(), e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 格式化收益金额(分转元)
|
|
|
+ *
|
|
|
+ * @param revenueInCents 收益金额(单位:分)
|
|
|
+ * @return 格式化后的金额字符串(单位:元)
|
|
|
+ */
|
|
|
+ private String formatRevenue(long revenueInCents) {
|
|
|
+ if (revenueInCents == 0) {
|
|
|
+ return "0";
|
|
|
+ }
|
|
|
+ BigDecimal revenue = new BigDecimal(revenueInCents);
|
|
|
+ BigDecimal revenueInYuan = revenue.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
|
|
|
+ return revenueInYuan.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送退款申请通知给申请人
|
|
|
+ *
|
|
|
+ * @param order 订单对象
|
|
|
+ * @param clientUserId 客户端用户ID
|
|
|
+ */
|
|
|
+ private void sendRefundApplyNotice(LawyerConsultationOrder order, String clientUserId) {
|
|
|
+ try {
|
|
|
+ LifeNotice lifeNotice = createRefundApplyNotice(order, clientUserId);
|
|
|
+ if (lifeNotice == null) {
|
|
|
+ log.warn("生成退款申请通知失败,订单ID={}, 用户ID={}", order.getId(), clientUserId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ int noticeResult = lifeNoticeMapper.insert(lifeNotice);
|
|
|
+ if (noticeResult <= 0) {
|
|
|
+ log.warn("保存退款申请通知失败,订单ID={}, 用户ID={}", order.getId(), clientUserId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 发送WebSocket消息
|
|
|
+ WebSocketVo webSocketVo = buildWebSocketVo(lifeNotice);
|
|
|
+ webSocketProcess.sendMessage(lifeNotice.getReceiverId(),
|
|
|
+ JSONObject.from(webSocketVo).toJSONString());
|
|
|
+
|
|
|
+ log.info("退款申请通知发送成功,接收人ID={}, 订单编号={}", lifeNotice.getReceiverId(), order.getOrderNumber());
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("发送退款申请通知异常,订单ID={}, 用户ID={}, 异常信息={}",
|
|
|
+ order.getId(), clientUserId, e.getMessage(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建退款申请通知对象
|
|
|
+ *
|
|
|
+ * @param order 订单对象
|
|
|
+ * @param clientUserId 客户端用户ID
|
|
|
+ * @return 通知对象,如果生成失败返回null
|
|
|
+ */
|
|
|
+ private LifeNotice createRefundApplyNotice(LawyerConsultationOrder order, String clientUserId) {
|
|
|
+ if (order == null || clientUserId == null) {
|
|
|
+ log.warn("创建退款申请通知失败,订单或用户ID为空");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ LifeNotice lifeNotice = new LifeNotice();
|
|
|
+ lifeNotice.setSenderId(SYSTEM_SENDER_ID);
|
|
|
+ lifeNotice.setBusinessId(order.getId());
|
|
|
+ lifeNotice.setTitle("申请退款通知");
|
|
|
+
|
|
|
+ // 获取申请人接收ID
|
|
|
+ String receiverId = getClientReceiverId(clientUserId);
|
|
|
+ if (org.apache.commons.lang3.StringUtils.isEmpty(receiverId)) {
|
|
|
+ log.warn("获取申请人接收ID失败,用户ID={}", clientUserId);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ lifeNotice.setReceiverId(receiverId);
|
|
|
+
|
|
|
+ // 构建通知消息内容
|
|
|
+ String orderNumber = order.getOrderNumber();
|
|
|
+ String message = String.format("您的编号为%s的订单,申请退款的信息已提交给律师,等待律师同意。律师同意或48小时未处理,系统会将订单金额原路返还,请注意查收。",
|
|
|
+ orderNumber != null ? orderNumber : "");
|
|
|
+
|
|
|
+ JSONObject jsonObject = new JSONObject();
|
|
|
+ jsonObject.put("title", "申请退款通知");
|
|
|
+ jsonObject.put("message", message);
|
|
|
+ lifeNotice.setContext(jsonObject.toJSONString());
|
|
|
+ lifeNotice.setNoticeType(1);
|
|
|
+
|
|
|
+ return lifeNotice;
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("创建退款申请通知异常,订单ID={}, 用户ID={}, 异常信息={}",
|
|
|
+ order.getId(), clientUserId, e.getMessage(), e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取客户端用户接收ID
|
|
|
+ *
|
|
|
+ * @param clientUserId 客户端用户ID
|
|
|
+ * @return 接收人ID,格式:user_ + 手机号
|
|
|
+ */
|
|
|
+ private String getClientReceiverId(String clientUserId) {
|
|
|
+ try {
|
|
|
+ LifeUser lifeUser = lifeUserMapper.selectById(clientUserId);
|
|
|
+ if (lifeUser != null && org.apache.commons.lang3.StringUtils.isNotEmpty(lifeUser.getUserPhone())) {
|
|
|
+ return "user_" + lifeUser.getUserPhone();
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("获取客户端用户手机号异常,用户ID={}, 异常信息={}", clientUserId, e.getMessage(), e);
|
|
|
+ }
|
|
|
+
|
|
|
+ log.warn("获取客户端用户手机号失败,用户ID={}", clientUserId);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建WebSocket消息对象
|
|
|
+ *
|
|
|
+ * @param lifeNotice 通知对象
|
|
|
+ * @return WebSocketVo对象
|
|
|
+ */
|
|
|
+ private WebSocketVo buildWebSocketVo(LifeNotice lifeNotice) {
|
|
|
+ WebSocketVo webSocketVo = new WebSocketVo();
|
|
|
+ webSocketVo.setSenderId(SYSTEM_SENDER_ID);
|
|
|
+ webSocketVo.setReceiverId(lifeNotice.getReceiverId());
|
|
|
+ webSocketVo.setCategory("notice");
|
|
|
+ webSocketVo.setNoticeType("1");
|
|
|
+ webSocketVo.setIsRead(0);
|
|
|
+ webSocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
|
|
|
+ return webSocketVo;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|