|
|
@@ -0,0 +1,343 @@
|
|
|
+package com.fs.qw.service.impl;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Locale;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.fs.common.utils.DateUtils;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.fs.qw.domain.QwExternalContact;
|
|
|
+import com.fs.qw.dto.QwMsgAuditConversationDTO;
|
|
|
+import com.fs.qw.vo.QwMsgAuditConversationVO;
|
|
|
+import com.fs.qw.domain.audit.QwMsgAuditMessage;
|
|
|
+import com.fs.qw.mapper.QwExternalContactMapper;
|
|
|
+import com.fs.qw.mapper.QwMsgAuditMessageMapper;
|
|
|
+import com.fs.qw.mapper.QwUserMapper;
|
|
|
+import com.fs.qw.service.IQwMsgAuditMessageService;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 企微会话存档结构化消息Service业务层处理
|
|
|
+ *
|
|
|
+ * @author fs
|
|
|
+ * @date 2026-03-19
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class QwMsgAuditMessageServiceImpl extends ServiceImpl<QwMsgAuditMessageMapper, QwMsgAuditMessage> implements IQwMsgAuditMessageService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private QwExternalContactMapper qwExternalContactMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private QwUserMapper qwUserMapper;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询企微会话存档结构化消息
|
|
|
+ *
|
|
|
+ * @param id 企微会话存档结构化消息主键
|
|
|
+ * @return 企微会话存档结构化消息
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public QwMsgAuditMessage selectQwMsgAuditMessageById(Long id)
|
|
|
+ {
|
|
|
+ return baseMapper.selectQwMsgAuditMessageById(id);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询企微会话存档结构化消息列表
|
|
|
+ *
|
|
|
+ * @param qwMsgAuditMessage 企微会话存档结构化消息
|
|
|
+ * @return 企微会话存档结构化消息
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<QwMsgAuditMessage> selectQwMsgAuditMessageList(QwMsgAuditMessage qwMsgAuditMessage)
|
|
|
+ {
|
|
|
+ List<QwMsgAuditMessage> list = baseMapper.selectQwMsgAuditMessageList(qwMsgAuditMessage);
|
|
|
+// fillContactNameAndQwUserName(list);
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 填充 qw_external_contact.name、qw_user.qw_user_name:<br>
|
|
|
+ * 单聊(无 room_id):按 conversation_key 的 p2p 段拆分参与方,结合可选查询参数 qwUserId 或 wm/wo/wb 前缀区分客户与员工;<br>
|
|
|
+ * 群聊(有 room_id):按 from_user_role + from_user + to_list 解析。
|
|
|
+ */
|
|
|
+// private void fillContactNameAndQwUserName(List<QwMsgAuditMessage> list)
|
|
|
+// {
|
|
|
+// if (list == null || list.isEmpty()) {
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// Map<String, String> qwUserNameCache = new HashMap<>();
|
|
|
+// Map<String, String> contactNameCache = new HashMap<>();
|
|
|
+// String[] salesAndExternal = new String[2];
|
|
|
+// for (QwMsgAuditMessage m : list) {
|
|
|
+// String corpId = m.getCorpId();
|
|
|
+// if (!StringUtils.hasText(corpId)) {
|
|
|
+// continue;
|
|
|
+// }
|
|
|
+// String salesQwUserId = null;
|
|
|
+// String externalUserid = null;
|
|
|
+// boolean isGroup = StringUtils.hasText(m.getRoomId());
|
|
|
+// if (!isGroup) {
|
|
|
+// resolveSingleChatSalesAndExternal(corpId, m.getConversationKey(), m.getQwUserId(), salesAndExternal);
|
|
|
+// salesQwUserId = salesAndExternal[0];
|
|
|
+// externalUserid = salesAndExternal[1];
|
|
|
+// } else {
|
|
|
+// resolveGroupChatSalesAndExternal(m, salesAndExternal);
|
|
|
+// salesQwUserId = salesAndExternal[0];
|
|
|
+// externalUserid = salesAndExternal[1];
|
|
|
+// }
|
|
|
+// if (StringUtils.hasText(salesQwUserId)) {
|
|
|
+// String uk = corpId + "\0" + salesQwUserId;
|
|
|
+// if (!qwUserNameCache.containsKey(uk)) {
|
|
|
+// String n = qwUserMapper.selectQwUserName(salesQwUserId, corpId);
|
|
|
+// qwUserNameCache.put(uk, n != null ? n : "");
|
|
|
+// }
|
|
|
+// String qn = qwUserNameCache.get(uk);
|
|
|
+// if (StringUtils.hasText(qn)) {
|
|
|
+// m.setQwUserName(qn);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// if (StringUtils.hasText(salesQwUserId) && StringUtils.hasText(externalUserid)) {
|
|
|
+// String ck = corpId + "\0" + salesQwUserId + "\0" + externalUserid;
|
|
|
+// if (!contactNameCache.containsKey(ck)) {
|
|
|
+// QwExternalContact ec = qwExternalContactMapper.selectQwExternalContactUserIdAndExternalIdAndCompanyId(
|
|
|
+// externalUserid, salesQwUserId, corpId);
|
|
|
+// contactNameCache.put(ck, ec != null && ec.getName() != null ? ec.getName() : "");
|
|
|
+// }
|
|
|
+// String cn = contactNameCache.get(ck);
|
|
|
+// if (StringUtils.hasText(cn)) {
|
|
|
+// m.setContactName(cn);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// /**
|
|
|
+// * 单聊:从 conversation_key 的 {@code corpId:p2p:} 后拆分参与方 id;优先用请求中的 qwUserId 锁定员工,另一方为外部联系人;
|
|
|
+// * 否则用 wm/wo/wb 前缀识别外部联系人(与入库逻辑一致)。
|
|
|
+// */
|
|
|
+// private static void resolveSingleChatSalesAndExternal(String corpId, String conversationKey, String qwUserIdHint, String[] out)
|
|
|
+// {
|
|
|
+// out[0] = null;
|
|
|
+// out[1] = null;
|
|
|
+// if (conversationKey == null) {
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// String p2p = corpId + ":p2p:";
|
|
|
+// if (!conversationKey.startsWith(p2p)) {
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// String rest = conversationKey.substring(p2p.length());
|
|
|
+// if (rest.isEmpty() || "unknown".equalsIgnoreCase(rest)) {
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// String[] parts = rest.split(":", -1);
|
|
|
+// if (StringUtils.hasText(qwUserIdHint)) {
|
|
|
+// out[0] = qwUserIdHint;
|
|
|
+// for (String part : parts) {
|
|
|
+// if (part != null && !part.isEmpty() && !qwUserIdHint.equals(part)) {
|
|
|
+// out[1] = part;
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// }
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// String ext = null;
|
|
|
+// String nonExt = null;
|
|
|
+// for (String part : parts) {
|
|
|
+// if (part == null || part.isEmpty()) {
|
|
|
+// continue;
|
|
|
+// }
|
|
|
+// if (isExternalWechatId(part)) {
|
|
|
+// ext = part;
|
|
|
+// } else if (nonExt == null) {
|
|
|
+// nonExt = part;
|
|
|
+// }
|
|
|
+// }
|
|
|
+// if (ext != null && nonExt != null) {
|
|
|
+// out[0] = nonExt;
|
|
|
+// out[1] = ext;
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// /**
|
|
|
+// * 群聊:from_user_role=1 时 from 为员工、tolist 中另一参与方为客户;=2 时相反。
|
|
|
+// */
|
|
|
+// private static void resolveGroupChatSalesAndExternal(QwMsgAuditMessage m, String[] out)
|
|
|
+// {
|
|
|
+// out[0] = null;
|
|
|
+// out[1] = null;
|
|
|
+// Integer role = m.getFromUserRole();
|
|
|
+// if (!Integer.valueOf(1).equals(role) && !Integer.valueOf(2).equals(role)) {
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// String from = m.getFromUser();
|
|
|
+// JSONArray tolist = parseToListJson(m.getToList());
|
|
|
+// if (Integer.valueOf(1).equals(role)) {
|
|
|
+// out[0] = from;
|
|
|
+// out[1] = firstOtherInTolist(tolist, from);
|
|
|
+// } else {
|
|
|
+// out[1] = from;
|
|
|
+// out[0] = firstOtherInTolist(tolist, from);
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// /** 与 QwMsgAuditIngestService 一致:wm/wo/wb 视为外部联系人 id */
|
|
|
+// private static boolean isExternalWechatId(String id)
|
|
|
+// {
|
|
|
+// if (id == null || id.length() < 2) {
|
|
|
+// return false;
|
|
|
+// }
|
|
|
+// String prefix = id.substring(0, 2).toLowerCase(Locale.ROOT);
|
|
|
+// return "wm".equals(prefix) || "wo".equals(prefix) || "wb".equals(prefix);
|
|
|
+// }
|
|
|
+//
|
|
|
+// private static JSONArray parseToListJson(String toListJson)
|
|
|
+// {
|
|
|
+// if (!StringUtils.hasText(toListJson)) {
|
|
|
+// return null;
|
|
|
+// }
|
|
|
+// try {
|
|
|
+// return JSON.parseArray(toListJson);
|
|
|
+// } catch (Exception e) {
|
|
|
+// return null;
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// /** tolist 中与发送方不同的第一个 id */
|
|
|
+// private static String firstOtherInTolist(JSONArray arr, String fromUser)
|
|
|
+// {
|
|
|
+// if (arr == null || arr.isEmpty()) {
|
|
|
+// return null;
|
|
|
+// }
|
|
|
+// for (int i = 0; i < arr.size(); i++) {
|
|
|
+// String s = arr.getString(i);
|
|
|
+// if (!StringUtils.hasText(s)) {
|
|
|
+// continue;
|
|
|
+// }
|
|
|
+// if (!s.equals(fromUser)) {
|
|
|
+// return s;
|
|
|
+// }
|
|
|
+// }
|
|
|
+// return null;
|
|
|
+// }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<QwMsgAuditConversationVO> selectConversationList(String corpId, String qwUserId, String chatScope)
|
|
|
+ {
|
|
|
+ if ("group".equalsIgnoreCase(chatScope)) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ if (!StringUtils.hasText(corpId) || !StringUtils.hasText(qwUserId)) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ List<QwMsgAuditConversationDTO> rows = baseMapper.selectSingleConversationList(corpId, qwUserId);
|
|
|
+ List<QwMsgAuditConversationVO> vos = new ArrayList<>(rows.size());
|
|
|
+ for (QwMsgAuditConversationDTO row : rows) {
|
|
|
+ QwMsgAuditConversationVO vo = new QwMsgAuditConversationVO();
|
|
|
+ vo.setConversationKey(row.getConversationKey());
|
|
|
+ vo.setLastMsgTime(row.getLastMsgTime());
|
|
|
+ vo.setRoomId(null);
|
|
|
+ String externalUserid = resolveExternalUseridFromP2pKey(row.getConversationKey(), corpId, qwUserId);
|
|
|
+ if (StringUtils.hasText(externalUserid)) {
|
|
|
+ QwExternalContact ec = qwExternalContactMapper.selectQwExternalContactUserIdAndExternalIdAndCompanyId(externalUserid, qwUserId, corpId);
|
|
|
+ if (ec != null) {
|
|
|
+ vo.setExternalUserId(ec.getExternalUserId());
|
|
|
+ vo.setName(ec.getName());
|
|
|
+ vo.setRemark(ec.getRemark());
|
|
|
+ vo.setAvatar(ec.getAvatar());
|
|
|
+ } else {
|
|
|
+ vo.setExternalUserId(externalUserid);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ vos.add(vo);
|
|
|
+ }
|
|
|
+ return vos;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析出外部联系人id
|
|
|
+ * @param conversationKey 会话key
|
|
|
+ * @param corpId
|
|
|
+ * @param qwUserId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static String resolveExternalUseridFromP2pKey(String conversationKey, String corpId, String qwUserId)
|
|
|
+ {
|
|
|
+ if (!StringUtils.hasText(conversationKey) || !StringUtils.hasText(corpId) || !StringUtils.hasText(qwUserId)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String prefix = corpId + ":p2p:";
|
|
|
+ if (!conversationKey.startsWith(prefix)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String rest = conversationKey.substring(prefix.length());
|
|
|
+ if (rest.isEmpty() || "unknown".equalsIgnoreCase(rest)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String[] parts = rest.split(":", -1);
|
|
|
+ for (String part : parts) {
|
|
|
+ if (part != null && !part.isEmpty() && !qwUserId.equals(part)) {
|
|
|
+ return part;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 新增企微会话存档结构化消息
|
|
|
+ *
|
|
|
+ * @param qwMsgAuditMessage 企微会话存档结构化消息
|
|
|
+ * @return 结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int insertQwMsgAuditMessage(QwMsgAuditMessage qwMsgAuditMessage)
|
|
|
+ {
|
|
|
+ qwMsgAuditMessage.setCreateTime(DateUtils.getNowDate());
|
|
|
+ return baseMapper.insertQwMsgAuditMessage(qwMsgAuditMessage);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 修改企微会话存档结构化消息
|
|
|
+ *
|
|
|
+ * @param qwMsgAuditMessage 企微会话存档结构化消息
|
|
|
+ * @return 结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int updateQwMsgAuditMessage(QwMsgAuditMessage qwMsgAuditMessage)
|
|
|
+ {
|
|
|
+ return baseMapper.updateQwMsgAuditMessage(qwMsgAuditMessage);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量删除企微会话存档结构化消息
|
|
|
+ *
|
|
|
+ * @param ids 需要删除的企微会话存档结构化消息主键
|
|
|
+ * @return 结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int deleteQwMsgAuditMessageByIds(Long[] ids)
|
|
|
+ {
|
|
|
+ return baseMapper.deleteQwMsgAuditMessageByIds(ids);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除企微会话存档结构化消息信息
|
|
|
+ *
|
|
|
+ * @param id 企微会话存档结构化消息主键
|
|
|
+ * @return 结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int deleteQwMsgAuditMessageById(Long id)
|
|
|
+ {
|
|
|
+ return baseMapper.deleteQwMsgAuditMessageById(id);
|
|
|
+ }
|
|
|
+}
|