From 9bebf2fdb87c715115fd75563a6c5d3b8fe37c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=98=E6=B0=91=E5=BA=B7?= Date: Thu, 15 May 2025 15:29:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=AF=E4=BF=A1=E4=BB=A3=E7=A0=81=E5=BA=93-A?= =?UTF-8?q?I=E5=A4=A7=E6=A8=A1=E5=9E=8B=E5=88=9B=E5=BB=BA=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D\=E4=BC=9A=E8=AF=9D=E5=88=97=E8=A1=A8\=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D=E8=AF=A6=E6=83=85=E6=8E=A5=E5=8F=A3=E5=AF=B9=E6=8E=A5?= =?UTF-8?q?=E5=8F=8A=E5=89=8D=E7=AB=AF=E5=8A=9F=E8=83=BD=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 2 +- .../ViewHistoryAside/ViewHistoryAside.vue | 255 ++++++----- src/layouts/AILayout/index.vue | 68 +-- src/views/Jyh/AI/Home/components/AIList.vue | 7 +- .../ViewHistoryAside/BatchManageModal.vue | 211 +++++++++ .../ViewHistoryAside/ViewHistoryAside.vue | 412 ++++++++++++++++++ src/views/Jyh/AI/Home/index.vue | 249 +++++++++-- 7 files changed, 969 insertions(+), 235 deletions(-) create mode 100644 src/views/Jyh/AI/Home/components/ViewHistoryAside/BatchManageModal.vue create mode 100644 src/views/Jyh/AI/Home/components/ViewHistoryAside/ViewHistoryAside.vue diff --git a/.env.development b/.env.development index 6d906ff..9b8412c 100644 --- a/.env.development +++ b/.env.development @@ -38,4 +38,4 @@ VITE_COPILOT_HOST = 'https://test.gitcode.net/child/aichat-app/' VITE_BASE_URL=/ # AI大模型接口地址 -VITE_AI_API_HOST = 'http://222.20.126.208:8089' +VITE_AI_API_HOST = 'http://222.20.126.208:8087' diff --git a/src/layouts/AILayout/ViewHistoryAside/ViewHistoryAside.vue b/src/layouts/AILayout/ViewHistoryAside/ViewHistoryAside.vue index fec6f29..0388ca2 100644 --- a/src/layouts/AILayout/ViewHistoryAside/ViewHistoryAside.vue +++ b/src/layouts/AILayout/ViewHistoryAside/ViewHistoryAside.vue @@ -14,9 +14,9 @@
-
+
-

{{ item.title }}

+

{{ item.question }}

@@ -43,10 +43,10 @@
- {{ item.text }} + {{ item.text || '可信代码库AI' }}
- {{ formatTime(item.time) }} + 时间:{{ formatTime(item.time||'') }}
@@ -54,35 +54,35 @@
- - -
-
- -
-

{{ item.title }}

-
- -
-
- - {{ item.text }} -
-
- {{ formatTime(item.time) }} -
-
-
-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -116,85 +116,85 @@
- - - -
- -
-
- -
-

{{ item.title }}

- -
- - - - - - - - - -
-
- -
-
- - {{ item.text }} -
-
- {{ formatTime(item.time) }} -
-
-
-
- -
-
- - -
-
- -
-

{{ item.title }}

