From c5b8466b398f433b6a36e4099c403c5ff59a74b5 Mon Sep 17 00:00:00 2001 From: Kkuil317 <102936058+Kkuil@users.noreply.github.com> Date: Tue, 14 Nov 2023 19:11:20 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=98=BE=E7=A4=BA=E5=B0=8F=E5=8D=A1?= =?UTF-8?q?=E7=89=87=E5=8A=9F=E8=83=BD=20(#110)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constant/message.ts | 12 +++ src/stores/chat.ts | 13 +++ src/stores/group.ts | 9 ++- src/utils/renderReplyContent.ts | 11 +-- .../MsgItem/components/UserCard/UserCard.vue | 80 +++++++++++++++++++ .../MsgItem/components/UserCard/styles.scss | 60 ++++++++++++++ .../components/ChatList/MsgItem/index.vue | 15 +++- .../DeadZoneSetting/DeadZoneSetting.vue | 12 ++- .../Home/components/PostCard/PostCard.vue | 28 +++++++ .../Home/components/PostCard/styles.scss | 29 +++++++ src/views/Home/index.vue | 26 +++++- 11 files changed, 281 insertions(+), 14 deletions(-) create mode 100644 src/constant/message.ts create mode 100644 src/views/Home/Chat/components/ChatList/MsgItem/components/UserCard/UserCard.vue create mode 100644 src/views/Home/Chat/components/ChatList/MsgItem/components/UserCard/styles.scss create mode 100644 src/views/Home/components/PostCard/PostCard.vue create mode 100644 src/views/Home/components/PostCard/styles.scss diff --git a/src/constant/message.ts b/src/constant/message.ts new file mode 100644 index 00000000..277e8cc6 --- /dev/null +++ b/src/constant/message.ts @@ -0,0 +1,12 @@ +import { MsgEnum } from '@/enums' + +// 消息回复映射表 +export const MSG_REPLY_TEXT_MAP: Record = { + [MsgEnum.UNKNOWN]: '[未知]', + [MsgEnum.RECALL]: '[撤回消息]', + [MsgEnum.IMAGE]: '[图片]', + [MsgEnum.FILE]: '[文件]', + [MsgEnum.VOICE]: '[语音]', + [MsgEnum.VIDEO]: '[音频]', + [MsgEnum.EMOJI]: '[表情]', +} diff --git a/src/stores/chat.ts b/src/stores/chat.ts index c7d938f0..da316905 100644 --- a/src/stores/chat.ts +++ b/src/stores/chat.ts @@ -263,6 +263,11 @@ export const useChatStore = defineStore('chat', () => { sortAndUniqueSessionList() } + // 通过房间ID获取会话信息 + const getSession = (roomId: number): SessionItem => { + return sessionList.find((item) => item.roomId === roomId) as SessionItem + } + const pushMsg = async (msg: MessageType) => { const current = messageMap.get(msg.message.roomId) current?.set(msg.message.id, msg) @@ -430,6 +435,12 @@ export const useChatStore = defineStore('chat', () => { return currentMessageMap.value?.get(messageId) } + // 删除会话 + const removeContact = (roomId: number) => { + const index = sessionList.findIndex((session) => session.roomId === roomId) + sessionList.splice(index, 1) + } + return { getMsgIndex, chatMessageList, @@ -455,8 +466,10 @@ export const useChatStore = defineStore('chat', () => { updateSession, updateSessionLastActiveTime, markSessionRead, + getSession, isGroup, currentSessionInfo, getMessage, + removeContact, } }) diff --git a/src/stores/group.ts b/src/stores/group.ts index f8623422..facb17f9 100644 --- a/src/stores/group.ts +++ b/src/stores/group.ts @@ -3,7 +3,7 @@ import apis from '@/services/apis' import { defineStore } from 'pinia' import { useGlobalStore } from '@/stores/global' import type { GroupDetailReq, UserItem } from '@/services/types' -import { pageSize } from './chat' +import { pageSize, useChatStore } from './chat' import cloneDeep from 'lodash/cloneDeep' import { OnlineEnum, RoleEnum } from '@/enums' import { uniqueUserList } from '@/utils/unique' @@ -28,6 +28,7 @@ export const useGroupStore = defineStore('group', () => { const cachedStore = useCachedStore() const globalStore = useGlobalStore() const userStore = useUserStore() + const chatStore = useChatStore() // 消息列表 const userList = ref([]) const userListOptions = reactive({ isLast: false, loading: true, cursor: '' }) @@ -184,6 +185,12 @@ export const useGroupStore = defineStore('group', () => { // 更新群成员列表 const index = userList.value.findIndex((user) => user.uid === userStore.userInfo.uid) userList.value.splice(index, 1) + + // 更新会话列表 + chatStore.removeContact(currentRoomId.value) + + // 切换为第一个会话 + globalStore.currentSession.roomId = chatStore.sessionList[0].roomId } return { diff --git a/src/utils/renderReplyContent.ts b/src/utils/renderReplyContent.ts index d4be9829..d2239acf 100644 --- a/src/utils/renderReplyContent.ts +++ b/src/utils/renderReplyContent.ts @@ -1,4 +1,5 @@ import { MsgEnum } from '@/enums' +import { MSG_REPLY_TEXT_MAP } from '@/constant/message' // 计算展示的回复消息的内容 const renderReplyContent = (name?: string, type?: MsgEnum, content?: string) => { @@ -8,19 +9,19 @@ const renderReplyContent = (name?: string, type?: MsgEnum, content?: string) => return `${name}:${content}` } case MsgEnum.IMAGE: { - return `${name}: [图片]` + return `${name}: ${MSG_REPLY_TEXT_MAP[MsgEnum.IMAGE]}` } case MsgEnum.FILE: { - return `${name}: [文件]` + return `${name}: ${MSG_REPLY_TEXT_MAP[MsgEnum.FILE]}` } case MsgEnum.VOICE: { - return `${name}: [语音]` + return `${name}: ${MSG_REPLY_TEXT_MAP[MsgEnum.VOICE]}` } case MsgEnum.VIDEO: { - return `${name}: [视频]` + return `${name}: ${MSG_REPLY_TEXT_MAP[MsgEnum.VIDEO]}` } case MsgEnum.EMOJI: { - return `${name}: [表情]` + return `${name}: ${MSG_REPLY_TEXT_MAP[MsgEnum.EMOJI]}` } default: { return '' diff --git a/src/views/Home/Chat/components/ChatList/MsgItem/components/UserCard/UserCard.vue b/src/views/Home/Chat/components/ChatList/MsgItem/components/UserCard/UserCard.vue new file mode 100644 index 00000000..90fb359e --- /dev/null +++ b/src/views/Home/Chat/components/ChatList/MsgItem/components/UserCard/UserCard.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/src/views/Home/Chat/components/ChatList/MsgItem/components/UserCard/styles.scss b/src/views/Home/Chat/components/ChatList/MsgItem/components/UserCard/styles.scss new file mode 100644 index 00000000..d389b80a --- /dev/null +++ b/src/views/Home/Chat/components/ChatList/MsgItem/components/UserCard/styles.scss @@ -0,0 +1,60 @@ +.user-card { + position: absolute; + top: 0; + left: 0; + width: 200px; + padding: 10px; + background-color: var(--background-wrapper); + border-radius: 8px; + box-shadow: 1px 1px 5px 1px var(--background-2); + + &_top { + display: flex; + padding-bottom: 10px; + border-bottom: 1px solid var(--background-secondary); + + &-avatar { + width: 35%; + } + + &-info { + width: 65%; + font-size: 13px; + + &_name { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + } + + &_badge { + display: flex; + justify-content: space-between; + padding: 5px 0; + + &-item { + width: 25px; + height: 25px; + } + } + + &_other { + display: flex; + align-items: center; + + &-item { + display: flex; + flex-direction: column; + align-items: center; + min-height: 60px; + font-size: 10px; + cursor: pointer; + + &:hover { + color: var(--hover-primary); + } + } + } +} diff --git a/src/views/Home/Chat/components/ChatList/MsgItem/index.vue b/src/views/Home/Chat/components/ChatList/MsgItem/index.vue index c6a83279..e1b46ad7 100644 --- a/src/views/Home/Chat/components/ChatList/MsgItem/index.vue +++ b/src/views/Home/Chat/components/ChatList/MsgItem/index.vue @@ -4,7 +4,7 @@ import { useUserStore } from '@/stores/user' import { pageSize, useChatStore } from '@/stores/chat' import { formatTimestamp } from '@/utils/computedTime' import { useBadgeInfo, useUserInfo } from '@/hooks/useCached' -import type { MessageType, MsgType } from '@/services/types' +import type { CacheUserItem, MessageType, MsgType } from '@/services/types' import { useElementVisibility } from '@vueuse/core' import type { TooltipTriggerType } from 'element-plus/es/components/tooltip/src/trigger' import { useLikeToggle } from '@/hooks/useLikeToggle' @@ -15,6 +15,7 @@ import { useGlobalStore } from '@/stores/global' import MsgOption from '../MsgOption/index.vue' import ContextMenu from '../ContextMenu/index.vue' import UserContextMenu from '../UserContextMenu/index.vue' +import UserCard from '@/views/Home/Chat/components/ChatList/MsgItem/components/UserCard/UserCard.vue' const props = withDefaults( defineProps<{ @@ -185,8 +186,16 @@ const currentReadList = (msgId: number) => {
- - + + + +
diff --git a/src/views/Home/components/PostCard/PostCard.vue b/src/views/Home/components/PostCard/PostCard.vue new file mode 100644 index 00000000..08e1295b --- /dev/null +++ b/src/views/Home/components/PostCard/PostCard.vue @@ -0,0 +1,28 @@ + + + + + diff --git a/src/views/Home/components/PostCard/styles.scss b/src/views/Home/components/PostCard/styles.scss new file mode 100644 index 00000000..55c23247 --- /dev/null +++ b/src/views/Home/components/PostCard/styles.scss @@ -0,0 +1,29 @@ +.post-confirm_box { + padding: 0 10px 10px; + + .contact-info { + display: flex; + align-items: center; + + .session-avatar { + width: 40px; + height: 40px; + margin-right: 10px; + border-radius: 10px; + } + } + + .msg-body { + display: -webkit-box; + width: 100%; + height: 70px; + padding: 5px 10px; + margin-top: 10px; + overflow: hidden; + text-overflow: ellipsis; + word-break: break-word; + background-color: var(--background-dark); + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + } +} diff --git a/src/views/Home/index.vue b/src/views/Home/index.vue index 1f985bde..e30b284d 100644 --- a/src/views/Home/index.vue +++ b/src/views/Home/index.vue @@ -2,7 +2,7 @@ import ToolBar from './components/ToolBar/index.vue' import { useImgPreviewStore, useVideoPreviewStore } from '@/stores/preview' import { useUserStore } from '@/stores/user' -import { onMounted, onUnmounted, ref, watch } from 'vue' +import { h, onMounted, onUnmounted, ref, watch } from 'vue' import { RouterView } from 'vue-router' import AddFriendModal from '@/components/AddFriendModal/index.vue' import MsgReadModal from '@/components/MsgReadModal/index.vue' @@ -11,11 +11,13 @@ import { clearListener, initListener, readCountQueue } from '@/utils/readCountQu import { useChatStore } from '@/stores/chat' import { ElMessageBox } from 'element-plus' import apis from '@/services/apis' +import PostCard from './components/PostCard/PostCard.vue' type TContainerDListener = { messageId: number | null dragStart: (e: DragEvent) => any dragOver: (e: DragEvent) => any + dragLeave: (e: DragEvent) => any drop: (e: DragEvent) => any } @@ -61,18 +63,32 @@ const containerDragListener: TContainerDListener = { }, dragOver(e) { e.preventDefault() + const target = e.target as HTMLDivElement + if (target.dataset.roomId) { + target.style.backgroundColor = 'var(--hover-bg-1)' + } + }, + dragLeave(e) { + e.preventDefault() + const target = e.target as HTMLDivElement + if (target.dataset.roomId) { + target.style.backgroundColor = '' + } }, drop(e) { const target = e.target as HTMLDivElement if (target.dataset.roomId && this.messageId) { + target.style.backgroundColor = '' // 获取消息体 const message = chatStore.getMessage(Number(this.messageId)) - if (message) { + const session = chatStore.getSession(Number(target.dataset.roomId)) + if (message && session) { // 发送消息 - ElMessageBox.confirm('是否发送该消息?', '消息', { + ElMessageBox.confirm(h(PostCard, { session, message }), '发送给: ', { confirmButtonText: '确定', cancelButtonText: '取消', - type: 'success', + draggable: true, + dangerouslyUseHTMLString: true, }).then(() => { // 发送消息 apis @@ -97,11 +113,13 @@ const containerDragListener: TContainerDListener = { const initListeners = () => { container.value?.addEventListener('dragstart', containerDragListener.dragStart) container.value?.addEventListener('dragover', containerDragListener.dragOver) + container.value?.addEventListener('dragleave', containerDragListener.dragLeave) container.value?.addEventListener('drop', containerDragListener.drop) } const removeListeners = () => { container.value?.removeEventListener('dragstart', containerDragListener.dragStart) container.value?.removeEventListener('dragover', containerDragListener.dragOver) + container.value?.removeEventListener('dragleave', containerDragListener.dragLeave) container.value?.removeEventListener('drop', containerDragListener.drop) }