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}}
@@ -62,7 +68,7 @@
    <div class="gas-scheduling-center">
      <div class="mode-switch">
        <el-radio-group v-model="tabPosition" class="custom-radio-group">
        <el-radio-group v-model="tabPosition" @change="handleChange" class="custom-radio-group">
          <el-radio-button label="model">大模型模式</el-radio-button>
          <el-radio-button label="conversation">对话模式</el-radio-button>
        </el-radio-group>
@@ -164,23 +170,26 @@
        <!-- 历史建议 -->
        <HistoryMessageDialog
          ref="historyMessageRef"
          :conversation="activeConversation"
          :parentMethod="queryHistoryMessage"
          @gotoManualMethod="gotoManual"
        />
      </div>
      <div v-else>
        <NormalConversation />
        <NormalConversation
          :data="defaultMessage"
        />
      </div>
    </div>
    <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>
@@ -245,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>
@@ -259,12 +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 {ScheduleSuggestApi, ScheduleSuggestVO} from "@/api/ai/schedulesuggest";
import {formatDate} from "@/utils/formatTime";
const mqhsList = ref([
  {
@@ -274,7 +312,7 @@
  },
  {
    name: '转炉煤气 O 含量',
    value: 618,
    value: 10,
    unit: '%'
  },
  {
@@ -302,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',
  },
])
@@ -436,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'
  }
])
@@ -491,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
  }
])
@@ -533,6 +586,11 @@
])
const topSuggests = ref<ScheduleSuggestVO[]>([])
const contentRef = ref([]);
const isOverflow = ref([]);
const ddtlResult = ref('')
const route = useRoute() // 路由
@@ -548,6 +606,7 @@
const messageRef = ref()
const activeMessageList = ref<ChatMessageVO[]>([]) // 选中对话的消息列表
const activeHistoryMessageList = ref<ChatMessageVO[]>([]) // 历史建议列表
const activeHistoryMessageTotal = ref(0) // 历史建议总数
const activeMessageListLoading = ref<boolean>(false) // activeMessageList 是否正在加载中
const activeMessageListLoadingTimer = ref<any>() // activeMessageListLoading Timer 定时器。如果加载速度很快,就不进入加载中
// 消息滚动
@@ -573,8 +632,30 @@
const historyMessageRef = ref()
const openHistoryMessage = async () => {
  // 刷新 message 列表
  await getHistoryMessageList()
  historyMessageRef.value.open(activeHistoryMessageList.value, activeConversation.value)
  let resDate = await historyMessageRef.value.dealDate()
  await getHistoryMessageList(resDate)
  historyMessageRef.value.open(activeHistoryMessageList.value, activeConversation.value, activeHistoryMessageTotal.value)
}
const queryHistoryMessage = async (queryParams: ChatMessageVO) => {
  return await getHistoryMessageList(queryParams)
}
//切换对话模式判断
const handleChange = async () => {
  // 对话进行中,不允许切换
  if (conversationInProgress.value) {
    message.alert('对话中,不允许切换!')
    return false
  }
}
// 默认选中消息
const defaultMessage = ref<ChatMessageVO>()
const gotoManual = async (item: ChatMessageVO) => {
  defaultMessage.value = item
  tabPosition.value = 'conversation'
}
// =========== 【聊天对话】相关 ===========
@@ -671,22 +752,23 @@
}
/** 获取消息 message 列表 */
const getHistoryMessageList = async () => {
const getHistoryMessageList = async (params: any) => {
  if (activeConversationId.value === null) {
    return
  }
  params.conversationId = activeConversationId.value
  // 获取消息列表
  activeHistoryMessageList.value = await ChatMessageApi.getChatMessageListByConversationId(
    activeConversationId.value
  )
  if (activeHistoryMessageList.value.length > 0) {
  let pageResult = await ChatMessageApi.getChatMessagePageListByConversationId(params)
  activeHistoryMessageList.value = pageResult.list
  activeHistoryMessageTotal.value = pageResult.total
  if (activeHistoryMessageList.value != null && activeHistoryMessageList.value.length > 0) {
    activeHistoryMessageList.value.forEach((message: ChatMessageVO) => {
      if(message.type != 'user') {
        dealResult(message)
      }
    })
    return activeHistoryMessageList.value
  }
  return pageResult
}
//处理调度推理结论
const dealResult = (message: any) => {
@@ -697,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()
}
/**
 * 消息列表
 *
@@ -708,9 +794,22 @@
 */
const messageList = computed(() => {
  if (activeMessageList.value.length > 0) {
    activeMessageList.value[1].thinking = dealResultAndData(activeMessageList.value[1].content)
    console.log(activeMessageList.value)
    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) {
@@ -746,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) => {
@@ -918,6 +1025,10 @@
    conversationId: activeConversationId.value,
    content: content
  } as ChatMessageVO)
  // 保存调度建议
  setTimeout(async () => {
    await createSuggest()
  }, 1000)
}
/** 真正执行【发送】消息操作 */
@@ -1081,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回收量预测)
@@ -1121,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        // 原始值
@@ -1143,11 +1279,11 @@
  let returnValue = 0;
  if(type == 'max') {
    returnValue = computed(() => {
      return Math.max(...tank) + 20
      return Number((Math.max(...tank) + 20).toFixed(0))
    })
  } else if(type == 'min') {
    returnValue = computed(() => {
      return Math.min(...tank) - 60
      return Number((Math.min(...tank) - 60).toFixed(0))
    })
  } else if(type == 'average') {
    returnValue = computed(() => {
@@ -1155,7 +1291,7 @@
      tank.forEach((item) => {
        sum += item[0]
      })
      return (sum / tank.length).toFixed(0);
      return Number((sum / tank.length).toFixed(0));
    })
  }
  return returnValue.value
@@ -1205,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'
      },
