Explorar o código

Merge branch '2025-02-20/fetaure-BigScreenNew'

sunxiao hai 4 semanas
pai
achega
3e8ed07101
Modificáronse 34 ficheiros con 2578 adicións e 93 borrados
  1. BIN=BIN
      src/assets/fonts/DingTalk.ttf
  2. BIN=BIN
      src/assets/images/screenViewBlack/bg-header-continue.png
  3. BIN=BIN
      src/assets/images/screenViewBlack/bg-header-data.png
  4. BIN=BIN
      src/assets/images/screenViewBlack/bg-header-gongyi.png
  5. BIN=BIN
      src/assets/images/screenViewBlack/bg-header-quality.png
  6. BIN=BIN
      src/assets/images/screenViewBlack/bg-header-yield.png
  7. BIN=BIN
      src/assets/images/screenViewBlack/bg-header.png
  8. BIN=BIN
      src/assets/images/screenViewBlack/bg-input.png
  9. BIN=BIN
      src/assets/images/screenViewBlack/bg-left-active.png
  10. BIN=BIN
      src/assets/images/screenViewBlack/bg-left.png
  11. BIN=BIN
      src/assets/images/screenViewBlack/bg-qualty-item.png
  12. BIN=BIN
      src/assets/images/screenViewBlack/bg-right-active.png
  13. BIN=BIN
      src/assets/images/screenViewBlack/bg-right.png
  14. BIN=BIN
      src/assets/images/screenViewBlack/bg-select.png
  15. BIN=BIN
      src/assets/images/screenViewBlack/bg-title-first.png
  16. BIN=BIN
      src/assets/images/screenViewBlack/img-coord-a.png
  17. BIN=BIN
      src/assets/images/screenViewBlack/img-coord-b.png
  18. BIN=BIN
      src/assets/images/screenViewBlack/img-coord-c.png
  19. BIN=BIN
      src/assets/images/screenViewBlack/img-factory.png
  20. BIN=BIN
      src/assets/images/screenViewBlack/img-start.png
  21. 8 0
      src/assets/styles/common.scss
  22. 1 1
      src/components/Layout/TheUserAvatar.vue
  23. 16 0
      src/router/index.js
  24. 300 0
      src/views/screen/ScreenViewBlack/components/ContinueData.vue
  25. 82 0
      src/views/screen/ScreenViewBlack/components/LayoutCard.vue
  26. 397 0
      src/views/screen/ScreenViewBlack/components/WaterQuality.vue
  27. 327 0
      src/views/screen/ScreenViewBlack/components/WaterYield.vue
  28. 103 0
      src/views/screen/ScreenViewBlack/components/dataBox.vue
  29. 120 0
      src/views/screen/ScreenViewBlack/components/gongyi.vue
  30. 768 0
      src/views/screen/ScreenViewBlack/config/echartOption.js
  31. 452 0
      src/views/screen/ScreenViewBlack/index.vue
  32. 4 4
      src/views/screen/components/WaterYield.vue
  33. 0 44
      vite.config.ts.timestamp-1719915060984-6fabe9de1b68c.mjs
  34. 0 44
      vite.config.ts.timestamp-1720486813773-2c95633e7e6a2.mjs

BIN=BIN
src/assets/fonts/DingTalk.ttf


BIN=BIN
src/assets/images/screenViewBlack/bg-header-continue.png


BIN=BIN
src/assets/images/screenViewBlack/bg-header-data.png


BIN=BIN
src/assets/images/screenViewBlack/bg-header-gongyi.png


BIN=BIN
src/assets/images/screenViewBlack/bg-header-quality.png


BIN=BIN
src/assets/images/screenViewBlack/bg-header-yield.png


BIN=BIN
src/assets/images/screenViewBlack/bg-header.png


BIN=BIN
src/assets/images/screenViewBlack/bg-input.png


BIN=BIN
src/assets/images/screenViewBlack/bg-left-active.png


BIN=BIN
src/assets/images/screenViewBlack/bg-left.png


BIN=BIN
src/assets/images/screenViewBlack/bg-qualty-item.png


BIN=BIN
src/assets/images/screenViewBlack/bg-right-active.png


BIN=BIN
src/assets/images/screenViewBlack/bg-right.png


BIN=BIN
src/assets/images/screenViewBlack/bg-select.png


BIN=BIN
src/assets/images/screenViewBlack/bg-title-first.png


BIN=BIN
src/assets/images/screenViewBlack/img-coord-a.png


BIN=BIN
src/assets/images/screenViewBlack/img-coord-b.png


BIN=BIN
src/assets/images/screenViewBlack/img-coord-c.png


BIN=BIN
src/assets/images/screenViewBlack/img-factory.png


BIN=BIN
src/assets/images/screenViewBlack/img-start.png


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

@@ -24,6 +24,14 @@
   // font-style: normal;
 }
 
