|
@@ -0,0 +1,388 @@
|
|
|
+<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: "4%",
|
|
|
+ top: "26%",
|
|
|
+ left: '4%',
|
|
|
+ right: "2%",
|
|
|
+ containLabel: true,
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ trigger: "axis",
|
|
|
+ },
|
|
|
+ title: {
|
|
|
+ text: title,
|
|
|
+ left: '0',
|
|
|
+ textStyle: {
|
|
|
+ fontSize: '1.2rem',
|
|
|
+ color: '#415B73'
|
|
|
+ },
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ orient: 'horizontal',
|
|
|
+ icon: 'circle',
|
|
|
+ itemWidth: 8,
|
|
|
+ y: 'top',
|
|
|
+ x: 'right',
|
|
|
+ textStyle: {fontSize: '1.2rem', color: '#415B73'}
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: "category",
|
|
|
+ data: xAxisData,
|
|
|
+ axisLabel: {
|
|
|
+ show: true,
|
|
|
+ fontSize: '1.2rem',
|
|
|
+ color: "#0A284E",
|
|
|
+
|
|
|
+ },
|
|
|
+ axisLine: {
|
|
|
+ show: true,
|
|
|
+ lineStyle: {
|
|
|
+ type: 'dashed',
|
|
|
+ show: true,
|
|
|
+ color: "#c1d3e6",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ boundaryGap: true,
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ splitNumber: 2,
|
|
|
+ type: "value",
|
|
|
+ axisLabel: {
|
|
|
+ show: true,
|
|
|
+ fontSize: '1.2rem',
|
|
|
+ color: "#7395B3"
|
|
|
+ },
|
|
|
+ axisLine: {
|
|
|
+ show: false,
|
|
|
+ lineStyle: {
|
|
|
+ color: "#BDD4E8",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ lineStyle: {
|
|
|
+ color: "#BDD4E8",
|
|
|
+ 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(jsCod), currentValue: formatDecimals(jscodSjz) },
|
|
|
+ { label: 'NH3-N', standardValue: formatDecimals(jsNh3), currentValue: formatDecimals(jsadSjz) },
|
|
|
+ { label: 'TN', standardValue: formatDecimals(jsTn), currentValue: formatDecimals(jszdSjz) },
|
|
|
+ { label: 'TP', standardValue: formatDecimals(jsTp), currentValue: formatDecimals(jszlSjz) },
|
|
|
+ { label: 'SS', standardValue: formatDecimals(jsSs), currentValue: formatDecimals(jsssSjz) },
|
|
|
+ { label: 'PH值', standardValue: '6-9', currentValue: formatDecimals(jsPh) }
|
|
|
+ ],
|
|
|
+ outWater.value = [
|
|
|
+ { label: 'COD', standardValue: formatDecimals(csCod), currentValue: formatDecimals(cscodBzz) },
|
|
|
+ { label: 'NH3-N', standardValue: formatDecimals(csNh3), currentValue: formatDecimals(csadBzz) },
|
|
|
+ { label: 'TN', standardValue: formatDecimals(csTn), currentValue: formatDecimals(cszzBzz) },
|
|
|
+ { label: 'TP', standardValue: formatDecimals(csTp), currentValue: formatDecimals(cszlBzz) },
|
|
|
+ { label: 'SS', standardValue: formatDecimals(csSs), currentValue: formatDecimals(csssBzz) },
|
|
|
+ { label: 'PH值', standardValue: '6-9', currentValue: formatDecimals(csPh) }
|
|
|
+ ]
|
|
|
+})
|
|
|
+
|
|
|
+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="水质数据">
|
|
|
+ <div class="main-container">
|
|
|
+ <div class="count-card mb-[1rem]">
|
|
|
+ <div class="count-num_inner">
|
|
|
+ <p class="title">今日<br>进水</p>
|
|
|
+ <ul class="num-group flex space-x-[0.4rem]">
|
|
|
+ <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-[1.2rem] leading-[1.8rem]">
|
|
|
+ <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">今日<br>出水</p>
|
|
|
+ <ul class="num-group flex space-x-[0.4rem]">
|
|
|
+ <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-[1.2rem] leading-[1.8rem]">
|
|
|
+ <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="echart-card">
|
|
|
+ <!-- <div class="title">
|
|
|
+ <span>进出水·流量分析</span>
|
|
|
+ <ul class="tabs space-x-[1.8rem]">
|
|
|
+ <li class="item space-x-[0.6rem]">
|
|
|
+ <span class="square-icon border-[#9fcbf2]"><i class="bg-[#5faeeb]"></i></span>
|
|
|
+ <span>出水</span>
|
|
|
+ </li>
|
|
|
+ <li class="item space-x-[0.6rem]">
|
|
|
+ <span class="square-icon border-[#f4e28c]"><i class="bg-[#eed056]"></i></span>
|
|
|
+ <span>出水</span>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </div> -->
|
|
|
+ <div class="echart-inner mb-[1.4rem]" 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: 6.2rem;
|
|
|
+ padding: 4px;
|
|
|
+ background: url('@/assets/images/workbench/bg-square-line.png') center center no-repeat;
|
|
|
+ background-size: 100% 100%;
|
|
|
+
|
|
|
+ .count-num_inner {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ padding: 0.6rem 0.6rem;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+
|
|
|
+ .title {
|
|
|
+ flex-shrink: 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 4.8rem;
|
|
|
+ height: 100%;
|
|
|
+ color: #3C97F7;
|
|
|
+ text-align: center;
|
|
|
+ font-family: "DingTalk JinBuTi";
|
|
|
+ font-size: 1.2rem;
|
|
|
+ letter-spacing: 0.12px;
|
|
|
+ line-height: 1.6rem;
|
|
|
+ border-radius: 2px;
|
|
|
+ background: linear-gradient(180deg, #99D7FF 0%, rgba(255, 255, 255, 0.00) 100%);
|
|
|
+ }
|
|
|
+
|
|
|
+ .num-group {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(6, minmax(5.8rem, 1fr));
|
|
|
+ gap: 1rem;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ padding-left: 0.9rem;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ .item {
|
|
|
+ @include flex(y, center, center);
|
|
|
+ text-align: center;
|
|
|
+
|
|
|
+ .label {
|
|
|
+ color: #0A284E;
|
|
|
+ font-size: 1.2rem;
|
|
|
+ font-weight: bold;
|
|
|
+ line-height: 1.6rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .num {
|
|
|
+ color: #415B73;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 1.0rem;
|
|
|
+ line-height: 1.4rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ border-radius: 2px;
|
|
|
+ background: #fff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .echart-card {
|
|
|
+ color: #415B73;
|
|
|
+ font-size: 1.2rem;
|
|
|
+ font-weight: bold;
|
|
|
+ padding-top: 1.4rem;
|
|
|
+
|
|
|
+ .title {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 1.4rem 0 1.2rem 0;
|
|
|
+
|
|
|
+ .tabs {
|
|
|
+ display: flex;
|
|
|
+
|
|
|
+ .item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ font-size: 1.2rem;
|
|
|
+
|
|
|
+ .square-icon {
|
|
|
+ display: inline-block;
|
|
|
+ padding: 1px;
|
|
|
+ border-width: 1px;
|
|
|
+ border-style: solid;
|
|
|
+ background: #fff;
|
|
|
+
|
|
|
+ i {
|
|
|
+ display: block;
|
|
|
+ width: 0.8rem;
|
|
|
+ height: 0.8rem;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .echart-inner {
|
|
|
+ height: 14rem;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|