Jelajahi Sumber

feat: 碳源投加界面基本布局

sunxiao 1 bulan lalu
induk
melakukan
60539dc7e8
27 mengubah file dengan 3315 tambahan dan 493 penghapusan
  1. TEMPAT SAMPAH
      src/assets/fonts/DIN-RegularAlternate.otf
  2. TEMPAT SAMPAH
      src/assets/images/control/bg-play-btn.png
  3. TEMPAT SAMPAH
      src/assets/images/control/bg-top.png
  4. 13 0
      src/assets/images/control/icon-end.svg
  5. 3 0
      src/assets/images/control/line-left-1.svg
  6. 3 0
      src/assets/images/control/line-left-2.svg
  7. 3 0
      src/assets/images/control/line-left-3.svg
  8. TEMPAT SAMPAH
      src/assets/images/control/number-card-left.png
  9. 29 0
      src/assets/images/control/number-card-middle.svg
  10. 30 0
      src/assets/images/control/number-card-middle2.svg
  11. TEMPAT SAMPAH
      src/assets/images/control/number-card-right.png
  12. 9 0
      src/assets/styles/common.scss
  13. 1 1
      src/components/Layout/TheChatView.vue
  14. 863 0
      src/views/control-Old/MedicinalView-Old.vue
  15. 541 0
      src/views/control-Old/MedicinalView.vue
  16. 73 0
      src/views/control-Old/components/BaseButton.vue
  17. 56 0
      src/views/control-Old/components/BaseCard.vue
  18. 163 0
      src/views/control-Old/components/BaseChooseItem.vue
  19. 202 0
      src/views/control-Old/components/BaseInput.vue
  20. 72 0
      src/views/control-Old/components/BaseRadioCard.vue
  21. 67 0
      src/views/control-Old/components/BaseRadioGroup.vue
  22. 62 0
      src/views/control-Old/components/BaseTitle.vue
  23. 501 0
      src/views/control-Old/components/TheEchartPanel.vue
  24. 275 0
      src/views/control-Old/components/TheResultPanel.vue
  25. 311 486
      src/views/control/MedicinalView.vue
  26. 32 0
      src/views/control/NumberPanel.vue
  27. 6 6
      src/views/control/components/BaseTitle.vue

TEMPAT SAMPAH
src/assets/fonts/DIN-RegularAlternate.otf


TEMPAT SAMPAH
src/assets/images/control/bg-play-btn.png


TEMPAT SAMPAH
src/assets/images/control/bg-top.png


+ 13 - 0
src/assets/images/control/icon-end.svg

@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 28 28" fill="none">
+  <g clip-path="url(#clip0_6019_2985)">
+    <path d="M0 14C0 17.713 1.475 21.274 4.10051 23.8995C6.72601 26.525 10.287 28 14 28C17.713 28 21.274 26.525 23.8995 23.8995C26.525 21.274 28 17.713 28 14C28 10.287 26.525 6.72601 23.8995 4.10051C21.274 1.475 17.713 0 14 0C10.287 0 6.72601 1.475 4.10051 4.10051C1.475 6.72601 0 10.287 0 14Z" fill="#2454FF" fill-opacity="0.3"/>
+    <path d="M1.88159 14.0013C1.88159 15.5928 2.19505 17.1686 2.80406 18.6389C3.41307 20.1092 4.30572 21.4451 5.43102 22.5704C6.55633 23.6957 7.89227 24.5884 9.36255 25.1974C10.8328 25.8064 12.4087 26.1198 14.0001 26.1198C15.5915 26.1198 17.1674 25.8064 18.6377 25.1974C20.108 24.5884 21.4439 23.6957 22.5692 22.5704C23.6945 21.4451 24.5871 20.1092 25.1962 18.6389C25.8052 17.1686 26.1186 15.5928 26.1186 14.0013C26.1186 12.4099 25.8052 10.8341 25.1962 9.36377C24.5871 7.89349 23.6945 6.55755 22.5692 5.43224C21.4439 4.30694 20.108 3.41429 18.6377 2.80528C17.1674 2.19627 15.5915 1.88281 14.0001 1.88281C12.4087 1.88281 10.8328 2.19627 9.36255 2.80528C7.89227 3.41429 6.55633 4.30694 5.43102 5.43224C4.30572 6.55755 3.41307 7.89349 2.80406 9.36377C2.19505 10.8341 1.88159 12.4099 1.88159 14.0013Z" fill="#2454FF"/>
+    <path opacity="0.1" d="M0 14C0 21.7284 6.26667 27.9951 14 27.9951V0C6.26667 0 0 6.26667 0 14Z" fill="#FEFFFF"/>
+    <rect x="9.33325" y="9.33398" width="9.33333" height="9.33333" rx="1.55556" fill="white"/>
+  </g>
+  <defs>
+    <clipPath id="clip0_6019_2985">
+      <rect width="28" height="28" fill="white"/>
+    </clipPath>
+  </defs>
+</svg>

+ 3 - 0
src/assets/images/control/line-left-1.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="141" height="166" viewBox="0 0 141 166" fill="none">
+<path d="M140 164.58L31.9403 159.904C31.0853 159.867 30.3377 159.316 30.0493 158.51L0.532073 76.0659C0.216753 75.1852 0.520411 74.202 1.27747 73.6525L100.789 1.42188L103 4.50098" stroke="#5262FF"/>
+</svg>

+ 3 - 0
src/assets/images/control/line-left-2.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="134" height="73" viewBox="0 0 134 73" fill="none">
+<path d="M0.842285 3.15841L11.6318 0.263672L32.7162 56.0604C33.0158 56.8532 33.7617 57.3891 34.6087 57.42L134 61.0531V72.3689L25.4129 67.6929C24.5585 67.6561 23.8113 67.1061 23.5222 66.3013L0.842285 3.15841Z" fill="#2454FF"/>
+</svg>

+ 3 - 0
src/assets/images/control/line-left-3.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="111" height="7" viewBox="0 0 111 7" fill="none">
+  <path d="M0.526367 0.841797L110 5.57864" stroke="#25AB7E" stroke-width="1.57895"/>
+</svg>

TEMPAT SAMPAH
src/assets/images/control/number-card-left.png


+ 29 - 0
src/assets/images/control/number-card-middle.svg

@@ -0,0 +1,29 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="188" height="188" viewBox="0 0 188 188" fill="none">
+  <g filter="url(#filter0_ii_6019_2931)">
+    <circle cx="94.0003" cy="93.9994" r="93.3333" fill="white"/>
+  </g>
+  <circle cx="94.0003" cy="93.9994" r="93.3333" fill="url(#paint0_linear_6019_2931)" fill-opacity="0.6"/>
+  <defs>
+    <filter id="filter0_ii_6019_2931" x="0.666992" y="-9.28954" width="186.667" height="204.088" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+      <feFlood flood-opacity="0" result="BackgroundImageFix"/>
+      <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
+      <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+      <feOffset dy="7.46667"/>
+      <feGaussianBlur stdDeviation="6.22222"/>
+      <feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
+      <feColorMatrix type="matrix" values="0 0 0 0 0.0724288 0 0 0 0 0.613512 0 0 0 0 1 0 0 0 0.5 0"/>
+      <feBlend mode="normal" in2="shape" result="effect1_innerShadow_6019_2931"/>
+      <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+      <feOffset dy="-9.95556"/>
+      <feGaussianBlur stdDeviation="6.22222"/>
+      <feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
+      <feColorMatrix type="matrix" values="0 0 0 0 0.439466 0 0 0 0 0.377616 0 0 0 0 0.84149 0 0 0 0.39 0"/>
+      <feBlend mode="normal" in2="effect1_innerShadow_6019_2931" result="effect2_innerShadow_6019_2931"/>
+    </filter>
+    <linearGradient id="paint0_linear_6019_2931" x1="94.0003" y1="168.666" x2="94.0003" y2="17.466" gradientUnits="userSpaceOnUse">
+      <stop stop-color="white" stop-opacity="0.2"/>
+      <stop offset="0.495205" stop-color="white"/>
+      <stop offset="1" stop-color="white" stop-opacity="0.2"/>
+    </linearGradient>
+  </defs>
+</svg>

+ 30 - 0
src/assets/images/control/number-card-middle2.svg

@@ -0,0 +1,30 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="193" height="46" viewBox="0 0 193 46" fill="none">
+  <ellipse opacity="0.5" cx="96.5" cy="30.1051" rx="96.5" ry="15.8941" fill="url(#paint0_linear_6019_2924)"/>
+  <mask id="mask0_6019_2924" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="20" y="0" width="157" height="46">
+    <ellipse cx="98.2034" cy="23" rx="78" ry="23" fill="url(#paint1_linear_6019_2924)"/>
+  </mask>
+  <g mask="url(#mask0_6019_2924)">
+    <g opacity="0.6" filter="url(#filter0_f_6019_2924)">
+      <ellipse cx="98.2034" cy="23" rx="78" ry="23" fill="url(#paint2_linear_6019_2924)"/>
+    </g>
+  </g>
+  <defs>
+    <filter id="filter0_f_6019_2924" x="10.2034" y="-10" width="176" height="66" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+      <feFlood flood-opacity="0" result="BackgroundImageFix"/>
+      <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
+      <feGaussianBlur stdDeviation="5" result="effect1_foregroundBlur_6019_2924"/>
+    </filter>
+    <linearGradient id="paint0_linear_6019_2924" x1="96" y1="30" x2="96.5" y2="45.9992" gradientUnits="userSpaceOnUse">
+      <stop stop-color="#C9CEDC" stop-opacity="0"/>
+      <stop offset="1" stop-color="#DBDDEA"/>
+    </linearGradient>
+    <linearGradient id="paint1_linear_6019_2924" x1="98.2034" y1="0" x2="98.2034" y2="46" gradientUnits="userSpaceOnUse">
+      <stop stop-color="#A2A5CD" stop-opacity="0.2"/>
+      <stop offset="1" stop-color="#A2A5CD"/>
+    </linearGradient>
+    <linearGradient id="paint2_linear_6019_2924" x1="98.0002" y1="20" x2="98.2034" y2="46" gradientUnits="userSpaceOnUse">
+      <stop stop-color="white" stop-opacity="0"/>
+      <stop offset="1" stop-color="#9A82E1"/>
+    </linearGradient>
+  </defs>
+</svg>

TEMPAT SAMPAH
src/assets/images/control/number-card-right.png


+ 9 - 0
src/assets/styles/common.scss

@@ -16,6 +16,15 @@
   font-style: normal;
 }
 
