he wei
5 天以前 3c3576d5792bfabcef84979757ee344712e71cd3
src/views/history/hisTest.vue
@@ -1,65 +1,700 @@
<script setup name="hisTest">
import { ref, reactive } from "vue";
   import { ref, reactive, onMounted, watch, nextTick, computed } from "vue";
   import lineChart from '@/components/echarts/line4.vue';
   import barChart from '@/components/echarts/bar7.vue';
const testTypes = [
  {
    prop: 'hrfd',
    label: '核容放电'
  },
  {
    prop: 'hrcd',
    label: '核容充电'
  },
  {
    prop: 'jkfd',
    label: '监控放电'
  },
  {
    prop: 'jkcd',
    label: '监控充电'
  },
  {
    prop: 'tdfd',
    label: '停电放电'
  }
];
   import formatSeconds from '@/utils/formatSeconds';
   import useElement from "@/hooks/useElement.js";
   const { $loading, $message, $confirm } = useElement();
const testRecordList = reactive({
  hrfd: [],
  hrcd: [],
  jkfd: [],
  jkcd: [],
  tdfd: []
});
   import * as echarts from 'echarts';
   import {
      toFixed,
      digits,
   } from '@/utils/toFixed';
   import {
      getBattTinf,
      getTinfDataWithTestRecordCount,
   } from "@/api/history.js";
   import { format } from "echarts";
   const props = defineProps({
      battgroupId: {
         type: [String, Number],
      },
      num: {
         type: [String, Number],
      }
   });
   const testTypes = [
      {
         prop: 'hrfd',
         label: '核容放电'
      },
      {
         prop: 'hrcd',
         label: '核容充电'
      },
      {
         prop: 'jkfd',
         label: '监测放电'
      },
      {
         prop: 'jkcd',
         label: '监测充电'
      },
      {
         prop: 'tdfd',
         label: '停电放电'
      }
   ];
   const testRecordList = reactive({
      hrfd: [],
      hrcd: [],
      jkfd: [],
      jkcd: [],
      tdfd: [],
   });
   const selectValues = reactive({
      hrfd: '',
      hrcd: '',
      jkfd: '',
      jkcd: '',
      tdfd: '',
   });
   const slider = ref(100);
   const chart0 = ref(null);
   const chart1 = ref(null);
   const chart2 = ref(null);
   const chart3 = ref(null);
   const statusList = reactive([
      { label: '电池状态', prop: 'battStateName', unit: '' },
      { label: '在线电压', prop: 'onlineVol', unit: 'V' },
      { label: '电池电流', prop: 'groupCurr', unit: 'A' },
      { label: '测试时长', prop: 'testTimeLongStr', unit: '' },
      { label: '测试时间', prop: 'testStarttime', unit: '' },
      { label: '测试容量', prop: 'testCap', unit: 'Ah' },
      { label: '预估容量', prop: 'realCap', unit: 'Ah' },
      { label: '预估续航', prop: 'restTimeStr', unit: '' },
   ]);
   const infoList = reactive([
      { label: '标称容量', prop: 'moncapstd', unit: 'Ah' },
      { label: '蓄电池数量', prop: 'monCount', unit: '' },
      { label: '标称电压', prop: 'monvolstd', unit: 'V' },
      { label: '浮充电压', prop: 'floatchartVol', unit: 'V' },
   ])
   const monBarTitle = ref("最大值=0V;最小值=0V;平均值=0V");
   const chartType = ref("vol");
   const chartTypes = [
      {
         label: "单体电压",
         value: "vol",
         unit: "V",
         fixed: digits.VOL,
      },
      {
         label: "单体温度",
         value: "temp",
         unit: "℃",
         fixed: digits.TEMP,
      },
      {
         label: "单体实际容量",
         value: "realCap",
         unit: "AH",
         fixed: digits.CAP,
      },
      {
         label: "单体剩余容量",
         value: "resCap",
         unit: "AH",
         fixed: digits.CAP,
      },
      {
         label: "单体容量百分比",
         value: "preCap",
         unit: "%",
         fixed: 0,
      },
   ];
   const chartData = reactive({
      vol: [],
      temp: [],
      realCap: [],
      resCap: [],
      preCap: [],
   });
   const testRecordCount = ref('');
   const currProp = ref('');
   function filterChange(prop) {
      testTypes.forEach(v => {
         if (v.prop !== prop) {
            selectValues[v.prop] = '';
         }
      });
      testRecordCount.value = selectValues[prop];
      currProp.value = prop;
      getTestInfo();
   }
   const battStatus = computed(() => {
      return currProp.value ? testTypes.filter(v => v.prop == currProp.value)[0].label : '--';
   });
   const testInfo = computed(() => {
      let obj = currProp.value ? testRecordList[currProp.value].filter(v => v.value == testRecordCount.value)[0] : {};
      obj.battStateName = battStatus.value;
      console.log('obj', obj, '=============');
      return obj;
   });
   // 历史测试记录
   async function getLists() {
      let res = await getBattTinf(props.battgroupId);
      let { code, data, data2 } = res;
      if (code && data) {
         testRecordList.hrfd = data2['核容放电'].map(v => ({
            ...v,
            testCap: toFixed(v.testCap, digits.CAP),
            restTimeStr: formatSeconds(v.restTime),
            testTimeLongStr: formatSeconds(v.testTimeLong),
            value: `${v.testRecordCount}-${v.recordNum}`,
            label: v.testStarttime
         }));
         testRecordList.hrfd = data2['核容放电'].map(v => ({
            ...v,
            testCap: toFixed(v.testCap, digits.CAP),
            restTimeStr: formatSeconds(v.restTime),
            testTimeLongStr: formatSeconds(v.testTimeLong),
            value: `${v.testRecordCount}-${v.recordNum}`,
            label: v.testStarttime
         }));
         testRecordList.hrfd = data2['核容放电'].map(v => ({
            ...v,
            testCap: toFixed(v.testCap, digits.CAP),
            restTimeStr: formatSeconds(v.restTime),
            testTimeLongStr: formatSeconds(v.testTimeLong),
            value: `${v.testRecordCount}-${v.recordNum}`,
            label: v.testStarttime
         }));
         testRecordList.hrfd = data2['核容放电'].map(v => ({
            ...v,
            testCap: toFixed(v.testCap, digits.CAP),
            restTimeStr: formatSeconds(v.restTime),
            testTimeLongStr: formatSeconds(v.testTimeLong),
            value: `${v.testRecordCount}-${v.recordNum}`,
            label: v.testStarttime
         }));
         testRecordList.hrfd = data2['核容放电'].map(v => ({
            ...v,
            testCap: toFixed(v.testCap, digits.CAP),
            restTimeStr: formatSeconds(v.restTime),
            testTimeLongStr: formatSeconds(v.testTimeLong),
            value: `${v.testRecordCount}-${v.recordNum}`,
            label: v.testStarttime
         }));
      }
   }
   // 查询测试信息
   async function getTestInfo() {
      let [recordCount, recordNum] = testRecordCount.value.split('-');
      let loading = $loading();
      let res = await getTinfDataWithTestRecordCount(props.battgroupId, props.num, recordNum, recordCount);
      loading.close();
      let { code, data, data2 } = res;
      if (code && data) {
         // testInfo.value = data2;
         formatData(data2);
      }
   }
  watch(
    () => props.num,
    () => {
      if (!currProp.value) {
        return false;
      }
      getTestInfo();
    }
  );
   const chartOptions = reactive({
      chart0: {
         color: ["#0081ff", "#df9d02"],
         title: {
            show: false,
            text: "端电压折线图(V)",
            x: "left",
            textStyle: {
               fontSize: "14",
            },
         },
         legend: {
            show: false,
            data: ["在线电压", "组端电压"],
            right: 0,
            orient: "vertical",
         },
         series: [
            {
               name: "在线电压",
               data: [],
            },
            {
               name: "组端电压",
               data: [],
            },
         ],
      },
      chart1: {
         name: '',
         data: [],
      },
      chart2: {
         title: {
            show: false,
            text: "电池电流折线图(A)",
            x: "center",
            textStyle: {
               fontSize: "14",
            },
         },
         legend: {
            show: false,
         },
         series: [
            {
               name: "电池电流",
               areaStyle: {
                  color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                     {
                        offset: 0,
                        color: "#00feff",
                     },
                     {
                        offset: 1,
                        color: "transparent",
                     },
                  ]),
               },
               data: [],
            },
         ],
      },
      chart3: {
         title: {
            show: false,
            text: "单体电压(V)",
            x: "center",
            textStyle: {
               fontSize: "14",
            },
         },
         legend: {
            show: false,
         },
         series: [],
      },
   });
   const testTLong = ref([]);
   const barDatas = ref({});
   const bgDatas = ref({});
   const monNames = ref([]);
   // 格式化数据
   function formatData(data) {
      let recordNum = -1;
      let chartData = {
         groupVol: [],
         onlineVol: [],
         testCurr: [],
         monVolLine: [],
      };
      let monBarData = {
         vol: [],
         temp: [],
         realCap: [],
         resCap: [],
         preCap: [],
      };
      let xLabels = [];
      let firestData = {
         vol: [],
         temp: [],
         realCap: [],
         resCap: [],
         preCap: [],
      };
      let firstRecordNum = -1;
      for (let i = 0, len = data.length; i < len; i++) {
         let item = data[i];
         let monNum = item.monNum;
         let testTimeLong = formatSeconds(item.testTimelong);
         if (recordNum != item.recordNum) {
            recordNum = item.recordNum;
            if (firstRecordNum == -1) {
               firstRecordNum = item.recordNum;
            }
            chartData.groupVol.push([testTimeLong, item.groupVol]);
            chartData.onlineVol.push([testTimeLong, item.onlineVol]);
            chartData.testCurr.push([testTimeLong, item.testCurr]);
            monBarData.vol.push([]);
            monBarData.temp.push([]);
            monBarData.realCap.push([]);
            monBarData.resCap.push([]);
            monBarData.preCap.push([]);
            testTLong.value.push(testTimeLong);
         }
         let monName;
         if (firstRecordNum == recordNum) {
            monName = '#' + monNum;
            firestData.vol.push(item.monVol);
            firestData.temp.push(item.monTmp);
            firestData.realCap.push(item.realCap);
            firestData.resCap.push(item.restCap);
            firestData.preCap.push(item.percentCap);
            xLabels.push(monName);
         }
         monBarData.vol[monBarData.vol.length - 1].push(item.monVol);
         monBarData.temp[monBarData.temp.length - 1].push(item.monTmp);
         monBarData.realCap[monBarData.realCap.length - 1].push(item.realCap);
         monBarData.resCap[monBarData.resCap.length - 1].push(item.restCap);
         monBarData.preCap[monBarData.preCap.length - 1].push(item.percentCap);
         let monIdx = monNum - 1;
         chartData.monVolLine[monIdx] = chartData.monVolLine[monIdx] || [];
         chartData.monVolLine[monIdx].push([testTimeLong, item.monVol]);
      }
      // return { chartData, monBarData, xLabels };
      chartOptions.chart0.series[0].data = chartData.onlineVol;
      chartOptions.chart0.series[1].data = chartData.groupVol;
      chartOptions.chart2.series[0].data = chartData.testCurr;
      chartOptions.chart3.series = chartData.monVolLine.map((item, idx) => ({
         name: '#' + (idx + 1),
         data: item
      }));
      barDatas.value = monBarData;
      bgDatas.value = firestData;
      monNames.value = xLabels;
      updateChart();
   }
   function updateChart() {
      chart0.value.updateChart(chartOptions.chart0);
      updateBarChart();
      chart2.value.updateChart(chartOptions.chart2);
      chart3.value.updateChart(chartOptions.chart3);
      // chart2.value.updateChart(xLabels, monBarData.vol, monBarData.temp, monBarData.realCap, monBarData.resCap, monBarData.preCap);
   }
   function getBarNum(data) {
      let sum = 0;
      data.map(v => v * 1).forEach((item) => {
         sum += item;
      });
      let max = data.length > 0 ? Math.max(...data) : 0;
      let min = data.length > 0 ? Math.min(...data) : 0;
      let avg = data.length > 0 ? sum / data.length : 0;
      return {
         max,
         min,
         avg,
      };
   }
   function updateBarChart() {
      let dataList = barDatas.value[chartType.value];
      let opt = chartTypes.find((item) => item.value == chartType.value);
      let fixed = opt.fixed;
      let unit = opt.unit;
      let name = opt.label;
      let index = getDataIndex(dataList.length, slider.value);
      let data = [];
      if (index != -1) {
         data = dataList[index];
         let batNum = getBarNum(data);
         monBarTitle.value =
            "最大值=" +
            batNum.max +
            unit +
            ";最小值=" +
            batNum.min +
            unit +
            ";平均值=" +
            toFixed(batNum.avg, fixed) +
            unit;
      } else {
         console.log("未获取到值");
      }
      // 设置柱状图
      chart1.value.updateChart(monNames.value, { name, data }, bgDatas.value[chartType.value]);
   }
   // 格式化滑块显示的内容
   function formatTooltip(value) {
      let index = getDataIndex(testTLong.value.length, value);
      let test_long = formatSeconds(0);
      if (index != -1) {
         test_long = formatSeconds(testTLong[index]);
      }
      return test_long;
   }
   // 拖动滑块时触发
   function sliderInput() {
      updateBarChart();
   }
   // 根据百分比获取显示的数据的笔数
   function getDataIndex(num, percent) {
      if (percent <= 0) {
         return 0;
      }
      return Math.floor((num * percent) / 100) - 1;
   }
   function changeChartType() {
      updateBarChart();
   }
   onMounted(() => {
      if (chart0.value && chart2.value && chart3.value) {
         echarts.connect([chart0.value.getChart(), chart2.value.getChart(), chart3.value.getChart()]);
      }
      getLists();
   });
