<template>
|
<div class="statistics">
|
<div class="title">
|
<div class="name">
|
<span> 设备统计</span>
|
<img @click="refresh" src="/src/assets/images/workbench/st1.png" alt="" />
|
</div>
|
<div class="arrow" @click="jumppage">
|
<img src="/src/assets/images/workbench/st2.png" alt="" />
|
</div>
|
</div>
|
|
<div class="grid-container" v-if="Object.keys(newtitleData).length > 0">
|
<div v-for="(item, index) in Object.keys(newtitleData)" :key="index" class="device-card">
|
<div class="device-title">
|
<img :src="test[item].img" :alt="newtitleData[item].name" />
|
<div class="itemcenter">
|
<div>{{ test[item]?.name || '--' }}</div>
|
<span class="shu">{{ newtitleData[item].total_num }}</span>
|
<span>{{ unitMap[test[item]?.name] }}</span>
|
</div>
|
</div>
|
<div class="status-list">
|
<template v-if="test[item]?.name == '机巢' || test[item]?.name == '无人机'">
|
<div
|
v-for="statusKey in [4, 0, -1]"
|
:key="statusKey"
|
class="status-item"
|
:class="getStatusStyle(test[item]?.name, statusKey)"
|
:style="{ color: getStatusColor(test[item]?.name, statusKey) }"
|
>
|
<span
|
class="indicator"
|
:style="{
|
backgroundColor: getStatusBackground(test[item]?.name, statusKey),
|
color: getStatusColor(test[item]?.name, statusKey),
|
}"
|
></span>
|
<span class="label">{{ getStatusLabel(test[item]?.name, statusKey) }}</span>
|
<span class="count">
|
{{ newtitleData[item].status_map[statusKey] }}
|
{{ unitMap[test[item]?.name] }}
|
</span>
|
</div>
|
</template>
|
<template v-else-if="test[item]?.name == '监控设备'">
|
<div
|
v-for="statusKey in [1, 0]"
|
:key="statusKey"
|
class="status-item"
|
:class="getStatusStyle(test[item]?.name, statusKey)"
|
:style="{ color: getStatusColor(test[item]?.name, statusKey) }"
|
>
|
<span
|
class="indicator"
|
:style="{
|
backgroundColor: getStatusBackground(test[item]?.name, statusKey),
|
color: getStatusColor(test[item]?.name, statusKey),
|
}"
|
></span>
|
<span class="label">{{ getStatusLabel(test[item]?.name, statusKey) }}</span>
|
<span class="count">
|
{{ newtitleData[item].status_map[statusKey] }}
|
{{ unitMap[test[item]?.name] }}
|
</span>
|
</div>
|
</template>
|
<template v-else-if="test[item]?.name == '机巢保险'">
|
<div
|
v-for="statusKey in [1, 0,2]"
|
:key="statusKey"
|
class="status-item"
|
:class="getStatusStyle(test[item]?.name, statusKey)"
|
:style="{ color: getStatusColor(test[item]?.name, statusKey) }"
|
>
|
<span
|
class="indicator"
|
:style="{
|
backgroundColor: getStatusBackground(test[item]?.name, statusKey),
|
color: getStatusColor(test[item]?.name, statusKey),
|
}"
|
></span>
|
<span class="label">{{ getStatusLabel(test[item]?.name, statusKey) }}</span>
|
<span class="count">
|
{{ newtitleData[item].status_map[statusKey] }}
|
{{ test[item]?.name === '无人机' ? '架' : '个' }}
|
</span>
|
</div>
|
</template>
|
<template v-else-if="test[item]?.name == '无人机流量'">
|
<div
|
v-for="statusKey in [ 0,2,1]"
|
:key="statusKey"
|
class="status-item"
|
:class="getStatusStyle(test[item]?.name, statusKey)"
|
:style="{ color: getStatusColor(test[item]?.name, statusKey) }"
|
>
|
<span
|
class="indicator"
|
:style="{
|
backgroundColor: getStatusBackground(test[item]?.name, statusKey),
|
color: getStatusColor(test[item]?.name, statusKey),
|
}"
|
></span>
|
<span class="label">{{ getStatusLabel(test[item]?.name, statusKey) }}</span>
|
<span class="count">
|
{{ newtitleData[item].status_map[statusKey] }}
|
{{ test[item]?.name === '无人机流量' ? '架' : '个' }}
|
</span>
|
</div>
|
</template>
|
<template v-else>
|
<div
|
v-for="(status, statusIndex) in newtitleData[item].status_map"
|
:key="statusIndex"
|
class="status-item"
|
:class="getStatusStyle(test[item]?.name, statusIndex)"
|
:style="{ color: getStatusColor(test[item]?.name, statusIndex) }"
|
>
|
<span
|
class="indicator"
|
:style="{
|
backgroundColor: getStatusBackground(test[item]?.name, statusIndex),
|
color: getStatusColor(test[item]?.name, statusIndex),
|
}"
|
></span>
|
<span class="label">{{ getStatusLabel(test[item]?.name, statusIndex) }}</span>
|
<span class="count">{{ status }} {{ unitMap[test[item]?.name] }}</span>
|
</div>
|
</template>
|
</div>
|
</div>
|
</div>
|
<div class="grid-container" v-else>
|
<el-empty>
|
<template #description>
|
<span class="custom-text">暂无数据</span>
|
</template>
|
</el-empty>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { useStore } from 'vuex';
|
import { computed } from 'vue';
|
import titleImg1 from '@/assets/images/workbench/st3.svg';
|
import titleImg2 from '@/assets/images/workbench/st4.svg';
|
import titleImg3 from '@/assets/images/workbench/st8.svg';
|
import titleImg4 from '@/assets/images/workbench/st5.svg';
|
import titleImg5 from '@/assets/images/workbench/st6.svg';
|
import titleImg6 from '@/assets/images/workbench/st9.svg';
|
import { getStatics } from '@/api/home/index';
|
import { useRouter } from 'vue-router';
|
const router = useRouter();
|
const store = useStore();
|
const refresh = () => {
|
getStaticsList();
|
};
|
const jumppage = () => {
|
router.push({
|
path: '/device/index',
|
});
|
};
|
const userInfo = computed(() => store.getters.userInfo);
|
const permission = computed(() => store.getters.permission);
|
|
const newtitleData = ref({});
|
|
const test = {
|
no_move_list: {
|
name: '机巢',
|
img: titleImg1,
|
},
|
plant_list: {
|
name: '无人机',
|
img: titleImg2,
|
},
|
flow_type_list: {
|
name: '无人机流量',
|
img: titleImg3,
|
},
|
monitor_list: {
|
name: '监控设备',
|
img: titleImg4,
|
},
|
move_list: {
|
name: '移动机巢',
|
img: titleImg5,
|
},
|
|
insure_list: {
|
name: '机巢保险',
|
img: titleImg6,
|
},
|
};
|
const statusSelect = {
|
4: '作业中',
|
0: '空闲中',
|
'-1': '离线中',
|
};
|
const flowStatus = {
|
0: '无忧',
|
1: '到期',
|
2: '不足',
|
};
|
const monitorStatus = {
|
0: '离线中',
|
1: '在线中',
|
};
|
|
const insureStatus = {
|
0: '临近到期',
|
1: '正常期限',
|
2:'保险过期'
|
};
|
const moveListStatus = {
|
'-1': '离线中',
|
4: '在线中',
|
};
|
// 样式配置对象
|
const statusStyles = {
|
机巢保险: {
|
0: { class: 'expired', color: '#FFA600', background: '#FFA600' },
|
1: { class: 'normal', color: 'rgba(0, 180, 69, 1)', background: 'rgba(0, 180, 69, 1)' },
|
2: { class: 'flying',color: 'rgba(255, 36, 36, 1)', background: 'rgba(255, 36, 36, 1)' },
|
},
|
|
无人机流量: {
|
0: { class: 'offline', color: 'rgba(0, 180, 69, 1)', background: 'rgba(0, 180, 69, 1)' },
|
1: { class: 'flying', color: 'rgba(255, 36, 36, 1)', background: 'rgba(255, 36, 36, 1)' },
|
2: { class: 'flying', color: '#FFA600', background: '#FFA600' },
|
},
|
监控设备: {
|
0: { class: 'offline', color: 'rgba(186, 186, 186, 1)', background: 'rgba(186, 186, 186, 1)' },
|
1: { class: 'flying', color: 'rgba(255, 106, 0, 1)', background: 'rgba(255, 106, 0, 1)' },
|
},
|
移动机巢: {
|
'-1': { class: 'offline', color: 'rgba(186, 186, 186, 1)', background: 'rgba(186, 186, 186, 1)' },
|
4: { class: 'flying', color: 'rgba(255, 106, 0, 1)', background: 'rgba(255, 106, 0, 1)' },
|
},
|
// 默认样式配置
|
default: {
|
0: { class: 'warning', color: 'rgba(0, 180, 69, 1)', background: 'rgba(0, 180, 69, 1)' },
|
4: { class: 'success', color: 'rgba(255, 106, 0, 1)', background: 'rgba(255, 106, 0, 1)' },
|
'-1': { class: 'success', color: 'rgba(186, 186, 186, 1)', background: 'rgba(186, 186, 186, 1)' },
|
},
|
};
|
|
const getStatusStyle = (name, statusIndex) => {
|
const styleConfig = statusStyles[name] || statusStyles.default;
|
return styleConfig[statusIndex]?.class || '';
|
};
|
const getStatusColor = (name, statusIndex) => {
|
const styleConfig = statusStyles[name] || statusStyles.default;
|
return styleConfig[statusIndex]?.color || '#333';
|
};
|
//背景颜色获取方法
|
const getStatusBackground = (name, statusIndex) => {
|
const styleConfig = statusStyles[name] || statusStyles.default;
|
return styleConfig[statusIndex]?.background || styleConfig[statusIndex]?.color || '#F0F0F0';
|
};
|
const getStatusLabel = (itemName, statusCode) => {
|
switch (itemName) {
|
case '无人机流量':
|
return flowStatus[statusCode] || statusSelect[statusCode];
|
case '监控设备':
|
return monitorStatus[statusCode] || statusSelect[statusCode];
|
case '机巢保险':
|
return insureStatus[statusCode] || statusSelect[statusCode];
|
case '移动机巢':
|
return moveListStatus[statusCode] || statusSelect[statusCode];
|
default:
|
return statusSelect[statusCode] || `未知状态(${statusCode})`;
|
}
|
};
|
|
const getStaticsList = () => {
|
getStatics(userInfo.value.detail.areaCode).then(res => {
|
// console.log('permission.value', permission.value);
|
// console.log('设备', res.data.data);
|
if (permission.value?.device_statistics_six) {
|
const { move_list, monitor_list, ...filteredData } = res.data.data;
|
newtitleData.value = filteredData;
|
return;
|
}
|
|
for (let key in res.data.data) {
|
if (permission.value?.device_statistics_four) {
|
const { flow_type_list, insure_list, ...filteredData } = res.data.data;
|
newtitleData.value = filteredData;
|
return;
|
}
|
}
|
});
|
};
|
|
const unitMap = {
|
无人机流量: '架',
|
无人机: '架',
|
机巢: '个',
|
机巢保险: '个',
|
监控设备: '个',
|
移动机巢: '个',
|
};
|
watch(
|
() => [
|
userInfo.value.detail?.areaCode,
|
permission.value.device_statistics_six,
|
permission.value?.device_statistics_four,
|
],
|
() => getStaticsList(),
|
{ immediate: true }
|
);
|
onMounted(() => {
|
getStaticsList();
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.statistics {
|
// height: 174px;
|
height: pxToVh(174);
|
background: #ffffff;
|
border-radius: 8px 8px 8px 8px;
|
margin-bottom: 10px;
|
font-size: clamp(12px, 2vw, 24px);
|
.title {
|
padding: 14px 14px 0 21px;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
|
.name {
|
display: flex;
|
align-items: center;
|
|
span {
|
margin-right: 4px;
|
font-weight: bold;
|
font-size: 16px;
|
color: #363636;
|
font-family: 'Source Han Sans CN';
|
}
|
|
img {
|
cursor: pointer;
|
}
|
}
|
|
.arrow {
|
cursor: pointer;
|
}
|
}
|
|
.grid-container {
|
padding: 0 14px 0 21px;
|
// display: grid;
|
// grid-template-columns: repeat(4, 1fr);
|
height: pxToVh(80);
|
display: flex;
|
justify-content: space-around;
|
:deep(.el-empty ){
|
width: 60px;
|
height: pxToVh(60);
|
.el-empty__image{
|
width: 60px !important;
|
height: pxToVh(60)!important;}
|
.custom-text {
|
font-size: 12px;
|
color: #7c8091;
|
}
|
}
|
.device-card {
|
display: flex;
|
align-items: center;
|
margin-top: 30px;
|
|
.device-title {
|
display: flex;
|
align-items: center;
|
|
img {
|
width: 64px;
|
height: 64px;
|
}
|
}
|
|
.itemcenter {
|
margin-left: 5px;
|
font-weight: 400;
|
font-size: 14px;
|
color: #343434;
|
div {
|
margin-top: 5px;
|
}
|
.shu {
|
font-weight: bold;
|
font-size: 36px;
|
color: #363636;
|
display: inline-block;
|
transform: skewX(-5deg);
|
font-family: 'Source Han Sans CN';
|
// font-size: calc(12px + 0.5vw);
|
margin-right: 2px;
|
}
|
|
span {
|
font-weight: 400;
|
font-size: 12px;
|
color: #7c8091;
|
}
|
}
|
}
|
|
.status-list {
|
display: grid;
|
margin-left: 5px;
|
.status-item {
|
display: flex;
|
align-items: center;
|
border-radius: 6px;
|
background: #fff;
|
font-size: 12px;
|
gap: 10px;
|
margin-bottom: 5px;
|
.indicator {
|
width: 6px;
|
height: 6px;
|
border-radius: 50%;
|
}
|
.label {
|
flex: 1;
|
// font-size: clamp(12px, 1vw, 14px);
|
}
|
|
.count {
|
// font-size: clamp(14px, 1.1vw, 16px);
|
font-size: 14px;
|
color: #7c8091;
|
}
|
}
|
}
|
}
|
|
.grid-container1 {
|
// padding: 0 14px 0 21px;
|
display: grid;
|
grid-template-columns: repeat(6, 1fr);
|
|
.device-card {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
|
.device-title {
|
display: flex;
|
align-items: center;
|
|
img {
|
width: 64px;
|
height: 64px;
|
}
|
}
|
|
.itemcenter {
|
margin-left: 14px;
|
font-weight: 400;
|
font-size: 14px;
|
color: #343434;
|
|
.shu {
|
font-weight: bold;
|
font-size: 36px;
|
color: #363636;
|
display: inline-block;
|
transform: skewX(-5deg);
|
font-family: 'Source Han Sans CN';
|
margin-right: 2px;
|
}
|
|
span {
|
font-weight: 400;
|
font-size: 12px;
|
color: #7c8091;
|
}
|
}
|
}
|
|
.status-list {
|
display: grid;
|
|
.status-item {
|
display: flex;
|
align-items: center;
|
border-radius: 6px;
|
background: #fff;
|
font-size: 12px;
|
gap: 10px;
|
margin-bottom: 5px;
|
|
.indicator {
|
width: 6px;
|
height: 6px;
|
border-radius: 50%;
|
}
|
|
.label {
|
flex: 1;
|
font-size: clamp(12px, 1vw, 14px);
|
}
|
|
.count {
|
font-size: clamp(12px, 1.1vw, 16px);
|
font-size: 14px;
|
color: #7c8091;
|
}
|
}
|
}
|
}
|
}
|
</style>
|