无人机管理后台前端(已迁走)
chenyao
2025-07-21 84d3ca7935f6cd913699cc5506cdc42a94fed640
src/views/wel/components/taskOutcome.vue
New file
@@ -0,0 +1,314 @@
<template>
  <div class="taskOutcome">
    <div class="card-title">
      <div class="cardtotal">
        <p>任务成果</p>
        <span class="total-number">{{totalNum}}</span>
        <p>个</p>
        <img @click="refresh" src="/src/assets/images/workbench/st1.svg" alt="" />
      </div>
      <div class="time-card">
        <div
          class="card-item"
          :class="item === checked ? 'active' : ''"
          v-for="(item, index) in timeListEnum"
          :key="index"
          @click="timeClick(item, index)"
        >
          {{ timeListStr[index] }}
        </div>
      </div>
    </div>
    <div class="chart" ref="echartsRef"></div>
  </div>
</template>
<script setup>
import { getdisposeApi, gettaskOutcomApi } from '@/api/home/index';
import * as echarts from 'echarts';
import dayjs from 'dayjs';
import useEchartsResize from '@/hooks/useEchartsResize';
let checked = ref('CURRENT_YEAR');
let timeListStr = ['本周', '本月', '本年'];
let timeListEnum = ['CURRENT_WEEK', 'CURRENT_MONTH', 'CURRENT_YEAR'];
const params = ref({
  dateEnum: 'CURRENT_YEAR',
  device_sn: '',
  end_date: undefined,
  start_date: undefined,
});
const totalNum = ref(0)
const dateSelect = ref('CURRENT_YEAR');
const refresh = () => {
  params.value.dateEnum = 'CURRENT_YEAR';
  checked.value = 'CURRENT_YEAR';
  dateSelect.value = 'CURRENT_YEAR';
  getBarChartData(params.value);
};
let timeClick = (item, index) => {
  checked.value = item;
  params.value.dateEnum = item;
  dateSelect.value = item;
 getBarChartData(params.value);
};
const seriesObj = {};
const echartsOption = {
    title: {
      text: seriesObj ? '' :'暂无数据',
      left: 'center',
      top: 'center',
      textStyle: {
        color: '#999',
        fontSize: '1.6rem',
        fontWeight: 'normal'
      }
    },
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: 'shadow',
    },
  },
  legend: {
    itemWidth: 14,
    itemHeight: 8,
    data: ['照片总数', '视频总数', 'AI识别', '全景', '三维', '正射'], // 确保包含所有系列名称
    top: '-1%',
    textStyle: {
      color: '#383838',
      fontSize: 12,
    },
  },
  grid: {
    // top: '5%',
    left: 0,
    right: 0,
    bottom: 0,
    containLabel: true,
  },
  xAxis: {
    type: 'category',
    axisLine: {
      show: true, // 隐藏轴线
      lineStyle: {
        color: '#cdd5e2',
      },
    },
    axisLabel: {
      color: '#383838',
      // interval: 0, // 显示所有标签
    },
    data: [],
  },
  yAxis: [
    {
      type: 'value',
      name: '',
      nameTextStyle: {
        color: '#E6F7FF',
        fontSize: '1rem',
        padding: [-8, 0, 0, 0], // 调整单位文字位置,向左偏移
        verticalAlign: 'top',
        lineHeight: 12,
      },
      axisLabel: {
        interval: 0, // 显示所有标签
        color: '#383838',
        fontFamily: 'Source Han Sans CN, Source Han Sans CN',
        fontWeight: 400,
        fontSize: 10,
      },
      axisLine: {
        lineStyle: {
          color: '#383838',
        },
      },
      splitLine: {
        lineStyle: {
          color: '#cdd5e2',
          type: 'dashed', // 设置为虚线
        },
      },
    },
  ],
  series: [],
};
const eventTypeList = ref([
  {name: '照片总数', value: 0, type: '0', color: '#ED672D' },
  { name: '视频总数', value: 0, type: '1', color: '#F5B763' },
  { name: 'AI识别', value: 0, type: '2', color: '#6851C3' },
  {  name: '全景', value: 0, type: '5', color: '#FFE100' },
  {  name: '三维', value: 0, type: '3', color: '#04C598' },
  {  name: '正射', value: 0, type: '4', color: '#3673E8' },
]);
eventTypeList.value.forEach(item => {
  seriesObj[item.name] = {
    type: 'bar',
    stack: 'Ad',
    barWidth: 8,
    emphasis: {
      focus: 'series',
    },
    name: item.name,
    itemStyle: { color: item.color },
    data: [],
  };
});
const echartsRef = ref(null);
let { chart } = useEchartsResize(echartsRef);
// 获取柱状图数据
const getBarChartData = value => {
  gettaskOutcomApi(value).then(res => {
    const list = res?.data?.data || [];
    eventTypeList.value.forEach(item => {
      item.value = 0;
    });
    const typeMap = new Map();
    eventTypeList.value.forEach(item => {
      typeMap.set(item.type, item);
    });
    echartsOption.xAxis.data = list.map(item => item.name);
    Object.keys(seriesObj).forEach(key => {
      seriesObj[key].data = [];
    });
    // 遍历所有月份
    list.forEach(month => {
    totalNum.value = month.total
      const monthData = new Map();
      month.data.forEach(item => {
        monthData.set(item.name, item.value);
      });
      eventTypeList.value.forEach(typeItem => {
        const value = monthData.get(typeItem.type) || 0;
        if (seriesObj[typeItem.name]) {
          seriesObj[typeItem.name].data.push(value);
        }
      });
    });
    if (list.length > 0) {
      const lastMonth = list[list.length - 1];
      const lastMonthData = new Map();
      lastMonth.data.forEach(item => {
        lastMonthData.set(item.name, item.value);
      });
      eventTypeList.value.forEach(item => {
        const value = lastMonthData.get(item.type);
        if (value !== undefined) {
          item.value = value;
        }
      });
    }
    // 更新图表
    echartsOption.series = Object.values(seriesObj);
    chart.value.setOption(echartsOption);
  });
};
onMounted(() => {
  getBarChartData(params.value);
});
</script>
<style scoped lang="scss">
.taskOutcome {
  border-radius: 8px 8px 8px 8px;
  padding: 4px 14px 0 15px;
  background: #ffffff !important;
  margin-top: 10px;
  margin-left: 10px;
  height: pxToVh(400);
  .card-title {
    display: flex;
    margin-bottom: 10px;
    align-items: center;
    justify-content: space-between;
    .cardtotal {
      display: flex;
      align-items: center;
      margin-left: 9px;
      img {
        width: 17px;
        height: 17px;
        margin-left: 6px;
        cursor: pointer;
      }
      p {
        font-weight: bold;
        font-size: 14px;
        color: #363636;
      }
      span {
        font-weight: 400;
        font-size: 14px;
        color: #7c8091;
      }
      .total-number {
        font-family: 'Source Han Sans CN';
        font-weight: bold;
        font-size: 32px;
        color: #2a54ff;
      }
    }
    img {
      width: 36px;
      height: 40px;
    }
  }
}
.time-card {
  text-align: center;
  // height: 30px;
  height: pxToVh(30);
  background: #ffffff;
  border: 1px solid #e5e5e5;
  font-weight: 400;
  font-size: 14px;
  color: #7c8091;
  display: flex;
  width: 282px;
  margin-left: 15px;
  border-radius: 4px;
  .card-item {
    width: 94px;
    height: 100%;
    line-height: 28px;
    cursor: pointer;
    font-family: 'Source Han Sans CN';
    font-weight: 400;
    font-size: 14px;
    color: #7c8091;
  }
  .card-item:first-child {
    border-right: 1px solid #e5e5e5;
  }
  .card-item:nth-child(2) {
    border-right: 1px solid #e5e5e5;
  }
  .card-item.active {
    color: #1441ff;
    border: 1px solid #1c5cff;
  }
}
.chart {
  width: 98%;
  // height: 265px;
  height: pxToVh(285);
  padding-left: 10px;
  margin-top: 27px;
}
</style>