Skip to content

Commit

Permalink
feat: 新增撤销管理员和退群功能 (#107)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kkuil authored Nov 2, 2023
1 parent 40b26cd commit 1181c89
Show file tree
Hide file tree
Showing 21 changed files with 349 additions and 150 deletions.
1 change: 1 addition & 0 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ declare module '@vue/runtime-core' {
ElIcon: typeof import('element-plus/es')['ElIcon']
ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
ElInput: typeof import('element-plus/es')['ElInput']
ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
ElPopover: typeof import('element-plus/es')['ElPopover']
ElProgress: typeof import('element-plus/es')['ElProgress']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
Expand Down
2 changes: 1 addition & 1 deletion src/components/RenderMessage/emoji.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const handleError = () => {
加载失败
</div>
<template v-else>
<img v-if="body?.url" :src="body?.url" @error="handleError" />
<img v-if="body?.url" :src="body?.url" @error="handleError" :alt="body.url" />
</template>
</div>
</template>
10 changes: 6 additions & 4 deletions src/components/RenderMessage/file.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { computed } from 'vue'
import { Close } from '@element-plus/icons-vue'
import { getFileSuffix, formatBytes } from '@/utils'
import { formatBytes, getFileSuffix } from '@/utils'
import type { FileBody } from '@/services/types'
import useDownloadQuenuStore from '@/stores/downloadQuenu'
Expand Down Expand Up @@ -41,9 +41,11 @@ const isQuenu = computed(() => {
<span class="file-name">{{ body?.fileName || '未知文件' }}</span>
<span class="file-size">{{ formatBytes(body?.size) }}</span>
</div>
<el-text v-if="isQuenu" class="mx-1" size="small" type="warning" @click="cancelDownloadFile"
>等待下载
<el-icon><Close /></el-icon>
<el-text v-if="isQuenu" class="mx-1" size="small" type="warning" @click="cancelDownloadFile">
等待下载
<el-icon>
<Close />
</el-icon>
</el-text>
<Icon v-else-if="!isDownloading" icon="xiazai" :size="22" @click="downloadFile" />
<el-progress
Expand Down
11 changes: 8 additions & 3 deletions src/components/RenderMessage/image.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import { computed, ref } from 'vue'
import type { ImageBody } from '@/services/types'
import { useImgPreviewStore } from '@/stores/preview'
import { formatImage } from '@/utils'
Expand Down Expand Up @@ -33,7 +33,11 @@ const handleError = () => {
</script>

<template>
<div class="image" :style="{ height: getImageHeight + 'px' }" @click="imageStore.show(body?.url)">
<div
class="image"
:style="{ height: getImageHeight + 'px' }"
@click="imageStore.show(body?.url as string)"
>
<div v-if="hasLoadError" class="image-slot" :style="getWidthStyle()">
<Icon icon="dazed" :size="36" colorful />
加载失败
Expand All @@ -42,8 +46,9 @@ const handleError = () => {
<img
v-if="body?.url"
:src="body?.url"
@click="imageStore.show(body?.url)"
@click="imageStore.show(body?.url as string)"
@error="handleError"
:alt="body?.url"
/>
</template>
</div>
Expand Down
10 changes: 9 additions & 1 deletion src/components/RenderMessage/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import File from './file.vue'
import Video from './video.vue'
import Text from './text.vue'
import Emoji from './emoji.vue'
import { useUserStore } from '@/stores/user'
const componentMap = {
[MsgEnum.UNKNOWN]: '',
Expand All @@ -20,9 +21,16 @@ const componentMap = {
[MsgEnum.EMOJI]: Emoji,
}
const userStore = useUserStore()
defineProps<{ message: MsgType }>()
</script>

<template>
<component :is="componentMap[message.type]" :body="message.body" />
<component
:is="componentMap[message.type]"
:body="message.body"
:data-messasge-id="message.id"
:draggable="userStore.isSign ? 'true' : 'false'"
/>
</template>
1 change: 1 addition & 0 deletions src/components/RenderMessage/text.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const openUrl = (url: string) => {
// 当没有协议时,自动添加协议
window.open(url.startsWith('http') ? url : '//' + url, '_blank')
}
function onImageLoadError(e: Event) {
const target = e.target as HTMLImageElement
if (!target) return
Expand Down
3 changes: 1 addition & 2 deletions src/components/RenderMessage/video.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { formatImage } from '@/utils'
const props = defineProps<{ body: VideoBody }>()
const videoStore = useVideoPreviewStore()
const getImageHeight = () => {
const width = props.body.thumbWidth || 0
const height = props.body.thumbHeight || 0
Expand All @@ -17,6 +16,6 @@ const getImageHeight = () => {
<template>
<div class="video" :style="`height:${getImageHeight()}px`" @click="videoStore.open(body?.url)">
<Icon icon="bofang" :size="30" />
<img :src="body.thumbUrl" />
<img :src="body.thumbUrl" :alt="body.thumbUrl" />
</div>
</template>
35 changes: 23 additions & 12 deletions src/services/apis.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import type {
ListResponse,
UserItem,
GroupStatisticType,
MessageType,
MarkMsgReq,
UserInfoType,
BadgeType,
MessageReq,
CacheUserItem,
CacheBadgeItem,
CacheUserReq,
CacheBadgeReq,
CacheUserItem,
CacheUserReq,
ContactItem,
EmojiItem,
GroupDetailReq,
GroupStatisticType,
ListResponse,
MarkMsgReq,
MessageReq,
MessageType,
MsgReadUnReadCountType,
RequestFriendItem,
ContactItem,
SessionItem,
MsgReadUnReadCountType,
GroupDetailReq,
UserInfoType,
UserItem,
} from '@/services/types'
import { alovaIns } from './request'
import urls from './urls'
Expand Down Expand Up @@ -119,4 +119,15 @@ export default {
roomId,
uidList,
}),
/** 撤销群管理 */
revokeAdmin: ({ roomId, uidList }: { roomId: number; uidList: number[] }) =>
deleteRequest<Boolean>(urls.revokeAdmin, {
roomId,
uidList,
}),
/** 退群 */
exitGroup: ({ roomId }: { roomId: number }) =>
deleteRequest<Boolean>(urls.exitGroup, {
roomId,
}),
}
2 changes: 2 additions & 0 deletions src/services/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export default {
createGroup: `${prefix}/capi/room/group`, // 新增群组
getGroupUserList: `${prefix}/capi/room/public/group/member/page`,
inviteGroupMember: `${prefix}/capi/room/group/member`, // 邀请群成员
exitGroup: `${prefix}/capi/room/group/member`, // 退群
addAdmin: `${prefix}/capi/room/group/admin`, // 添加管理员
revokeAdmin: `${prefix}/capi/room/group/admin`, // 添加管理员
groupDetail: `${prefix}/capi/room/public/group`, // 群组详情
sessionDetail: `${prefix}/capi/chat/public/contact/detail`, // 会话详情
sessionDetailWithFriends: `${prefix}/capi/chat/public/contact/detail/friend`, // 会话详情(联系人列表发消息用)
Expand Down
16 changes: 10 additions & 6 deletions src/stores/chat.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { ref, reactive, computed, watch } from 'vue'
import { computed, reactive, ref, watch } from 'vue'
import { defineStore } from 'pinia'
import cloneDeep from 'lodash/cloneDeep'
import { useRoute } from 'vue-router'
// import Router from '@/router'
import apis from '@/services/apis'
import type { MessageType, MarkItemType, RevokedMsgType, SessionItem } from '@/services/types'
import { MarkEnum, RoomTypeEnum } from '@/enums'
import type { MarkItemType, MessageType, RevokedMsgType, SessionItem } from '@/services/types'
import { MarkEnum, MsgEnum, RoomTypeEnum } from '@/enums'
import { computedTimeBlock } from '@/utils/computedTime'
import { useCachedStore } from '@/stores/cached'
import { useUserStore } from '@/stores/user'
Expand All @@ -14,7 +13,6 @@ import { useGroupStore } from '@/stores/group'
import { useContactStore } from '@/stores/contacts'
import shakeTitle from '@/utils/shakeTitle'
import notify from '@/utils/notification'
import { MsgEnum } from '@/enums'

export const pageSize = 20
// 标识是否第一次请求
Expand Down Expand Up @@ -286,7 +284,7 @@ export const useChatStore = defineStore('chat', () => {
if (!current) {
result = await apis.sessionDetail({ id: msg.message.roomId }).send()
}
// Router.push('/')
// Router.push('/')
// }
updateSessionLastActiveTime(msg.message.roomId, result)
}
Expand Down Expand Up @@ -427,6 +425,11 @@ export const useChatStore = defineStore('chat', () => {
return unreadCount
}

// 根据消息id获取消息体
const getMessage = (messageId: number) => {
return currentMessageMap.value?.get(messageId)
}

return {
getMsgIndex,
chatMessageList,
Expand Down Expand Up @@ -454,5 +457,6 @@ export const useChatStore = defineStore('chat', () => {
markSessionRead,
isGroup,
currentSessionInfo,
getMessage,
}
})
10 changes: 1 addition & 9 deletions src/stores/contacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@ import { reactive } from 'vue'
import { defineStore } from 'pinia'
import apis from '@/services/apis'
import { useGlobalStore } from '@/stores/global'
import { RequestFriendAgreeStatus } from '@/services/types'
import type { ContactItem, RequestFriendItem } from '@/services/types'
import { RequestFriendAgreeStatus } from '@/services/types'

export const pageSize = 20

export const useContactStore = defineStore('contact', () => {
const globalStore = useGlobalStore()
const contactsList = reactive<ContactItem[]>([])
const requestFriendsList = reactive<RequestFriendItem[]>([])

const contactsOptions = reactive({ isLast: false, isLoading: false, cursor: '' })
const requestFriendsOptions = reactive({ isLast: false, isLoading: false, cursor: '' })

const getContactList = async (isFresh = false) => {
if (!isFresh) {
if (contactsOptions.isLast || contactsOptions.isLoading) return
Expand Down Expand Up @@ -76,11 +73,9 @@ export const useContactStore = defineStore('contact', () => {
requestFriendsOptions.isLast = data.isLast
requestFriendsOptions.isLoading = false
}

// 默认执行一次
// getContactList()
// getRequestFriendsList()

/** 接受好友请求 */
const onAcceptFriend = (applyId: number) => {
// 同意好友申请
Expand All @@ -92,15 +87,13 @@ export const useContactStore = defineStore('contact', () => {
getRequestFriendsList(true)
// 刷新好友列表
getContactList(true)

// 标识为可以发消息的人
if (globalStore.currentSelectedContact) {
// @ts-ignore
globalStore.currentSelectedContact.status = RequestFriendAgreeStatus.Agree
}
})
}

/** 删除好友 */
const onDeleteContact = async (uid: number) => {
if (!uid) return
Expand All @@ -111,7 +104,6 @@ export const useContactStore = defineStore('contact', () => {
// 刷新好友列表
getContactList(true)
}

return {
getContactList,
getRequestFriendsList,
Expand Down
31 changes: 31 additions & 0 deletions src/stores/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import cloneDeep from 'lodash/cloneDeep'
import { OnlineEnum, RoleEnum } from '@/enums'
import { uniqueUserList } from '@/utils/unique'
import { useCachedStore } from '@/stores/cached'
import { useUserStore } from '@/stores/user'

const sorAction = (pre: UserItem, next: UserItem) => {
if (pre.activeStatus === OnlineEnum.ONLINE && next.activeStatus === OnlineEnum.ONLINE) {
Expand All @@ -26,6 +27,7 @@ const sorAction = (pre: UserItem, next: UserItem) => {
export const useGroupStore = defineStore('group', () => {
const cachedStore = useCachedStore()
const globalStore = useGlobalStore()
const userStore = useUserStore()
// 消息列表
const userList = ref<UserItem[]>([])
const userListOptions = reactive({ isLast: false, loading: true, cursor: '' })
Expand Down Expand Up @@ -158,6 +160,32 @@ export const useGroupStore = defineStore('group', () => {
})
}

/**
* 撤销管理员
* @param uidList
*/
const revokeAdmin = async (uidList: number[]) => {
await apis.revokeAdmin({ roomId: currentRoomId.value, uidList }).send()

// 更新群成员列表
userList.value.forEach((user) => {
if (uidList.includes(user.uid)) {
user.roleId = RoleEnum.NORMAL
}
})
}

/**
* 退出群聊
*/
const exitGroup = async () => {
await apis.exitGroup({ roomId: currentRoomId.value }).send()

// 更新群成员列表
const index = userList.value.findIndex((user) => user.uid === userStore.userInfo.uid)
userList.value.splice(index, 1)
}

return {
userList,
userListOptions,
Expand All @@ -169,8 +197,11 @@ export const useGroupStore = defineStore('group', () => {
batchUpdateUserStatus,
showGroupList,
filterUser,
adminUidList,
adminList,
memberList,
addAdmin,
revokeAdmin,
exitGroup,
}
})
10 changes: 6 additions & 4 deletions src/views/Home/Chat/components/ChatList/MsgItem/index.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script setup lang="ts">
import { computed, nextTick, onMounted, ref, type Ref, inject, watch, reactive } from 'vue'
import { computed, inject, nextTick, onMounted, reactive, ref, type Ref, watch } from 'vue'
import { useUserStore } from '@/stores/user'
import { useChatStore, pageSize } from '@/stores/chat'
import { pageSize, useChatStore } from '@/stores/chat'
import { formatTimestamp } from '@/utils/computedTime'
import { useUserInfo, useBadgeInfo } from '@/hooks/useCached'
import { useBadgeInfo, useUserInfo } from '@/hooks/useCached'
import type { MessageType, MsgType } from '@/services/types'
import { useElementVisibility } from '@vueuse/core'
import type { TooltipTriggerType } from 'element-plus/es/components/tooltip/src/trigger'
Expand Down Expand Up @@ -240,7 +240,9 @@ const currentReadList = (msgId: number) => {
<span class="chat-item-read-count-text" v-if="readCount.unread !== 0">
{{ readCount.read }}
</span>
<el-icon v-else><IEpCheck /></el-icon>
<el-icon v-else>
<IEpCheck />
</el-icon>
</div>
<!-- 消息加载中 -->
<Icon v-if="msg?.loading" icon="loading" :size="20" spin />
Expand Down
Loading

0 comments on commit 1181c89

Please sign in to comment.