180 lines
4.6 KiB
Vue
180 lines
4.6 KiB
Vue
<!-- 默认消息列表页 -->
|
|
<script setup lang="ts">
|
|
import type { FilesCardProps } from 'vue-element-plus-x/types/FilesCard';
|
|
import { Loading } from '@element-plus/icons-vue';
|
|
import { useDebounceFn } from '@vueuse/core';
|
|
import { ElMessage } from 'element-plus';
|
|
import { nextTick, ref, watch } from 'vue';
|
|
import ModelSelect from '@/components/ModelSelect/index.vue';
|
|
import WelecomeText from '@/components/WelecomeText/index.vue';
|
|
import { useGuideTourStore, useUserStore } from '@/stores';
|
|
import { useFilesStore } from '@/stores/modules/files';
|
|
|
|
import { useSessionStore } from '@/stores/modules/session';
|
|
|
|
const userStore = useUserStore();
|
|
const sessionStore = useSessionStore();
|
|
const filesStore = useFilesStore();
|
|
const guideTourStore = useGuideTourStore();
|
|
|
|
const senderValue = ref('');
|
|
const senderRef = ref();
|
|
const isSending = ref(false); // 发送状态标志
|
|
|
|
// 防抖发送函数
|
|
const debouncedSend = useDebounceFn(async () => {
|
|
if (!senderValue.value.trim()) {
|
|
ElMessage.warning('消息内容不能为空');
|
|
return;
|
|
}
|
|
|
|
if (isSending.value) {
|
|
ElMessage.warning('请等待上一条消息发送完成');
|
|
return;
|
|
}
|
|
|
|
const content = senderValue.value;
|
|
isSending.value = true;
|
|
|
|
try {
|
|
localStorage.setItem('chatContent', content);
|
|
await sessionStore.createSessionList({
|
|
userId: userStore.userInfo?.userId as number,
|
|
sessionContent: content,
|
|
sessionTitle: content.slice(0, 10),
|
|
remark: content.slice(0, 10),
|
|
});
|
|
senderValue.value = ''; // 清空输入框
|
|
}
|
|
catch (error: any) {
|
|
console.error('发送消息失败:', error);
|
|
ElMessage.error(error);
|
|
}
|
|
finally {
|
|
isSending.value = false;
|
|
}
|
|
}, 800, { leading: true, trailing: false }); // 800ms防抖
|
|
|
|
// 处理发送事件
|
|
function handleSend() {
|
|
debouncedSend();
|
|
}
|
|
|
|
function handleDeleteCard(_item: FilesCardProps, index: number) {
|
|
filesStore.deleteFileByIndex(index);
|
|
}
|
|
|
|
watch(
|
|
() => filesStore.filesList.length,
|
|
(val) => {
|
|
if (val > 0) {
|
|
nextTick(() => {
|
|
senderRef.value?.openHeader();
|
|
});
|
|
}
|
|
else {
|
|
nextTick(() => {
|
|
senderRef.value?.closeHeader();
|
|
});
|
|
}
|
|
},
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<div class="chat-defaul-wrap">
|
|
<WelecomeText />
|
|
<Sender
|
|
ref="senderRef"
|
|
v-model="senderValue"
|
|
class="chat-defaul-sender"
|
|
data-tour="chat-sender"
|
|
:auto-size="{
|
|
maxRows: 9,
|
|
minRows: 3,
|
|
}"
|
|
variant="updown"
|
|
clearable
|
|
allow-speech
|
|
:loading="isSending"
|
|
@submit="handleSend"
|
|
>
|
|
<template #header>
|
|
<div class="sender-header p-12px pt-6px pb-0px">
|
|
<Attachments
|
|
:items="filesStore.filesList"
|
|
:hide-upload="true"
|
|
@delete-card="handleDeleteCard"
|
|
>
|
|
<template #prev-button="{ show, onScrollLeft }">
|
|
<div
|
|
v-if="show"
|
|
class="prev-next-btn left-8px flex-center w-22px h-22px rounded-8px border-1px border-solid border-[rgba(0,0,0,0.08)] c-[rgba(0,0,0,.4)] hover:bg-#f3f4f6 bg-#fff font-size-10px"
|
|
@click="onScrollLeft"
|
|
>
|
|
<el-icon>
|
|
<ArrowLeftBold />
|
|
</el-icon>
|
|
</div>
|
|
</template>
|
|
|
|
<template #next-button="{ show, onScrollRight }">
|
|
<div
|
|
v-if="show"
|
|
class="prev-next-btn right-8px flex-center w-22px h-22px rounded-8px border-1px border-solid border-[rgba(0,0,0,0.08)] c-[rgba(0,0,0,.4)] hover:bg-#f3f4f6 bg-#fff font-size-10px"
|
|
@click="onScrollRight"
|
|
>
|
|
<el-icon>
|
|
<ArrowRightBold />
|
|
</el-icon>
|
|
</div>
|
|
</template>
|
|
</Attachments>
|
|
</div>
|
|
</template>
|
|
<template #prefix>
|
|
<div class="flex-1 flex items-center gap-8px flex-none w-fit overflow-hidden">
|
|
<FilesSelect />
|
|
|
|
<ModelSelect />
|
|
</div>
|
|
</template>
|
|
<template #suffix>
|
|
<el-icon v-if="isSending" class="is-loading">
|
|
<Loading />
|
|
</el-icon>
|
|
</template>
|
|
</Sender>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.chat-defaul-wrap {
|
|
position: relative;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
width: 100%;
|
|
max-width: 800px;
|
|
min-height: 450px;
|
|
.chat-defaul-sender {
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
:deep(.el-icon.is-loading) {
|
|
margin-left: 8px;
|
|
color: var(--el-color-primary);
|
|
animation: rotating 2s linear infinite;
|
|
}
|
|
|
|
@keyframes rotating {
|
|
0% {
|
|
transform: rotate(0deg);
|
|
}
|
|
100% {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
</style>
|