| | |
| | | <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}} |
| | |
| | | <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> |
| | |
| | | <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> |
| | |
| | | import MessageLoading from '../components/message/MessageLoading.vue' |
| | | import ConversationList from "../components/conversation/ConversationList.vue"; |
| | | import HistoryMessageDialog from "../components/message/HistoryMessageDialog.vue" |
| | | import ScheduleSuggestDialog from "../components/suggest/ScheduleSuggestDialog.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([ |
| | | { |
| | |
| | | }, |
| | | { |
| | | name: '转炉煤气 O 含量', |
| | | value: 618, |
| | | value: 10, |
| | | unit: '%' |
| | | }, |
| | | { |
| | |
| | | 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', |
| | | }, |
| | | ]) |
| | | |
| | |
| | | |
| | | const mqhsjhxxList = ref([ |
| | | { |
| | | name: '转炉总炉数\n' + |
| | | '日计划', |
| | | value: 567, |
| | | name: '转炉总炉数日计划', |
| | | value: 123, |
| | | unit: '炉' |
| | | }, |
| | | { |
| | | name: '转炉入炉铁水量\n' + |
| | | '日计划', |
| | | value: 200, |
| | | unit: '吨' |
| | | }, |
| | | { |
| | | name: '转炉检修计划', |
| | | value: '未进行', |
| | | value: '0', |
| | | unit: '' |
| | | }, |
| | | { |
| | | name: '钢产量日计划', |
| | | value: 300, |
| | | unit: '吨' |
| | | }, |
| | | { |
| | | name: '转炉加入废钢总量', |
| | | value: 500, |
| | | unit: '吨' |
| | | value: 20000, |
| | | unit: 't' |
| | | }, |
| | | { |
| | | name: '转炉实绩钢产量', |
| | | value: 100, |
| | | unit: '吨' |
| | | value: 20929, |
| | | unit: 't' |
| | | } |
| | | ]) |
| | | |
| | |
| | | { |
| | | id: 1, |
| | | name: '1#转炉', |
| | | current: 20, |
| | | total: 30 |
| | | current: 4, |
| | | total: 29 |
| | | }, |
| | | { |
| | | id: 2, |
| | | name: '2#转炉', |
| | | current: 25, |
| | | total: 100 |
| | | current: 5, |
| | | total: 42 |
| | | }, |
| | | { |
| | | id: 3, |
| | | name: '3#转炉', |
| | | current: 4, |
| | | total: 29 |
| | | current: 6, |
| | | total: 42 |
| | | } |
| | | ]) |
| | | |
| | |
| | | } |
| | | |
| | | ]) |
| | | |
| | | const topSuggests = ref<ScheduleSuggestVO[]>([]) |
| | | |
| | | const contentRef = ref([]); |
| | | const isOverflow = ref([]); |
| | | |
| | | const ddtlResult = ref('') |
| | | |
| | |
| | | message.thinking = match[2]; |
| | | message.conclusion = match[4] |
| | | } |
| | | message.thinking = formatReasoningContent(message.thinking) |
| | | return message |
| | | } |
| | | |
| | | |
| | | /** 调度建议 */ |
| | | const scheduleSuggestRef = ref() |
| | | const openSuggest = async () => { |
| | | scheduleSuggestRef.value.open() |
| | | } |
| | | /** |
| | | * 消息列表 |
| | | * |
| | |
| | | */ |
| | | 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) { |
| | |
| | | } |
| | | 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); |
| | | const result = match ? match[2].trim() : ''; |
| | | return result |
| | | } |
| | | |
| | | const extractRecoveryDetails = (text, consume, gui, totalMinutes = 60) => { |
| | |
| | | conversationId: activeConversationId.value, |
| | | content: content |
| | | } as ChatMessageVO) |
| | | // 保存调度建议 |
| | | setTimeout(async () => { |
| | | await createSuggest() |
| | | }, 1000) |
| | | } |
| | | |
| | | /** 真正执行【发送】消息操作 */ |
| | |
| | | } 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回收量预测) |
| | |
| | | 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 // 原始值 |
| | |
| | | }, |
| | | 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' |
| | | }, |
| | |
| | | focus: 'series' |
| | | }, |
| | | lineStyle: { |
| | | width: 1, |
| | | color: '#FF7686' // 粉色 |
| | | } |
| | | }, |
| | |
| | | focus: 'series' |
| | | }, |
| | | lineStyle: { |
| | | width: 1, |
| | | color: '#49FFD3' // 绿色 |
| | | } |
| | | }, |
| | |
| | | focus: 'series' |
| | | }, |
| | | lineStyle: { |
| | | width: 1, |
| | | color: '#FFAE81' // 橙色 |
| | | }, |
| | | }, |
| | |
| | | focus: 'series' |
| | | }, |
| | | lineStyle: { |
| | | width: 1, |
| | | color: 'white' |
| | | }, |
| | | } |
| | |
| | | left: 0, |
| | | right: 0, |
| | | bottom: 10, |
| | | top: 20, |
| | | top: 10, |
| | | containLabel: true |
| | | }, |
| | | tooltip: { |
| | |
| | | data: realData, |
| | | smooth: true, |
| | | symbol: 'none', |
| | | lineStyle: { color: '#95E6FF' }, |
| | | lineStyle: { |
| | | color: '#95E6FF', |
| | | width: 1 |
| | | }, |
| | | markLine: { |
| | | symbol: ['none', 'none'], |
| | | label: { |
| | |
| | | lineStyle: { |
| | | type: 'dashed', |
| | | color: '#E76666', |
| | | width: 1, |
| | | dashOffset: 5 |
| | | } |
| | | }, |
| | |
| | | // 初始状态检测 |
| | | updateFullscreenStatus(); |
| | | } |
| | | /** 查询列表 */ |
| | | const getTopSuggest = async () => { |
| | | const data = await ScheduleSuggestApi.getTopScheduleSuggests(5) |
| | | topSuggests.value = data |
| | | } |
| | | |
| | | /** 初始化 **/ |
| | | onMounted(async () => { |
| | |
| | | // 获取列表数据 |
| | | activeMessageListLoading.value = true |
| | | await getMessageList() |
| | | await getTopSuggest() |
| | | }) |
| | | |
| | | // 清理监听 |
| | | onUnmounted(() => { |
| | | console.log('stopStream') |
| | | const events = ['fullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange']; |
| | | events.forEach(event => { |
| | | document.removeEventListener(event, handleFullscreenChange); |
| | |
| | | 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 { |
| | |
| | | } |
| | | } |
| | | .data2-item { |
| | | height: 2.8rem; |
| | | width: 45%; |
| | | height: 1.4rem; |
| | | width: 46%; |
| | | display: inline-block; |
| | | margin: 6px 8px; |
| | | margin: 8px 8px; |
| | | background: url("@/assets/ai/zhuanlu/data_bg3.png") no-repeat; |
| | | } |
| | | .content { |
| | |
| | | margin-left: 10px; |
| | | |
| | | .name { |
| | | width: 95px; |
| | | height: 18px; |
| | | width: 130px; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #C7E7FF; |
| | | } |
| | | |
| | | .value { |
| | | margin-top: 10px; |
| | | margin-left: auto; |
| | | margin-right: 5px; |
| | | span:nth-child(1) { |
| | |
| | | .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; |
| | |
| | | } |
| | | } |
| | | } |
| | | .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; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |