admin-vue3/src/views/im/home/pages/group/components/CreateGroupDialog.vue

175 lines
4.7 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.

<template>
<!--
新建群聊对话框
- 顶部群名称输入
- 好友列表 checkbox
- 已勾选预览
- 提交 createGroup inviteGroupMember最后让父页 reload
-->
<el-dialog
v-model="visible"
title="新建群聊"
width="620px"
:close-on-click-modal="false"
>
<div class="flex flex-col gap-3">
<el-input
v-model="groupName"
placeholder="请输入群名称"
maxlength="20"
show-word-limit
/>
<div class="flex gap-2.5">
<div class="flex flex-col flex-1 overflow-hidden rounded border border-[var(--el-border-color)]">
<el-input v-model="searchText" placeholder="搜索好友" size="small" clearable>
<template #suffix>
<el-icon><Search /></el-icon>
</template>
</el-input>
<el-scrollbar class="h-[400px]">
<FriendItem
v-for="f in shownFriends"
:key="f.id"
:friend="f"
:menu="false"
:active="false"
@click="toggleCheck(f)"
>
<el-checkbox
:model-value="f.isCheck"
@click.stop
@change="(v) => (f.isCheck = !!v)"
/>
</FriendItem>
</el-scrollbar>
</div>
<div class="flex items-center text-lg text-[#409eff]">
<el-icon><DArrowRight /></el-icon>
</div>
<div class="flex flex-col flex-1 overflow-hidden rounded border border-[var(--el-border-color)]">
<div
class="h-10 pl-2.5 leading-10 text-13px text-[var(--el-text-color-secondary)] border-b border-[var(--el-border-color-lighter)]"
>
已勾选 {{ checkedFriends.length }} 位好友
</div>
<el-scrollbar class="h-[400px]">
<FriendItem
v-for="f in checkedFriends"
:key="f.id"
:friend="f"
:menu="false"
:active="false"
/>
</el-scrollbar>
</div>
</div>
</div>
<template #footer>
<el-button @click="visible = false">取 消</el-button>
<el-button type="primary" :loading="submitting" @click="handleOk"> </el-button>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
import { Search, DArrowRight } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { createGroup } from '@/api/im/group'
import { inviteGroupMember } from '@/api/im/group/member'
import FriendItem, { type FriendLite } from '../../friend/components/FriendItem.vue'
defineOptions({ name: 'ImCreateGroupDialog' })
interface FriendCheckable extends FriendLite {
isCheck?: boolean
}
const props = withDefaults(
defineProps<{
modelValue: boolean
/** 全量好友(由调用方从 friendStore 传入) */
friends?: FriendLite[]
}>(),
{
friends: () => []
}
)
const emit = defineEmits<{
'update:modelValue': [value: boolean]
/** 创建成功,携带新群编号 */
created: [groupId: number]
}>()
const visible = computed({
get: () => props.modelValue,
set: (v) => emit('update:modelValue', v)
})
const groupName = ref('')
const searchText = ref('')
const submitting = ref(false)
/** 工作副本(带 isCheck 标记),与 prop 隔离 */
const workingFriends = ref<FriendCheckable[]>([])
watch(
visible,
(v) => {
if (!v) {
return
}
groupName.value = ''
searchText.value = ''
workingFriends.value = props.friends
.filter((f) => !f.deleted)
.map((f) => ({ ...f, isCheck: false }))
},
{ immediate: true }
)
const shownFriends = computed(() =>
workingFriends.value.filter((f) => f.nickname.includes(searchText.value))
)
const checkedFriends = computed(() => workingFriends.value.filter((f) => f.isCheck))
function toggleCheck(f: FriendCheckable) {
f.isCheck = !f.isCheck
}
async function handleOk() {
const name = groupName.value.trim()
if (!name) {
ElMessage.warning('请输入群名称')
return
}
const memberUserIds = checkedFriends.value.map((f) => f.id)
if (memberUserIds.length === 0) {
ElMessage.warning('请至少选择一位好友')
return
}
submitting.value = true
try {
const group = await createGroup({ name })
if (!group?.id) {
throw new Error('创建群失败:未返回群编号')
}
await inviteGroupMember({ groupId: group.id, memberUserIds })
ElMessage.success('群聊创建成功')
emit('created', group.id)
visible.value = false
} catch (e: any) {
console.error('[IM] 创建群失败', e)
ElMessage.error(e?.message || '创建群失败')
} finally {
submitting.value = false
}
}
</script>