青鸟ai,pc版仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
5.4 KiB

<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { onBeforeRouteLeave } from 'vue-router'
import { Button, message } from 'ant-design-vue'
import { AppContainerBox } from '@/components/AppContainerBox'
import { AppSubMenuTitle } from '@/components/AppSubMenuTitle'
import { AppSubMenuList } from '@/components/AppSubMenuList'
import { AppConversationDefault } from '@/components/AppConversationDefault'
import type { SubMenuItem } from '@/components/AppSubMenuList/index.d'
import { AppTextarea } from '@/components/AppTextarea'
import { AppMessage } from '@/components/AppMessage'
import type { MessageItem } from '@/components/AppMessage/index.d'
import { useMessageStore } from '@/store/moules/messageStore/index'
import { MessageStatusEnum, MessageTypeEnum } from '@/enums/messageEnum'
import { conversationList, historyMessage } from '@/api/base/message'
import { useMqtt } from '@/hooks/useMqtt'
const messageStore = useMessageStore()
const sendBtnLoading = ref(false)
const subMenuActive = ref(0)
const subMenuList = ref<SubMenuItem[]>([])
const appMessage = ref()
const messageList = computed(() => messageStore.getMessageList)
const messageStatus = computed(() => messageStore.getMessageStatus)
const conversationData = computed(() => messageStore.getConversationData)
const historyMessageParams = ref({
conversationId: '',
current: 1,
size: 10,
total: 0,
})
const conversationDefaultShow = ref(true)
watch(
() => messageStatus.value,
(val) => {
if (val === MessageStatusEnum.END) {
sendBtnLoading.value = false
}
},
)
function handleSubMenuChange(index: number) {
if (messageStatus.value !== MessageStatusEnum.END) {
message.warn('请先结束对话')
return
}
subMenuActive.value = index
}
/**
* @description: 发送消息
*/
function handleSend(value: string) {
sendBtnLoading.value = true
conversationDefaultShow.value = false
if (!messageStore.getConversationData) {
return
}
useMqtt().sendMessage(messageStore.getConversationData.roleId, messageStore.getConversationData.id, value)
}
/**
* @description: 获取会话列表
*/
async function getConversationList() {
const res = await conversationList()
subMenuList.value = res
subMenuActive.value = 0
if (subMenuList.value.length) {
messageStore.setConversationData(subMenuList.value[subMenuActive.value])
historyMessageParams.value.current = 1
getHistoryMessage()
await useMqtt().connect()
}
}
/**
* @description: 获取历史对话记录
*/
async function getHistoryMessage() {
if (!conversationData.value) {
return
}
historyMessageParams.value.conversationId = conversationData.value.id
const res = await historyMessage(historyMessageParams.value)
if (!res || !res.records || !res.records.length) {
return
}
res.records.forEach((item: any) => {
const itemData: MessageItem = {
messageType: item.roleType === MessageTypeEnum.USER ? MessageTypeEnum.USER : MessageTypeEnum.AI,
content: item.messageContent,
time: item.messageTime,
avatar: '',
messageStatus: MessageStatusEnum.END,
}
historyMessageParams.value.total = res.total
messageStore.setMessageUnshiftItem(itemData)
})
conversationDefaultShow.value = false
}
/**
* @description: 滚动监听
*/
async function onScrollTop(scrollTop: number) {
if (scrollTop !== 0) {
return
}
if (historyMessageParams.value.current * historyMessageParams.value.size > historyMessageParams.value.total) {
return
}
if (historyMessageParams.value.current < historyMessageParams.value.total) {
historyMessageParams.value.current++
await getHistoryMessage()
// 无缝滚动
appMessage.value.seamlessScrollToTop()
}
}
/**
* @description: 重新回答
*/
function reloadMessage() {
if (!messageStore.getConversationData) {
return
}
const question = messageList.value[messageList.value.length - 2]?.content
useMqtt().sendMessage(messageStore.getConversationData.roleId, messageStore.getConversationData.id, question)
}
onMounted(() => {
getConversationList()
})
onUnmounted(() => {
useMqtt().end()
})
// 路由离开时的操作
onBeforeRouteLeave(() => {
if (messageStatus.value !== MessageStatusEnum.END) {
message.warn('请先结束对话')
return false
}
})
</script>
<template>
<AppContainerBox>
<template #subMenu>
<!-- 标题 -->
<AppSubMenuTitle></AppSubMenuTitle>
<!-- 按钮 -->
<div class="px-5 mb-5">
<Button type="primary" class="w-full">
新建会话
</Button>
</div>
<!-- 会话列表 -->
<AppSubMenuList
:list="subMenuList"
:active-index="subMenuActive"
@change="handleSubMenuChange"
>
</AppSubMenuList>
</template>
<template #content>
<!-- 默认导语 -->
<AppConversationDefault
v-if="conversationDefaultShow"
height="calc(100% - 120px)"
>
</AppConversationDefault>
<!-- 消息列表 -->
<AppMessage
v-else
ref="appMessage"
class="pl-27 pr-5"
:list="messageList"
@on-scroll-top="onScrollTop"
@reload-message="reloadMessage"
>
</AppMessage>
<!-- 发送框 -->
<AppTextarea
class="pl-52 pr-32 mt-10"
:btn-loading="sendBtnLoading"
@send="handleSend"
></AppTextarea>
</template>
</AppContainerBox>
</template>
<style scoped></style>