|
|
<script lang="ts" setup>
|
|
|
import * as echarts from "echarts";
|
|
|
import TotalChart from "@/components/Charts/totalChart.vue";
|
|
|
import PoleMonitorChart from "@/components/Charts/poleMonitorChart.vue";
|
|
|
import VehicleMonitorChart from "@/components/Charts/vehicleMonitorChart.vue";
|
|
|
import HomeSubTitle from "@/components/HeaderBar/homeSubTitle.vue";
|
|
|
import DeviceStatus from "./components/DeviceStatus.vue";
|
|
|
import car_device_icon from "@/assets/home/car_device_icon.png";
|
|
|
import pole_device_icon from "@/assets/home/pole_device_icon.png";
|
|
|
import excavator_device_icon from "@/assets/home/excavator_device_icon.png";
|
|
|
import {
|
|
|
getDataOverviewApi,
|
|
|
getDeviceInfowApi,
|
|
|
getRecordFaultApi,
|
|
|
getRealTimeApi,
|
|
|
} from "@/api/dashboard";
|
|
|
import { isSuccessApi } from "@/utils/forApi";
|
|
|
import { isArray } from "@/utils/is";
|
|
|
import AlarmModal from "./components/AlarmModal.vue";
|
|
|
import { dataViewConfig } from "@/config/dataView";
|
|
|
import { useWebSocketStore } from "@/stores/websocketStore";
|
|
|
import { onBeforeRouteLeave } from "vue-router";
|
|
|
defineOptions({
|
|
|
name: "DataOverviewWrap",
|
|
|
});
|
|
|
// TODO 需要转移到mock中
|
|
|
const xData = ref(["1月", "2月", "3月", "4月", "5月"]);
|
|
|
const legendArr = ["车体检测", "撑杆检测"];
|
|
|
const datas = ref([
|
|
|
[1528, 1266.02, 2468.39, 2982.67, 3165.91],
|
|
|
[2844.44, 6505.07, 8016.12, 6350.87, 1474.61],
|
|
|
]);
|
|
|
const colorArr = [
|
|
|
["#3B9FFE", "#5070F2"],
|
|
|
["#FFDA8D", "#FFAC06"],
|
|
|
];
|
|
|
const deviceStatus = ref({
|
|
|
onlineCount: 50,
|
|
|
errorCount: 10,
|
|
|
outlineCount: 10,
|
|
|
});
|
|
|
const searchForm = reactive({
|
|
|
car: "1",
|
|
|
pole: "1",
|
|
|
});
|
|
|
const deviceTotal = ref(0);
|
|
|
|
|
|
const carFaultTotal = ref([]);
|
|
|
const poleFaultTotal = ref([]);
|
|
|
const imageFault = ref([]);
|
|
|
const activeBtn = ref("month");
|
|
|
const isAlarmOpen = ref<Boolean>(false); //详情弹窗
|
|
|
const currentRow = ref<Record<string, any>>({}); // 当前选中行
|
|
|
const currFileList = ref<Record<string, any>[]>([]); // 详情的文件列表
|
|
|
const deviceInfo = reactive({
|
|
|
list: [
|
|
|
{
|
|
|
name: "车体检测设备",
|
|
|
bindVal: {
|
|
|
total: 0,
|
|
|
},
|
|
|
icon: car_device_icon,
|
|
|
},
|
|
|
{
|
|
|
name: "撑杆检测设备",
|
|
|
bindVal: {
|
|
|
total: 0,
|
|
|
},
|
|
|
icon: pole_device_icon,
|
|
|
},
|
|
|
{
|
|
|
name: "钩机检测设备",
|
|
|
bindVal: {
|
|
|
total: 0,
|
|
|
},
|
|
|
icon: excavator_device_icon,
|
|
|
},
|
|
|
],
|
|
|
});
|
|
|
|
|
|
const websocketStore = useWebSocketStore();
|
|
|
// 监听 messages 的变化
|
|
|
watch(
|
|
|
() => websocketStore.messages,
|
|
|
(newMessages: string[], oldMessages: string[]) => {
|
|
|
if (newMessages?.length > 0 && !isAlarmOpen.value) {
|
|
|
currentRow.value = newMessages[newMessages?.length - 1];
|
|
|
currFileList.value = newMessages[newMessages?.length - 1]?.images;
|
|
|
isAlarmOpen.value = true;
|
|
|
}
|
|
|
},
|
|
|
{ deep: true, immediate: true }
|
|
|
);
|
|
|
|
|
|
const getList = async (dateType: string = "month") => {
|
|
|
activeBtn.value = dateType;
|
|
|
const res = await getDataOverviewApi({ dateType });
|
|
|
if (isSuccessApi(res)) {
|
|
|
const { data } = res;
|
|
|
datas.value[0] = data.appearance;
|
|
|
datas.value[1] = data.pole;
|
|
|
if (dateType === "month") {
|
|
|
xData.value = data.dateArr.map((item: any) => {
|
|
|
if (dateType === "month") {
|
|
|
return item + "月";
|
|
|
}
|
|
|
});
|
|
|
} else {
|
|
|
xData.value = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"];
|
|
|
}
|
|
|
// console.log(data, 'getList_data')
|
|
|
}
|
|
|
};
|
|
|
const getDeviceInfo = async () => {
|
|
|
try {
|
|
|
const res = await getDeviceInfowApi();
|
|
|
if (isSuccessApi(res)) {
|
|
|
const { data } = res;
|
|
|
deviceTotal.value = data.deviceTotal;
|
|
|
deviceInfo.list = [
|
|
|
{
|
|
|
name: "车体检测设备",
|
|
|
bindVal: data?.appearance,
|
|
|
icon: car_device_icon,
|
|
|
},
|
|
|
{
|
|
|
name: "撑杆检测设备",
|
|
|
bindVal: data?.pole,
|
|
|
icon: pole_device_icon,
|
|
|
},
|
|
|
{
|
|
|
name: "钩机检测设备",
|
|
|
bindVal: data?.excavator,
|
|
|
icon: excavator_device_icon,
|
|
|
},
|
|
|
];
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error("获取设备信息出错:", error);
|
|
|
}
|
|
|
};
|
|
|
const fetchPoleMonitorData = async () => {
|
|
|
try {
|
|
|
const res = await getRecordFaultApi({
|
|
|
dateType: "month",
|
|
|
value: searchForm.pole,
|
|
|
type: "pole",
|
|
|
});
|
|
|
if (isSuccessApi(res)) {
|
|
|
const { data } = res;
|
|
|
poleFaultTotal.value = data;
|
|
|
// deviceStatus.value = data
|
|
|
console.log(data);
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error("获取设备信息出错:", error);
|
|
|
}
|
|
|
};
|
|
|
//
|
|
|
const fetchTrainMonitorData = async () => {
|
|
|
try {
|
|
|
const res = await getRecordFaultApi({
|
|
|
dateType: "month",
|
|
|
value: searchForm.car,
|
|
|
type: "appearance",
|
|
|
});
|
|
|
if (isSuccessApi(res)) {
|
|
|
const { data } = res;
|
|
|
carFaultTotal.value = data;
|
|
|
// deviceStatus.value = data
|
|
|
console.log(data);
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error("获取设备信息出错:", error);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
const getRealTime = async () => {
|
|
|
try {
|
|
|
const res = await getRealTimeApi({ deviceType: "" });
|
|
|
if (isSuccessApi(res)) {
|
|
|
const { data } = res;
|
|
|
if (isArray(data)) {
|
|
|
// TODO 暂时使用接口图重复填充
|
|
|
imageFault.value = data.concat(data).concat(data).splice(0, 4);
|
|
|
}
|
|
|
// deviceStatus.value = data
|
|
|
console.log(data);
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error("获取设备信息出错:", error);
|
|
|
}
|
|
|
};
|
|
|
onBeforeRouteLeave(() => {
|
|
|
isAlarmOpen.value = false;
|
|
|
currentRow.value = {};
|
|
|
currFileList.value = [];
|
|
|
});
|
|
|
onMounted(() => {
|
|
|
getList();
|
|
|
getDeviceInfo();
|
|
|
fetchTrainMonitorData();
|
|
|
fetchPoleMonitorData();
|
|
|
getRealTime();
|
|
|
});
|
|
|
</script>
|
|
|
<template>
|
|
|
<div class="flex data-overview-wrap">
|
|
|
<!-- 检测总量汇总 -->
|
|
|
<div class="grid-container">
|
|
|
<div class="grid-item">
|
|
|
<div class="module-header">
|
|
|
<HomeSubTitle title="检测总量汇总">
|
|
|
<template #extra>
|
|
|
<div>
|
|
|
<el-button
|
|
|
type="primary"
|
|
|
class="month-btn"
|
|
|
@click="getList('month')"
|
|
|
:class="{ 'active-btn': activeBtn === 'month' }"
|
|
|
>
|
|
|
月
|
|
|
</el-button>
|
|
|
<el-button
|
|
|
class="week-btn"
|
|
|
@click="getList('week')"
|
|
|
:class="{ 'active-btn': activeBtn === 'week' }"
|
|
|
>
|
|
|
周
|
|
|
</el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
</HomeSubTitle>
|
|
|
</div>
|
|
|
<div class="chart-container">
|
|
|
<TotalChart
|
|
|
:xData="xData"
|
|
|
:legendArr="legendArr"
|
|
|
:datas="datas"
|
|
|
:colorArr="colorArr"
|
|
|
/>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="grid-item">
|
|
|
<div class="module-header">
|
|
|
<HomeSubTitle title="车体监测">
|
|
|
<template #extra>
|
|
|
<div class="flex items-center text-[14px] px-[16px]">
|
|
|
<span>时间:</span>
|
|
|
<el-select
|
|
|
v-model="searchForm.pole"
|
|
|
placeholder="时间"
|
|
|
class="custom-select mini-size"
|
|
|
@change="fetchPoleMonitorData()"
|
|
|
>
|
|
|
<el-option
|
|
|
v-for="v in dataViewConfig.monthArr"
|
|
|
:key="v?.value"
|
|
|
:label="v?.name"
|
|
|
:value="v?.value"
|
|
|
></el-option>
|
|
|
</el-select>
|
|
|
</div>
|
|
|
</template>
|
|
|
</HomeSubTitle>
|
|
|
</div>
|
|
|
<div class="chart-container chart-pie-bg">
|
|
|
<!-- <PieChart :data="carFaultTotal" :colors="[
|
|
|
'#FF7C09',
|
|
|
'#0032FF',
|
|
|
'#04FFF2',
|
|
|
'#D19EFF',
|
|
|
'#FF0103',
|
|
|
'#9EFFF3',
|
|
|
]" /> -->
|
|
|
<VehicleMonitorChart />
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="grid-item">
|
|
|
<div class="module-header">
|
|
|
<HomeSubTitle title="撑杆监测">
|
|
|
<template #extra>
|
|
|
<div class="flex items-center text-[14px] px-[16px]">
|
|
|
<span>时间:</span>
|
|
|
<el-select
|
|
|
v-model="searchForm.pole"
|
|
|
placeholder="时间"
|
|
|
class="custom-select mini-size"
|
|
|
@change="fetchPoleMonitorData()"
|
|
|
>
|
|
|
<el-option
|
|
|
v-for="v in dataViewConfig.monthArr"
|
|
|
:key="v?.value"
|
|
|
:label="v?.name"
|
|
|
:value="v?.value"
|
|
|
></el-option>
|
|
|
</el-select>
|
|
|
</div>
|
|
|
</template>
|
|
|
</HomeSubTitle>
|
|
|
</div>
|
|
|
<div class="chart-container chart-pie-bg">
|
|
|
<PoleMonitorChart />
|
|
|
<!-- <PieChartSmall :data="poleFaultTotal" :colors="['#9DFFF3', '#FFA179']" /> -->
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 中部检测模块 -->
|
|
|
<div class="realTime-monitor-box">
|
|
|
<div class="w-full h-[35px] fg-title px-[16px] py-[20px]">
|
|
|
实时监测画面
|
|
|
</div>
|
|
|
<ul class="flex monitor-images">
|
|
|
<li class="monitor-images-item" v-for="(v, i) in imageFault" :key="i">
|
|
|
<img :src="v?.url" />
|
|
|
<div class="fault-info">{{ v?.fault_type }}</div>
|
|
|
</li>
|
|
|
</ul>
|
|
|
</div>
|
|
|
<!-- 设备信息 -->
|
|
|
<div class="device-info-box">
|
|
|
<div class="module-header">
|
|
|
<HomeSubTitle title="设备信息"> </HomeSubTitle>
|
|
|
</div>
|
|
|
<div class="device-info">
|
|
|
<div class="flex items-center justify-center total-device">
|
|
|
<div class="device-total-icon mt-[24px]"></div>
|
|
|
<div class="device-count ml-[24px]">
|
|
|
<div class="fg-mark1 text-[32px] font-bold">
|
|
|
{{ deviceTotal }}
|
|
|
</div>
|
|
|
<div class="text-[14px]">设备总数</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<ul class="device-list">
|
|
|
<li class="device-card" v-for="(v, k) in deviceInfo.list" :key="k">
|
|
|
<div
|
|
|
class="device-card-head text-[16px] flex items-center mb-[12px]"
|
|
|
>
|
|
|
<img :src="v.icon" alt="" class="w-[32px]" />
|
|
|
<span class="ml-[12px]">{{ v.name }}:</span>
|
|
|
<span class="font-bold">{{ v.bindVal?.total || 0 }}</span>
|
|
|
</div>
|
|
|
<!-- //TODO 使用echarts重构 https://echarts.zhangmuchen.top/#/detail?cid=164bb-40c1-e483-b7c9b-6cb171ad -->
|
|
|
<DeviceStatus :deviceStatus="v.bindVal" />
|
|
|
</li>
|
|
|
</ul>
|
|
|
</div>
|
|
|
</div>
|
|
|
<AlarmModal
|
|
|
v-model:value="isAlarmOpen"
|
|
|
:info="currentRow"
|
|
|
:image="currFileList"
|
|
|
@close="isAlarmOpen = false"
|
|
|
/>
|
|
|
</div>
|
|
|
</template>
|
|
|
<style scoped lang="scss">
|
|
|
@import url("./DataOverview.scss");
|
|
|
</style>
|