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>