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/api/qms/QcInspectionMain/types.ts b/src/api/qms/QcInspectionMain/types.ts index a6d1424..0d645ee 100644 --- a/src/api/qms/QcInspectionMain/types.ts +++ b/src/api/qms/QcInspectionMain/types.ts @@ -398,6 +398,9 @@ export interface QcInspectionMainQuery extends PageQuery { * 日期范围参数 */ params?: any; + + + planDetailId?: number; } 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/dms/dmsFaultInstanceActivity/index.vue b/src/views/dms/dmsFaultInstanceActivity/index.vue index 34b665f..9f782b9 100644 --- a/src/views/dms/dmsFaultInstanceActivity/index.vue +++ b/src/views/dms/dmsFaultInstanceActivity/index.vue @@ -47,11 +47,28 @@ + + + + @@ -65,8 +82,37 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -184,6 +230,17 @@ + + +

维修更换零件

+ + + + + + +
+ >({}); const workOrder = ref({}); const workOrderStatusText = ref(''); +const approveStatusText = ref(''); +const confirmStatusText = ref(''); const outsourceList = ref([]); const outsourcingName = ref(''); + // 表单相关 const processFormRef = ref(); const submitVerifyRef = ref>(); @@ -229,6 +290,9 @@ const approvalRecordRef = ref>(); // 任务变量 const taskVariables = ref({}); +// 当前用户是否为任务办理人 +const isCurrentUserTaskAssignee = ref(false); + // 表单数据 const initFormData = { repairInstanceId: undefined, @@ -255,8 +319,15 @@ const rules = reactive({ processHandleResolution: [{ required: false, message: '处理意见不能为空', trigger: 'blur' }] }); +// 是否为查看模式 +const isViewMode = computed(() => { + return routeParams.value.type === 'view'; +}); + // 计算属性 const needProcessResolution = computed(() => { + // 查看模式不显示处理意见输入框 + if (isViewMode.value) return false; return isApprovalStage.value || confirmButtonShow.value; }); @@ -268,8 +339,10 @@ const currentStepName = computed(() => { }); const approvalButtonShow = computed(() => { - // 显示审批按钮的条件:工单审批状态为待审批(1) - return workOrder.value?.approveStatus === '1'; + // 查看模式不显示审批按钮 + if (isViewMode.value) return false; + // 显示审批按钮的条件:工单审批状态为待审批(1) && 当前用户是任务办理人 + return workOrder.value?.approveStatus === '1' && isCurrentUserTaskAssignee.value; }); const confirmButtonShow = computed(() => { @@ -290,20 +363,26 @@ const confirmButtonShow = computed(() => { const approveStatusMatches = String(workOrder.value?.approveStatus) === '2'; const repairConfirmMatches = String(workOrder.value?.repairConfirm) === '0'; - const shouldShow = billsStatusMatches && approveStatusMatches && repairConfirmMatches; + // 查看模式不显示主管确认按钮 + if (isViewMode.value) return false; + + // 同时需要当前用户是任务办理人 + const shouldShow = billsStatusMatches && approveStatusMatches && repairConfirmMatches && isCurrentUserTaskAssignee.value; console.log('主管确认按钮显示结果:', { billsStatusMatches, approveStatusMatches, repairConfirmMatches, + isCurrentUserTaskAssignee: isCurrentUserTaskAssignee.value, shouldShow }); return shouldShow; }); -// 是否为审批阶段 +// 是否为审批阶段(查看模式不显示审批状态选择框) const isApprovalStage = computed(() => { + if (isViewMode.value) return false; return workOrder.value?.approveStatus === '1'; }); @@ -319,6 +398,9 @@ onMounted(async () => { // 获取外协单位列表 await getOutsourceList(); + // 检查当前用户是否为任务办理人 + await checkCurrentUserTaskPermission(); + // 初始化表单数据 initializeFormData(); @@ -333,6 +415,40 @@ onMounted(async () => { } }); +// 检查当前用户是否为任务办理人 +const checkCurrentUserTaskPermission = async () => { + try { + const businessId = routeParams.value.id; + if (!businessId) { + isCurrentUserTaskAssignee.value = false; + return; + } + + // 查询当前用户的待办任务列表,筛选出匹配当前工单的任务 + const taskRes = await pageByTaskWait({ + pageNum: 1, + pageSize: 100, + flowCode: 'Fault01' // 故障维修流程代码 + }); + + // 检查是否有匹配当前业务ID的待办任务 + const matchingTask = taskRes.rows?.find( + (task: any) => String(task.businessId) === String(businessId) + ); + + isCurrentUserTaskAssignee.value = !!matchingTask; + + console.log('用户任务权限检查:', { + businessId, + hasMatchingTask: !!matchingTask, + isCurrentUserTaskAssignee: isCurrentUserTaskAssignee.value + }); + } catch (error) { + console.error('检查用户任务权限失败:', error); + isCurrentUserTaskAssignee.value = false; + } +}; + // 加载工单信息 const loadWorkOrderInfo = async () => { // 从query参数获取businessId @@ -348,6 +464,8 @@ const loadWorkOrderInfo = async () => { // 设置状态显示文本 - 添加安全检查 workOrderStatusText.value = getStatusText(workOrder.value.billsStatus || ''); + approveStatusText.value = getApproveStatusText(workOrder.value.approveStatus || ''); + confirmStatusText.value = getConfirmStatusText(workOrder.value.repairConfirm || ''); }; // 初始化表单数据 @@ -385,7 +503,25 @@ const approvalVerifyOpen = async () => { if (!processFormRef.value) return; try { + // 先进行表单验证 const valid = await processFormRef.value.validate(); + if (!valid) { + (proxy as any)?.$modal.msgWarning('请填写必填项'); + return; + } + + // 检查审批状态是否已选择 + if (!form.approveStatus || form.approveStatus === '1') { + (proxy as any)?.$modal.msgWarning('请选择审批状态(通过或拒绝)'); + return; + } + + // 检查处理意见是否已填写 + if (!form.processHandleResolution || form.processHandleResolution.trim() === '') { + (proxy as any)?.$modal.msgWarning('请填写处理意见'); + return; + } + if (valid) { await (proxy as any)?.$modal.confirm('是否确认提交审批?'); @@ -433,6 +569,12 @@ const submitCallback = async (approvalResult?: any) => { // 主管确认处理 const handleConfirm = async () => { + // 检查处理意见是否已填写 + if (!form.processHandleResolution || form.processHandleResolution.trim() === '') { + (proxy as any)?.$modal.msgWarning('请填写处理意见'); + return; + } + try { // 使用自定义按钮的确认对话框 const result = await ElMessageBox.confirm( @@ -528,7 +670,7 @@ const setDynamicValidationRules = () => { // 工具函数 const getStatusText = (status: string) => { - const statusMap = { + const statusMap: Record = { '0': '待维修', '1': '维修中', '2': '维修完成', @@ -537,6 +679,25 @@ const getStatusText = (status: string) => { }; return statusMap[status] || '未知状态'; }; + +const getApproveStatusText = (status: string) => { + const statusMap: Record = { + '0': '未提交', + '1': '待审批', + '2': '审批通过', + '3': '审批拒绝' + }; + return statusMap[status] || '未知状态'; +}; + +const getConfirmStatusText = (status: string) => { + const statusMap: Record = { + '0': '待确认', + '1': '确认通过', + '2': '确认不通过' + }; + return statusMap[status] || '未知状态'; +}; diff --git a/src/views/mes/prodReport/components/PendingTasks.vue b/src/views/mes/prodReport/components/PendingTasks.vue index 232a0aa..0f2ae28 100644 --- a/src/views/mes/prodReport/components/PendingTasks.vue +++ b/src/views/mes/prodReport/components/PendingTasks.vue @@ -14,12 +14,13 @@ + - + diff --git a/src/views/mes/prodReport/components/WorkReportRecord.vue b/src/views/mes/prodReport/components/WorkReportRecord.vue index 553f8e6..e0ea5f6 100644 --- a/src/views/mes/prodReport/components/WorkReportRecord.vue +++ b/src/views/mes/prodReport/components/WorkReportRecord.vue @@ -18,7 +18,7 @@ - + @@ -50,7 +50,7 @@ import { PlanInfoQuery } from '@/api/mes/planInfo/types'; import { parseTime } from '@/utils/ruoyi'; const props = defineProps<{ - workstationId?: string | number; + workstationId?: number; }>(); const loading = ref(false); @@ -59,7 +59,8 @@ const total = ref(0); const queryParams = ref({ pageNum: 1, - pageSize: 10 + pageSize: 10, + stationId: props.workstationId }); // 获取报工记录列表 @@ -83,9 +84,9 @@ const getList = async () => { processName: (item as any).processName || '-', reportQuantity: item.completeAmount || 0, remainingAmount: (item as any).remainingAmount || 0, - reportTime: item.realBeginTime || item.realEndTime || '', - reportUser: item.userName || '-', - workstation: (item as any).workstationName || '-', + reportTime: item.realBeginTime, + reportUser: item.reportUser , + stationName: (item as any).stationName || '-', remark: item.remark || '-' })); diff --git a/src/views/mes/prodReport/index.vue b/src/views/mes/prodReport/index.vue index 11fe45d..b6a57a0 100644 --- a/src/views/mes/prodReport/index.vue +++ b/src/views/mes/prodReport/index.vue @@ -17,19 +17,14 @@ :disabled='activeTab !== "pending"' filterable clearable - :filter-method='filterWorkstation' @change='handleWorkstationChange' > - {{ item.stationName || item.stationCode }} - - ({{ item.stationCode }}) - @@ -52,6 +47,7 @@ + @@ -67,6 +63,9 @@
+
+ +
@@ -91,6 +90,7 @@ import { ArrowLeft, Menu } from '@element-plus/icons-vue'; import PendingTasks from './components/PendingTasks.vue'; import CurrentTask from './components/CurrentTask.vue'; import WorkReportRecord from './components/WorkReportRecord.vue'; +import InspectionRecord from './components/InspectionRecord.vue'; import ProcessDocuments from './components/ProcessDocuments.vue'; import { parseTime } from '@/utils/ruoyi'; import useUserStore from '@/store/modules/user'; @@ -107,11 +107,12 @@ const activeTab = ref('pending'); const pendingTasksRef = ref(); const currentTaskRef = ref(); const recordRef = ref(); +const inspectionRef = ref(); const documentRef = ref(); // 工位信息(可以从路由参数或用户信息中获取) const productionLine = ref('DJ01'); -const workstation = ref('DJ01-01'); // 工位编码,用于显示 +const workstation = ref(''); // 工位名称 const workstationId = ref(''); // 工位ID,用于查询 const currentShift = ref('白班'); const workstationList = ref([]); @@ -146,6 +147,9 @@ const handleTabChange = (tabName: string) => { } else if (tabName === 'record') { // 切换到报工记录时刷新数据 recordRef.value?.refresh?.(); + } else if (tabName === 'inspection') { + // 切换到质检记录时刷新数据 + inspectionRef.value?.refresh?.(); } }; @@ -159,13 +163,13 @@ const getWorkstationList = async () => { filteredWorkstationList.value = data; // 如果列表不为空且当前工位不在列表中,设置默认工位 if (data.length > 0) { - const foundWorkstation = data.find(item => item.stationCode === workstation.value); + const foundWorkstation = data.find(item => item.stationName === workstation.value); if (foundWorkstation) { // 如果找到匹配的工位编码,设置对应的工位ID(watch会自动触发刷新) workstationId.value = foundWorkstation.stationId; } else { // 如果找不到匹配的工位,设置第一个工位为默认值(watch会自动触发刷新) - workstation.value = data[0].stationCode; + workstation.value = data[0].stationName; workstationId.value = data[0].stationId; } } @@ -175,21 +179,6 @@ const getWorkstationList = async () => { } }; -// 工位搜索过滤 -const filterWorkstation = (query: string) => { - workstationSearchText.value = query; - if (!query) { - filteredWorkstationList.value = workstationList.value; - return; - } - const lowerQuery = query.toLowerCase(); - filteredWorkstationList.value = workstationList.value.filter(item => { - const stationName = (item.stationName || '').toLowerCase(); - const stationCode = (item.stationCode || '').toLowerCase(); - return stationName.includes(lowerQuery) || stationCode.includes(lowerQuery); - }); -}; - // 刷新所有组件数据 const refreshAllData = () => { // 刷新待处理任务 @@ -198,6 +187,8 @@ const refreshAllData = () => { currentTaskRef.value?.refresh?.(); // 刷新报工记录 recordRef.value?.refresh?.(); + // 刷新质检记录 + inspectionRef.value?.refresh?.(); // 刷新工艺文件(如果需要) documentRef.value?.refresh?.(); }; @@ -207,7 +198,7 @@ const handleWorkstationChange = (stationId: string | number) => { // 根据工位ID找到对应的工位编码 const selectedWorkstation = workstationList.value.find(item => item.stationId === stationId); if (selectedWorkstation) { - workstation.value = selectedWorkstation.stationCode; + workstation.value = selectedWorkstation.stationName; } // 更新工位ID(不在这里刷新,由watch统一处理,避免重复调用) workstationId.value = stationId; 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)