代码分享-动态图表表格

15 阅读3分钟

image.png

index.vue

<template>
  <div class="machBox">
    <div class="title">
      <span class="left"></span>
      <span>选择设备对象</span>
    </div>
    <div class="formBox">
      <el-radio-group v-model="data.radio" class="ml-4" @change="onChangeTab">
        <el-radio :value="1" size="large">设备类型</el-radio>
        <el-radio :value="2" size="large">持有单位</el-radio>
      </el-radio-group>
    </div>
    <template v-if="data.radio===1">
      <div class="title">
        <span class="left"></span>
        <span>设备类型</span>
      </div>
      <div class="formBox">
        <el-checkbox-group v-model="data.machTypeMap">
          <el-checkbox v-for="item in  data.machTypeList" :label="item.name" :value="item.id"/>
        </el-checkbox-group>
      </div>
    </template>
    <template v-else>
      <div class="title">
        <span class="left"></span>
        <span>持有单位</span>
      </div>
      <div class="formBox">
        <el-checkbox-group v-model="data.corpMap">
          <el-checkbox v-for="item in  data.corpMapList" :label="item.corpName" :value="item.corpId"/>
        </el-checkbox-group>
      </div>
    </template>
    <div class="title">
      <span class="left"></span>
      <span>选择数据项</span>
    </div>
    <div class="formBox">
      <el-checkbox-group v-model="data.columnIds">
        <el-checkbox v-for="item in machItemList" :label="item.name" :value="item.value"/>
      </el-checkbox-group>
    </div>
    <div class="title">
      <span class="left"></span>
      <span>选择日期</span>
    </div>
    <div class="formBox">
      <el-date-picker
          v-model="data.time"
          type="daterange"
          start-placeholder="开始时间"
          end-placeholder="结束时间"
          :disabledDate="disabledDate"
          @change="onChange"
      />
      <el-button class="ml-4" type="primary" @click="onSearch">搜索</el-button>
      <el-button @click="onReset">重置</el-button>
    </div>
    <div class="echartsList">
      <template v-for="item in machItemList">
        <LineBox v-if="echartsId.includes(item.value)" :title="item.title" :echartsDate="echartsDate"
                 :seriesData = "transformData(tableData,item.key)"
                 :echartsName="echartsName"
                 class="echartsItem"/>
      </template>
    </div>
    <div class="tableList">
      <TableList :tableData="tableData" :columns="newColumns" :is-number="false"/>
    </div>
  </div>
</template>

<script setup>
import {ref, reactive, onMounted, watch} from "vue";
import {corpList, getDataListCorp, getDataListType, machItemList, machTypeList} from '@/apis/multi.js'
import LineBox from './components/LineBox.vue'
import TableList from '@/components/TableList/index.vue'
import dayjs from "dayjs";
import {ElMessage} from "element-plus";


const today = new Date();
const sevenDaysAgo = new Date();
sevenDaysAgo.setDate(today.getDate() - 7)

const deptId = localStorage.getItem('deptId')
const data = reactive({
  radio: 1,
  columnIds: [],
  machTypeMap: [],
  corpMap: [],
  time: [sevenDaysAgo,today],
  machTypeList: [],
  corpMapList: []
})

const tableData = ref()
const columns = [
  {
    label: '时间',
    prop: 'date',
  },
  {
    label: '设备类型',
    prop: 'name',
  }
]

const checkColumns = [
  {
    label: '设备台数(台)',
    prop: 'machNumTotal',
    value: 1,
  },
  {
    label: '工作设备数(台)',
    prop: 'machNumWork',
    value: 2,
  },
  {
    label: '停机设备数(台)',
    prop: 'machNumIdle',
    value: 3,
  },
  {
    label: '在线设备数(台)',
    prop: 'machNumOnline',
    value: 4,
  },
  {
    label: '离线设备数(台)',
    prop: 'machNumOffline',
    value: 5,
  },
  {
    label: '日均时长(h)',
    prop: 'workTimes',
    value: 6,
  },
  {
    label: '日均工效(%)',
    prop: 'effic',
    value: 7,
  }, {
    label: '日均油耗量(L)',
    prop: 'oilWear',
    value: 8,
  },
  {
    label: '稳定指数',
    prop: 'stabExp',
    value: 9,
  },
  {
    label: '效率指数',
    prop: 'efficExp',
    value: 10,
  },
  {
    label: '强度指数',
    prop: 'strengthExp',
    value: 11,
  },
  {
    label: '安全指数',
    prop: 'safeExp',
    value: 12,
  },
  {
    label: '油耗指数',
    prop: 'oilExp',
    value: 13,
  },
  {
    label: '综合指数',
    prop: 'generalExp',
    value: 14,
  },
]

const newColumns = ref()

watch(() => data.columnIds, (val) => {
  const list = checkColumns.filter(item => data.columnIds.includes(item.value)).map(item => {
    return {
      label: item.label,
      prop: item.prop
    }
  })
  newColumns.value = [...columns, ...list]
  console.log(newColumns.value)
})


const disabledDate = (time) => {
  // 不可选择今天及以后的日期
  return time.getTime() > Date.now();
}

const onChange = (val) => {
  console.log(val)
  if (val) {

  } else {
    data.time = ['', '']
  }
}

const matchListByObj = (machTypeMap, dataArray) => {
  return machTypeMap.reduce((acc, id) => {
    const found = dataArray.find(item => item.id === id);
    if (found) {
      acc[id] = found.name;
    }
    return acc;
  }, {});
}

