Files
hgmj_h5/src/utils/im/sessionList.ts
T
谢宇宁 eada71e211 [Human] chore(project): 初始化导入 91dj H5 客户端项目代码
从本地工程首次入库;.npmrc(含私有 npm 源 token)与 tsbuildinfo 已加入 .gitignore,不随仓库提交。
2026-10-08 14:22:35 +07:00

128 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { needsImageDecrypt, parseImageExtra, toBusinessImagePath } from '@/utils/im/message';
/** 消息中心私信列表的一行数据(纯 SDK 会话映射) */
export type PrivateSessionItem = {
id: string;
/** 业务 uid;列表由 SDK 驱动时为 0,进会话前用 /im/user-id 反查 */
userId: number;
/** 对端 IM userId(= conv.receiverId) */
friendImUserId: number;
userName: string;
userAvatar: string;
preContent: string;
createdAt: string | number;
noReadNum: number;
};
/** SDK conversation.subscribeList 推送的会话结构 */
export type SdkConversation = {
type?: string;
receiverId?: number | string;
unreadCount?: number;
extra?: string;
lastMessageTime?: number;
updatedAt?: number;
createdAt?: number;
content?: string;
chatMessageType?: string | number;
user?: {
id?: number;
nickName?: string;
nickname?: string;
name?: string;
avatar?: string;
portrait?: string;
imgUrl?: string;
};
remark?: string;
};
// —— 展示文案 ——
/** blob/data 本地地址、http(s) 公网图无需再走 imgDecypt */
export function isPublicImageUrl(url?: string): boolean {
return !needsImageDecrypt(url);
}
export function formatSessionPreview(content?: string): string {
const text = (content || '').trim();
if (!text) return '暂无消息';
if (/^\[图片\]|^图片$|image/i.test(text)) return '[图片]';
return text;
}
export function formatSessionListTime(date: string | number): string {
if (date == null || date === '') return '';
const d = typeof date === 'number' ? new Date(date) : new Date(date);
if (Number.isNaN(d.getTime()) || d.getFullYear() === 1) return '';
return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;
}
export function buildMessagePreview(msg: {
content?: string;
chatMessageType?: string | number;
extra?: unknown;
}): string {
const type = msg.chatMessageType;
if (type === 'IMAGE' || type === 2 || parseImageExtra(msg.extra)) return '[图片]';
return (msg.content || '').trim() || '暂无消息';
}
// —— SDK 会话 → 列表行 ——
function toTimestamp(value: string | number | undefined): number {
if (value == null || value === '') return 0;
const ts = typeof value === 'number' ? value : new Date(value).getTime();
return Number.isFinite(ts) ? ts : 0;
}
function isDirectConversation(conv: SdkConversation): boolean {
if (conv.type && conv.type !== 'direct') return false;
const imId = Number(conv.receiverId);
return Number.isFinite(imId) && imId > 0;
}
/** IM 快照偶发幽灵会话(user 资料整体缺失),无法渲染也无法跳转,不展示 */
function hasUserProfile(conv: SdkConversation): boolean {
const user = conv.user;
return !!(user?.nickName || user?.nickname || user?.name || user?.avatar || user?.portrait || user?.imgUrl);
}
function toSessionItem(conv: SdkConversation): PrivateSessionItem {
const imId = Number(conv.receiverId);
const user = conv.user;
return {
id: String(imId),
userId: 0,
friendImUserId: imId,
userName: user?.nickName || user?.nickname || user?.name || conv.remark || '',
userAvatar: toBusinessImagePath(user?.avatar || user?.portrait || user?.imgUrl || ''),
preContent: parseImageExtra(conv.extra)
? '[图片]'
: buildMessagePreview({
content: conv.content,
chatMessageType: conv.chatMessageType,
extra: conv.extra,
}),
createdAt: conv.lastMessageTime ?? conv.updatedAt ?? conv.createdAt ?? '',
noReadNum: Number(conv.unreadCount ?? 0),
};
}
/** SDK 会话快照 → 私信列表(仅单聊;按最后消息时间倒序) */
export function mapSdkConversations(conversations: SdkConversation[]): PrivateSessionItem[] {
const seen = new Set<number>();
const list: PrivateSessionItem[] = [];
for (const conv of conversations) {
if (!isDirectConversation(conv) || !hasUserProfile(conv)) continue;
const imId = Number(conv.receiverId);
if (seen.has(imId)) continue;
seen.add(imId);
list.push(toSessionItem(conv));
}
return list.sort((a, b) => toTimestamp(b.createdAt) - toTimestamp(a.createdAt));
}