|
@@ -0,0 +1,294 @@
|
|
|
+<template>
|
|
|
+ <div class="single-page h-full w-full" style="height: 100vh">
|
|
|
+ <van-nav-bar @click-left="router.back()" @click-right="onClickRight">
|
|
|
+ <template #left>
|
|
|
+ <div>
|
|
|
+ <van-icon name="arrow-left" color="black" size="18"/>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template #title>
|
|
|
+ <div class="text-2xl text-black-3 text-semibold">
|
|
|
+ <div class="inline-block w-220 line-clamp-1">
|
|
|
+ {{ title }}
|
|
|
+ </div>
|
|
|
+ <!-- <span class="ml-7 iconfont icon-close-remind text-black-9" style="font-size: 16px"></span> -->
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template #right>
|
|
|
+ <van-icon name="ellipsis" color="black" size="18"/>
|
|
|
+ </template>
|
|
|
+ </van-nav-bar>
|
|
|
+ <template v-if="showPage">
|
|
|
+ <van-list
|
|
|
+ ref="chatListRef"
|
|
|
+ class="flex-1 overflow-y-auto px-12 flex flex-col"
|
|
|
+ :finished="true"
|
|
|
+ finished-text=""
|
|
|
+ >
|
|
|
+ <template v-for="(message, index) in currConversationChatList" :key="index">
|
|
|
+ <ChatMessage :show-name="true" :message="message" ></ChatMessage>
|
|
|
+ </template>
|
|
|
+ </van-list>
|
|
|
+ <!-- <van-pull-refresh v-model="refreshing" @refresh="loadMore" class="flex-1">
|
|
|
+ </van-pull-refresh>-->
|
|
|
+ <!-- <div class="fixed bottom-0 left-0 right-0 w-full">-->
|
|
|
+ <ChatInput :operates="['image', 'share-group']" @focus="scrollToBottom" @send="handleSendMessage"></ChatInput>
|
|
|
+ <!-- </div>-->
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <div class="flex-1 grid place-items-center text-black-9">
|
|
|
+ <div v-if="pageLoading">创建会话中...</div>
|
|
|
+ <div v-else class="grid place-items-center">
|
|
|
+ <div v-if="groupId">创建成功</div>
|
|
|
+ <div v-else class="grid place-items-center">
|
|
|
+ <div class="mb-10">创建会话失败</div>
|
|
|
+ <van-button size="small" @click="initGroupId">点击重试</van-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script setup>
|
|
|
+import ChatMessage from './chat-message'
|
|
|
+import ChatInput from "./chat-input";
|
|
|
+import {findHyperlinks} from "~/pages/chat/chat-message/link-message/handle";
|
|
|
+import {XYWebSocket} from "~/utils/XYWebSocket";
|
|
|
+import {isValidJson} from "~/utils";
|
|
|
+
|
|
|
+const route = useRoute()
|
|
|
+const router = useRouter()
|
|
|
+
|
|
|
+const chatsStore = useChatsStore();
|
|
|
+const userInfoStore = useUserInfoStore();
|
|
|
+
|
|
|
+const {userInfo} = storeToRefs(userInfoStore);
|
|
|
+// 单聊的标题
|
|
|
+const title = computed(() => route.query.groupRemark)
|
|
|
+
|
|
|
+// 聊天列表
|
|
|
+const chatListRef = ref(null);
|
|
|
+
|
|
|
+const pageLoading = ref(true);
|
|
|
+const getUserId = ref(null); // 消息接收者的用户id
|
|
|
+const sendUserId = computed(() => userInfo?.value.pass) // 消息发送者:当前登录用户的加密id
|
|
|
+const groupId = ref(route.query?.groupId); // 会话ID
|
|
|
+const showPage = computed(() => groupId.value)
|
|
|
+
|
|
|
+const initGroupId = async () => {
|
|
|
+ try {
|
|
|
+/* if (!groupId.value) return;
|
|
|
+ pageLoading.value = true;
|
|
|
+ const res = await chatsStore.getCurrConversationId(getUserId.value)
|
|
|
+ await handleResponse(res)
|
|
|
+ groupId.value = res.data;*/
|
|
|
+ await getChatList('init')
|
|
|
+ } catch (e) {
|
|
|
+
|
|
|
+ } finally {
|
|
|
+ pageLoading.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+let pageNum = ref(0)
|
|
|
+const currConversationChatList = ref([]);
|
|
|
+/**
|
|
|
+ * 加载当前聊天信息
|
|
|
+ * @param type init|more
|
|
|
+ * @returns {Promise<void>}
|
|
|
+ */
|
|
|
+const getChatList = async (type = 'init') => {
|
|
|
+ try {
|
|
|
+ const page = type === 'init' ? 1 : pageNum.value + 1;
|
|
|
+ const res = await chatsStore.getChatHistory({
|
|
|
+ pageNum: page,
|
|
|
+ pageSize: 100,
|
|
|
+ groupId: groupId.value,
|
|
|
+ })
|
|
|
+ pageNum.value = page;
|
|
|
+ await handleResponse(res);
|
|
|
+ currConversationChatList.value = handleChatList(res.data?.data)
|
|
|
+ console.log(currConversationChatList.value, 'currConversationChatList')
|
|
|
+ if (type === 'init') await scrollToBottom()
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e)
|
|
|
+ } finally {
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+const handleChatList = (list = []) => {
|
|
|
+ return (list ?? []).filter(o => isValidJson(o.messageContent)).map(o => JSON.parse(o.messageContent));
|
|
|
+}
|
|
|
+
|
|
|
+// 发送文本消息
|
|
|
+const sendTextMessage = async (text) => {
|
|
|
+ try {
|
|
|
+ console.log(text, 'sendTextMessage')
|
|
|
+ if (!text) return
|
|
|
+ let msg = {
|
|
|
+ groupId: groupId.value,
|
|
|
+ getUserId: getUserId.value,
|
|
|
+ sendUserId: sendUserId.value,
|
|
|
+ specialUserId: '',
|
|
|
+ messageContent: text,
|
|
|
+ messageType: 0,
|
|
|
+ noticeType: 1,
|
|
|
+ object: {
|
|
|
+ id: getLocalId()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const isLink = !!findHyperlinks(text)
|
|
|
+ if (isLink) msg.messageType = 4;
|
|
|
+ currConversationChatList.value.push(msg)
|
|
|
+ await scrollToBottom()
|
|
|
+ const res = await chatsStore.sendSocketMessage(msg)
|
|
|
+ console.log('luck:', res)
|
|
|
+ } catch (e) {
|
|
|
+ console.log(e, '2')
|
|
|
+ } finally {
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 选择发送图片
|
|
|
+const sendImageMessage = async (file) => {
|
|
|
+ try {
|
|
|
+ const formData = new FormData()
|
|
|
+ formData.append('uploadFile', file)
|
|
|
+ formData.append('asImage', true)
|
|
|
+ formData.append('fieldName', 'messageContent')
|
|
|
+ const {data} = await request('/website/tourMessage/upload', {
|
|
|
+ method: 'post',
|
|
|
+ body: formData
|
|
|
+ })
|
|
|
+
|
|
|
+ let msg = {
|
|
|
+ groupId: groupId.value,
|
|
|
+ getUserId: getUserId.value,
|
|
|
+ sendUserId: sendUserId.value,
|
|
|
+ specialUserId: '',
|
|
|
+ messageContent: data.fileUrl,
|
|
|
+ messageType: 1,
|
|
|
+ noticeType: 1,
|
|
|
+ object: {
|
|
|
+ id: getLocalId()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ currConversationChatList.value.push(msg)
|
|
|
+ await scrollToBottom()
|
|
|
+ await chatsStore.sendSocketMessage(msg)
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e, '??')
|
|
|
+ } finally {
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleSendMessage = async ({type, messageContent}) => {
|
|
|
+ try {
|
|
|
+ switch (type) {
|
|
|
+ case 'text':
|
|
|
+ await sendTextMessage(messageContent)
|
|
|
+ break;
|
|
|
+ case 'image':
|
|
|
+ await sendImageMessage(messageContent)
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (e) {
|
|
|
+
|
|
|
+ } finally {
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const scrollToBottom = async () => {
|
|
|
+ setTimeout(async () => {
|
|
|
+ await nextTick(); // 确保DOM已经更新
|
|
|
+ const listElement = chatListRef.value?.$el;
|
|
|
+ if (listElement) {
|
|
|
+ const scrollContainer = listElement;
|
|
|
+ scrollContainer.scrollTop = scrollContainer.scrollHeight;
|
|
|
+ }
|
|
|
+ }, 200)
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// 加载更多
|
|
|
+const refreshing = ref(false)
|
|
|
+const loadMore = async () => {
|
|
|
+ try {
|
|
|
+ refreshing.value = true
|
|
|
+ await getChatList('more')
|
|
|
+ } catch (e) { } finally {
|
|
|
+ refreshing.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const onClickRight = () => {
|
|
|
+ navigateTo({
|
|
|
+ path: '/chat/set-single',
|
|
|
+ query: {
|
|
|
+ toUserId: route.query.getUserId
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// 本地生成一个唯一消息id
|
|
|
+function getLocalId() {
|
|
|
+ const random = Math.floor(Math.random() * 10000)
|
|
|
+ return Date.now() + '' + random
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ initGroupId()
|
|
|
+ XYWebSocket.SocketEventsBus.on(XYWebSocket.SocketEvents.chatEvent, async (chat) => {
|
|
|
+ const isCurrGroupId = chat.groupId && chat.groupId === groupId.value;
|
|
|
+ const isOtherUserMessage = chat.sendUserId && chatsStore.isRealMessage(chat.sendUserId);
|
|
|
+ if (isCurrGroupId && isOtherUserMessage) {
|
|
|
+ currConversationChatList.value.push(chat)
|
|
|
+ await scrollToBottom()
|
|
|
+ }
|
|
|
+ })
|
|
|
+})
|
|
|
+
|
|
|
+// 用户删除消息
|
|
|
+const delMessage = (messageId) => {
|
|
|
+ showConfirmDialog({
|
|
|
+ width: 260,
|
|
|
+ message: '是否删除这条消息?',
|
|
|
+ confirmButtonColor: '#FF9300'
|
|
|
+ })
|
|
|
+ .then(async () => {
|
|
|
+ const res = await request('/website/tourMessage/delMessage', {
|
|
|
+ method: 'post',
|
|
|
+ body: {
|
|
|
+ messageId: [messageId]
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ if (res && res?.success) {
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+definePageMeta({
|
|
|
+ layout: false
|
|
|
+})
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.single-page {
|
|
|
+ height: 100vh;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ min-height: 0;
|
|
|
+}
|
|
|
+</style>
|