|
@@ -9,11 +9,14 @@ import io.github.linpeilie.Converter;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.dromara.common.core.exception.ServiceException;
|
|
import org.dromara.common.core.exception.ServiceException;
|
|
|
|
|
+import org.dromara.common.satoken.utils.LoginHelper;
|
|
|
import org.dromara.main.config.WxPayConfig;
|
|
import org.dromara.main.config.WxPayConfig;
|
|
|
import org.dromara.main.domain.*;
|
|
import org.dromara.main.domain.*;
|
|
|
import org.dromara.main.domain.bo.CsOrderCardBo;
|
|
import org.dromara.main.domain.bo.CsOrderCardBo;
|
|
|
|
|
+import org.dromara.main.domain.vo.CsMessageVo;
|
|
|
import org.dromara.main.domain.vo.CsOrderCardVo;
|
|
import org.dromara.main.domain.vo.CsOrderCardVo;
|
|
|
import org.dromara.main.mapper.CsMessageMapper;
|
|
import org.dromara.main.mapper.CsMessageMapper;
|
|
|
|
|
+import org.springframework.messaging.simp.SimpMessagingTemplate;
|
|
|
import org.dromara.main.mapper.CsOrderCardMapper;
|
|
import org.dromara.main.mapper.CsOrderCardMapper;
|
|
|
import org.dromara.main.mapper.CsSessionMapper;
|
|
import org.dromara.main.mapper.CsSessionMapper;
|
|
|
import org.dromara.main.mapper.MainExamEvaluationMapper;
|
|
import org.dromara.main.mapper.MainExamEvaluationMapper;
|
|
@@ -40,6 +43,7 @@ public class CsOrderCardServiceImpl implements ICsOrderCardService {
|
|
|
private final CsMessageMapper messageMapper;
|
|
private final CsMessageMapper messageMapper;
|
|
|
private final ICsSessionService sessionService;
|
|
private final ICsSessionService sessionService;
|
|
|
private final Converter converter;
|
|
private final Converter converter;
|
|
|
|
|
+ private final SimpMessagingTemplate messagingTemplate;
|
|
|
private final MainOrderMapper orderMapper;
|
|
private final MainOrderMapper orderMapper;
|
|
|
private final MainStudentMapper studentMapper;
|
|
private final MainStudentMapper studentMapper;
|
|
|
private final CsSessionMapper sessionMapper;
|
|
private final CsSessionMapper sessionMapper;
|
|
@@ -51,11 +55,21 @@ public class CsOrderCardServiceImpl implements ICsOrderCardService {
|
|
|
@Override
|
|
@Override
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
public CsOrderCardVo sendOrderCard(CsOrderCardBo bo) {
|
|
public CsOrderCardVo sendOrderCard(CsOrderCardBo bo) {
|
|
|
|
|
+ // 解析发送者ID(优先使用传入值,fallback 到当前登录用户)
|
|
|
|
|
+ Long senderId = bo.getSenderId() != null ? bo.getSenderId() : LoginHelper.getUserId();
|
|
|
|
|
+
|
|
|
|
|
+ // 动态解析发送者类型
|
|
|
|
|
+ CsSession session = sessionMapper.selectById(bo.getSessionId());
|
|
|
|
|
+ Integer senderType = 2; // 默认为客服(手动发送结算单只从总控端调用)
|
|
|
|
|
+ if (senderId != null && session != null && session.getFromUserId() != null && session.getFromUserId().equals(senderId)) {
|
|
|
|
|
+ senderType = 1; // 极端情况:用户自己发的
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
CsMessage message = new CsMessage();
|
|
CsMessage message = new CsMessage();
|
|
|
message.setSessionId(bo.getSessionId());
|
|
message.setSessionId(bo.getSessionId());
|
|
|
message.setMsgNo(bo.getMsgNo());
|
|
message.setMsgNo(bo.getMsgNo());
|
|
|
- message.setSenderType(2);
|
|
|
|
|
- message.setSenderId(bo.getSenderId());
|
|
|
|
|
|
|
+ message.setSenderType(senderType);
|
|
|
|
|
+ message.setSenderId(senderId);
|
|
|
message.setMsgType("order_card");
|
|
message.setMsgType("order_card");
|
|
|
message.setStatus(1);
|
|
message.setStatus(1);
|
|
|
message.setIsRead(0);
|
|
message.setIsRead(0);
|
|
@@ -86,8 +100,39 @@ public class CsOrderCardServiceImpl implements ICsOrderCardService {
|
|
|
|
|
|
|
|
sessionService.updateLastMessage(bo.getSessionId(), "[结算单]" + bo.getOrderName());
|
|
sessionService.updateLastMessage(bo.getSessionId(), "[结算单]" + bo.getOrderName());
|
|
|
|
|
|
|
|
|
|
+ // 推送消息到会话频道(与 CsMessageServiceImpl 保持一致)
|
|
|
|
|
+ CsMessageVo msgVo = new CsMessageVo();
|
|
|
|
|
+ msgVo.setId(message.getId());
|
|
|
|
|
+ msgVo.setSessionId(message.getSessionId());
|
|
|
|
|
+ msgVo.setMsgNo(message.getMsgNo());
|
|
|
|
|
+ msgVo.setSenderType(message.getSenderType());
|
|
|
|
|
+ msgVo.setSenderId(message.getSenderId());
|
|
|
|
|
+ msgVo.setMsgType(message.getMsgType());
|
|
|
|
|
+ msgVo.setPayload(message.getPayload());
|
|
|
|
|
+ msgVo.setStatus(message.getStatus());
|
|
|
|
|
+ msgVo.setSendTime(message.getSendTime());
|
|
|
|
|
+ // 设置 senderRole,确保前端正确识别发送者
|
|
|
|
|
+ if (message.getSenderType() == 2) {
|
|
|
|
|
+ msgVo.setSenderRole("waiter");
|
|
|
|
|
+ } else if (message.getSenderType() == 3) {
|
|
|
|
|
+ msgVo.setSenderRole("system");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ msgVo.setSenderRole("user");
|
|
|
|
|
+ }
|
|
|
|
|
+ messagingTemplate.convertAndSend("/topic/session/" + bo.getSessionId(), msgVo);
|
|
|
|
|
+ // 通知坐席
|
|
|
|
|
+ if (session != null && session.getWaiterId() != null) {
|
|
|
|
|
+ messagingTemplate.convertAndSendToUser(
|
|
|
|
|
+ session.getWaiterId().toString(),
|
|
|
|
|
+ "/queue/notify",
|
|
|
|
|
+ msgVo
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
CsOrderCardVo vo = converter.convert(orderCard, CsOrderCardVo.class);
|
|
CsOrderCardVo vo = converter.convert(orderCard, CsOrderCardVo.class);
|
|
|
if (vo != null) {
|
|
if (vo != null) {
|
|
|
|
|
+ vo.setOrderCardId(orderCard.getId());
|
|
|
|
|
+ vo.setSenderType(senderType);
|
|
|
vo.setCountdownSeconds(60L);
|
|
vo.setCountdownSeconds(60L);
|
|
|
}
|
|
}
|
|
|
return vo;
|
|
return vo;
|
|
@@ -97,9 +142,12 @@ public class CsOrderCardServiceImpl implements ICsOrderCardService {
|
|
|
public CsOrderCardVo queryById(Long orderCardId) {
|
|
public CsOrderCardVo queryById(Long orderCardId) {
|
|
|
CsOrderCard entity = baseMapper.selectById(orderCardId);
|
|
CsOrderCard entity = baseMapper.selectById(orderCardId);
|
|
|
CsOrderCardVo vo = converter.convert(entity, CsOrderCardVo.class);
|
|
CsOrderCardVo vo = converter.convert(entity, CsOrderCardVo.class);
|
|
|
- if (vo != null && "pending".equals(vo.getStatus())) {
|
|
|
|
|
- long seconds = Duration.between(LocalDateTime.now(), vo.getExpireTime()).getSeconds();
|
|
|
|
|
- vo.setCountdownSeconds(Math.max(0, seconds));
|
|
|
|
|
|
|
+ if (vo != null) {
|
|
|
|
|
+ vo.setOrderCardId(entity.getId());
|
|
|
|
|
+ if ("pending".equals(vo.getStatus())) {
|
|
|
|
|
+ long seconds = Duration.between(LocalDateTime.now(), vo.getExpireTime()).getSeconds();
|
|
|
|
|
+ vo.setCountdownSeconds(Math.max(0, seconds));
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
return vo;
|
|
return vo;
|
|
|
}
|
|
}
|
|
@@ -151,23 +199,23 @@ public class CsOrderCardServiceImpl implements ICsOrderCardService {
|
|
|
@Override
|
|
@Override
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
public Map<String,Object>createPayOrder(Long orderCardId,Long userId) {
|
|
public Map<String,Object>createPayOrder(Long orderCardId,Long userId) {
|
|
|
|
|
+ log.info("========== createPayOrder 入参: orderCardId={}, userId={} ==========", orderCardId, userId);
|
|
|
CsOrderCard orderCard = baseMapper.selectById(orderCardId);
|
|
CsOrderCard orderCard = baseMapper.selectById(orderCardId);
|
|
|
if (orderCard == null) {
|
|
if (orderCard == null) {
|
|
|
|
|
+ log.error("结算单不存在, orderCardId={}", orderCardId);
|
|
|
throw new RuntimeException("结算单不存在");
|
|
throw new RuntimeException("结算单不存在");
|
|
|
}
|
|
}
|
|
|
|
|
+ log.info("结算单查询成功: id={}, status={}, sessionId={}, orderPrice={}", orderCard.getId(), orderCard.getStatus(), orderCard.getSessionId(), orderCard.getOrderPrice());
|
|
|
if (!"pending".equals(orderCard.getStatus())) {
|
|
if (!"pending".equals(orderCard.getStatus())) {
|
|
|
throw new RuntimeException("结算单状态异常");
|
|
throw new RuntimeException("结算单状态异常");
|
|
|
}
|
|
}
|
|
|
-// if(LocalDateTime.now().isAfter(orderCard.getCreateTime())){
|
|
|
|
|
-// orderCard.setStatus("expired");
|
|
|
|
|
-// baseMapper.updateById(orderCard);
|
|
|
|
|
-// throw new RuntimeException("结算单已过期");
|
|
|
|
|
-// }
|
|
|
|
|
-
|
|
|
|
|
|
|
|
|
|
MainStudent student = studentMapper.selectById(userId);
|
|
MainStudent student = studentMapper.selectById(userId);
|
|
|
|
|
+ log.info("学员查询结果: userId={}, student={}", userId, student != null ? "id=" + student.getId() + ",name=" + student.getName() + ",openid=" + student.getOpenid() : "NULL");
|
|
|
if (student == null) {
|
|
if (student == null) {
|
|
|
- throw new ServiceException("用户不存在");
|
|
|
|
|
|
|
+ // 尝试通过 tenantId + mobile 查找,或者给出更详细的错误信息
|
|
|
|
|
+ log.error("用户不存在, 传入userId={}, 尝试检查main_student表是否有此ID", userId);
|
|
|
|
|
+ throw new ServiceException("用户不存在[userId=" + userId + "]");
|
|
|
}
|
|
}
|
|
|
if(StringUtils.isEmpty(student.getOpenid())){
|
|
if(StringUtils.isEmpty(student.getOpenid())){
|
|
|
throw new ServiceException("用户未绑定微信");
|
|
throw new ServiceException("用户未绑定微信");
|
|
@@ -313,9 +361,19 @@ public class CsOrderCardServiceImpl implements ICsOrderCardService {
|
|
|
.last("LIMIT 1"));
|
|
.last("LIMIT 1"));
|
|
|
if (existing != null) {
|
|
if (existing != null) {
|
|
|
CsOrderCardVo vo = converter.convert(existing, CsOrderCardVo.class);
|
|
CsOrderCardVo vo = converter.convert(existing, CsOrderCardVo.class);
|
|
|
- if (vo != null && "pending".equals(vo.getStatus())) {
|
|
|
|
|
- long seconds = Duration.between(LocalDateTime.now(), existing.getExpireTime()).getSeconds();
|
|
|
|
|
- vo.setCountdownSeconds(Math.max(0, seconds));
|
|
|
|
|
|
|
+ if (vo != null) {
|
|
|
|
|
+ vo.setOrderCardId(existing.getId());
|
|
|
|
|
+ // 从关联消息获取 senderType
|
|
|
|
|
+ if (existing.getMsgId() != null) {
|
|
|
|
|
+ CsMessage existingMsg = messageMapper.selectById(existing.getMsgId());
|
|
|
|
|
+ if (existingMsg != null) {
|
|
|
|
|
+ vo.setSenderType(existingMsg.getSenderType());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if ("pending".equals(vo.getStatus())) {
|
|
|
|
|
+ long seconds = Duration.between(LocalDateTime.now(), existing.getExpireTime()).getSeconds();
|
|
|
|
|
+ vo.setCountdownSeconds(Math.max(0, seconds));
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
return vo;
|
|
return vo;
|
|
|
}
|
|
}
|
|
@@ -376,13 +434,20 @@ public class CsOrderCardServiceImpl implements ICsOrderCardService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 创建消息
|
|
|
|
|
|
|
+ // 创建消息(自动创建结算单,有客服时以客服身份,否则以系统身份)
|
|
|
CsMessage message = new CsMessage();
|
|
CsMessage message = new CsMessage();
|
|
|
message.setSessionId(sessionId);
|
|
message.setSessionId(sessionId);
|
|
|
message.setMsgNo("ORDER_" + System.currentTimeMillis());
|
|
message.setMsgNo("ORDER_" + System.currentTimeMillis());
|
|
|
- message.setSenderType(2);
|
|
|
|
|
- message.setSenderId(session != null ? session.getWaiterId() : null);
|
|
|
|
|
message.setMsgType("order_card");
|
|
message.setMsgType("order_card");
|
|
|
|
|
+ Long waiterId = session != null ? session.getWaiterId() : null;
|
|
|
|
|
+ // senderId: 有坐席用坐席ID(客服),没有坐席时以系统身份
|
|
|
|
|
+ if (waiterId != null) {
|
|
|
|
|
+ message.setSenderId(waiterId);
|
|
|
|
|
+ message.setSenderType(2); // 客服
|
|
|
|
|
+ } else {
|
|
|
|
|
+ message.setSenderId(0L);
|
|
|
|
|
+ message.setSenderType(3); // 系统
|
|
|
|
|
+ }
|
|
|
message.setStatus(1);
|
|
message.setStatus(1);
|
|
|
message.setIsRead(0);
|
|
message.setIsRead(0);
|
|
|
message.setSendTime(LocalDateTime.now());
|
|
message.setSendTime(LocalDateTime.now());
|
|
@@ -416,8 +481,39 @@ public class CsOrderCardServiceImpl implements ICsOrderCardService {
|
|
|
|
|
|
|
|
sessionService.updateLastMessage(sessionId, "[结算单]" + orderCard.getOrderName());
|
|
sessionService.updateLastMessage(sessionId, "[结算单]" + orderCard.getOrderName());
|
|
|
|
|
|
|
|
|
|
+ // 通过 WebSocket 广播消息,确保前端实时收到
|
|
|
|
|
+ CsMessageVo msgVo = new CsMessageVo();
|
|
|
|
|
+ msgVo.setId(message.getId());
|
|
|
|
|
+ msgVo.setSessionId(message.getSessionId());
|
|
|
|
|
+ msgVo.setMsgNo(message.getMsgNo());
|
|
|
|
|
+ msgVo.setSenderType(message.getSenderType());
|
|
|
|
|
+ msgVo.setSenderId(message.getSenderId());
|
|
|
|
|
+ msgVo.setMsgType(message.getMsgType());
|
|
|
|
|
+ msgVo.setPayload(message.getPayload());
|
|
|
|
|
+ msgVo.setStatus(message.getStatus());
|
|
|
|
|
+ msgVo.setSendTime(message.getSendTime());
|
|
|
|
|
+ // 设置 senderRole,确保前端正确识别发送者
|
|
|
|
|
+ if (message.getSenderType() == 2) {
|
|
|
|
|
+ msgVo.setSenderRole("waiter");
|
|
|
|
|
+ } else if (message.getSenderType() == 3) {
|
|
|
|
|
+ msgVo.setSenderRole("system");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ msgVo.setSenderRole("user");
|
|
|
|
|
+ }
|
|
|
|
|
+ messagingTemplate.convertAndSend("/topic/session/" + sessionId, msgVo);
|
|
|
|
|
+ // 通知坐席
|
|
|
|
|
+ if (session != null && session.getWaiterId() != null) {
|
|
|
|
|
+ messagingTemplate.convertAndSendToUser(
|
|
|
|
|
+ session.getWaiterId().toString(),
|
|
|
|
|
+ "/queue/notify",
|
|
|
|
|
+ msgVo
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
CsOrderCardVo vo = converter.convert(orderCard, CsOrderCardVo.class);
|
|
CsOrderCardVo vo = converter.convert(orderCard, CsOrderCardVo.class);
|
|
|
if (vo != null) {
|
|
if (vo != null) {
|
|
|
|
|
+ vo.setOrderCardId(orderCard.getId());
|
|
|
|
|
+ vo.setSenderType(message.getSenderType());
|
|
|
vo.setCountdownSeconds(1800L);
|
|
vo.setCountdownSeconds(1800L);
|
|
|
}
|
|
}
|
|
|
return vo;
|
|
return vo;
|