const matchListByCrop = (machTypeMap, dataArray) => {
  return machTypeMap.reduce((acc, id) => {
    const found = dataArray.find(item => item.corpId === id);
    if (found) {
      acc[id] = found.corpName;
    }
    return acc;
  }, {});
}

const flattenData = (data) => {
  return data.reduce((acc, curr) => {
    return acc.concat(curr.list);
  }, []);
}

const echartsDate = ref()
const echartsId = ref([])
const echartsName = ref()
const getDataList = async () => {
  if (!data.columnIds.length > 0) {
    ElMessage.error('至少选择一项数据项')
    return false
  }
  const params = {
    columnIds: data.columnIds,
    deptId,
    machTypeMap: data.machTypeMap,
    corpMap: data.corpMap,
    startDate: null,
    endDate: null
  }
  params.startDate = data.time[0] !== '' ? dayjs(data.time[0]).format('YYYY-MM-DD') : null
  params.endDate = data.time[1] !== '' ? dayjs(data.time[1]).format('YYYY-MM-DD') : null
  let request
  if (data.radio === 1) {
    if (!data.machTypeMap.length > 0) {
      ElMessage.error('至少选择一项设备类型')
      return false
    }
    params.machTypeMap = matchListByObj(data.machTypeMap, data.machTypeList)
    request = getDataListType
    delete params.corpMap
  } else {
    if (!params.corpMap.length > 0) {
      ElMessage.error('至少选择一项持有单位')
      return false
    }
    params.corpMap = matchListByCrop(data.corpMap, data.corpMapList)
    request = getDataListCorp
    delete params.machTypeMap
  }
  const res = await request(params)
  if (res && res.code === '200') {
    echartsId.value = data.columnIds
    tableData.value = flattenData(res.data.list)
    echartsDate.value = res.data.list.map(item => {
      return item.date
    })
    if(res.data.list.length>0){
      echartsName.value = res.data.list[0].list.map(item=>{
        return item.name
      })
    }

  }
}

function transformData(rawData, key) {
  // 创建一个用于存储结果的对象
  const resultMap = {};

  // 遍历原始数据
  rawData.forEach(item => {
    if (!resultMap[item.name]) {
      resultMap[item.name] = {
        name: item.name,
        type: 'line',
        data: []
      };
    }
    resultMap[item.name].data.push(item[key]);
  });

  // 将结果对象转换为数组
  return Object.values(resultMap);
}

onMounted(async () => {
  const res = await machTypeList({deptId})
  if (res && res.code === '200') {
    data.machTypeList = res.data.list
  }
  const res2 = await corpList({deptId})
  if (res2 && res2.code === '200') {
    data.corpMapList = res2.data.list
  }
})

const onSearch = () => {
  getDataList()
}

const onReset = () => {
  let obj = {
    radio: 1,
    columnIds: [],
    machTypeMap: [],
    corpMap: [],
    time: [],
  }
  Object.assign(data, obj)
  echartsId.value=[]
  tableData.value=[]
}

const onChangeTab=(val)=>{
  let obj = {
    columnIds: [],
    machTypeMap: [],
    corpMap: [],
    time: [],
  }
  echartsId.value=[]
  tableData.value=[]
  Object.assign(data, obj)
}

</script>

<style scoped lang="scss">
.machBox {
  background: #fff;
  border-radius: 8px;
  padding: 20px 40px;

  .title {
    width: 100%;
    background: #fafafa;
    color: #1961AC;
    display: flex;
    padding: 5px 10px;
    box-sizing: border-box;
    font-size: 14px;

    .left {
      width: 5px;
      display: block;
      height: 20px;
      background: #1961AC;
      margin-right: 10px;
    }
  }

  .formBox {
    padding: 15px 30px;
  }

  .echartsList {
    width: 100%;
    display: flex;
    flex-wrap: wrap;

    .echartsItem {
      width: 50%;
      margin-bottom: 50px;
    }
  }
}
</style>

echart组件

<template>
  <div ref="lineRef" style="height: 400px"></div>
</template>

<script setup>
import {useEcharts} from "@/composables/useEcharts.js";
import {ref, onMounted, defineProps, watch} from "vue";

const props = defineProps({
  data: {
    type: Array,
    default: [],
  },
  title: {
    type: String,
    default: '',
  },
  echartsDate: {
    type: Array,
    default: [],
  },
  echartsName: {
    type: Array,
    default: [],
  },
  seriesData: {
    type: Array,
    default: [],
  }
})

const lineOptions = ref({})

const {appRef: lineRef} = useEcharts(lineOptions);

const updateChartOptions = () => {
  lineOptions.value = {
    title: {
      text: props.title
    },
    tooltip: {
      trigger: 'axis'
    },
    legend: {
      orient: 'horizontal',
      left: '5%',
      bottom: '0%',
      data: props.echartsName
    },
    grid: {
      left: '5%',
      right: '5%',
      bottom: '20%',
      containLabel: true
    },
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: props.echartsDate
    },
    yAxis: {
      type: 'value'
    },
    series: props.seriesData
  };
};

onMounted(() => {
  updateChartOptions();
});

watch(() => [props.echartsDate, props.echartsName, props.seriesData], updateChartOptions, {deep: true});

</script>

<style scoped>
</style>