|
@@ -0,0 +1,461 @@
|
|
|
+<script setup>
|
|
|
+import { ref, onMounted, watch } from 'vue';
|
|
|
+import { NScrollbar, useMessage } from 'naive-ui';
|
|
|
+import { objectCopy } from '@/utils/tools';
|
|
|
+import { TheChatView } from '@/components';
|
|
|
+
|
|
|
+import { controlApi } from "@/api/control";
|
|
|
+
|
|
|
+import BaseButton from './components/BaseButton.vue';
|
|
|
+import BaseTitle from './components/BaseTitle.vue';
|
|
|
+import BaseRadioCard from './components/BaseRadioCard.vue';
|
|
|
+import BaseCard from './components/BaseCard.vue';
|
|
|
+import BaseRadioGroup from './components/BaseRadioGroup.vue';
|
|
|
+import BaseChooseItem from './components/BaseChooseItem.vue';
|
|
|
+import BaseInput from './components/BaseInput.vue';
|
|
|
+
|
|
|
+import TheResultPanel from './components/TheResultPanel.vue';
|
|
|
+import TheEchartPanel from './components/TheEchartPanel.vue';
|
|
|
+
|
|
|
+const message = useMessage();
|
|
|
+const isVisibleBtn = ref(true);
|
|
|
+const dataSource = ref({});
|
|
|
+const chooseItemRef = ref([]);
|
|
|
+
|
|
|
+const columnData = [
|
|
|
+ { label: '后反馈设定', key: 'hfksd' },
|
|
|
+ { label: '基准系数', key: 'jzxs' },
|
|
|
+ { label: '修正系数', key: 'xzxs' },
|
|
|
+ { label: '控制系数', key: 'kzxs' },
|
|
|
+ { label: '水量分配系数', key: 'sffpxs' },
|
|
|
+ { label: '碳源当量', key: 'tydl' },
|
|
|
+ { label: '转换系数', key: 'zhxs' },
|
|
|
+ { label: '稀释配属', key: 'xsbs' },
|
|
|
+ { label: '药剂密度', key: 'yjmd' },
|
|
|
+ { label: '最小启动流量', key: 'zxqdll' },
|
|
|
+ { label: '碳氮比', key: 'tdb' }
|
|
|
+]
|
|
|
+
|
|
|
+// 基础参数 - 按钮选择
|
|
|
+const paramData = ref({
|
|
|
+ pump: 0, // 加药泵
|
|
|
+ running: 0, // 运行方式
|
|
|
+ pond:0, // 池组手自动方式
|
|
|
+ setting: 0, // 智适应碳源设置 1# 2#
|
|
|
+ jslYB: null, // 进水流量
|
|
|
+ jscod: null, // 进水COD
|
|
|
+ hycxsy: null, // 好氧池硝酸盐
|
|
|
+ qycxsy: null, // 缺氧池硝酸盐
|
|
|
+ qycad: null, // 缺氧池氨氮
|
|
|
+ jszd: null // 进水总氮
|
|
|
+})
|
|
|
+
|
|
|
+// 基础系数 - input输入
|
|
|
+const factorData = ref({
|
|
|
+ hfksd: 12.00, // 后反馈设置定
|
|
|
+ jzxs: 3.00, // 基准系数
|
|
|
+ xzxs: 1.00, // 修正系数
|
|
|
+ kzxs: 5.20, // 控制系数
|
|
|
+ sffpxs: 1.00, // 水量分配系数
|
|
|
+ tydl: 0.90, // 碳源当量
|
|
|
+ zhxs: 0.90, // 转换系数
|
|
|
+ xsbs: 1.00, // 稀释倍数
|
|
|
+ yjmd: 1.00, // 药剂密度
|
|
|
+ zxqdll: 0.02, // 最小启动流量
|
|
|
+ tdb: 3.54 // 碳氮比
|
|
|
+})
|
|
|
+
|
|
|
+const originParamData = objectCopy(paramData.value);
|
|
|
+const originFactorData = objectCopy(factorData.value);
|
|
|
+
|
|
|
+const factorInpData = ref(objectCopy(factorData.value));
|
|
|
+
|
|
|
+const doseNum = ref(null);
|
|
|
+const flowNum = ref(null);
|
|
|
+
|
|
|
+watch(() => paramData.value.setting, () => {
|
|
|
+ handelReset("变化了");
|
|
|
+});
|
|
|
+
|
|
|
+// 重置
|
|
|
+const handelReset = () => {
|
|
|
+
|
|
|
+ if ( !isVisibleBtn.value ) {
|
|
|
+ return message.warning("设定参数系数的值未保存")
|
|
|
+ }
|
|
|
+
|
|
|
+ chooseItemRef.value.forEach(item => item.resetInpVal() );
|
|
|
+
|
|
|
+ paramData.value = objectCopy({...originParamData, setting: paramData.value.setting});
|
|
|
+ factorData.value = objectCopy(originFactorData);
|
|
|
+ factorInpData.value = objectCopy(originFactorData);
|
|
|
+
|
|
|
+ doseNum.value = '';
|
|
|
+ flowNum.value = '';
|
|
|
+}
|
|
|
+
|
|
|
+// 计算最终结果
|
|
|
+const handleResult = () => {
|
|
|
+
|
|
|
+ if ( !isVisibleBtn.value ) {
|
|
|
+ return message.warning("设定参数系数的值未保存")
|
|
|
+ }
|
|
|
+
|
|
|
+ const codeSetEnum = {
|
|
|
+ jslYB: '进水流量',
|
|
|
+ jscod: '进水COD',
|
|
|
+ hycxsy: '好氧池硝酸盐',
|
|
|
+ qycxsy: '缺氧池硝酸盐',
|
|
|
+ qycad: '缺氧池氨氮',
|
|
|
+ jszd: '进水总氮',
|
|
|
+
|
|
|
+ hfksd: '后反馈设置',
|
|
|
+ jzxs: '基准系数',
|
|
|
+ xzxs: '修正系数',
|
|
|
+ kzxs: '控制系数',
|
|
|
+ sffpxs: '水量分配系数',
|
|
|
+ tydl: '碳源当量',
|
|
|
+ zhxs: '转换系数',
|
|
|
+ xsbs: '稀释倍数',
|
|
|
+ yjmd: '药剂密度',
|
|
|
+ zxqdll: '最小启动流量',
|
|
|
+ tdb: '碳氮比'
|
|
|
+ }
|
|
|
+ const whitelist = [ 'pump', 'running', 'pond', 'setting' ];
|
|
|
+ const mergeData = { ...paramData.value, ...factorData.value };
|
|
|
+ const keyList = Object.keys(mergeData);
|
|
|
+ let isErrorItem = null;
|
|
|
+
|
|
|
+ for (let i = 0; i < keyList.length; i++) {
|
|
|
+ const key = keyList[i];
|
|
|
+ const val = mergeData[key]
|
|
|
+
|
|
|
+ if (!val && !whitelist.includes(key)) {
|
|
|
+ isErrorItem = { key, val, label: codeSetEnum[key] }
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( isErrorItem ) {
|
|
|
+ return message.warning(`${isErrorItem.label}未填写`)
|
|
|
+ }
|
|
|
+
|
|
|
+ const stepOne = ((( 2 * paramData.value.hycxsy - factorData.value.hfksd)+((paramData.value.qycad + paramData.value.qycxsy) * factorData.value.xzxs - factorData.value.hfksd)) * (factorData.value.jzxs - 1)) * (paramData.value.jslYB * factorData.value.sffpxs) / 1000
|
|
|
+
|
|
|
+ const setpTwo = ( stepOne * factorData.value.kzxs - ( paramData.value.jslYB * factorData.value.sffpxs * paramData.value.jscod * factorData.value.zhxs / 1000)) / factorData.value.tydl
|
|
|
+
|
|
|
+ const setpThree = setpTwo / factorData.value.yjmd / 1000 * factorData.value.xsbs
|
|
|
+
|
|
|
+ doseNum.value = setpThree.toFixed(3);
|
|
|
+ flowNum.value = paramData.value.jslYB;
|
|
|
+}
|
|
|
+
|
|
|
+const onEditConfirm = () => {
|
|
|
+ const keys = Object.keys(factorInpData.value);
|
|
|
+ let isError = false;
|
|
|
+
|
|
|
+ for (let i = 0; i < keys.length; i++) {
|
|
|
+ const key = keys[i];
|
|
|
+ const val = factorInpData.value[key];
|
|
|
+ if ( !val || val === Infinity) {
|
|
|
+ message.warning("数据来源填写有误,请检查")
|
|
|
+ isError = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( isError ) return;
|
|
|
+
|
|
|
+ isVisibleBtn.value = true;
|
|
|
+ factorData.value = JSON.parse(JSON.stringify(factorInpData.value));
|
|
|
+}
|
|
|
+
|
|
|
+const onEditCancel = () => {
|
|
|
+ isVisibleBtn.value = true;
|
|
|
+ factorInpData.value = JSON.parse(JSON.stringify(factorData.value));
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ const { data } = await controlApi.getNumValue();
|
|
|
+ let result = {};
|
|
|
+ Object.entries(data).forEach(([key, val]) => {
|
|
|
+ result[key] = val ? Number(val.toFixed(2)) : val;
|
|
|
+ });
|
|
|
+ dataSource.value = result;
|
|
|
+})
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <section class="flex items-start h-full">
|
|
|
+ <TheChatView leftTitle="智适应碳源投加" :isChatSlot="false" :isFooter="false">
|
|
|
+ <template #control>
|
|
|
+ <div class="control-container space-x-[12px]">
|
|
|
+ <div class="left-section">
|
|
|
+
|
|
|
+ <BaseTitle title="智能投加计算">
|
|
|
+ <template #right>
|
|
|
+ <BaseButton @click="handelReset">重置</BaseButton>
|
|
|
+ <BaseButton type="gradual" @on-click="handleResult">投加计算</BaseButton>
|
|
|
+ </template>
|
|
|
+ </BaseTitle>
|
|
|
+
|
|
|
+ <n-scrollbar class="scrollbar" style="height: 100%;">
|
|
|
+ <div class="form-content">
|
|
|
+ <BaseCard title="选择加药泵">
|
|
|
+ <BaseRadioCard v-model="paramData.pump"></BaseRadioCard>
|
|
|
+ </BaseCard>
|
|
|
+
|
|
|
+ <BaseCard title="选择运行方式">
|
|
|
+ <BaseRadioGroup :data="['自动', '手动']" v-model="paramData.running"></BaseRadioGroup>
|
|
|
+ </BaseCard>
|
|
|
+
|
|
|
+ <BaseCard title="选择池组手自动方式">
|
|
|
+ <BaseRadioGroup :data="['自动', '手动']" v-model="paramData.pond"></BaseRadioGroup>
|
|
|
+ </BaseCard>
|
|
|
+
|
|
|
+ <BaseCard title="确定智适应碳源设置">
|
|
|
+ <BaseRadioGroup :data="['1号池', '2号池']" v-model="paramData.setting"></BaseRadioGroup>
|
|
|
+ </BaseCard>
|
|
|
+
|
|
|
+ <BaseCard :title="paramData.setting == 0 ? '1号池设定数据来源' : '2号池设定数据来源'">
|
|
|
+ <div class="space-y-[12px]">
|
|
|
+ <BaseChooseItem
|
|
|
+ title="进水流量"
|
|
|
+ v-model="paramData.jslYB"
|
|
|
+ :btn-group="[
|
|
|
+ { label: '手动', key: 'hand', value: '' },
|
|
|
+ { label: '仪表', key: 'laboratory', value: dataSource.jslYB },
|
|
|
+ ]"
|
|
|
+ unit="m³"
|
|
|
+ :ref="el=> chooseItemRef[0] = el"
|
|
|
+ ></BaseChooseItem>
|
|
|
+
|
|
|
+ <BaseChooseItem
|
|
|
+ title="进水COD"
|
|
|
+ v-model="paramData.jscod"
|
|
|
+ :btn-group="[
|
|
|
+ { label: '手动', key: 'hand' },
|
|
|
+ { label: '仪表', key: 'laboratory', value: dataSource.jsCodYB },
|
|
|
+ { label: '化验', key: 'assay', value: dataSource.jsCodHY },
|
|
|
+ ]"
|
|
|
+ unit="mg/L"
|
|
|
+ :ref="el=> chooseItemRef[1] = el"
|
|
|
+ ></BaseChooseItem>
|
|
|
+
|
|
|
+ <BaseChooseItem
|
|
|
+ title="好氧池硝酸盐"
|
|
|
+ v-model="paramData.hycxsy"
|
|
|
+ :btn-group="[
|
|
|
+ { label: '手动', key: 'hand', value: '' },
|
|
|
+ { label: '化验', key: 'forecast', value: dataSource[paramData.setting === 0 ? 'hyXsyHYOne' : 'hyXsyHYTwo'] },
|
|
|
+ { label: '预测', key: 'forecast', value: dataSource[paramData.setting === 0 ? 'hyXsyYCOne' : 'hyXsyYCTwo'] },
|
|
|
+ ]"
|
|
|
+ unit="mg/L"
|
|
|
+ :ref="el=> chooseItemRef[2] = el"
|
|
|
+ ></BaseChooseItem>
|
|
|
+
|
|
|
+ <BaseChooseItem
|
|
|
+ title="缺氧池硝酸盐"
|
|
|
+ v-model="paramData.qycxsy"
|
|
|
+ :btn-group="[
|
|
|
+ { label: '手动', key: 'hand', value: ''},
|
|
|
+ { label: '化验', key: 'forecast', value: dataSource[paramData.setting === 0 ? 'qyXsyHYOne' : 'qyXsyHYTwo'] },
|
|
|
+ ]"
|
|
|
+ unit="mg/L"
|
|
|
+ :ref="el=> chooseItemRef[3] = el"
|
|
|
+ ></BaseChooseItem>
|
|
|
+
|
|
|
+ <BaseChooseItem
|
|
|
+ title="缺氧池氨氮"
|
|
|
+ v-model="paramData.qycad"
|
|
|
+ :btn-group="[
|
|
|
+ { label: '手动', key: 'hand', value:'' },
|
|
|
+ { label: '化验', key: 'forecast', value: dataSource[paramData.setting === 0 ? 'qyAdHYOne' : 'qyAdHYTwo'] },
|
|
|
+ ]"
|
|
|
+ unit="mg/L"
|
|
|
+ :ref="el=> chooseItemRef[4] = el"
|
|
|
+ ></BaseChooseItem>
|
|
|
+
|
|
|
+ <BaseChooseItem
|
|
|
+ title="进水总氮"
|
|
|
+ v-model="paramData.jszd"
|
|
|
+ :btn-group="[
|
|
|
+ { label: '手动', key: 'hand', value: '' },
|
|
|
+ { label: '仪表', key: 'laboratory', value: dataSource.jsTnYB}
|
|
|
+ ]"
|
|
|
+ unit="mg/L"
|
|
|
+ :ref="el=> chooseItemRef[5] = el"
|
|
|
+ ></BaseChooseItem>
|
|
|
+ </div>
|
|
|
+ </BaseCard>
|
|
|
+
|
|
|
+ <BaseCard title="设定参数系数" style="margin: 0" tips="建议使用默认值,非必要不修改">
|
|
|
+ <template #titleRight>
|
|
|
+ <div>
|
|
|
+ <div
|
|
|
+ class="flex items-center space-x-[4px] cursor-pointer text-[#2454FF] text-[13px]"
|
|
|
+ v-show="isVisibleBtn"
|
|
|
+ @click="isVisibleBtn = false
|
|
|
+ ">
|
|
|
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
|
+ <path d="M2.33337 14H14.3334" stroke="#2454FF" stroke-linecap="round" stroke-linejoin="round" />
|
|
|
+ <path d="M3.66663 8.90663V11.3333H6.10569L13 4.43603L10.565 2L3.66663 8.90663Z" stroke="#2454FF"
|
|
|
+ stroke-linejoin="round" />
|
|
|
+ </svg>
|
|
|
+ <span>编辑</span>
|
|
|
+ </div>
|
|
|
+ <ul class="flex items-center text-[13px] space-x-[8px] cursor-pointer" v-show="!isVisibleBtn">
|
|
|
+ <li class="cursor-pointer" @click="onEditConfirm" style="color: #2454FF">确定</li>
|
|
|
+ <li class="cursor-pointer text-[#B0B7C0]" @click="onEditCancel">取消</li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <ul class="data-source-list space-y-[12px]">
|
|
|
+ <li class="data-soruce-item" v-for="item, index in columnData">
|
|
|
+ <span>{{ item.label }}:</span>
|
|
|
+ <span class="unit" v-show="isVisibleBtn">
|
|
|
+ {{ factorData[item.key].toFixed(2) }}
|
|
|
+ {{ index === 0 ? 'mg/L' : '' }}
|
|
|
+ </span>
|
|
|
+ <div style="width: 140px;" v-show="!isVisibleBtn">
|
|
|
+ <BaseInput :unit="index === 0 ? 'mg/L' : '' " size='small' :isNeedFlotBtn="false" v-model="factorInpData[item.key]" isCenter placeholder=""></BaseInput>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </BaseCard>
|
|
|
+ </div>
|
|
|
+ </n-scrollbar>
|
|
|
+ </div>
|
|
|
+ <div class="right-section">
|
|
|
+ <TheResultPanel :doseNum="doseNum" :flowNum="flowNum"></TheResultPanel>
|
|
|
+ <TheEchartPanel></TheEchartPanel>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </TheChatView>
|
|
|
+ </section>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.control-container {
|
|
|
+ @include flex(x, start, start);
|
|
|
+ height: 100%;
|
|
|
+
|
|
|
+ .left-section {
|
|
|
+ display: flex;
|
|
|
+ flex-flow: column;
|
|
|
+ width: 400px;
|
|
|
+ height: 100%;
|
|
|
+ border-radius: 10px;
|
|
|
+ background: #fff;
|
|
|
+
|
|
|
+ .scrollbar {
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-content {
|
|
|
+ padding: 24px 16px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .data-source-list {
|
|
|
+ .data-soruce-item {
|
|
|
+ @include flex(x, center, between);
|
|
|
+ .inp-inner {
|
|
|
+ width: 112px;
|
|
|
+ }
|
|
|
+ .unit {
|
|
|
+ font-family: "D-DIN-PRO-700-Bold";
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.right-section {
|
|
|
+ display: flex;
|
|
|
+ flex-flow: column;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+
|
|
|
+ .top {
|
|
|
+ flex-shrink: 1;
|
|
|
+ height: 214px;
|
|
|
+ border-radius: 8px;
|
|
|
+ border: 0.5px solid #FFF;
|
|
|
+ background: linear-gradient(90deg, #E0E8FC 0%, #F2F4FF 100%);
|
|
|
+ }
|
|
|
+
|
|
|
+ .bottom {
|
|
|
+ height: 100%;
|
|
|
+ background: pink;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// 通用区域的样式
|
|
|
+
|
|
|
+.btn {
|
|
|
+ width: 80px;
|
|
|
+ height: 32px;
|
|
|
+ border-radius: 4px;
|
|
|
+ border: 1px solid #D3D7DD;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 32px;
|
|
|
+ color: #1A2029;
|
|
|
+}
|
|
|
+
|
|
|
+.btn-primary {
|
|
|
+ border: 0;
|
|
|
+ background: var(--Linear, linear-gradient(270deg, #3BD6E3 0%, #019AFE 100%));
|
|
|
+ font-weight: bold;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.btn-info {
|
|
|
+ width: 44px;
|
|
|
+ height: 28px;
|
|
|
+ border-radius: 4px;
|
|
|
+ border: 1px solid #D3D7DD;
|
|
|
+ background: #fff;
|
|
|
+ font-size: 12px;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 28px;
|
|
|
+ color: #1A2029;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.btn-info_active {
|
|
|
+ color: #2454FF;
|
|
|
+ border: 1px solid #2454FF;
|
|
|
+ background: #EBF0FF;
|
|
|
+}
|
|
|
+
|
|
|
+.radio {
|
|
|
+ display: block;
|
|
|
+ width: 12px;
|
|
|
+ height: 12px;
|
|
|
+ border-radius: 100%;
|
|
|
+ border: 1px solid #ccc;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.radio_big {
|
|
|
+ width: 16px;
|
|
|
+ height: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.radio-active {
|
|
|
+ transition: all .1s;
|
|
|
+ border: 3px solid #2454FF;
|
|
|
+}
|
|
|
+
|
|
|
+.radio_big.radio-active {
|
|
|
+ border: 4px solid #2454FF;
|
|
|
+}
|
|
|
+</style>
|