2025-02-25 09:06:35 +00:00
|
|
|
|
<template>
|
|
|
|
|
<div class="container">
|
|
|
|
|
<div class="header">
|
|
|
|
|
<div class="title">微工厂设备详情</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="content">
|
|
|
|
|
<div class="left-plane">
|
|
|
|
|
<div class="lt-plane">
|
|
|
|
|
<div class="ltl-plane">
|
|
|
|
|
<Card class="ltl-item1" title="设备详情">
|
|
|
|
|
<div class="ltl-content">
|
|
|
|
|
<div class="ltl-box">
|
2025-02-27 01:14:31 +00:00
|
|
|
|
<div class="ltl-item-box">
|
|
|
|
|
<div class="label">名称:</div>
|
|
|
|
|
<div class="value">{{ deviceInfo.name }}</div>
|
|
|
|
|
</div>
|
2025-02-25 09:06:35 +00:00
|
|
|
|
</div>
|
|
|
|
|
<div class="ltl-box">
|
2025-02-27 01:14:31 +00:00
|
|
|
|
<div class="ltl-item-box">
|
|
|
|
|
<div class="label">编号:</div>
|
|
|
|
|
<div class="value">{{ deviceInfo.code }}</div>
|
|
|
|
|
</div>
|
2025-02-25 09:06:35 +00:00
|
|
|
|
</div>
|
|
|
|
|
<div class="ltl-box">
|
2025-02-27 01:14:31 +00:00
|
|
|
|
<div class="ltl-item-box">
|
|
|
|
|
<div class="label">负责人:</div>
|
|
|
|
|
<div class="value">{{ deviceInfo.director }}</div>
|
|
|
|
|
</div>
|
2025-02-25 09:06:35 +00:00
|
|
|
|
</div>
|
|
|
|
|
<div class="ltl-box">
|
2025-02-27 01:14:31 +00:00
|
|
|
|
<div class="ltl-item-box">
|
|
|
|
|
<div class="label">所在位置:</div>
|
|
|
|
|
<div class="value">{{ deviceInfo.deviceLocation }}</div>
|
|
|
|
|
</div>
|
2025-02-25 09:06:35 +00:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</Card>
|
2025-02-27 01:14:31 +00:00
|
|
|
|
<Card class="ltl-item2" title="设备利用率">
|
|
|
|
|
<div style="width: 100%;height: 100%;display: flex;flex-direction: column;justify-content: space-around;align-items: center;">
|
|
|
|
|
<Progress :mdoelValue1="item" v-for="item in deviceRateChartData"></Progress>
|
|
|
|
|
</div>
|
|
|
|
|
</Card>
|
2025-02-25 09:06:35 +00:00
|
|
|
|
</div>
|
|
|
|
|
<div class="ltr-plane">
|
2025-02-27 01:14:31 +00:00
|
|
|
|
<div class="tip-type">
|
|
|
|
|
<div class="tip-type-item">
|
|
|
|
|
<svg-icon icon-class="run" class="el-input__icon" style="width: 26px;height: 26px;" />
|
|
|
|
|
<div class="tip-type-item-text">工作</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="tip-type-item">
|
|
|
|
|
<svg-icon icon-class="wait" class="el-input__icon" style="width: 26px;height: 26px;" />
|
|
|
|
|
<div class="tip-type-item-text">待机</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="tip-type-item">
|
|
|
|
|
<svg-icon icon-class="stop" class="el-input__icon" style="width: 26px;height: 26px;" />
|
|
|
|
|
<div class="tip-type-item-text">停机</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="tip-type-item">
|
|
|
|
|
<svg-icon icon-class="repair" class="el-input__icon"
|
|
|
|
|
style="width: 26px;height: 26px;" />
|
|
|
|
|
<div class="tip-type-item-text">维修</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="tip-type-item">
|
|
|
|
|
<svg-icon icon-class="alarm" class="el-input__icon" style="width: 26px;height: 26px;" />
|
|
|
|
|
<div class="tip-type-item-text">故障</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-02-25 09:06:35 +00:00
|
|
|
|
<div class="c-item c-top">
|
2025-02-27 01:14:31 +00:00
|
|
|
|
<div class="item-box">当前状态:
|
|
|
|
|
<svg-icon v-if="devStatus.state == 0" icon-class="stop"
|
|
|
|
|
class="el-input__icon input-icon" />
|
|
|
|
|
<svg-icon v-else-if="devStatus.state == 1" icon-class="wait"
|
|
|
|
|
class="el-input__icon input-icon" />
|
|
|
|
|
<svg-icon v-else-if="devStatus.state == 2" icon-class="run"
|
|
|
|
|
class="el-input__icon input-icon" />
|
|
|
|
|
<svg-icon v-else-if="devStatus.state == 4" icon-class="alarm"
|
|
|
|
|
class="el-input__icon input-icon" />
|
|
|
|
|
</div>
|
|
|
|
|
<div class="item-box">运行时长:{{ devStatus.runTime }}min</div>
|
2025-02-25 09:06:35 +00:00
|
|
|
|
</div>
|
|
|
|
|
<div class="c-item c-center">
|
2025-02-27 01:14:31 +00:00
|
|
|
|
<div class="item-box">停机时长:{{ devStatus.stopTime }}min</div>
|
|
|
|
|
<el-image :src="baseUrl + deviceInfo.file"
|
|
|
|
|
style="height: 100%;position: relative;top: -30px;" />
|
|
|
|
|
<div class="item-box">工作时长:{{ devStatus.workTime }}min</div>
|
2025-02-25 09:06:35 +00:00
|
|
|
|
</div>
|
|
|
|
|
<div class="c-item c-bottom">
|
2025-02-27 01:14:31 +00:00
|
|
|
|
<div class="item-box">故障时长:{{ devStatus.faultTime }}min</div>
|
|
|
|
|
<div class="item-box">待机时长:{{ devStatus.waitTime }}min</div>
|
2025-02-25 09:06:35 +00:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<Card class="lb-plane" title="设备状态分析">
|
2025-02-27 01:14:31 +00:00
|
|
|
|
<StackBarChart :data="deviceStatusChartData"></StackBarChart>
|
2025-02-25 09:06:35 +00:00
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
<div class="right-plane">
|
|
|
|
|
|
2025-02-27 01:14:31 +00:00
|
|
|
|
<Card class="right-item1" title="设备维修记录">
|
|
|
|
|
<el-table :data="repairData" v-if="repairData.length > 0" v-tableAutoScroll="{ delay: 15 }"
|
|
|
|
|
header-row-class-name="table_header" style="width: 100%;height: 100%;">
|
|
|
|
|
<el-table-column prop="devCode" label="编码" width="90" />
|
|
|
|
|
<el-table-column prop="name" label="设备名称" />
|
|
|
|
|
<el-table-column prop="runTime" label="报警内容" />
|
|
|
|
|
<el-table-column prop="person" label="负责人" />
|
|
|
|
|
<el-table-column prop="time" label="报警时间" />
|
|
|
|
|
</el-table>
|
|
|
|
|
<el-empty v-else description="暂无记录" />
|
|
|
|
|
</Card>
|
2025-02-25 09:06:35 +00:00
|
|
|
|
|
2025-02-27 01:14:31 +00:00
|
|
|
|
<Card class="right-item2" title="设备保养记录">
|
|
|
|
|
<el-table :data="remindData" v-if="remindData.length > 0" v-tableAutoScroll="{ delay: 15 }"
|
|
|
|
|
header-row-class-name="table_header" style="width: 100%;height: 100%;">
|
|
|
|
|
<el-table-column prop="devCode" label="编码" width="90" />
|
|
|
|
|
<el-table-column prop="name" label="设备名称" />
|
|
|
|
|
<el-table-column prop="runTime" label="保养内容" />
|
|
|
|
|
<el-table-column prop="person" label="负责人" />
|
|
|
|
|
<el-table-column prop="time" label="保养时间" />
|
|
|
|
|
</el-table>
|
|
|
|
|
<el-empty v-else description="暂无记录" />
|
|
|
|
|
</Card>
|
2025-02-25 09:06:35 +00:00
|
|
|
|
|
2025-02-27 01:14:31 +00:00
|
|
|
|
<Card class="right-item3" title="设备用电量分析">
|
|
|
|
|
<LineChart :data="deviceElectChartData"></LineChart>
|
|
|
|
|
</Card>
|
2025-02-25 09:06:35 +00:00
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2025-02-27 01:14:31 +00:00
|
|
|
|
import 'element-plus/theme-chalk/dark/css-vars.css'
|
|
|
|
|
import { onMounted, ref } from 'vue';
|
2025-02-25 09:06:35 +00:00
|
|
|
|
import Card from './component/card.vue';
|
|
|
|
|
import StackBarChart from './component/stackBarChart.vue';
|
2025-02-27 01:14:31 +00:00
|
|
|
|
import Progress from './component/Progress.vue';
|
|
|
|
|
import LineChart from './component/lineChart.vue';
|
|
|
|
|
import { useRoute } from 'vue-router';
|
|
|
|
|
import { listDevice, deviceCheck, deviceRepair, deviceStatusById, deviceStatusChart,deviceRateChart,deviceElectChart } from '@/api/screen/micro'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
let id = ref(0)
|
|
|
|
|
|
|
|
|
|
const baseUrl = import.meta.env.VITE_APP_BASE_API;
|
|
|
|
|
let deviceInfo = ref({})
|
|
|
|
|
//获取设备列表
|
|
|
|
|
function getListDevice() {
|
|
|
|
|
listDevice(id.value).then(res => {
|
|
|
|
|
deviceInfo.value = res.data
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
let remindData = ref([])
|
|
|
|
|
//获取保养记录
|
|
|
|
|
const getDeviceCheck = async () => {
|
|
|
|
|
const res = await deviceCheck(id.value);
|
|
|
|
|
remindData.value = res.data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let repairData = ref([])
|
|
|
|
|
//获取维修记录
|
|
|
|
|
const getDeviceRepair = async () => {
|
|
|
|
|
const res = await deviceRepair(id.value);
|
|
|
|
|
repairData.value = res.data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let devStatus = ref({
|
|
|
|
|
"deviceCode": null,
|
|
|
|
|
"onlineTime": null,
|
|
|
|
|
"realTime": null,
|
|
|
|
|
"deviceId": null,
|
|
|
|
|
"workTime": null,
|
|
|
|
|
"runTime": null,
|
|
|
|
|
"waitTime": null,
|
|
|
|
|
"stopTime": null,
|
|
|
|
|
"faultTime": null,
|
|
|
|
|
"ts": null,
|
|
|
|
|
"state": null,
|
|
|
|
|
})
|
|
|
|
|
//单设备运行状态
|
|
|
|
|
const getDeviceStatus = async () => {
|
|
|
|
|
const res = await deviceStatusById(id.value);
|
|
|
|
|
devStatus.value = res.data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let deviceStatusChartData = reactive({
|
|
|
|
|
xAxis: [],
|
|
|
|
|
series: []
|
|
|
|
|
})
|
|
|
|
|
//设备状态图表
|
|
|
|
|
const getDeviceStatusChart = async () => {
|
|
|
|
|
const res = await deviceStatusChart(id.value);
|
|
|
|
|
deviceStatusChartData.xAxis = res.data.dates;
|
|
|
|
|
deviceStatusChartData.series.push({
|
|
|
|
|
name: '工作',
|
|
|
|
|
data: res.data.work
|
|
|
|
|
})
|
|
|
|
|
deviceStatusChartData.series.push({
|
|
|
|
|
name: '待机',
|
|
|
|
|
data: res.data.wait
|
|
|
|
|
})
|
|
|
|
|
deviceStatusChartData.series.push({
|
|
|
|
|
name: '停机',
|
|
|
|
|
data: res.data.stop
|
|
|
|
|
})
|
|
|
|
|
deviceStatusChartData.series.push({
|
|
|
|
|
name: '故障',
|
|
|
|
|
data: res.data.fault
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//设备利用率
|
|
|
|
|
let deviceRateChartData = ref([])
|
|
|
|
|
const getDeviceRateChart = async () => {
|
|
|
|
|
const res = await deviceRateChart(id.value);
|
|
|
|
|
deviceRateChartData.value = res.data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//单设备用电量图表
|
|
|
|
|
let deviceElectChartData = reactive({
|
|
|
|
|
xAxis: [],
|
|
|
|
|
series: []
|
|
|
|
|
})
|
|
|
|
|
function getdeviceElectChart() {
|
|
|
|
|
deviceElectChart(id.value).then(res => {
|
|
|
|
|
deviceElectChartData.xAxis = res.data.dates;
|
|
|
|
|
deviceElectChartData.series = res.data.elects;
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
id.value = route.params.id;
|
|
|
|
|
getDeviceCheck();
|
|
|
|
|
getDeviceRepair();
|
|
|
|
|
getListDevice()
|
|
|
|
|
getDeviceStatus()
|
|
|
|
|
getDeviceStatusChart()
|
|
|
|
|
getDeviceRateChart()
|
|
|
|
|
getdeviceElectChart()
|
|
|
|
|
});
|
|
|
|
|
|
2025-02-25 09:06:35 +00:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
2025-02-27 01:14:31 +00:00
|
|
|
|
::v-deep(.table_header th) {
|
|
|
|
|
background-color: transparent !important;
|
|
|
|
|
color: #21dadb;
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-25 09:06:35 +00:00
|
|
|
|
.container {
|
|
|
|
|
width: 1920px;
|
|
|
|
|
height: 1080px;
|
|
|
|
|
position: relative;
|
|
|
|
|
// display: flex;
|
|
|
|
|
// justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
background-image: url('/src/assets/images/screen-bg.png');
|
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
|
/* 如果你不想让背景平铺 */
|
|
|
|
|
background-size: cover;
|
|
|
|
|
/* 或者其他你需要的大小设置 */
|
|
|
|
|
background-position: center;
|
|
|
|
|
|
|
|
|
|
.header {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 89px;
|
|
|
|
|
background-image: url('/src/assets/images/screen-header-bg1.png');
|
|
|
|
|
background-size: 100% 100%;
|
|
|
|
|
|
|
|
|
|
.title {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 89px;
|
|
|
|
|
font-size: 36px;
|
|
|
|
|
color: #f9f8f4;
|
|
|
|
|
text-align: center;
|
|
|
|
|
line-height: 89px;
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.content {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 975px;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-around;
|
|
|
|
|
align-items: center;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
padding: 20px 0;
|
|
|
|
|
|
|
|
|
|
.right-plane {
|
|
|
|
|
width: 488px;
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
|
|
.right-item1 {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 280px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.right-item2 {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 280px;
|
|
|
|
|
margin: 10px 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.right-item3 {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 395px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.left-plane {
|
|
|
|
|
width: 1400px;
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
|
|
.lt-plane {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 635px;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
.ltl-plane {
|
|
|
|
|
width: 488px;
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
|
|
.ltl-item1 {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 260px;
|
|
|
|
|
|
|
|
|
|
.ltl-content {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
|
|
|
|
.ltl-box {
|
|
|
|
|
width: 48%;
|
|
|
|
|
height: 50%;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
align-items: center;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
|
|
|
|
.ltl-item-box {
|
|
|
|
|
height: 60px;
|
|
|
|
|
width: 100%;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
background-color: rgba(2, 48, 87, 0.5);
|
|
|
|
|
border: #2A80B8 2px solid;
|
|
|
|
|
padding: 0 10px;
|
|
|
|
|
color: #f9f8f4;
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
text-align: center;
|
2025-02-27 01:14:31 +00:00
|
|
|
|
|
2025-02-25 09:06:35 +00:00
|
|
|
|
.label {
|
|
|
|
|
width: 50%;
|
|
|
|
|
text-wrap: nowrap;
|
|
|
|
|
text-align: left;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.ltl-item2 {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 360px;
|
|
|
|
|
margin-top: 15px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.ltr-plane {
|
2025-02-27 01:14:31 +00:00
|
|
|
|
position: relative;
|
2025-02-25 09:06:35 +00:00
|
|
|
|
width: 892px;
|
|
|
|
|
height: 100%;
|
|
|
|
|
background: url('./image/center-bg.png') no-repeat;
|
|
|
|
|
background-size: 38% auto;
|
|
|
|
|
background-position: 50% 70%;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
2025-02-27 01:14:31 +00:00
|
|
|
|
.tip-type {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: -15px;
|
|
|
|
|
left: 50%;
|
|
|
|
|
transform: translateX(-50%);
|
|
|
|
|
width: 260px;
|
|
|
|
|
height: 50px;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
|
|
|
|
.tip-type-item {
|
|
|
|
|
width: 33%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-25 09:06:35 +00:00
|
|
|
|
.c-top,
|
|
|
|
|
.c-bottom {
|
|
|
|
|
width: 70%;
|
2025-02-27 01:14:31 +00:00
|
|
|
|
height: 150px;
|
2025-02-25 09:06:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.c-center {
|
|
|
|
|
width: 85%;
|
2025-02-27 01:14:31 +00:00
|
|
|
|
flex: 1;
|
2025-02-25 09:06:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.c-item {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
.item-box {
|
|
|
|
|
background-color: rgba(2, 48, 87, 0.5);
|
|
|
|
|
border: #2A80B8 2px solid;
|
|
|
|
|
padding: 15px;
|
|
|
|
|
color: #f9f8f4;
|
|
|
|
|
font-size: 22px;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.lb-plane {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 340px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|