+@font-face {
+  // font-display: swap;
+  font-family: 'DingTalk';
+  src: url('@/assets/fonts/DingTalk.ttf');
+  // font-weight: normal;
+  // font-style: normal;
+}
+
 // chat 布局相关
 .chat-ask_icon,
 .chat-answer_icon {

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

@@ -67,7 +67,7 @@ const RenderUserAvatar = ({ store }) => {
     trigger: () => (
       <div class="flex items-center cursor-pointer">
         <img src={user.avatar} alt="" class="w-[32px] h-[32px] mr-[10px] rounded-[50%]" />
-        <span class="text-[#272D35] text-[12px]">{user.nickName}</span>
+        <span class="name text-[#272D35] text-[12px]">{user.nickName}</span>
       </div>
     )
   };

+ 16 - 0
src/router/index.js

@@ -1,9 +1,25 @@
 import { createRouter, createWebHistory } from 'vue-router'
 
 const constantRouterMap = [
+  // {
+  //   path: '/',
+  //   name: 'Scrren',
+  //   component: () => import('@/views/screen/ScreenView.vue'),
+  //   meta: {
+  //     title: "智慧总控"
+  //   }
+  // },
   {
     path: '/',
     name: 'Scrren',
+    component: () => import('@/views/screen/ScreenViewBlack/index.vue'),
+    meta: {
+      title: "智慧总控"
+    }
+  },
+  {
+    path: '/screen-light',
+    name: 'ScreenLight',
     component: () => import('@/views/screen/ScreenView.vue'),
     meta: {
       title: "智慧总控"

+ 300 - 0
src/views/screen/ScreenViewBlack/components/ContinueData.vue

@@ -0,0 +1,300 @@
+<script setup>
+import { onMounted, onUnmounted, watch, ref } from 'vue';
+import * as echarts from 'echarts';
+import { formatDecimals } from "@/utils/format";
+import { screenApi } from '@/api/screen';
+import dayjs from 'dayjs';
+import LayoutCard from './LayoutCard.vue';
+import { getBarOptions } from '../config/echartOption';
+
+const props = defineProps({
+  screenData: {
+    type: Object,
+    default: []
+  }
+})
+
+let barOption = {};
+let lineOption = {};
+let timer = null;
+let chart = null;
+const activeIndex = ref(0);
+const echartRef = ref(null);
+
+
+const windowResize = () => {
+  clearTimeout(timer);
+  timer = setTimeout(() => chart.resize(), 100);
+};
+
+watch(() => props.screenData, (currentVal) => {
+  const { no3Hlj1Jqr, no3Hlj2Jqr, nh31Jqr, nh32Jqr, tpRccJqr } = currentVal;
+  const options = [ no3Hlj1Jqr, no3Hlj2Jqr, nh31Jqr, nh32Jqr, tpRccJqr ].map(item => {
+    return item ? Number(item.toFixed(2)) : 0;
+  })
+  barOption = options;
+  chart.setOption( getBarOptions(options) )
+})
+
+const getLineOptions = ({xAxisData, seriesData}) => {
+  const colors = ['#F7931E', '#2454FF', '#00FFFF', '#00FF00', '#3DB0F1', '#F4CF35',];
+  const series = Object.keys(seriesData).map(((key, index) => {
+    const item = seriesData[key];
+    const color = colors[index];
+    return {
+      name: key,
+      type: "line",
+      smooth: true,
+      symbol: 'none',
+      areaStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          {
+            offset: 0,
+            color,
+          },
+          {
+            offset: 1,
+            color: "rgba(255, 255, 255, 0.3)",
+          },
+        ]),
+      },
+      itemStyle: { color },
+      lineStyle: {
+        width: '2',
+        color
+      },
+      data: item
+    }
+  }));
+
+  const option = {
+    grid: {
+      bottom: '4%',
+      top: "23%",
+      left: "5%",
+      right: "2%",
+      containLabel: true,
+    },
+    tooltip: {
+      trigger: "axis",
+    },
+    legend: [
+      {
+        show: true,
+        orient: 'horizontal',
+        icon: 'circle',
+        itemWidth: 8,
+        y: 'top',
+        x: 'right',
+        textStyle: {fontSize: '12px', color: '#fff'},
+        data: ['1#好氧池硝酸盐', '1#缺氧氨氮', '二沉池正磷酸盐']  
+      },
+      {
+      show: true,
+      orient: 'horizontal',
+      icon: 'circle',
+      itemWidth: 8,
+      y: '8%',
+      x: 'right',
+      textStyle: {fontSize: '12px', color: '#fff'},
+      data: ['2#好氧池硝酸盐', '2#缺氧氨氮',]  
+    }
+    ],
+    xAxis: {
+      type: "category",
+      data: xAxisData,
+      axisLabel: {
+        interval: 'auto',
+        show: true,
+        fontSize: '11px',
+        color: "#fff",
+      },
+      axisLine: {
+        show: true,
+        lineStyle: {
+          type: 'dashed',
+          show: true,
+          color: "3f4a59",
+        },
+      },
+      axisTick: {
+        show: false,
+      },
+      interval: 0, // 0 表示强制显示所有标签,'auto' 表示自动间隔
+      // boundaryGap: true,
+    },
+    yAxis: {
+      splitNumber: 4,
+      type: "value",
+      axisLabel: {
+        show: true,
+        fontSize: '12px',
+        color: "#fff"
+      },
+      axisLine: {
+        show: false,
+        lineStyle: {
+          color: "#BDD4E8",
+        },
+      },
+      axisTick: {
+        show: false,
+      },
+      splitLine: {
+        lineStyle: {
+          color: "#3f4a59",
+          type: "dashed",
+        },
+      }
+    },
+    series
+  };
+
+  return option;
+}
+
+const onChangeTab = (index) => {
+  activeIndex.value = index;
+  if (index == 0) {
+    chart.setOption( getBarOptions(barOption), {notMerge: true} )
+  } else {
+    chart.setOption( getLineOptions(lineOption), {notMerge: true} )
+  }
+  setTimeout(() => chart.resize());
+}
+
+onMounted(() => {
+  screenApi.getContinueDataByDays().then(({ data }) => {
+    const seriesData = { '1#好氧池硝酸盐': [], '2#好氧池硝酸盐': [], '1#缺氧氨氮': [], '2#缺氧氨氮': [], '二沉池正磷酸盐': [] };
+    const xAxisData = data.map(item => dayjs(item.testHour).format('MM/DD HH'));
+    data.forEach(({ no3Hlj1Jqr, no3Hlj2Jqr, nh31Jqr, nh32Jqr, tpRccJqr }) => {
+      seriesData['1#好氧池硝酸盐'].push(formatDecimals(no3Hlj1Jqr));
+      seriesData['2#好氧池硝酸盐'].push(formatDecimals(no3Hlj2Jqr));
+      seriesData['1#缺氧氨氮'].push(formatDecimals(nh31Jqr));
+      seriesData['2#缺氧氨氮'].push(formatDecimals(nh32Jqr));
+      seriesData['二沉池正磷酸盐'].push(formatDecimals(tpRccJqr));
+    })
+    lineOption = {xAxisData, seriesData};
+  })
+
+  chart = echarts.init(echartRef.value, 'light');
+  window.addEventListener("resize", windowResize);
+})
+
+onUnmounted(() => {
+  window.removeEventListener("resize", windowResize);
+})
+</script>
+
+<template>
+  <LayoutCard title="连续检测数据" name="continue" width="100%">
+    <template #headerRight>
+      <ul>
+        <li :class="['btn', activeIndex == 0 ? 'action' : '']" @click="onChangeTab(0)">当前</li>
+        <li :class="['btn', activeIndex == 1 ? 'action' : '']" @click="onChangeTab(1)">近7日</li>
+      </ul>
+    </template>
+    <div class="main-container">
+      <div class="echart-card">
+        <div class="title" v-show="activeIndex == 0">
+          <span></span>
+          <ul class="tabs space-x-[18px]">
+            <li class="item space-x-[6px]">
+              <span class="square-icon square-current"></span>
+              <span>当前值</span>
+            </li>
+            <li class="item space-x-[6px]">
+              <span class="square-icon square-real"></span>
+              <span>标准值</span>
+            </li>
+          </ul>
+        </div>
+        <div class="echart-inner" ref="echartRef" ></div>
+      </div>
+    </div>
+  </LayoutCard>
+</template>
+
+<style lang="scss" scoped>
+.main-container {
+  width: 100%;
+  height: 222px;
+
+  .echart-card {
+    display: flex;
+    flex-flow: column;
+    height: 100%;
+    color: #fff;
+    font-size: 12px;
+    font-weight: bold;
+
+    .title {
+      flex-shrink: 0;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 0px 0 12px 0;
+
+      .tabs {
+        display: flex;
+
+        .item {
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          font-size: 12px;
+
+          .square-icon {
+            display: inline-block;
+            width: 14px;
+            height: 8px;
+            border-radius: 2px;
+          }
+          .square-current {
+            background: linear-gradient(270deg, #FBB03B 0%, rgba(251, 176, 59, 0.00) 100%);
+          }
+          .square-real {
+            background: linear-gradient(270deg, #17FFC9 0%, rgba(23, 255, 201, 0.00) 100%);
+          }
+        }
+      }
+    }
+    .echart-inner {
+      flex: 1;
+    }
+  }
+}
+
+.btn {
+  width: 62px;
+  height: 28px;
+  border-radius: 2px 0px 0px 2px;
+  border: 1px solid #6a7899;
+  float: left;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  color: rgba(84, 194, 248, 1);
+  font-size: 14px;
+  color: #fff;
+
+  &:first-child {
+    border-right: 0;
+    border-top-left-radius: 4px;
+    border-bottom-left-radius: 4px;
+  }
+
+  &:last-child {
+    border-left: 0;
+    border-top-right-radius: 4px;
+    border-bottom-right-radius: 4px;
+  }
+}
+.action {
+  border: 1px solid #E7C177;
+  background: #000;
+  box-shadow: 0px 0px 4px 0px #CF9014, 0px 0px 19px 0px #DA9000 inset, 0px 0px 28px 0px #DA9000 inset;
+  color: #fff;
+}
+</style>

+ 82 - 0
src/views/screen/ScreenViewBlack/components/LayoutCard.vue

@@ -0,0 +1,82 @@
+<script setup>
+import { ref, computed } from "vue";
+
+defineProps({
+  title: {
+    type: String,
+    default: ''
+  },
+  name: {
+    type: String,
+    default: '' 
+  },
+  width: {
+    type: String,
+    default: '482px'
+  }
+})
+
+const xx = computed(() => {
+
+})
+
+</script>
+
+<template>
+  <section class="layout-card">
+    <div class="pl-[18px]">
+      <div :class="['header', 'header-' + name]" :style="{ width: width }">
+        <div class="header-right">
+          <slot name="headerRight"></slot>
+        </div>
+      </div>
+    </div>
+    <div class="layout-main">
+      <slot></slot>
+    </div>
+  </section>
+</template>
+
+<style lang="scss" scoped>
+.layout-card {
+  width: 540px;
+  .header {
+    width: 482px;
+    height: 48px;
+    padding-left: 20px;
+    display: flex;
+    justify-content: flex-end;
+    align-items: center;
+    position: relative;
+  }
+
+  .header-yield {
+    background: url(@/assets/images/screenViewBlack/bg-header-yield.png) no-repeat;
+    background-size: 100% 100%;
+  }
+
+  .header-quality {
+    background: url(@/assets/images/screenViewBlack/bg-header-quality.png) no-repeat;
+    background-size: 100% 100%;
+  }
+
+  .header-continue {
+    background: url(@/assets/images/screenViewBlack/bg-header-continue.png) no-repeat;
+    background-size: 100% 100%;
+  }
+
+  .header-data {
+    background: url(@/assets/images/screenViewBlack/bg-header-data.png) no-repeat;
+    background-size: 100% 100%;
+  }
+
+  .header-gongyi {
+    background: url(@/assets/images/screenViewBlack/bg-header-gongyi.png) no-repeat;
+    background-size: 100% 100%;
+  }
+  
+  .layout-main {
+    padding: 10px 32px 10px 28px;
+  }
+}
+</style>

+ 397 - 0
src/views/screen/ScreenViewBlack/components/WaterQuality.vue

@@ -0,0 +1,397 @@
+<script setup>
+import { onMounted, onUnmounted, watchEffect, ref } from 'vue';
+import { NTooltip } from 'naive-ui';
+import dayjs from 'dayjs';
+import { formatDecimals } from "@/utils/format";
+import { screenApi } from '@/api/screen'
+import LayoutCard from './LayoutCard.vue';
+
+import * as echarts from 'echarts';
+
+let timer = null;
+let echartJs = null;
+let echartCs = null;
+const echartJsRef = ref(null);
+const echartCsRef = ref(null);
+const inWater = ref({});
+const outWater = ref({});
+
+const props = defineProps({
+  screenData: {
+    type: Object,
+    default: []
+  }
+})
+const createEchart = ({ xAxisData, seriesData, chart, title }) => {
+  const colors = ['#F7931E', '#2454FF', '#00FFFF', '#00FF00', '#3DB0F1', '#F4CF35',];
+
+  const series = Object.keys(seriesData).map(((key, index) => {
+    const item = seriesData[key];
+    const color = colors[index];
+    return {
+      name: key,
+      type: "line",
+      smooth: true,
+      symbol: 'none',
+      areaStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          {
+            offset: 0,
+            color,
+          },
+          {
+            offset: 1,
+            color: "rgba(255, 255, 255, 0.3)",
+          },
+        ]),
+      },
+      itemStyle: { color },
+      lineStyle: {
+        width: '2',
+        color
+      },
+      data: item
+    }
+  }));
+
+  const option = {
+    grid: {
+      bottom: "14%",
+      top: "26%",
+      left: '10%',
+      right: "6%",
+      // containLabel: true,
+    },
+    tooltip: {
+      trigger: "axis",
+    },
+    title: {
+      text: title,
+      left: '0',
+      textStyle: {
+        fontSize: '12px',
+        color: '#fff'
+      },
+    },
+    legend: {
+      orient: 'horizontal',
+      icon: 'circle',
+      itemWidth: 8,
+      y: 'top',
+      x: 'right',
+      textStyle: {fontSize: '12px', color: '#fff'}
+    },
+    xAxis: {
+      type: "category",
+      data: xAxisData,
+      axisLabel: {
+        show: true,
+        fontSize: '12px',
+        color: "#fff",
+      },
+      axisLine: {
+        show: true,
+        lineStyle: {
+          type: 'dashed',
+          show: true,
+          color: "#fff",
+        },
+      },
+      axisTick: {
+        show: false,
+      },
+      boundaryGap: true,
+    },
+    yAxis: {
+      splitNumber: 2,
+      type: "value",
+      axisLabel: {
+        show: true,
+        fontSize: '12px',
+        color: "#fff"
+      },
+      axisLine: {
+        show: false,
+        lineStyle: {
+          color: "#3f4a59",
+        },
+      },
+      axisTick: {
+        show: false,
+      },
+      splitLine: {
+        lineStyle: {
+          color: "#3f4a59",
+          type: "dashed",
+        },
+      }
+    },
+    series
+  };
+  chart && chart.setOption(option);
+};
+
+watchEffect(() => {
+  const {
+    jsCod, jsNh3, jsTn, jsTp, jsSs, jsPh,
+    jscodSjz, jsadSjz, jszdSjz, jszlSjz, jsssSjz,
+    csCod, csNh3, csTn, csTp, csSs, csPh,
+    cscodBzz, csadBzz, cszzBzz, cszlBzz, csssBzz
+  } = props.screenData;
+
+  inWater.value = [
+    { label: 'COD', standardValue: formatDecimals(jscodSjz), currentValue: formatDecimals(jsCod), isExceed: jsCod > jscodSjz },
+    { label: 'NH3-N', standardValue: formatDecimals(jsadSjz), currentValue: formatDecimals(jsNh3), isExceed: jsNh3 > jsadSjz },
+    { label: 'TN', standardValue: formatDecimals(jszdSjz), currentValue: formatDecimals(jsTn), isExceed: jsTn > jszdSjz },
+    { label: 'TP', standardValue: formatDecimals(jszlSjz), currentValue: formatDecimals(jsTp), isExceed: jsTp > jszlSjz },
+    { label: 'SS', standardValue: formatDecimals(jsssSjz), currentValue: formatDecimals(jsSs), isExceed: jsSs > jsssSjz },
+    { label: 'PH值', standardValue: '6-9', currentValue: formatDecimals(jsPh), isExceed: jsPh > 6 && jsPh < 9 }
+  ],
+  outWater.value = [
+    { label: 'COD', standardValue: formatDecimals(cscodBzz), currentValue: formatDecimals(csCod), isExceed: csCod > cscodBzz },
+    { label: 'NH3-N', standardValue: formatDecimals(csadBzz), currentValue: formatDecimals(csNh3), isExceed: csNh3 > csadBzz },
+    { label: 'TN', standardValue: formatDecimals(cszzBzz), currentValue: formatDecimals(csTn), isExceed: csTn > cszzBzz},
+    { label: 'TP', standardValue: formatDecimals(cszlBzz), currentValue: formatDecimals(csTp), isExceed: csTp > cszlBzz },
+    { label: 'SS', standardValue: formatDecimals(csssBzz), currentValue: formatDecimals(csSs), isExceed: csSs > csssBzz },
+    { label: 'PH值', standardValue: '6-9', currentValue: formatDecimals(csPh), isExceed: csPh < 6 || csPh > 9 }
+  ]
+})
+
+const windowResize = () => {
+  clearTimeout(timer);
+  timer = setTimeout(() => {
+    echartJs.resize();
+    echartCs.resize();
+  }, 100);
+};
+
+onMounted(() => {
+  echartJs = echarts.init(echartJsRef.value, 'light');
+  echartCs = echarts.init(echartCsRef.value, 'light');
+  window.addEventListener("resize", windowResize);
+
+  screenApi.getIndustryDataByDays().then(res => {
+    const seriesJsData = { 'COD': [], 'NH3-N': [], 'TN': [], 'TP': [], 'SS': [], 'PH值': [] };
+    const seriesCsData = { 'COD': [], 'NH3-N': [], 'TN': [], 'TP': [], 'SS': [], 'PH值': [] };
+
+    const xAxisData = res.data.map(item => dayjs(item.testHour).format('MM/DD HH'));
+
+    res.data.forEach(item => {
+      seriesJsData['COD'].push(formatDecimals(item.jsCod));
+      seriesJsData['NH3-N'].push(formatDecimals(item.jsNh3));
+      seriesJsData['TN'].push(formatDecimals(item.jsTn));
+      seriesJsData['TP'].push(formatDecimals(item.jsTp));
+      seriesJsData['SS'].push(formatDecimals(item.jsSs));
+      seriesJsData['PH值'].push(formatDecimals(item.jsPh));
+
+      seriesCsData['COD'].push(formatDecimals(item.csCod));
+      seriesCsData['NH3-N'].push(formatDecimals(item.csNh3));
+      seriesCsData['TN'].push(formatDecimals(item.csTn));
+      seriesCsData['TP'].push(formatDecimals(item.csTp));
+      seriesCsData['SS'].push(formatDecimals(item.csSs));
+      seriesCsData['PH值'].push(formatDecimals(item.csPh));
+    });
+
+    createEchart({ xAxisData, seriesData: seriesJsData, chart: echartJs, title: '进水 · 近7日趋势' });
+    createEchart({ xAxisData, seriesData: seriesCsData, chart: echartCs, title: '出水 · 近7日趋势' });
+  })
+
+})
+
+onUnmounted(() => {
+  window.removeEventListener("resize", windowResize);
+})
+</script>
+
+<template>
+  <LayoutCard title="水质数据" name="quality">
+    <div class="main-container">
+      <div class="count-card mb-[10px]">
+        <div class="count-num_inner">
+          <p class="title in-water-title">今日<br>进水</p>
+          <ul class="num-group flex">
+            <template v-for="item, index in inWater" :key="item.label">
+              <n-tooltip placement="top" trigger="hover">
+                <template #trigger>
+                  <li class="item">
+                    <span class="label">{{ item.label }}</span>
+                    <span class="num">{{ item.currentValue }} <i v-if="index != inWater.length - 1">mg/L</i></span>
+                  </li>
+                </template>
+                <ul class="text-bold text-[#fff] text-[12px] leading-[18px]">
+                  <li>当前值:{{ item.currentValue }} <i v-if="index != inWater.length - 1">mg/L</i></li>
+                  <li>标准值:{{ item.standardValue }} <i v-if="index != inWater.length - 1">mg/L</i></li>
+                </ul>
+              </n-tooltip>
+            </template>
+          </ul>
+        </div>
+      </div>
+      <div class="count-card">
+        <div class="count-num_inner">
+          <p class="title out-water-title">今日<br>出水</p>
+          <ul class="num-group flex">
+            <template v-for="item, index in outWater" :key="item.label">
+              <n-tooltip placement="top" trigger="hover">
+                <template #trigger>
+                  <li class="item">
+                    <span class="label">{{ item.label }}</span>
+                    <span class="num">{{ item.currentValue }} <i v-if="index != inWater.length - 1">mg/L</i></span>
+                  </li>
+                </template>
+                <ul class="text-bold text-[#fff] text-[12px] leading-[18px]">
+                  <li :style="{color: item.isExceed ? 'red' : '#fff'}">当前值:{{ item.currentValue }} <i v-if="index != inWater.length - 1">mg/L</i></li>
+                  <li>标准值:{{ item.standardValue }} <i v-if="index != inWater.length - 1">mg/L</i></li>
+                </ul>
+              </n-tooltip>
+            </template>
+          </ul>
+        </div>
+      </div>
+      <div class="echart-card">
+        <div class="echart-inner mb-[14px]" ref="echartJsRef"></div>
+        <div class="echart-inner" ref="echartCsRef"></div>
+      </div>
+    </div>
+  </LayoutCard>
+</template>
+
+<style lang="scss" scoped>
+.main-container {
+  width: 100%;
+
+  .count-card {
+    width: 100%;
+    height: 62px;
+    background-size: 100% 100%;
+
+    .count-num_inner {
+      width: 100%;
+      height: 100%;
+      padding: 6px 6px 6px 10px;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      border-radius: 8px;
+      background: url('@/assets/images/screenViewBlack/bg-qualty-item.png') center center no-repeat;
+      backdrop-filter: blur(4px);
+      background-size: 100% 100%;
+
+      .title {
+        flex-shrink: 0;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        width: 42px;
+        height: 42px;
+        text-align: center;
+        font-size: 12px;
+        letter-spacing: 0.12px;
+        line-height: 16px;
+        font-family: DingTalk;
+        border-radius: 2px;
+        text-shadow: 0px 0px 4px rgba(201, 253, 243, 0.50) ;
+      }
+
+      .num-group {
+        display: grid;
+        grid-template-columns: repeat(6, minmax(62px, 1fr));
+        gap: 10px;
+        width: 100%;
+        height: 100%;
+        padding-left: 9px;
+        cursor: pointer;
+
+        .item {
+          @include flex(y, center, center);
+          text-align: center;
+
+          .label {
+            color: #fff;
+            font-size: 12px;
+            font-weight: bold;
+            line-height: 16px;
+            text-shadow: 0px 0px 6px #C9FDF3;
+          }
+
+          .num {
+            height: 12px;
+            color: #fff;
+            text-align: center;
+            font-size: 10px;
+            line-height: 14px;
+          }
+
+          &:hover {
+            border-radius: 4px;
+            background: rgba(0, 0, 0, 0.4);
+          }
+        }
+      }
+    }
+
+    .in-water-title {
+      color: #FFFF0E;
+      border-top: 0.5px solid #FBFB3B;
+      background: linear-gradient(180deg, rgba(255, 255, 255, 0.20) 0%, rgba(113, 133, 147, 0.00) 100%);
+    }
+    .out-water-title {
+      color: #68FF0B;
+      border-radius: 2px;
+      border-top: 0.5px solid rgba(114, 247, 32, 0.83);
+      background: linear-gradient(180deg, rgba(255, 255, 255, 0.20) 0%, rgba(113, 133, 147, 0.00) 100%);
+    }
+  }
+
+  .echart-card {
+    color: #415B73;
+    font-size: 12px;
+    font-weight: bold;
+    padding-top: 1.4rem;
+
+    .title {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 14px 0 12px 0;
+
+      .tabs {
+        display: flex;
+
+        .item {
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          font-size: 12px;
+
+          .square-icon {
+            display: inline-block;
+            padding: 1px;
+            border-width: 1px;
+            border-style: solid;
+            background: #fff;
+
+            i {
+              display: block;
+              width: 8px;
+              height: 8px;
+            }
+          }
+        }
+      }
+    }
+
+    .echart-inner {
+      height: 140px;
+    }
+  }
+}
+
+@media (min-height: 1070px) {
+  .echart-card {
+    .echart-inner {
+      height: 160px !important;
+    }
+  }
+}
+</style>

