diff --git a/src/api/ai/skill/aiReport/index.ts b/src/api/ai/skill/aiReport/index.ts new file mode 100644 index 0000000..65a17ca --- /dev/null +++ b/src/api/ai/skill/aiReport/index.ts @@ -0,0 +1,90 @@ +import request from '@/utils/request'; +import { AxiosPromise } from 'axios'; +import {AskVO} from "@/api/ai/skill/aiChat/types"; + +// AI报表分析生成SQL语句API +export const generateReportSql = (query?: AskVO): AxiosPromise => { + return request({ + url: '/ai/aiReport/generateReportSql', + method: 'post', + params: query, + timeout: 1000000 + }); +}; + +// AI报表分析API +export function generateReport(data) { + return request({ + url: '/ai/aiReport/generateReport', + method: 'post', + data + }) +} + +// 获取最新AI生成报表信息 +export function getRecentReports() { + return request({ + url: '/ai/aiReport/getRecentReports', + method: 'get' + }) +} + + +/** + * 根据sessionid和messagedetailtype获取最新一条AI生成报表详细给信息 + * @param query + * @returns {*} + */ +export function getRecentReportInfo (query) { + return request({ + url: '/ai/aiReport/getRecentReportInfo', + method: 'get', + params: query + }); +}; + + + + +// 测试报表分析API +export function generateTestReport(data) { + return request({ + url: '/ai/aiReport/generateTestReport', + method: 'post', + data + }) +} + +// 获取快速体验示例 +export function getQuickExamples() { + return request({ + url: '/ai/aiReport/examples', + method: 'get' + }) +} + +// 生成SQL(测试用) +export function generateSQL(prompt) { + return request({ + url: '/ai/aiReport/generate-sql', + method: 'post', + params: { prompt } + }) +} + +// 生成HTML(测试用) +export function generateHTML(prompt) { + return request({ + url: '/ai/aiReport/generate-html', + method: 'post', + params: { prompt } + }) +} + +// 健康检查 +export function healthCheck() { + return request({ + url: '/ai/aiReport/health', + method: 'get' + }) +} diff --git a/src/layout/components/TopBar/aiAssistant.vue b/src/layout/components/TopBar/aiAssistant.vue index 6b0e94e..3542919 100644 --- a/src/layout/components/TopBar/aiAssistant.vue +++ b/src/layout/components/TopBar/aiAssistant.vue @@ -355,6 +355,10 @@ const selectForm = async (aiFormSetting: AiFormSettingVO) => { const resetAiAssistant = () =>{ chatList.value = []; + selectLists.value = []; + type1Elements.value = []; + type2Elements.value = []; + selectedType2Elements.value = []; } // function selectForm(aiFormSetting: AiFormSettingVO) { @@ -440,12 +444,130 @@ function onModelChange() { } } -watch(state, (newVal) => { - if (newVal.isShowSearch) { - loadForms() - getAiModelList(); +// 创建重置函数 +const resetAllState = () => { + // 重置表单选择状态 + selectedFormSettingId.value = null + selectedForm.value = null + + // 重置聊天记录 + chatList.value = [] + selectLists.value = [] + type1Elements.value = [] + type2Elements.value = [] + selectedType2Elements.value = [] + + // 重置输入区域 + inputValue.value = '' + aiThinking.value = false + aiLoading.value = false + + // 重置录音相关状态 + isRecording.value = false + audioAsrLoading.value = false + recognitionResult.value = '' + uploadProgress.value = 0 + isUploading.value = false + + // 重置选择对话框 + selectDialog.value = false + selectDialogList.value = null + selectDialogListIndex.value = undefined + selectDialogFilterText.value = '' + selectedOption.value = '' + + // 重置窗口位置和大小 + windowPosition.value = { x: 'auto', y: 0 } + windowSize.value = { width: '24%', height: '100vh' } + isCustomPosition.value = false + + // 重置当前组件 + currentComponent.value = null + currentProps.value = {} + isShowLeft.value = false + currentSize.value = "menu" + + // 重置更多对话框 + showMore.value = false + moreFilterText.value = '' + + // 重置sendForm + sendForm.value = {} + + // 清理录音相关资源 + if (microphoneStream) { + microphoneStream.getTracks().forEach(track => track.stop()) + microphoneStream = null } -}); + + if (mediaRecorder && mediaRecorder.state !== 'inactive') { + mediaRecorder.stop() + mediaRecorder = null + } + + audioChunks = [] + + // 清理录音文件URL + recordings.value.forEach(recording => { + URL.revokeObjectURL(recording.url) + }) + recordings.value = [] +} + +// 添加窗口关闭时的清理函数 +const cleanupOnClose = () => { + // 停止录音(如果正在录音) + if (isRecording.value) { + stopRecording() + } + + // 清理音频资源 + if (microphoneStream) { + microphoneStream.getTracks().forEach(track => track.stop()) + microphoneStream = null + } + + if (mediaRecorder && mediaRecorder.state !== 'inactive') { + mediaRecorder.stop() + mediaRecorder = null + } + + audioChunks = [] + + // 重置状态 + resetAllState() +} + +// 监听窗口显示状态变化 +watch(() => state.isShowSearch, async (newVal) => { + if (newVal) { + console.log('AI窗口打开,重置状态并重新加载') + + // 重置状态 + resetAllState() + + try { + // 并行加载表单和模型数据 + await Promise.all([ + loadForms(), + getAiModelList() + ]) + + // 初始化表单映射 + initFormPageMap() + + // 重置共享存储数据 + sharedStore.updateDynamicValue({ + message: null, + timestamp: null + }) + } catch (error) { + console.error('重新加载数据失败:', error) + ElMessage.error('加载数据失败,请重试') + } + } +}, { immediate: true }) + const selectLists = ref([]); @@ -494,6 +616,7 @@ const sendForm = ref({}); const handleSend = async (selectedText?: string) => { if ((!canSend.value || aiThinking.value) && !selectedText) return const userMsg = selectedText || inputValue.value + selectLists.value = []; chatList.value.push({text: userMsg, from: 'user', type: 'text'}) scrollToBottom() aiThinking.value = true @@ -1077,8 +1200,9 @@ onMounted(() => { // processData(testData1); }) +// 组件卸载时清理资源 onBeforeUnmount(() => { - + cleanupOnClose() }) // 组件卸载时清理资源 @@ -1158,6 +1282,7 @@ function onInputKeydown(e: KeyboardEvent) { } function close() { + cleanupOnClose() state.isShowSearch = false } diff --git a/src/router/index.ts b/src/router/index.ts index fafc8b6..d2deca8 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -530,7 +530,7 @@ export const dynamicRoutes: RouteRecordRaw[] = [ path: '/ai/skill/knowledgeBaseQA', component: Layout, hidden: true, - permissions: ['ai:aiKnowledgeBaseDocs:qa'], + permissions: ['ai:aiKnowledgeBase:qa'], children: [ { path: 'index/:knowledgeBaseId/:embeddingModelId/:retrieveLimit', diff --git a/src/views/ai/skill/aiReport/index.vue b/src/views/ai/skill/aiReport/index.vue new file mode 100644 index 0000000..7263965 --- /dev/null +++ b/src/views/ai/skill/aiReport/index.vue @@ -0,0 +1,1677 @@ + + + + + diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue index 1c36b99..064f035 100644 --- a/src/views/system/user/index.vue +++ b/src/views/system/user/index.vue @@ -710,8 +710,8 @@ const sharedData = computed(() => sharedStore.dynamicValue) watch( () => sharedStore.dynamicValue, (newValue, oldValue) => { - if (newValue !== oldValue) { - ElMessage.info('收到新数据更新') + if (newValue!=null && newValue.message!=null && newValue !== oldValue) { + // ElMessage.info('收到新数据更新') console.log('数据更新:', newValue) // 这里可以执行数据更新后的业务逻辑 // handleDataUpdate(newValue)