From cc8703ca90c645ac4c6aecfd602e69f955ead3d8 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 15 Nov 2025 13:50:55 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E3=80=90antd=E3=80=91=E3=80=90ai?= =?UTF-8?q?=E3=80=91chat=20=E7=9A=84=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/ai/chat/index/index.vue | 27 +++++++++++-------- .../conversation/list.vue} | 17 +++++------- .../conversation/update-form.vue} | 0 .../message/knowledge.vue} | 0 .../message/list-empty.vue} | 7 ++--- .../message/list.vue} | 5 ++-- .../message/loading.vue} | 0 .../message/new-conversation.vue} | 0 .../role/category-list.vue} | 5 ++-- .../RoleList.vue => modules/role/list.vue} | 7 ++--- .../role/repository.vue} | 7 ++--- 11 files changed, 36 insertions(+), 39 deletions(-) rename apps/web-antd/src/views/ai/chat/index/{components/conversation/ConversationList.vue => modules/conversation/list.vue} (97%) rename apps/web-antd/src/views/ai/chat/index/{components/conversation/ConversationUpdateForm.vue => modules/conversation/update-form.vue} (100%) rename apps/web-antd/src/views/ai/chat/index/{components/message/MessageKnowledge.vue => modules/message/knowledge.vue} (100%) rename apps/web-antd/src/views/ai/chat/index/{components/message/MessageListEmpty.vue => modules/message/list-empty.vue} (95%) rename apps/web-antd/src/views/ai/chat/index/{components/message/MessageList.vue => modules/message/list.vue} (98%) rename apps/web-antd/src/views/ai/chat/index/{components/message/MessageLoading.vue => modules/message/loading.vue} (100%) rename apps/web-antd/src/views/ai/chat/index/{components/message/MessageNewConversation.vue => modules/message/new-conversation.vue} (100%) rename apps/web-antd/src/views/ai/chat/index/{components/role/RoleCategoryList.vue => modules/role/category-list.vue} (91%) rename apps/web-antd/src/views/ai/chat/index/{components/role/RoleList.vue => modules/role/list.vue} (97%) rename apps/web-antd/src/views/ai/chat/index/{components/role/RoleRepository.vue => modules/role/repository.vue} (98%) diff --git a/apps/web-antd/src/views/ai/chat/index/index.vue b/apps/web-antd/src/views/ai/chat/index/index.vue index 9e6cc2559..c18ae1b76 100644 --- a/apps/web-antd/src/views/ai/chat/index/index.vue +++ b/apps/web-antd/src/views/ai/chat/index/index.vue @@ -18,12 +18,12 @@ import { sendChatMessageStream, } from '#/api/ai/chat/message'; -import ConversationList from './components/conversation/ConversationList.vue'; -import ConversationUpdateForm from './components/conversation/ConversationUpdateForm.vue'; -import MessageList from './components/message/MessageList.vue'; -import MessageListEmpty from './components/message/MessageListEmpty.vue'; -import MessageLoading from './components/message/MessageLoading.vue'; -import MessageNewConversation from './components/message/MessageNewConversation.vue'; +import ConversationList from './modules/conversation/list.vue'; +import ConversationUpdateForm from './modules/conversation/update-form.vue'; +import MessageListEmpty from './modules/message/list-empty.vue'; +import MessageList from './modules/message/list.vue'; +import MessageLoading from './modules/message/loading.vue'; +import MessageNewConversation from './modules/message/new-conversation.vue'; /** AI 聊天对话 列表 */ defineOptions({ name: 'AiChat' }); @@ -33,6 +33,7 @@ const [FormModal, formModalApi] = useVbenModal({ connectedComponent: ConversationUpdateForm, destroyOnClose: true, }); + // 聊天对话 const conversationListRef = ref(); const activeConversationId = ref(null); // 选中的对话编号 @@ -87,7 +88,7 @@ async function handleConversationClick( ) { // 对话进行中,不允许切换 if (conversationInProgress.value) { - alert('对话中,不允许切换!'); + await alert('对话中,不允许切换!'); return false; } @@ -97,6 +98,7 @@ async function handleConversationClick( // 刷新 message 列表 await getMessageList(); // 滚动底部 + // TODO @AI:看看要不要 await scrollToBottom(true); // 清空输入框 prompt.value = ''; @@ -117,7 +119,7 @@ async function handlerConversationDelete( async function handleConversationClear() { // 对话进行中,不允许切换 if (conversationInProgress.value) { - alert('对话中,不允许切换!'); + await alert('对话中,不允许切换!'); return false; } activeConversationId.value = null; @@ -128,8 +130,9 @@ async function handleConversationClear() { async function openChatConversationUpdateForm() { formModalApi.setData({ id: activeConversationId.value }).open(); } + +/** 对话更新成功,刷新最新信息 */ async function handleConversationUpdateSuccess() { - // 对话更新成功,刷新最新信息 await getConversation(activeConversationId.value); } @@ -138,6 +141,7 @@ async function handleConversationCreate() { // 创建对话 await conversationListRef.value.createConversation(); } + /** 处理聊天对话的创建成功 */ async function handleConversationCreateSuccess() { // 创建新的对话,清空输入框 @@ -228,6 +232,7 @@ function handleGoTopMessage() { } // =========== 【发送消息】相关 =========== + /** 处理来自 keydown 的发送消息 */ async function handleSendByKeydown(event: any) { // 判断用户是否在输入 @@ -282,7 +287,6 @@ function onCompositionstart() { } function onCompositionend() { - // console.log('输入结束...') setTimeout(() => { isComposing.value = false; }, 200); @@ -339,6 +343,7 @@ async function doSendMessageStream(userMessage: AiChatMessageApi.ChatMessage) { await nextTick(); await scrollToBottom(); // 底部 // 1.3 开始滚动 + // TODO @AI:要不要 await textRoll(); // 2. 发送 event stream @@ -351,7 +356,7 @@ async function doSendMessageStream(userMessage: AiChatMessageApi.ChatMessage) { async (res: any) => { const { code, data, msg } = JSON.parse(res.data); if (code !== 0) { - alert(`对话异常! ${msg}`); + await alert(`对话异常! ${msg}`); return; } diff --git a/apps/web-antd/src/views/ai/chat/index/components/conversation/ConversationList.vue b/apps/web-antd/src/views/ai/chat/index/modules/conversation/list.vue similarity index 97% rename from apps/web-antd/src/views/ai/chat/index/components/conversation/ConversationList.vue rename to apps/web-antd/src/views/ai/chat/index/modules/conversation/list.vue index e6526ecf8..a52ed6291 100644 --- a/apps/web-antd/src/views/ai/chat/index/components/conversation/ConversationList.vue +++ b/apps/web-antd/src/views/ai/chat/index/modules/conversation/list.vue @@ -19,9 +19,8 @@ import { } from '#/api/ai/chat/conversation'; import { $t } from '#/locales'; -import RoleRepository from '../role/RoleRepository.vue'; +import RoleRepository from '../role/repository.vue'; -// 定义组件 props const props = defineProps({ activeId: { type: [Number, null] as PropType, @@ -29,7 +28,6 @@ const props = defineProps({ }, }); -// 定义钩子 const emits = defineEmits([ 'onConversationCreate', 'onConversationClick', @@ -41,7 +39,6 @@ const [Drawer, drawerApi] = useVbenDrawer({ connectedComponent: RoleRepository, }); -// 定义属性 const searchName = ref(''); // 对话搜索 const activeConversationId = ref(null); // 选中的对话,默认为 null const hoverConversationId = ref(null); // 悬浮上去的对话 @@ -180,7 +177,7 @@ async function updateConversationTitle( conversation: AiChatConversationApi.ChatConversation, ) { // 1. 二次确认 - prompt({ + await prompt({ async beforeClose(scope) { if (scope.isConfirm) { if (scope.value) { @@ -202,8 +199,7 @@ async function updateConversationTitle( if ( filterConversationList.length > 0 && filterConversationList[0] && // tip:避免切换对话 - activeConversationId.value === - (filterConversationList[0].id!) + activeConversationId.value === filterConversationList[0].id! ) { emits('onConversationClick', filterConversationList[0]); } @@ -252,9 +248,9 @@ async function handleClearConversation() { await confirm('确认后对话会全部清空,置顶的对话除外。'); await deleteChatConversationMyByUnpinned(); message.success($t('ui.actionMessage.operationSuccess')); - // 清空 对话 和 对话内容 + // 清空对话、对话内容 activeConversationId.value = null; - // 获取 对话列表 + // 获取对话列表 await getChatConversationList(); // 回调 方法 emits('onConversationClear'); @@ -283,7 +279,6 @@ watch(activeId, async (newValue) => { activeConversationId.value = newValue; }); -// 定义 public 方法 defineExpose({ createConversation }); /** 初始化 */ @@ -298,7 +293,7 @@ onMounted(async () => { if (conversationList.value.length > 0 && conversationList.value[0]) { activeConversationId.value = conversationList.value[0].id; // 回调 onConversationClick - await emits('onConversationClick', conversationList.value[0]); + emits('onConversationClick', conversationList.value[0]); } } }); diff --git a/apps/web-antd/src/views/ai/chat/index/components/conversation/ConversationUpdateForm.vue b/apps/web-antd/src/views/ai/chat/index/modules/conversation/update-form.vue similarity index 100% rename from apps/web-antd/src/views/ai/chat/index/components/conversation/ConversationUpdateForm.vue rename to apps/web-antd/src/views/ai/chat/index/modules/conversation/update-form.vue diff --git a/apps/web-antd/src/views/ai/chat/index/components/message/MessageKnowledge.vue b/apps/web-antd/src/views/ai/chat/index/modules/message/knowledge.vue similarity index 100% rename from apps/web-antd/src/views/ai/chat/index/components/message/MessageKnowledge.vue rename to apps/web-antd/src/views/ai/chat/index/modules/message/knowledge.vue diff --git a/apps/web-antd/src/views/ai/chat/index/components/message/MessageListEmpty.vue b/apps/web-antd/src/views/ai/chat/index/modules/message/list-empty.vue similarity index 95% rename from apps/web-antd/src/views/ai/chat/index/components/message/MessageListEmpty.vue rename to apps/web-antd/src/views/ai/chat/index/modules/message/list-empty.vue index 9ccb028e3..b8ac0a3e4 100644 --- a/apps/web-antd/src/views/ai/chat/index/components/message/MessageListEmpty.vue +++ b/apps/web-antd/src/views/ai/chat/index/modules/message/list-empty.vue @@ -1,8 +1,7 @@