|
|
@@ -0,0 +1,205 @@
|
|
|
+package com.etotem.num.service;
|
|
|
+
|
|
|
+import com.etotem.num.common.BizException;
|
|
|
+import com.etotem.num.entity.ChatIntervention;
|
|
|
+import com.etotem.num.entity.ChatMessage;
|
|
|
+import com.etotem.num.entity.ChartRecord;
|
|
|
+import com.etotem.num.entity.User;
|
|
|
+import com.etotem.num.repository.ChatInterventionRepository;
|
|
|
+import com.etotem.num.repository.ChatMessageRepository;
|
|
|
+import com.etotem.num.repository.ChartRecordRepository;
|
|
|
+import com.etotem.num.repository.UserRepository;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class InterventionService {
|
|
|
+
|
|
|
+ private final UserRepository userRepository;
|
|
|
+ private final ChartRecordRepository chartRecordRepository;
|
|
|
+ private final ChatMessageRepository chatMessageRepository;
|
|
|
+ private final ChatInterventionRepository chatInterventionRepository;
|
|
|
+
|
|
|
+ public InterventionService(UserRepository userRepository, ChartRecordRepository chartRecordRepository,
|
|
|
+ ChatMessageRepository chatMessageRepository, ChatInterventionRepository chatInterventionRepository) {
|
|
|
+ this.userRepository = userRepository;
|
|
|
+ this.chartRecordRepository = chartRecordRepository;
|
|
|
+ this.chatMessageRepository = chatMessageRepository;
|
|
|
+ this.chatInterventionRepository = chatInterventionRepository;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Ensure the user is an active practitioner.
|
|
|
+ */
|
|
|
+ public void ensurePractitioner(Long userId) {
|
|
|
+ User user = userRepository.findById(userId)
|
|
|
+ .orElseThrow(() -> new BizException(1003, "User not found"));
|
|
|
+ if (!"practitioner".equals(user.getVipType()) || user.getVipEndTime() == null || user.getVipEndTime().isBefore(LocalDateTime.now())) {
|
|
|
+ throw new BizException(1005, "仅能量师可执行此操作");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * US-9.3: Get subordinate users' chat list for practitioner monitoring.
|
|
|
+ * Returns list of maps containing user info and their chart records with last active time.
|
|
|
+ */
|
|
|
+ public List<Map<String, Object>> getSubordinateChatList(Long practitionerId) {
|
|
|
+ ensurePractitioner(practitionerId);
|
|
|
+
|
|
|
+ List<User> subordinates = userRepository.findByInvitedBy(practitionerId);
|
|
|
+ List<Map<String, Object>> result = new ArrayList<>();
|
|
|
+
|
|
|
+ for (User user : subordinates) {
|
|
|
+ List<ChartRecord> chartRecords = chartRecordRepository.findByUserIdOrderByCreatedAtDesc(user.getId());
|
|
|
+
|
|
|
+ if (chartRecords.isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get the most recent chart record for this user
|
|
|
+ ChartRecord latestRecord = chartRecords.get(0);
|
|
|
+
|
|
|
+ // Calculate lastActiveTime: most recent between chart record createdAt and latest chat message
|
|
|
+ LocalDateTime lastActiveTime = latestRecord.getCreatedAt();
|
|
|
+ List<ChatMessage> messages = chatMessageRepository.findByChartRecordIdOrderByCreatedAtAsc(latestRecord.getId());
|
|
|
+ if (!messages.isEmpty()) {
|
|
|
+ LocalDateTime latestMsgTime = messages.get(messages.size() - 1).getCreatedAt();
|
|
|
+ if (latestMsgTime.isAfter(lastActiveTime)) {
|
|
|
+ lastActiveTime = latestMsgTime;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Object> item = new LinkedHashMap<>();
|
|
|
+ item.put("userId", user.getId());
|
|
|
+ item.put("nickname", user.getNickname());
|
|
|
+ item.put("avatarUrl", user.getAvatarUrl());
|
|
|
+ item.put("chartRecordId", latestRecord.getId());
|
|
|
+ item.put("birthday", latestRecord.getBirthday());
|
|
|
+ item.put("lastActiveTime", lastActiveTime);
|
|
|
+ result.add(item);
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * US-9.3: Get chat history for practitioner monitoring (read-only).
|
|
|
+ */
|
|
|
+ public List<ChatMessage> getChatHistoryForMonitoring(Long practitionerId, Long chartRecordId) {
|
|
|
+ ensurePractitioner(practitionerId);
|
|
|
+
|
|
|
+ ChartRecord record = chartRecordRepository.findById(chartRecordId)
|
|
|
+ .orElseThrow(() -> new BizException(1003, "Chart record not found"));
|
|
|
+
|
|
|
+ User user = userRepository.findById(record.getUserId())
|
|
|
+ .orElseThrow(() -> new BizException(1003, "User not found"));
|
|
|
+
|
|
|
+ if (!practitionerId.equals(user.getInvitedBy())) {
|
|
|
+ throw new BizException(1004, "无权访问此命盘");
|
|
|
+ }
|
|
|
+
|
|
|
+ return chatMessageRepository.findByChartRecordIdOrderByCreatedAtAsc(chartRecordId);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * US-9.3: Start an intervention session.
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public ChatIntervention startIntervention(Long practitionerId, Long chartRecordId) {
|
|
|
+ ensurePractitioner(practitionerId);
|
|
|
+
|
|
|
+ ChartRecord record = chartRecordRepository.findById(chartRecordId)
|
|
|
+ .orElseThrow(() -> new BizException(1003, "Chart record not found"));
|
|
|
+
|
|
|
+ User user = userRepository.findById(record.getUserId())
|
|
|
+ .orElseThrow(() -> new BizException(1003, "User not found"));
|
|
|
+
|
|
|
+ if (!practitionerId.equals(user.getInvitedBy())) {
|
|
|
+ throw new BizException(1004, "无权访问此命盘");
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check no active intervention already exists for this session+practitioner
|
|
|
+ chatInterventionRepository.findBySessionIdAndPractitionerIdAndEndTimeIsNull(chartRecordId, practitionerId)
|
|
|
+ .ifPresent(existing -> {
|
|
|
+ throw new BizException(1006, "当前已有进行中的介入会话");
|
|
|
+ });
|
|
|
+
|
|
|
+ // Create intervention record
|
|
|
+ ChatIntervention intervention = new ChatIntervention();
|
|
|
+ intervention.setSessionId(chartRecordId);
|
|
|
+ intervention.setPractitionerId(practitionerId);
|
|
|
+ intervention.setStartTime(LocalDateTime.now());
|
|
|
+ ChatIntervention saved = chatInterventionRepository.save(intervention);
|
|
|
+
|
|
|
+ // Create system message
|
|
|
+ ChatMessage systemMsg = new ChatMessage();
|
|
|
+ systemMsg.setChartRecordId(chartRecordId);
|
|
|
+ systemMsg.setUserId(record.getUserId());
|
|
|
+ systemMsg.setRole("system");
|
|
|
+ systemMsg.setSenderType("system");
|
|
|
+ systemMsg.setContent("🔔 能量师 已进入本次咨询");
|
|
|
+ chatMessageRepository.save(systemMsg);
|
|
|
+
|
|
|
+ return saved;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * US-9.3: End an intervention session.
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public ChatIntervention endIntervention(Long practitionerId, Long interventionId, String endedBy) {
|
|
|
+ ChatIntervention intervention = chatInterventionRepository.findById(interventionId)
|
|
|
+ .orElseThrow(() -> new BizException(1003, "Intervention not found"));
|
|
|
+
|
|
|
+ if (!practitionerId.equals(intervention.getPractitionerId())) {
|
|
|
+ throw new BizException(1004, "无权结束此介入会话");
|
|
|
+ }
|
|
|
+
|
|
|
+ intervention.setEndTime(LocalDateTime.now());
|
|
|
+ intervention.setEndedBy(endedBy);
|
|
|
+ ChatIntervention saved = chatInterventionRepository.save(intervention);
|
|
|
+
|
|
|
+ // Create system message
|
|
|
+ String content = "practitioner".equals(endedBy) ? "能量师 已退出本次咨询" : "用户已结束本次协同咨询";
|
|
|
+ ChatMessage systemMsg = new ChatMessage();
|
|
|
+ systemMsg.setChartRecordId(intervention.getSessionId());
|
|
|
+ systemMsg.setUserId(null); // system message, no specific user
|
|
|
+ systemMsg.setRole("system");
|
|
|
+ systemMsg.setSenderType("system");
|
|
|
+ systemMsg.setContent(content);
|
|
|
+ chatMessageRepository.save(systemMsg);
|
|
|
+
|
|
|
+ return saved;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * US-9.3: Send a message during active intervention.
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public ChatMessage sendPractitionerMessage(Long practitionerId, Long chartRecordId, String content) {
|
|
|
+ ensurePractitioner(practitionerId);
|
|
|
+
|
|
|
+ // Verify there's an active intervention for this session+practitioner
|
|
|
+ ChatIntervention intervention = chatInterventionRepository
|
|
|
+ .findBySessionIdAndPractitionerIdAndEndTimeIsNull(chartRecordId, practitionerId)
|
|
|
+ .orElseThrow(() -> new BizException(1006, "当前没有进行中的介入会话"));
|
|
|
+
|
|
|
+ ChartRecord record = chartRecordRepository.findById(chartRecordId)
|
|
|
+ .orElseThrow(() -> new BizException(1003, "Chart record not found"));
|
|
|
+
|
|
|
+ // Create practitioner message
|
|
|
+ ChatMessage message = new ChatMessage();
|
|
|
+ message.setChartRecordId(chartRecordId);
|
|
|
+ message.setUserId(record.getUserId());
|
|
|
+ message.setRole("practitioner");
|
|
|
+ message.setSenderType("practitioner");
|
|
|
+ message.setContent(content);
|
|
|
+ return chatMessageRepository.save(message);
|
|
|
+ }
|
|
|
+}
|