소스 검색

perf(views): 优化"算法管理"模块"算法编辑"组件传参逻辑与多语言修改

wangshun 1 개월 전
부모
커밋
590e2cb1cd
3개의 변경된 파일759개의 추가작업 그리고 5개의 파일을 삭제
  1. 6 3
      src/i18n/locales/zh.json
  2. 751 0
      src/views/algorithm-manage/AlgorithmEditing.vue
  3. 2 2
      src/views/algorithm-manage/EquipmentControl.vue

+ 6 - 3
src/i18n/locales/zh.json

@@ -45,12 +45,13 @@
   },
   "algorithmManage": {
     "algorithmConfiguration": "算法配置",
+    "backwater": "回水",
     "backwaterTemperatureSettingValue": "冷却总管回水温度设定值(℃)",
     "computingCycle": "计算周期",
     "continuousOperation": "是否需要连续运行",
     "controlBasis": "控制依据",
     "controlInstruction": "是否下发控制指令",
-    "controlStepSize": "最小控制步长(℃)",
+    "controlStepSize": "最小控制步长",
     "coolingOffPeriod": "智控策略降温调控周期",
     "coolingSetValue": "动态调整冷却总管回水温度设定值",
     "copAlgorithm": "COP算法",
@@ -78,15 +79,16 @@
     "regulationCycle": "智控策略升温调控周期",
     "shutdownCompensationValue": "停机补偿值",
     "sourceTemperature": "供水温度来源",
-    "stepSizeForWaterTemperatureSetting": "水温设定步长(℃)",
+    "stepSizeForWaterTemperatureSetting": "水温设定步长",
     "systemFunctionSettings": "系统功能设置",
     "temperatureHumidity": "温湿度",
-    "temperatureHumidityAcquisitionCycle": "温湿度采集周期(min)",
+    "temperatureHumidityAcquisitionCycle": "温湿度采集周期",
     "temperatureRange": "温度区间",
     "temperatureSafetyMargin": "温度安全余量",
     "thermometer": "冷量表",
     "upperLimit": "上限",
     "waterOutletSetting": "初始冷冻水出水温度设定值",
+    "waterSupply": "供水",
     "waterTemperatureControlMode": "水温控制模式",
     "weighted": "加权"
   },
@@ -133,6 +135,7 @@
     "offline": "离线",
     "on": "开",
     "online": "在线",
+    "open": "开启",
     "operation": "操作",
     "opsCenter": "运维中心",
     "pageTotal": "共 {total} 条",

+ 751 - 0
src/views/algorithm-manage/AlgorithmEditing.vue

