feat(im): 通话事件接入会话列表预览(私聊补 START 入消息流);文案统一「语音通话」

im
YunaiV 2026-05-17 22:26:07 +08:00
parent 6cd49f0ce4
commit dc318c8e75
2 changed files with 43 additions and 18 deletions

View File

@ -6,7 +6,7 @@
// 2. fallbackName 由调用方传入典型来源Conversation.lastSenderDisplayName 快照),透传到 getSenderDisplayName 内部,算不出真名时兜底 // 2. fallbackName 由调用方传入典型来源Conversation.lastSenderDisplayName 快照),透传到 getSenderDisplayName 内部,算不出真名时兜底
// ==================================================================== // ====================================================================
import { ImConversationType, ImMessageType, isFriendChatTip, isGroupNotification } from './constants' import { ImConversationType, ImMessageType, isFriendChatTip, isGroupNotification, isRtcCallTip } from './constants'
import { import {
getCardLabelInfo, getCardLabelInfo,
parseMessage, parseMessage,
@ -20,7 +20,7 @@ import {
type TipSegment type TipSegment
} from './message' } from './message'
import { getSenderDisplayName } from './user' import { getSenderDisplayName } from './user'
import { resolveFriendNotificationText, resolveGroupNotificationText } from './message' import { resolveFriendNotificationText, resolveGroupNotificationText, resolveRtcCallLastContent } from './message'
import type { Message } from '../home/types' import type { Message } from '../home/types'
/** 会话主键:`type-targetId` 拼成稳定字符串,给 v-for :key、active 比对、map key 等场景共用 */ /** 会话主键:`type-targetId` 拼成稳定字符串,给 v-for :key、active 比对、map key 等场景共用 */
@ -152,5 +152,8 @@ export function resolveConversationLastContent(
getSenderDisplayName(id, ImConversationType.GROUP, message.targetId ?? 0) getSenderDisplayName(id, ImConversationType.GROUP, message.targetId ?? 0)
) )
} }
if (isRtcCallTip(message.type)) {
return resolveRtcCallLastContent(message, conversationType)
}
return summarizeMessageContent(message) return summarizeMessageContent(message)
} }

View File

@ -1,6 +1,5 @@
import { generateUUID } from '@/utils' import { generateUUID } from '@/utils'
import { useUserStore } from '@/store/modules/user' import { useUserStore } from '@/store/modules/user'
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
import { import {
ImRtcCallEndReason, ImRtcCallEndReason,
ImConversationType, ImConversationType,
@ -105,10 +104,7 @@ const URL_MIN_LENGTH = 6
* *
* mentions @xxx 退 text store * mentions @xxx 退 text store
*/ */
export function parseTextSegments( export function parseTextSegments(text: string, mentions: MentionCandidate[] = []): TipSegment[] {
text: string,
mentions: MentionCandidate[] = []
): TipSegment[] {
if (!text) { if (!text) {
return [] return []
} }
@ -712,9 +708,7 @@ export function resolveGroupNotificationSegments(
// ENTER 主语是 entrant 而非 operator独立处理其它 case 都以 operatorUserId 为主语 // ENTER 主语是 entrant 而非 operator独立处理其它 case 都以 operatorUserId 为主语
if (message.type === ImMessageType.GROUP_MEMBER_ENTER) { if (message.type === ImMessageType.GROUP_MEMBER_ENTER) {
const entrantId = payload.entrantUserId ?? payload.operatorUserId const entrantId = payload.entrantUserId ?? payload.operatorUserId
return entrantId return entrantId ? [tipMention(entrantId, resolveName(entrantId)), tipText(' 加入了群聊')] : []
? [tipMention(entrantId, resolveName(entrantId)), tipText(' 加入了群聊')]
: []
} }
if (!payload.operatorUserId) { if (!payload.operatorUserId) {
return [] return []
@ -855,7 +849,7 @@ export function parseRtcCallPayload(
/** /**
* segmentsRTC_CALL_START / RTC_CALL_END * segmentsRTC_CALL_START / RTC_CALL_END
* <p> * <p>
* START{inviter} {voice/video}+ END{voice/video} [ X] * START{inviter} + END
* <p> * <p>
* {@link resolveRtcCallPrivateBubbleText} * {@link resolveRtcCallPrivateBubbleText}
*/ */
@ -868,20 +862,48 @@ export function resolveRtcCallTipSegments(message: {
if (!payload) { if (!payload) {
return [] return []
} }
const media = getDictLabel(DICT_TYPE.IM_RTC_CALL_MEDIA_TYPE, payload.mediaType)
if (message.type === ImMessageType.RTC_CALL_START) { if (message.type === ImMessageType.RTC_CALL_START) {
const inviter = payload.inviterNickname?.trim() || `用户 ${payload.inviterUserId ?? ''}` return payload.inviterUserId
return [tipText(`${inviter} 发起了${media}通话`)] ? [tipMention(payload.inviterUserId, resolveRtcInviterLabel(payload)), tipText(' 发起了语音通话')]
: []
} }
if (message.type === ImMessageType.RTC_CALL_END) { if (message.type === ImMessageType.RTC_CALL_END) {
if (payload.durationSeconds && payload.durationSeconds > 0) { return [tipText('语音通话已经结束')]
return [tipText(`${media}通话已结束(时长 ${formatCallDuration(payload.durationSeconds)}`)]
}
return [tipText(`${media}通话已结束`)]
} }
return [] return []
} }
/** 取 RTC 通话发起人展示名;昵称为空时回退「用户 {id}」 */
function resolveRtcInviterLabel(payload: RtcCallStartPayload): string {
return payload.inviterNickname?.trim() || `用户 ${payload.inviterUserId ?? ''}`
}
/**
* RTC_CALL_START / RTC_CALL_END
* <p>
* START / END [] [] / []
* <p>
* START{inviter} END tip
*/
export function resolveRtcCallLastContent(
message: { type?: number; content?: string },
conversationType: number
): string {
if (conversationType === ImConversationType.PRIVATE) {
return '[语音通话]'
}
if (message.type === ImMessageType.RTC_CALL_END) {
return '语音通话已经结束'
}
if (message.type === ImMessageType.RTC_CALL_START) {
const payload = parseRtcCallPayload(message.content)
if (payload) {
return `${resolveRtcInviterLabel(payload)} 发起了语音通话`
}
}
return ''
}
/** /**
* RTC_CALL_END operatorUserId * RTC_CALL_END operatorUserId
* <p> * <p>