-
- -
-
- - {{ item.text }} -
-
- {{ formatTime(item.time) }} -
-
-
-
-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -228,19 +228,24 @@ diff --git a/src/views/Jyh/AI/Home/components/AIList.vue b/src/views/Jyh/AI/Home/components/AIList.vue index 965f47c..88b73ef 100644 --- a/src/views/Jyh/AI/Home/components/AIList.vue +++ b/src/views/Jyh/AI/Home/components/AIList.vue @@ -50,7 +50,6 @@ const router = useRouter(); const route = useRoute(); const props = defineProps(['content']) -debugger const filterTableRef = ref(); const { namespace } = getOrgInfo(); @@ -96,7 +95,6 @@ const fieldTranslation = { const columns = ref([ ]); // 处理数据,生成列信息 const processData = () => { - debugger const uniqueKeys = new Set(); tableData.value.forEach((item) => { Object.keys(item).forEach((key) => uniqueKeys.add(key)); @@ -104,8 +102,8 @@ const processData = () => { columns.value = Array.from(uniqueKeys).map((key) => ({ key, - // label: fieldTranslation[key] || key, - label: key, + label: fieldTranslation[key] || key, + // label: key, width: 120 })); tableKey.value++; @@ -114,7 +112,6 @@ const processData = () => { // 监听数据变化,重新处理数据 watch(() => props.content, (newData) => { tableData.value = JSON.parse(newData); - debugger processData(); }, { deep: true,immediate:true }); diff --git a/src/views/Jyh/AI/Home/components/ViewHistoryAside/BatchManageModal.vue b/src/views/Jyh/AI/Home/components/ViewHistoryAside/BatchManageModal.vue new file mode 100644 index 0000000..fb9bc84 --- /dev/null +++ b/src/views/Jyh/AI/Home/components/ViewHistoryAside/BatchManageModal.vue @@ -0,0 +1,211 @@ + + + + + diff --git a/src/views/Jyh/AI/Home/components/ViewHistoryAside/ViewHistoryAside.vue b/src/views/Jyh/AI/Home/components/ViewHistoryAside/ViewHistoryAside.vue new file mode 100644 index 0000000..831ea75 --- /dev/null +++ b/src/views/Jyh/AI/Home/components/ViewHistoryAside/ViewHistoryAside.vue @@ -0,0 +1,412 @@ + + + + + diff --git a/src/views/Jyh/AI/Home/index.vue b/src/views/Jyh/AI/Home/index.vue index fcf185e..43a4280 100644 --- a/src/views/Jyh/AI/Home/index.vue +++ b/src/views/Jyh/AI/Home/index.vue @@ -3,7 +3,7 @@
@@ -145,11 +155,14 @@ import WarningList from './components/WarningList.vue'; import OssDetail from './components/OssDetail.vue'; import Other from './components/Other.vue'; import AIList from './components/AIList.vue'; +import ViewHistoryAside from './components/ViewHistoryAside/ViewHistoryAside.vue'; import axios from 'axios'; import { useDiscussGetUserInfo } from '@/api/discussion/hook'; +import { Message } from 'vue-devui/message'; // 获取当前用户信息 & 是否登录 const { isLogin = false, userInfo = {}} = useDiscussGetUserInfo(); +const {username=''} = userInfo const inputValue = ref(''); const startChat = ref(false); @@ -164,6 +177,7 @@ const agentList = ref([ { label: 'InsCode', value: 'inscode' }, ]); const selectedAgent = ref(agentList.value[0]); + const aiModelAvatar = { imgSrc: 'https://matechat.gitcode.com/logo.svg', width: 32, @@ -182,13 +196,22 @@ const inputFootIcons = [ const messages = ref([]); +// 控制 ViewHistoryAside 组件的显示状态 +const isHistoryVisible = ref(false); + + +// 切换 ViewHistoryAside 组件的显示与隐藏 +const toggleHistory = () => { + isHistoryVisible.value =!isHistoryVisible.value; +}; + const onInputIconClick = (e) => { if (e.icon === 'icon-at') { inputValue.value += `@${selectedAgent.value.label}`; } }; -const onSubmit = (e, answer = undefined) => { +const onSubmit = async (e, answer = undefined) => { if(e === '') { return; } @@ -197,70 +220,163 @@ const onSubmit = (e, answer = undefined) => { startChat.value = true; } messages.value.push({ - from: 'user', + role: 'user', content: e, avatarPosition: 'side-right', avatarConfig: { ...customerAvatar }, }); + // getAIAnswer(answer ?? e); + // 判断是否有会话id + if(!CONV_ID.value) { + // 调用创建会话接口 + await createConversation() + } + await getAIAnswer(e,1); nextTick(() => { conversationRef.value?.scrollTo({ top: conversationRef.value.scrollHeight, behavior: 'smooth', }); }); - // getAIAnswer(answer ?? e); - getAIAnswer(e,1); }; const VITE_AI_API_HOST = (import.meta as any).env.VITE_AI_API_HOST; + +// AI对话接口对接 const getAIAnswer = async (content) => { - messages.value.push({ - from: 'ai-model', - type: '', - content: '', - avatarPosition: 'side-left', - avatarConfig: { ...aiModelAvatar }, - loading: true, - }); + debugger + if(!username) return Message.error('请先登录!') + if(CONV_ID.value) { + messages.value.push({ + role: 'ai-model', + type: '', + content: '', + avatarPosition: 'side-left', + avatarConfig: { ...aiModelAvatar }, + loading: true, + }); - const {data} = await axios.get(VITE_AI_API_HOST + '/api/v0/chat_use_sql?question='+content); - const {text,type} = data; + const response = await axios.post(`${VITE_AI_API_HOST}/api/v0/chat_use_sql`, { + userId: username, // 使用 username 作为 userId + conversationId: CONV_ID.value, + question: content, + }); - if(type==='text') { - messages.value[messages.value.length - 1].content = text; - messages.value[messages.value.length - 1].loading = false; - messages.value[messages.value.length - 1].type = 'text'; - } else if(type==='df') { - messages.value[messages.value.length - 1].content = data[type]; - messages.value[messages.value.length - 1].loading = false; - messages.value[messages.value.length - 1].type = 'df'; + if(response.data.type) { + const {text,type} = response.data; + + if(type==='text') { + messages.value[messages.value.length - 1].content = text; + messages.value[messages.value.length - 1].loading = false; + messages.value[messages.value.length - 1].type = 'text'; + } else if(type==='df') { + messages.value[messages.value.length - 1].content = response.data[type]; + messages.value[messages.value.length - 1].loading = false; + messages.value[messages.value.length - 1].type = 'df'; + } + } else { + Message.warning('接口异常!') + } + // messages.value.push({ + // from: 'ai-model', + // content: '', + // avatarPosition: 'side-left', + // avatarConfig: { ...aiModelAvatar }, + // loading: true, + // }); + + // /* 模拟流式数据返回 */ + // setTimeout(async () => { + // messages.value.at(-1).loading = false; + // for (let i = 0; i < content.length;) { + // await new Promise(r => setTimeout(r, 300 * Math.random())); + // messages.value[messages.value.length - 1].content = content.slice(0, i += Math.random() * 10); + // nextTick(() => { + // conversationRef.value?.scrollTo({ + // top: conversationRef.value.scrollHeight + // }); + // }); + // } + // }, 1000); + } else { + Message.error('请先创建会话!'); } - // messages.value.push({ - // from: 'ai-model', - // content: '', - // avatarPosition: 'side-left', - // avatarConfig: { ...aiModelAvatar }, - // loading: true, - // }); +}; - // /* 模拟流式数据返回 */ - // setTimeout(async () => { - // messages.value.at(-1).loading = false; - // for (let i = 0; i < content.length;) { - // await new Promise(r => setTimeout(r, 300 * Math.random())); - // messages.value[messages.value.length - 1].content = content.slice(0, i += Math.random() * 10); - // nextTick(() => { - // conversationRef.value?.scrollTo({ - // top: conversationRef.value.scrollHeight - // }); - // }); - // } - // }, 1000); +const viewHistoryRef = ref(null); +// 当前会话id +const CONV_ID = ref(''); +// 创建对话接口 +const createConversation = async () => { + try { + if (!username) { + Message.error('请先登录!'); + return; + } + const response = await axios.post(`${VITE_AI_API_HOST}/api/createConversation`, { + userId: username, + }); + debugger + const createRes = response.data; + + if (createRes&&createRes.conversationId) { + CONV_ID.value = createRes.conversationId; + console.log('创建会话成功,会话ID:', CONV_ID.value); + nextTick(() => { + // 刷新会话列表 + if (viewHistoryRef.value) { + viewHistoryRef.value.getQuestionHistory(); // 调用子组件方法 + } + }) + } else { + Message.error('创建会话失败,未获取到会话ID'); + } + } catch (error) { + console.error('创建会话失败:', error); + Message.error('创建会话失败,请重试'); + } +}; + +const handleSelectConv = (convId: string) => { + CONV_ID.value = convId; // 更新为选中的会话 ID + getConversationDetail(convId); // 调用详情接口 +}; + +// 定义获取会话详情的接口(根据实际接口调整) +const getConversationDetail = async (convId: string) => { + try { + const response = await axios.get(`${VITE_AI_API_HOST}/api/conversationDetail`, { + params: { + userId: username, + conversationId: convId, + }, + }); + const detail = response.data; + // 处理详情数据(如回显消息列表) + handleDetailResponse(detail); + } catch (error) { + console.error('获取会话详情失败:', error); + Message.error('获取会话详情失败,请重试'); + } +}; + +// 处理详情数据(示例:更新消息列表) +const handleDetailResponse = (detail: any) => { + // 假设接口返回消息列表为 messagesList + messages.value = detail.messages || []; + startChat.value = true; // 显示聊天界面 + nextTick(() => { + conversationRef.value?.scrollTo({ + top: conversationRef.value.scrollHeight, + behavior: 'smooth', + }); + }); }; const onNewConvo = () => { startChat.value = false; messages.value = []; + createConversation() }; const onItemClick = (item) => { @@ -660,4 +776,51 @@ onMounted(() => { text-align: left; } + + +.back-in-btn { + position: fixed; + left: 20px; + bottom: 20px; + display: flex; + gap: 12px; + + .active { + background-color: #f0f0f0; /* 灰色背景 */ + } + + .active .icon { + transform: translateY(-4px); /* 图标上移4px */ + } + + .back-in-time-btn { + display: flex; + align-items: center; + gap: 8px; + padding: 8px; + background-color: var(--el-color-primary); + //color: white; + border-radius: 20px; + cursor: pointer; + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); + z-index: 999; + transition: all 0.3s; + font-size: 18px; + } + + .back-in-time-btn:hover { + background-color: var(--el-color-primary-light-3); + transform: translateY(-2px); + } + + /* 响应式调整 - 移动端隐藏或调整位置 */ + @media (max-width: 768px) { + .back-in-time-btn { + left: 10px; + bottom: 10px; + padding: 6px 12px; + font-size: 14px; + } + } +}