feat(archive): 支持按最近聊天日加载客户单聊消息
- 新增参数 fullDay,支持返回最近一个聊天日的全部单聊消息,最大限制1000条 - 重构查询逻辑,先获取最新消息日期,再查询该自然日内消息 - 保留按 limit 参数分页查询,默认最多50条,按 seq 降序排序 - 优化单聊消息的 LambdaQueryWrapper 构建,整合客户和销售老师匹配条件 - 前端调整 SummarySearchApp,客户无每日总结时兜底展示最近聊天日的所有单聊消息 - 显示格式改为“日期 当日全部 x 条聊天”,提升用户体验
This commit is contained in:
parent
7722c4e7e3
commit
9bf4291586
@ -27,6 +27,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
@ -382,20 +383,57 @@ public class ArchiveMessageController {
|
|||||||
* @param customerId 客户企微外部联系人 userid
|
* @param customerId 客户企微外部联系人 userid
|
||||||
* @param staffId 销售老师企微 userId,传入则只查该老师与客户的单聊,否则查与客户的所有单聊
|
* @param staffId 销售老师企微 userId,传入则只查该老师与客户的单聊,否则查与客户的所有单聊
|
||||||
* @param limit 最多返回条数,默认 10,上限 50
|
* @param limit 最多返回条数,默认 10,上限 50
|
||||||
|
* @param fullDay 为 true 时返回最近一个聊天日(最新一条消息所在自然日,Asia/Shanghai)的全部单聊消息,上限 1000 条
|
||||||
* @return 消息列表,按 seq 倒序(最新在前)
|
* @return 消息列表,按 seq 倒序(最新在前)
|
||||||
*/
|
*/
|
||||||
@GetMapping("/messages/recent-chat")
|
@GetMapping("/messages/recent-chat")
|
||||||
public Result<List<ArchiveMessageVO>> recentChat(
|
public Result<List<ArchiveMessageVO>> recentChat(
|
||||||
@RequestParam String customerId,
|
@RequestParam String customerId,
|
||||||
@RequestParam(required = false) String staffId,
|
@RequestParam(required = false) String staffId,
|
||||||
@RequestParam(defaultValue = "10") Integer limit) {
|
@RequestParam(defaultValue = "10") Integer limit,
|
||||||
|
@RequestParam(defaultValue = "false") Boolean fullDay) {
|
||||||
|
|
||||||
if (customerId.trim().isEmpty()) {
|
if (customerId.trim().isEmpty()) {
|
||||||
return Result.fail("customerId 不能为空");
|
return Result.fail("customerId 不能为空");
|
||||||
}
|
}
|
||||||
int max = Math.min(Math.max(limit, 1), 50);
|
|
||||||
String c = customerId.trim();
|
String c = customerId.trim();
|
||||||
|
|
||||||
|
LambdaQueryWrapper<ArchiveMessage> wrapper = buildSingleChatWrapper(c, staffId);
|
||||||
|
|
||||||
|
if (Boolean.TRUE.equals(fullDay)) {
|
||||||
|
// 先取最新一条消息的时间,确定“当日”,再返回该自然日内的全部单聊消息
|
||||||
|
LambdaQueryWrapper<ArchiveMessage> 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<ArchiveMessage> messages = archiveMessageMapper.selectList(wrapper);
|
||||||
|
List<ArchiveMessageVO> list = messages.stream().map(this::toVO).collect(Collectors.toList());
|
||||||
|
// 补充发送人/接收人昵称(客户昵称、销售老师名称)
|
||||||
|
enrichSenderNames(list);
|
||||||
|
return Result.success(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建客户单聊消息的基础查询条件(corpId + 单聊 + 客户匹配)
|
||||||
|
*/
|
||||||
|
private LambdaQueryWrapper<ArchiveMessage> buildSingleChatWrapper(String customerId, String staffId) {
|
||||||
LambdaQueryWrapper<ArchiveMessage> wrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<ArchiveMessage> wrapper = new LambdaQueryWrapper<>();
|
||||||
wrapper.eq(ArchiveMessage::getCorpId, corpId);
|
wrapper.eq(ArchiveMessage::getCorpId, corpId);
|
||||||
// 只查单聊,排除群消息
|
// 只查单聊,排除群消息
|
||||||
@ -405,29 +443,21 @@ public class ArchiveMessageController {
|
|||||||
if (staffId != null && !staffId.trim().isEmpty()) {
|
if (staffId != null && !staffId.trim().isEmpty()) {
|
||||||
String s = staffId.trim();
|
String s = staffId.trim();
|
||||||
wrapper.and(w -> w
|
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)
|
.and(b -> b.eq(ArchiveMessage::getToUser, s)
|
||||||
.or().like(ArchiveMessage::getToUser, "\"" + s + "\"")
|
.or().like(ArchiveMessage::getToUser, "\"" + s + "\"")
|
||||||
.or().like(ArchiveMessage::getTolist, "\"" + s + "\"")))
|
.or().like(ArchiveMessage::getTolist, "\"" + s + "\"")))
|
||||||
.or(a -> a.eq(ArchiveMessage::getFromUser, s)
|
.or(a -> a.eq(ArchiveMessage::getFromUser, s)
|
||||||
.and(b -> b.eq(ArchiveMessage::getToUser, c)
|
.and(b -> b.eq(ArchiveMessage::getToUser, customerId)
|
||||||
.or().like(ArchiveMessage::getToUser, "\"" + c + "\"")
|
.or().like(ArchiveMessage::getToUser, "\"" + customerId + "\"")
|
||||||
.or().like(ArchiveMessage::getTolist, "\"" + c + "\""))));
|
.or().like(ArchiveMessage::getTolist, "\"" + customerId + "\""))));
|
||||||
} else {
|
} else {
|
||||||
wrapper.and(w -> w.eq(ArchiveMessage::getFromUser, c)
|
wrapper.and(w -> w.eq(ArchiveMessage::getFromUser, customerId)
|
||||||
.or().eq(ArchiveMessage::getToUser, c)
|
.or().eq(ArchiveMessage::getToUser, customerId)
|
||||||
.or().like(ArchiveMessage::getToUser, "\"" + c + "\"")
|
.or().like(ArchiveMessage::getToUser, "\"" + customerId + "\"")
|
||||||
.or().like(ArchiveMessage::getTolist, "\"" + c + "\""));
|
.or().like(ArchiveMessage::getTolist, "\"" + customerId + "\""));
|
||||||
}
|
}
|
||||||
|
return wrapper;
|
||||||
wrapper.orderByDesc(ArchiveMessage::getSeq);
|
|
||||||
wrapper.last("LIMIT " + max);
|
|
||||||
|
|
||||||
List<ArchiveMessage> messages = archiveMessageMapper.selectList(wrapper);
|
|
||||||
List<ArchiveMessageVO> list = messages.stream().map(this::toVO).collect(Collectors.toList());
|
|
||||||
// 补充发送人/接收人昵称(客户昵称、销售老师名称)
|
|
||||||
enrichSenderNames(list);
|
|
||||||
return Result.success(list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -240,7 +240,7 @@ function SummarySearchApp() {
|
|||||||
export default SummarySearchApp
|
export default SummarySearchApp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户暂无每日总结时的兜底:加载最近 10 条单聊消息
|
* 客户暂无每日总结时的兜底:加载最近一个聊天日的全部单聊消息
|
||||||
*/
|
*/
|
||||||
function RecentChatFallback({ customerId }: { customerId: string }) {
|
function RecentChatFallback({ customerId }: { customerId: string }) {
|
||||||
const [chatMessages, setChatMessages] = useState<ChatMessage[] | null>(null)
|
const [chatMessages, setChatMessages] = useState<ChatMessage[] | null>(null)
|
||||||
@ -253,7 +253,7 @@ function RecentChatFallback({ customerId }: { customerId: string }) {
|
|||||||
const load = async () => {
|
const load = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await noCacheFetch(
|
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()
|
const data = await res.json()
|
||||||
setChatMessages(data.code === 0 && Array.isArray(data.data) ? data.data : [])
|
setChatMessages(data.code === 0 && Array.isArray(data.data) ? data.data : [])
|
||||||
@ -277,6 +277,9 @@ function RecentChatFallback({ customerId }: { customerId: string }) {
|
|||||||
return <Empty description="该客户暂无每日总结" style={{ padding: 24 }} />
|
return <Empty description="该客户暂无每日总结" style={{ padding: 24 }} />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 接口按 seq 倒序返回,第一条即最新一条,取其日期作为“当日”
|
||||||
|
const chatDay = chatMessages.length > 0 ? (chatMessages[0].msgTimeStr || '').slice(0, 10) : ''
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div style={{
|
<div style={{
|
||||||
@ -288,7 +291,7 @@ function RecentChatFallback({ customerId }: { customerId: string }) {
|
|||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
color: '#999'
|
color: '#999'
|
||||||
}}>
|
}}>
|
||||||
暂无每日总结,展示最近 {chatMessages.length} 条聊天
|
暂无每日总结,展示 {chatDay} 当日全部 {chatMessages.length} 条聊天
|
||||||
</div>
|
</div>
|
||||||
<ChatMessageList messages={chatMessages} />
|
<ChatMessageList messages={chatMessages} />
|
||||||
</>
|
</>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user