<template>
|
<InfiniteLoading
|
scrollViewClassName="common-infinite-scroll-list chat-message-list"
|
v-bind="infiniteLoadingProps"
|
:listData="listData"
|
:showMoreText="false"
|
:enabledLoadingMore="false"
|
:refresherEnabled="false"
|
ref="infiniteLoadingRef"
|
>
|
<template #extra v-if="infiniteLoadingProps.hasMore">
|
<div v-if="infiniteLoadingProps.isFetching" class="infiniting-tips">
|
<Loading class="infiniting-tips-icon"></Loading>数据加载中...
|
</div>
|
<p v-else class="infiniting-tips" @click="getHistoryMessageList()">查看更多</p>
|
</template>
|
<template #renderItem="{ item, index }">
|
<div class="chat-message-item-wrapper" :key="item.id">
|
<MessageTimestamp
|
:currTime="dayjs(item.creationTime).toDate().getTime() / 1000"
|
:prevTime="getPrevTime(item)"
|
class="chat-message-item-timestamp"
|
></MessageTimestamp>
|
<div :class="['chat-message-item', { self: item.sourceId === userDetail?.userId }]">
|
<Avatar
|
:size="30"
|
class="chat-message-item-avatar"
|
:src="item.avatarUrl ? setOSSLink(item.avatarUrl) : ''"
|
/>
|
<div class="chat-message-item-content">
|
{{ item.messageContent }}
|
</div>
|
</div>
|
</div>
|
</template>
|
</InfiniteLoading>
|
<div class="chat-input-wrapper">
|
<nut-input v-model.trim="inputValue" class="chat-input" cursor-spacing="20" />
|
<nut-button class="chat-submit-btn" shape="square" type="primary" @click="sendMessage"
|
>发送</nut-button
|
>
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import { Avatar } from '@12333/components';
|
import { useUser } from '@/hooks';
|
import { useInfiniteLoading, useSetMessageIsRead } from '@12333/hooks';
|
import * as messageServices from '@12333/services/api/Message';
|
import { OrderInputType, MessageBusinessTypeEnum } from '@12333/constants';
|
import Taro from '@tarojs/taro';
|
import dayjs from 'dayjs';
|
import { Message, setOSSLink } from '@12333/utils';
|
import { useQueryClient } from '@tanstack/vue-query';
|
import { Loading } from '@nutui/icons-vue-taro';
|
|
defineOptions({
|
name: 'InnerPage',
|
});
|
|
// type Props = {};
|
|
// const props = withDefaults(defineProps<Props>(), {});
|
|
const { userDetail } = useUser();
|
|
const { setAllMessageIsRead } = useSetMessageIsRead();
|
|
const router = Taro.useRouter();
|
|
const chatId = router.params?.chatId ?? '';
|
|
const isLoadMessage = ref(false);
|
|
const { infiniteLoadingProps, flattenListData, infiniteLoadingRef, invalidateQueries } =
|
useInfiniteLoading(
|
({ pageParam }) => {
|
let params: API.QueryMyMessageInput = {
|
pageModel: {
|
rows: 10,
|
page: pageParam,
|
orderInput: [{ property: 'creationTime', order: OrderInputType.Desc }],
|
},
|
sourceId: chatId,
|
};
|
|
return messageServices.getMyChatMessagePage(params, {
|
showLoading: false,
|
});
|
},
|
{
|
queryKey: ['messageServices/getMyChatMessagePage'],
|
enabled: !!chatId,
|
onSuccess(data) {
|
setAllMessageIsRead({
|
businessType: MessageBusinessTypeEnum.聊天消息,
|
sourceId: chatId,
|
});
|
},
|
}
|
);
|
|
const listData = computed(() => {
|
if (!infiniteLoadingProps.value.listData) return {} as any;
|
return {
|
...infiniteLoadingProps.value.listData,
|
pages: [...(infiniteLoadingProps.value.listData?.pages ?? [])].reverse().map((page) => {
|
return {
|
...page,
|
data: [...page.data].reverse(),
|
};
|
}),
|
};
|
});
|
|
watch(flattenListData, () => {
|
if (!isLoadMessage.value) {
|
nextTick(() => {
|
infiniteLoadingRef.value?.scrollToBottom?.(3000);
|
});
|
}
|
isLoadMessage.value = false;
|
});
|
|
const getHistoryMessageList = () => {
|
isLoadMessage.value = true;
|
infiniteLoadingProps.value.fetchNextPage();
|
};
|
|
const _flattenListData = computed(() => {
|
let list: API.UserMessageInfo[] = [];
|
if (listData && listData.value) {
|
listData.value?.pages.forEach((group) => {
|
group.data.forEach((item) => {
|
list.push(item);
|
});
|
});
|
}
|
return list;
|
});
|
|
function getPrevTime(item: API.UserMessageInfo) {
|
const index = _flattenListData.value.findIndex((_item) => _item.id === item.id);
|
const prevTime = index > 0 ? _flattenListData.value[index - 1].creationTime : 0;
|
return prevTime === 0 ? 0 : dayjs(prevTime).toDate().getTime() / 1000;
|
}
|
|
const inputValue = ref('');
|
|
const queryClient = useQueryClient();
|
|
async function sendMessage() {
|
try {
|
if (!inputValue.value) {
|
Message.error('请输入内容');
|
} else {
|
let params: API.UserTextChatMessageInput = {
|
toId: chatId,
|
messageContent: inputValue.value,
|
};
|
let res = await messageServices.sendUserMessage(params);
|
if (res) {
|
inputValue.value = '';
|
await invalidateQueries();
|
}
|
}
|
} catch (error) {
|
console.log('error: ', error);
|
}
|
}
|
</script>
|
|
<style lang="scss">
|
@import '@/styles/common.scss';
|
|
.chat-message-list {
|
padding-top: 24px;
|
|
.message-more {
|
text-align: center;
|
font-size: 24px;
|
color: boleGetCssVar('text-color', 'primary');
|
line-height: 32px;
|
margin-bottom: 20px;
|
}
|
}
|
|
.chat-message-item-wrapper {
|
.chat-message-item-timestamp {
|
padding-bottom: 48px;
|
}
|
|
.chat-message-item {
|
display: flex;
|
margin-bottom: 40px;
|
|
.chat-message-item-avatar {
|
margin-right: 16px;
|
}
|
|
.chat-message-item-content {
|
font-weight: 400;
|
font-size: 28px;
|
color: boleGetCssVar('text-color', 'primary');
|
line-height: 40px;
|
background: #eaeaea;
|
border-radius: 20px 20px 20px 0px;
|
padding: 20px 16px;
|
}
|
|
&.self {
|
flex-direction: row-reverse;
|
|
.chat-message-item-avatar {
|
margin-right: 0;
|
margin-left: 16px;
|
}
|
|
.chat-message-item-content {
|
background: boleGetCssVar('color', 'primary');
|
border-radius: 20px 20px 0px 20px;
|
color: #fff;
|
}
|
}
|
}
|
}
|
|
.chat-input-wrapper {
|
padding: 32px boleGetCssVar('size', 'body-padding-h');
|
background-color: #fff;
|
display: flex;
|
|
.chat-input {
|
border-bottom: none;
|
border: 2px solid #dbdbdb;
|
flex: 1;
|
min-width: 0;
|
padding: 18px;
|
border-radius: 8px;
|
}
|
|
.chat-submit-btn {
|
border-radius: 8px;
|
margin-left: 16px;
|
height: 80px;
|
/* --nut-button-default-padding: 48px; */
|
}
|
}
|
</style>
|