admin-vben/apps/web-antd/src/views/im/home/components/group/GroupInfoCard.vue

117 lines
3.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<script lang="ts" setup>
import type { GroupLite } from '../../types'
import { computed, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import { prompt } from '@vben/common-ui'
import { Input, message } from 'ant-design-vue'
import { applyJoinGroup } from '#/api/im/group/request'
import { ImConversationType, ImGroupAddSource } from '../../../utils/constants'
import { getGroupDisplayName } from '../../../utils/user'
import { useConversationStore } from '../../store/conversationStore'
import { useGroupStore } from '../../store/groupStore'
import { useImUiStore } from '../../store/uiStore'
import GroupInfo from './GroupInfo.vue'
defineOptions({ name: 'ImGroupInfoCard' })
const uiStore = useImUiStore()
const conversationStore = useConversationStore()
const groupStore = useGroupStore()
const router = useRouter()
const card = computed(() => uiStore.groupInfoCard)
/** 关闭浮层 */
function handleClose() {
uiStore.closeGroupInfoCard()
}
/** Esc 关闭 */
function handleKeydown(e: KeyboardEvent) {
if (e.key === 'Escape' && card.value.show) {
handleClose()
}
}
onMounted(() => window.addEventListener('keydown', handleKeydown))
onUnmounted(() => window.removeEventListener('keydown', handleKeydown))
/** 进入群聊:取本地最新群信息(含 silent / 群备注),新建或激活会话 + 跳路由 */
function handleChat(group: GroupLite) {
const cached = groupStore.getGroup(group.id)
// cached 命中走 getGroupDisplayName 让群备注优先(与 contact / 会话列表的展示名一致);缺 cached 时回落 showGroupName / 原群名
const displayName = cached
? getGroupDisplayName(cached)
: group.showGroupName || group.name || ''
// 打开或新建会话
conversationStore.openConversation(
group.id,
ImConversationType.GROUP,
displayName,
cached?.avatar || group.showImage || '',
{ silent: !!cached?.silent }
)
// 如果不在会话页先跳过去如果在了MessagePanel 会自己感知会话变化刷新)
if (router.currentRoute.value.name !== 'ImHomeConversation') {
router.push({ name: 'ImHomeConversation' })
}
handleClose()
}
/** 加入群聊:先关浮层(避免与 prompt 的 mask 互相遮挡)→ 弹申请理由(可选)→ applyJoinGroup */
async function handleApply(group: GroupLite) {
handleClose()
let applyContent: string
try {
const result = await prompt<string>({
cancelText: '取消',
component: Input,
componentProps: {
allowClear: true,
placeholder: '请填写验证消息(可选)'
},
content: '',
defaultValue: '',
confirmText: '发送申请',
modelPropName: 'value',
title: `申请加入「${group.name || ''}`
})
applyContent = (result || '').trim()
} catch {
return
}
await applyJoinGroup({
groupId: group.id,
applyContent: applyContent || undefined,
addSource: ImGroupAddSource.SHARE_LINK
})
message.success('加群申请已发送')
}
</script>
<template>
<!--
群信息浮层 UserInfoCard 对位
- 仅承担浮层定位 + 关闭逻辑点遮罩 / Esc群信息视觉走 <GroupInfo>与通讯录详情共用一份组件
- 触发useImUiStore.openGroupInfoCardAtEvent(group, e)
- GroupInfo 内部按 groupStore 缓存推导 member / stranger浮层只负责接 chat / apply 事件做业务
-->
<teleport to="body">
<div v-if="card.show" class="fixed inset-0 z-9998" @click.self="handleClose">
<div
class="fixed w-80 p-4 bg-[var(--ant-color-bg-elevated)] rounded-md shadow-xl"
:style="{ left: `${card.position.x }px`, top: `${card.position.y }px` }"
@click.stop
>
<GroupInfo v-if="card.group" :group="card.group" @chat="handleChat" @apply="handleApply" />
</div>
</div>
</teleport>
</template>