From 9bf4291586fc7aecc1444e8bdb073793007d099b Mon Sep 17 00:00:00 2001 From: jqb Date: Thu, 13 Aug 2026 10:31:42 +0800 Subject: [PATCH] =?UTF-8?q?feat(archive):=20=E6=94=AF=E6=8C=81=E6=8C=89?= =?UTF-8?q?=E6=9C=80=E8=BF=91=E8=81=8A=E5=A4=A9=E6=97=A5=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E5=8D=95=E8=81=8A=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增参数 fullDay,支持返回最近一个聊天日的全部单聊消息,最大限制1000条 - 重构查询逻辑,先获取最新消息日期,再查询该自然日内消息 - 保留按 limit 参数分页查询,默认最多50条,按 seq 降序排序 - 优化单聊消息的 LambdaQueryWrapper 构建,整合客户和销售老师匹配条件 - 前端调整 SummarySearchApp,客户无每日总结时兜底展示最近聊天日的所有单聊消息 - 显示格式改为“日期 当日全部 x 条聊天”,提升用户体验 --- .../controller/ArchiveMessageController.java | 68 +++++++++++++------ frontend/sidebar/src/SummarySearchApp.tsx | 9 ++- 2 files changed, 55 insertions(+), 22 deletions(-) diff --git a/backend/archive-service/src/main/java/com/artedu/archive/controller/ArchiveMessageController.java b/backend/archive-service/src/main/java/com/artedu/archive/controller/ArchiveMessageController.java index c2a885b..538bd83 100644 --- a/backend/archive-service/src/main/java/com/artedu/archive/controller/ArchiveMessageController.java +++ b/backend/archive-service/src/main/java/com/artedu/archive/controller/ArchiveMessageController.java @@ -27,6 +27,7 @@ import org.springframework.web.bind.annotation.*; import java.io.File; import java.nio.file.Files; import java.time.Instant; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; @@ -382,20 +383,57 @@ public class ArchiveMessageController { * @param customerId 客户企微外部联系人 userid * @param staffId 销售老师企微 userId,传入则只查该老师与客户的单聊,否则查与客户的所有单聊 * @param limit 最多返回条数,默认 10,上限 50 + * @param fullDay 为 true 时返回最近一个聊天日(最新一条消息所在自然日,Asia/Shanghai)的全部单聊消息,上限 1000 条 * @return 消息列表,按 seq 倒序(最新在前) */ @GetMapping("/messages/recent-chat") public Result> recentChat( @RequestParam String customerId, @RequestParam(required = false) String staffId, - @RequestParam(defaultValue = "10") Integer limit) { + @RequestParam(defaultValue = "10") Integer limit, + @RequestParam(defaultValue = "false") Boolean fullDay) { if (customerId.trim().isEmpty()) { return Result.fail("customerId 不能为空"); } - int max = Math.min(Math.max(limit, 1), 50); String c = customerId.trim(); + LambdaQueryWrapper wrapper = buildSingleChatWrapper(c, staffId); + + if (Boolean.TRUE.equals(fullDay)) { + // 先取最新一条消息的时间,确定“当日”,再返回该自然日内的全部单聊消息 + LambdaQueryWrapper latestWrapper = buildSingleChatWrapper(c, staffId); + latestWrapper.orderByDesc(ArchiveMessage::getSeq); + latestWrapper.last("LIMIT 1"); + ArchiveMessage latest = archiveMessageMapper.selectOne(latestWrapper); + if (latest == null || latest.getMsgtime() == null) { + return Result.success(new java.util.ArrayList<>()); + } + ZoneId zone = ZoneId.of("Asia/Shanghai"); + LocalDate day = Instant.ofEpochMilli(latest.getMsgtime()).atZone(zone).toLocalDate(); + long dayStart = day.atStartOfDay(zone).toInstant().toEpochMilli(); + long dayEnd = day.plusDays(1).atStartOfDay(zone).toInstant().toEpochMilli(); + wrapper.ge(ArchiveMessage::getMsgtime, dayStart); + wrapper.lt(ArchiveMessage::getMsgtime, dayEnd); + wrapper.orderByDesc(ArchiveMessage::getSeq); + wrapper.last("LIMIT 1000"); + } else { + int max = Math.min(Math.max(limit, 1), 50); + wrapper.orderByDesc(ArchiveMessage::getSeq); + wrapper.last("LIMIT " + max); + } + + List messages = archiveMessageMapper.selectList(wrapper); + List list = messages.stream().map(this::toVO).collect(Collectors.toList()); + // 补充发送人/接收人昵称(客户昵称、销售老师名称) + enrichSenderNames(list); + return Result.success(list); + } + + /** + * 构建客户单聊消息的基础查询条件(corpId + 单聊 + 客户匹配) + */ + private LambdaQueryWrapper buildSingleChatWrapper(String customerId, String staffId) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(ArchiveMessage::getCorpId, corpId); // 只查单聊,排除群消息 @@ -405,29 +443,21 @@ public class ArchiveMessageController { if (staffId != null && !staffId.trim().isEmpty()) { String s = staffId.trim(); wrapper.and(w -> w - .and(a -> a.eq(ArchiveMessage::getFromUser, c) + .and(a -> a.eq(ArchiveMessage::getFromUser, customerId) .and(b -> b.eq(ArchiveMessage::getToUser, s) .or().like(ArchiveMessage::getToUser, "\"" + s + "\"") .or().like(ArchiveMessage::getTolist, "\"" + s + "\""))) .or(a -> a.eq(ArchiveMessage::getFromUser, s) - .and(b -> b.eq(ArchiveMessage::getToUser, c) - .or().like(ArchiveMessage::getToUser, "\"" + c + "\"") - .or().like(ArchiveMessage::getTolist, "\"" + c + "\"")))); + .and(b -> b.eq(ArchiveMessage::getToUser, customerId) + .or().like(ArchiveMessage::getToUser, "\"" + customerId + "\"") + .or().like(ArchiveMessage::getTolist, "\"" + customerId + "\"")))); } else { - wrapper.and(w -> w.eq(ArchiveMessage::getFromUser, c) - .or().eq(ArchiveMessage::getToUser, c) - .or().like(ArchiveMessage::getToUser, "\"" + c + "\"") - .or().like(ArchiveMessage::getTolist, "\"" + c + "\"")); + wrapper.and(w -> w.eq(ArchiveMessage::getFromUser, customerId) + .or().eq(ArchiveMessage::getToUser, customerId) + .or().like(ArchiveMessage::getToUser, "\"" + customerId + "\"") + .or().like(ArchiveMessage::getTolist, "\"" + customerId + "\"")); } - - wrapper.orderByDesc(ArchiveMessage::getSeq); - wrapper.last("LIMIT " + max); - - List messages = archiveMessageMapper.selectList(wrapper); - List list = messages.stream().map(this::toVO).collect(Collectors.toList()); - // 补充发送人/接收人昵称(客户昵称、销售老师名称) - enrichSenderNames(list); - return Result.success(list); + return wrapper; } /** diff --git a/frontend/sidebar/src/SummarySearchApp.tsx b/frontend/sidebar/src/SummarySearchApp.tsx index 1f48e89..00ff151 100644 --- a/frontend/sidebar/src/SummarySearchApp.tsx +++ b/frontend/sidebar/src/SummarySearchApp.tsx @@ -240,7 +240,7 @@ function SummarySearchApp() { export default SummarySearchApp /** - * 客户暂无每日总结时的兜底:加载最近 10 条单聊消息 + * 客户暂无每日总结时的兜底:加载最近一个聊天日的全部单聊消息 */ function RecentChatFallback({ customerId }: { customerId: string }) { const [chatMessages, setChatMessages] = useState(null) @@ -253,7 +253,7 @@ function RecentChatFallback({ customerId }: { customerId: string }) { const load = async () => { try { const res = await noCacheFetch( - `/api/v1/archive/messages/recent-chat?customerId=${encodeURIComponent(customerId)}&limit=10` + `/api/v1/archive/messages/recent-chat?customerId=${encodeURIComponent(customerId)}&fullDay=true` ) const data = await res.json() setChatMessages(data.code === 0 && Array.isArray(data.data) ? data.data : []) @@ -277,6 +277,9 @@ function RecentChatFallback({ customerId }: { customerId: string }) { return } + // 接口按 seq 倒序返回,第一条即最新一条,取其日期作为“当日” + const chatDay = chatMessages.length > 0 ? (chatMessages[0].msgTimeStr || '').slice(0, 10) : '' + return ( <>
- 暂无每日总结,展示最近 {chatMessages.length} 条聊天 + 暂无每日总结,展示 {chatDay} 当日全部 {chatMessages.length} 条聊天