✨ feat(im): 初始化群申请 v0.3:第四把 review(优化界面,进一步对齐微信界面)【之前提交错了】
parent
f746aebe08
commit
b2ba42049b
|
|
@ -1,3 +0,0 @@
|
||||||
// 用户端 IM 表情 API barrel 出口;按子目录(pack / userItem)二次拆分,调用方可用 `from '@/api/im/face'` 一次拿全
|
|
||||||
export * from './pack'
|
|
||||||
export * from './userItem'
|
|
||||||
|
|
@ -96,14 +96,6 @@ onMounted(async () => {
|
||||||
// 3. 实时通信:建 WebSocket 长连接 + 拉离线消息(pullOnce finally 把 loading 归位)
|
// 3. 实时通信:建 WebSocket 长连接 + 拉离线消息(pullOnce finally 把 loading 归位)
|
||||||
webSocketStore.connect()
|
webSocketStore.connect()
|
||||||
await pullOnce()
|
await pullOnce()
|
||||||
// 3.1 我管理的群下未处理加群申请,给顶部横幅 / Drawer 派生 count 与 list;失败不阻断主流程
|
|
||||||
// TODO @AI:可以挪到 1.2 那么?不阻塞就行呀。
|
|
||||||
void groupRequestStore.fetchUnhandledList().catch((e) =>
|
|
||||||
console.warn('[IM] 拉取未处理加群申请失败', e)
|
|
||||||
)
|
|
||||||
// 3.2 系统表情包后台预拉,消除表情面板首次展开的白屏;个人表情保持「点开 tab 才拉」
|
|
||||||
// TODO @AI:同上;
|
|
||||||
void faceStore.ensureFacePacks().catch((e) => console.warn('[IM] 后台预拉表情包失败', e))
|
|
||||||
|
|
||||||
// 4. 默认选中第一个会话;若置顶分组处于折叠态,需跳过被折叠隐藏的置顶项,避免自动展开折叠
|
// 4. 默认选中第一个会话;若置顶分组处于折叠态,需跳过被折叠隐藏的置顶项,避免自动展开折叠
|
||||||
const sorted = conversationStore.getSortedConversations
|
const sorted = conversationStore.getSortedConversations
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,8 @@ import { updateFile } from '@/api/infra/file'
|
||||||
import { useFaceStore } from '@/views/im/home/store/faceStore'
|
import { useFaceStore } from '@/views/im/home/store/faceStore'
|
||||||
import { IM_EMOJI_LIST } from '@/views/im/utils/emoji'
|
import { IM_EMOJI_LIST } from '@/views/im/utils/emoji'
|
||||||
import { probeImageSize } from '@/views/im/utils/image'
|
import { probeImageSize } from '@/views/im/utils/image'
|
||||||
import type { ImFacePackUserItemVO, ImFaceUserItemVO } from '@/api/im/face'
|
import type { ImFacePackUserItemVO } from '@/api/im/face/pack'
|
||||||
|
import type { ImFaceUserItemVO } from '@/api/im/face/useritem'
|
||||||
|
|
||||||
defineOptions({ name: 'ImFacePicker' })
|
defineOptions({ name: 'ImFacePicker' })
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -496,9 +496,20 @@ const videoPayload = computed(() =>
|
||||||
const cardPayload = computed(() =>
|
const cardPayload = computed(() =>
|
||||||
isCard.value ? parseMessage<CardMessage>(props.message.content) : null
|
isCard.value ? parseMessage<CardMessage>(props.message.content) : null
|
||||||
)
|
)
|
||||||
const facePayload = computed(() =>
|
/** 表情 payload;非法宽高(缺失 / 0 / 负数 / 超出 2048)派生成 undefined,让 <img> 走 CSS max-w / max-h 兜底 */
|
||||||
isFace.value ? parseMessage<FaceMessage>(props.message.content) : null
|
const FACE_DIMENSION_MAX = 2048
|
||||||
)
|
const facePayload = computed(() => {
|
||||||
|
if (!isFace.value) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const raw = parseMessage<FaceMessage>(props.message.content)
|
||||||
|
if (!raw) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const sanitize = (v: number | undefined) =>
|
||||||
|
v && v > 0 && v <= FACE_DIMENSION_MAX ? v : undefined
|
||||||
|
return { ...raw, width: sanitize(raw.width), height: sanitize(raw.height) }
|
||||||
|
})
|
||||||
|
|
||||||
/** 名片点击:弹被推荐用户的 UserInfoCard;陌生人名片走「名片」加好友来源 */
|
/** 名片点击:弹被推荐用户的 UserInfoCard;陌生人名片走「名片」加好友来源 */
|
||||||
function handleCardClick(e: MouseEvent) {
|
function handleCardClick(e: MouseEvent) {
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,15 @@ import { store } from '@/store'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getFacePackList as apiGetFacePackList,
|
getFacePackList as apiGetFacePackList,
|
||||||
|
type ImFacePackUserVO
|
||||||
|
} from '@/api/im/face/pack'
|
||||||
|
import {
|
||||||
getFaceUserItemList as apiGetFaceUserItemList,
|
getFaceUserItemList as apiGetFaceUserItemList,
|
||||||
createFaceUserItem as apiCreateFaceUserItem,
|
createFaceUserItem as apiCreateFaceUserItem,
|
||||||
deleteFaceUserItem as apiDeleteFaceUserItem,
|
deleteFaceUserItem as apiDeleteFaceUserItem,
|
||||||
type ImFacePackUserVO,
|
|
||||||
type ImFaceUserItemVO,
|
type ImFaceUserItemVO,
|
||||||
type ImFaceUserItemSaveReqVO
|
type ImFaceUserItemSaveReqVO
|
||||||
} from '@/api/im/face'
|
} from '@/api/im/face/useritem'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IM 表情面板数据 store(系统表情包 + 个人表情)
|
* IM 表情面板数据 store(系统表情包 + 个人表情)
|
||||||
|
|
|
||||||
|
|
@ -22,21 +22,21 @@
|
||||||
<el-form-item label="尺寸">
|
<el-form-item label="尺寸">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-model="formData.width"
|
v-model="formData.width"
|
||||||
:min="0"
|
:min="1"
|
||||||
:max="9999"
|
:max="2048"
|
||||||
controls-position="right"
|
controls-position="right"
|
||||||
class="!w-1/3"
|
class="!w-1/3"
|
||||||
/>
|
/>
|
||||||
<span class="mx-2 text-[var(--el-text-color-secondary)]">×</span>
|
<span class="mx-2 text-[var(--el-text-color-secondary)]">×</span>
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-model="formData.height"
|
v-model="formData.height"
|
||||||
:min="0"
|
:min="1"
|
||||||
:max="9999"
|
:max="2048"
|
||||||
controls-position="right"
|
controls-position="right"
|
||||||
class="!w-1/3"
|
class="!w-1/3"
|
||||||
/>
|
/>
|
||||||
<span class="ml-2 text-12px text-[var(--el-text-color-placeholder)]">
|
<span class="ml-2 text-12px text-[var(--el-text-color-placeholder)]">
|
||||||
上传后自动探测;可手动调整
|
上传后自动探测;可手动调整(1 ~ 2048 像素)
|
||||||
</span>
|
</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="排序" prop="sort">
|
<el-form-item label="排序" prop="sort">
|
||||||
|
|
@ -92,8 +92,8 @@ const formData = ref({
|
||||||
packId: 0,
|
packId: 0,
|
||||||
url: '',
|
url: '',
|
||||||
name: '',
|
name: '',
|
||||||
width: 0,
|
width: undefined as number | undefined,
|
||||||
height: 0,
|
height: undefined as number | undefined,
|
||||||
sort: 0,
|
sort: 0,
|
||||||
status: CommonStatusEnum.ENABLE
|
status: CommonStatusEnum.ENABLE
|
||||||
})
|
})
|
||||||
|
|
@ -106,8 +106,8 @@ const formRef = ref() // 表单 Ref
|
||||||
/** 上传完成后从 URL 回探宽高,自动填表单(用户仍可手改) */
|
/** 上传完成后从 URL 回探宽高,自动填表单(用户仍可手改) */
|
||||||
async function onUrlChange(url: string) {
|
async function onUrlChange(url: string) {
|
||||||
if (!url) {
|
if (!url) {
|
||||||
formData.value.width = 0
|
formData.value.width = undefined
|
||||||
formData.value.height = 0
|
formData.value.height = undefined
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const size = await probeImageSize(url)
|
const size = await probeImageSize(url)
|
||||||
|
|
@ -165,8 +165,8 @@ const resetForm = () => {
|
||||||
packId: props.packId,
|
packId: props.packId,
|
||||||
url: '',
|
url: '',
|
||||||
name: '',
|
name: '',
|
||||||
width: 0,
|
width: undefined,
|
||||||
height: 0,
|
height: undefined,
|
||||||
sort: 0,
|
sort: 0,
|
||||||
status: CommonStatusEnum.ENABLE
|
status: CommonStatusEnum.ENABLE
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { dateFormatter } from '@/utils/formatTime'
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
import * as ManagerFaceUserItemApi from '@/api/im/manager/face/userItem'
|
import * as ManagerFaceUserItemApi from '@/api/im/manager/face/useritem'
|
||||||
|
|
||||||
defineOptions({ name: 'ImManagerFaceUserItem' })
|
defineOptions({ name: 'ImManagerFaceUserItem' })
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue