fix(im): 对齐群备注展示并修复 IM 消息管理字典
聊天端: - 群 API 类型补充 groupRemark 和 silent - 群列表同步时以接口返回的个人群设置为准,只保留成员缓存 - 会话名写入入口统一使用 getGroupDisplayName,避免群备注被原群名覆盖 - 聊天标题、转发、推荐名片、新建群入口同步群展示名逻辑 - 空群头像且成员未加载时异步预拉群成员,用于合成群头像 - 通讯录和合并消息详情补充滚动容器 - 消息历史日期选择改用 antd Calendar 卡片模式并修正样式 管理端: - IM 字典常量统一为 im_content_type、im_message_status、im_message_receipt_status - 私聊 / 群聊消息列表和详情页切换到统一内容类型、消息状态、回执状态字典 - 私聊消息 API 和详情页补充 receiptStatus - 统计消息类型分布改用内容类型字典pull/367/head
parent
e61d0a5aa2
commit
5a4f8b4e2a
|
|
@ -19,6 +19,8 @@ export namespace ImGroupApi {
|
|||
createTime?: string; // 创建时间
|
||||
pinnedMessages?: ImGroupMessageApi.GroupMessageRespVO[]; // 群置顶消息列表(后端关联回填,仅当登录用户是群成员时非空)
|
||||
joinStatus?: number; // 当前登录用户在该群的成员状态(参见 CommonStatusEnum:0 在群 / 1 已退群);历史退群群仍返回,供展示离线消息的群名 / 头像
|
||||
groupRemark?: string; // 当前登录用户对该群的备注
|
||||
silent?: boolean; // 当前登录用户是否免打扰
|
||||
}
|
||||
|
||||
/** 群消息置顶 / 取消置顶 Request VO */
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export namespace ImManagerPrivateMessageApi {
|
|||
type: number;
|
||||
content: string;
|
||||
status: number;
|
||||
receiptStatus?: number;
|
||||
sendTime: Date;
|
||||
createTime: Date;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { ImContentType, ImConversationType, isGroupConversation } from '../../..
|
|||
import { getConversationKey } from '../../../utils/conversation'
|
||||
import { buildDefaultGroupName } from '../../../utils/group'
|
||||
import { type CardTarget, serializeMessage } from '../../../utils/message'
|
||||
import { isGroupQuit } from '../../../utils/user'
|
||||
import { getGroupDisplayName, isGroupQuit } from '../../../utils/user'
|
||||
import { useMessageSender } from '../../composables/useMessageSender'
|
||||
import { FacePicker } from '../../pages/conversation/components/input'
|
||||
import { useConversationStore } from '../../store/conversationStore'
|
||||
|
|
@ -181,7 +181,7 @@ async function handleCreateGroupAndSend() {
|
|||
const newConversation: Conversation = {
|
||||
type: ImConversationType.GROUP,
|
||||
targetId: group.id,
|
||||
name: group.name || name,
|
||||
name: getGroupDisplayName(group) || name,
|
||||
avatar: group.avatar || '',
|
||||
unreadCount: 0,
|
||||
lastContent: '',
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import {
|
|||
} from '../../utils/constants'
|
||||
import { generateClientMessageId, getPrivateMessagePeerId } from '../../utils/message'
|
||||
import { runMinIdPull } from '../../utils/pull'
|
||||
import { getFriendDisplayName } from '../../utils/user'
|
||||
import { getFriendDisplayName, getGroupDisplayName } from '../../utils/user'
|
||||
import { useConversationStore } from '../store/conversationStore'
|
||||
import { useFriendStore } from '../store/friendStore'
|
||||
import { useGroupRequestStore } from '../store/groupRequestStore'
|
||||
|
|
@ -146,7 +146,7 @@ export const useMessagePuller = () => {
|
|||
return {
|
||||
type: ImConversationType.GROUP,
|
||||
targetId: message.groupId,
|
||||
name: group?.name || String(message.groupId),
|
||||
name: group ? getGroupDisplayName(group) : String(message.groupId),
|
||||
avatar: group?.avatar || '',
|
||||
silent: group?.silent
|
||||
}
|
||||
|
|
|
|||
|
|
@ -241,7 +241,8 @@ function onRemarkSaved(displayName: string) {
|
|||
</div>
|
||||
|
||||
<!-- 列表主体:拆 FriendRequestList / GroupList / FriendList 三个子组件,各自管理折叠 + 过滤;本页只透传选中态 -->
|
||||
<div class="flex-1">
|
||||
<!-- overflow-y-auto:联系人多时本列表可滚动(父 ResizableAside 不提供滚动),对齐 Vue3 的 el-scrollbar -->
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<FriendRequestList
|
||||
:requests="friendRequests"
|
||||
:active-id="selection?.type === 'request' ? selection.request.id : undefined"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { useConversationStore } from '#/views/im/home/store/conversationStore'
|
|||
import { useFriendStore } from '#/views/im/home/store/friendStore'
|
||||
import { useGroupStore } from '#/views/im/home/store/groupStore'
|
||||
import { ImConversationType } from '#/views/im/utils/constants'
|
||||
import { getFriendDisplayName } from '#/views/im/utils/user'
|
||||
import { getFriendDisplayName, getGroupDisplayName } from '#/views/im/utils/user'
|
||||
|
||||
import { GroupCreateDialog } from '../../../../components/group'
|
||||
import { UserAvatar } from '../../../../components/user'
|
||||
|
|
@ -119,7 +119,7 @@ function handleGroupCreated(groupId: number) {
|
|||
conversationStore.openConversation(
|
||||
groupId,
|
||||
ImConversationType.GROUP,
|
||||
group.name,
|
||||
getGroupDisplayName(group),
|
||||
group.avatar || '',
|
||||
{ silent: !!group.silent }
|
||||
)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import {
|
|||
removeQuotePayload,
|
||||
serializeMessage
|
||||
} from '#/views/im/utils/message'
|
||||
import { isGroupQuit } from '#/views/im/utils/user'
|
||||
import { getGroupDisplayName, isGroupQuit } from '#/views/im/utils/user'
|
||||
|
||||
import { FacePicker } from '../../input'
|
||||
|
||||
|
|
@ -263,7 +263,7 @@ async function handleCreateGroupAndSend() {
|
|||
const newConversation: Conversation = {
|
||||
type: ImConversationType.GROUP,
|
||||
targetId: group.id,
|
||||
name: group.name || name,
|
||||
name: getGroupDisplayName(group) || name,
|
||||
avatar: group.avatar || '',
|
||||
unreadCount: 0,
|
||||
lastContent: '',
|
||||
|
|
|
|||
|
|
@ -84,7 +84,8 @@ function handleClose() {
|
|||
>
|
||||
以下是 {{ currentPayload.messages.length }} 条消息
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<!-- overflow-y-auto:合并消息多时在定高弹窗内可滚动,对齐 Vue3 的 el-scrollbar -->
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<div
|
||||
v-for="(item, idx) in currentPayload.messages"
|
||||
:key="idx"
|
||||
|
|
|
|||
|
|
@ -582,7 +582,11 @@ function locateMessage(messageId: number) {
|
|||
<div class="px-2 pt-1 pb-2 text-13px font-medium text-[var(--ant-color-text)]">
|
||||
选择发送日期
|
||||
</div>
|
||||
<Calendar v-model:value="datePickerValue" class="im-message-history__calendar" />
|
||||
<Calendar
|
||||
v-model:value="datePickerValue"
|
||||
:fullscreen="false"
|
||||
class="im-message-history__calendar"
|
||||
/>
|
||||
<div class="flex gap-2 justify-end px-2 pt-2">
|
||||
<Button size="small" @click="datePopoverVisible = false">取消</Button>
|
||||
<Button size="small" type="primary" @click="onDateConfirm">确定</Button>
|
||||
|
|
@ -785,18 +789,19 @@ function locateMessage(messageId: number) {
|
|||
border-radius: 1px;
|
||||
}
|
||||
|
||||
/* :deep 穿透 el-calendar 子组件 DOM;默认偏大压一压让它能塞进 320 popover */
|
||||
.im-message-history__calendar :deep(.el-calendar) {
|
||||
40px: 36px;
|
||||
}
|
||||
.im-message-history__calendar :deep(.el-calendar__header) {
|
||||
/* :deep 穿透 antd Calendar(fullscreen=false 卡片模式)子 DOM,压一压塞进 320 popover */
|
||||
.im-message-history__calendar :deep(.ant-picker-calendar-header) {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
.im-message-history__calendar :deep(.el-calendar-table) {
|
||||
.im-message-history__calendar :deep(.ant-picker-content) {
|
||||
font-size: 12px;
|
||||
}
|
||||
.im-message-history__calendar :deep(.el-calendar-day) {
|
||||
height: 36px;
|
||||
padding: 4px;
|
||||
.im-message-history__calendar :deep(.ant-picker-cell) {
|
||||
padding: 1px 0;
|
||||
}
|
||||
.im-message-history__calendar :deep(.ant-picker-cell .ant-picker-calendar-date) {
|
||||
height: 28px;
|
||||
margin: 0 2px;
|
||||
padding: 2px 4px 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import { getCurrentUserId } from '#/views/im/utils/auth'
|
|||
import { ImConversationType, ImRtcCallMediaType, ImRtcCallStatus } from '#/views/im/utils/constants'
|
||||
import { getClientConversationId } from '#/views/im/utils/db'
|
||||
import { resolveCallEndReasonText } from '#/views/im/utils/message'
|
||||
import { getMemberDisplayName, isGroupQuit } from '#/views/im/utils/user'
|
||||
import { getGroupDisplayName, getMemberDisplayName, isGroupQuit } from '#/views/im/utils/user'
|
||||
|
||||
import { GroupMuteMemberDialog } from '../../../../components/group'
|
||||
import {
|
||||
|
|
@ -185,10 +185,11 @@ const groupInfo = computed<
|
|||
}
|
||||
const group = groupStore.getGroup(conversation.targetId)
|
||||
const selfMember = group?.members?.find((member) => member.userId === getCurrentUserId())
|
||||
const showGroupName = group ? getGroupDisplayName(group) : conversation.name
|
||||
return {
|
||||
id: conversation.targetId,
|
||||
name: group?.name || conversation.name,
|
||||
showGroupName: group?.name || conversation.name,
|
||||
showGroupName,
|
||||
showImage: group?.avatar || conversation.avatar,
|
||||
notice: group?.notice,
|
||||
remarkNickName: selfMember?.displayUserName,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { Button, Dropdown, Input, Menu } from 'ant-design-vue'
|
|||
import { ImConversationType } from '../../../utils/constants'
|
||||
import { filterConversationsByKeyword, getConversationKey } from '../../../utils/conversation'
|
||||
import { StorageKeys } from '../../../utils/db'
|
||||
import { getGroupDisplayName } from '../../../utils/user'
|
||||
import { ResizableAside } from '../../components'
|
||||
import { FriendAddDialog } from '../../components/friend'
|
||||
import { GroupCreateDialog } from '../../components/group'
|
||||
|
|
@ -124,7 +125,7 @@ function handleGroupCreated(groupId: number) {
|
|||
conversationStore.openConversation(
|
||||
groupId,
|
||||
ImConversationType.GROUP,
|
||||
group.name,
|
||||
getGroupDisplayName(group),
|
||||
group.avatar || '',
|
||||
{ silent: !!group.silent }
|
||||
)
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ export const useGroupStore = defineStore('imGroupStore', {
|
|||
return
|
||||
}
|
||||
const fresh = (list || []).map((group) => convertGroup(group))
|
||||
// 合并而非全量替换:silent / groupRemark / 成员缓存这些字段不在 ImGroupApi.GroupRespVO 里,得从旧 group 保留
|
||||
// 合并而非全量替换:成员缓存只在成员列表接口维护,群个人设置以群列表接口为准
|
||||
const groupMap = new Map(this.groups.map((group) => [group.id, group]))
|
||||
this.groups = fresh.map((group) => {
|
||||
const existing = groupMap.get(group.id)
|
||||
|
|
@ -234,8 +234,6 @@ export const useGroupStore = defineStore('imGroupStore', {
|
|||
...group,
|
||||
members: existing.members,
|
||||
memberCount: existing.memberCount ?? group.memberCount,
|
||||
silent: existing.silent ?? group.silent,
|
||||
groupRemark: existing.groupRemark,
|
||||
membersLoaded: existing.membersLoaded,
|
||||
membersExpired: existing.membersExpired
|
||||
}
|
||||
|
|
@ -250,6 +248,24 @@ export const useGroupStore = defineStore('imGroupStore', {
|
|||
})
|
||||
}
|
||||
this.saveGroupList()
|
||||
this.preloadMembersForEmptyAvatarGroups()
|
||||
},
|
||||
|
||||
/** 预加载空群头像的成员列表,供 GroupAvatar 异步合成群头像 */
|
||||
preloadMembersForEmptyAvatarGroups() {
|
||||
for (const group of this.groups) {
|
||||
if (
|
||||
group.avatar ||
|
||||
group.joinStatus === CommonStatusEnum.DISABLE ||
|
||||
(group.membersLoaded && !group.membersExpired && group.members?.length)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
const force = !!group.membersLoaded && !group.membersExpired && !group.members?.length
|
||||
this.fetchGroupMemberList(group.id, force).catch((error) => {
|
||||
console.warn('[IM groupStore] 预加载群头像成员失败', { groupId: group.id }, error)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/** 失效全部群成员缓存 */
|
||||
|
|
@ -908,7 +924,9 @@ function convertGroup(group: ImGroupApi.GroupRespVO): Group {
|
|||
mutedAll: group.mutedAll,
|
||||
banned: group.banned,
|
||||
joinApproval: group.joinApproval,
|
||||
joinStatus: group.joinStatus
|
||||
joinStatus: group.joinStatus,
|
||||
groupRemark: group.groupRemark,
|
||||
silent: group.silent
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ import {
|
|||
playAudioTip,
|
||||
resolveCallEndReasonText
|
||||
} from '../../utils/message'
|
||||
import { getFriendDisplayName } from '../../utils/user'
|
||||
import { getFriendDisplayName, getGroupDisplayName } from '../../utils/user'
|
||||
import { useConversationStore } from './conversationStore'
|
||||
import { type FriendNotificationPayload, useFriendStore } from './friendStore'
|
||||
import { useGroupRequestStore } from './groupRequestStore'
|
||||
|
|
@ -781,7 +781,7 @@ export const useImWebSocketStore = defineStore('imWebSocketStore', {
|
|||
{
|
||||
type: ImConversationType.GROUP,
|
||||
targetId: websocketMessage.groupId,
|
||||
name: group?.name || String(websocketMessage.groupId),
|
||||
name: group ? getGroupDisplayName(group) : String(websocketMessage.groupId),
|
||||
avatar: group?.avatar || '',
|
||||
silent: group?.silent
|
||||
},
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export function usePrivateGridFormSchema(): VbenFormSchema[] {
|
|||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
options: getDictOptions(DICT_TYPE.IM_MESSAGE_TYPE, 'number'),
|
||||
options: getDictOptions(DICT_TYPE.IM_CONTENT_TYPE, 'number'),
|
||||
placeholder: '请选择内容类型',
|
||||
},
|
||||
},
|
||||
|
|
@ -84,7 +84,7 @@ export function usePrivateGridColumns(showReadColumns: boolean): VxeTableGridOpt
|
|||
width: 100,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.IM_MESSAGE_TYPE },
|
||||
props: { type: DICT_TYPE.IM_CONTENT_TYPE },
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -101,7 +101,17 @@ export function usePrivateGridColumns(showReadColumns: boolean): VxeTableGridOpt
|
|||
width: 100,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.IM_PRIVATE_MESSAGE_STATUS },
|
||||
props: { type: DICT_TYPE.IM_MESSAGE_STATUS },
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'receiptStatus',
|
||||
title: '回执',
|
||||
width: 110,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
// 回执状态(私聊 / 群聊共用 im_message_receipt_status),与源端「回执」列对齐
|
||||
props: { type: DICT_TYPE.IM_MESSAGE_RECEIPT_STATUS },
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
@ -143,7 +153,7 @@ export function useGroupGridFormSchema(): VbenFormSchema[] {
|
|||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
options: getDictOptions(DICT_TYPE.IM_MESSAGE_TYPE, 'number'),
|
||||
options: getDictOptions(DICT_TYPE.IM_CONTENT_TYPE, 'number'),
|
||||
placeholder: '请选择内容类型',
|
||||
},
|
||||
},
|
||||
|
|
@ -192,7 +202,7 @@ export function useGroupGridColumns(showReadColumns: boolean): VxeTableGridOptio
|
|||
width: 100,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.IM_MESSAGE_TYPE },
|
||||
props: { type: DICT_TYPE.IM_CONTENT_TYPE },
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -214,7 +224,7 @@ export function useGroupGridColumns(showReadColumns: boolean): VxeTableGridOptio
|
|||
width: 100,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.IM_GROUP_MESSAGE_STATUS },
|
||||
props: { type: DICT_TYPE.IM_MESSAGE_STATUS },
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -223,7 +233,7 @@ export function useGroupGridColumns(showReadColumns: boolean): VxeTableGridOptio
|
|||
width: 110,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.IM_GROUP_MESSAGE_RECEIPT_STATUS },
|
||||
props: { type: DICT_TYPE.IM_MESSAGE_RECEIPT_STATUS },
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -48,14 +48,14 @@ defineExpose({ open });
|
|||
{{ formatUserLabel(detail.senderNickname, detail.senderId) }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="类型">
|
||||
<DictTag :type="DICT_TYPE.IM_MESSAGE_TYPE" :value="detail.type" />
|
||||
<DictTag :type="DICT_TYPE.IM_CONTENT_TYPE" :value="detail.type" />
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="状态">
|
||||
<DictTag :type="DICT_TYPE.IM_GROUP_MESSAGE_STATUS" :value="detail.status" />
|
||||
<DictTag :type="DICT_TYPE.IM_MESSAGE_STATUS" :value="detail.status" />
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem v-if="MESSAGE_GROUP_READ_ENABLED" label="回执" :span="2">
|
||||
<DictTag
|
||||
:type="DICT_TYPE.IM_GROUP_MESSAGE_RECEIPT_STATUS"
|
||||
:type="DICT_TYPE.IM_MESSAGE_RECEIPT_STATUS"
|
||||
:value="detail.receiptStatus"
|
||||
/>
|
||||
</DescriptionsItem>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
formatJsonText,
|
||||
formatUserLabel,
|
||||
} from '#/views/im/manager/utils/format';
|
||||
import { MESSAGE_PRIVATE_READ_ENABLED } from '#/views/im/utils/config';
|
||||
|
||||
import { MessageContentPreview } from '../..';
|
||||
|
||||
|
|
@ -44,10 +45,17 @@ defineExpose({ open });
|
|||
{{ formatUserLabel(detail.receiverNickname, detail.receiverId) }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="类型">
|
||||
<DictTag :type="DICT_TYPE.IM_MESSAGE_TYPE" :value="detail.type" />
|
||||
<DictTag :type="DICT_TYPE.IM_CONTENT_TYPE" :value="detail.type" />
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="状态">
|
||||
<DictTag :type="DICT_TYPE.IM_PRIVATE_MESSAGE_STATUS" :value="detail.status" />
|
||||
<DictTag :type="DICT_TYPE.IM_MESSAGE_STATUS" :value="detail.status" />
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem v-if="MESSAGE_PRIVATE_READ_ENABLED" label="回执">
|
||||
<!-- 回执状态(私聊 / 群聊共用 im_message_receipt_status),与源端私聊详情「回执」对齐 -->
|
||||
<DictTag
|
||||
:type="DICT_TYPE.IM_MESSAGE_RECEIPT_STATUS"
|
||||
:value="detail.receiptStatus"
|
||||
/>
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="发送时间" :span="2">
|
||||
{{ formatDateTimeText(detail.sendTime) }}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ async function loadData() {
|
|||
const data = await getMessageTypeDistribution();
|
||||
const items = data.map((item) => ({
|
||||
name:
|
||||
getDictObj(DICT_TYPE.IM_MESSAGE_TYPE, String(item.type))?.label ||
|
||||
getDictObj(DICT_TYPE.IM_CONTENT_TYPE, String(item.type))?.label ||
|
||||
`未知(${item.type})`,
|
||||
value: item.value,
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -178,17 +178,16 @@ const IOT_DICT = {
|
|||
/** ========== IM - 即时通讯模块 ========== */
|
||||
const IM_DICT = {
|
||||
IM_CHANNEL_MATERIAL_TYPE: 'im_channel_material_type', // IM 频道素材类型
|
||||
IM_CONTENT_TYPE: 'im_content_type', // IM 消息内容类型
|
||||
IM_FRIEND_ADD_SOURCE: 'im_friend_add_source', // IM 好友添加来源
|
||||
IM_FRIEND_REQUEST_HANDLE_RESULT: 'im_friend_request_handle_result', // IM 好友申请处理结果
|
||||
IM_FRIEND_STATUS: 'im_friend_status', // IM 好友状态
|
||||
IM_GROUP_ADD_SOURCE: 'im_group_add_source', // IM 加群来源
|
||||
IM_GROUP_MEMBER_ROLE: 'im_group_member_role', // IM 群成员角色
|
||||
IM_GROUP_MESSAGE_RECEIPT_STATUS: 'im_group_message_receipt_status', // IM 群消息回执状态
|
||||
IM_GROUP_MESSAGE_STATUS: 'im_group_message_status', // IM 群聊消息状态
|
||||
IM_GROUP_REQUEST_HANDLE_RESULT: 'im_group_request_handle_result', // IM 加群申请处理结果
|
||||
IM_GROUP_STATUS: 'im_group_status', // IM 群状态
|
||||
IM_MESSAGE_TYPE: 'im_message_type', // IM 消息类型
|
||||
IM_PRIVATE_MESSAGE_STATUS: 'im_private_message_status', // IM 私聊消息状态
|
||||
IM_MESSAGE_RECEIPT_STATUS: 'im_message_receipt_status', // IM 消息回执状态(私聊 / 群聊共用)
|
||||
IM_MESSAGE_STATUS: 'im_message_status', // IM 消息状态(私聊 / 群聊共用)
|
||||
IM_RTC_CALL_CONVERSATION_TYPE: 'im_rtc_call_conversation_type', // IM 通话会话类型
|
||||
IM_RTC_CALL_END_REASON: 'im_rtc_call_end_reason', // IM 通话结束原因
|
||||
IM_RTC_CALL_MEDIA_TYPE: 'im_rtc_call_media_type', // IM 通话媒体类型
|
||||
|
|
|
|||
Loading…
Reference in New Issue