|
@@ -1,23 +1,62 @@
|
|
|
<script setup lang="jsx">
|
|
|
-import { ref, h } from 'vue';
|
|
|
-import { NTabs, NTab, NEllipsis, NModal, NInput } from 'naive-ui';
|
|
|
+import { ref, unref, watch } from 'vue';
|
|
|
+import { NTabs, NTab } from 'naive-ui';
|
|
|
import { BaseCard, BaseTable, ChatWelcome, SvgIcon, RecodeSquareCardItem, TheSubMenu, TheChatView } from "@/components";
|
|
|
+import { ChatAsk, ChatBaseCard, ChatAnswer } from '@/components/Chat';
|
|
|
|
|
|
-import { useInfinite } from '@/composables/useInfinite';
|
|
|
+import { format } from "@/utils/format";
|
|
|
+
|
|
|
+import { waterApi } from '@/api/water';
|
|
|
import { CustomModal } from "./components";
|
|
|
|
|
|
+import { useInfinite } from '@/composables/useInfinite';
|
|
|
+import { useRecommend } from '@/composables/useRecommend';
|
|
|
+import { useFetchStream } from '@/composables/useFetchStream';
|
|
|
+import { useScroll } from '@/composables/useScroll';
|
|
|
+
|
|
|
+const { recommendList } = useRecommend({type: 1});
|
|
|
+const { scrollRef, scrollToTop, scrollToBottomIfAtBottom } = useScroll();
|
|
|
+const { streamData, refetch } = useFetchStream("/grpc/decisionStream", { methdos: 'POST' }, false);
|
|
|
const { recordList, isFetching, onScrolltolower, onRestore, addHistoryRecord } = useInfinite('/front/bigModel/warning/pageList', { type: 0, warningStatus: 0 });
|
|
|
|
|
|
+let controller = new AbortController();
|
|
|
+
|
|
|
+// 获取最终回答流数据参数
|
|
|
+const flowParams = {
|
|
|
+ feedback: '',
|
|
|
+ category: '',
|
|
|
+ warningId: ''
|
|
|
+};
|
|
|
+
|
|
|
+const reportAnswer = ref('');
|
|
|
+const alertAnswer = ref([]);
|
|
|
+
|
|
|
+const checkedAlertData = ref([]);
|
|
|
+
|
|
|
+const textDataSources = ref(null);
|
|
|
+const answerAlertDataSources = ref([]);
|
|
|
+
|
|
|
+// 进出水数据
|
|
|
+const jsTableData = ref([]);
|
|
|
+const csTableData = ref([]);
|
|
|
+
|
|
|
const visible = ref(false);
|
|
|
|
|
|
+const renderRowDom = ({ row, key }) => {
|
|
|
+ const { exceed, value } = row[key] || {};
|
|
|
+ const cls = exceed ? 'text-[#F44C49] font-bold' : 'text-[1A2029]'
|
|
|
+ return (<span class={ cls }>{value} {exceed && <i>↑</i>}</span>)
|
|
|
+}
|
|
|
+
|
|
|
const columns = [
|
|
|
{
|
|
|
- title: (<span class="text-[11px]">COD</span>),
|
|
|
+ title: '流量(m³/h)',
|
|
|
key: 'name',
|
|
|
titleAlign: 'center',
|
|
|
align: 'center',
|
|
|
className: 'small',
|
|
|
- width: '80px'
|
|
|
+ width: '80px',
|
|
|
+ render: (row) => renderRowDom({ row, key: '流量' })
|
|
|
},
|
|
|
{
|
|
|
title: 'COD(mg/L)',
|
|
@@ -25,7 +64,8 @@ const columns = [
|
|
|
titleAlign: 'center',
|
|
|
align: 'center',
|
|
|
className: 'small',
|
|
|
- width: '80px'
|
|
|
+ width: '80px',
|
|
|
+ render: (row) => renderRowDom({ row, key: 'COD' })
|
|
|
},
|
|
|
{
|
|
|
title: 'TN(mg/L)',
|
|
@@ -33,39 +73,38 @@ const columns = [
|
|
|
titleAlign: 'center',
|
|
|
align: 'center',
|
|
|
className: 'small',
|
|
|
- width: '80px'
|
|
|
+ width: '80px',
|
|
|
+ render: (row) => renderRowDom({ row, key: 'TN' })
|
|
|
},
|
|
|
{
|
|
|
- title: 'NH3 -N(mg/L)',
|
|
|
+ title: 'NH3-N(mg/L)',
|
|
|
key: 'tags',
|
|
|
titleAlign: 'center',
|
|
|
align: 'center',
|
|
|
className: 'small',
|
|
|
- width: '80px'
|
|
|
+ width: '80px',
|
|
|
+ render: (row) => renderRowDom({ row, key: 'NH3-N' })
|
|
|
},
|
|
|
{
|
|
|
title: '总磷TP(mg/L)',
|
|
|
- key: 'actions',
|
|
|
+ key: 'COD',
|
|
|
titleAlign: 'center',
|
|
|
align: 'center',
|
|
|
className: 'small',
|
|
|
width: '80px',
|
|
|
- render(row) {
|
|
|
- // TODO: 需要调整,待后续请求参数确定
|
|
|
- return (<span class={row.actions > 7 ? 'text-[#F44C49] font-bold' : 'text-[1A2029]'}>{row.actions} ↑</span>)
|
|
|
- }
|
|
|
+ render: (row) => renderRowDom({ row, key: 'TP' })
|
|
|
},
|
|
|
{
|
|
|
title: 'SS(mg/L)',
|
|
|
- key: 'actions1',
|
|
|
+ key: '流量',
|
|
|
titleAlign: 'center',
|
|
|
align: 'center',
|
|
|
className: 'age',
|
|
|
- width: '78px'
|
|
|
+ width: '78px',
|
|
|
+ render: (row) => renderRowDom({ row, key: 'SS' })
|
|
|
}
|
|
|
]
|
|
|
|
|
|
-
|
|
|
const inWaterTableData = ref([{ name: 1233, actions: "7.87" }]);
|
|
|
|
|
|
// 新建对话
|
|
@@ -81,14 +120,124 @@ const handleModelVisible = () => {
|
|
|
visible.value = true
|
|
|
}
|
|
|
|
|
|
-const handleOpenContent = () => {
|
|
|
- alert(1)
|
|
|
+/**
|
|
|
+ * 报警详情
|
|
|
+*/
|
|
|
+const handleOpenContent = async ({id, category}) => {
|
|
|
+ const { data } = await waterApi.getWaringDetails(id);
|
|
|
+ const showVal = JSON.parse(data.showVal);
|
|
|
+ const { basic, jsData, csData } = showVal;
|
|
|
+ const answer = JSON.parse(data.answer);
|
|
|
+ const [ answerStrItem ] = answer;
|
|
|
+ const answerObjItem = JSON.parse( answerStrItem );
|
|
|
+
|
|
|
+ console.log( answerObjItem.biz );
|
|
|
+
|
|
|
+ const textWhiteList = [
|
|
|
+ { label: '报警时间', value: '', isWarning: false },
|
|
|
+ { label: '报警值', value: 'mg/L', isWarning: true },
|
|
|
+ { label: '管控值', value: 'mg/L', isWarning: false },
|
|
|
+ { label: '标准值', value: 'mg/L', isWarning: false },
|
|
|
+ { label: '报警级别', value: '', isWarning: false },
|
|
|
+ { label: '报警次数', value: '', isWarning: false },
|
|
|
+ { label: '状态', value: '', isWarning: false }
|
|
|
+ ]
|
|
|
+
|
|
|
+ if ( answerObjItem.biz === "DECISION_REPORT" ) {
|
|
|
+ alertAnswer.value = [];
|
|
|
+ reportAnswer.value = answer.map(item => {
|
|
|
+ const itemParse = JSON.parse(item);
|
|
|
+ return itemParse.message;
|
|
|
+ }).join();
|
|
|
+ } else {
|
|
|
+ reportAnswer.value = '';
|
|
|
+ const [ parseAnswer ] = answer.map(item => {
|
|
|
+ const result = JSON.parse( item );
|
|
|
+ result.message = Object.keys(result.message).map(key => ({ ...result.message[key], isActive: null }));
|
|
|
+ return result;
|
|
|
+ })
|
|
|
+ console.log( parseAnswer?.message );
|
|
|
+ alertAnswer.value = parseAnswer?.message;
|
|
|
+ }
|
|
|
+
|
|
|
+ textDataSources.value = format.textSorting(basic, textWhiteList);
|
|
|
+
|
|
|
+ jsTableData.value = [jsData];
|
|
|
+ csTableData.value = [csData];
|
|
|
+
|
|
|
+ flowParams.category = category;
|
|
|
+ flowParams.warningId = id;
|
|
|
+
|
|
|
+ scrollToTop();
|
|
|
}
|
|
|
|
|
|
const onChangeTabs = warningStatus => {
|
|
|
- console.log( "warningStatus", warningStatus );
|
|
|
onRestore({ warningStatus })
|
|
|
}
|
|
|
+
|
|
|
+const onRegenerate = async () => {
|
|
|
+
|
|
|
+ let counter = 0;
|
|
|
+ let str = 0;
|
|
|
+
|
|
|
+ // const timer = setInterval(item => {
|
|
|
+ // if( timer === 10 ) {
|
|
|
+ // console.log("str", str);
|
|
|
+ // clearInterval(timer);
|
|
|
+ // }
|
|
|
+ // counter++;
|
|
|
+ // const data = {biz: "DECISION_REPORT", message: counter};
|
|
|
+
|
|
|
+ // str += data.message + "||"
|
|
|
+
|
|
|
+ // reportAnswer.value = str;
|
|
|
+
|
|
|
+ // }, 1000)
|
|
|
+
|
|
|
+
|
|
|
+ try {
|
|
|
+ const obj = {"biz": "DECISION_ALERT", "message": {"2_30": {"id": "2_30", "mainType": "alert", "mainContent": "设备与电气类是否有故障发生", "options": ["否", "是"], "next": "", "checked": false}}}
|
|
|
+ const result = Object.keys(obj.message).map(key => ({ ...obj.message[key], isActive: null }));
|
|
|
+ console.log( "result", result );
|
|
|
+ // refetch({
|
|
|
+ // body: JSON.stringify(flowParams),
|
|
|
+ // successHandler: data => {
|
|
|
+ // const item = JSON.parse(data);
|
|
|
+ // str += item.message;
|
|
|
+ // reportAnswer.value = str;
|
|
|
+ // scrollToBottomIfAtBottom()
|
|
|
+ // },
|
|
|
+ // doneHandler: () => {
|
|
|
+ // alert("结束了")
|
|
|
+ // }
|
|
|
+ // })
|
|
|
+ }
|
|
|
+ catch(error) {
|
|
|
+ console.log("exist error .....", error);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 回答选项点击
|
|
|
+const handlerAlertOptions = (item, index) => {
|
|
|
+
|
|
|
+ const isExists = checkedAlertData.value.find(d => d.id === item.id);
|
|
|
+
|
|
|
+ item.isActive = index;
|
|
|
+
|
|
|
+ isExists ?? checkedAlertData.value.push( item );
|
|
|
+
|
|
|
+ if ( unref(checkedAlertData).length === unref(alertAnswer).length ) {
|
|
|
+
|
|
|
+ const tempArr = alertAnswer.value.map(({ id, options, isActive }) => ({ [id]: options[isActive] }));
|
|
|
+ const tempArrToStr = JSON.stringify(tempArr);
|
|
|
+
|
|
|
+ flowParams.feedback = JSON.stringify(tempArr).substring(1, tempArrToStr.length - 1);
|
|
|
+
|
|
|
+ onRegenerate();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
@@ -115,24 +264,74 @@ const onChangeTabs = warningStatus => {
|
|
|
</div>
|
|
|
</TheSubMenu>
|
|
|
|
|
|
- <TheChatView>
|
|
|
+ <TheChatView ref="scrollRef" :is-footer="false">
|
|
|
|
|
|
<ChatWelcome title="您好,我是LibraAI工艺管控助手" card-title="常见处理方案:"
|
|
|
:sub-title="[
|
|
|
'报警分析功能具备实时监测与预警机制,检测到异常情况立即触发多种报警方式,推送相关',
|
|
|
'工作人员确保问题及时处理。报警时间为每小时警报,请大家及时处理。'
|
|
|
]"
|
|
|
- :card-content="[
|
|
|
- '进水COD超标原因分析及常见的解决方案',
|
|
|
- '进水TP超标原因分析及常见的解决方案',
|
|
|
- '出水TN超标原因分析及常见的解决方案'
|
|
|
- ]" v-if="false"
|
|
|
+ :card-content="recommendList"
|
|
|
+ v-if="!textDataSources"
|
|
|
/>
|
|
|
+
|
|
|
+ <ChatBaseCard v-if="textDataSources">
|
|
|
+ <div class="waring-answer-wrapper">
|
|
|
+ <dl class="message-inner warning-info_medium ">
|
|
|
+ <dt class="mb-[2px] font-bold text-[#1A2029]">{{ textDataSources?.value }}</dt>
|
|
|
+ <dd v-for="item, index in textDataSources?.list" :key="index"><span :class="{'text-[#F44C49]': item.isWarning}">{{ item.label }}: {{ item.value }}</span></dd>
|
|
|
+ </dl>
|
|
|
+ <div class="table-inner">
|
|
|
+ <div class="warning-table mb-[8px]">
|
|
|
+ <div class="title">
|
|
|
+ <span>当前进水数据:</span>
|
|
|
+ </div>
|
|
|
+ <div class="main">
|
|
|
+ <BaseTable :columns="columns" :data="jsTableData"></BaseTable>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="warning-table">
|
|
|
+ <div class="title">
|
|
|
+ <span>当前出水数据:</span>
|
|
|
+ </div>
|
|
|
+ <div class="main">
|
|
|
+ <BaseTable :columns="columns" :data="csTableData"></BaseTable>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </ChatBaseCard>
|
|
|
+
|
|
|
+ <!-- report -->
|
|
|
+ <ChatAnswer
|
|
|
+ :loading="true"
|
|
|
+ :toggleVisibleIcons="false"
|
|
|
+ :content="reportAnswer"
|
|
|
+ v-show="reportAnswer"
|
|
|
+ ></ChatAnswer>
|
|
|
+
|
|
|
+ <!-- alert -->
|
|
|
+ <ChatBaseCard v-show="alertAnswer.length">
|
|
|
+ <p class="mb-[15px] font-bold text-[#1A2029]">需要确定以下问题,完成决策方案:</p>
|
|
|
+ <ul class="radio-wrapper space-y-[14px]">
|
|
|
+ <li class="flex items-center" v-for="item in alertAnswer" :key="item.id">
|
|
|
+ <p class="mr-[14px]">{{ item.mainContent }}</p>
|
|
|
+ <p class="radio-btn-group space-x-[14px]">
|
|
|
+ <span
|
|
|
+ :key="index"
|
|
|
+ :class="['radio-btn', { active: item.isActive === index }]"
|
|
|
+ v-for="val,index in item.options"
|
|
|
+ @click="handlerAlertOptions(item, index)"
|
|
|
+ >{{ val }}</span>
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </ChatBaseCard>
|
|
|
|
|
|
- <BaseCard :loading="true">
|
|
|
+ <!-- <BaseCard :loading="true">
|
|
|
<div class="waring-answer-wrapper">
|
|
|
<dl class="message-inner warning-info_medium ">
|
|
|
- <dt class="mb-[2px] font-bold text-[#1A2029]">进水总磷报警</dt>
|
|
|
+ <dt class="mb-[2px] font-bold text-[#1A2029]">{{ textDataSources?.title }}</dt>
|
|
|
<dd><span>报警时间:2024-4-25 21:00</span></dd>
|
|
|
<dd><span class="text-[#F44C49]">报警值:7.87mg/L</span></dd>
|
|
|
<dd><span>标准值:7.1mg/L</span></dd>
|
|
@@ -146,7 +345,6 @@ const onChangeTabs = warningStatus => {
|
|
|
<span>当前进水数据:</span>
|
|
|
</div>
|
|
|
<div class="main">
|
|
|
- <BaseTable :columns="columns" :data="inWaterTableData"></BaseTable>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="warning-table">
|
|
@@ -154,14 +352,13 @@ const onChangeTabs = warningStatus => {
|
|
|
<span>当前出水数据:</span>
|
|
|
</div>
|
|
|
<div class="main">
|
|
|
- <BaseTable :columns="columns" :data="[]"></BaseTable>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </BaseCard>
|
|
|
+ </BaseCard> -->
|
|
|
|
|
|
- <BaseCard>
|
|
|
+ <!-- <BaseCard>
|
|
|
<p class="flex-1 text-[15px] leading-[24px]">
|
|
|
COD,即化学需氧量,是衡量水中有机物质含量的重要指标。它反映了水中可氧化有机物的量,通常用来评估水体的污染程度。水中的有机物主要来源于工业废水、生活污水、农药残留等,这些有机物不仅会导致水质变差,还会对生物和人类健康产生负面影响。因此,通过测定COD值,可以了解水中有机污染物的含量,进而评估水体的污染程度。这对于制定环境保护政策、控制污染源、保障水资源安全等方面都具有重要的指导意义
|
|
|
</p>
|
|
@@ -175,27 +372,9 @@ const onChangeTabs = warningStatus => {
|
|
|
@click="handleModelVisible"
|
|
|
>
|
|
|
水质预测推演
|
|
|
- </button>
|
|
|
+ </button> -->
|
|
|
+
|
|
|
|
|
|
- <BaseCard>
|
|
|
- <p class="mb-[15px] font-bold text-[#1A2029]">需要确定以下问题,完成决策方案:</p>
|
|
|
- <ul class="radio-wrapper space-y-[14px]">
|
|
|
- <li class="flex items-center ">
|
|
|
- <p class="mr-[14px]">在线仪表是否正常?</p>
|
|
|
- <p class="radio-btn-group space-x-[14px]">
|
|
|
- <span class="radio-btn active">是</span>
|
|
|
- <span class="radio-btn">否</span>
|
|
|
- </p>
|
|
|
- </li>
|
|
|
- <li class="flex items-center ">
|
|
|
- <p class="mr-[14px]">在线仪表是否正常?</p>
|
|
|
- <p class="radio-btn-group space-x-[14px]">
|
|
|
- <span class="radio-btn">是</span>
|
|
|
- <span class="radio-btn">否</span>
|
|
|
- </p>
|
|
|
- </li>
|
|
|
- </ul>
|
|
|
- </BaseCard>
|
|
|
|
|
|
</TheChatView>
|
|
|
</section>
|