</script>
<template>
  <div class="page-his">
    <div class="filter">
    <div class="filter page-filter">
      <div class="item" v-for="(item, idx) in testTypes" :key="'list0_' + idx">
        <div class="label">{{ item.label }}</div>
        <div class="value">
          <el-select
            v-model="item.prop"
            size="small"
            clearable
            placeholder="请选择"
          >
            <el-option
              v-for="(item, idx) in testRecordList[item.prop]"
              :key="'list5_' + idx"
              :label="item.label"
              :value="item.value"
            >
          <el-select v-model="selectValues[item.prop]" size="small" placeholder="请选择" @change="filterChange(item.prop)">
            <el-option v-for="(item, idx) in testRecordList[item.prop]" :key="'list5_' + idx" :label="item.label"
              :value="item.value">
            </el-option>
          </el-select>
        </div>
      </div>
    </div>
    <div class="info">
      <div :class="['status-item',]" v-for="(item, index) in statusList" :key="'status_' + index">
        <div class="item-value" v-if="item.prop == 'captestTimelong' || item.prop == 'restTime'">
          {{ testInfo[item.prop] ?
          formatSeconds(testInfo[item.prop]) : '--' }}
        </div>
        <div class="item-value time" v-else-if="item.prop == 'testStarttime'">
          {{ testInfo[item.prop] || '--' }}
        </div>
        <div class="item-value" v-else>
          {{ testInfo[item.prop]}}{{ item.unit }}
        </div>
        <div class="item-name">{{ item.label }}</div>
      </div>
      <div class="info-item" v-for="(item, index) in infoList" :key="'info_' + index">
        <div class="label">{{ item.label }}({{ item.unit }})</div>
        <div class="value">{{ testInfo[item.prop] }}</div>
      </div>
    </div>
    <div class="main">
      <div class="grid">
        <div class="g-item">
          <card title="端电压折线图(V)">
            <line-chart ref="chart0"></line-chart>
          </card>
        </div>
        <div class="g-item">
          <card :title="monBarTitle">
            <template #tools>
              <el-select v-model="chartType" :disabled="!currProp" size="small" @change="changeChartType">
                <el-option v-for="item in chartTypes" :key="item.value" :label="item.label"
                  :value="item.value"></el-option>
              </el-select>
            </template>
            <bar-chart ref="chart1"></bar-chart>
          </card>
        </div>
        <div class="g-item">
          <card title="电池电流折线图(A)">
            <line-chart ref="chart2"></line-chart>
          </card>
        </div>
        <div class="g-item">
          <card title="单体电压(V)">
            <line-chart ref="chart3"></line-chart>
          </card>
        </div>
      </div>
    </div>
    <div class="footer">
      <el-slider v-model="slider" size="small" :format-tooltip="formatTooltip" @input="sliderInput" />
    </div>
  </div>
