316 lines
10 KiB
Vue
316 lines
10 KiB
Vue
<template>
|
||
<!-- 运行 运行(中断) 运行(故障) 离线 -->
|
||
<div :style="height" style="overflow-y: auto" v-loading="loading">
|
||
<div class="container">
|
||
<div class="tabs-container">
|
||
<!-- 左侧标签头 -->
|
||
<div class="tab-list" :style="echartHeight" style="overflow-y: auto">
|
||
<button
|
||
v-for="(item, index) in list"
|
||
:key="index"
|
||
:class="{ 'tab-button active': activeTab === index, 'tab-button': activeTab !== index }"
|
||
@click="changeTab(index)"
|
||
>
|
||
<span>{{ item.moduleName }}</span>
|
||
<el-tag
|
||
class="ml10"
|
||
:type="item.moduleState == '离线' ? 'danger' : 'success'"
|
||
size="small"
|
||
effect="dark"
|
||
>
|
||
{{ item.moduleState }}
|
||
</el-tag>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 右侧内容区域 -->
|
||
<div class="tab-content-container flex-1" :key="activeTab">
|
||
<div :style="echartHeight">
|
||
<MyEchart :options="echartList.options" v-if="echartList.dataList != null" />
|
||
<el-empty description="暂无数据" style="width: 100%; height: 100%" v-else></el-empty>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- <el-collapse v-model="activeNames" v-loading="loading">
|
||
<el-collapse-item v-for="(item, index) in list" :key="index" :name="index">
|
||
<template #title>
|
||
<div class="header">
|
||
{{ item.moduleName }}
|
||
<el-tag
|
||
class="ml10"
|
||
:type="item.moduleState == '离线' ? 'danger' : 'success'"
|
||
size="small"
|
||
effect="dark"
|
||
>
|
||
{{ item.moduleState }}
|
||
</el-tag>
|
||
</div>
|
||
</template>
|
||
<div :style="echartHeight" style="min-height: 150px">
|
||
<MyEchart :options="item.options" v-if="item.dataList != null" />
|
||
<el-empty description="暂无数据" style="height: 130px" v-else></el-empty>
|
||
</div>
|
||
</el-collapse-item>
|
||
</el-collapse> -->
|
||
</div>
|
||
</template>
|
||
<script setup lang="ts">
|
||
import { ref, reactive } from 'vue'
|
||
import { mainHeight } from '@/utils/layout'
|
||
import { WarnTriangleFilled } from '@element-plus/icons-vue'
|
||
import { getModuleState } from '@/api/cs-device-boot/EquipmentDelivery'
|
||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||
import { ElMessage } from 'element-plus'
|
||
import { chain } from 'lodash'
|
||
const list: any = ref([])
|
||
const loading = ref(false)
|
||
const height = ref(mainHeight(290))
|
||
const echartHeight = ref(mainHeight(302))
|
||
const activeTab = ref(0)
|
||
const echartList: any = ref({})
|
||
|
||
const setData = (data: any) => {
|
||
activeTab.value = 0
|
||
// echartHeight.value = mainHeight(292 + data.length * 49, data.length)
|
||
data.forEach((item: any) => {
|
||
// console.log('🚀 ~ setData ~ data:', data)
|
||
if (item.dataList == null) return
|
||
item.options = {
|
||
title: {
|
||
show: false
|
||
},
|
||
tooltip: {
|
||
formatter: function (params: any) {
|
||
var tips = params[0].data[0] + ':' + params[0].data[2] + '<br/>'
|
||
if (params[0].data[3] == 1) {
|
||
tips += '事件:' + params[0].data[4]
|
||
}
|
||
|
||
return tips
|
||
}
|
||
},
|
||
xAxis: {
|
||
type: 'time',
|
||
name: '时间',
|
||
//
|
||
axisLabel: {
|
||
formatter: {
|
||
day: '{MM}-{dd}',
|
||
month: '{MM}',
|
||
year: '{yyyy}'
|
||
}
|
||
}
|
||
},
|
||
|
||
// 添加自定义图例
|
||
legend: {
|
||
show: true,
|
||
type: 'plain',
|
||
top: 0,
|
||
itemWidth: 14, // 图例标记宽度
|
||
itemHeight: 14, // 图例标记高度
|
||
data: [
|
||
{
|
||
name: '事件',
|
||
icon: 'path://M0,10 L10,10 L5,0 Z', // 自定义三角形路径
|
||
textStyle: {
|
||
color: '#333',
|
||
fontSize: 12
|
||
}
|
||
}
|
||
],
|
||
itemStyle: {
|
||
color: '#FFB74D' // 图例标记颜色与数据标记一致
|
||
}
|
||
},
|
||
toolbox: {
|
||
show: false
|
||
},
|
||
grid: {
|
||
top: '30px'
|
||
},
|
||
yAxis: {
|
||
max: 1,
|
||
data: ['运行', '中断'],
|
||
interval: 1,
|
||
|
||
axisLabel: {
|
||
formatter: value => {
|
||
// if (value === 0) {
|
||
// return ` `
|
||
// }
|
||
if (value === 0) {
|
||
return `{lx|离线} `
|
||
}
|
||
if (value === 1) {
|
||
return `{yx|运行} `
|
||
}
|
||
},
|
||
rich: {
|
||
yx: {
|
||
backgroundColor: '#67c23a',
|
||
color: '#fff',
|
||
borderRadius: 5,
|
||
padding: [1, 3],
|
||
fontWeight: 600,
|
||
fontSize: 12,
|
||
align: 'center',
|
||
textAlign: 'center',
|
||
width: 35,
|
||
height: 20,
|
||
borderColor: '#000'
|
||
},
|
||
lx: {
|
||
backgroundColor: '#f56c6c',
|
||
color: '#fff',
|
||
borderRadius: 5,
|
||
padding: [1, 3],
|
||
fontWeight: 600,
|
||
fontSize: 12,
|
||
align: 'center',
|
||
textAlign: 'center',
|
||
width: 35,
|
||
height: 20,
|
||
borderColor: '#000'
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
options: {
|
||
series: [
|
||
{
|
||
name: '事件',
|
||
type: 'line',
|
||
data: item.dataList.map((k: any) => [
|
||
k.time,
|
||
k.stateDesc == '离线' ? 0 : 1,
|
||
k.stateDesc,
|
||
k.dataType,
|
||
k.eventName
|
||
]),
|
||
step: 'end',
|
||
symbol: 'none',
|
||
|
||
// 动态显示标记
|
||
markPoint: {
|
||
symbol: 'triangle', // 使用三角形标记
|
||
symbolSize: 10, // 标记大小
|
||
symbolOffset: [0, 6], // 向上偏移,放置在线条上方
|
||
data: item.dataList
|
||
.filter((k: any) => k.dataType === 1)
|
||
.map((k: any) => ({
|
||
name: k.stateDesc,
|
||
coord: [k.time, k.stateDesc === '离线' ? 0 : 1],
|
||
itemStyle: {
|
||
color: '#FFB74D', // 亮黄色填充
|
||
borderColor: '#FFB74D', // 边框颜色
|
||
borderWidth: 1 // 边框宽度
|
||
}
|
||
}))
|
||
}
|
||
}
|
||
]
|
||
}
|
||
}
|
||
})
|
||
|
||
list.value = data
|
||
echartList.value = list.value[activeTab.value]
|
||
}
|
||
const getModule = async (id: string) => {
|
||
loading.value = true
|
||
await getModuleState({ id: id }).then(res => {
|
||
res.data.forEach((item: any) => {
|
||
list.value.forEach((k: any) => {
|
||
if (k.moduleName === item.moduleName) {
|
||
k.moduleState = item.moduleState
|
||
}
|
||
})
|
||
})
|
||
|
||
ElMessage.success('刷新成功')
|
||
})
|
||
loading.value = false
|
||
}
|
||
const changeTab = (e: any) => {
|
||
echartList.value = list.value[e]
|
||
activeTab.value = e
|
||
}
|
||
|
||
defineExpose({ setData, getModule })
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.container {
|
||
margin: 10px 10px 0 10px;
|
||
background-color: white;
|
||
border-radius: 0.5rem;
|
||
// box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.tabs-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
}
|
||
|
||
@media (min-width: 768px) {
|
||
.tabs-container {
|
||
flex-direction: row;
|
||
}
|
||
}
|
||
|
||
.tab-list {
|
||
width: 100%;
|
||
border-bottom: 1px solid #e2e8f0;
|
||
background-color: #f8fafc;
|
||
}
|
||
|
||
@media (min-width: 768px) {
|
||
.tab-list {
|
||
width: 140px;
|
||
border-right: 1px solid #e2e8f0;
|
||
border-bottom: none;
|
||
}
|
||
}
|
||
|
||
.tab-button {
|
||
display: flex;
|
||
align-items: center;
|
||
width: 100%;
|
||
padding: 15px 20px;
|
||
text-align: left;
|
||
border: none;
|
||
background: none;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
color: #64748b;
|
||
border-right: 4px solid transparent;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.tab-button:hover {
|
||
background-color: #f1f5f9;
|
||
color: #475569;
|
||
}
|
||
|
||
.tab-button.active {
|
||
background-color: #e2e8f0;
|
||
color: #000;
|
||
border-right-color: var(--el-color-primary);
|
||
font-weight: 700;
|
||
}
|
||
|
||
.tab-button i {
|
||
width: 1.25rem;
|
||
margin-right: 0.75rem;
|
||
}
|
||
|
||
.tab-content-container {
|
||
flex: 1;
|
||
}
|
||
</style>
|