+@font-face {
+  font-display: swap;
+  font-family: 'DIN-RegularAlternate';
+  src: url('@/assets/fonts/DIN-RegularAlternate.otf') format('opentype');
+  font-weight: normal;
+  font-style: normal;
+}
+
+
 @font-face {
   // font-display: swap;
   font-family: 'YouSheBiaoTiHei';

+ 1 - 1
src/components/Layout/TheChatView.vue

@@ -53,7 +53,7 @@ defineExpose({ targetScrollDom });
       <slot name="catalog"></slot>
     </div>
     <div class="chat-wrapper w-full h-full flex flex-col rounded-[10px]" :style="{ padding: isHeader ? '0px' : '20px 0px 20px 0px' }">
-      <div class="chat-header flex items-center justify-between py-[24px] px-[18px] " v-if="isHeader">
+      <div class="chat-header flex items-center justify-between py-[12px] px-[24px] " v-if="isHeader">
         <div class="left_inner" @click="handleClickBack">
           <span v-if="isBackBtn" class="back-btn"></span>
           <span v-if="leftTitle" class="left_title">{{ leftTitle }}</span>

+ 863 - 0
src/views/control-Old/MedicinalView-Old.vue

@@ -0,0 +1,863 @@
+<script setup>
+import { ref, onMounted, computed, unref, watch } from 'vue';
+import { NScrollbar, useMessage, NTabs, NTabPane, c } from 'naive-ui';
+import { TheChatView } from '@/components';
+import { controlApi } from "@/api/control";
+import BaseTitle from './components/BaseTitle.vue';
+import BaseRadioCard from './components/BaseRadioCard.vue';
+import BaseCard from './components/BaseCard.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 isVisibleUpdateInfo = ref(false);
+const systemStatus = ref(0);
+
+const columnData = ref([
+  { label: '后反馈设定', key: 'htfksd', value: '' },
+  { label: '基准系数', key: 'jzxs', value: '' },
+  { label: '修正系数', key: 'xzxs', value: '' },
+  { label: '控制系数', key: 'kzxs', value: '' },
+  { label: '水量分配系数', key: 'slfpxs', value: '' },
+  { label: '碳源当量', key: 'tydl', value: '' },
+  { label: '转换系数', key: 'zhxs', value: '' },
+  { label: '稀释倍数', key: 'sxps', value: '' },
+  { label: '药剂密度', key: 'yymd', value: '' },
+  { label: '最小启动流量', key: 'zxqdll', value: '' },
+  { label: '碳氮比', key: 'tdb', value: '' }
+])
+
+const doseNum = ref(null);
+const flowNum = ref(null);
+const updateNum = ref(null);
+
+const tabKeyEnum = {
+  0: 'auto',
+  1: 'onePool',
+  2: 'twoPool',
+  3: 'worker'
+}
+
+// water实时数据
+const waterConfigParams = ref({});
+
+// 基础数据
+const dataSourceParams = ref({
+  auto: {},
+  onePool: {},
+  twoPool: {},
+  worker: {
+    medicineAmount: null
+  }
+})
+
+// 系数
+const baseSourceParams = ref({
+  numberBeng: 0,
+  type: 0
+})
+
+// 当前Tab选中的key
+const tabActiveKey = computed(() => tabKeyEnum[baseSourceParams.value.type]);
+// 计算碳氮比
+const tdbNum = computed(() => {
+  const type = tabActiveKey.value;
+
+  const [ r1, r2, rOne, rTwo] = getTotalNum();
+ 
+  const { 
+    jsLlOne, jsLlTwo,
+    jsCodOne, jsCodTwo,
+    jsTnOne, jsTnTwo
+  } = dataSourceParams.value[type];
+
+  const {
+    tydl, zhxs
+  } = baseSourceParams.value
+ 
+  if ( type === 'auto' || type === 'worker' ) {
+    const rNum = Math.max( r1, r2 );
+    const jsll = rNum == r1 ? jsLlOne: jsLlTwo;
+    const cod = rNum == r1 ? jsCodOne: jsCodTwo;
+    const jsTn = rNum == r1 ? jsTnOne: jsTnTwo;
+    const n = rNum == r1 ? rOne : rOne
+    return Number(((n*1000/jsll*tydl+cod*zhxs*tydl)/jsTn).toFixed(2));
+  }
+  if ( type === 'onePool' ) {
+    return Number(((rOne*1000/jsLlOne*tydl+jsCodOne*zhxs*tydl)/jsTnOne).toFixed(2));
+  }
+  if ( type === 'twoPool' ) {
+    return Number(((rTwo*1000/jsLlTwo*tydl+jsCodTwo*zhxs*tydl)/jsTnTwo).toFixed(2));
+  }
+})
+watch(() => tdbNum.value , tdb => {
+  columnData.value[columnData.value.length - 1].value = tdb;
+})
+
+// 编辑系数 - confirm
+const onEditConfirm = () => {
+  isVisibleBtn.value = true;
+  columnData.value = columnData.value.map(item => {
+    Object.entries(baseSourceParams.value).forEach(([key, value]) => {
+      if (key === item.key) {
+        item.value = value;
+      }
+    })
+    return item;
+  })
+
+  handleMedicateAmount();
+}
+
+// 编辑系数 - 取消
+const onEditCancel = () => {
+  isVisibleBtn.value = true;
+
+  columnData.value.map(({ key, value }) => {
+    baseSourceParams.value[key] = value;
+  })
+}
+
+const onFinalResult = () => {
+  const addStatus = systemStatus.value === 0 ? 1 : 0;
+
+  controlApi.putSystemStatus({ addStatus });
+
+  systemStatus.value = addStatus;
+
+  message.warning(addStatus === 0 ? '当前投药状态:已停用' : '当前投药状态:投放中');
+
+}
+
+const onUpdateTab = (index) => {
+  const currentData = dataSourceParams.value[tabKeyEnum[index]];
+  baseSourceParams.value.type = index;
+  if ( !Object.keys(currentData).length ) {
+    isVisibleUpdateInfo.value = false;
+    return;
+  }
+  isVisibleBtn.value = true;
+  handleMedicateAmount();
+}
+
+function getTotalNum() {
+  const {
+    hycXsyOne = 0, hycXsyTwo = 0,
+    qycAdOne = 0, qycAdTwo = 0,
+    qycYxyOne = 0, qycYxyTwo = 0,
+    jsLlOne = 0, jsLlTwo = 0,
+    jsCodOne = 0, jsCodTwo = 0
+  } = dataSourceParams.value[tabActiveKey.value];
+
+  const {
+    htfksd, xzxs, kzxs, slfpxs, zhxs, tydl, jzxs, yymd, sxps
+  } = baseSourceParams.value;
+
+  const rOne1 = (((2*hycXsyOne-htfksd)+((qycAdOne+qycYxyOne)*xzxs-htfksd))*(jzxs-1))*(jsLlOne*slfpxs)/1000;
+  const rOne2 = (rOne1*kzxs-(jsLlOne*slfpxs*jsCodOne*zhxs/1000))/tydl;
+  const rOne3 = rOne2/yymd/1000*sxps
+
+  const rTwo1 = (((2*hycXsyTwo-htfksd)+((qycAdTwo+qycYxyTwo)*xzxs-htfksd))*(jzxs-1))*(jsLlTwo*slfpxs)/1000;
+  const rTwo2 = (rTwo1*kzxs-(jsLlTwo*slfpxs*jsCodTwo*zhxs/1000))/tydl;
+  const rTwo3 = rTwo2/yymd/1000*sxps
+
+  const r1 = Number((rOne3 < 0 || !rOne3) ? 0 : rOne3.toFixed(3)) || 0;
+  const r2 = Number((rTwo3 < 0 || !rTwo3) ? 0 : rTwo3.toFixed(3)) || 0;
+
+  return [ r1, r2, rOne2, rTwo2 ];
+}
+
+const onConfirmUpdate = async () => {
+  await controlApi.postAddRecord({
+    ...dataSourceParams.value[tabKeyEnum[baseSourceParams.value.type]],
+    ...baseSourceParams.value,
+  });
+
+  isVisibleUpdateInfo.value = false;
+
+  message.success("系统加药量,更新成功");
+
+  doseNum.value = updateNum.value;
+}
+
+// 更新投药结果
+const handleMedicateAmount = () => {
+  const type = tabActiveKey.value;
+  const lastNum = unref(updateNum);
+  const tdb = tdbNum.value;
+
+  if ( type === 'worker' ) {
+    const medicineNum = dataSourceParams.value.worker.medicineAmount;
+    if ( medicineNum || medicineNum == 0 ) {
+      updateNum.value = medicineNum;
+      isVisibleUpdateInfo.value = true;
+      baseSourceParams.value.tdb = tdb;
+      message.warning("有新投放方案, 请查看")
+    } else {
+      updateNum.value = null;
+      isVisibleUpdateInfo.value = false;
+    }
+    return;
+  }
+
+  const [r1, r2] = getTotalNum();
+  const maxR = Math.max( r1, r2 );
+
+  if ( type === 'auto' && maxR !== lastNum) {
+    updateNum.value = maxR;
+    isVisibleUpdateInfo.value = true;
+    baseSourceParams.value.tdb = tdb;
+    message.warning("有新的投放方案, 请查看");
+  }
+
+  if ( type === 'onePool' && r1 != lastNum) {
+    updateNum.value = r1;
+    isVisibleUpdateInfo.value = true;
+    baseSourceParams.value.tdb = tdb;
+    message.warning("有新的投放方案, 请查看");
+  }
+
+  if ( type === 'twoPool' && r2 != lastNum ) {
+    updateNum.value = r2;
+    isVisibleUpdateInfo.value = true;
+    baseSourceParams.value.tdb = tdb;
+    message.warning("有新的投放方案, 请查看");
+  }
+
+}
+
+onMounted(async () => {
+  // 获取最后一条记录  getSystemStatus
+  await controlApi.getBaseData().then(({ data }) => {
+    const {
+      numberBeng = 0, type = 0,
+      htfksd, jzxs, xzxs, kzxs, slfpxs, tydl, zhxs, sxps, yymd, zxqdll,
+      medicineAmount,
+      addType,
+      tytjTransientLL
+    } = data;
+ 
+    baseSourceParams.value = { 
+      ...baseSourceParams.value,
+      numberBeng, type,
+      htfksd, jzxs, xzxs, kzxs, slfpxs, tydl, zhxs, sxps, yymd, zxqdll,
+      addType
+    };
+    
+    updateNum.value = medicineAmount;
+
+    doseNum.value = medicineAmount;
+
+    flowNum.value = tytjTransientLL;
+
+    dataSourceParams.value[tabActiveKey.value] = data;
+
+  })
+
+ 
+  // 获取实时数据
+  controlApi.getNumValue().then(({ data }) => {
+
+    Object.entries(data).forEach(([key, val]) => {
+      data[key] = val;
+    });
+
+    // water实时数据
+    waterConfigParams.value = data;
+
+    // 重新计算碳氮比
+    const tdb = tdbNum.value;
+    baseSourceParams.value.tdb = tdb;
+ 
+    columnData.value = columnData.value.map(item => {
+      item.value = item.key === 'tdb' ? tdb : dataSourceParams.value[tabActiveKey.value][item.key];
+      return item;
+    })
+
+    const params = {
+      jsLlType: 1,
+      jsLlOne: data.jslYB,
+      jsLlTwo: data.jslYB,
+      jsCodType: 1,
+      jsCodOne: data.jsCodYB,
+      jsCodTwo: data.jsCodYB,
+      hycXsyType: 1,
+      hycXsyOne: data.hyXsyHYOne,
+      hycXsyTwo: data.hyXsyHYTwo,
+      qycYxyType: 1,
+      qycYxyOne: data.qyXsyHYOne,
+      qycYxyTwo: data.qyXsyHYTwo,
+      qycAdType: 1,
+      qycAdOne: data.qyAdHYOne,
+      qycAdTwo: data.qyAdHYTwo,
+      jsTnType: 1,
+      jsTnOne: data.jsTnYB,
+      jsTnTwo: data.jsTnYB
+    }
+
+    Object.keys(dataSourceParams.value).forEach(key => {
+      const item = dataSourceParams.value[key];
+      if ( !Object.keys(item).length ) {
+        dataSourceParams.value[key] = { ...params };
+      }
+    })
+  })
+
+  // 获取是否允许投药开关
+  controlApi.getSystemStatus().then(({ data }) => {
+    // 0不允许  1允许
+    systemStatus.value = data;
+  });
+})
+
+</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="智能投加计算"></BaseTitle>
+            <n-scrollbar class="scrollbar" style="height: 100%;">
+              <div class="form-content">
+
+                <BaseCard title="选择加药泵">
+                  <BaseRadioCard v-model="baseSourceParams.numberBeng"></BaseRadioCard>
+                </BaseCard>
+
+                <BaseCard title="投加运行方式">
+                  <span class="status-bar">
+                    <i>{{ baseSourceParams.addType === 0 ? '启用智适应碳源投加' : '手动碳源投加' }}</i>
+                  </span>
+                </BaseCard>
+
+                <BaseCard title="选择池组手自动方式">
+                  <n-tabs justify-content="space-between" type="line" :bar-width="40"
+                    tab-style="min-width: 89px;" tab-class="custom-tab_item" animated :on-update:value="onUpdateTab" :value="baseSourceParams.type">
+                    <n-tab-pane :name="0" tab="自动">
+                      <div class="panel-header_main">
+                        <p>设置数据来源</p>
+                        <p class="space-x-[20px] text-center">
+                          <span>1号池</span>
+                          <span>2号池</span>
+                        </p>
+                      </div>
+                      <div class="space-y-[12px]">
+                        <BaseChooseItem
+                          tab-key="auto"
+                          title="进水流量"
+                          unit="m³"
+                          isDouble
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.auto.jsLlType"
+                          v-model:value1="dataSourceParams.auto.jsLlOne"
+                          v-model:value2="dataSourceParams.auto.jsLlTwo"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '仪表', value1: waterConfigParams.jslYB, value2: waterConfigParams.jslYB }
+                          ]"
+                        ></BaseChooseItem>
+                        <BaseChooseItem
+                          tab-key="auto"
+                          title="进水COD"
+                          unit="mg/L"
+                          isDouble
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.auto.jsCodType"
+                          v-model:value1="dataSourceParams.auto.jsCodOne"
+                          v-model:value2="dataSourceParams.auto.jsCodTwo"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '仪表', value1: waterConfigParams.jsCodYB, value2: waterConfigParams.jsCodYB },
+                            { label: '化验', value1: waterConfigParams.jsCodHY, value2: waterConfigParams.jsCodHY }
+                          ]"
+                        ></BaseChooseItem>
+                        
+                        <BaseChooseItem
+                          tab-key="auto"
+                          title="好氧池硝酸盐"
+                          unit="mg/L"
+                          isDouble
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.auto.hycXsyType"
+                          v-model:value1="dataSourceParams.auto.hycXsyOne"
+                          v-model:value2="dataSourceParams.auto.hycXsyTwo"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '化验', value1: waterConfigParams.hyXsyHYOne, value2: waterConfigParams.hyXsyHYTwo },
+                            { label: '预测', value1: waterConfigParams.hyXsyYCOne, value2: waterConfigParams.hyXsyYCTwo }
+                          ]"
+                        ></BaseChooseItem>
+                        <BaseChooseItem
+                          tab-key="auto"
+                          title="缺氧池硝酸盐"
+                          unit="mg/L"
+                          isDouble
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.auto.qycYxyType"
+                          v-model:value1="dataSourceParams.auto.qycYxyOne"
+                          v-model:value2="dataSourceParams.auto.qycYxyTwo"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '化验', value1: waterConfigParams.qyXsyHYOne, value2: waterConfigParams.qyXsyHYTwo }
+                          ]"
+                        ></BaseChooseItem>
+                        <BaseChooseItem
+                          tab-key="auto"
+                          title="缺氧池氨氮"
+                          unit="mg/L"
+                          isDouble
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.auto.qycAdType"
+                          v-model:value1="dataSourceParams.auto.qycAdOne"
+                          v-model:value2="dataSourceParams.auto.qycAdTwo"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '化验', value1: waterConfigParams.qyAdHYOne, value2: waterConfigParams.qyAdHYTwo }
+                          ]"
+                        ></BaseChooseItem>
+                        <BaseChooseItem
+                          tab-key="auto"
+                          title="进水总氮"
+                          unit="mg/L"
+                          isDouble
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.auto.jsTnType"
+                          v-model:value1="dataSourceParams.auto.jsTnOne"
+                          v-model:value2="dataSourceParams.auto.jsTnTwo"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '仪表', value1: waterConfigParams.jsTnYB, value2: waterConfigParams.jsTnYB }
+                          ]"
+                        ></BaseChooseItem>
+                      </div>
+                    </n-tab-pane>
+
+                    <n-tab-pane :name="1" tab="1号池">
+                      <div class="panel-header_main">
+                        <p>设置数据来源</p>
+                        <p class="space-x-[20px] text-center">
+                          <span>1号池</span>
+                        </p>
+                      </div>
+                      <div class="space-y-[12px]">
+                        <BaseChooseItem
+                          tab-key="onePool"
+                          title="进水流量"
+                          unit="m³"
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.onePool.jsLlType"
+                          v-model:value1="dataSourceParams.onePool.jsLlOne"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '仪表', value1: waterConfigParams.jslYB, value2: waterConfigParams.jslYB }
+                          ]"
+                        ></BaseChooseItem>
+                        <BaseChooseItem
+                          tab-key="onePool"
+                          title="进水COD"
+                          unit="mg/L"
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.onePool.jsCodType"
+                          v-model:value1="dataSourceParams.onePool.jsCodOne"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '仪表', value1: waterConfigParams.jsCodYB, value2: waterConfigParams.jsCodYB },
+                            { label: '化验', value1: waterConfigParams.jsCodHY, value2: waterConfigParams.jsCodHY }
+                          ]"
+                        ></BaseChooseItem>
+                        <BaseChooseItem
+                          tab-key="onePool"
+                          title="好氧池硝酸盐"
+                          unit="mg/L"
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.onePool.hycXsyType"
+                          v-model:value1="dataSourceParams.onePool.hycXsyOne"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '化验', value1: waterConfigParams.hyXsyHYOne, value2: waterConfigParams.hyXsyHYTwo },
+                            { label: '预测', value1: waterConfigParams.hyXsyYCOne, value2: waterConfigParams.hyXsyYCTwo }
+                          ]"
+                        ></BaseChooseItem>
+                        <BaseChooseItem
+                          tab-key="onePool"
+                          title="缺氧池硝酸盐"
+                          unit="mg/L"
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.onePool.qycYxyType"
+                          v-model:value1="dataSourceParams.onePool.qycYxyOne"
+                          v-model:value2="dataSourceParams.onePool.qycYxyTwo"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '化验', value1: waterConfigParams.qyXsyHYOne, value2: waterConfigParams.qyXsyHYTwo }
+                          ]"
+                        ></BaseChooseItem>
+                        <BaseChooseItem
+                          tab-key="onePool"
+                          title="缺氧池氨氮"
+                          unit="mg/L"
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.onePool.qycAdType"
+                          v-model:value1="dataSourceParams.onePool.qycAdOne"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '化验', value1: waterConfigParams.qyAdHYOne, value2: waterConfigParams.qyAdHYTwo }
+                          ]"
+                        ></BaseChooseItem>
+                        <BaseChooseItem
+                          tab-key="onePool"
+                          title="进水总氮"
+                          unit="mg/L"
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.onePool.jsTnType"
+                          v-model:value1="dataSourceParams.onePool.jsTnOne"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '仪表', value1: waterConfigParams.jsTnYB, value2: waterConfigParams.jsTnYB }
+                          ]"
+                        ></BaseChooseItem>
+                      </div>
+                    </n-tab-pane>
+
+                    <n-tab-pane :name="2" tab="2号池">
+                      <div class="panel-header_main">
+                        <p>设置数据来源</p>
+                        <p class="space-x-[20px] text-center">
+                          <span>2号池</span>
+                        </p>
+                      </div>
+                      <div class="space-y-[12px]">
+                        <BaseChooseItem
+                          tab-key="twoPool"
+                          title="进水流量"
+                          unit="m³"
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.twoPool.jsLlType"
+                          v-model:value1="dataSourceParams.twoPool.jsLlTwo"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '仪表', value1: waterConfigParams.jslYB, value2: waterConfigParams.jslYB }
+                          ]"
+                        ></BaseChooseItem>
+                        <BaseChooseItem
+                          tab-key="twoPool"
+                          title="进水COD"
+                          unit="mg/L"
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.twoPool.jsCodType"
+                          v-model:value1="dataSourceParams.twoPool.jsCodTwo"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '仪表', value1: waterConfigParams.jsCodYB, value2: waterConfigParams.jsCodYB },
+                            { label: '化验', value1: waterConfigParams.jsCodHY, value2: waterConfigParams.jsCodHY }
+                          ]"
+                        ></BaseChooseItem>
+                        <BaseChooseItem
+                          tab-key="twoPool"
+                          title="好氧池硝酸盐"
+                          unit="mg/L"
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.twoPool.hycXsyType"
+                          v-model:value1="dataSourceParams.twoPool.hycXsyTwo"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '化验', value1: waterConfigParams.hyXsyHYTwo },
+                            { label: '预测', value1: waterConfigParams.hyXsyYCTwo }
+                          ]"
+                        ></BaseChooseItem>
+                        <BaseChooseItem
+                          tab-key="twoPool"
+                          title="缺氧池硝酸盐"
+                          unit="mg/L"
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.twoPool.qycYxyType"
+                          v-model:value1="dataSourceParams.twoPool.qycYxyTwo"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '化验', value1: waterConfigParams.qyXsyHYTwo }
+                          ]"
+                        ></BaseChooseItem>
+                        <BaseChooseItem
+                          tab-key="twoPool"
+                          title="缺氧池氨氮"
+                          unit="mg/L"
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.twoPool.qycAdType"
+                          v-model:value1="dataSourceParams.twoPool.qycAdTwo"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '化验', value1: waterConfigParams.qyAdHYTwo }
+                          ]"
+                        ></BaseChooseItem>
+                        <BaseChooseItem
+                          tab-key="twoPool"
+                          title="进水总氮"
+                          unit="mg/L"
+                          @on-update="handleMedicateAmount"
+                          v-model:type="dataSourceParams.twoPool.jsTnType"
+                          v-model:value1="dataSourceParams.twoPool.jsTnTwo"
+                          :btn-group="[
+                            { label: '手动', value1: '', value2: '' },
+                            { label: '仪表', value1: waterConfigParams.jsTnYB }
+                          ]"
+                        ></BaseChooseItem>
+                      </div>
+                    </n-tab-pane>
+
+                    <n-tab-pane :name="3" tab="人工投放">
+                      <div class="panel-header_main">
+                        <p>设置数据来源</p>
+                        <p class="space-x-[20px] text-center">
+                          <span>人工投放</span>
+                        </p>
+                      </div>
+                      <div class="w-full flex items-center justify-between">
+                        <span>人工投放:</span>
+                        <div class="w-[200px]">
+                          <BaseInput
+                            :isCloseIcon="false"
+                            v-model="dataSourceParams.worker.medicineAmount"
+                            @on-blur="handleMedicateAmount"
+                          ></BaseInput>
+                        </div>
+                      </div>
+                    </n-tab-pane>
+                  </n-tabs>
+                </BaseCard>
+                <BaseCard title="设定参数系数" style="margin: 0" tips="建议使用默认值,非必要不修改" v-show="tabActiveKey !== 'worker'">
+                  <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">
+                        {{ item.value }}
+                        {{ index === 0 ? 'mg/L' : '' }}
+                      </span>
+                      <div style="width: 140px;" v-show="!isVisibleBtn">
+                        <BaseInput :unit="index === 0 ? 'mg/L' : ''" size='small' :isNeedFlotBtn="false"
+                          v-model="baseSourceParams[item.key]" isCenter placeholder="" :readonly="index === columnData.length - 1"></BaseInput>
+                      </div>
+                    </li>
+                  </ul>
+                </BaseCard>
+              </div>
+            </n-scrollbar>
+          </div>
+          <div class="right-section">
+            <TheResultPanel
+              :updateNum="updateNum"
+              :flowNum="flowNum"
+              :doseNum="doseNum"
+              :configuration-status="baseSourceParams.addType"
+              v-model:system="systemStatus"
+              v-model="isVisibleUpdateInfo"
+              @on-click="onFinalResult"
+              @on-update="onConfirmUpdate"
+            ></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;
+    flex-shrink: 0;
+    width: 440px;
+    height: 100%;
+    border-radius: 10px;
+    background: #fff;
+
+    .status-bar {
+      display: inline-block;
+      padding: 4px 14px;
+      margin-left: 20px;
+      border-top: 0.5px solid rgba(212, 241, 255, 0.00);
+      border-bottom: 0.5px solid rgba(212, 241, 255, 0.00);
+      background: linear-gradient(90deg, rgba(240, 250, 255, 0.00) 0%, #E9F8FF 27.27%, rgba(240, 250, 255, 0.00) 100%);
+
+      i {
+        line-height: 24px;
+        background: linear-gradient(92deg, #5ABBF2 12.24%, #2454FF 63.2%);
+        background-clip: text;
+        -webkit-background-clip: text;
+        -webkit-text-fill-color: transparent;
+        font-weight: bold;
+      }
+    }
+
+    .scrollbar {
+      height: 100%;
+    }
+
+    .form-content {
+      padding: 0 16px 24px 16px;
+    }
+
+    .panel-header_main {
+      @include flex(x, center, between);
+      margin-bottom: 12px;
+      color: #86909C;
+      span {
+        display: inline-block;
+        width: 60px;
+      }
+    }
+
+  }
+
+  .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: 12px;
+        color: #333;
+      }
+    }
+  }
+}
+
+.right-section {
+  width: 100%;
+  height: 100%;
+  border-radius: 8px;
+  background: #fff;
+  overflow: hidden;
+
+  // .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>
+
+<style lang="scss">
+.custom-tab_item {
+  @include flex (x, center, center);
+  height: 35px;
+  border-radius: 4px;
+  background: #F3F5FA;
+
+  &.n-tabs-tab--active {
+    transition: none !important;
+    border-radius: 4px;
+    transition: none !important;
+    background: url('https://static.fuxicarbon.com/bigModel/pc/tab-border-item-2x.png') -3px 0px no-repeat, linear-gradient(180deg, #F1F3FE 0%, #FFF 100%);
+    background-size: 107% 100%;
+  }
+}
+
+.control-container .left-section {
+  .n-tabs-nav-scroll-content {
+    padding-bottom: 10px;
+  }
+}
+</style>

+ 541 - 0
src/views/control-Old/MedicinalView.vue

@@ -0,0 +1,541 @@
+<script setup>
+import { ref, onMounted, computed, unref, watch } from 'vue';
+import { NScrollbar, useMessage, NTabs, NTabPane, c } from 'naive-ui';
+import { TheChatView } from '@/components';
+import { controlApi } from "@/api/control";
+import BaseTitle from './components/BaseTitle.vue';
+import BaseRadioCard from './components/BaseRadioCard.vue';
+import BaseCard from './components/BaseCard.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 isVisibleUpdateInfo = ref(false);
+const systemStatus = ref(0);
+
+const columnData = ref([
+  { label: '后反馈设定', key: 'htfksd', value: '' },
+  { label: '基准系数', key: 'jzxs', value: '' },
+  { label: '修正系数', key: 'xzxs', value: '' },
+  { label: '控制系数', key: 'kzxs', value: '' },
+  { label: '水量分配系数', key: 'slfpxs', value: '' },
+  { label: '碳源当量', key: 'tydl', value: '' },
+  { label: '转换系数', key: 'zhxs', value: '' },
+  { label: '稀释倍数', key: 'sxps', value: '' },
+  { label: '药剂密度', key: 'yymd', value: '' },
+  { label: '最小启动流量', key: 'zxqdll', value: '' },
+  { label: '碳氮比', key: 'tdb', value: '' }
+])
+
+const doseNum = ref(null);
+const flowNum = ref(null);
+const updateNum = ref(null);
+
+const tabKeyEnum = {
+  0: 'auto',
+  1: 'onePool',
+  2: 'twoPool',
+  3: 'worker'
+}
+
+// water实时数据
+const waterConfigParams = ref({});
+
+// 基础数据
+const dataSourceParams = ref({
+  auto: {},
+  onePool: {},
+  twoPool: {},
+  worker: {
+    medicineAmount: null
+  }
+})
+
+// 系数
+const baseSourceParams = ref({
+  numberBeng: 0,
+  type: 0
+})
+
+// 当前Tab选中的key
+const tabActiveKey = computed(() => tabKeyEnum[baseSourceParams.value.type]);
+// 计算碳氮比
+const tdbNum = computed(() => {
+  const type = tabActiveKey.value;
+
+  const [ r1, r2, rOne, rTwo] = getTotalNum();
+ 
+  const { 
+    jsLlOne, jsLlTwo,
+    jsCodOne, jsCodTwo,
+    jsTnOne, jsTnTwo
+  } = dataSourceParams.value[type];
+
+  const {
+    tydl, zhxs
+  } = baseSourceParams.value
+ 
+  if ( type === 'auto' || type === 'worker' ) {
+    const rNum = Math.max( r1, r2 );
+    const jsll = rNum == r1 ? jsLlOne: jsLlTwo;
+    const cod = rNum == r1 ? jsCodOne: jsCodTwo;
+    const jsTn = rNum == r1 ? jsTnOne: jsTnTwo;
+    const n = rNum == r1 ? rOne : rOne
+    return Number(((n*1000/jsll*tydl+cod*zhxs*tydl)/jsTn).toFixed(2));
+  }
+  if ( type === 'onePool' ) {
+    return Number(((rOne*1000/jsLlOne*tydl+jsCodOne*zhxs*tydl)/jsTnOne).toFixed(2));
+  }
+  if ( type === 'twoPool' ) {
+    return Number(((rTwo*1000/jsLlTwo*tydl+jsCodTwo*zhxs*tydl)/jsTnTwo).toFixed(2));
+  }
+})
+watch(() => tdbNum.value , tdb => {
+  columnData.value[columnData.value.length - 1].value = tdb;
+})
+
+// 编辑系数 - confirm
+const onEditConfirm = () => {
+  isVisibleBtn.value = true;
+  columnData.value = columnData.value.map(item => {
+    Object.entries(baseSourceParams.value).forEach(([key, value]) => {
+      if (key === item.key) {
+        item.value = value;
+      }
+    })
+    return item;
+  })
+
+  handleMedicateAmount();
+}
+
+// 编辑系数 - 取消
+const onEditCancel = () => {
+  isVisibleBtn.value = true;
+
+  columnData.value.map(({ key, value }) => {
+    baseSourceParams.value[key] = value;
+  })
+}
+
+const onFinalResult = () => {
+  const addStatus = systemStatus.value === 0 ? 1 : 0;
+
+  controlApi.putSystemStatus({ addStatus });
+
+  systemStatus.value = addStatus;
+
+  message.warning(addStatus === 0 ? '当前投药状态:已停用' : '当前投药状态:投放中');
+
+}
+
+const onUpdateTab = (index) => {
+  const currentData = dataSourceParams.value[tabKeyEnum[index]];
+  baseSourceParams.value.type = index;
+  if ( !Object.keys(currentData).length ) {
+    isVisibleUpdateInfo.value = false;
+    return;
+  }
+  isVisibleBtn.value = true;
+  handleMedicateAmount();
+}
+
+function getTotalNum() {
+  const {
+    hycXsyOne = 0, hycXsyTwo = 0,
+    qycAdOne = 0, qycAdTwo = 0,
+    qycYxyOne = 0, qycYxyTwo = 0,
+    jsLlOne = 0, jsLlTwo = 0,
+    jsCodOne = 0, jsCodTwo = 0
+  } = dataSourceParams.value[tabActiveKey.value];
+
+  const {
+    htfksd, xzxs, kzxs, slfpxs, zhxs, tydl, jzxs, yymd, sxps
+  } = baseSourceParams.value;
+
+  const rOne1 = (((2*hycXsyOne-htfksd)+((qycAdOne+qycYxyOne)*xzxs-htfksd))*(jzxs-1))*(jsLlOne*slfpxs)/1000;
+  const rOne2 = (rOne1*kzxs-(jsLlOne*slfpxs*jsCodOne*zhxs/1000))/tydl;
+  const rOne3 = rOne2/yymd/1000*sxps
+
+  const rTwo1 = (((2*hycXsyTwo-htfksd)+((qycAdTwo+qycYxyTwo)*xzxs-htfksd))*(jzxs-1))*(jsLlTwo*slfpxs)/1000;
+  const rTwo2 = (rTwo1*kzxs-(jsLlTwo*slfpxs*jsCodTwo*zhxs/1000))/tydl;
+  const rTwo3 = rTwo2/yymd/1000*sxps
+
+  const r1 = Number((rOne3 < 0 || !rOne3) ? 0 : rOne3.toFixed(3)) || 0;
+  const r2 = Number((rTwo3 < 0 || !rTwo3) ? 0 : rTwo3.toFixed(3)) || 0;
+
+  return [ r1, r2, rOne2, rTwo2 ];
+}
+
+const onConfirmUpdate = async () => {
+  await controlApi.postAddRecord({
+    ...dataSourceParams.value[tabKeyEnum[baseSourceParams.value.type]],
+    ...baseSourceParams.value,
+  });
+
+  isVisibleUpdateInfo.value = false;
+
+  message.success("系统加药量,更新成功");
+
+  doseNum.value = updateNum.value;
+}
+
+// 更新投药结果
+const handleMedicateAmount = () => {
+  const type = tabActiveKey.value;
+  const lastNum = unref(updateNum);
+  const tdb = tdbNum.value;
+
+  if ( type === 'worker' ) {
+    const medicineNum = dataSourceParams.value.worker.medicineAmount;
+    if ( medicineNum || medicineNum == 0 ) {
+      updateNum.value = medicineNum;
+      isVisibleUpdateInfo.value = true;
+      baseSourceParams.value.tdb = tdb;
+      message.warning("有新投放方案, 请查看")
+    } else {
+      updateNum.value = null;
+      isVisibleUpdateInfo.value = false;
+    }
+    return;
+  }
+
+  const [r1, r2] = getTotalNum();
+  const maxR = Math.max( r1, r2 );
+
+  if ( type === 'auto' && maxR !== lastNum) {
+    updateNum.value = maxR;
+    isVisibleUpdateInfo.value = true;
+    baseSourceParams.value.tdb = tdb;
+    message.warning("有新的投放方案, 请查看");
+  }
+
+  if ( type === 'onePool' && r1 != lastNum) {
+    updateNum.value = r1;
+    isVisibleUpdateInfo.value = true;
+    baseSourceParams.value.tdb = tdb;
+    message.warning("有新的投放方案, 请查看");
+  }
+
+  if ( type === 'twoPool' && r2 != lastNum ) {
+    updateNum.value = r2;
+    isVisibleUpdateInfo.value = true;
+    baseSourceParams.value.tdb = tdb;
+    message.warning("有新的投放方案, 请查看");
+  }
+
+}
+
+onMounted(async () => {
+  // 获取最后一条记录  getSystemStatus
+  await controlApi.getBaseData().then(({ data }) => {
+    const {
+      numberBeng = 0, type = 0,
+      htfksd, jzxs, xzxs, kzxs, slfpxs, tydl, zhxs, sxps, yymd, zxqdll,
+      medicineAmount,
+      addType,
+      tytjTransientLL
+    } = data;
+ 
+    baseSourceParams.value = { 
+      ...baseSourceParams.value,
+      numberBeng, type,
+      htfksd, jzxs, xzxs, kzxs, slfpxs, tydl, zhxs, sxps, yymd, zxqdll,
+      addType
+    };
+    
+    updateNum.value = medicineAmount;
+
+    doseNum.value = medicineAmount;
+
+    flowNum.value = tytjTransientLL;
+
+    dataSourceParams.value[tabActiveKey.value] = data;
+
+  })
+
+ 
+  // 获取实时数据
+  controlApi.getNumValue().then(({ data }) => {
+
+    Object.entries(data).forEach(([key, val]) => {
+      data[key] = val;
+    });
+
+    // water实时数据
+    waterConfigParams.value = data;
+
+    // 重新计算碳氮比
+    const tdb = tdbNum.value;
+    baseSourceParams.value.tdb = tdb;
+ 
+    columnData.value = columnData.value.map(item => {
+      item.value = item.key === 'tdb' ? tdb : dataSourceParams.value[tabActiveKey.value][item.key];
+      return item;
+    })
+
+    const params = {
+      jsLlType: 1,
+      jsLlOne: data.jslYB,
+      jsLlTwo: data.jslYB,
+      jsCodType: 1,
+      jsCodOne: data.jsCodYB,
+      jsCodTwo: data.jsCodYB,
+      hycXsyType: 1,
+      hycXsyOne: data.hyXsyHYOne,
+      hycXsyTwo: data.hyXsyHYTwo,
+      qycYxyType: 1,
+      qycYxyOne: data.qyXsyHYOne,
+      qycYxyTwo: data.qyXsyHYTwo,
+      qycAdType: 1,
+      qycAdOne: data.qyAdHYOne,
+      qycAdTwo: data.qyAdHYTwo,
+      jsTnType: 1,
+      jsTnOne: data.jsTnYB,
+      jsTnTwo: data.jsTnYB
+    }
+
+    Object.keys(dataSourceParams.value).forEach(key => {
+      const item = dataSourceParams.value[key];
+      if ( !Object.keys(item).length ) {
+        dataSourceParams.value[key] = { ...params };
+      }
+    })
+  })
+
+  // 获取是否允许投药开关
+  controlApi.getSystemStatus().then(({ data }) => {
+    // 0不允许  1允许
+    systemStatus.value = data;
+  });
+})
+
+</script>
+
+<template>
+  <section class="flex items-start h-full">
+    <TheChatView leftTitle="智适应碳源投加" :isChatSlot="false" :isFooter="false">
+      <template #control>
+        <div class="control-container space-y-[16px]">
+          <div class="arg-section">
+            <BaseTitle title="智能投加计算"></BaseTitle>
+            <div class="content">
+              <div class="left-paramter"></div>
+            </div>
+          </div>
+          <div class="echart-section"></div>
+        </div>
+      </template>
+    </TheChatView>
+  </section>
+</template>
+
+<style lang="scss" scoped>
+.control-container {
+  // @include flex(x, start, start);
+  height: 100%;
+
+  .arg-section {
+    height: 57%;
+    padding: 16px 14px;
+    border: 1px solid #fff;
+    border-radius: 10px;
+    background: url(@/assets/images/control/bg-top.png) left center no-repeat;
+    background-size: 878px 100% ;
+    display: flex;
+    flex-flow: column;
+
+    .content {
+      height: 100%;
+      padding-top: 16px;
+      .left-paramter {
+        width: 338px;
+        height: 100%;
+        border: 1px solid #fff;
+        border-radius: 10px;
+        background: rgba(255, 255, 255, 0.20);
+        backdrop-filter: blur(5px);
+      }
+    }
+  }
+
+  .echart-section {
+    height: 43%;
+    background: red;
+  }
+
+  .left-section {
+    display: flex;
+    flex-flow: column;
+    flex-shrink: 0;
+    width: 440px;
+    height: 100%;
+    border-radius: 10px;
+    background: #fff;
+
+    .status-bar {
+      display: inline-block;
+      padding: 4px 14px;
+      margin-left: 20px;
+      border-top: 0.5px solid rgba(212, 241, 255, 0.00);
+      border-bottom: 0.5px solid rgba(212, 241, 255, 0.00);
+      background: linear-gradient(90deg, rgba(240, 250, 255, 0.00) 0%, #E9F8FF 27.27%, rgba(240, 250, 255, 0.00) 100%);
+
+      i {
+        line-height: 24px;
+        background: linear-gradient(92deg, #5ABBF2 12.24%, #2454FF 63.2%);
+        background-clip: text;
+        -webkit-background-clip: text;
+        -webkit-text-fill-color: transparent;
+        font-weight: bold;
+      }
+    }
+
+    .scrollbar {
+      height: 100%;
+    }
+
+    .form-content {
+      padding: 0 16px 24px 16px;
+    }
+
+    .panel-header_main {
+      @include flex(x, center, between);
+      margin-bottom: 12px;
+      color: #86909C;
+      span {
+        display: inline-block;
+        width: 60px;
+      }
+    }
+
+  }
+
+  .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: 12px;
+        color: #333;
+      }
+    }
+  }
+}
+
+.right-section {
+  width: 100%;
+  height: 100%;
+  border-radius: 8px;
+  background: #fff;
+  overflow: hidden;
+
+  // .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>
+
+<style lang="scss">
+.custom-tab_item {
+  @include flex (x, center, center);
+  height: 35px;
+  border-radius: 4px;
+  background: #F3F5FA;
+
+  &.n-tabs-tab--active {
+    transition: none !important;
+    border-radius: 4px;
+    transition: none !important;
+    background: url('https://static.fuxicarbon.com/bigModel/pc/tab-border-item-2x.png') -3px 0px no-repeat, linear-gradient(180deg, #F1F3FE 0%, #FFF 100%);
+    background-size: 107% 100%;
+  }
+}
+
+.control-container .left-section {
+  .n-tabs-nav-scroll-content {
+    padding-bottom: 10px;
+  }
+}
+</style>

+ 73 - 0
src/views/control-Old/components/BaseButton.vue

@@ -0,0 +1,73 @@
+<script setup>
+defineProps({
+  type: {
+    type: String,
+    default: 'default'
+  },
+  isActive: {
+    type: Boolean,
+    default: false
+  }
+})
+
+const emit = defineEmits(['on-click']);
+
+const emitClickEvent = () => emit('on-click');
+
+</script>
+
+<template>
+  <button
+    :class="[
+      'custom-button',
+      'button-type_' + type, 
+      {'type_active': isActive}
+    ]"
+    @click="emitClickEvent"
+  >
+    <slot></slot>
+  </button>
+</template>
+
+<style lang="scss" scoped>
+.custom-button {
+  width: 80px;
+  height: 32px;
+  border-radius: 4px;
+  border: 1px solid #D3D7DD;
+  text-align: center;
+  font-size: 14px;
+  line-height: 32px;
+  color: #1A2029;
+}
+
+.button-type_default {
+  background: #fff;
+}
+
+.button-type_gradual {
+  border: 0;
+  background: var(--Linear, linear-gradient(270deg, #3BD6E3 0%, #019AFE 100%));
+  font-weight: bold;
+  color: #fff;
+}
+
+.button-type_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;
+
+  @at-root .type_active {
+    color: #2454FF;
+    border: 1px solid #2454FF;
+    background: #EBF0FF;
+  }
+}
+</style>

+ 56 - 0
src/views/control-Old/components/BaseCard.vue

@@ -0,0 +1,56 @@
+<script setup>
+import { NTooltip } from 'naive-ui';
+import { SvgIcon } from '@/components';
+defineProps({
+  title: {
+    type: String,
+    default: ""
+  },
+  tips: {
+    type: String,
+    default: ""
+  }
+})
+</script>
+
+<template>
+  <div class="base-card_view">
+    <div class="title-wrapper">
+      <h4 class="title space-x-4">
+        <span>{{ title }}</span>
+        <template v-if="tips">
+          <n-tooltip placement="bottom" trigger="hover">
+            <template #trigger>
+              <SvgIcon name="control-icon-tips"></SvgIcon>
+            </template>
+            <span>{{ tips }}</span>
+          </n-tooltip>
+        </template>
+      </h4>
+      <slot name="titleRight"></slot>
+    </div>
+    <slot />
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.base-card_view {
+  margin-bottom: 24px;
+
+  .title-wrapper {
+    @include flex(x, center, between);
+    margin-bottom: 16px;
+
+    .title {
+      @include flex(x, center, start);
+      height: 30px;
+      line-height: 30px;
+      border-radius: 4px;
+      font-size: 14px;
+      font-weight: bold;
+      color: #1A2029;
+    }
+  }
+
+}
+</style>

+ 163 - 0
src/views/control-Old/components/BaseChooseItem.vue

@@ -0,0 +1,163 @@
+<script setup>
+import { ref, computed, watch, watchEffect } from 'vue';
+import { useMessage } from 'naive-ui';
+
+import BaseButton from './BaseButton.vue';
+import BaseInput from './BaseInput.vue';
+
+const message = useMessage();
+
+const activeIndex = ref(-1);
+const inpVal = ref();
+const modelValue = defineModel();
+
+const modelType = defineModel('type');
+const modelValue1 = defineModel('value1');
+const modelValue2 = defineModel('value2');
+
+const emit = defineEmits(['on-update']);
+
+const props = defineProps({
+  title: {
+    type: String,
+    default: ''
+  },
+  btnGroup: {
+    type: Array,
+    default: false
+  },
+  unit: {
+    type: String,
+    default: ''
+  },
+  isDouble: {
+    type: Boolean,
+    default: false
+  },
+  tabKey: {
+    type: String,
+    requured: true
+  }
+})
+
+watchEffect(() => {
+  if ( modelType.value === 0 ) {
+    if ( props.tabKey == 'auto' ) {
+      inpVal.value = modelValue1.value;
+    }
+    if ( props.tabKey == 'onePool' ) {
+      inpVal.value = modelValue1.value;
+    }
+    if ( props.tabKey == 'twoPool' ) {
+      inpVal.value = modelValue1.value;
+    }
+  }
+})
+
+const onePoolNum = computed(() => (modelValue1.value && modelValue1.value !=0 ) ?  Number((modelValue1.value || 0).toFixed(2)) : '--');
+const twoPoolNum = computed(() => (modelValue2.value && modelValue2.value !=0 ) ?  Number((modelValue2.value || 0).toFixed(2)) : '--');
+
+const onInpCancel = (val) => {
+  inpVal.value = val;
+}
+
+const onInpConfirm = (num) => {
+  if (num === Infinity || num === -Infinity) {
+    modelValue.value = null
+    return message.warning(`${props.title}的数值填写有误, 请检查`);
+  }
+  modelValue.value = num;
+}
+
+const onInput = (val) => {
+  modelValue1.value = val;
+  modelValue2.value = val;
+}
+
+const onEmitEvent = () => {
+  if ( activeIndex.value === 0 ) {
+    if ( inpVal.value ) {
+      emit('on-update');
+    }
+  } else {
+    emit('on-update');
+  }
+}
+
+const changeActive = (item, index) => {
+  activeIndex.value = index;
+  modelType.value = index;
+  modelValue1.value = index != 0 ? item.value1 : inpVal.value;
+  modelValue2.value = index != 0 ? item.value2 : inpVal.value;
+  onEmitEvent();
+}
+
+</script>
+
+<template>
+  <div class="base-chooseItem_view">
+    <span class="label-inner">{{ title }}:</span>
+    <div class="choose-inner">
+      <div class="top-box">
+        <ul class="btn-group space-x-[4px]">
+          <BaseButton
+            v-for="item, index in btnGroup"
+            type="info"
+            :key="index"
+            :isActive="modelType === index || btnGroup.length === 1"
+            @click="changeActive(item, index)"
+          >
+            {{ item.label }}
+          </BaseButton>
+        </ul>
+        <ul class="num-group flex space-x-[20px] text-center">
+          <li class="w-[60px]">{{ onePoolNum }}</li>
+          <li class="w-[60px]" v-if="isDouble">{{ twoPoolNum }}</li>
+        </ul>
+      </div>
+
+      <BaseInput
+        v-show="(modelType !== undefined && !modelType) || btnGroup.length === 1"
+        default-value=""
+        :placeholder="'请输入' + props.title"
+        :unit="unit"
+        v-model="inpVal"
+        @click:confirm="onInpConfirm"
+        @click:cancel="onInpCancel"
+        @on-input="onInput"
+        @on-blur="onEmitEvent"
+      ></BaseInput>
+    </div>
+  </div>
+</template>
+
+<style lang="scss">
+.base-chooseItem_view {
+  @include flex(x, start, start);
+
+  .label-inner {
+    width: 160px;
+    flex-shrink: 1;
+    line-height: 28px;
+  }
+
+  .choose-inner {
+    width: 100%;
+
+    .top-box {
+      @include flex(x, center, between);
+
+      .btn-group {
+        @include flex(x, center, center);
+      }
+
+      .num-group {
+        font-family: "D-DIN-PRO-700-Bold";
+        font-weight: bold;
+        font-size: 12px;
+        color: #333;
+      }
+    }
+  }
+}
+</style>

+ 202 - 0
src/views/control-Old/components/BaseInput.vue

@@ -0,0 +1,202 @@
+<script setup>
+import { ref, computed } from 'vue';
+import { NInputNumber } from 'naive-ui';
+
+const props = defineProps({
+  placeholder: {
+    type: String,
+    default: () => ""
+  },
+  size: {
+    type: String,
+    default: ''
+  },
+  type: {
+    type: String,
+    default: 'default'
+  },
+  isActive: {
+    type: Boolean,
+    default: false
+  },
+  unit: {
+    type: String,
+    default: ''
+  },
+  isNeedFlotBtn: {
+    type: Boolean,
+    default: true
+  },
+  isCenter: {
+    type: Boolean,
+    default: false
+  },
+  isCloseIcon: {
+    type: Boolean,
+    default: true
+  },
+  readonly: {
+    type: Boolean,
+    default: false
+  }
+})
+
+const isFocusStatus = ref(false);
+
+const emit = defineEmits(['click:confirm', 'on-input', 'on-blur', 'click:cancel']);
+const modelValue = defineModel();
+
+const domClassName = computed(() => {
+  return [
+    'input_wrapper',
+    {'input_text_center': props.isCenter },
+    'input-' + props.type + "_" + props.size,
+    'inpit_' + props.size
+  ]
+})
+
+const onFocus = () => {
+  isFocusStatus.value = true;
+}
+
+const onBlur = (ev) => {
+  isFocusStatus.value = false;
+  emit('on-blur');
+}
+
+const onInput = (value) => {
+  emit('on-input', value);
+  modelValue.value = value;
+}
+
+const handleInpValue = (event, type) => {
+  if (type === 'confirm') {
+    emit('click:confirm', modelValue.value);
+  }
+  if (type === 'cancel') {
+    event.preventDefault();
+    modelValue.value = null;
+    emit('click:cancel', null);
+  }
+}
+</script>
+
+<template>
+  <div :class="[domClassName, 'base-input-wrapper']">
+    <NInputNumber
+      size="small"
+      round
+      style="width: 100%;"
+      :readonly="readonly"
+      :precision="2"
+      :max="99999.99"
+      :min="0"
+      :placeholder="placeholder"
+      :show-button="false"
+      :on-update:value="onInput"
+      :on-blur="onBlur"
+      :on-focus="onFocus"
+      :value="modelValue"
+    >
+      <template #suffix>
+        <div class="unit" v-if="unit">{{ unit }}</div>
+      </template>
+    </NInputNumber>
+    <ul class="inp-flot_group space-x-[4px]" v-show="isFocusStatus && isNeedFlotBtn">
+      <!-- <li>
+        <SvgIcon name="control-icon-confirm" size="16" @mousedown="handleInpValue($event, 'confirm')"></SvgIcon>
+      </li> -->
+      <!-- <li v-if="isCloseIcon">
+        <SvgIcon name="control-icon-cancel" size="16" @mousedown="handleInpValue($event, 'cancel')"></SvgIcon>
+      </li> -->
+    </ul>
+  </div>
+</template>
+
+
+<style lang="scss" scoped>
+.input_wrapper {
+  @include flex(x, center, between);
+  position: relative;
+  margin-top: 4px;
+
+  .inp {
+    width: 100%;
+    height: 28px;
+    padding: 0px 56px 0 10px;
+    border-radius: 4px 0px 0px 4px;
+    border: 1px solid #E6EAEE;
+    background: #fff;
+    outline: none;
+    font-size: 12px;
+
+    &:focus {
+      border: 1px solid #2454FF;
+    }
+  }
+
+  .unit {
+    flex-shrink: 1;
+    width: 60px;
+    height: 28px;
+    border-radius: 0px 4px 4px 0px;
+    border: 1px solid #E6EAEE;
+    border-left: 0;
+    background: #F0F2F5;
+    text-align: center;
+    line-height: 28px;
+    font-size: 12px;
+    font-weight: bold;
+    color: #333;
+  }
+
+  .inp-flot_group {
+    @include flex(x, center, center);
+    position: absolute;
+    right: 66px;
+    top: 50%;
+    transform: translateY(-50%);
+
+    li {
+      width: 16px;
+      height: 16px;
+      border-radius: 100%;
+      color: #DFE2E6;
+      cursor: pointer;
+
+      svg,
+      svg path {
+        fill: #e0e2e6;
+        stroke: #e0e2e6;
+      }
+
+      &:hover svg {
+        fill: #b3c4e3;
+        stroke: #b3c4e3;
+      }
+    }
+  }
+}
+</style>
+
+<style lang="scss">
+.base-input-wrapper {
+  .n-input-wrapper {
+    padding-right: 0px;
+    border: 1px solid #E6EAEE;
+    border-radius: 4px;
+    .n-input__input-el, .n-input__placeholder {
+      font-size: 12px;
+    }
+  }
+}
+
+.input_text_center {
+  .n-input-wrapper {
+    .n-input__input-el {
+      padding-right: 10px;
+      text-align: center;
+    }
+  }
+}
+</style>

+ 72 - 0
src/views/control-Old/components/BaseRadioCard.vue

@@ -0,0 +1,72 @@
+<script setup>
+import { ref } from 'vue';
+import { SvgIcon } from '@/components';
+
+const modelValue = defineModel();
+
+const defaultData = [
+  { label: '1号加药泵', key: 'first' },
+  { label: '2号加药泵', key: 'second' },
+  { label: '3号加药泵', key: 'third' },
+]
+
+const chageActive = (index) => modelValue.value = index;
+</script>
+
+<template>
+  <ul class="radio-card_group space-x-[10px]">
+    <li :class="['radio-card_item', { 'card_item_active': index === modelValue }]" v-for="item, index in defaultData"
+      :key="item.key" @click="chageActive(index)">
+      <div class="radio-wrapper">
+        <SvgIcon :name="index === modelValue ? 'control-icon-pump-active' : 'control-icon-pump'" size="16" fillColor="#2454FF" />
+        <span class="radio radio-active"></span>
+      </div>
+      <p class="text">{{ item.label }}</p>
+    </li>
+  </ul>
+</template>
+
+<style lang="scss" scoped>
+.radio-card_group {
+  @include flex(x, center, between);
+  font-size: 11px;
+  font-weight: bold;
+  line-height: 14px;
+  color: #333;
+
+  .radio-card_item {
+    @include flex(y, start, between);
+    width: 120px;
+    height: 48px;
+    padding: 6px;
+    border-radius: 4px;
+    border: 1px solid #E6EAEE;
+    transition: all .3s;
+    cursor: pointer;
+
+    .radio-wrapper {
+      @include flex(x, center, between);
+      width: 100%;
+    }
+  }
+
+  .card_item_active {
+    width: 150px;
+    border: 1px solid rgba(36, 84, 255, 0.80);
+
+    .radio {
+      transition: all .1s;
+      border: 3px solid #2454FF;
+    }
+  }
+
+  .radio {
+    display: block;
+    width: 12px;
+    height: 12px;
+    border-radius: 100%;
+    border: 1px solid #ccc;
+    cursor: pointer;
+  }
+}
+</style>

+ 67 - 0
src/views/control-Old/components/BaseRadioGroup.vue

@@ -0,0 +1,67 @@
+<script setup>
+import { ref } from 'vue';
+
+const props = defineProps({
+  data: {
+    type: Array,
+    default: () => []
+  }
+})
+
+const modelValue = defineModel();
+
+const changeActive = (index) => {
+  modelValue.value = index;
+}
+
+</script>
+
+<template>
+  <ul class="radio-list_group space-x-[24px]">
+    <li class="radio_item space-x-[8px]" v-for="item,index in data" :key="index" @click="changeActive(index)">
+      <span
+        :class="[
+          'radio',
+          'radio_big',
+          {'radio-active': modelValue === index}
+        ]"
+        
+      ></span>
+      <span class="label">{{ item }}</span>
+    </li>
+  </ul>
+</template>
+
+<style lang="scss" scoped>
+.radio-list_group {
+  @include flex(x, center, start);
+  padding-left: 20px;
+
+  .radio_item {
+    @include flex(x, center, center);
+
+    .radio {
+      display: block;
+      width: 12px;
+      height: 12px;
+      border-radius: 100%;
+      border: 1px solid #ccc;
+      cursor: pointer;
+    }
+
+    .radio_big {
+      width: 16px;
+      height: 16px;
+    }
+
+    .radio_big.radio-active {
+      border: 4px solid #2454FF;
+    }
+
+    .label {
+      min-width: 40px;
+      cursor: pointer;
+    }
+  }
+}
+</style>

+ 62 - 0
src/views/control-Old/components/BaseTitle.vue

@@ -0,0 +1,62 @@
+<script setup>
+
+defineProps({
+  title: {
+    type: String,
+    default: ''
+  },
+  type: {
+    type: String,
+    default: 'first'
+  }
+})
+
+</script>
+
+<template>
+  <div class="header">
+    <div class="title">
+      <svg xmlns="http://www.w3.org/2000/svg" width="8" height="24" viewBox="0 0 8 24" fill="none"
+        v-if="type === 'first'">
+        <path d="M0 6.86197V3.24507L4.21274 0H7.11111L4.45741 24H1.35684L4.01053 3.85352L0 6.86197Z" fill="#2454FF" />
+      </svg>
+      <svg xmlns="http://www.w3.org/2000/svg" width="12" height="24" viewBox="0 0 12 24" fill="none" v-else>
+        <path
+          d="M7.74366 10.4333C8.43696 9.03333 8.78361 7.76667 8.78361 6.6V6.1C8.78361 5.06667 8.58552 4.26667 8.16459 3.7C7.74366 3.13333 7.19892 2.83333 6.48086 2.83333C5.7628 2.83333 5.21807 3.1 4.8219 3.66667C4.42573 4.23333 4.22764 5.1 4.22764 6.23333V7.16667H1.94966V6.1C1.94966 4.26667 2.37059 2.8 3.18769 1.66667C4.02956 0.566667 5.14379 0 6.53039 0C7.42177 0 8.23887 0.266667 8.93217 0.8C9.62547 1.3 10.1702 2.03333 10.5416 2.96667C10.9378 3.9 11.1111 4.93333 11.1111 6.03333V6.6C11.1111 7.6 10.9873 8.5 10.7149 9.4C10.4673 10.2667 10.0959 11.1667 9.57595 12.1L2.94652 21.1667H9.16145V24H0V21.6L7.74366 10.4333Z"
+          fill="#2454FF" />
+      </svg>
+      <span class="text">{{ title }}</span>
+    </div>
+    <div class="btn-group space-x-[8px]">
+      <slot name="right" />
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.header {
+  @include flex(x, center, between);
+  color: #1A2029;
+
+  .title {
+    display: flex;
+    align-items: center;
+    height: 24px;
+
+    .text {
+      height: 100%;
+      padding-left: 13px;
+      margin-left: -6px;
+      background: linear-gradient(90deg, rgba(36, 84, 255, 0.10) -0.94%, rgba(36, 84, 255, 0.00) 95.3%);
+      font-size: 15px;
+      font-weight: bold;
+      line-height: 24px
+    }
+  }
+
+  .btn-group {
+    @include flex(x, center, center);
+  }
+
+}
+</style>

+ 501 - 0
src/views/control-Old/components/TheEchartPanel.vue

@@ -0,0 +1,501 @@
+<script setup>
+import { ref, computed, onMounted, unref, onUnmounted } from 'vue';
+import { NTabs, NTab, NSelect, NDatePicker } from "naive-ui";
+import * as echarts from 'echarts';
+import { startOfDay } from "date-fns/esm"
+import { controlApi } from "@/api/control"
+import dayjs from 'dayjs';
+
+const modelValue = defineModel("height");
+
+let echart = null;
+let tempTabItemOneKey = 0;
+let tempTabItemTwoKey = 'jzxs';
+const datePickerValue = ref(null);
+const dateRangeRef = ref(null);
+const tabs = ref([]);
+const tabActive = ref(null);
+const selectValue = ref(0);
+const coefficientDataSource = ref([]);
+const echartDataSource = ref({});
+const echartRef = ref(null);
+const isEmpty = ref(false);
+const activeIndex = ref(0);
+
+const tabList = ['水质', '系数'];
+
+const selectOptions = ref([]);
+
+const echartOptions = [
+  { label: "进水流量", value: 0, style: "font-size: 12px" },
+  { label: "#1好氧池硝酸盐", value: 1, style: "font-size: 12px" },
+  { label: "#2好氧池硝酸盐", value: 2, style: "font-size: 12px" },
+  { label: "#1缺氧池氨氮", value: 3, style: "font-size: 12px" },
+  { label: "#2缺氧池氨氮", value: 4, style: "font-size: 12px" },
+  { label: "进水COD", value: 5, style: "font-size: 12px" },
+  { label: "进水总氮", value: 6, style: "font-size: 12px" },
+  { label: "碳源投加量", value: 7, style: "font-size: 12px" }
+]
+
+const coefficientOptions = [
+  { label: "基准系数", value: 'jzxs', style: "font-size: 12px" },
+  { label: "修正系数", value: 'xzxs', style: "font-size: 12px" },
+  { label: "水量分配系数", value: 'slfpxs', style: "font-size: 12px" },
+  { label: "碳源当量", value: 'tydl', style: "font-size: 12px" },
+  { label: "转换系数", value: 'zhxs', style: "font-size: 12px" },
+  { label: "稀释倍数", value: 'sxps', style: "font-size: 12px" },
+  { label: "密度", value: 'yymd', style: "font-size: 12px" },
+]
+
+const seriesName = computed(() => {
+  let name = '';
+  if ( activeIndex.value === 0) {
+    name = echartOptions.find(({ value }) => selectValue.value === value).label
+  } else {
+    name = coefficientOptions.find(item => item.value === selectValue.value).label
+  }
+  return name
+})
+
+// 切换tab选项
+const handleSwitchTab = (index) => {
+  if ( activeIndex.value === index ) return;
+  activeIndex.value = index;
+  if ( !index ) {
+    // echart
+    tempTabItemTwoKey = selectValue.value;
+    selectValue.value = tempTabItemOneKey;
+    selectOptions.value = echartOptions;
+    datePickerValue.value = null;
+    initWaterEchartData();
+  } else {
+     // 系数
+    tempTabItemOneKey = selectValue.value;
+    selectValue.value = tempTabItemTwoKey;
+    selectOptions.value = coefficientOptions;
+    datePickerValue.value = null;
+    intiCoefficientEchartData();
+  }
+}
+
+// select option change
+const handleSelectOptions = (val) => {
+  selectValue.value = val;
+
+  activeIndex.value === 0 ? initWaterEchartData() : intiCoefficientEchartData();
+}
+
+const windowResize = () => echart.resize();
+
+const getEchartOptions = (data, type) => {
+  const option = {
+    backgroundColor: '#FFF',
+    title: {
+      show: !data.length,
+      text: '暂无数据',
+      x: 'center',
+      y: 'center',
+      textStyle: {
+        fontSize: 14,
+        fontWeight: 'normal',
+      }
+    },
+    grid: {
+      top: '40px',
+      bottom: '50px',
+      left: '6%',
+      right: '6%',
+    },
+    tooltip: {
+      trigger: 'axis',
+      label: {
+        show: true
+      },
+    },
+    xAxis: {
+      boundaryGap: false,
+      axisLine: {
+        show: false
+      },
+      splitLine: {
+        show: false
+      },
+      axisTick: {
+        show: false,
+        alignWithLabel: true
+      },
+      axisLabel: {
+        formatter: function (value) {
+          return type ? dayjs(value).format('YYYY/MM/DD') : value
+        }
+      },
+      data: data.map(({ time }) => time)
+    },
+    yAxis: {
+      axisLine: {
+        show: false
+      },
+      splitLine: {
+        show: true,
+        lineStyle: {
+          type: 'dashed',
+          color: '#E5E5E5'
+        }
+      },
+      axisTick: {
+        show: false
+      },
+      splitArea: {
+        show: false,
+        color: '#fff'
+      }
+    },
+    series: [
+      {
+        name: seriesName.value,
+        showSymbol: false,
+        smooth: true,
+        type: 'line',
+        symbolSize: 10,
+        lineStyle: {
+          color: '#17a6fa',
+          shadowBlur: 12,
+          shadowColor: 'rgba(0, 0, 0, 0.12)',
+          shadowOffsetX: 0,
+          shadowOffsetY: 4,
+          width: 2,
+        },
+        itemStyle: {
+          color: '#4080FF',
+          borderWidth: 3,
+          borderColor: '#4080FF'
+        },
+        areaStyle: {
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
+            offset: 0,
+            color: 'rgba(0, 136, 212, 0.2)'
+          }, {
+            offset: 1,
+            color: 'rgba(0, 136, 212, 0)'
+          }], false),
+        },
+        data: data.map(({ val }) => val)
+      }
+    ]
+  };
+  return option;
+}
+
+const onSwitchEchart = (item) => {
+  const echartData = echartDataSource.value[item.value];
+  isEmpty.value = !!echartData.length
+  echart.setOption(getEchartOptions(echartData));
+}
+
+// 水务相关数据格式化
+const initWaterEchartData = async () => {
+  const [tBegin, tEnd] = datePickerValue.value || [];
+
+  const timeBegin = tBegin ? dayjs(tBegin).format('YYYY/MM/DD') : null;
+  const timeEnd = tEnd ? dayjs(tEnd).format('YYYY/MM/DD') : null;
+  const { data: echartData } = await controlApi.getEchartData(unref(selectValue), { timeBegin, timeEnd });
+
+  const enumSource = {
+    YB: '在线仪表',
+    HY: '连续检测',
+    YC: '预测'
+  };
+
+  tabs.value = Object.keys(echartData).map((key, index) => {
+    if (index === 0) {
+      tabActive.value = key + '-' + selectValue.value + '-' + index;
+    }
+    if (echartData[key].length) {
+      return ({ label: enumSource[key], value: key });
+    }
+  }).filter(Boolean);
+
+  echartDataSource.value = echartData;
+
+  onSwitchEchart({ value: tabActive.value.substring(0, tabActive.value.indexOf('-')) });
+}
+
+// 系数相关数据
+const intiCoefficientEchartData = async () => {
+  const [timeBegin, timeEnd] = datePickerValue.value || [];
+  const { data } = await controlApi.getEchartList({ timeBegin, timeEnd });
+  coefficientDataSource.value = data;
+  
+  const d = data.map(item => ({
+    time: dayjs(item.createTime).format('YYYY/MM/DD HH'),
+    val: item[selectValue.value]
+  }));
+
+  echart.setOption(getEchartOptions(d));
+}
+
+// 日期范围限制
+const isRangeDateDisabled = (ts, type, range) => {
+  const d = 864e5;
+  if (type === "start" && range !== null) {
+    return startOfDay(range[1]).valueOf() - startOfDay(ts).valueOf() >= d * 10;
+  }
+  if (type === "end" && range !== null) {
+    return startOfDay(ts).valueOf() - startOfDay(range[0]).valueOf() >= d * 10;
+  }
+  return false;
+}
+
+const onDatePickerConfirm = (ts) => {
+  datePickerValue.value = ts.map(t => dayjs(t).format('YYYY-MM-DD'));
+  activeIndex.value === 0 ? initWaterEchartData() : intiCoefficientEchartData();
+}
+
+const onDatePickerClear = () => {
+  datePickerValue.value = null;
+  activeIndex.value === 0 ? initWaterEchartData() : intiCoefficientEchartData();
+}
+
+onMounted(async () => {
+  selectOptions.value = echartOptions;
+
+  echart = echarts.init(echartRef.value, 'light');
+
+  await initWaterEchartData();
+
+  window.addEventListener("resize", windowResize);
+
+})
+
+onUnmounted(() => {
+  window.removeEventListener("resize", windowResize);
+  echart && echart.dispose();
+})
+
+</script>
+
+<template>
+  <div class="echart-card_view">
+    <div class="title">
+      <div class="left-inner">
+        <span class="text">数据看板</span>
+      </div>
+      <div class="right-inner">
+        <ul class="custom-radio-group">
+          <li :class="{ active: activeIndex === index }" v-for="item, index in tabList" :key="item"
+            @click="handleSwitchTab(index)">{{ item }}</li>
+        </ul>
+      </div>
+    </div>
+
+    <div class="select-wrapper">
+      <div>
+        <n-tabs
+          animated
+          type="segment"
+          size="small"
+          class="tabs"
+          style="width: 200px;"
+          v-model:value="tabActive"
+          v-show="activeIndex === 0"
+        >
+          <n-tab
+            v-for="item, index in tabs"
+            :key="item.value"
+            :name="item.value + '-' + selectValue + '-' + index"
+            @click="onSwitchEchart(item)"
+          >{{ item.label }}</n-tab>
+        </n-tabs>
+      </div>
+      <div class="flex space-x-[10px]">
+        <NDatePicker
+          clearable
+          class="w-[300px]"
+          size="small"
+          type="daterange"
+          ref="dateRangeRef"
+          :is-date-disabled="isRangeDateDisabled"
+          :on-confirm="onDatePickerConfirm"
+          :on-clear="onDatePickerClear"
+          v-model:formatted-value="datePickerValue"
+        ></NDatePicker>
+        <!-- v-model:formatted-value="datePickerValue" -->
+        <!--  -->
+        <!-- v-model:value="selectValue" -->
+        <NSelect
+          class="w-[150px]"
+          :options="selectOptions"
+          :value="selectValue"
+          :on-update:value="handleSelectOptions"
+          size="small" />
+      </div>
+    </div>
+
+    <div class="echart-wrapper">
+      <div class="echart" ref="echartRef"></div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.echart-card_view {
+  display: flex;
+  flex-flow: column;
+  height: calc(100% - 256px);
+  padding: 0px 16px 0 25px;
+  border-radius: 10px;
+
+  .title {
+    flex-shrink: 0;
+    @include flex(x, center, between);
+    padding-bottom: 16px;
+
+    .left-inner {
+      @include flex(x, center, start);
+
+      .text {
+        color: #1A2029;
+        font-size: 15px;
+        font-style: normal;
+        font-weight: 500;
+        line-height: 24px;
+      }
+
+      .tabs {
+        width: 240px;
+        margin-left: 16px;
+      }
+    }
+
+    .right-inner {
+      @include flex(x, center, start);
+
+      .custom-radio-group {
+        @include flex(x, center, center);
+        width: 104px;
+        height: 24px;
+        border-radius: 4px;
+        border: 1px solid #D3D7DD;
+
+        li {
+          width: 50%;
+          font-size: 12px;
+          text-align: center;
+          line-height: 24px;
+          color: #333;
+          cursor: pointer;
+
+          &:nth-child(1) {
+            border-right: 1px solid #D3D7DD;
+          }
+        }
+
+        li.active {
+          color: #2454FF;
+        }
+      }
+    }
+  }
+
+  .select-wrapper {
+    @include flex(x, center, between);
+    height: 32px;
+  }
+
+  .echart-wrapper {
+    height: calc(100% - 72px);
+
+    .echart,
+    .empty {
+      width: 100%;
+      height: 100%;
+    }
+
+    .empty {
+      @include flex(x, center, center);
+    }
+  }
+}
+</style>
+
+<style lang="scss">
+.echart-card_view {
+  .tabs {
+    .n-tabs-tab--active {
+      .n-tabs-tab__label {
+        color: #2454FF;
+      }
+    }
+
+    .n-tabs-tab__label {
+      font-size: 12px;
+      color: #333333;
+    }
+  }
+
+  .n-base-selection .n-base-selection-label .n-base-selection-input {
+    font-size: 12px;
+    color: #333333 !important;
+  }
+
+  .right-inner {
+    .n-base-selection__border {
+      border: 0;
+    }
+
+    .n-base-selection-label {
+      border: 0;
+      border-radius: 0;
+      background: #F2F3F5 !important;
+    }
+
+    .n-base-selection__state-border,
+    .n-base-selection__border {
+      border: 0 !important;
+    }
+
+    .n-base-selection .n-base-selection__border,
+    .n-base-selection .n-base-selection__state-border {
+      box-shadow: none;
+    }
+
+    .n-base-suffix__arrow {
+      color: #4E5969;
+    }
+  }
+
+  .n-input--pair {
+    background: #f0f1f3 !important;
+  }
+
+  .n-base-selection-input__content {
+    font-size: 12px;
+  }
+
+  .n-base-selection {
+    background: #f0f1f3 !important;
+  }
+
+  .n-base-selection-label {
+    background: #f0f1f3;
+    border-radius: 3px;
+  }
+
+  .n-base-selection__border,
+  .n-base-selection__state-border {
+    display: none !important;
+  }
+
+  .n-date-picker {
+    .n-input__input-el,
+    .n-input__placeholder {
+      font-size: 12px !important;
+    }
+  }
+
+  .n-base-selection:not(.n-base-selection--disabled).n-base-selection--active .n-base-selection-label {
+    background: #f0f1f3 !important;
+  }
+}
+
+</style>