</template>
<style scoped lang="less">
.page-his {
  height: 100%;
  display: flex;
  flex-direction: column;
}
</style>
.filter {
  background: #073451;
  display: flex;
  // flex-wrap: wrap;
  align-items: center;
  padding: 8px;
  font-size: 16px;
  color: #45beea;
  .item {
    flex: 1;
    display: flex;
    &~.item {
      margin-left: 10px;
    }
    .label {
      margin-right: 10px;
      &::after {
        content: ":";
      }
    }
    .value {
      flex: 1;
    }
  }
}
.info {
  height: 72px;
  display: flex;
  flex-direction: row;
  .status-item {
    flex: 1;
    font-size: 14px;
    font-weight: 700;
    color: #50c7f1;
    // border: 1px solid #0F6B79;
    border-radius: 6px;
    margin: 4px 2px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    box-shadow: inset 0 0 30px -10px #0F6B79;
    background: radial-gradient(circle at -10% center, #1F6571 5%, transparent 20%) no-repeat,
      radial-gradient(circle at 110% center, #1F6571 5%, transparent 20%) no-repeat,
      radial-gradient(circle at center -72%, #1F6571 12%, transparent 50%) no-repeat,
      radial-gradient(circle at center 138%, #1F6571 12%, transparent 50%) no-repeat;
    .item-value {
      margin-bottom: 6px;
      color: #ff0;
      font-size: 20px;
      &.time {
        white-space: nowrap;
        font-size: 12px;
      }
    }
    .item-name {
      color: #6DCCE6;
    }
  }
  .info-item {
    flex: 1.2;
    display: flex;
    align-items: center;
    margin-left: 2px;
    .label {
      color: #6DCCE6;
      font-size: 12px;
      margin-bottom: 4px;
      &::after {
        content: ":";
      }
    }
    .value {
      color: #6DCCE6;
      font-size: 14px;
      background: #134263;
      flex: 1;
      border-radius: 4px;
      padding-left: 6px;
      margin-left: 4px;
      margin-right: 6px;
      min-height: 1.8em;
      display: flex;
      align-items: center;
    }
  }
}
.main {
  flex: 1;
  padding: 8px;
  .grid {
    height: 100%;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(2, 1fr);
    grid-gap: 10px 8px;
    place-content: stretch;
    // place-items: center stretch;
    // justify-items: stretch;
    // align-items: stretch;
    .g-item {
      display: flex;
      align-items: center;
      justify-content: center;
      :deep(.card) {
        width: 100%;
        .el-select {
          width: 140px;
        }
      }
    }
  }
}
.footer {
  padding: 0 8px;
}
</style>