123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- <template>
- <div>
- <van-nav-bar fixed @click-left="onClickLeft" @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>
- <van-pull-refresh v-model="loading" @refresh="onRefresh">
- <div class="w-full h-[100vh] pt-55">
- <div ref="messageBoxRef" class="w-full box-border px-12 overflow-y-auto scrollbar">
- <van-list
- v-model:loading="loading"
- :finished="finished"
- finished-text="没有更多了"
- @load="onLoad"
- >
- <template v-for="(item, index) in receiveGetter" :key="index">
- <!-- 右侧是自己的消息 -->
- <template v-if="item.sendUserId == user.pass">
- <!-- 右侧消息 图片 -->
- <template v-if="item.messageType == 1">
- <div class="w-full text-center text-black/[0.4] mt-24 text-sm">
- {{ item.createTime }}
- </div>
- <div class="flex justify-end items-start">
- <div
- class="mr-10 text-left inline-block min-h-46 max-w-full break-words overflow-auto bg-[#FEF4E6] box-border text-base p-12 text-wrap"
- >
- {{ item.messageContent }}
- </div>
- <div class="w-40 h-40 rounded-full overflow-hidden shrink-0">
- <img
- v-if="user?.headImageUrl"
- class="w-full h-full object-cover"
- :src="user?.headImageUrl"
- alt=""
- />
- <img
- v-else
- class="w-full h-full object-cover"
- src="~/assets/img/default_avatar.png"
- alt=""
- />
- </div>
- </div>
- </template>
- <!-- 文字消息 -->
- <template v-if="item.messageType == 0 && item.messageContent.trim()">
- <div class="w-full text-center text-black/[0.4] mt-24 text-sm">
- {{ formatTimestamp(item.createTime) }}
- </div>
- <div class="flex justify-end items-start">
- <div
- class="mr-10 text-left inline-block min-h-46 max-w-full break-words overflow-auto rounded-b-2xl rounded-tl-2xl bg-white box-border text-base p-12 text-wrap"
- >
- {{ messageContentParse(item.messageContent) }}
- </div>
- </div>
- <div class="w-40 h-40 rounded-full overflow-hidden shrink-0">
- <img
- v-if="user?.headImageUrl"
- class="w-full h-full object-cover"
- :src="user?.headImageUrl"
- alt=""
- />
- <img
- v-else
- class="w-full h-full object-cover"
- src="~/assets/img/default_avatar.png"
- alt=""
- />
- </div>
- </template>
- </template>
- <!-- 左侧他人的消息 -->
- <template v-else>
- <!-- 左侧消息 图片 -->
- <template v-if="item.messageType == 1">
- <div class="w-full text-center text-black/[0.4] mt-24 text-sm">
- {{ item.createTime }}
- </div>
- <div class="flex justify-end items-start">
- <div
- class="mr-10 text-left inline-block min-h-46 max-w-full break-words overflow-auto rounded-[4px] bg-white box-border text-base p-12 text-wrap"
- >
- <!-- {{ item.messageContent }} -->
- </div>
- <div class="w-40 h-40 rounded-full overflow-hidden shrink-0">
- <img
- v-if="user?.headImageUrl"
- class="w-full h-full object-cover"
- :src="user?.headImageUrl"
- alt=""
- />
- <img
- v-else
- class="w-full h-full object-cover"
- src="~/assets/img/default_avatar.png"
- alt=""
- />
- </div>
- </div>
- </template>
- <!-- 左侧文字 -->
- <!-- <template v-if="item.messageType == 0 && item.messageContent.trim()"> -->
- <div class="w-full text-center text-black/[0.4] mt-24 text-sm">
- {{ formatTimestamp(item.createTime) }}
- </div>
- <div class="flex justify-start items-start">
- <div class="w-40 h-40 rounded-full overflow-hidden shrink-0">
- <img
- v-if="user?.headImageUrl"
- class="w-full h-full object-cover"
- :src="user?.headImageUrl"
- alt=""
- />
- <img
- v-else
- class="w-full h-full object-cover"
- src="~/assets/img/default_avatar.png"
- alt=""
- />
- </div>
- <div
- class="ml-8 inline-block rounded-b-2xl rounded-tr-2xl min-h-46 max-w-full break-words overflow-auto bg-[#F3F3F3] box-border text-base p-12 text-wrap"
- >
- {{ messageContentParse(item.messageContent) }}
- </div>
- </div>
- <!-- </template> -->
- </template>
- </template>
- <div ref="msgBottomRef"></div>
- </van-list>
- </div>
- </div>
- </van-pull-refresh>
- <ProfileNewsChatInput
- :shareGroup="false"
- @on-select-Img="selectImg"
- @on-send-message="sendMessage"
- ></ProfileNewsChatInput>
- </div>
- </template>
- <script setup>
- import { messageContentParse, formatTimestamp } from '~/utils/detalTime'
- const route = useRoute()
- const router = useRouter()
- const uploadUrl = `${import.meta.env.VITE_APP_BASE_URL}/website/tourMessage/upload`
- const chatStore = useChatStore()
- const { ws, curConversiton, receive, receiveGetter, connectSta, onNewMessage } =
- storeToRefs(chatStore)
- const user = computed(() => chatStore.user)
- // 消息接收者的用户id
- const getUserId = computed(() => curConversiton.value.toUserId)
- // 消息发送者:当前登录用户的加密id
- const sendUserId = computed(() => user.value.pass)
- // 会话id
- const groupId = computed(() => route.query.groupId)
- // 用户在群聊中艾特的人
- const specialUserId = ref('')
- // 用户输入的文本消息
- const messageContent = ref('')
- // 聊天类型 1单聊 2群聊 3系统消息 4关注信息
- const noticeType = computed(() => curConversiton.value.noticeType)
- const messageBoxRef = ref(null)
- const msgBottomRef = ref(null)
- const inputBoxRef = ref(null)
- // 当前websocket连接状态 0: 未连接 1: 连接中 2: 已连接 3: 已断开
- const wsConnect = computed(() => connectSta.value)
- const followStatus = ref(0)
- const querySwParams = reactive({
- getUserId: computed(() => route.query.getUserId ?? ''),
- groupId: computed(() => route.query.groupId ?? ''),
- sendUserId: computed(() => route.query.sendUserId ?? '')
- })
- // 本地生成一个唯一消息id
- function getLocalId() {
- const random = Math.floor(Math.random() * 10000)
- return Date.now() + '' + random
- }
- // 刷新次数
- const count = ref(0)
- const loading = ref(false)
- const finished = ref(false)
- const messageList = ref([])
- // 单聊的标题
- const title = computed(() => route.query.groupRemark)
- // 刷新
- const onRefresh = () => {}
- const onClickLeft = () => router.back()
- const onClickRight = () => {
- navigateTo({
- path: '/chat/set-single',
- query: {
- toUserId: route.query.getUserId
- }
- })
- }
- // 发送消息的方法
- // 发送文本消息
- function sendMessage(messageParams) {
- console.log(messageParams, 'messageParams')
- console.log(getUserId.value, '5555')
- console.log(noticeType, '5555')
- if (!messageParams.trim()) return
- let msg = {
- // getUserId: getUserId.value,
- // sendUserId: sendUserId.value,
- // groupId: groupId.value,
- ...querySwParams,
- specialUserId: specialUserId.value,
- messageContent: messageParams,
- messageType: 0,
- noticeType: 1,
- object: {
- id: getLocalId()
- }
- }
- receive.value.push({
- ...msg,
- messageContent: JSON.stringify({ messageContent: msg.messageContent })
- })
- messageContent.value = ''
- messageBoxRef.value.scrollTop = messageBoxRef.value.scrollHeight
- msg = JSON.stringify(msg)
- ws.value.send(msg)
- }
- const pageSize = ref(10)
- const messageCount = ref(0)
- // 获取聊天记录
- async function getChatHistory(messageId = '') {
- if (curConversiton.value.isLocal) return
- if (!groupId.value) return
- if (receive.value.length >= messageCount.value && receive.value.length > 0) return
- if (receive.value.length && !messageId) return
- const query = {
- pageSize: pageSize.value,
- groupId: groupId.value,
- messageId
- }
- const {
- data: { data = [], count = [] }
- } = await request('/website/tourMessage/getMessageByGroupId', { query })
- messageCount.value = count || 0
- if (Array.isArray(data)) {
- receive.value = [...data, ...receive.value]
- }
- // 获取到数据后,滚动到底部
- if (!messageId) {
- nextTick(() => {
- setTimeout(() => {
- messageBoxRef.value && messageBoxRef.value.scrollTo({ top: msgBottomRef.value.offsetTop })
- }, 100)
- })
- }
- console.log('历史记录:', data)
- }
- // 监听输入框的enter事件
- function addEventListenerTextarea() {
- nextTick(() => {
- if (inputBoxRef.value) {
- inputBoxRef.value.removeEventListener('keydown', () => {})
- inputBoxRef.value.addEventListener('keydown', function (event) {
- if (event.key === 'Enter') {
- event.preventDefault()
- sendMessage()
- }
- })
- }
- })
- }
- // 监听消息列表的滚动事件
- function addEventListenerMessage() {
- nextTick(() => {
- if (messageBoxRef.value) {
- messageBoxRef.value.removeEventListener('scroll', () => {})
- messageBoxRef.value.addEventListener('scroll', (e) => {
- if (messageBoxRef.value.scrollTop == 0 && receive.value[0]?.id) {
- console.log('滚动到顶部了')
- console.log(receive.value[0].id)
- getChatHistory(receive.value[0].id)
- }
- })
- }
- })
- }
- // 选择发送图片
- function selectImg(e) {
- const file = e.target.files[0]
- const { size, type, name } = file
- const IMIETypes = ['image/jpeg', 'image/png', 'image/gif']
- if (!IMIETypes.includes(type)) {
- showToast('请上传图片')
- return
- }
- const maxSize = 1024 * 1024 * 20
- if (size > maxSize) {
- showFailToast('图片大小不能超过10M')
- return
- }
- const formData = new FormData()
- formData.append('uploadFile', file)
- formData.append('fieldName', 'messageContent')
- formData.append('asImage', true)
- request(uploadUrl, { method: 'post', body: formData }).then((res) => {
- const {
- data: { fileUrl }
- } = res
- if (fileUrl) {
- const msg = {
- getUserId: getUserId.value,
- sendUserId: sendUserId.value,
- specialUserId: '',
- groupId: groupId.value,
- messageContent: fileUrl,
- messageType: 1,
- noticeType: noticeType.value,
- object: {
- id: getLocalId()
- }
- }
- ws.value.send(JSON.stringify(msg))
- }
- })
- }
- // 获取我与对方的关注情况
- async function isFollow() {
- if (noticeType.value !== 1) return //只有单聊中才需要获取关注情况
- const query = {
- userId: curConversiton.value.toUserId
- }
- const { data: status = 0 } = await request('/website/tourGroup/isFollow', { query })
- followStatus.value = status
- console.log('关注情况:', status)
- }
- watch(groupId, async () => {
- // 消息置空
- receive.value = []
- // 监听消息输入框键盘enter事件
- addEventListenerTextarea()
- // 监听聊天框消息滚动事件
- addEventListenerMessage()
- // 获取与当前会话用户的关注状态
- isFollow()
- // 获取前会话用户的聊天记录
- getChatHistory()
- })
- watch(onNewMessage, getUserId, sendUserId, () => {})
- onMounted(() => {
- // 获取前会话用户的聊天记录
- getChatHistory()
- addEventListenerTextarea()
- addEventListenerMessage()
- // 获取与当前会话用户的关注状态
- isFollow()
- })
- definePageMeta({
- layout: false
- })
- </script>
- <style lang="scss" scoped></style>
|