|
@@ -1,8 +1,10 @@
|
|
|
<script setup lang="jsx">
|
|
|
-import { ref, unref, watch } from 'vue';
|
|
|
+import { ref } from 'vue';
|
|
|
+import { useRouter } from 'vue-router';
|
|
|
import { NTabs, NTab } from 'naive-ui';
|
|
|
-import { BaseCard, BaseTable, ChatWelcome, SvgIcon, RecodeSquareCardItem, TheSubMenu, TheChatView } from "@/components";
|
|
|
-import { ChatAsk, ChatBaseCard, ChatAnswer } from '@/components/Chat';
|
|
|
+import { useChatStore } from '@/stores/modules/chatStore';
|
|
|
+import { BaseTable, ChatWelcome, RecodeSquareCardItem, TheSubMenu, TheChatView } from "@/components";
|
|
|
+import { ChatBaseCard, ChatAnswer } from '@/components/Chat';
|
|
|
|
|
|
import { format } from "@/utils/format";
|
|
|
|
|
@@ -16,11 +18,14 @@ 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 { refetch, cancelFetch } = 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 router = useRouter();
|
|
|
+const chatStore = useChatStore();
|
|
|
|
|
|
+// 回答列表
|
|
|
+const answerResult = ref([]);
|
|
|
// 获取最终回答流数据参数
|
|
|
const flowParams = {
|
|
|
feedback: '',
|
|
@@ -28,13 +33,9 @@ const flowParams = {
|
|
|
warningId: ''
|
|
|
};
|
|
|
|
|
|
-const reportAnswer = ref('');
|
|
|
-const alertAnswer = ref([]);
|
|
|
-
|
|
|
-const checkedAlertData = ref([]);
|
|
|
+const answerLoading = ref(false);
|
|
|
|
|
|
const textDataSources = ref(null);
|
|
|
-const answerAlertDataSources = ref([]);
|
|
|
|
|
|
// 进出水数据
|
|
|
const jsTableData = ref([]);
|
|
@@ -105,7 +106,6 @@ const columns = [
|
|
|
}
|
|
|
]
|
|
|
|
|
|
-const inWaterTableData = ref([{ name: 1233, actions: "7.87" }]);
|
|
|
|
|
|
// 新建对话
|
|
|
const handleCreateDialog = () => {
|
|
@@ -123,13 +123,23 @@ const handleModelVisible = () => {
|
|
|
/**
|
|
|
* 报警详情
|
|
|
*/
|
|
|
-const handleOpenContent = async ({id, category}) => {
|
|
|
+const handleOpenContent = async ({ id, category }) => {
|
|
|
+
|
|
|
+ if ( id == flowParams.warningId ) return;
|
|
|
+
|
|
|
+ flowParams.category = category;
|
|
|
+ flowParams.warningId = id;
|
|
|
+
|
|
|
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 );
|
|
|
+
|
|
|
+ cancelFetch();
|
|
|
+
|
|
|
+ answerResult.value = [];
|
|
|
|
|
|
console.log( answerObjItem.biz );
|
|
|
|
|
@@ -144,20 +154,33 @@ const handleOpenContent = async ({id, category}) => {
|
|
|
]
|
|
|
|
|
|
if ( answerObjItem.biz === "DECISION_REPORT" ) {
|
|
|
- alertAnswer.value = [];
|
|
|
- reportAnswer.value = answer.map(item => {
|
|
|
+
|
|
|
+ const answerContent = answer.map(item => {
|
|
|
const itemParse = JSON.parse(item);
|
|
|
return itemParse.message;
|
|
|
}).join();
|
|
|
+
|
|
|
+ answerResult.value.push({
|
|
|
+ biz: 'DECISION_REPORT',
|
|
|
+ answer: answerContent,
|
|
|
+ loading: false,
|
|
|
+ delayLoading: false
|
|
|
+ })
|
|
|
+
|
|
|
} 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;
|
|
|
+ answerResult.value.push({
|
|
|
+ biz: 'DECISION_ALERT',
|
|
|
+ loading: false,
|
|
|
+ delayLoading: false,
|
|
|
+ isAllSelect: false,
|
|
|
+ list: parseAnswer?.message
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
textDataSources.value = format.textSorting(basic, textWhiteList);
|
|
@@ -165,52 +188,77 @@ const handleOpenContent = async ({id, category}) => {
|
|
|
jsTableData.value = [jsData];
|
|
|
csTableData.value = [csData];
|
|
|
|
|
|
- flowParams.category = category;
|
|
|
- flowParams.warningId = id;
|
|
|
-
|
|
|
scrollToTop();
|
|
|
}
|
|
|
|
|
|
const onChangeTabs = warningStatus => {
|
|
|
+ textDataSources.value = '';
|
|
|
+ answerLoading.value = false;
|
|
|
+ answerResult.value = [];
|
|
|
+ cancelFetch();
|
|
|
onRestore({ warningStatus })
|
|
|
}
|
|
|
|
|
|
const onRegenerate = async () => {
|
|
|
+
|
|
|
+ answerLoading.value = true;
|
|
|
+
|
|
|
+ const list = [ {biz: 'DECISION_REPORT', list: []} ]
|
|
|
+
|
|
|
+ const len = answerResult.value.length ? answerResult.value.length : 0;
|
|
|
+
|
|
|
+ const tempReport = {
|
|
|
+ biz: 'DECISION_REPORT',
|
|
|
+ answer: '',
|
|
|
+ loading: true,
|
|
|
+ delayLoading: true,
|
|
|
+ };
|
|
|
+ const params = {
|
|
|
+ body: JSON.stringify(flowParams),
|
|
|
+ errorHandler: () => {
|
|
|
+
|
|
|
+ },
|
|
|
+ successHandler: data => {
|
|
|
+
|
|
|
+ const item = JSON.parse(data);
|
|
|
+
|
|
|
+ answerLoading.value = false;
|
|
|
+
|
|
|
+ if (item.biz === 'DECISION_REPORT') {
|
|
|
+ tempReport.answer += item.message;
|
|
|
+ answerResult.value[len] = { ...tempReport };
|
|
|
+ }
|
|
|
+
|
|
|
+ if (item.biz === 'DECISION_ALERT') {
|
|
|
+ const list = Object.keys(item.message).map(key => ({ ...item.message[key], isActive: null }));
|
|
|
+
|
|
|
+ answerResult.value.push({
|
|
|
+ biz: 'DECISION_ALERT',
|
|
|
+ loading: true,
|
|
|
+ delayLoading: true,
|
|
|
+ isAllSelect: false,
|
|
|
+ list
|
|
|
+ })
|
|
|
|
|
|
- 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)
|
|
|
+ if (item.biz === 'DECISION_SIMULATE') {
|
|
|
+ console.log( item );
|
|
|
+ alert("DECISION_SIMULATE")
|
|
|
+ }
|
|
|
|
|
|
+ scrollToBottomIfAtBottom();
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
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("结束了")
|
|
|
- // }
|
|
|
- // })
|
|
|
+ const res = await refetch(params);
|
|
|
+ console.log( "最终", res );
|
|
|
+ const answerItem = answerResult.value[answerResult.value.length - 1];
|
|
|
+ if (answerItem?.biz) {
|
|
|
+ answerItem.loading = false;
|
|
|
+ answerItem.delayLoading = false;
|
|
|
+ }
|
|
|
}
|
|
|
catch(error) {
|
|
|
console.log("exist error .....", error);
|
|
@@ -218,30 +266,39 @@ const onRegenerate = async () => {
|
|
|
}
|
|
|
|
|
|
// 回答选项点击
|
|
|
-const handlerAlertOptions = (item, index) => {
|
|
|
+const handlerAlertOptions = (item, val, index) => {
|
|
|
+ const { list, isAllSelect } = item;
|
|
|
|
|
|
- const isExists = checkedAlertData.value.find(d => d.id === item.id);
|
|
|
+ if ( isAllSelect ) return;
|
|
|
|
|
|
- item.isActive = index;
|
|
|
+ val.isActive = index;
|
|
|
|
|
|
- isExists ?? checkedAlertData.value.push( item );
|
|
|
+ const isExists = list.find(({ isActive }) => isActive === null);
|
|
|
|
|
|
- if ( unref(checkedAlertData).length === unref(alertAnswer).length ) {
|
|
|
-
|
|
|
- const tempArr = alertAnswer.value.map(({ id, options, isActive }) => ({ [id]: options[isActive] }));
|
|
|
- const tempArrToStr = JSON.stringify(tempArr);
|
|
|
+ if ( !isExists ) {
|
|
|
+ item.isAllSelect = true;
|
|
|
|
|
|
- flowParams.feedback = JSON.stringify(tempArr).substring(1, tempArrToStr.length - 1);
|
|
|
-
|
|
|
- onRegenerate();
|
|
|
+ const result = item.list
|
|
|
+ .map(({ id, options, isActive }) => ({ [id]: options[isActive] }))
|
|
|
+ .reduce((accumulator, currentValue) => {
|
|
|
+ Object.keys(currentValue).forEach(key => accumulator[key] = currentValue[key]);
|
|
|
+ return accumulator;
|
|
|
+ }, {});
|
|
|
+ flowParams.feedback = JSON.stringify(result);
|
|
|
|
|
|
+ onRegenerate();
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
+// 欢迎页提交
|
|
|
+const handleWelcomeRecommend = question => {
|
|
|
+ chatStore.setChatQuestion(question);
|
|
|
+ router.push('/answer');
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
- <section class="flex items-start h-full">
|
|
|
+ <section class="flex items-start h-full" id="warning">
|
|
|
<TheSubMenu title="水质报警" @scrollToLower="onScrolltolower" :loading="isFetching">
|
|
|
<template #top>
|
|
|
<div class="border-[#DAE5ED]">
|
|
@@ -272,6 +329,7 @@ const handlerAlertOptions = (item, index) => {
|
|
|
'工作人员确保问题及时处理。报警时间为每小时警报,请大家及时处理。'
|
|
|
]"
|
|
|
:card-content="recommendList"
|
|
|
+ @on-click="handleWelcomeRecommend"
|
|
|
v-if="!textDataSources"
|
|
|
/>
|
|
|
|
|
@@ -302,69 +360,49 @@ const handlerAlertOptions = (item, index) => {
|
|
|
</div>
|
|
|
</ChatBaseCard>
|
|
|
|
|
|
- <!-- report -->
|
|
|
+ {{ answerResult.length }}
|
|
|
+
|
|
|
+ <section v-for="item,index in answerResult" :key="index">
|
|
|
+ <template v-if="item.biz === 'DECISION_REPORT'">
|
|
|
+ <ChatAnswer
|
|
|
+ :loading="item.loading"
|
|
|
+ :delay-loading="item.delayLoading"
|
|
|
+ :toggleVisibleIcons="false"
|
|
|
+ :content="item.answer"
|
|
|
+ ></ChatAnswer>
|
|
|
+ </template>
|
|
|
+ {{ item }}
|
|
|
+ <template v-if="item.biz === 'DECISION_ALERT'">
|
|
|
+ <ChatBaseCard
|
|
|
+ :loading="item.loading"
|
|
|
+ :delay-loading="item.delayLoading"
|
|
|
+ :toggleVisibleIcons="false"
|
|
|
+ >
|
|
|
+ <p class="mb-[15px] font-bold text-[#1A2029]">需要确定以下问题,完成决策方案:</p>
|
|
|
+ <ul class="radio-wrapper space-y-[14px]">
|
|
|
+ <li class="flex items-center" v-for="val,i in item.list" :key="i">
|
|
|
+ <p class="mr-[14px]">{{ val.mainContent }}</p>
|
|
|
+ <p class="radio-btn-group space-x-[14px]">
|
|
|
+ <span
|
|
|
+ v-for="option,index in val.options"
|
|
|
+ :class="['radio-btn', { active: val.isActive === index }]"
|
|
|
+ @click="handlerAlertOptions(item, val, index)"
|
|
|
+ >{{ option }}</span>
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </ChatBaseCard>
|
|
|
+ </template>
|
|
|
+ </section>
|
|
|
+
|
|
|
<ChatAnswer
|
|
|
- :loading="true"
|
|
|
+ :loading="answerLoading"
|
|
|
+ :delay-loading="answerLoading"
|
|
|
:toggleVisibleIcons="false"
|
|
|
- :content="reportAnswer"
|
|
|
- v-show="reportAnswer"
|
|
|
+ v-show="answerLoading"
|
|
|
></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">
|
|
|
- <div class="waring-answer-wrapper">
|
|
|
- <dl class="message-inner warning-info_medium ">
|
|
|
- <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>
|
|
|
- <dd><span>报警级别:二级</span></dd>
|
|
|
- <dd><span>报警次数:33</span></dd>
|
|
|
- <dd><span>状态:报警中</span></dd>
|
|
|
- </dl>
|
|
|
- <div class="table-inner">
|
|
|
- <div class="warning-table mb-[8px]">
|
|
|
- <div class="title">
|
|
|
- <span>当前进水数据:</span>
|
|
|
- </div>
|
|
|
- <div class="main">
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="warning-table">
|
|
|
- <div class="title">
|
|
|
- <span>当前出水数据:</span>
|
|
|
- </div>
|
|
|
- <div class="main">
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </BaseCard> -->
|
|
|
-
|
|
|
- <!-- <BaseCard>
|
|
|
- <p class="flex-1 text-[15px] leading-[24px]">
|
|
|
- COD,即化学需氧量,是衡量水中有机物质含量的重要指标。它反映了水中可氧化有机物的量,通常用来评估水体的污染程度。水中的有机物主要来源于工业废水、生活污水、农药残留等,这些有机物不仅会导致水质变差,还会对生物和人类健康产生负面影响。因此,通过测定COD值,可以了解水中有机污染物的含量,进而评估水体的污染程度。这对于制定环境保护政策、控制污染源、保障水资源安全等方面都具有重要的指导意义
|
|
|
- </p>
|
|
|
- </BaseCard>
|
|
|
-
|
|
|
- <button class="
|
|
|
+ <!-- <button class="
|
|
|
px-[30px] py-[10px] mb-[20px]
|
|
|
rounded-[8px]
|
|
|
bg-white text-[13px]
|
|
@@ -374,125 +412,9 @@ const handlerAlertOptions = (item, index) => {
|
|
|
水质预测推演
|
|
|
</button> -->
|
|
|
|
|
|
-
|
|
|
-
|
|
|
</TheChatView>
|
|
|
</section>
|
|
|
|
|
|
<CustomModal v-model:visible="visible"></CustomModal>
|
|
|
|
|
|
-</template>
|
|
|
-
|
|
|
-<style scoped lang="scss">
|
|
|
-
|
|
|
-
|
|
|
-.base-card-container {
|
|
|
- margin-bottom: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.warning-item-inner {
|
|
|
- position: relative;
|
|
|
- padding: 20px 8px 8px 8px;
|
|
|
- border-radius: 4px;
|
|
|
- background: #DDE5EF;
|
|
|
-
|
|
|
- .tips {
|
|
|
- position: absolute;
|
|
|
- width: 36px;
|
|
|
- height: 14px;
|
|
|
- top: 0;
|
|
|
- right: 0px;
|
|
|
- border-radius: 0px 4px 0px 4px;
|
|
|
- font-size: 8px;
|
|
|
- text-align: center;
|
|
|
- line-height: 14px;
|
|
|
-
|
|
|
- &_warning,
|
|
|
- &_being {
|
|
|
- color: #F44C49;
|
|
|
- background: #FFF0ED;
|
|
|
- }
|
|
|
-
|
|
|
- &_success {
|
|
|
- color: #51BF8E;
|
|
|
- background: #E9FAF2;
|
|
|
- }
|
|
|
-
|
|
|
- &_close {
|
|
|
- color: #999999;
|
|
|
- background: #D5D5D5;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.warning-info {
|
|
|
- line-height: 16px;
|
|
|
- font-size: 11px;
|
|
|
- color: #5E5E5E;
|
|
|
-
|
|
|
- dd {
|
|
|
- margin-top: 4px;
|
|
|
- }
|
|
|
-
|
|
|
- &_medium {
|
|
|
- line-height: 26px;
|
|
|
- font-size: 14px;
|
|
|
- color: #1A2029;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 回答区域卡片
|
|
|
-.waring-answer-wrapper {
|
|
|
- @include flex(x, start, between);
|
|
|
-
|
|
|
- .message-inner {
|
|
|
- width: 194px;
|
|
|
- flex-shrink: 0;
|
|
|
- }
|
|
|
-
|
|
|
- .table-inner {
|
|
|
- @include flex(y, end, center);
|
|
|
- padding-left: 20px;
|
|
|
- border-left: 1px solid #F1F1F1;
|
|
|
- .warning-table {
|
|
|
- .title {
|
|
|
- margin-bottom: 8px;
|
|
|
- line-height: 16px;
|
|
|
- font-size: 12px;
|
|
|
- font-weight: bold;
|
|
|
- color: #1A2029;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.radio-wrapper {
|
|
|
-
|
|
|
- .radio-btn-group {
|
|
|
- @include flex(x, center, center);
|
|
|
- font-size: 14px;
|
|
|
- text-align: center;
|
|
|
- color: #5E5E5E;
|
|
|
-
|
|
|
- .radio-btn {
|
|
|
- width: 62px;
|
|
|
- height: 28px;
|
|
|
- border-radius: 4px;
|
|
|
- background: #F4F6F8;
|
|
|
- font-size: 14px;
|
|
|
- line-height: 26px;
|
|
|
- cursor: pointer;
|
|
|
-
|
|
|
- &.active, &:hover {
|
|
|
- color: #2454FF;
|
|
|
- background: #E2F1FF;
|
|
|
- }
|
|
|
- &.active {
|
|
|
- background: #E2F1FF url('@/assets/images/chat/bg-raido-check.png') right bottom no-repeat;
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-}
|
|
|
-</style>
|
|
|
+</template>
|