| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { FriendLite } from '../../types' |
| | | |
| | | import { computed, ref } from 'vue' |
| | | |
| | | import { Button, message, Modal } from 'ant-design-vue' |
| | | |
| | | import { createGroup } from '#/api/im/group' |
| | | |
| | | import { buildDefaultGroupName } from '../../../utils/group' |
| | | import { useFriendStore } from '../../store/friendStore' |
| | | import { useGroupStore } from '../../store/groupStore' |
| | | import { FriendPickerPanel } from '../picker' |
| | | |
| | | defineOptions({ name: 'ImGroupCreateDialog' }) |
| | | |
| | | const emit = defineEmits<{ |
| | | /** å建æåï¼æºå¸¦æ°ç¾¤ç¼å·ï¼ç¶ä¾§éå¸¸ç¨æ¥è·³è½¬å°æ°ç¾¤ä¼è¯ */ |
| | | created: [groupId: number] |
| | | }>() |
| | | |
| | | const friendStore = useFriendStore() |
| | | const groupStore = useGroupStore() |
| | | |
| | | const visible = ref(false) |
| | | const submitting = ref(false) |
| | | const lockedIds = ref<number[]>([]) |
| | | const selectedIds = ref<number[]>([]) |
| | | |
| | | defineExpose({ |
| | | /** æå¼å起群èå¼¹çªï¼reset â çå â visible=true */ |
| | | open(opts?: { lockedIds?: number[] }) { |
| | | lockedIds.value = opts?.lockedIds ? [...opts.lockedIds] : [] |
| | | selectedIds.value = [] |
| | | submitting.value = false |
| | | visible.value = true |
| | | } |
| | | }) |
| | | |
| | | /** å
¨é好åï¼ç´æ¥å¤ç¨ friendStore Lite è§å¾ï¼å¸¦æ¼é³å段ä¾åæ¡¶ç¨ï¼ */ |
| | | const friends = computed<FriendLite[]>(() => friendStore.getActiveFriendLiteList) |
| | | |
| | | /** 宿æé®å¯ç¹ï¼è³å°æ 1 个é locked å¾éï¼locked æ¯å
¥å£éå®é¡¹ï¼ä¸ç®"ç¨æ·ä¸»å¨éæ©"ï¼ */ |
| | | const canSubmit = computed(() => selectedIds.value.length > 0) |
| | | |
| | | /** æ¿å°ææè¦è¿ç¾¤ç好åï¼locked + selectedï¼ï¼å»ºç¾¤é»è®¤ç¾¤åæè¿æ¹äººçæ */ |
| | | function resolveMembersToInvite(): FriendLite[] { |
| | | const seen = new Set<number>() |
| | | const result: FriendLite[] = [] |
| | | const byId = new Map(friends.value.map((f) => [f.id, f])) |
| | | for (const id of lockedIds.value) { |
| | | if (seen.has(id)) { |
| | | continue |
| | | } |
| | | const friend = byId.get(id) |
| | | if (friend) { |
| | | seen.add(id) |
| | | result.push(friend) |
| | | } |
| | | } |
| | | for (const id of selectedIds.value) { |
| | | if (seen.has(id)) { |
| | | continue |
| | | } |
| | | const friend = byId.get(id) |
| | | if (friend) { |
| | | seen.add(id) |
| | | result.push(friend) |
| | | } |
| | | } |
| | | return result |
| | | } |
| | | |
| | | /** å建群èï¼å»ºç¾¤ï¼åæ¶é请åå§æåï¼â upsert groupStore â emit created 让ç¶é¡µè·³è½¬æ°ä¼è¯ */ |
| | | async function handleOk() { |
| | | const members = resolveMembersToInvite() |
| | | if (members.length === 0) { |
| | | return |
| | | } |
| | | submitting.value = true |
| | | try { |
| | | const memberUserIds = members.map((m) => m.id) |
| | | const name = buildDefaultGroupName(members) |
| | | const group = await createGroup({ name, memberUserIds, joinApproval: false }) |
| | | if (!group?.id) { |
| | | throw new Error('åå»ºç¾¤å¤±è´¥ï¼æªè¿å群ç¼å·') |
| | | } |
| | | // ç´æ¥ upsert è¿ groupStoreï¼ç䏿¬¡ fetchGroupList ââ æå¡ç«¯è¿å VO å·²ç»å¤å»ºä¼è¯äº |
| | | groupStore.upsertGroup({ |
| | | id: group.id, |
| | | name: group.name, |
| | | avatar: group.avatar, |
| | | notice: group.notice, |
| | | ownerUserId: group.ownerUserId |
| | | }) |
| | | message.success('群èå建æå') |
| | | emit('created', group.id) |
| | | visible.value = false |
| | | } finally { |
| | | submitting.value = false |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <!-- |
| | | å起群èï¼é好å â é»è®¤ææéæååçæç¾¤å â createGroup |
| | | - dialog 壳æ¬ç»ä»¶ææï¼éæ© UI å§æ FriendPickerPanel |
| | | - lockedIds ç±è°ç¨æ¹éè¿ open({ lockedIds }) ä¼ å
¥ï¼ç§èä¾§ +建群éå®å¯¹æ¹ |
| | | - ä¸åè¦æ±å
è¾å
¥ç¾¤å / ä¸åå±ç¤ºãè¿ç¾¤å®¡æ¹ãå¼å
³ï¼å¯¹é½å¾®ä¿¡ PC |
| | | - 坹夿¥å£ï¼ref + open({ lockedIds }) + emit created(groupId) |
| | | --> |
| | | <Modal |
| | | v-model:open="visible" |
| | | title="å起群è" |
| | | width="720px" |
| | | :mask-closable="false" |
| | | class="im-picker-dialog" |
| | | > |
| | | <div class="h-[480px]"> |
| | | <FriendPickerPanel |
| | | v-model:selected-ids="selectedIds" |
| | | :friends="friends" |
| | | :locked-ids="lockedIds" |
| | | /> |
| | | </div> |
| | | |
| | | <template #footer> |
| | | <Button @click="visible = false">åæ¶</Button> |
| | | <Button type="primary" :loading="submitting" :disabled="!canSubmit" @click="handleOk"> |
| | | 宿 |
| | | </Button> |
| | | </template> |
| | | </Modal> |
| | | </template> |
| | | |
| | | <style scoped lang="scss"> |
| | | @use '../picker/picker-dialog' as picker; |
| | | |
| | | /* :deep ç©¿é el-dialog å
é¨ç±»ï¼å¤ç¨ picker å
Œ
± mixin */ |
| | | .im-picker-dialog { |
| | | @include picker.styles; |
| | | } |
| | | </style> |