@@ -1266,6 +1402,7 @@
          focus: 'series'
        },
        lineStyle: {
          width: 1,
          color: '#FF7686' // 粉色
        }
      },
@@ -1279,6 +1416,7 @@
          focus: 'series'
        },
        lineStyle: {
          width: 1,
          color: '#49FFD3' // 绿色
        }
      },
@@ -1293,6 +1431,7 @@
          focus: 'series'
        },
        lineStyle: {
          width: 1,
          color: '#FFAE81' // 橙色
        },
      },
@@ -1306,6 +1445,7 @@
          focus: 'series'
        },
        lineStyle: {
          width: 1,
          color: 'white'
        },
      }
@@ -1356,7 +1496,7 @@
      left: 0,
      right: 0,
      bottom: 10,
      top: 20,
      top: 10,
      containLabel: true
    },
    tooltip: {
@@ -1407,7 +1547,10 @@
        data: realData,
        smooth: true,
        symbol: 'none',
        lineStyle: { color: '#95E6FF' },
        lineStyle: {
          color: '#95E6FF',
          width: 1
        },
        markLine: {
          symbol: ['none', 'none'],
          label: {
@@ -1432,6 +1575,7 @@
        lineStyle: {
          type: 'dashed',
          color: '#E76666',
          width: 1,
          dashOffset: 5
        }
      },
@@ -1564,6 +1708,11 @@
  // 初始状态检测
  updateFullscreenStatus();
}
/** 查询列表 */
const getTopSuggest = async () => {
  const data = await ScheduleSuggestApi.getTopScheduleSuggests(5)
  topSuggests.value = data
}
/** 初始化 **/
onMounted(async () => {
@@ -1578,6 +1727,7 @@
  // 获取列表数据
  activeMessageListLoading.value = true
  await getMessageList()
  await getTopSuggest()
})
// 清理监听
@@ -1654,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 {
@@ -2201,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 {
@@ -2213,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) {
@@ -2251,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;
@@ -2327,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;
        }
      }
    }
  }
}