+ 327 - 0
src/views/screen/ScreenViewBlack/components/WaterYield.vue

@@ -0,0 +1,327 @@
+<script setup>
+import { onMounted, onUnmounted, watchEffect, ref, computed } from 'vue';
+import * as echarts from 'echarts';
+import { formatDecimals } from "@/utils/format";
+import LayoutCard from './LayoutCard.vue';
+
+const props = defineProps({
+  screenData: {
+    type: Object,
+    default: []
+  }
+})
+
+let timer = null;
+let chart = null;
+const echartRef = ref(null);
+const outWaterData = ref([]);
+const inWaterData = ref([]);
+const totalNum = ref(0)
+
+const waterYield = computed(() => {
+  if ( !totalNum.value ) return [0];
+  return totalNum.value.toFixed(0).split('');
+})
+
+const initEchart = () => {
+  const option = {
+    tooltip: {
+      trigger: 'axis',
+    },
+    grid: {
+      bottom: "20%",
+      top: "6%",
+      left: "12%",
+      right: "0%",
+    },
+    xAxis: [
+      {
+        type: "category",
+        data: ['瞬时 m³/h', '昨日累计 m³/h', '周均值 m³/h'],
+        axisLabel: {
+          interval: 0,
+          show: true,
+          fontSize: '12px',
+          color: "#fff",
+        },
+        axisLine: {
+          show: true,
+          lineStyle: {
+            type: 'dashed',
+            show: true,
+            color: "#3f4a59",
+          },
+        },
+        axisTick: {
+          show: false,
+        },
+      },
+    ],
+    yAxis: [
+      {
+        splitNumber: 2,
+        type: "value",
+        axisLabel: {
+          show: true,
+          fontSize: '12px',
+          color: "#fff",
+
+        },
+        axisLine: {
+          show: false,
+          lineStyle: {
+            color: "#BDD4E8",
+          },
+        },
+        axisTick: {
+          show: false,
+        },
+        splitLine: {
+          lineStyle: {
+            color: "#3f4a59",
+            type: "dashed",
+          },
+        },
+      },
+      {
+         type: "category",
+         show: false,
+         data: outWaterData.value,
+      },
+    ],
+    series: [
+      {
+        name: "出水",
+        type: "bar",
+        showBackground: true,
+        itemStyle: {
+          borderRadius: [2, 2, 0, 0],
+          color: {
+            x: 0,
+            y: 0,
+            x2: 0,
+            y2: 1,
+            colorStops: [
+              {
+                offset: 0,
+                color: "#3877f7",
+              },
+              {
+                offset: 1,
+                color: "#71e1fb",
+              },
+            ],
+          },
+        },
+        barWidth: 10,
+        data: outWaterData.value,
+      },
+      {
+        name: "进水",
+        type: "bar",
+        showBackground: true,
+        itemStyle: {
+          color: {
+            x: 0,
+            y: 0,
+            x2: 0,
+            y2: 1,
+            colorStops: [
+              {
+                offset: 0,
+                color: "#f4bb44",
+              },
+              {
+                offset: 1,
+                color: "#fdf260",
+              },
+            ],
+          },
+        },
+        barWidth: 10,
+        data: inWaterData.value,
+      },
+    ]
+  }
+  chart && chart.setOption(option)
+}
+
+const windowResize = () => {
+  clearTimeout(timer);
+  timer = setTimeout(() => chart.resize(), 100);
+};
+
+watchEffect(() => {
+  const { jsSlq, zrZJSL, szZJSAvg, csSlqc, zrZCSL, szZCSAvg, totalTodayCSL } = props.screenData;
+  inWaterData.value = [formatDecimals(jsSlq), formatDecimals(zrZJSL ? zrZJSL / 24 : zrZJSL), formatDecimals(szZJSAvg ? szZJSAvg / 24 : szZJSAvg)];
+  outWaterData.value = [formatDecimals(csSlqc), formatDecimals(zrZCSL ? zrZCSL / 24 : zrZCSL), formatDecimals(szZCSAvg ? szZCSAvg / 24 : szZCSAvg)];
+  totalNum.value = totalTodayCSL;
+  initEchart();
+})
+
+onMounted(() => {
+  chart = echarts.init(echartRef.value, 'light');
+  window.addEventListener("resize", windowResize);
+})
+
+onUnmounted(() => {
+  window.removeEventListener("resize", windowResize);
+})
+
+</script>
+
+<template>
+  <LayoutCard title="水量数据" name="yield">
+    <div class="main-container">
+      <div class="count-card">
+        <div class="count-num_inner">
+          <span class="count-title">今日累计出水水量</span>
+          <div class="count-value">
+            <ul class="num-group flex space-x-[4px]">
+              <li class="item" v-for="item, index in waterYield" :key="index"><span class="num">{{ item }}</span></li>
+            </ul>
+            <span class="unit">m³</span>
+          </div>
+        </div>
+      </div>
+      <div class="echart-card">
+        <div class="title">
+          <span>进出水·流量分析</span>
+          <ul class="tabs space-x-[18px]">
+            <li class="item space-x-[6px]">
+              <span class="square-icon border-[#9fcbf2]"><i class="bg-[#5faeeb]"></i></span>
+              <span>出水</span>
+            </li>
+            <li class="item space-x-[6px]">
+              <span class="square-icon border-[#f4e28c]"><i class="bg-[#eed056]"></i></span>
+              <span>进水</span>
+            </li>
+          </ul>
+        </div>
+        <div class="echart-inner" ref="echartRef"></div>
+      </div>
+    </div>
+  </LayoutCard>
+</template>
+
+<style lang="scss" scoped>
+.main-container {
+  width: 100%;
+  overflow: hidden;
+
+  .count-card {
+    width: 100%;
+    height: 62px;
+    padding: 4px;
+    background: url('@/assets/images/screenViewBlack/bg-title-first.png') center center no-repeat;
+    background-size: 100% 100%;
+
+    .count-num_inner {
+      width: 100%;
+      height: 100%;
+      padding: 0 0 0 20px;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+
+      .count-title {
+        color: #FFF;
+        font-family: "DingTalk";
+        font-size: 20px;
+      }
+
+      .count-value {
+        display: flex;
+        align-items: flex-end;
+
+        .num-group {
+          display: flex;
+          align-items: flex-end;
+          color: #FFF;
+          text-align: center;
+          font-family: D-DIN-PRO-700-Bold;
+          font-size: 30px;
+          font-weight: bold;
+          letter-spacing: 0.3px;
+
+          .item {
+            position: relative;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            width: 28px;
+            height: 38px;
+            border-radius: 3px;
+            border: 1px solid rgba(79, 211, 255, 0.24);
+            background: linear-gradient(0deg, rgba(17, 88, 138, 0.00) 0%, rgba(18, 89, 139, 0.01) 19%, rgba(22, 94, 143, 0.05) 32%, rgba(29, 103, 150, 0.11) 44%, rgba(38, 116, 160, 0.20) 54%, rgba(51, 132, 173, 0.31) 64%, rgba(66, 152, 190, 0.44) 74%, rgba(84, 175, 209, 0.61) 83%, rgba(104, 202, 230, 0.79) 92%, #80E8FF 100%);
+
+            .num {
+              position: relative;
+              z-index: 1;
+              background: linear-gradient(180deg, #FFF 0%, #FFF 61.52%, #59BDFF 83.33%);
+              background-clip: text;
+              -webkit-background-clip: text;
+              -webkit-text-fill-color: transparent;
+            }
+          }
+        }
+
+        .unit {
+          margin-left: 8px;
+          color: #fff;
+          text-align: center;
+          font-family: D-DIN-PRO;
+          font-size: 24px;
+          line-height: normal;
+          font-weight: bold;
+          line-height: 28px;
+        }
+      }
+    }
+  }
+
+  .echart-card {
+    color: #fff;
+    font-size: 12px;
+    font-weight: bold;
+
+    .title {
+      flex-shrink: 0;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 14px 0 12px 0;
+      font-weight: bold;
+
+      .tabs {
+        display: flex;
+
+        .item {
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          font-size: 12px;
+          font-weight: normal;
+
+          .square-icon {
+            display: inline-block;
+            padding: 1px;
+            border-width: 1px;
+            border-style: solid;
+            background: #fff;
+
+            i {
+              display: block;
+              width: 8px;
+              height: 8px;
+            }
+          }
+        }
+      }
+    }
+    .echart-inner {
+      height: 116px;
+    }
+  }
+}
+</style>

+ 103 - 0
src/views/screen/ScreenViewBlack/components/dataBox.vue

@@ -0,0 +1,103 @@
+<script setup>
+import LayoutCard from './LayoutCard.vue';
+import ChatText from '@/components/Chat/ChatText.vue';
+defineProps({
+  reportData: {
+    type: Object,
+    default: {}
+  },
+})
+</script>
+
+<template>
+  <LayoutCard title="数据分析" class="data-box" name="data" width="100%">
+    <template #headerRight>
+      <RouterLink to="/work-order" class="flex items-center space-x-[4px] text-[14px]">
+        <div class="jump-btn"></div>
+      </RouterLink>
+    </template>
+    <div class="data-box-main">
+      <div class="content">
+        <h5 class="title">{{ reportData.showVal }}</h5>
+        <div class="markdown-inner">
+          <ChatText :content="reportData.answer" class="html-box"></ChatText>
+        </div>
+      </div>
+    </div>
+  </LayoutCard>
+</template>
+
+<style scoped lang="scss">
+.jump-btn {
+  display: inline-block;
+  width: 50px;
+  height: 20px;
+}
+.data-box {
+  &-main {
+    height: 210px;
+    padding: 18px 25px 16px 40px;
+    display: flex;
+    align-items: center;
+    flex-direction: column;
+
+    .content {
+      width: 100%;
+      .markdown-inner {
+        width: 100%;
+        height: 160px;
+        overflow-y: scroll;
+
+        &::-webkit-scrollbar-track {
+          background-color: rgba(255, 255, 255, 0.3);
+        }
+      }
+
+      .title {
+        margin-bottom: 16px;
+        font-size: 16px;
+        font-weight: bold;
+        color: #fff;
+        text-shadow: 0px 0px 8px #C9FDF3;
+      }
+
+      .html-box {
+        font-size: 14px;
+        color: #fff;
+      }
+
+      .markdown-body {
+        background: initial;
+      }
+    }
+
+    .btn {
+      width: 124px;
+      height: 44px;
+      background: linear-gradient(270deg, #59CCFA 0%, #3C97F7 100%);
+      font-size: 16px;
+      font-weight: 500;
+      color: #fff;
+      border-radius: 4px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-top: 20px;
+    }
+  }
+}
+
+@media (min-height: 1070px) {
+  .data-box {
+    .data-box-main {
+      height: 230px !important;
+    }
+  }
+}
+</style>
+
+<style>
+.data-box .data-box-main .content .markdown-body .custom-table-wrapper {
+  width: 450px !important;
+}
+</style>

+ 120 - 0
src/views/screen/ScreenViewBlack/components/gongyi.vue

@@ -0,0 +1,120 @@
+<script setup>
+import { useRouter } from 'vue-router';
+import LayoutCard from './LayoutCard.vue';
+
+defineProps({
+  gongyiData: {
+    type: Array,
+    default: []
+  }
+})
+
+const router = useRouter()
+const types = ['水质报警', '生化报警', '预测报警']
+const toGongyi = (item) => {
+  router.push('water-warn');
+}
+
+</script>
+
+<template>
+  <LayoutCard title="工艺管控助手" name="gongyi" width="100%">
+    <template #headerRight>
+      <RouterLink to="/water-warn" class="flex items-center space-x-[0.4rem] text-[14px]">
+        <div class="jump-btn"></div>
+      </RouterLink>
+    </template>
+    <div class="gongyi-wrap">
+      <div class="gongyi-wrap-top gongyi-wrap-item">
+        <span>告警类型</span>
+        <span>告警信息</span>
+        <span>触发时间</span>
+      </div>
+      <ul class="gongyi-wrap-list">
+        <li class="gongyi-wrap-item" v-for="item in gongyiData" @click="toGongyi">
+          <span>{{ types[item.type] }}</span>
+          <span>{{ item.reason }}</span>
+          <span>{{ item.time }}</span>
+        </li>
+      </ul>
+    </div>
+  </LayoutCard>
+</template>
+
+<style scoped lang="scss">
+.jump-btn {
+  display: inline-block;
+  width: 50px;
+  height: 20px;
+}
+
+.gongyi-wrap {
+  padding: 12px;
+
+  &-list {
+    height: 100px;
+    overflow-y: auto;
+
+    &::-webkit-scrollbar {
+      width: 0px !important;
+    }
+  }
+
+  &-item {
+    margin-bottom: 10px;
+    padding: 10px 12px;
+    display: flex;
+    line-height: 14px;
+    background: rgba(97, 163, 217, 0.10);
+    justify-content: space-between;
+    align-items: center;
+    color: #fff;
+    cursor: pointer;
+    font-size: 14px;
+
+    span {
+      text-overflow: ellipsis;
+      overflow: hidden;
+      word-break: break-all;
+      white-space: nowrap;
+    }
+
+    >span {
+      flex: 1;
+    }
+
+    >span:nth-child(2) {
+      text-align: center;
+    }
+
+    >span:last-child {
+      text-align: right;
+    }
+  }
+
+  &-top {
+    background: rgba(13, 80, 135, 0.60);
+    font-size: 14px;
+    color: #fff;
+    font-weight: bold;
+  }
+
+  .warning,
+  &-item:hover {
+    color: #F15A24;
+  }
+
+  &-top:hover {
+    color: #fff;
+  }
+}
+
+@media (min-height: 1070px) {
+  .gongyi-wrap {
+    padding: 12px 12px 0 12px;
+    .gongyi-wrap-list {
+      height: 134px;
+    }
+  }
+}
+</style>

+ 768 - 0
src/views/screen/ScreenViewBlack/config/echartOption.js

@@ -0,0 +1,768 @@
+export const getBarOptions = (currentData = []) => {
+  const xAxis = ["1#好氧池硝酸盐", "2#好氧池硝酸盐", "1#缺氧氨氮", "2#缺氧氨氮", "二沉池正磷酸盐"];
+  const rangeData = [12, 12, 15, 15, 0.4];
+
+  let option = {
+    tooltip: {
+      trigger: 'axis',
+    },
+    grid: {
+      bottom: '4%',
+      top: "6%",
+      left: "5%",
+      right: "2%",
+      containLabel: true,
+      // bottom: "4%",
+      // top: "6%",
+      // left: "10%",
+      // right: "2%",
+    },
+    legend: {
+      show: false,
+    },
+    xAxis: [
+      {
+        type: "category",
+        data: xAxis,
+        axisLabel: {
+          interval: 0,
+          show: true,
+          fontSize: '12px',
+          color: "#fff",
+        },
+        axisLine: {
+          show: true,
+          lineStyle: {
+            show: true,
+            color: "#3f4a59",
+          },
+        },
+        axisTick: {
+          show: false,
+        },
+      },
+
+    ],
+    yAxis: [
+      {
+        splitNumber: 4,
+        type: "value",
+        axisLabel: {
+          show: true,
+          fontSize: '12px',
+          color: "#fff"
+        },
+        axisLine: {
+          show: false,
+          lineStyle: {
+            color: "#3f4a59",
+          },
+        },
+        axisTick: {
+          show: false,
+        },
+        splitLine: {
+          lineStyle: {
+            color: "#3f4a59",
+          },
+        }
+      },
+    ],
+    series: [
+      {
+        name: 'custom',
+        type: 'custom',
+        itemStyle: {
+          color: 'rgba(216, 230, 255, .1)'
+        },
+        tooltip: {
+          show: false // 禁用该系列的 tooltip
+      },
+        renderItem: function (params, api) {
+          //获取对应类目的axisTick中心点坐标
+          var start = api.coord([api.value(0)])
+
+          //通过坐标系的宽度和类目数,计算单个类目的背景
+          var width = (params.coordSys.width / 7) * 0.7
+
+          return {
+            type: 'rect',
+            shape: {
+              // 相对左上角坐标
+              x: start[0] - width / 2,
+              y: params.coordSys.y,
+              width: width,
+              height: params.coordSys.height
+            },
+            style: api.style()
+          }
+        },
+        data: currentData.map(() => 0)
+      },
+      {
+        name: "当前值",
+        type: "bar",
+        itemStyle: {
+          borderRadius: [2, 2, 0, 0],
+          color: {
+            x: 0,
+            y: 0,
+            x2: 0,
+            y2: 1,
+            colorStops: [
+              {
+                offset: 0,
+                color: "#FBB03B",
+              },
+              {
+                offset: 1,
+                color: "rgba(246,115,7, 0.1)",
+              },
+            ],
+          },
+        },
+        barWidth: 8,
+        data: currentData,
+      },
+      {
+        name: "标准值",
+        type: "bar",
+        itemStyle: {
+          color: {
+            x: 0,
+            y: 0,
+            x2: 0,
+            y2: 1,
+            colorStops: [
+              {
+                offset: 0,
+                color: "#17FFC9",
+              },
+              {
+                offset: 1,
+                color: "rgba(10,184,4, 0.1)",
+              },
+            ],
+          },
+        },
+        barWidth: 8,
+        // 展示柱图背景
+        data: rangeData,
+      },
+      {
+        // 柱形顶部色块
+        name: '',
+        type: 'pictorialBar',
+        itemStyle: {
+          normal: {
+            color: '#fff'
+          }
+        },
+        tooltip: {
+          show: false
+        },
+        symbolRepeat: false,
+        symbolMargin: 8,
+        symbol: 'rect',
+        symbolClip: false,
+        symbolSize: [7, 2],
+        symbolPosition: 'end',
+        symbolOffset: [-5, -3],
+        data: currentData,
+        width: 1,
+        z: 0,
+        zlevel: 1
+      },
+      {
+        // 柱形顶部色块
+        name: '',
+        type: 'pictorialBar',
+        itemStyle: {
+          normal: {
+            color: '#fff'
+          }
+        },
+        tooltip: {
+          show: false
+        },
+        symbolRepeat: false,
+        symbolMargin: 8,
+        symbol: 'rect',
+        symbolClip: false,
+        symbolSize: [7, 2],
+        symbolPosition: 'end',
+        symbolOffset: [5, -3],
+        data: rangeData,
+        width: 1,
+        z: 0,
+        zlevel: 1
+      },
+    ],
+  };
+
+  return option;
+}
+
+export const getPieOptions = (optionsData) => {
+  let colors = ['#00A0E9', '#00AB84', '#C6A3FF', '#E9D0A1', '#45D3F2']
+
+  function getParametricEquation(
+    startRatio,
+    endRatio,
+    isSelected,
+    isHovered,
+    k,
+    height,
+    i
+  ) {
+    // 计算
+    let midRatio = (startRatio + endRatio) / 2;
+  
+    let startRadian = startRatio * Math.PI * 2;
+    let endRadian = endRatio * Math.PI * 2;
+    let midRadian = midRatio * Math.PI * 2;
+  
+    // 如果只有一个扇形,则不实现选中效果。
+    if (startRatio === 0 && endRatio === 1) {
+      isSelected = false;
+    }
+  
+    // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)
+    k = typeof k !== "undefined" ? k : 1 / 3;
+  
+    // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)
+    let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
+    let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
+    let offsetZ = i == 1 ? 2 : 0;
+    // 计算高亮效果的放大比例(未高亮,则比例为 1)
+    let hoverRate = isHovered ? 1.05 : 1;
+  
+    // 返回曲面参数方程
+    return {
+      u: {
+        min: -Math.PI,
+        max: Math.PI * 3,
+        step: Math.PI / 32,
+      },
+  
+      v: {
+        min: 0,
+        max: Math.PI * 2,
+        step: Math.PI / 20,
+      },
+  
+      x: function (u, v) {
+        if (u < startRadian) {
+          return (
+            offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate
+          );
+        }
+        if (u > endRadian) {
+          return (
+            offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate
+          );
+        }
+        return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
+      },
+  
+      y: function (u, v) {
+        if (u < startRadian) {
+          return (
+            offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate
+          );
+        }
+        if (u > endRadian) {
+          return (
+            offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate
+          );
+        }
+        return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
+      },
+  
+      z: function (u, v) {
+        if (u < -Math.PI * 0.5) {
+          return Math.sin(u);
+        }
+        if (u > Math.PI * 2.5) {
+          return Math.sin(u);
+        }
+        return Math.sin(v) > 0 ? 1 * height : -1;
+      },
+    };
+  }
+  // 生成模拟 3D 饼图的配置项
+  function getPie3D(pieData, internalDiameterRatio) {
+    let series = [];
+    let sumValue = 0;
+    let startValue = 0;
+    let endValue = 0;
+    let legendData = [];
+    let k =
+      typeof internalDiameterRatio !== "undefined"
+        ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio)
+        : 1 / 3;
+  
+    // 为每一个饼图数据,生成一个 series-surface 配置
+    for (let i = 0; i < pieData.length - 1; i++) {
+      sumValue += pieData[i].value;
+  
+      let seriesItem = {
+        name:
+          typeof pieData[i].name === "undefined"
+            ? `series${i}`
+            : pieData[i].name,
+        type: "surface",
+        parametric: true,
+        wireframe: {
+          show: false,
+        },
+        pieData: pieData[i],
+        itemStyle: {
+          color: pieData[i].color, // 自定义颜色
+          opacity: '0.7'
+        },
+        pieStatus: {
+          selected: false,
+          hovered: false,
+          k: k,
+        },
+      };
+  
+      if (typeof pieData[i].itemStyle != "undefined") {
+        let itemStyle = {};
+  
+        typeof pieData[i].itemStyle.color != "undefined"
+          ? (itemStyle.color = pieData[i].itemStyle.color)
+          : null;
+        typeof pieData[i].itemStyle.opacity != "undefined"
+          ? (itemStyle.opacity = pieData[i].itemStyle.opacity)
+          : null;
+  
+        seriesItem.itemStyle = itemStyle;
+      }
+      series.push(seriesItem);
+    }
+  
+    for (let i = 0; i < series.length; i++) {
+      endValue = startValue + series[i].pieData.value;
+      series[i].pieData.startRatio = startValue / sumValue;
+      series[i].pieData.endRatio = endValue / sumValue;
+      series[i].parametricEquation = getParametricEquation(
+        series[i].pieData.startRatio,
+        series[i].pieData.endRatio,
+        false,
+        false,
+        k,
+        // 调整扇形高度
+        i === 0 ? 10 : 10,
+        i,
+        series[i].pieData.value
+      );
+  
+      startValue = endValue;
+  
+      legendData.push(series[i].name);
+    }
+    return series;
+  }
+  
+  const series = getPie3D(optionsData, 0.6); // 可做为调整内环大小 0为实心圆饼图,大于0 小于1 为圆环
+  series.push({
+    name: "pie2d",
+    type: "pie",
+    startAngle: 2, //起始角度,支持范围[0, 360]。
+    clockwise: false, //饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
+    // radius: ["50%", "60%"],
+    // center: ["62%", "50%"],
+    data: optionsData,
+    itemStyle: {
+      opacity: 0,
+    },
+    labelLine: {
+      show: false
+    },
+    label: {
+      show: false,
+      position: 'center'
+    },
+  });
+  // 准备待返回的配置项,把准备好的 legendData、series 传入。
+  let option = {
+    animation: true,
+    tooltip: {
+      formatter: (params) => {
+         if (params.seriesName !== 'mouseoutSeries') {
+          const { name, value, color} = optionsData[params.seriesIndex] ?? {};
+            return `${name
+               }<br/><span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${color
+               };"></span>${value}` ;
+         }
+      },
+   },
+    title: {
+      x: "center",
+      top: "20",
+      textStyle: {
+        color: "#fff",
+        fontSize: 22,
+      },
+    },
+    xAxis3D: {
+      min: -1,
+      max: 1,
+    },
+    yAxis3D: {
+      min: -1,
+      max: 1,
+    },
+    zAxis3D: {
+      min: -1,
+      max: 1,
+    },
+    grid3D: {
+      show: false,
+      boxHeight: 2.5,
+      top: '-10%',
+      // left: "8%",
+      // bottom: "50%",
+      viewControl: {
+        // alpha: 38,
+        // beta: 70,
+        enabled: true,
+        alpha: 30,
+        beta: 55,
+        distance: 150,
+        rotateSensitivity: 0, //设置为0无法旋转
+        zoomSensitivity: 0, //设置为0无法缩放
+        panSensitivity: 0, //设置为0无法平移
+        autoRotate: false, //自动旋转
+        
+        
+        // beta: 325,
+      //   autoRotate: false, // 自动旋转
+      },
+    },
+    series: series,
+  };
+
+  // return option
+
+  // let colors = ['#16d0ff', '#664bff', '#37a2da', '#ffdb5c', '#ff9f7f', '#9fe6b8', '#67e0e3', '#32c5e9', '#fb7293', "#9A60B4", "#ea7ccc"]
+  // // 传入数据生成 option
+  // const optionsData = [
+  //   {
+  //     name: "第一科室",
+  //     value: 68,
+  //   },
+  //   {
+  //     name: "第二科室",
+  //     value: 52,
+  //   },
+  //   {
+  //     name: "第三科室",
+  //     value: 37,
+  //   },
+  //   {
+  //     name: "第四科室",
+  //     value: 58,
+  //   },
+  // ];
+  // function getParametricEquation(
+  //   startRatio,
+  //   endRatio,
+  //   isSelected,
+  //   isHovered,
+  //   k,
+  //   height,
+  //   i
+  // ) {
+  //   // 计算
+  //   let midRatio = (startRatio + endRatio) / 2;
+  
+  //   let startRadian = startRatio * Math.PI * 2;
+  //   let endRadian = endRatio * Math.PI * 2;
+  //   let midRadian = midRatio * Math.PI * 2;
+  
+  //   // 如果只有一个扇形,则不实现选中效果。
+  //   if (startRatio === 0 && endRatio === 1) {
+  //     isSelected = false;
+  //   }
+  
+  //   // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)
+  //   k = typeof k !== "undefined" ? k : 1 / 3;
+  
+  //   // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)
+  //   let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
+  //   let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
+  //   let offsetZ = i == 1 ? 2 : 0;
+  //   // 计算高亮效果的放大比例(未高亮,则比例为 1)
+  //   let hoverRate = isHovered ? 1.05 : 1;
+  
+  //   // 返回曲面参数方程
+  //   return {
+  //     u: {
+  //       min: -Math.PI,
+  //       max: Math.PI * 3,
+  //       step: Math.PI / 32,
+  //     },
+  
+  //     v: {
+  //       min: 0,
+  //       max: Math.PI * 2,
+  //       step: Math.PI / 20,
+  //     },
+  
+  //     x: function (u, v) {
+  //       if (u < startRadian) {
+  //         return (
+  //           offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate
+  //         );
+  //       }
+  //       if (u > endRadian) {
+  //         return (
+  //           offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate
+  //         );
+  //       }
+  //       return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
+  //     },
+  
+  //     y: function (u, v) {
+  //       if (u < startRadian) {
+  //         return (
+  //           offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate
+  //         );
+  //       }
+  //       if (u > endRadian) {
+  //         return (
+  //           offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate
+  //         );
+  //       }
+  //       return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
+  //     },
+  
+  //     z: function (u, v) {
+  //       if (u < -Math.PI * 0.5) {
+  //         return Math.sin(u);
+  //       }
+  //       if (u > Math.PI * 2.5) {
+  //         return Math.sin(u);
+  //       }
+  //       return Math.sin(v) > 0 ? 1 * height : -1;
+  //     },
+  //   };
+  // }
+  // // 生成模拟 3D 饼图的配置项
+  // function getPie3D(pieData, internalDiameterRatio) {
+  //   let series = [];
+  //   let sumValue = 0;
+  //   let startValue = 0;
+  //   let endValue = 0;
+  //   let legendData = [];
+  //   let k =
+  //     typeof internalDiameterRatio !== "undefined"
+  //       ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio)
+  //       : 1 / 3;
+  
+  //   // 为每一个饼图数据,生成一个 series-surface 配置
+  //   for (let i = 0; i < pieData.length; i++) {
+  //     sumValue += pieData[i].value;
+  
+  //     let seriesItem = {
+  //       name:
+  //         typeof pieData[i].name === "undefined"
+  //           ? `series${i}`
+  //           : pieData[i].name,
+  //       type: "surface",
+  //       parametric: true,
+  //       wireframe: {
+  //         show: false,
+  //       },
+  //       pieData: pieData[i],
+  //       itemStyle: {
+  //         color: colors[i], // 自定义颜色
+  //         opacity: '0.7'
+  //       },
+  //       pieStatus: {
+  //         selected: false,
+  //         hovered: false,
+  //         k: k,
+  //       },
+  //     };
+  
+  //     if (typeof pieData[i].itemStyle != "undefined") {
+  //       let itemStyle = {};
+  
+  //       typeof pieData[i].itemStyle.color != "undefined"
+  //         ? (itemStyle.color = pieData[i].itemStyle.color)
+  //         : null;
+  //       typeof pieData[i].itemStyle.opacity != "undefined"
+  //         ? (itemStyle.opacity = pieData[i].itemStyle.opacity)
+  //         : null;
+  
+  //       seriesItem.itemStyle = itemStyle;
+  //     }
+  //     series.push(seriesItem);
+  //   }
+  
+  //   // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
+  //   // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
+  //   for (let i = 0; i < series.length; i++) {
+  //     endValue = startValue + series[i].pieData.value;
+  //     console.log(series[i]);
+  //     series[i].pieData.startRatio = startValue / sumValue;
+  //     series[i].pieData.endRatio = endValue / sumValue;
+  //     series[i].parametricEquation = getParametricEquation(
+  //       series[i].pieData.startRatio,
+  //       series[i].pieData.endRatio,
+  //       false,
+  //       false,
+  //       k,
+  //       // 调整扇形高度
+  //       i === 0 ? 10 : 10,
+  //       i,
+  //       series[i].pieData.value
+  //     );
+  
+  //     startValue = endValue;
+  
+  //     legendData.push(series[i].name);
+  //   }
+  //   return series;
+  // }
+  
+  // const series = getPie3D(optionsData, 0.6); // 可做为调整内环大小 0为实心圆饼图,大于0 小于1 为圆环
+  // series.push({
+  //   name: "pie2d",
+  //   type: "pie",
+  //   label: {
+  //     opacity: 1,
+  //     fontSize: 14,
+  //     lineHeight: 20,
+  //     textStyle: {
+  //       fontSize: 14,
+  //       color: "#fff",
+  //     },
+  //   },
+  //   labelLine: {
+  //     length: 10,
+  //     length2: 10,
+  //   },
+  //   startAngle: 2, //起始角度,支持范围[0, 360]。
+  //   clockwise: false, //饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
+  //   radius: ["50%", "60%"],
+  //   center: ["62%", "50%"],
+  //   data: optionsData,
+  //   itemStyle: {
+  //     opacity: 0,
+  //   },
+  //   labelLine: {
+  //     show: false
+  //   },
+  //   label: {
+  //     show: false,
+  //     position: 'center'
+  //   },
+  // });
+  // // 准备待返回的配置项,把准备好的 legendData、series 传入。
+  // let option = {
+    
+  //   animation: true,
+  //   tooltip: {
+  //     show: false,
+  //     textStyle: {
+  //       fontSize: 14,
+  //     },
+  //   },
+  //   title: {
+  //     x: "center",
+  //     top: "20",
+  //     textStyle: {
+  //       color: "#fff",
+  //       fontSize: 22,
+  //     },
+  //   },
+  //   labelLine: {
+  //     show: true,
+  //     lineStyle: {
+  //       color: "#7BC0CB",
+  //     },
+  //     normal: {
+  //       show: false,
+  //       length: 10,
+  //       length2: 10,
+  //     },
+  //   },
+  //   label: {
+  //     show: true,
+  //     position: "outside",
+  //     // formatter: "{b} {d}%",
+  //     formatter: function (optionsData) {
+  //       console.log('optionsData', optionsData)
+  //       return (
+  //         "{name|" +
+  //         optionsData.name +
+  //         "}" +
+  //         " {value|" +
+  //         optionsData.percent.toFixed(0) +
+  //         "%}"
+  //       );
+  //     },
+  //     rich: {
+  //       name: {
+  //         fontSize: 14,
+  //         color: "#ffffff",
+  //       },
+  //       value: {
+  //         fontSize: 14,
+  //         color: "#ffffff",
+  //       },
+  //     },
+  //     textStyle: {
+  //       color: "#fff",
+  //       fontSize: "14px",
+  //     },
+  //   },
+  //   xAxis3D: {
+  //     min: -1,
+  //     max: 1,
+  //   },
+  //   yAxis3D: {
+  //     min: -1,
+  //     max: 1,
+  //   },
+  //   zAxis3D: {
+  //     min: -1,
+  //     max: 1,
+  //   },
+  //   grid3D: {
+  //     show: false,
+  //     boxHeight: 2,
+  //     top: '-10%',
+  //     // left: "8%",
+  //     // bottom: "50%",
+  //     // environment: "rgba(255,255,255,0)",
+  //     viewControl: {
+  //       alpha: 30,
+  //       distance: 150,
+  //       beta: 15,
+  //       autoRotate: false, // 自动旋转
+
+  // //       // alpha: 38,
+  // //       // beta: 70,
+  // //       enabled: true,
+  // //       alpha: 30,
+  // //       beta: 30,
+  // //       distance: 150,
+  // //       rotateSensitivity: 0, //设置为0无法旋转
+  // //       zoomSensitivity: 0, //设置为0无法缩放
+  // //       panSensitivity: 0, //设置为0无法平移
+  // //       autoRotate: false, //自动旋转
+        
+  //     },
+  //   },
+  //   series: series,
+  // };
+
+  return option;
+
+}

+ 452 - 0
src/views/screen/ScreenViewBlack/index.vue

@@ -0,0 +1,452 @@
+<script setup>
+import { ref, onMounted, onUnmounted } from "vue";
+import autofit from 'autofit.js';
+import dayjs from 'dayjs';
+
+import WaterYield from "./components/WaterYield";
+import WaterQuality from "./components/WaterQuality";
+import ContinueData from "./components/ContinueData";
+import DataBox from "./components/dataBox";
+import GongYi from "./components/gongyi";
+
+import { editPassword } from '@/components';
+import TheUserAvatar from '@/components/Layout/TheUserAvatar.vue';
+import { screenApi } from "@/api/screen"
+
+let timer = "";
+let dataTimer = "";
+
+const updateTime = ref();
+const gongyiData = ref([])
+const screenData = ref({});
+const reportData = ref({})
+
+const currentTime = ref({
+  time: '',
+  weekday: '',
+  date: '',
+})
+
+// 日期 - header使用
+const getCurrentWeekDay = () => {
+  const weekEnum = { 0: '星期日', 1: '星期一', 2: '星期二', 3: '星期三', 4: '星期四', 5: '星期五', 6: '星期六' };
+  const time = dayjs(new Date()).format('HH:mm:ss');
+  const weekday = weekEnum[dayjs().day()];
+  const date = dayjs().format('YYYY-MM-DD');
+  currentTime.value = { time, weekday, date };
+}
+
+
+// 获取大屏分析数据
+const getRealTimeData = () => {
+  screenApi.realTimeData().then(res => {
+    screenData.value = res.data;
+    updateTime.value = `更新时间:${res.data.testHour}`
+  })
+}
+
+// 获取工艺管控 助手
+const getWarningList = () => {
+  screenApi.warningList().then(res => {
+    gongyiData.value = res.data || []
+  })
+}
+
+// 获取文字数据
+const getLeastShortReport = () => {
+  screenApi.getLeastShortReport().then(res => {
+    reportData.value = res.data
+  })
+}
+
+onMounted(() => {
+  // 时钟开始计时
+  getCurrentWeekDay();
+  // 图表数据
+  getRealTimeData();
+  // 文字数据
+  getLeastShortReport();
+  // 工艺
+  getWarningList();
+
+  autofit.init({
+    dw: 1920,
+    dh: 1080,
+    el: "#screen-view-black",
+    resize: true,
+  })
+
+  timer = setInterval(getCurrentWeekDay, 1 * 1000);
+
+  dataTimer = setInterval(() => {
+    getRealTimeData();
+    getLeastShortReport();
+    getWarningList();
+  }, 60 * 60 * 1000);
+})
+
+onUnmounted(() => {
+  clearInterval(timer);
+  clearInterval(dataTimer);
+})
+
+</script>
+
+<template>
+  <div class="screen-view-black" id="screen-view-black">
+    <header class="header">
+      <div class="header-left">
+        <div class="time">{{ currentTime.time }}</div>
+        <div class="line"></div>
+        <ul class="date">
+          <li>{{ currentTime.weekday }}</li>
+          <li>{{ currentTime.date }}</li>
+        </ul>
+      </div>
+      <div class="header-right flex items-center justify-end pr-[18px]">
+        <div class="select-factory"></div>
+        <TheUserAvatar></TheUserAvatar>
+        <editPassword></editPassword>
+      </div>
+    </header>
+    <main class="main">
+      <!-- 导航菜单 -->
+      <div class="menu-container">
+        <ul class="menu-list justify-end">
+          <li class="item mr-[20px] active">
+            <RouterLink to="/"><span>智慧总控</span></RouterLink>
+          </li>
+          <li class="item">
+            <RouterLink to="/answer"><span>专家问答</span></RouterLink>
+          </li>
+        </ul>
+        <ul class="menu-list justify-start">
+          <li class="item mr-[20px]">
+            <RouterLink to="/water-warn"><span>智能分析</span></RouterLink>
+          </li>
+          <li class="item">
+            <RouterLink to="/work"><span>智能助手</span></RouterLink>
+          </li>
+        </ul>
+      </div>
+      <div class="screen-container">
+        <div class="factory">
+          <img class="w-full h-full" src="@/assets/images/screenViewBlack/img-factory.png" alt="">
+          <img class="coord img-a" src="@/assets/images/screenViewBlack/img-coord-a.png" alt="">
+          <img class="coord img-b" src="@/assets/images/screenViewBlack/img-coord-b.png" alt="">
+          <img class="coord img-c" src="@/assets/images/screenViewBlack/img-coord-c.png" alt="">
+        </div>
+        <div class="content">
+          <div class="left">
+            <WaterYield :screenData="screenData"></WaterYield>
+            <WaterQuality :screenData="screenData" class="pt-[20px]"></WaterQuality>
+          </div>
+          <div class="middle">
+            <div class="middle-wrap">
+              <span class="text-[#9E9E9E] pb-[8px] text-[12px]">{{ updateTime }}</span>
+              <RouterLink to="/answer" class="inp-box">
+                <span>输入您的问题或需求</span>
+                <img src="@/assets/images/screenViewBlack/img-start.png" alt="">
+              </RouterLink>
+            </div>
+          </div>
+          <div class="right">
+            <ContinueData :screenData="screenData"></ContinueData>
+            <DataBox :reportData="reportData" class="pt-[20px]"></DataBox>
+            <GongYi :gongyiData="gongyiData"></GongYi>
+          </div>
+        </div>
+      </div>
+    </main>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+// 主体背景颜色
+$primary-bg-color: #040d1c;
+
+.screen-view-black {
+  position: relative;
+  display: flex;
+  flex-flow: column;
+  width: 100vw;
+  height: 100vh;
+  min-width: 1200px;
+  min-height: 700px;
+  background: $primary-bg-color;
+  background-size: 100% 100%;
+  overflow: hidden;
+}
+
+.header {
+  display: flex;
+  align-items: start;
+  justify-content: space-between;
+  flex-shrink: 0;
+  height: 98px;
+  padding: 20px 50px 0 50px;
+  background: url(@/assets/images/screenViewBlack/bg-header.png) center center no-repeat;
+  background-size: 100% 100%;
+
+  .header-left {
+    display: flex;
+    align-items: center;
+
+    .time {
+      width: 160px;
+      color: #FFF;
+      text-shadow: 0px 1px 3px rgba(5, 12, 25, 0.54);
+      font-family: D-DIN-PRO-700-Bold;
+      font-size: 36px;
+      font-style: normal;
+      font-weight: 700;
+      line-height: normal;
+      letter-spacing: 4.32px;
+    }
+
+    .line {
+      width: 1px;
+      height: 28px;
+      margin: 0 20px 0 15px;
+      background: rgba(157, 197, 232, 0.36);
+    }
+
+    .date {
+      color: #CDD6E3;
+      text-align: center;
+      font-size: 16px;
+      font-weight: bold;
+      letter-spacing: 1.92px;
+      line-height: normal;
+      font-style: normal;
+
+      li:nth-child(1) {
+        color: #CDD6E3;
+      }
+
+      li:nth-child(2) {
+        color: #CDD6E3;
+        font-family: D-DIN-PRO-700-Bold;
+        font-size: 12px;
+        letter-spacing: 1.44px;
+      }
+    }
+  }
+
+  .header-right {
+    .select-factory {
+      width: 114px;
+      height: 34px;
+      margin-right: 16px;
+      background: url(@/assets/images/screenViewBlack/bg-select.png) center center no-repeat;
+      background-size: 100% 100%;
+      cursor: pointer;
+    }
+  }
+}
+
+.main {
+  flex: 1;
+  display: flex;
+  flex-flow: column;
+  padding: 0 30px 14px 30px;
+
+  .menu-container {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+
+    .menu-list {
+      display: flex;
+      align-items: center;
+      width: 540px;
+      height: 86px;
+
+      .item {
+        width: 172px;
+        height: 46px;
+        text-align: center;
+        font-family: YouSheBiaoTiHei;
+        font-size: 24px;
+        font-style: normal;
+        font-weight: 400;
+        line-height: 40px;
+        letter-spacing: 1px;
+        cursor: pointer;
+        transition: all 0.8s;
+
+        span {
+          transition: all 0.3s;
+          background: linear-gradient(182deg, #02A3F8 11.72%, #83D2FB 38.89%, #FFF 98.7%);
+          background-clip: text;
+          -webkit-background-clip: text;
+          -webkit-text-fill-color: transparent;
+        }
+      }
+    }
+
+    .menu-list:nth-child(1) {
+      .item {
+        background: url(@/assets/images/screenViewBlack/bg-left.png) center center no-repeat;
+        background-size: 100% 100%;
+
+        &:hover {
+          background: url(@/assets/images/screenViewBlack/bg-left-active.png) center center no-repeat;
+          background-size: 100% 100%;
+
+          span {
+            background: linear-gradient(182deg, #00FFE4, #FFF 78.7%);
+            background-clip: text;
+          }
+        }
+      }
+
+      .active {
+        background: url(@/assets/images/screenViewBlack/bg-left-active.png) center center no-repeat;
+        background-size: 100% 100%;
+
+        span {
+          background: linear-gradient(182deg, #00FFE4, #FFF 78.7%);
+          background-clip: text;
+        }
+      }
+    }
+
+    .menu-list:nth-child(2) {
+      .item {
+        background: url(@/assets/images/screenViewBlack/bg-right.png) center center no-repeat;
+        background-size: 100% 100%;
+
+        &:hover {
+          background: url(@/assets/images/screenViewBlack/bg-right-active.png) center center no-repeat;
+          background-size: 100% 100%;
+
+          span {
+            background: linear-gradient(182deg, #00FFE4, #FFF 78.7%);
+            background-clip: text;
+          }
+        }
+      }
+
+      .active {
+        background: url(@/assets/images/screenViewBlack/bg-right-active.png) center center no-repeat;
+        background-size: 100% 100%;
+
+        span {
+          background: linear-gradient(182deg, #00FFE4, #FFF 78.7%);
+          background-clip: text;
+        }
+      }
+    }
+  }
+
+  @keyframes jump {
+    0%, 100% {
+      transform: translateY(0);
+    }
+    50% {
+      transform: translateY(-20px); /* 调整这个值来控制跳跃的高度 */
+    }
+  }
+
+  .screen-container {
+    position: relative;
+    background: $primary-bg-color;
+
+    .factory {
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      width: 1408px;
+      height: 792px;
+
+      .coord {
+        position: absolute;
+        width: 108px;
+        height: 82px;
+      }
+
+      .img-a {
+        top: 370px;
+        left: 320px;
+        animation: jump 1.5s ease-in-out infinite;
+        animation-delay: 0.2s;
+      }
+      .img-b {
+        top: 280px;
+        left: 650px;
+        animation: jump 1.5s ease-in-out infinite;
+        animation-delay: 0.6s;
+      }
+      .img-c {
+        top: 226px;
+        right: 330px;
+        animation: jump 1.5s ease-in-out infinite;
+        animation-delay: 0.4s;
+      }
+    }
+
+    .content {
+      position: relative;
+      display: flex;
+      ;
+      justify-content: space-between;
+
+      .left,
+      .right {
+        width: 540px;
+      }
+
+      .middle {
+        flex-shrink: 0;
+        flex: 1;
+        display: flex;
+        flex-flow: column;
+        justify-content: flex-end;
+        padding: 0 50px 30px 50px;
+
+        .middle-wrap {
+          display: flex;
+          flex-flow: column;
+          align-items: flex-end;
+
+          .inp-box {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            width: 100%;
+            height: 60px;
+            padding: 0 14px;
+            background: url(@/assets/images/screenViewBlack/bg-input.png) center center no-repeat;
+            background-size: 100% 100%;
+
+            span {
+              color: rgba(255, 255, 255, 0.80);
+              text-shadow: 0px 0px 8px rgba(201, 253, 243, 0.50);
+              font-size: 15px;
+              font-weight: 400;
+              line-height: 22px;
+            }
+
+            img {
+              width: 56px;
+              height: 36px;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>
+
+<style lang="scss">
+#screen-view-black {
+  .header .header-right {
+    .name {
+      color: #fff;
+    }
+  }
+}
+</style>

+ 4 - 4
src/views/screen/components/WaterYield.vue

@@ -153,8 +153,8 @@ const windowResize = () => {
 
 watchEffect(() => {
   const { jsSlq, zrZJSL, szZJSAvg, csSlqc, zrZCSL, szZCSAvg, totalTodayCSL } = props.screenData;
-  inWaterData.value = [formatDecimals(jsSlq), formatDecimals(zrZJSL), formatDecimals(szZJSAvg)];
-  outWaterData.value = [formatDecimals(csSlqc), formatDecimals(zrZCSL), formatDecimals(szZCSAvg)];
+  inWaterData.value = [formatDecimals(jsSlq), formatDecimals(zrZJSL ? zrZJSL / 24 : zrZJSL), formatDecimals(szZJSAvg ? szZJSAvg / 24 : szZJSAvg)];
+  outWaterData.value = [formatDecimals(csSlqc), formatDecimals(zrZCSL ? zrZCSL / 24 : zrZCSL), formatDecimals(szZCSAvg ? szZCSAvg / 24 : szZCSAvg)];
   totalNum.value = totalTodayCSL;
   initEchart();
 })
@@ -175,7 +175,7 @@ onUnmounted(() => {
     <div class="main-container">
       <div class="count-card">
         <div class="count-num_inner">
-          <span class="count-title">今日累计出水水量</span>
+          <span class="count-title">今日累计处理水量</span>
           <div class="count-value">
             <ul class="num-group flex space-x-[4px]">
               <li class="item" v-for="item, index in waterYield" :key="index"><span class="num">{{ item }}</span></li>
@@ -194,7 +194,7 @@ onUnmounted(() => {
             </li>
             <li class="item space-x-[6px]">
               <span class="square-icon border-[#f4e28c]"><i class="bg-[#eed056]"></i></span>
-              <span>水</span>
+              <span>水</span>
             </li>
           </ul>
         </div>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 44
vite.config.ts.timestamp-1719915060984-6fabe9de1b68c.mjs


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 44
vite.config.ts.timestamp-1720486813773-2c95633e7e6a2.mjs


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio