From 923f49266b00bd05bf8a4037b29ecb706d1306ff Mon Sep 17 00:00:00 2001 From: houzhongjian <houzhongyi@126.com> Date: 星期三, 18 六月 2025 09:03:33 +0800 Subject: [PATCH] 转炉大模型功能完善 --- src/views/ai/dashboard/zhuanlu/index.vue | 303 +++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 262 insertions(+), 41 deletions(-) diff --git a/src/views/ai/dashboard/zhuanlu/index.vue b/src/views/ai/dashboard/zhuanlu/index.vue index 9feb5d0..8c62b93 100644 --- a/src/views/ai/dashboard/zhuanlu/index.vue +++ b/src/views/ai/dashboard/zhuanlu/index.vue @@ -26,9 +26,15 @@ <div id="tsxx"> <div class="title"></div> <div class="data1-item" v-for="(item, index) in tsxxList" :key="`dynamics-${index}`"> - <div class="content"> - <div class="value"> - <span>{{item.value}}</span> <span>{{item.unit}}</span> + <div class="content1"> + <div class="value" v-if="item.type == 1"> + <div class="item" v-for="(list, i) in item.lists" :key="`dynamics-${i}`"> + <span>{{list.no}}</span><span>{{list.value}}</span> + </div> + </div> + <div class="value" v-else> + <span v-if="item.value == '进行'" style="color: #49FFD3; font-size: 14px; font-weight: bold;">{{item.value}}</span> + <span v-else style="color: #FFAE81; font-size: 14px; font-weight: bold;">{{item.value}}</span> </div> <div class="name"> {{item.name}} @@ -179,11 +185,11 @@ <div class="gas-scheduling-right"> <div id="ldghslyc"> <div class="title"></div> - <div ref="LDGHSLYCEhartContainer" style="width: 100%; height: 180px"></div> + <div ref="LDGHSLYCEhartContainer" style="width: 100%; height: 140px"></div> </div> <div id="ldggrqsyc"> <div class="title"></div> - <div ref="LDGGRYCEhartContainer" style="width: 100%; height: 180px"></div> + <div ref="LDGGRYCEhartContainer" style="width: 100%; height: 140px"></div> </div> <div id="mqhsjhxx"> <div class="title"></div> @@ -248,6 +254,32 @@ <div class="item right-label"></div> </div> </div> + <div class="schedule-suggest"> + <div class="result-title"> + <span>推理结论</span><el-button @click="openSuggest" size="small" class="result-button" :icon="ArrowRight">查看更多</el-button> + </div> + <div class="result-content"> + <div class="content-item" v-for="(item, index) in topSuggests" :key="`dynamics-${index}`"> + <div class="time"> + <span>{{formatDate(item.createTime, 'MM-DD HH:mm')}}</span> + </div> + <el-tooltip + effect="dark" + :content="item.content" + placement="top" + :disabled="!isOverflow" + > + <div class="content" ref="contentRef"> + {{ item.content }} + </div> + </el-tooltip> + </div> + </div> + <!-- 历史建议 --> + <ScheduleSuggestDialog + ref="scheduleSuggestRef" + /> + </div> </div> </div> </template> @@ -264,11 +296,13 @@ import HistoryMessageDialog from "../components/message/HistoryMessageDialog.vue" import * as echarts from "echarts"; import {formatToDateTime} from "@/utils/dateUtil"; +import { formatReasoningContent } from '@/views/ai/utils/utils' import {refreshToken} from "@/api/login"; import {round} from "lodash-es"; -import {ArrowUpBold} from "@element-plus/icons-vue"; +import {ArrowRight, ArrowUpBold} from "@element-plus/icons-vue"; import * as authUtil from "@/utils/auth"; -import HistoryMessageList from "@/views/ai/dashboard/components/message/HistoryMessageList.vue"; +import {ScheduleSuggestApi, ScheduleSuggestVO} from "@/api/ai/schedulesuggest"; +import {formatDate} from "@/utils/formatTime"; const mqhsList = ref([ { @@ -306,33 +340,60 @@ const tsxxList = ref([ { name: '各高炉出铁水信号', - value: '进行', - unit: '' + type: 1, + lists: [ + { + no: '1#', + value: '不进行', + }, + { + no: '2#', + value: '不进行', + } + ] }, { name: '各高炉出铁量', - value: 5000, - unit: '吨' + type: 1, + lists: [ + { + no: '1#', + value: '500t', + }, + { + no: '2#', + value: '600t', + } + ] }, { name: '各高炉铁水装入鱼雷罐车信号', - value: '进行', - unit: 'm³/h' + type: 1, + lists: [ + { + no: '1#', + value: '不进行', + }, + { + no: '2#', + value: '不进行', + } + ] }, { name: '鱼雷罐车等待信号', - value: '进行', - unit: 'm³/h' + type: 2, + value: '进行' }, { name: '铁水倒入铁水包信号', - value: '不进行', - unit: 'm³/h' + type: 2, + value: '不进行' }, { name: '铁产量计划', - value: 6000, - unit: '吨' + type: 3, + value: '6000t', }, ]) @@ -440,14 +501,12 @@ const mqhsjhxxList = ref([ { - name: '转炉总炉数\n' + - '日计划', + name: '转炉总炉数日计划', value: 567, unit: '炉' }, { - name: '转炉入炉铁水量\n' + - '日计划', + name: '转炉入炉铁水量日计划', value: 200, unit: '吨' }, @@ -536,6 +595,11 @@ } ]) + +const topSuggests = ref<ScheduleSuggestVO[]>([]) + +const contentRef = ref([]); +const isOverflow = ref([]); const ddtlResult = ref('') @@ -725,10 +789,14 @@ message.thinking = match[2]; message.conclusion = match[4] } + message.thinking = formatReasoningContent(message.thinking) return message } - - +/** 调度建议 */ +const scheduleSuggestRef = ref() +const openSuggest = async () => { + scheduleSuggestRef.value.open() +} /** * 消息列表 * @@ -736,8 +804,22 @@ */ const messageList = computed(() => { if (activeMessageList.value.length > 0) { - activeMessageList.value[1].thinking = dealResultAndData(activeMessageList.value[1].content) - return activeMessageList.value + // 对AI返回的消息进行格式化处理 + const formattedList = activeMessageList.value.map(msg => { + if (msg.type === 'assistant') { + // 复制消息对象以避免修改原始数据 + const formattedMsg = {...msg}; + // 处理推理思路内容 + formattedMsg.content = formatReasoningContent(msg.content); + return formattedMsg; + } + return msg; + }); + + // 处理调度推理结论及数据 + formattedList[1].thinking = dealResultAndData(formattedList[1].content); + + return formattedList; } // 没有消息时,如果有 systemMessage 则展示它 if (activeConversation.value?.systemMessage) { @@ -773,6 +855,15 @@ } initLDGGRQSYCChart() return content +} + +const getScheduleResult = (content: string) => { + const spliceText = content.includes("总结:") ? "总结:" : "结论:"; + const regex = new RegExp(`^([\\s\\S]*?)${spliceText}([\\s\\S]*)$`); + const match = content.match(regex); + console.log(match) + const result = match ? match[2].trim() : ''; + return result } const extractRecoveryDetails = (text, consume, gui, totalMinutes = 60) => { @@ -945,6 +1036,10 @@ conversationId: activeConversationId.value, content: content } as ChatMessageVO) + // 保存调度建议 + setTimeout(async () => { + await createSuggest() + }, 1000) } /** 真正执行【发送】消息操作 */ @@ -1108,6 +1203,31 @@ } catch {} } +const suggestData = ref({ + id: undefined, + modelId: undefined, + conversationId: undefined, + messageId: undefined, + content: undefined, + status: undefined, +}) + +const createSuggest = async () => { + const suggestParam = suggestData.value as unknown as ScheduleSuggestVO + let assistantMessage = activeMessageList.value[1] + suggestParam.content = getScheduleResult(assistantMessage.content) + if(suggestParam.content != '') { + suggestParam.modelId = activeConversation.value.modelId + suggestParam.conversationId = activeConversation.value.id + suggestParam.messageId = assistantMessage.id + suggestParam.createTime = assistantMessage.createTime + suggestParam.status = 0 + await ScheduleSuggestApi.createScheduleSuggest(suggestParam) + // 刷新首页推理结果列表 + await getTopSuggest() + } +} + const LDGHSLYCEhartContainer = ref(); // 生成未来60秒的时间标签(LDG回收量预测) @@ -1148,7 +1268,7 @@ const max = LDGMaxTotalValue() const schedule = modelData.value.schedule[type] // 返回对象格式数据,包含原始值和基准值 - const baseline = round(max, 0) + (6 - 2 * type) + const baseline = round(max, 0) + (4.5 - 2 * type) return schedule.map(item => ({ value: item + baseline, // 显示值 = 原始值 + 基准值 original: item // 原始值 @@ -1232,15 +1352,15 @@ }, grid: { left: 25, - right: 25, + right: 5, bottom: 10, top: 30, containLabel: true }, legend: { - top: 10, + top: 5, right: 10, - data: ['1#转炉', '2#转炉', '3#转炉', '总回收量'], + data: ['1#转炉', '2#转炉', '3#转炉'], textStyle: { color: '#8FD6FE' }, @@ -1293,6 +1413,7 @@ focus: 'series' }, lineStyle: { + width: 1, color: '#FF7686' // 粉色 } }, @@ -1306,6 +1427,7 @@ focus: 'series' }, lineStyle: { + width: 1, color: '#49FFD3' // 绿色 } }, @@ -1320,6 +1442,7 @@ focus: 'series' }, lineStyle: { + width: 1, color: '#FFAE81' // 橙色 }, }, @@ -1333,6 +1456,7 @@ focus: 'series' }, lineStyle: { + width: 1, color: 'white' }, } @@ -1383,7 +1507,7 @@ left: 0, right: 0, bottom: 10, - top: 20, + top: 10, containLabel: true }, tooltip: { @@ -1434,7 +1558,10 @@ data: realData, smooth: true, symbol: 'none', - lineStyle: { color: '#95E6FF' }, + lineStyle: { + color: '#95E6FF', + width: 1 + }, markLine: { symbol: ['none', 'none'], label: { @@ -1459,6 +1586,7 @@ lineStyle: { type: 'dashed', color: '#E76666', + width: 1, dashOffset: 5 } }, @@ -1591,6 +1719,11 @@ // 初始状态检测 updateFullscreenStatus(); } +/** 查询列表 */ +const getTopSuggest = async () => { + const data = await ScheduleSuggestApi.getTopScheduleSuggests(5) + topSuggests.value = data +} /** 初始化 **/ onMounted(async () => { @@ -1605,11 +1738,11 @@ // 获取列表数据 activeMessageListLoading.value = true await getMessageList() + await getTopSuggest() }) // 清理监听 onUnmounted(() => { - console.log('stopStream') const events = ['fullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange']; events.forEach(event => { document.removeEventListener(event, handleFullscreenChange); @@ -1682,6 +1815,35 @@ font-weight: 400; font-size: 12px; color: #C7E7FF; + } + } + .name { + height: 16px; + font-weight: 400; + font-size: 12px; + color: #C7E7FF; + } + } + .content1 { + margin-left: 16px; + .value { + span:nth-child(1) { + height: 16px; + font-weight: 400; + font-size: 12px; + color: #C7E7FF; + } + span:nth-child(2){ + padding-left: 3px; + height: 19px; + font-weight: bold; + font-size: 14px; + color: #FFAE81; + line-height: 19px; + } + .item { + display: inline-block; + width: 45%; } } .name { @@ -2229,8 +2391,8 @@ } } .data2-item { - height: 2.8rem; - width: 45%; + height: 1.4rem; + width: 46%; display: inline-block; margin: 6px 8px; background: url("@/assets/ai/zhuanlu/data_bg3.png") no-repeat; @@ -2241,15 +2403,13 @@ margin-left: 10px; .name { - width: 95px; - height: 18px; + width: 140px; font-weight: 400; font-size: 14px; color: #C7E7FF; } .value { - margin-top: 10px; margin-left: auto; margin-right: 5px; span:nth-child(1) { @@ -2279,13 +2439,13 @@ .little-title { font-size: 14px; color: #8FD6FE; - margin: 10px; + margin: 5px 10px 5px 10px; } .data3-item { height: 5.2rem; width: 30%; display: inline-block; - margin: 0 6px 6px 6px; + margin: 0 6px 0 6px; background: url("@/assets/ai/zhuanlu/data_bg4.png") center/cover no-repeat; .name { font-family: Alimama ShuHeiTi, Alimama ShuHeiTi; @@ -2355,6 +2515,67 @@ } } } + .schedule-suggest { + .result-title { + margin-top: 10px; + background: url("@/assets/ai/zhuanlu/ddtljl_result_title.png") no-repeat; + height: 1.8rem; + font-weight: 400; + font-size: 14px; + color: #8FD6FE; + text-align: left; + font-style: normal; + text-transform: none; + span { + margin-left: 30px; + } + .result-button { + color: rgba(143, 214, 254); + font-weight: bold; + float: right; + margin-right: 5px; + background-color: rgba(0, 255, 255, 0.1); + border-radius: 3px; + padding: 0 5px; + border: none; + cursor: pointer + } + .history-button:hover { + color: rgba(143, 214, 254, 0.5); + } + } + .result-content { + margin-top: 5px; + display: inline-block; + font-weight: 400; + font-size: 14px; + color: rgba(130,202,255,0.89); + text-align: left; + font-style: normal; + text-transform: none; + .content-item { + height: 28px; + background: rgba(69,133,255,0.2); + border-radius: 2px 2px 2px 2px; + padding-left: 3px; + margin: 3px 0; + display: flex; + align-items: center; + overflow: hidden; + } + .time { + flex-shrink: 0; + margin-right: 12px; + } + .content { + width: 350px; + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + } } } -- Gitblit v1.9.3