@@ -0,0 +1,751 @@
+<script setup lang="ts">
+import { onMounted, ref, useTemplateRef } from 'vue';
+import dayjs, { Dayjs } from 'dayjs';
+
+import SvgIcon from '@/components/SvgIcon.vue';
+import { useDictData } from '@/hooks/dict-data';
+import { useRequest } from '@/hooks/request';
+import { t } from '@/i18n';
+import { addAlgorithmConfigUpdate } from '@/api';
+import { DictCode } from '@/constants';
+
+import EquipmentControl from './EquipmentControl.vue';
+import MonthSetting from './MonthSetting.vue';
+import SetInterval from './SetInterval.vue';
+
+import type { FormInstance, Rule } from 'ant-design-vue/es/form';
+import type { AlgorithmConfigInfo, AlgorithmForm, ChillersItem, TemperatureRange, TemperatureRangeItem } from '@/types';
+
+const { dictData: algTempCtrlMinStep, getDictData: getAlgTempCtrlMinStep } = useDictData(DictCode.AlgTempCtrlMinStep);
+const { dictData: algTempHumCollectPeriod, getDictData: getAlgTempHumCollectPeriod } = useDictData(
+  DictCode.AlgTempHumCollectPeriod,
+);
+const { dictData: algWtTempCtrlMode, getDictData: getAlgWtTempCtrlMode } = useDictData(DictCode.AlgWtTempCtrlMode);
+const { dictData: algAlways, getDictData: getAlgAlways } = useDictData(DictCode.AlgAlways);
+const { dictData: algWtTempSetStep, getDictData: getAlgWtTempSetStep } = useDictData(DictCode.AlgWtTempSetStep);
+
+const formRef = ref<FormInstance>();
+const monthSettingRefs = useTemplateRef('monthSetting');
+const emit = defineEmits(['confirmClick', 'cancelClick']);
+const setIntervalRefs = ref<InstanceType<typeof SetInterval>[]>([]);
+const equipmentControlRefs = ref<InstanceType<typeof EquipmentControl>[]>([]);
+
+const { handleRequest } = useRequest();
+const activeKey = ref<string[]>(['intelligentControl', 'functionSettings']);
+const customStyle = 'border-radius: 4px;;border: 0;background: #F5F6F7;margin-bottom: 4px';
+const analysisOpen = ref<boolean>(false);
+const setOpen = ref<boolean>(false);
+const temperatureSettingValue = ref<string>('');
+const analysisTypeDisplay = ref<number>(0);
+const coolingPipeDynamicOffsetDisplay = ref<number>(0);
+const coolingPipeDynamicSetDisplay = ref<number>(0);
+const coolingPipeDynamicDeadZoneDisplay = ref<number>(0);
+const coolingPipeDynamicLowerDisplay = ref<number>(0);
+const coolingPipeDynamicUpperDisplay = ref<number>(0);
+const temperatureRangeList = ref<TemperatureRange[]>([]);
+const chillersList = ref<ChillersItem[]>([]);
+const algorithmId = ref<number>();
+const groupId = ref<number>();
+const algorithmForm = ref<AlgorithmForm>({
+  enabled: false,
+  sendCtrlCmd: true,
+  msgBox: true,
+  tempRiseCtrlPeriod: 10,
+  tempReductionCtrlPeriod: 3,
+  minCtrlStep: '',
+  intelligentMode: 0,
+  controlBasis: 0,
+  period: 0,
+  tempSafetyMargin: 0,
+  humiditySafetyMargin: 0,
+  tempHumidityCollectPeriod: '',
+  waterSupplyTempSource: 0,
+  analysis: true,
+  analysisType: 0,
+  enableRefrigerationPipeDynamicSet: true,
+  enableCoolingPipeDynamicSet: false,
+  coolingPipeDynamicOffset: 0,
+  coolingPipeDynamicSet: 0,
+  coolingPipeDynamicDeadZone: 0,
+  coolingPipeDynamicLower: 0,
+  coolingPipeDynamicUpper: 0,
+});
+const addClick = () => {
+  temperatureRangeList.value.push({
+    time: undefined,
+    lower: 0,
+    upper: 0,
+  });
+};
+const deleteClick = (index: number) => {
+  temperatureRangeList.value.splice(index, 1);
+};
+const rules: Record<string, Rule[]> = {
+  sendCtrlCmd: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
+  msgBox: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
+  tempRiseCtrlPeriod: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
+  tempReductionCtrlPeriod: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
+  minCtrlStep: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
+  intelligentMode: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
+  controlBasis: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
+  period: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
+  tempSafetyMargin: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
+  humiditySafetyMargin: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
+  tempHumidityCollectPeriod: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
+  waterSupplyTempSource: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
+};
+const editorAlgorithmChange = (info: AlgorithmConfigInfo) => {
+  temperatureRangeList.value = [];
+  chillersList.value = [];
+  handleRequest(async () => {
+    const {
+      id: algId,
+      enabled,
+      sendCtrlCmd,
+      msgBox,
+      tempRiseCtrlPeriod,
+      minCtrlStep,
+      intelligentMode,
+      controlBasis,
+      period,
+      tempSafetyMargin,
+      humiditySafetyMargin,
+      tempHumidityCollectPeriod,
+      waterSupplyTempSource,
+      tempReductionCtrlPeriod,
+      analysis,
+      analysisType,
+      enableRefrigerationPipeDynamicSet,
+      enableCoolingPipeDynamicSet,
+      coolingPipeDynamicOffset,
+      coolingPipeDynamicSet,
+      coolingPipeDynamicDeadZone,
+      coolingPipeDynamicLower,
+      coolingPipeDynamicUpper,
+      chillers,
+      chilledWaterOutletTempRangeList,
+      chilledWaterOutletTempSet,
+      devGroupId,
+    } = info;
+    groupId.value = devGroupId;
+    algorithmId.value = algId;
+    Object.assign(algorithmForm.value, {
+      enabled,
+      sendCtrlCmd,
+      msgBox,
+      tempRiseCtrlPeriod,
+      tempReductionCtrlPeriod,
+      minCtrlStep: String(minCtrlStep),
+      intelligentMode,
+      controlBasis,
+      period,
+      tempSafetyMargin,
+      humiditySafetyMargin,
+      tempHumidityCollectPeriod: String(tempHumidityCollectPeriod),
+      waterSupplyTempSource,
+      analysis,
+      analysisType,
+      enableRefrigerationPipeDynamicSet,
+      enableCoolingPipeDynamicSet,
+      coolingPipeDynamicOffset,
+      coolingPipeDynamicSet,
+      coolingPipeDynamicDeadZone,
+      coolingPipeDynamicLower,
+      coolingPipeDynamicUpper,
+    });
+
+    analysisTypeDisplay.value = analysisType;
+    coolingPipeDynamicOffsetDisplay.value = coolingPipeDynamicOffset;
+    coolingPipeDynamicSetDisplay.value = coolingPipeDynamicSet;
+    coolingPipeDynamicDeadZoneDisplay.value = coolingPipeDynamicDeadZone;
+    coolingPipeDynamicLowerDisplay.value = coolingPipeDynamicLower;
+    coolingPipeDynamicUpperDisplay.value = coolingPipeDynamicUpper;
+    temperatureSettingValue.value = chilledWaterOutletTempSet;
+    chilledWaterOutletTempRangeList.forEach((item) => {
+      const { startTime, endTime, lower, upper } = item;
+      temperatureRangeList.value.push({
+        time: [dayjs(startTime, 'HH:mm'), dayjs(endTime, 'HH:mm')],
+        lower,
+        upper,
+      });
+    });
+    chillers.forEach((item) => {
+      const {
+        id,
+        devId,
+        waterTempControlMode,
+        continuous,
+        stopCompensate,
+        restartCompensate,
+        safeDiffPressureLower,
+        safeLoadLower,
+        waterTempStep,
+        deviceName,
+      } = item;
+      chillersList.value.push({
+        id,
+        algId,
+        devId,
+        waterTempControlMode: String(waterTempControlMode),
+        continuous: String(continuous),
+        stopCompensate,
+        restartCompensate,
+        safeDiffPressureLower,
+        safeLoadLower,
+        waterTempStep: String(waterTempStep),
+        deviceName,
+      });
+    });
+  });
+};
+const analysisEditor = () => {
+  analysisTypeDisplay.value = algorithmForm.value.analysisType;
+  analysisOpen.value = true;
+};
+const setEditor = () => {
+  const {
+    coolingPipeDynamicOffset,
+    coolingPipeDynamicSet,
+    coolingPipeDynamicDeadZone,
+    coolingPipeDynamicLower,
+    coolingPipeDynamicUpper,
+  } = algorithmForm.value;
+  coolingPipeDynamicOffsetDisplay.value = coolingPipeDynamicOffset;
+  coolingPipeDynamicSetDisplay.value = coolingPipeDynamicSet;
+  coolingPipeDynamicDeadZoneDisplay.value = coolingPipeDynamicDeadZone;
+  coolingPipeDynamicLowerDisplay.value = coolingPipeDynamicLower;
+  coolingPipeDynamicUpperDisplay.value = coolingPipeDynamicUpper;
+  setOpen.value = true;
+};
+const okConfirm = () => {
+  algorithmForm.value.analysisType = analysisTypeDisplay.value;
+  analysisOpen.value = false;
+};
+const okSetConfirm = () => {
+  algorithmForm.value.coolingPipeDynamicOffset = coolingPipeDynamicOffsetDisplay.value;
+  algorithmForm.value.coolingPipeDynamicSet = coolingPipeDynamicSetDisplay.value;
+  algorithmForm.value.coolingPipeDynamicDeadZone = coolingPipeDynamicDeadZoneDisplay.value;
+  algorithmForm.value.coolingPipeDynamicLower = coolingPipeDynamicLowerDisplay.value;
+  algorithmForm.value.coolingPipeDynamicUpper = coolingPipeDynamicUpperDisplay.value;
+  setOpen.value = false;
+};
+
+// 添加格式转换
+const formatDate = (date: Dayjs) => date.format('HH:mm');
+
+const addAlgorithm = async () => {
+  try {
+    // 创建校验任务队列(包含所有子组件+父组件自身)
+    const allTasks = [
+      ...setIntervalRefs.value.map((c) => c.formRefSubmit()),
+      ...equipmentControlRefs.value.map((c) => c.formRefSubmit()),
+      formRef.value?.validate() || Promise.resolve(),
+      monthSettingRefs.value?.formRefSubmit(),
+    ];
+    // 并行执行所有校验(父+子)
+    await Promise.all(allTasks);
+    handleRequest(async () => {
+      const timeList: TemperatureRangeItem[] = [];
+      temperatureRangeList.value.forEach((item) => {
+        const { time, lower, upper } = item;
+
+        const data = time?.map(formatDate) || [];
+
+        timeList.push({
+          startTime: data[0],
+          endTime: data[1],
+          lower,
+          upper,
+        });
+      });
+
+      await addAlgorithmConfigUpdate({
+        ...algorithmForm.value,
+        id: algorithmId.value,
+        chillers: chillersList.value,
+        chilledWaterOutletTempRangeList: timeList,
+        chilledWaterOutletTempSet: monthSettingRefs.value ? monthSettingRefs.value.stringConversion() : '',
+      });
+      if (groupId.value) {
+        emit('confirmClick', groupId.value);
+      }
+    });
+  } catch {
+    console.log('存在验证未通过的表单');
+  }
+};
+
+const canceladd = () => {
+  emit('cancelClick');
+};
+
+defineExpose({
+  editorAlgorithmChange,
+});
+
+onMounted(() => {
+  handleRequest(async () => {
+    await getAlgTempCtrlMinStep();
+    algorithmForm.value.minCtrlStep = algTempCtrlMinStep.value[0].dictEngValue;
+    await getAlgTempHumCollectPeriod();
+    algorithmForm.value.tempHumidityCollectPeriod = algTempHumCollectPeriod.value[0].dictEngValue;
+    await getAlgWtTempCtrlMode();
+    await getAlgAlways();
+    await getAlgWtTempSetStep();
+  });
+});
+</script>
+
+<template>
+  <div>
+    <!-- <AFlex justify="space-between">
+      <div class="title-text">{{ $t('algorithmManage.algorithmConfiguration') }}</div>
+      <DeviceGroupSelect @change="handleDevGroupChange" />
+    </AFlex> -->
+    <div class="algorithm-content">
+      <ACollapse v-model:active-key="activeKey" style="border: 0" collapsible="icon">
+        <ACollapsePanel key="intelligentControl" :style="customStyle">
+          <template #header>
+            <AFlex align="center" class="header-heigth">
+              <span class="header-text">{{ $t('algorithmManage.intelligentControlChilledWater') }}</span>
+              <ASwitch v-model:checked="algorithmForm.enabled" />
+            </AFlex>
+          </template>
+          <div>
+            <AForm
+              ref="formRef"
+              class="algorithm-form"
+              :model="algorithmForm"
+              label-align="left"
+              layout="vertical"
+              :rules="rules"
+            >
+              <AFlex class="flex-bottom" :gap="40">
+                <AFormItem :label="t('algorithmManage.controlInstruction')" name="sendCtrlCmd">
+                  <ARadioGroup v-model:value="algorithmForm.sendCtrlCmd">
+                    <ARadio class="radio-right" :value="true">{{ $t('common.yes') }}</ARadio>
+                    <ARadio :value="false">{{ $t('common.no') }}</ARadio>
+                  </ARadioGroup>
+                </AFormItem>
+                <AFormItem :label="$t('algorithmManage.popupReminder')" name="msgBox">
+                  <ARadioGroup v-model:value="algorithmForm.msgBox">
+                    <ARadio class="radio-right" :value="true">{{ $t('common.yes') }}</ARadio>
+                    <ARadio :value="false">{{ $t('common.no') }}</ARadio>
+                  </ARadioGroup>
+                </AFormItem>
+                <AFormItem :label="t('algorithmManage.regulationCycle')" name="tempRiseCtrlPeriod">
+                  <AInputNumber
+                    v-model:value="algorithmForm.tempRiseCtrlPeriod"
+                    class="input-width"
+                    addon-after="min"
+                    :min="1"
+                    :max="99999"
+                    :placeholder="t('common.pleaseEnter')"
+                  />
+                </AFormItem>
+                <AFormItem :label="t('algorithmManage.coolingOffPeriod')" name="tempReductionCtrlPeriod">
+                  <AInputNumber
+                    v-model:value="algorithmForm.tempReductionCtrlPeriod"
+                    class="input-width"
+                    addon-after="min"
+                    :min="1"
+                    :max="99999"
+                    :placeholder="t('common.pleaseEnter')"
+                  />
+                </AFormItem>
+                <AFormItem
+                  class="input-width"
+                  :label="t('algorithmManage.controlStepSize') + '(℃)'"
+                  name="minCtrlStep"
+                >
+                  <ASelect
+                    v-model:value="algorithmForm.minCtrlStep"
+                    :options="algTempCtrlMinStep"
+                    :field-names="{ label: 'dictValue', value: 'dictEngValue' }"
+                    :placeholder="$t('common.plzSelect')"
+                  />
+                </AFormItem>
+              </AFlex>
+              <div class="analysis-style interval-style">
+                <span>* </span>{{ $t('algorithmManage.effluentInterval') }}
+              </div>
+
+              <div v-for="(item, index) in temperatureRangeList" :key="index">
+                <SetInterval
+                  ref="setIntervalRefs"
+                  :index="index"
+                  :form="item"
+                  @addClick="addClick"
+                  @deleteClick="deleteClick"
+                />
+              </div>
+
+              <div class="analysis-style"><span>* </span>{{ $t('algorithmManage.waterOutletSetting') }}</div>
+              <MonthSetting ref="monthSetting" :temperature-setting-value="temperatureSettingValue" />
+              <AFlex class="flex-bottom" wrap="wrap" :gap="40">
+                <AFormItem :label="t('algorithmManage.intelligentMode')" name="intelligentMode">
+                  <ARadioGroup v-model:value="algorithmForm.intelligentMode">
+                    <ARadio class="radio-right" :value="0">
+                      <AFlex align="center">
+                        <div>{{ $t('algorithmManage.intelligentEnergyConservation') }}</div>
+                        <SvgIcon class="icon-style" name="question-circle-o" />
+                      </AFlex>
+                    </ARadio>
+                    <ARadio :value="1">
+                      <AFlex align="center">
+                        <div>{{ $t('algorithmManage.prioritizeRequirements') }}</div>
+                        <SvgIcon class="icon-style" name="question-circle-o" />
+                      </AFlex>
+                    </ARadio>
+                  </ARadioGroup>
+                </AFormItem>
+                <AFormItem :label="t('algorithmManage.controlBasis')" name="controlBasis">
+                  <ARadioGroup v-model:value="algorithmForm.controlBasis">
+                    <ARadio class="radio-right" :value="0">{{ $t('envMonitor.temperature') }}</ARadio>
+                    <ARadio class="radio-right" :value="1">{{ $t('envMonitor.humidity') }}</ARadio>
+                    <ARadio :value="2">{{ $t('algorithmManage.temperatureHumidity') }}</ARadio>
+                  </ARadioGroup>
+                </AFormItem>
+                <AFormItem :label="t('algorithmManage.computingCycle')" name="period">
+                  <AInputNumber
+                    :placeholder="t('common.pleaseEnter')"
+                    v-model:value="algorithmForm.period"
+                    class="input-width"
+                    addon-after="min"
+                  />
+                </AFormItem>
+                <AFormItem :label="t('algorithmManage.temperatureSafetyMargin')" name="tempSafetyMargin">
+                  <AInputNumber
+                    :placeholder="t('common.pleaseEnter')"
+                    v-model:value="algorithmForm.tempSafetyMargin"
+                    class="input-width"
+                    addon-after="℃"
+                  />
+                </AFormItem>
+
+                <AFormItem :label="t('algorithmManage.humiditySafetyMargin')" name="humiditySafetyMargin">
+                  <AInputNumber
+                    v-model:value="algorithmForm.humiditySafetyMargin"
+                    class="input-width"
+                    addon-after="%"
+                    :placeholder="t('common.pleaseEnter')"
+                  />
+                </AFormItem>
+                <AFormItem
+                  :label="t('algorithmManage.temperatureHumidityAcquisitionCycle') + '(min)'"
+                  name="tempHumidityCollectPeriod"
+                >
+                  <ASelect
+                    class="input-width"
+                    v-model:value="algorithmForm.tempHumidityCollectPeriod"
+                    :options="algTempHumCollectPeriod"
+                    :field-names="{ label: 'dictValue', value: 'dictEngValue' }"
+                    :placeholder="$t('common.plzSelect')"
+                  />
+                </AFormItem>
+                <AFormItem :label="t('algorithmManage.sourceTemperature')" name="waterSupplyTempSource">
+                  <ARadioGroup v-model:value="algorithmForm.waterSupplyTempSource">
+                    <ARadio class="radio-right" :value="0">{{ $t('algorithmManage.weighted') }} </ARadio>
+                    <ARadio :value="1"> {{ $t('algorithmManage.read') }} </ARadio>
+                  </ARadioGroup>
+                </AFormItem>
+              </AFlex>
+            </AForm>
+          </div>
+        </ACollapsePanel>
+
+        <ACollapsePanel
+          v-show="chillersList.length > 0"
+          :style="customStyle"
+          v-for="item in chillersList"
+          :key="item.id"
+        >
+          <template #header>
+            <AFlex align="center" class="header-heigth">
+              <span class="header-text">{{ item.deviceName }}</span>
+            </AFlex>
+          </template>
+          <EquipmentControl
+            ref="equipmentControlRefs"
+            :alg-wt-temp-ctrl-mode="algWtTempCtrlMode"
+            :alg-always="algAlways"
+            :alg-wt-temp-set-step="algWtTempSetStep"
+            :form="item"
+          />
+        </ACollapsePanel>
+
+        <ACollapsePanel key="functionSettings" :style="customStyle">
+          <template #header>
+            <AFlex align="center" class="header-heigth">
+              <span class="header-text">{{ $t('algorithmManage.systemFunctionSettings') }}</span>
+            </AFlex>
+          </template>
+          <div>
+            <AFlex align="center" class="analysis-bottom">
+              <div class="text">{{ $t('energyAnalysis.energyEfficiencyAnalysis') }}</div>
+              <ASwitch class="analysis-margin" v-model:checked="algorithmForm.analysis" />
+              <div @click="analysisEditor" class="editor-style">{{ $t('common.editor') }}</div>
+            </AFlex>
+            <AFlex align="center">
+              <div class="div-width">{{ $t('algorithmManage.dynamicAdjustment') }}</div>
+              <AFlex align="center" class="adjustment-div">
+                <div class="adjustment-text">{{ $t('algorithmManage.freezingSetValue') }}</div>
+                <ASwitch v-model:checked="algorithmForm.enableRefrigerationPipeDynamicSet" />
+                <div class="adjustment-text adjustment-left">{{ $t('algorithmManage.coolingSetValue') }}</div>
+                <ASwitch v-model:checked="algorithmForm.enableCoolingPipeDynamicSet" />
+                <div @click="setEditor" class="editor-style editor-left">{{ $t('common.editor') }}</div>
+              </AFlex>
+            </AFlex>
+          </div>
+        </ACollapsePanel>
+      </ACollapse>
+      <AFlex justify="space-between" class="bottom-style">
+        <AButton type="text" @click="canceladd">{{ $t('common.cancel') }}</AButton>
+        <AButton type="primary" class="button-width" @click="addAlgorithm">{{ $t('common.certain') }}</AButton>
+      </AFlex>
+    </div>
+    <AModal
+      v-model:open="analysisOpen"
+      :title="t('algorithmManage.energyEfficiencyAnalysisSettings')"
+      width="460px"
+      :mask-closable="false"
+      @ok="okConfirm"
+    >
+      <div class="analysis-style">
+        <span>* </span>{{ $t('algorithmManage.energyEfficiencyAnalysisCalculationMethod') }}
+      </div>
+      <ARadioGroup v-model:value="analysisTypeDisplay">
+        <ARadio class="radio-right" :value="0">{{ $t('algorithmManage.thermometer') }}</ARadio>
+        <ARadio class="radio-right" :value="1">{{ $t('algorithmManage.flowChart') }}</ARadio>
+        <ARadio :value="2">{{ $t('algorithmManage.copAlgorithm') }}</ARadio>
+      </ARadioGroup>
+    </AModal>
+    <AModal
+      v-model:open="setOpen"
+      :title="t('common.settings')"
+      width="460px"
+      :mask-closable="false"
+      @ok="okSetConfirm"
+    >
+      <AFlex align="center" class="set-top set-bottom">
+        <div class="text">
+          {{ $t('algorithmManage.backwaterTemperatureSettingValue') }} &nbsp;=&nbsp;
+          {{ $t('algorithmManage.outdoorWetBulbTemperature') }} +
+        </div>
+        &nbsp;&nbsp;
+        <AInputNumber v-model:value="coolingPipeDynamicOffsetDisplay" :min="-99999.99999" :max="99999" />
+      </AFlex>
+      <AFlex align="center" class="set-bottom">
+        <div class="text set-text">{{ $t('algorithmManage.initialValue') }}(℃)</div>
+        <AInputNumber
+          class="set-input-width set-input-right"
+          v-model:value="coolingPipeDynamicSetDisplay"
+          :min="-99999.99999"
+          :max="99999"
+        />
+        <div class="set-text text">{{ $t('algorithmManage.deadZone') }}(℃)</div>
+        <AInputNumber
+          class="set-input-width"
+          v-model:value="coolingPipeDynamicDeadZoneDisplay"
+          :min="-99999.99999"
+          :max="99999"
+        />
+      </AFlex>
+
+      <AFlex align="center" class="set-bottom">
+        <div class="text lower-limit">{{ $t('algorithmManage.lowerLimit') }}(℃)</div>
+        <AInputNumber
+          class="set-input-width set-input-right"
+          v-model:value="coolingPipeDynamicLowerDisplay"
+          :min="-99999.99999"
+          :max="99999"
+        />
+        <div class="set-text text">{{ $t('algorithmManage.upperLimit') }}(℃)</div>
+        <AInputNumber
+          class="set-input-width"
+          v-model:value="coolingPipeDynamicUpperDisplay"
+          :min="-99999.99999"
+          :max="99999"
+        />
+      </AFlex>
+    </AModal>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.button-width {
+  width: 128px;
+  height: 40px;
+}
+
+.bottom-style {
+  width: 55%;
+  padding-left: 28px;
+  margin-top: 8px;
+}
+
+.set-top {
+  margin-top: 20px;
+}
+
+.set-bottom {
+  margin-bottom: 24px;
+}
+
+.lower-limit {
+  margin-right: 26px;
+}
+
+.set-input-right {
+  margin-right: 40px;
+}
+
+.algorithm-form :deep(.ant-form-item-label > label) {
+  color: #666;
+}
+
+.set-text {
+  margin-right: 12px;
+}
+
+.text {
+  font-size: 14px;
+  font-style: normal;
+  font-weight: 400;
+  line-height: 22px;
+  color: #666;
+}
+
+.set-input-width {
+  width: 96px;
+}
+
+.editor-left {
+  margin-left: 16px;
+}
+
+.adjustment-left {
+  margin-left: 82px;
+}
+
+.adjustment-text {
+  margin-right: 16px;
+  font-size: 14px;
+  font-style: normal;
+  font-weight: 400;
+  line-height: 22px;
+  color: #666;
+  text-align: left;
+}
+
+.analysis-style {
+  margin-top: 16px;
+  margin-bottom: 13px;
+  color: #666;
+}
+
+.analysis-style span {
+  color: red;
+}
+
+.analysis-bottom {
+  margin-bottom: 24px;
+}
+
+.div-width {
+  width: 72px;
+  color: #666;
+}
+
+.adjustment-div {
+  width: 100%;
+  height: 72px;
+  padding-left: 16px;
+  background: #f5f7fa;
+  border-radius: 4px;
+}
+
+.editor-style {
+  color: #32bac0;
+  text-decoration: underline;
+  cursor: pointer;
+}
+
+.analysis-margin {
+  margin: 0 18px 0 17px;
+}
+
+.header-heigth {
+  height: 32px;
+}
+
+.icon-style {
+  margin-left: 4px;
+}
+
+.flex-margin {
+  margin: 16px 0;
+}
+
+.radio-right {
+  margin-right: 16px;
+}
+
+.flex-bottom {
+  row-gap: 0 !important;
+}
+
+.input-width {
+  width: 192px;
+}
+
+.header-text {
+  margin-right: 18px;
+  font-size: 16px;
+  font-style: normal;
+  font-weight: 500;
+  line-height: 24px;
+  color: #000;
+  text-align: left;
+}
+
+:deep(.algorithm-content) {
+  .ant-collapse > .ant-collapse-item > .ant-collapse-header .ant-collapse-expand-icon {
+    margin-top: 6px;
+  }
+
+  .ant-input-number-group .ant-input-number-group-addon {
+    background-color: #fff;
+  }
+
+  .ant-collapse .ant-collapse-content {
+    border: 0;
+
+    .ant-collapse-content-box {
+      padding: 16px 0;
+    }
+  }
+}
+
+.algorithm-content {
+  width: 100%;
+  height: 100%;
+  padding: 24px;
+  margin-top: 16px;
+  background: #fff;
+  border-radius: 16px;
+}
+
+.title-text {
+  font-size: 20px;
+  font-style: normal;
+  font-weight: 500;
+  line-height: 32px;
+  color: rgb(0 0 0 / 85%);
+  text-align: left;
+}
+
+.interval-style {
+  margin-top: 0;
+}
+</style>

+ 2 - 2
src/views/algorithm-manage/EquipmentControl.vue

@@ -87,10 +87,10 @@ defineExpose({
             :placeholder="t('common.pleaseEnter')"
             class="select-width"
             v-model:value="form.safeLoadLower"
-            addon-after="kpa"
+            addon-after="%"
           />
         </AFormItem>
-        <AFormItem :label="t('algorithmManage.stepSizeForWaterTemperatureSetting')" name="continuous">
+        <AFormItem :label="t('algorithmManage.stepSizeForWaterTemperatureSetting') + '(℃)'" name="continuous">
           <ASelect
             class="select-width"
             v-model:value="form.waterTempStep"