+ 275 - 0
src/views/control-Old/components/TheResultPanel.vue

@@ -0,0 +1,275 @@
+<script setup>
+import { computed } from 'vue';
+import { useMessage, NNumberAnimation } from 'naive-ui';
+import BaseTitle from './BaseTitle.vue';
+import { SvgIcon } from '@/components';
+
+const message = useMessage();
+const isVisibleBtn = defineModel();
+const modelSystemStatus = defineModel('system');
+const emit = defineEmits(['on-click', 'on-update']);
+
+const props = defineProps({
+  flowNum: {
+    type: Number,
+    default: 0
+  },
+  updateNum: {
+    type: Number,
+    default: 0
+  },
+  doseNum: {
+    type: Number,
+    default: 0
+  },
+  configurationStatus: {
+    type: Number,
+    default: 1
+  }
+});
+
+const systemSwitchType = computed(() => props.configurationStatus === 0 && modelSystemStatus.value === 1);
+
+const emitEvent = () => {
+  if ( props.configurationStatus === 1 ) {
+    return message.warning('当前组态未启用,无法投放');
+  } else {
+    emit('on-click');
+  }
+
+};
+const emitUpdate = async () => {
+  emit('on-update');
+};
+</script>
+
+<template>
+  <div>
+    <BaseTitle title="智能投加计算结果" type="second"></BaseTitle>
+    <div class="result-card_view">
+      <div class="update-message-box">
+        <ul class="update-message space-x-[16px]" v-show="isVisibleBtn">
+          <li class="flex space-x-[4px]">
+            <SvgIcon name="control-icon-warning" size="16"></SvgIcon>
+            <span>有新投放方案,系统加药量计算为:{{ updateNum }}m³/h,是否更新?</span>
+          </li>
+          <li class="space-x-[10px]">
+            <span class="text-[#ed742f] cursor-pointer" @click="emitUpdate">更新投放量</span>
+            <span class="text-[#88909b] cursor-pointer" @click="isVisibleBtn = false">取消</span>
+          </li>
+        </ul>
+      </div>
+      <div class="result-card">
+        <div class="result-inner space-x-[8px]">
+          <div class="result-card_item">
+            <div class="h-full flex flex-col justify-between">
+              <h4>
+                <span>碳源投加瞬时流量</span>
+                <span class="block w-[12px] h-[3px] mt-[4px] bg-[#1D2129]"></span>
+              </h4>
+              <p class="num-group space-x-[4px]">
+                <span class="num">
+                  <NNumberAnimation :from="0" :to="flowNum" :duration="1000" :precision="flowNum < 1 ? 3 : 3"></NNumberAnimation>
+                </span>
+                <span class="text-[12px] text-[#86909C]">m³/h</span>
+              </p>
+            </div>
+          </div>
+          <div class="result-card_item">
+            <div class="h-full flex flex-col justify-between">
+              <h4>
+                <span>系统加药量</span>
+                <span class="block w-[12px] h-[3px] mt-[4px] bg-[#1D2129]"></span>
+              </h4>
+              <p class="num-group space-x-[4px]">
+                <span class="num">
+                  <NNumberAnimation :from="0" :to="doseNum" :duration="1000" :precision="3"></NNumberAnimation>
+                </span>
+                <span class="text-[12px] text-[#86909C]">m³/h</span>
+              </p>
+            </div>
+          </div>
+        </div>
+        <div class="btn-card">
+          <div :class="['round-btn', {disable: configurationStatus === 1}]" @click="emitEvent">
+            <div class="circle1" v-show="systemSwitchType"></div>
+            <div class="circle2" v-show="systemSwitchType"></div>
+            <div class="circle3" v-show="systemSwitchType"></div>
+            <div class="inner space-y-[4px]">
+              <SvgIcon name="control-icon-result-btn" size="24" />
+              <span>{{ systemSwitchType ? "投放中" : "未启用" }}</span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+
+.result-card_view {
+  position: relative;
+  height: 190px;
+  padding: 0px 16px 24px 16px;
+
+  .update-message-box {
+    height: 37px;
+  }
+
+  .update-message {
+    display: flex;
+    align-items: center;
+    width: 100%;
+    height: 100%;
+    padding-left: 16px;
+    padding-bottom: 7px;
+    flex-shrink: 0;
+    border-radius: 8px 8px 0px 0px;
+    border: 1px solid #FFE9CE;
+    background: #FFF5E5;
+    font-size: 12px;
+    color: #7E604F;
+  }
+
+  .result-card {
+    @include flex(x, center, between);
+    padding: 16px 35px 16px 16px;
+    margin-top: -9px;
+    border: 1px solid #fff;
+    border-radius: 8px;
+    background: url('@/assets/images/control/bg-control-top.png') center right no-repeat, linear-gradient(90deg, #E0E8FC 0%, #F2F4FF 100%);
+    background-size: auto 100%, auto;
+    background-position: 50% 10%;
+
+    .result-inner {
+      border-radius: 8px;
+      @include flex(x, center, start);
+
+      .result-card_item {
+        width: 254px;
+        height: 104px;
+        padding: 20px 0 20px 20px;
+        border-radius: inherit;
+        border: 1px solid #FFF;
+        background: #fff;
+        background: linear-gradient(90deg, #FFF 50%, rgba(255, 255, 255, 0.50) 100%);
+        backdrop-filter: blur(2px);
+
+        .num {
+          color: #1A2029;
+          font-family: D-DIN-PRO-700-Bold;
+          font-size: 24px;
+          font-weight: bold;
+          line-height: 0;
+        }
+      }
+    }
+
+    & .result-card_item:nth-child(2) {
+      border: 1px solid #FFF;
+      background: linear-gradient(90deg, #FFF 50%, rgba(255, 255, 255, 0.50) 100%);
+      backdrop-filter: blur(2px);
+    }
+  }
+
+  .round-btn {
+    position: relative;
+    @include flex(x, center, center);
+    width: 88px;
+    height: 88px;
+    border: 2px solid #E6EFFE;
+    border-radius: 50%;
+    background: #898EFE;
+    font-size: 10px;
+    font-weight: bold;
+    color: #fff;
+    cursor: pointer;
+    transition: all 0.5s;
+
+    .inner {
+      position: relative;
+      @include flex(x, center, center);
+      flex-flow: column;
+      width: 74px;
+      height: 74px;
+      padding: 14px;
+      border-radius: 100%;
+      background: #2454FF;
+      transition: all 0.3s;
+    }
+  }
+
+  .disable {
+    cursor: not-allowed;
+  }
+
+  // .active {
+  //   transition: all 0.5s;
+  //   background: #898EFE;
+
+  //   .inner {
+  //     background: #2454FF;
+  //   }
+  // }
+
+  .circle1,
+  .circle2,
+  .circle3 {
+    position: absolute;
+    width: 40px;
+    height: 40px;
+    background: rgba(137, 142, 254, 1);
+    border: 1px solid rgba(137, 142, 254, 0.85);
+    border-radius: 999px;
+  }
+
+  .circle1,
+  .circle2,
+  .circle3 {
+    animation-name: circleChange;
+    animation-duration: 3s;
+    animation-iteration-count: infinite;
+    animation-timing-function: linear;
+  }
+
+  .circle1 {
+    animation-delay: 0.5s;
+  }
+
+  .circle2 {
+    animation-delay: 1.5s;
+  }
+
+  .circle3 {
+    animation-delay: 2.5s;
+  }
+
+  @keyframes circleChange {
+    0% {
+      transform: scale(2);
+      opacity: 0.95;
+    }
+
+    // 25% {
+    //   transform: scale(1.8);
+    //   opacity: 0.75;
+    // }
+
+    // 50% {
+    //   transform: scale(2);
+    //   opacity: 0.5;
+    // }
+
+    // 75% {
+    //   transform: scale(2.4);
+    //   opacity: 0.25;
+    // }
+
+    100% {
+      transform: scale(3);
+      opacity: 0.05;
+    }
+  }
+}
+</style>

+ 311 - 486
src/views/control/MedicinalView.vue

@@ -11,6 +11,8 @@ import BaseInput from './components/BaseInput.vue';
 import TheResultPanel from './components/TheResultPanel.vue';
 import TheEchartPanel from './components/TheEchartPanel.vue';
 
+import NumberPanel from './NumberPanel.vue';
+
 const message = useMessage();
 const isVisibleBtn = ref(true);
 const isVisibleUpdateInfo = ref(false);
@@ -311,372 +313,113 @@ onMounted(async () => {
     // 0不允许  1允许
     systemStatus.value = data;
   });
+
 })
 
 </script>
 
 <template>
   <section class="flex items-start h-full">
-    <TheChatView leftTitle="智适应投药" :isChatSlot="false" :isFooter="false">
+    <TheChatView leftTitle="智适应碳源投加" :isChatSlot="false" :isFooter="false">
       <template #control>
-        <div class="control-container space-x-[12px]">
-          <div class="left-section">
-            <BaseTitle title="智能投加计算"></BaseTitle>
-            <n-scrollbar class="scrollbar" style="height: 100%;">
-              <div class="form-content">
-
-                <BaseCard title="选择加药泵">
-                  <BaseRadioCard v-model="baseSourceParams.numberBeng"></BaseRadioCard>
-                </BaseCard>
-
-                <BaseCard title="投加运行方式">
-                  <span class="status-bar">
-                    <i>{{ baseSourceParams.addType === 0 ? '启用智适应碳源投加' : '手动碳源投加' }}</i>
-                  </span>
-                </BaseCard>
-
-                <BaseCard title="选择池组手自动方式">
-                  <n-tabs justify-content="space-between" type="line" :bar-width="40"
-                    tab-style="min-width: 89px;" tab-class="custom-tab_item" animated :on-update:value="onUpdateTab" :value="baseSourceParams.type">
-                    <n-tab-pane :name="0" tab="自动">
-                      <div class="panel-header_main">
-                        <p>设置数据来源</p>
-                        <p class="space-x-[20px] text-center">
-                          <span>1号池</span>
-                          <span>2号池</span>
-                        </p>
-                      </div>
-                      <div class="space-y-[12px]">
-                        <BaseChooseItem
-                          tab-key="auto"
-                          title="进水流量"
-                          unit="m³"
-                          isDouble
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.auto.jsLlType"
-                          v-model:value1="dataSourceParams.auto.jsLlOne"
-                          v-model:value2="dataSourceParams.auto.jsLlTwo"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '仪表', value1: waterConfigParams.jslYB, value2: waterConfigParams.jslYB }
-                          ]"
-                        ></BaseChooseItem>
-                        <BaseChooseItem
-                          tab-key="auto"
-                          title="进水COD"
-                          unit="mg/L"
-                          isDouble
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.auto.jsCodType"
-                          v-model:value1="dataSourceParams.auto.jsCodOne"
-                          v-model:value2="dataSourceParams.auto.jsCodTwo"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '仪表', value1: waterConfigParams.jsCodYB, value2: waterConfigParams.jsCodYB },
-                            { label: '化验', value1: waterConfigParams.jsCodHY, value2: waterConfigParams.jsCodHY }
-                          ]"
-                        ></BaseChooseItem>
-                        
-                        <BaseChooseItem
-                          tab-key="auto"
-                          title="好氧池硝酸盐"
-                          unit="mg/L"
-                          isDouble
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.auto.hycXsyType"
-                          v-model:value1="dataSourceParams.auto.hycXsyOne"
-                          v-model:value2="dataSourceParams.auto.hycXsyTwo"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '化验', value1: waterConfigParams.hyXsyHYOne, value2: waterConfigParams.hyXsyHYTwo },
-                            { label: '预测', value1: waterConfigParams.hyXsyYCOne, value2: waterConfigParams.hyXsyYCTwo }
-                          ]"
-                        ></BaseChooseItem>
-                        <BaseChooseItem
-                          tab-key="auto"
-                          title="缺氧池硝酸盐"
-                          unit="mg/L"
-                          isDouble
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.auto.qycYxyType"
-                          v-model:value1="dataSourceParams.auto.qycYxyOne"
-                          v-model:value2="dataSourceParams.auto.qycYxyTwo"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '化验', value1: waterConfigParams.qyXsyHYOne, value2: waterConfigParams.qyXsyHYTwo }
-                          ]"
-                        ></BaseChooseItem>
-                        <BaseChooseItem
-                          tab-key="auto"
-                          title="缺氧池氨氮"
-                          unit="mg/L"
-                          isDouble
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.auto.qycAdType"
-                          v-model:value1="dataSourceParams.auto.qycAdOne"
-                          v-model:value2="dataSourceParams.auto.qycAdTwo"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '化验', value1: waterConfigParams.qyAdHYOne, value2: waterConfigParams.qyAdHYTwo }
-                          ]"
-                        ></BaseChooseItem>
-                        <BaseChooseItem
-                          tab-key="auto"
-                          title="进水总氮"
-                          unit="mg/L"
-                          isDouble
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.auto.jsTnType"
-                          v-model:value1="dataSourceParams.auto.jsTnOne"
-                          v-model:value2="dataSourceParams.auto.jsTnTwo"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '仪表', value1: waterConfigParams.jsTnYB, value2: waterConfigParams.jsTnYB }
-                          ]"
-                        ></BaseChooseItem>
-                      </div>
-                    </n-tab-pane>
-
-                    <n-tab-pane :name="1" tab="1号池">
-                      <div class="panel-header_main">
-                        <p>设置数据来源</p>
-                        <p class="space-x-[20px] text-center">
-                          <span>1号池</span>
-                        </p>
-                      </div>
-                      <div class="space-y-[12px]">
-                        <BaseChooseItem
-                          tab-key="onePool"
-                          title="进水流量"
-                          unit="m³"
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.onePool.jsLlType"
-                          v-model:value1="dataSourceParams.onePool.jsLlOne"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '仪表', value1: waterConfigParams.jslYB, value2: waterConfigParams.jslYB }
-                          ]"
-                        ></BaseChooseItem>
-                        <BaseChooseItem
-                          tab-key="onePool"
-                          title="进水COD"
-                          unit="mg/L"
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.onePool.jsCodType"
-                          v-model:value1="dataSourceParams.onePool.jsCodOne"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '仪表', value1: waterConfigParams.jsCodYB, value2: waterConfigParams.jsCodYB },
-                            { label: '化验', value1: waterConfigParams.jsCodHY, value2: waterConfigParams.jsCodHY }
-                          ]"
-                        ></BaseChooseItem>
-                        <BaseChooseItem
-                          tab-key="onePool"
-                          title="好氧池硝酸盐"
-                          unit="mg/L"
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.onePool.hycXsyType"
-                          v-model:value1="dataSourceParams.onePool.hycXsyOne"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '化验', value1: waterConfigParams.hyXsyHYOne, value2: waterConfigParams.hyXsyHYTwo },
-                            { label: '预测', value1: waterConfigParams.hyXsyYCOne, value2: waterConfigParams.hyXsyYCTwo }
-                          ]"
-                        ></BaseChooseItem>
-                        <BaseChooseItem
-                          tab-key="onePool"
-                          title="缺氧池硝酸盐"
-                          unit="mg/L"
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.onePool.qycYxyType"
-                          v-model:value1="dataSourceParams.onePool.qycYxyOne"
-                          v-model:value2="dataSourceParams.onePool.qycYxyTwo"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '化验', value1: waterConfigParams.qyXsyHYOne, value2: waterConfigParams.qyXsyHYTwo }
-                          ]"
-                        ></BaseChooseItem>
-                        <BaseChooseItem
-                          tab-key="onePool"
-                          title="缺氧池氨氮"
-                          unit="mg/L"
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.onePool.qycAdType"
-                          v-model:value1="dataSourceParams.onePool.qycAdOne"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '化验', value1: waterConfigParams.qyAdHYOne, value2: waterConfigParams.qyAdHYTwo }
-                          ]"
-                        ></BaseChooseItem>
-                        <BaseChooseItem
-                          tab-key="onePool"
-                          title="进水总氮"
-                          unit="mg/L"
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.onePool.jsTnType"
-                          v-model:value1="dataSourceParams.onePool.jsTnOne"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '仪表', value1: waterConfigParams.jsTnYB, value2: waterConfigParams.jsTnYB }
-                          ]"
-                        ></BaseChooseItem>
-                      </div>
-                    </n-tab-pane>
-
-                    <n-tab-pane :name="2" tab="2号池">
-                      <div class="panel-header_main">
-                        <p>设置数据来源</p>
-                        <p class="space-x-[20px] text-center">
-                          <span>2号池</span>
-                        </p>
-                      </div>
-                      <div class="space-y-[12px]">
-                        <BaseChooseItem
-                          tab-key="twoPool"
-                          title="进水流量"
-                          unit="m³"
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.twoPool.jsLlType"
-                          v-model:value1="dataSourceParams.twoPool.jsLlTwo"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '仪表', value1: waterConfigParams.jslYB, value2: waterConfigParams.jslYB }
-                          ]"
-                        ></BaseChooseItem>
-                        <BaseChooseItem
-                          tab-key="twoPool"
-                          title="进水COD"
-                          unit="mg/L"
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.twoPool.jsCodType"
-                          v-model:value1="dataSourceParams.twoPool.jsCodTwo"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '仪表', value1: waterConfigParams.jsCodYB, value2: waterConfigParams.jsCodYB },
-                            { label: '化验', value1: waterConfigParams.jsCodHY, value2: waterConfigParams.jsCodHY }
-                          ]"
-                        ></BaseChooseItem>
-                        <BaseChooseItem
-                          tab-key="twoPool"
-                          title="好氧池硝酸盐"
-                          unit="mg/L"
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.twoPool.hycXsyType"
-                          v-model:value1="dataSourceParams.twoPool.hycXsyTwo"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '化验', value1: waterConfigParams.hyXsyHYTwo },
-                            { label: '预测', value1: waterConfigParams.hyXsyYCTwo }
-                          ]"
-                        ></BaseChooseItem>
-                        <BaseChooseItem
-                          tab-key="twoPool"
-                          title="缺氧池硝酸盐"
-                          unit="mg/L"
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.twoPool.qycYxyType"
-                          v-model:value1="dataSourceParams.twoPool.qycYxyTwo"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '化验', value1: waterConfigParams.qyXsyHYTwo }
-                          ]"
-                        ></BaseChooseItem>
-                        <BaseChooseItem
-                          tab-key="twoPool"
-                          title="缺氧池氨氮"
-                          unit="mg/L"
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.twoPool.qycAdType"
-                          v-model:value1="dataSourceParams.twoPool.qycAdTwo"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '化验', value1: waterConfigParams.qyAdHYTwo }
-                          ]"
-                        ></BaseChooseItem>
-                        <BaseChooseItem
-                          tab-key="twoPool"
-                          title="进水总氮"
-                          unit="mg/L"
-                          @on-update="handleMedicateAmount"
-                          v-model:type="dataSourceParams.twoPool.jsTnType"
-                          v-model:value1="dataSourceParams.twoPool.jsTnTwo"
-                          :btn-group="[
-                            { label: '手动', value1: '', value2: '' },
-                            { label: '仪表', value1: waterConfigParams.jsTnYB }
-                          ]"
-                        ></BaseChooseItem>
-                      </div>
-                    </n-tab-pane>
-
-                    <n-tab-pane :name="3" tab="人工投放">
-                      <div class="panel-header_main">
-                        <p>设置数据来源</p>
-                        <p class="space-x-[20px] text-center">
-                          <span>人工投放</span>
-                        </p>
-                      </div>
-                      <div class="w-full flex items-center justify-between">
-                        <span>人工投放:</span>
-                        <div class="w-[200px]">
-                          <BaseInput
-                            :isCloseIcon="false"
-                            v-model="dataSourceParams.worker.medicineAmount"
-                            @on-blur="handleMedicateAmount"
-                          ></BaseInput>
-                        </div>
-                      </div>
-                    </n-tab-pane>
-                  </n-tabs>
-                </BaseCard>
-                <BaseCard title="设定参数系数" style="margin: 0" tips="建议使用默认值,非必要不修改" v-show="tabActiveKey !== 'worker'">
-                  <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 class="control-container space-y-[16px]">
+          <div class="arg-section">
+
+            <div class="left-card space-y-[16px]">
+              <BaseTitle title="智能投加计算"></BaseTitle>
+              <ul class="paramter-list">
+                <li class="paramter-item">
+                  <span class="label">加药设备</span>
+                  <span class="value">1号加药泵 / 1号池</span>
+                </li>
+                <li class="line"></li>
+                <li class="paramter-item">
+                  <span class="label">进水流量</span>
+                  <span class="value">1号加药泵 / 1号池</span>
+                </li>
+                <li class="line"></li>
+                <li class="paramter-item">
+                  <span class="label">进水COD</span>
+                  <span class="value">1号加药泵 / 1号池</span>
+                </li>
+                <li class="line"></li>
+                <li class="paramter-item">
+                  <span class="label">进水总氮</span>
+                  <span class="value">1号加药泵 / 1号池</span>
+                </li>
+                <li class="line"></li>
+                <li class="paramter-item">
+                  <span class="label">好氧池硝酸盐</span>
+                  <span class="value">1号加药泵 / 1号池</span>
+                </li>
+                <li class="line"></li>
+                <li class="paramter-item">
+                  <span class="label">好氧池氨氮</span>
+                  <span class="value">1号加药泵 / 1号池</span>
+                </li>
+                <li class="line"></li>
+                <li class="paramter-item">
+                  <span class="label">缺氧池硝酸盐</span>
+                  <span class="value">1号加药泵 / 1号池</span>
+                </li>
+                <li class="line"></li>
+                <li class="paramter-item">
+                  <span class="label">缺氧池氨氮</span>
+                  <span class="value">1号加药泵 / 1号池</span>
+                </li>
+              </ul>
+            </div>
+
+            <div class="right-card">
+              <div class="header">
+                <h4 class="title">智能系统参数</h4>
+                <ul class="btn-list space-x-[8px]">
+                  <li class="item">
+                    <span>参数设置</span>
+                  </li>
+                  <li class="item">
+                    <span>系统告警</span>
+                    <span class="waring-circle-icon"></span>
+                  </li>
+                </ul>
+              </div>
+              <div class="result-content">
+                <div class="number_card space-x-[72px]">
+                  <NumberPanel></NumberPanel>
+                  <!-- <div class="left">
+                    <div class="animate-card left-animate">
+                      <span class="number">5.9</span>
                     </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">
