fix(im):修复迁移评审发现的组件与目录问题

- 修复 antdv-next 群详情缺少 DescriptionsItem 导入的问题
- 对齐 antdv-next 群详情、RTC 详情的数据访问写法,移除多余辅助函数
- 修复 web-ele 弹窗、抽屉、原生元素、头像、图标的 title/content 误用
- 将三端表情 API 目录 useritem 统一为 userItem
- 同步更新普通表情和管理端表情相关 import 路径
pull/367/head
YunaiV 2026-06-19 17:12:42 -07:00
parent 010da63c7c
commit fac0190ca8
29 changed files with 45 additions and 78 deletions

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { ImFacePackApi } from '#/api/im/face/pack'
import type { ImFaceUserItemApi } from '#/api/im/face/useritem'
import type { ImFaceUserItemApi } from '#/api/im/face/userItem'
import { computed, onUnmounted, ref, useTemplateRef, watch } from 'vue'

View File

@ -1,12 +1,12 @@
import type { ImFacePackApi } from '#/api/im/face/pack'
import type { ImFaceUserItemApi } from '#/api/im/face/useritem'
import type { ImFaceUserItemApi } from '#/api/im/face/userItem'
import { ref } from 'vue'
import { acceptHMRUpdate, defineStore } from 'pinia'
import { getFacePackList as apiGetFacePackList } from '#/api/im/face/pack'
import { createFaceUserItem as apiCreateFaceUserItem, deleteFaceUserItem as apiDeleteFaceUserItem, getFaceUserItemList as apiGetFaceUserItemList } from '#/api/im/face/useritem'
import { createFaceUserItem as apiCreateFaceUserItem, deleteFaceUserItem as apiDeleteFaceUserItem, getFaceUserItemList as apiGetFaceUserItemList } from '#/api/im/face/userItem'
/**
* IM store +

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { ImManagerFaceUserItemApi } from '#/api/im/manager/face/useritem';
import type { ImManagerFaceUserItemApi } from '#/api/im/manager/face/userItem';
import { Page } from '@vben/common-ui';
@ -10,7 +10,7 @@ import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import {
deleteManagerFaceUserItem,
getManagerFaceUserItemPage,
} from '#/api/im/manager/face/useritem';
} from '#/api/im/manager/face/userItem';
import { $t } from '#/locales';
import { formatUserLabel } from '#/views/im/manager/utils/format';

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { ImFacePackApi } from '#/api/im/face/pack'
import type { ImFaceUserItemApi } from '#/api/im/face/useritem'
import type { ImFaceUserItemApi } from '#/api/im/face/userItem'
import { computed, onUnmounted, ref, useTemplateRef, watch } from 'vue'

View File

@ -1,12 +1,12 @@
import type { ImFacePackApi } from '#/api/im/face/pack'
import type { ImFaceUserItemApi } from '#/api/im/face/useritem'
import type { ImFaceUserItemApi } from '#/api/im/face/userItem'
import { ref } from 'vue'
import { acceptHMRUpdate, defineStore } from 'pinia'
import { getFacePackList as apiGetFacePackList } from '#/api/im/face/pack'
import { createFaceUserItem as apiCreateFaceUserItem, deleteFaceUserItem as apiDeleteFaceUserItem, getFaceUserItemList as apiGetFaceUserItemList } from '#/api/im/face/useritem'
import { createFaceUserItem as apiCreateFaceUserItem, deleteFaceUserItem as apiDeleteFaceUserItem, getFaceUserItemList as apiGetFaceUserItemList } from '#/api/im/face/userItem'
/**
* IM store +

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { ImManagerFaceUserItemApi } from '#/api/im/manager/face/useritem';
import type { ImManagerFaceUserItemApi } from '#/api/im/manager/face/userItem';
import { Page } from '@vben/common-ui';
@ -10,7 +10,7 @@ import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import {
deleteManagerFaceUserItem,
getManagerFaceUserItemPage,
} from '#/api/im/manager/face/useritem';
} from '#/api/im/manager/face/userItem';
import { $t } from '#/locales';
import { formatUserLabel } from '#/views/im/manager/utils/format';

View File

@ -9,6 +9,7 @@ import {
Avatar,
Checkbox,
Descriptions,
DescriptionsItem,
Drawer,
Table,
Tag,
@ -47,16 +48,6 @@ const columns = [
{ title: '禁言状态', dataIndex: 'muteEndTime', width: 180 },
];
/** 获取列字段 */
function getColumnDataIndex(column: any) {
return String(column.dataIndex || '');
}
/** 获取成员字段值 */
function getMemberValue(record: ImManagerGroupApi.GroupMember, key: string) {
return (record as unknown as Record<string, unknown>)[key] || '-';
}
/** 打开详情 */
async function open(row: ImManagerGroupApi.Group) {
detail.value = row;
@ -122,27 +113,27 @@ defineExpose({ open });
size="small"
>
<template #bodyCell="{ column, record }">
<template v-if="getColumnDataIndex(column) === 'avatar'">
<template v-if="column.dataIndex === 'avatar'">
<Avatar :src="record.avatar" :size="40">
{{ record.nickname?.charAt(0) || '?' }}
</Avatar>
</template>
<template v-else-if="getColumnDataIndex(column) === 'role'">
<template v-else-if="column.dataIndex === 'role'">
<DictTag :type="DICT_TYPE.IM_GROUP_MEMBER_ROLE" :value="record.role" />
</template>
<template v-else-if="getColumnDataIndex(column) === 'silent'">
<template v-else-if="column.dataIndex === 'silent'">
<DictTag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="record.silent" />
</template>
<template v-else-if="getColumnDataIndex(column) === 'status'">
<template v-else-if="column.dataIndex === 'status'">
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="record.status" />
</template>
<template v-else-if="getColumnDataIndex(column) === 'joinTime'">
<template v-else-if="column.dataIndex === 'joinTime'">
{{ formatDateTimeText(record.joinTime) }}
</template>
<template v-else-if="getColumnDataIndex(column) === 'quitTime'">
<template v-else-if="column.dataIndex === 'quitTime'">
{{ formatDateTimeText(record.quitTime) }}
</template>
<template v-else-if="getColumnDataIndex(column) === 'muteEndTime'">
<template v-else-if="column.dataIndex === 'muteEndTime'">
<template v-if="record.muteEndTime && new Date(record.muteEndTime) > new Date()">
<Tag color="error">禁言中</Tag>
<div class="mt-1 text-xs text-gray-400">
@ -152,7 +143,7 @@ defineExpose({ open });
<span v-else>-</span>
</template>
<template v-else>
{{ getMemberValue(record, getColumnDataIndex(column)) }}
{{ record[column.dataIndex] || '-' }}
</template>
</template>
</Table>

View File

@ -35,30 +35,6 @@ const columns = [
{ title: '离开时间', dataIndex: 'leaveTime', width: 180 },
];
/** 获取列字段 */
function getColumnDataIndex(column: any) {
return String(column.dataIndex || '');
}
/** 获取参与者字段值 */
function getParticipantValue(
record: ImManagerRtcApi.RtcParticipant,
key: string,
) {
return (record as unknown as Record<string, unknown>)[key] || '-';
}
/** 获取参与时间字段 */
function getParticipantTime(
record: ImManagerRtcApi.RtcParticipant,
key: string,
) {
const value = getParticipantValue(record, key);
return value instanceof Date || typeof value === 'number' || typeof value === 'string'
? value
: undefined;
}
/** 打开详情 */
async function open(row: ImManagerRtcApi.RtcCall) {
detail.value = row;
@ -125,17 +101,17 @@ defineExpose({ open });
size="small"
>
<template #bodyCell="{ column, record }">
<template v-if="getColumnDataIndex(column) === 'role'">
<template v-if="column.dataIndex === 'role'">
<DictTag :type="DICT_TYPE.IM_RTC_PARTICIPANT_ROLE" :value="record.role" />
</template>
<template v-else-if="getColumnDataIndex(column) === 'status'">
<template v-else-if="column.dataIndex === 'status'">
<DictTag :type="DICT_TYPE.IM_RTC_PARTICIPANT_STATUS" :value="record.status" />
</template>
<template v-else-if="['inviteTime', 'acceptTime', 'leaveTime'].includes(getColumnDataIndex(column))">
{{ formatDateTimeText(getParticipantTime(record, getColumnDataIndex(column))) }}
<template v-else-if="['inviteTime', 'acceptTime', 'leaveTime'].includes(column.dataIndex as string)">
{{ formatDateTimeText(record[column.dataIndex]) }}
</template>
<template v-else>
{{ getParticipantValue(record, getColumnDataIndex(column)) }}
{{ record[column.dataIndex] || '-' }}
</template>
</template>
</Table>

View File

@ -161,7 +161,7 @@ async function handleSubmitApply() {
-->
<ElDialog
v-model="visible"
:content="dialogTitle"
:title="dialogTitle"
width="480px"
:close-on-click-modal="false"
>

View File

@ -93,7 +93,7 @@ function stopResize() {
<div
class="im-resizable-aside__handle absolute top-0 right--0.75 z-10 flex items-center justify-center w-1.5 h-full cursor-col-resize transition-colors"
:class="{ 'is-resizing': isResizing }"
content="拖拽调整宽度"
title="拖拽调整宽度"
@mousedown="startResize"
>
<div class="im-resizable-aside__line w-0.5 h-full rounded-0.5 bg-transparent transition-all"></div>

View File

@ -83,7 +83,7 @@ const callMembers = useGroupCallMembers(
radius="4px"
:clickable="false"
:class="{ 'opacity-50': member.pending }"
:content="member.pending ? `${member.nickname}(接入中)` : member.nickname"
:title="member.pending ? `${member.nickname}(接入中)` : member.nickname"
/>
</div>
</template>

View File

@ -79,7 +79,7 @@ function handleOk() {
-->
<ElDialog
v-model="visible"
:content="title"
:title="title"
width="720px"
:close-on-click-modal="false"
class="im-picker-dialog"

View File

@ -181,7 +181,7 @@ async function handleJoin() {
radius="6px"
:clickable="false"
:class="{ 'opacity-50': member.pending }"
:content="member.pending ? `${member.nickname}(接入中)` : member.nickname"
:title="member.pending ? `${member.nickname}(接入中)` : member.nickname"
/>
<!-- 首次填充时房内可能暂时 0 加入后由 ParticipantConnected 事件追加 -->
<div

View File

@ -454,7 +454,7 @@ function handleOpenTransferOwner() {
<div
v-if="!isQuitGroup"
class="im-conversation-group-side__tile-wrap flex flex-col items-center w-[66px] cursor-pointer"
content="邀请好友入群"
title="邀请好友入群"
@click="handleOpenInvite"
>
<div class="im-conversation-group-side__icon-tile flex items-center justify-center w-[50px] h-[50px] text-20px text-[var(--ant-color-text)] bg-[var(--ant-color-fill-tertiary)] border border-dashed border-[var(--ant-color-border)] rounded-md transition-colors duration-200">
@ -467,7 +467,7 @@ function handleOpenTransferOwner() {
<div
v-if="isOwnerOrAdmin"
class="im-conversation-group-side__tile-wrap flex flex-col items-center w-[66px] cursor-pointer"
content="移出群成员"
title="移出群成员"
@click="handleOpenRemove"
>
<div class="im-conversation-group-side__icon-tile flex items-center justify-center w-[50px] h-[50px] text-20px text-[var(--ant-color-text)] bg-[var(--ant-color-fill-tertiary)] border border-dashed border-[var(--ant-color-border)] rounded-md transition-colors duration-200">

View File

@ -286,7 +286,7 @@ function handleContextMenu(e: MouseEvent) {
icon="mdi:bell-off-outline"
:size="14"
class="conversation-item__silent flex-shrink-0 ml-1 text-[var(--ant-color-text-disabled)]"
content="消息免打扰"
title="消息免打扰"
/>
</div>
</div>

View File

@ -168,7 +168,7 @@ function handleGroupCreated(groupId: number) {
<!-- + tile点击调起 GroupCreateDialog把对方 id 作为 lockedIds 传入 -->
<div
class="im-conversation-private-side__tile-wrap-clickable flex flex-col items-center w-[66px] cursor-pointer"
content="发起群聊"
title="发起群聊"
@click="handleOpenCreateGroup"
>
<div class="im-conversation-private-side__icon-tile flex items-center justify-center w-[50px] h-[50px] text-20px text-[var(--ant-color-text)] bg-[var(--ant-color-fill-tertiary)] border border-dashed border-[var(--ant-color-border)] rounded-md transition-colors duration-200">

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { ImFacePackApi } from '#/api/im/face/pack'
import type { ImFaceUserItemApi } from '#/api/im/face/useritem'
import type { ImFaceUserItemApi } from '#/api/im/face/userItem'
import { computed, onUnmounted, ref, useTemplateRef, watch } from 'vue'
@ -188,7 +188,7 @@ onUnmounted(() => {
class="aspect-square flex items-center justify-center rounded-md cursor-pointer transition-colors border border-dashed border-[var(--ant-color-border)] bg-transparent text-[var(--ant-color-text-placeholder)] hover:border-[var(--ant-color-primary)] hover:text-[var(--ant-color-primary)] disabled:cursor-not-allowed disabled:text-[var(--ant-color-text-disabled)]"
type="button"
:disabled="uploading"
:content="uploading ? '上传中…' : '上传图片到个人表情'"
:title="uploading ? '上传中…' : '上传图片到个人表情'"
@click="onUploadClick"
>
<Icon
@ -200,7 +200,7 @@ onUnmounted(() => {
v-for="item in faceStore.faceUserItems"
:key="item.id"
class="im-face-grid-cell group relative aspect-square flex items-center justify-center rounded-md bg-[var(--ant-color-fill-tertiary)] cursor-pointer transition-colors hover:bg-[var(--ant-color-fill)]"
:content="item.name || '点击发送 / 右键删除'"
:title="item.name || '点击发送 / 右键删除'"
@click="handleSelectFaceUserItem(item)"
@contextmenu.prevent="handleDeleteUserItem(item)"
>
@ -233,7 +233,7 @@ onUnmounted(() => {
v-for="item in pack.items"
:key="item.id"
class="im-face-grid-cell flex flex-col items-center gap-1 cursor-pointer rounded-md p-1 transition-colors hover:bg-[var(--ant-color-fill)]"
:content="item.name || ''"
:title="item.name || ''"
@click="handleSelectPackItem(item)"
>
<div

View File

@ -112,7 +112,7 @@ const onClick = async () => {
<!-- 富文本详情全屏弹窗按需挂载关闭后释放富文本 DOM -->
<ElDialog
v-model="detailVisible"
:content="payload.title || '详情'"
:title="payload.title || '详情'"
width="100vw"
class="im-material-detail-modal"

View File

@ -294,7 +294,7 @@ onBeforeUnmount(() => {
<img
:src="facePayload.url"
:alt="facePayload.name || '表情'"
:content="facePayload.name || ''"
:title="facePayload.name || ''"
:width="facePayload.width"
:height="facePayload.height"
class="block max-w-[160px] max-h-[160px] object-contain"

View File

@ -993,7 +993,7 @@ function handleDelete() {
icon="ant-design:warning-filled"
color="#f56c6c"
class="cursor-pointer"
content="发送失败,点击重试"
title="发送失败,点击重试"
@click="handleResend"
/>
<!-- 已读态私聊 -->

View File

@ -1,12 +1,12 @@
import type { ImFacePackApi } from '#/api/im/face/pack'
import type { ImFaceUserItemApi } from '#/api/im/face/useritem'
import type { ImFaceUserItemApi } from '#/api/im/face/userItem'
import { ref } from 'vue'
import { acceptHMRUpdate, defineStore } from 'pinia'
import { getFacePackList as apiGetFacePackList } from '#/api/im/face/pack'
import { createFaceUserItem as apiCreateFaceUserItem, deleteFaceUserItem as apiDeleteFaceUserItem, getFaceUserItemList as apiGetFaceUserItemList } from '#/api/im/face/useritem'
import { createFaceUserItem as apiCreateFaceUserItem, deleteFaceUserItem as apiDeleteFaceUserItem, getFaceUserItemList as apiGetFaceUserItemList } from '#/api/im/face/userItem'
/**
* IM store +

View File

@ -145,7 +145,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
<template>
<ElDrawer
v-model="visible"
:content="title"
:title="title"
destroy-on-close
width="65%"
@after-open-change="handleOpenChange"

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { ImManagerFaceUserItemApi } from '#/api/im/manager/face/useritem';
import type { ImManagerFaceUserItemApi } from '#/api/im/manager/face/userItem';
import { Page } from '@vben/common-ui';
@ -10,7 +10,7 @@ import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import {
deleteManagerFaceUserItem,
getManagerFaceUserItemPage,
} from '#/api/im/manager/face/useritem';
} from '#/api/im/manager/face/userItem';
import { $t } from '#/locales';
import { formatUserLabel } from '#/views/im/manager/utils/format';