优化消息列表组件,新增消息内容展示,调整消息时间格式处理逻辑,更新获取消息列表的API以支持分页,提升用户体验和代码可读性。
This commit is contained in:
@@ -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 />}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
//获取客服列表
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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风格
|
||||
|
||||
Reference in New Issue
Block a user