dongyukun
21 小时以前 e295922209fb87c6dcd68ea1560fd16c3e6d808c
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,31 @@
          <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>
@@ -262,13 +293,16 @@
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([
  {
@@ -278,7 +312,7 @@
  },
  {
    name: '转炉煤气 O 含量',
    value: 618,
    value: 10,
    unit: '%'
  },
  {
@@ -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,36 +501,24 @@
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'
  }
])
@@ -495,20 +544,20 @@
  {
    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
  }
])
@@ -536,6 +585,11 @@
  }
])
const topSuggests = ref<ScheduleSuggestVO[]>([])
const contentRef = ref([]);
const isOverflow = ref([]);
const ddtlResult = ref('')
@@ -725,10 +779,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 +794,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 +845,14 @@
  }
  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) => {
@@ -945,6 +1025,10 @@
    conversationId: activeConversationId.value,
    content: content
  } as ChatMessageVO)
  // 保存调度建议
  setTimeout(async () => {
    await createSuggest()
  }, 1000)
}
/** 真正执行【发送】消息操作 */
@@ -1108,6 +1192,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 +1257,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 +1341,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 +1402,7 @@
          focus: 'series'
        },
        lineStyle: {
          width: 1,
          color: '#FF7686' // 粉色
        }
      },
@@ -1306,6 +1416,7 @@
          focus: 'series'
        },
        lineStyle: {
          width: 1,
          color: '#49FFD3' // 绿色
        }
      },
@@ -1320,6 +1431,7 @@
          focus: 'series'
        },
        lineStyle: {
          width: 1,
          color: '#FFAE81' // 橙色
        },
      },
@@ -1333,6 +1445,7 @@
          focus: 'series'
        },
        lineStyle: {
          width: 1,
          color: 'white'
        },
      }
@@ -1383,7 +1496,7 @@
      left: 0,
      right: 0,
      bottom: 10,
      top: 20,
      top: 10,
      containLabel: true
    },
    tooltip: {
@@ -1434,7 +1547,10 @@
        data: realData,
        smooth: true,
        symbol: 'none',
        lineStyle: { color: '#95E6FF' },
        lineStyle: {
          color: '#95E6FF',
          width: 1
        },
        markLine: {
          symbol: ['none', 'none'],
          label: {
@@ -1459,6 +1575,7 @@
        lineStyle: {
          type: 'dashed',
          color: '#E76666',
          width: 1,
          dashOffset: 5
        }
      },
@@ -1591,6 +1708,11 @@
  // 初始状态检测
  updateFullscreenStatus();
}
/** 查询列表 */
const getTopSuggest = async () => {
  const data = await ScheduleSuggestApi.getTopScheduleSuggests(5)
  topSuggests.value = data
}
/** 初始化 **/
onMounted(async () => {
@@ -1605,11 +1727,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 +1804,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,10 +2380,10 @@
        }
      }
      .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 {
@@ -2241,15 +2392,13 @@
        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) {
@@ -2279,13 +2428,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 +2504,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;
        }
      }
    }
  }
}