优化消息列表组件,新增消息内容展示,调整消息时间格式处理逻辑,更新获取消息列表的API以支持分页,提升用户体验和代码可读性。

This commit is contained in:
超级老白兔
2025-10-22 15:28:03 +08:00
parent 17e81cafc2
commit 5b9ae2b805
7 changed files with 142 additions and 134 deletions

View File

@@ -217,10 +217,7 @@ const NavCommon: React.FC<NavCommonProps> = ({ title = "触客宝" }) => {
icon={<BarChartOutlined style={{ fontSize: 18 }} />}
type="primary"
onClick={handleMenuClick}
>
{isWeChat() ? "功能中心" : "Ai智能客服"}
<RetweetOutlined style={{ fontSize: 18 }} />
</Button>
></Button>
<Button
icon={<CalendarOutlined />}

View File

@@ -58,8 +58,8 @@ export function getLabelsListByGroup(params) {
// }
//群、好友聊天记录列表
export function getMessageList() {
return request("/v1/kefu/message/list", {}, "GET");
export function getMessageList(params: { page: number; limit: number }) {
return request("/v1/kefu/message/list", params, "GET");
}
//获取客服列表

View File

@@ -76,51 +76,11 @@
}
.messageContent {
display: flex;
justify-content: space-between;
align-items: center;
.lastMessage {
font-size: 12px;
color: #8c8c8c;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
position: relative;
padding-right: 5px;
height: 18px; // 添加固定高度
line-height: 18px; // 设置行高与高度一致
&::before {
content: attr(data-count);
position: absolute;
right: -5px;
top: 0;
background-color: #ff4d4f;
color: white;
border-radius: 10px;
padding: 0 6px;
font-size: 10px;
line-height: 16px;
min-width: 16px;
height: 16px;
text-align: center;
display: none;
}
&[data-count]:not([data-count=""]):not([data-count="0"]) {
&::before {
display: inline-block;
}
}
}
.onlineIndicator {
font-size: 10px;
color: #52c41a;
flex-shrink: 0;
margin-left: 8px;
}
font-size: 12px;
color: #888;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}

View File

@@ -278,6 +278,7 @@ const MessageList: React.FC<MessageListProps> = () => {
{formatWechatTime(session?.lastUpdateTime)}
</div>
</div>
<div className={styles.messageContent}>{session.content}</div>
</div>
</div>
</List.Item>

View File

@@ -13,7 +13,6 @@ import { useUserStore } from "@/store/module/user";
import { weChatGroupService, contractService } from "@/utils/db";
import {
loginWithToken,
getControlTerminalList,
getContactList,
getGroupList,
@@ -28,7 +27,6 @@ import {
weChatGroup,
} from "@/pages/pc/ckbox/data";
const { login2 } = useUserStore.getState();
//获取触客宝基础信息
export const chatInitAPIdata = async () => {
try {
@@ -64,60 +62,51 @@ export const chatInitAPIdata = async () => {
const countLables = await getCountLables();
await asyncCountLables(countLables);
//获取消息会话列表并按lastUpdateTime排序
const filterUserSessions = contractList?.filter(
v => v?.config && v.config?.chat,
);
const filterGroupSessions = groupList?.filter(
v => v?.config && v.config?.chat,
);
// 获取显示名称的辅助函数(优先 conRemark其次 nickname
const getDisplayName = (session: any) => {
return session.conRemark || session.nickname || "";
};
const messageList = await getMessageList();
console.log(messageList);
const messageList = await getAllMessageList();
//排序功能
const sortedSessions = [...filterUserSessions, ...filterGroupSessions].sort(
(a, b) => {
// 获取置顶状态
const aTop = a.config?.top || false;
const bTop = b.config?.top || false;
const sortedSessions = messageList.sort((a, b) => {
// 获取置顶状态
const aTop = a.config?.top || false;
const bTop = b.config?.top || false;
// 首先按置顶状态排序(置顶的排在前面)
if (aTop !== bTop) {
return aTop ? -1 : 1;
}
// 首先按置顶状态排序(置顶的排在前面)
if (aTop !== bTop) {
return aTop ? -1 : 1;
}
// 如果都是置顶或都不是置顶,则按未读消息数量降序排列(未读消息多的排在前面)
const aUnread = a.config?.unreadCount || 0;
const bUnread = b.config?.unreadCount || 0;
// 如果都是置顶或都不是置顶,则按未读消息数量降序排列(未读消息多的排在前面)
const aUnread = a.config?.unreadCount || 0;
const bUnread = b.config?.unreadCount || 0;
if (aUnread !== bUnread) {
return bUnread - aUnread;
}
if (aUnread !== bUnread) {
return bUnread - aUnread;
}
// 如果未读消息数量相同,则按显示名称排序(字母排序)
const aName = getDisplayName(a).toLowerCase();
const bName = getDisplayName(b).toLowerCase();
// 如果未读消息数量相同,则按显示名称排序(字母排序)
const aName = getDisplayName(a).toLowerCase();
const bName = getDisplayName(b).toLowerCase();
if (aName !== bName) {
return aName.localeCompare(bName, "zh-CN");
}
if (aName !== bName) {
return aName.localeCompare(bName, "zh-CN");
}
// 如果名称也相同,则按时间降序排列(最新的在前面)
// 如果lastUpdateTime不存在则将其排在最后
if (!a.lastUpdateTime) return 1;
if (!b.lastUpdateTime) return -1;
// 如果名称也相同,则按时间降序排列(最新的在前面)
// 如果lastUpdateTime不存在则将其排在最后
if (!a.lastUpdateTime) return 1;
if (!b.lastUpdateTime) return -1;
const timeCompare =
new Date(b.lastUpdateTime).getTime() -
new Date(a.lastUpdateTime).getTime();
const timeCompare =
new Date(b.lastUpdateTime).getTime() -
new Date(a.lastUpdateTime).getTime();
return timeCompare;
},
);
return timeCompare;
});
//会话数据同步
asyncChatSessions(sortedSessions);
@@ -131,6 +120,46 @@ export const chatInitAPIdata = async () => {
return [];
}
};
// 递归获取所有联系人列表
export const getAllMessageList = async () => {
try {
let allMessages = [];
let page = 1;
const limit = 500;
let hasMore = true;
while (hasMore) {
const Result = await getMessageList({
page,
limit,
});
const messageList = Result;
if (
!messageList ||
!Array.isArray(messageList) ||
messageList.length === 0
) {
hasMore = false;
break;
}
allMessages = [...allMessages, ...messageList];
// 如果返回的数据少于请求的数量,说明已经没有更多数据了
if (messageList.length == 0) {
hasMore = false;
} else {
page = page + 1;
}
}
return allMessages;
} catch (error) {
console.error("获取所有联系人列表失败:", error);
return [];
}
};
//发起soket连接
export const initSocket = () => {
// 从store获取token和accountId

View File

@@ -19,7 +19,7 @@ export const createContractList = async (
const dataByLabels = [];
for (const label of countLables) {
let data;
if (label.groupType === 1) {
if (Number(label.groupType) === 1) {
if (label.id == 0) {
data = await contractService.findWhereMultiple([
{
@@ -36,7 +36,7 @@ export const createContractList = async (
data = data.filter(contact => contact.wechatAccountId === kfSelected);
}
// console.log(`标签 ${label.groupName} 对应的联系人数据:`, data);
} else if (label.groupType === 2) {
} else if (Number(label.groupType) === 2) {
// groupType: 2, 查询 weChatGroupService
if (label.id == 0) {
data = await weChatGroupService.findWhereMultiple([

View File

@@ -1,55 +1,76 @@
import { Modal } from "antd-mobile";
import { getSetting } from "@/store/module/settings";
export function formatWechatTime(timestamp) {
if (!timestamp) {
import dayjs from "dayjs";
export function formatWechatTime(lastUpdateTime: string) {
if (!lastUpdateTime) {
return "";
}
// 处理时间戳(兼容秒级/毫秒级)
const date = new Date(
timestamp.toString().length === 10 ? timestamp * 1000 : timestamp,
);
const now = new Date();
// 获取消息时间的年月日时分
const messageYear = date.getFullYear();
const messageMonth = date.getMonth();
const messageDate = date.getDate();
const messageHour = date.getHours().toString().padStart(2, "0");
const messageMinute = date.getMinutes().toString().padStart(2, "0");
// 使用dayjs解析时间字符串处理"2025-10-22 13:21:13"格式
let messageTime;
try {
// 直接解析时间字符串dayjs可以自动识别这种格式
messageTime = dayjs(lastUpdateTime);
// 获取当前时间的年月日
const nowYear = now.getFullYear();
const nowMonth = now.getMonth();
const nowDate = now.getDate();
// 创建当天0点的时间对象用于比较是否同一天
const today = new Date(nowYear, nowMonth, nowDate, 0, 0, 0);
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
const weekAgo = new Date(today);
weekAgo.setDate(weekAgo.getDate() - 6); // 7天前包括今天
// 消息日期(不含时间)
const messageDay = new Date(messageYear, messageMonth, messageDate, 0, 0, 0);
// 当天消息:只显示时分
if (messageDay.getTime() === today.getTime()) {
return `${messageHour}:${messageMinute}`;
// 检查日期是否有效
if (!messageTime.isValid()) {
console.warn("formatWechatTime: Invalid date string", lastUpdateTime);
return "";
}
} catch (error) {
console.error(
"formatWechatTime: Error processing date string",
lastUpdateTime,
error,
);
return "";
}
// 昨天消息:显示"昨天 时分"
if (messageDay.getTime() === yesterday.getTime()) {
return `昨天 ${messageHour}:${messageMinute}`;
const now = dayjs();
// 获取消息时间和当前时间的年份
const messageYear = messageTime.year();
const nowYear = now.year();
// 如果是去年或更早的时间,直接返回空字符串
if (messageYear < nowYear) {
return "";
}
// 一周内消息:显示"星期X 时分"
if (messageDay.getTime() >= weekAgo.getTime()) {
// 创建时间比较对象
const today = now.startOf("day");
const yesterday = today.subtract(1, "day");
const messageDay = messageTime.startOf("day");
// 1. 时间是否今天,如果是就展示时和分,示例为: "13:00"
if (messageDay.isSame(today, "day")) {
return messageTime.format("HH:mm");
}
// 2. 时间是否为昨天,如果是就展示"昨天"和时与分,示例为: "昨天 13:00"
if (messageDay.isSame(yesterday, "day")) {
return `昨天 ${messageTime.format("HH:mm")}`;
}
// 3. 时间是否在本周,如果是就展示具体周几,示例为: "周一"
const startOfWeek = now.startOf("week");
const endOfWeek = now.endOf("week");
if (messageTime.isAfter(startOfWeek) && messageTime.isBefore(endOfWeek)) {
const weekdays = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];
return `${weekdays[date.getDay()]} ${messageHour}:${messageMinute}`;
return weekdays[messageTime.day()];
}
// 超过一周:显示"年月日 时分"
return `${messageYear}${messageMonth + 1}${messageDate}${messageHour}:${messageMinute}`;
// 4. 时间是否在本月,如果是就展示月和日,示例为: "12/07"
if (messageTime.isSame(now, "month")) {
return messageTime.format("MM/DD");
}
// 5. 时间是否在本年,如果在本年就展示月和日,示例为: "12/07"
if (messageTime.isSame(now, "year")) {
return messageTime.format("MM/DD");
}
return "";
}
/**
* 通用js调用弹窗Promise风格