-                        {{ item.value }}
-                        {{ index === 0 ? 'mg/L' : '' }}
+                    <span class="sub-title">智能控制系数</span>
+                  </div> -->
+                  <div class="middel"></div>
+                  <div class="right">
+                    <div class="animate-card right-animate">
+                      <span class="number">
+                        <i>122</i>
+                        <span>mg/L</span>
                       </span>
-                      <div style="width: 140px;" v-show="!isVisibleBtn">
-                        <BaseInput :unit="index === 0 ? 'mg/L' : ''" size='small' :isNeedFlotBtn="false"
-                          v-model="baseSourceParams[item.key]" isCenter placeholder="" :readonly="index === columnData.length - 1"></BaseInput>
-                      </div>
-                    </li>
-                  </ul>
-                </BaseCard>
+                    </div>
+                    <span class="sub-title">硝酸盐智能设定</span>
+                  </div>
+                </div>
+                <div class="progress_card space-y-[8px]">
+                  <span class="time">模型更新时间: 2025-04-11 12:11:11</span>
+                  <div class="progress"></div>
+                  <span class="tips">Libra智能投药中...</span>
+                </div>
+                <div class="play_card">
+                  <div class="play-btn space-x-[12px]">
+                    <span class="icon"></span>
+                    <span>暂停</span>
+                  </div>
+                </div>
               </div>
-            </n-scrollbar>
+            </div>
+
           </div>
-          <div class="right-section">
-            <TheResultPanel
-              :updateNum="updateNum"
-              :flowNum="flowNum"
-              :doseNum="doseNum"
-              :configuration-status="baseSourceParams.addType"
-              v-model:system="systemStatus"
-              v-model="isVisibleUpdateInfo"
-              @on-click="onFinalResult"
-              @on-update="onConfirmUpdate"
-            ></TheResultPanel>
-            <TheEchartPanel></TheEchartPanel> 
+          <div class="echart-section">
+
           </div>
         </div>
       </template>
@@ -686,157 +429,239 @@ onMounted(async () => {
 
 <style lang="scss" scoped>
 .control-container {
-  @include flex(x, start, start);
+  // @include flex(x, start, start);
   height: 100%;
 
-  .left-section {
-    display: flex;
-    flex-flow: column;
-    flex-shrink: 0;
-    width: 440px;
-    height: 100%;
+  .arg-section {
+    @include flex(x, start, start);
+    height: 57%;
+    padding: 16px 14px;
+    border: 1px solid #fff;
     border-radius: 10px;
-    background: #fff;
-
-    .status-bar {
-      display: inline-block;
-      padding: 4px 14px;
-      margin-left: 20px;
-      border-top: 0.5px solid rgba(212, 241, 255, 0.00);
-      border-bottom: 0.5px solid rgba(212, 241, 255, 0.00);
-      background: linear-gradient(90deg, rgba(240, 250, 255, 0.00) 0%, #E9F8FF 27.27%, rgba(240, 250, 255, 0.00) 100%);
-
-      i {
-        line-height: 24px;
-        background: linear-gradient(92deg, #5ABBF2 12.24%, #2454FF 63.2%);
-        background-clip: text;
-        -webkit-background-clip: text;
-        -webkit-text-fill-color: transparent;
-        font-weight: bold;
-      }
-    }
+    background: url(@/assets/images/control/bg-top.png) left center no-repeat;
+    background-size: 878px 100% ;
 
-    .scrollbar {
+    .left-card {      
+      flex-shrink: 0;  
+      width: 338px;
       height: 100%;
-    }
-
-    .form-content {
-      padding: 0 16px 24px 16px;
-    }
-
-    .panel-header_main {
-      @include flex(x, center, between);
-      margin-bottom: 12px;
-      color: #86909C;
-      span {
-        display: inline-block;
-        width: 60px;
+      display: flex;
+      flex-flow: column;
+
+      .paramter-list {
+        flex: 1;
+        display: flex;
+        justify-content: space-between;
+        flex-flow: column;
+        padding: 14px;
+        border: 1px solid #fff;
+        border-radius: 10px;
+        background: rgba(255, 255, 255, 0.20);
+        backdrop-filter: blur(5px);
+        font-size: 13px;
+        color: #585858;
+        line-height: 22px;
+
+        .line {
+          width: 100%;
+          height: 1px;
+          background: #EEE;
+        }
+        .paramter-item {
+          @include flex(x, center, between);
+          .value {
+            color: #1A2029;
+            font-weight: bold;
+          }
+        }
       }
     }
 
-  }
-
-  .data-source-list {
-    .data-soruce-item {
-      @include flex(x, center, between);
+    .right-card {
+      flex: 1;
+      height: 100%;
 
-      .inp-inner {
-        width: 112px;
+      .header {
+        height: 40px;
+        position: relative;
+        text-align: center;
+        .title {
+          color: #1A2029;
+          font-size: 15px;
+          font-weight: bold;
+          line-height: 24px;
+        }
+        .btn-list {
+          position: absolute;
+          top: 0;
+          right: 0;
+          @include flex(x, center, center);
+          color: #1A2029;
+          font-size: 12px;
+          font-weight: 400;
+
+          .item {
+            position: relative;
+            @include flex(x, center, center);
+            width: 68px;
+            height: 28px;
+            border-radius: 4px;
+            background: #fff;
+            cursor: pointer;
+
+            .waring-circle-icon {
+              position: absolute;
+              top: 2px;
+              right: 2px;
+              width: 5px;
+              height: 5px;
+              border-radius: 50%;
+              background: #FF4920;
+            }
+          }
+        }
       }
 
-      .unit {
-        font-family: "D-DIN-PRO-700-Bold";
-        font-weight: bold;
-        font-size: 12px;
-        color: #333;
+      .result-content {
+        @include flex(y, center, around);
+        height: calc(100% - 40px);
+        padding: 0px 86px 0 86px;
+        // background: #0059FF;
+        background-clip: padding-box;
+        
+        .number_card {
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          
+          .left, .right {
+            text-align: center;
+            .left-animate {
+              background: url("@/assets/images/control/number-card-left.png") center center no-repeat;
+              .number {
+                right: 30px;
+              }
+            }
+            .right-animate {
+              background: url("@/assets/images/control/number-card-right.png") center center no-repeat;
+              .number {
+                @include flex(y, start, center);
+                left: 30px;
+                span {
+                  color: #000;
+                  font-family: "PingFang SC";
+                  font-size: 12px;
+                  font-style: normal;
+                  font-weight: 400;
+                  line-height: normal;
+                }
+              }
+            }
+            .animate-card {
+              position: relative;
+              width: 194px;
+              height: 164px;
+              // background-size: 140px 100%;
+              background-size: cover;
+
+              .number {
+                position: absolute;
+                top: 30px;
+                color: #1A2029;
+                // font-family: "DIN-RegularAlternate";
+                font-family: "D-DIN-PRO-700-Bold";
+                font-size: 52px;
+                font-style: normal;
+                font-weight: 700;
+              }
+            }
+            .sub-title {
+              color: #333;
+              font-family: "PingFang SC";
+              font-size: 12px;
+              font-style: normal;
+              font-weight: 400;
+              line-height: 20px;
+            }
+          }
+
+          .middel {
+            width: 186px;
+            height: 186px;
+            background: url("@/assets/images/control/number-card-middle.svg") center center no-repeat,
+            url("@/assets/images/control/number-card-middle2.svg") center bottom no-repeat;
+            background-size: contain;
+          }
+        }
+
+        .progress_card {
+          @include flex(y, center, center);
+          padding-top: 6px;
+          text-align: center;
+
+          .time {
+            color: #F6A52C;
+            font-size: 10px;
+            font-style: normal;
+            font-weight: 400;
+            line-height: 16px;
+          }
+
+          .tips {
+            text-align: center;
+            font-size: 12px;
+            font-weight: 500;
+            line-height: 24px;
+            background: linear-gradient(90deg, #0059FF 0%, #29C2FA 100%);
+            background-clip: text;
+            -webkit-background-clip: text;
+            -webkit-text-fill-color: transparent;
+          }
+
+          .progress {
+            width: 165px;
+            height: 10px;
+            background: red;
+          }
+        }
+
+        .play_card {
+          @include flex(x, center, center);
+          .play-btn {
+            @include flex(x, center, center);
+            // width: 136px;
+            // height: 64px;
+            width: 120px;
+            height: 48px;
+            background: url("@/assets/images/control/bg-play-btn.png") center center no-repeat;
+            background-size: cover;
+            color: #2454FF;
+            font-size: 14px;
+            font-weight: 500;
+            line-height: 16px;
+            cursor: pointer;
+            .icon {
+              display: block;
+              width: 28px;
+              height: 28px;
+              background: url("@/assets/images/control/icon-end.svg") center center no-repeat;
+              background-size: cover;
+            }
+          }
+        }
       }
     }
   }
-}
-
-.right-section {
-  width: 100%;
-  height: 100%;
-  border-radius: 8px;
-  background: #fff;
-  overflow: hidden;
-
-  // .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;
-}
+  .echart-section {
+    height: 43%;
+    background: red;
+  }
 
-.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>
 
 <style lang="scss">

+ 32 - 0
src/views/control/NumberPanel.vue

@@ -0,0 +1,32 @@
+<script setup>
+
+</script>
+
+<template>
+  <div class="number-panel-container space-y-[6px]">
+    <div class="number-panel-inner direction-left"></div>
+    <div>
+      <span>智能控制系数</span>
+    </div>
+  </div>
+</template>
+
+
+<style lang="scss">
+.number-panel-container {
+  width: 194px;
+  background: #ccc;
+
+  .number-panel-inner {
+    width: 140px;
+    height: 164px;
+  }
+
+  .direction-left {
+    background: url("@/assets/images/control/line-left-1.svg") left center no-repeat,
+    url("@/assets/images/control/line-left-2.svg") right bottom no-repeat,
+    url("@/assets/images/control/line-left-3.svg") right bottom no-repeat;
+    background: red;
+  }
+}
+</style>

+ 6 - 6
src/views/control/components/BaseTitle.vue

@@ -16,16 +16,19 @@ defineProps({
 <template>
   <div class="header">
     <div class="title">
-      <svg xmlns="http://www.w3.org/2000/svg" width="8" height="24" viewBox="0 0 8 24" fill="none" v-if="type === 'first'">
+      <svg xmlns="http://www.w3.org/2000/svg" width="8" height="24" viewBox="0 0 8 24" fill="none"
+        v-if="type === 'first'">
         <path d="M0 6.86197V3.24507L4.21274 0H7.11111L4.45741 24H1.35684L4.01053 3.85352L0 6.86197Z" fill="#2454FF" />
       </svg>
       <svg xmlns="http://www.w3.org/2000/svg" width="12" height="24" viewBox="0 0 12 24" fill="none" v-else>
-        <path d="M7.74366 10.4333C8.43696 9.03333 8.78361 7.76667 8.78361 6.6V6.1C8.78361 5.06667 8.58552 4.26667 8.16459 3.7C7.74366 3.13333 7.19892 2.83333 6.48086 2.83333C5.7628 2.83333 5.21807 3.1 4.8219 3.66667C4.42573 4.23333 4.22764 5.1 4.22764 6.23333V7.16667H1.94966V6.1C1.94966 4.26667 2.37059 2.8 3.18769 1.66667C4.02956 0.566667 5.14379 0 6.53039 0C7.42177 0 8.23887 0.266667 8.93217 0.8C9.62547 1.3 10.1702 2.03333 10.5416 2.96667C10.9378 3.9 11.1111 4.93333 11.1111 6.03333V6.6C11.1111 7.6 10.9873 8.5 10.7149 9.4C10.4673 10.2667 10.0959 11.1667 9.57595 12.1L2.94652 21.1667H9.16145V24H0V21.6L7.74366 10.4333Z" fill="#2454FF"/>
+        <path
+          d="M7.74366 10.4333C8.43696 9.03333 8.78361 7.76667 8.78361 6.6V6.1C8.78361 5.06667 8.58552 4.26667 8.16459 3.7C7.74366 3.13333 7.19892 2.83333 6.48086 2.83333C5.7628 2.83333 5.21807 3.1 4.8219 3.66667C4.42573 4.23333 4.22764 5.1 4.22764 6.23333V7.16667H1.94966V6.1C1.94966 4.26667 2.37059 2.8 3.18769 1.66667C4.02956 0.566667 5.14379 0 6.53039 0C7.42177 0 8.23887 0.266667 8.93217 0.8C9.62547 1.3 10.1702 2.03333 10.5416 2.96667C10.9378 3.9 11.1111 4.93333 11.1111 6.03333V6.6C11.1111 7.6 10.9873 8.5 10.7149 9.4C10.4673 10.2667 10.0959 11.1667 9.57595 12.1L2.94652 21.1667H9.16145V24H0V21.6L7.74366 10.4333Z"
+          fill="#2454FF" />
       </svg>
       <span class="text">{{ title }}</span>
     </div>
     <div class="btn-group space-x-[8px]">
-      <slot name="right"/>
+      <slot name="right" />
     </div>
   </div>
 </template>
@@ -33,9 +36,6 @@ defineProps({
 <style lang="scss" scoped>
 .header {
   @include flex(x, center, between);
-  height: 75px;
-  flex-shrink: 1;
-  padding: 24px 16px 24px 16px;
   color: #1A2029;
 
   .title {