|
|
@@ -1,6 +1,6 @@
|
|
|
<script setup lang="ts">
|
|
|
import * as echarts from 'echarts'
|
|
|
-import { Odometer, CircleCheckFilled } from '@element-plus/icons-vue'
|
|
|
+import { Odometer, CircleCheckFilled, CircleCloseFilled } from '@element-plus/icons-vue'
|
|
|
import { rangeShortcuts } from '@/utils/formatTime'
|
|
|
|
|
|
import dayjs from 'dayjs'
|
|
|
@@ -20,15 +20,20 @@ const data = ref({
|
|
|
lastInlineTime: params.time || '',
|
|
|
ifInline: params.ifInline || '',
|
|
|
dept: params.dept || '',
|
|
|
- vehicle: params.vehicle || ''
|
|
|
+ vehicle: params.vehicle || '',
|
|
|
+ carOnline: params.carOnline || ''
|
|
|
})
|
|
|
|
|
|
+const disabledIdentifier = ref<string[]>(['online', 'vehicle_name', 'touchScreenDataAccumulate'])
|
|
|
+
|
|
|
const specs = ref<any[]>([])
|
|
|
const gatewayspecs = ref<any[]>([])
|
|
|
const zhbdspecs = ref<any[]>([])
|
|
|
const selectSpec = ref<Record<string, boolean>>({})
|
|
|
const chartMap = ref<Record<string, { name: string; value: any[] }>>({})
|
|
|
|
|
|
+const specsLoading = ref(false)
|
|
|
+
|
|
|
const lastTsMap = ref<Record<string, number>>({})
|
|
|
|
|
|
// 每 10s 刷新定时器
|
|
|
@@ -41,25 +46,27 @@ const date = ref([
|
|
|
])
|
|
|
|
|
|
const reset = () => {
|
|
|
- cancelAllRequests()
|
|
|
- const def = rangeShortcuts[0].value()
|
|
|
+ cancelAllRequests().then(() => {
|
|
|
+ const def = rangeShortcuts[0].value()
|
|
|
|
|
|
- date.value = [
|
|
|
- dayjs(def[0]).format('YYYY-MM-DD HH:mm:ss'),
|
|
|
- dayjs(def[1]).format('YYYY-MM-DD HH:mm:ss')
|
|
|
- ]
|
|
|
- stopAutoFetch()
|
|
|
- if (chart) chart.clear()
|
|
|
- render()
|
|
|
- initLoad()
|
|
|
+ date.value = [
|
|
|
+ dayjs(def[0]).format('YYYY-MM-DD HH:mm:ss'),
|
|
|
+ dayjs(def[1]).format('YYYY-MM-DD HH:mm:ss')
|
|
|
+ ]
|
|
|
+ stopAutoFetch()
|
|
|
+ if (chart) chart.clear()
|
|
|
+ render()
|
|
|
+ initLoad()
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
const handleDateChange = () => {
|
|
|
- cancelAllRequests()
|
|
|
- stopAutoFetch()
|
|
|
- if (chart) chart.clear()
|
|
|
- render()
|
|
|
- initLoad(false)
|
|
|
+ cancelAllRequests().then(() => {
|
|
|
+ stopAutoFetch()
|
|
|
+ if (chart) chart.clear()
|
|
|
+ render()
|
|
|
+ initLoad(false)
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
const handleClickSpec = (modelName: string) => {
|
|
|
@@ -74,6 +81,18 @@ const handleClickSpec = (modelName: string) => {
|
|
|
const chartRef = ref<HTMLDivElement | null>(null)
|
|
|
let chart: echarts.ECharts | null = null
|
|
|
|
|
|
+const chartInit = () => {
|
|
|
+ if (!chart) return
|
|
|
+
|
|
|
+ chart.on('legendselectchanged', (params: any) => {
|
|
|
+ selectSpec.value = params.selected
|
|
|
+ })
|
|
|
+
|
|
|
+ window.addEventListener('resize', () => {
|
|
|
+ if (chart) chart.resize()
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
// 映射区间相关
|
|
|
let intervalArr: number[] = []
|
|
|
let maxInterval = 0
|
|
|
@@ -82,8 +101,10 @@ let minInterval = 0
|
|
|
// 1. 加载 specs
|
|
|
const loadSpecs = async () => {
|
|
|
if (!params.id) return
|
|
|
+ specsLoading.value = true
|
|
|
const res = await IotDeviceApi.getIotDeviceTds(Number(params.id))
|
|
|
const zhbdres = await IotDeviceApi.getIotDeviceZHBDTds(Number(params.id))
|
|
|
+
|
|
|
zhbdspecs.value = zhbdres.sort((a, b) => b.modelOrder - a.modelOrder)
|
|
|
gatewayspecs.value = res.sort((a, b) => b.modelOrder - a.modelOrder)
|
|
|
|
|
|
@@ -94,14 +115,18 @@ const loadSpecs = async () => {
|
|
|
|
|
|
selectSpec.value = specs.value.reduce(
|
|
|
(acc, spec) => {
|
|
|
- acc[spec.modelName] = gatewayspecs.value.some((item) => item.modelName === spec.modelName)
|
|
|
+ acc[spec.modelName] =
|
|
|
+ gatewayspecs.value.some((item) => item.modelName === spec.modelName) &&
|
|
|
+ !disabledIdentifier.value.includes(spec.identifier)
|
|
|
return acc
|
|
|
},
|
|
|
{} as Record<string, boolean>
|
|
|
)
|
|
|
|
|
|
+ specsLoading.value = false
|
|
|
+
|
|
|
chartMap.value = specs.value
|
|
|
- .filter((spec) => !['online', 'vehicle_name'].includes(spec.identifier))
|
|
|
+ .filter((spec) => !disabledIdentifier.value.includes(spec.identifier))
|
|
|
.reduce(
|
|
|
(acc, spec) => {
|
|
|
acc[spec.identifier] = { name: spec.modelName, value: [] }
|
|
|
@@ -111,6 +136,8 @@ const loadSpecs = async () => {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
+const chartLoading = ref(false)
|
|
|
+
|
|
|
const initLoad = async (real_time: boolean = true) => {
|
|
|
if (!specs.value.length) return
|
|
|
|
|
|
@@ -119,6 +146,8 @@ const initLoad = async (real_time: boolean = true) => {
|
|
|
lastTsMap.value[identifier] = 0
|
|
|
})
|
|
|
|
|
|
+ chartLoading.value = true
|
|
|
+
|
|
|
for (const identifier of Object.keys(chartMap.value)) {
|
|
|
const res = await IotStatApi.getDeviceInfoChart(
|
|
|
data.value.deviceCode,
|
|
|
@@ -132,6 +161,8 @@ const initLoad = async (real_time: boolean = true) => {
|
|
|
lastTsMap.value[identifier] = sorted.at(-1)?.ts ?? 0
|
|
|
|
|
|
updateSingleSeries(identifier)
|
|
|
+
|
|
|
+ chartLoading.value = false
|
|
|
}
|
|
|
|
|
|
if (real_time) startAutoFetch()
|
|
|
@@ -176,6 +207,8 @@ const render = () => {
|
|
|
|
|
|
if (!chart) chart = echarts.init(chartRef.value)
|
|
|
|
|
|
+ chartInit()
|
|
|
+
|
|
|
const values = Object.values(chartMap.value).flatMap((item) => item.value.map((d) => d.value))
|
|
|
|
|
|
const maxVal = Math.max(...values)
|
|
|
@@ -297,6 +330,10 @@ onMounted(async () => {
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
stopAutoFetch()
|
|
|
+
|
|
|
+ window.removeEventListener('resize', () => {
|
|
|
+ if (chart) chart.resize()
|
|
|
+ })
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
@@ -312,19 +349,55 @@ onUnmounted(() => {
|
|
|
<el-form-item label="资产编码"> {{ data.deviceCode }} </el-form-item>
|
|
|
<el-form-item label="设备类别"> {{ data.deviceName }} </el-form-item>
|
|
|
<el-form-item label="所在部门"> {{ data.dept }} </el-form-item>
|
|
|
- <el-form-item label="是否在线" class="online" type="plain">
|
|
|
- <el-tag type="success" size="default" class="flex items-center">
|
|
|
+ <el-form-item label="网关状态" class="online" type="plain">
|
|
|
+ <el-tag
|
|
|
+ v-if="data.ifInline === '3'"
|
|
|
+ type="success"
|
|
|
+ size="default"
|
|
|
+ class="flex items-center"
|
|
|
+ >
|
|
|
+ <el-icon class="text-emerald!"><CircleCheckFilled /></el-icon>
|
|
|
+ 在线
|
|
|
+ </el-tag>
|
|
|
+
|
|
|
+ <el-tag v-if="data.ifInline === '4'" type="danger" size="default" class="flex items-center">
|
|
|
+ <el-icon class="text-rose"><CircleCloseFilled /></el-icon>
|
|
|
+ 离线
|
|
|
+ </el-tag>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="中航北斗2" class="online" type="plain">
|
|
|
+ <el-tag
|
|
|
+ v-if="data.carOnline === 'true'"
|
|
|
+ type="success"
|
|
|
+ size="default"
|
|
|
+ class="flex items-center"
|
|
|
+ >
|
|
|
<el-icon class="text-emerald!"><CircleCheckFilled /></el-icon>
|
|
|
在线
|
|
|
</el-tag>
|
|
|
+
|
|
|
+ <el-tag
|
|
|
+ v-if="data.carOnline === 'false'"
|
|
|
+ type="danger"
|
|
|
+ size="default"
|
|
|
+ class="flex items-center"
|
|
|
+ >
|
|
|
+ <el-icon class="text-rose"><CircleCloseFilled /></el-icon>
|
|
|
+ 离线
|
|
|
+ </el-tag>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="最后数据时间"> {{ data.lastInlineTime }} </el-form-item>
|
|
|
<el-form-item v-if="data.vehicle" label="车牌号码"> {{ data.vehicle }} </el-form-item>
|
|
|
</el-form>
|
|
|
</div>
|
|
|
- <div class="mt-4 w-full rounded-lg bg-gradient-to-r from-blue-100 to-white p-4 shadow">
|
|
|
+ <div class="mt-4 w-full rounded-lg bg-gradient-to-r from-blue-100 to-white p-4 shadow min-h-50">
|
|
|
<header class="font-medium text-center w-full">网关数采</header>
|
|
|
- <div class="w-full mt-4 grid grid-cols-4 gap-4" id="dimension">
|
|
|
+ <div
|
|
|
+ v-loading="specsLoading"
|
|
|
+ element-loading-background="transparent"
|
|
|
+ class="w-full mt-4 grid grid-cols-4 gap-4 min-h-30"
|
|
|
+ id="dimension"
|
|
|
+ >
|
|
|
<div
|
|
|
v-for="item in gatewayspecs"
|
|
|
:key="item.productId"
|
|
|
@@ -332,14 +405,17 @@ onUnmounted(() => {
|
|
|
:class="{
|
|
|
'bg-blue-200': selectSpec[item.modelName]
|
|
|
}"
|
|
|
- @click="handleClickSpec(item.modelName)"
|
|
|
+ @click="!disabledIdentifier.includes(item.identifier) && handleClickSpec(item.modelName)"
|
|
|
>
|
|
|
<span class="text-sm text-[var(--el-text-color-regular)]">{{ item.modelName }}</span>
|
|
|
<span class="text-lg font-medium ms-a">{{ item.value }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="mt-4 w-full rounded-lg bg-gradient-to-r from-blue-100 to-white p-4 shadow">
|
|
|
+ <div
|
|
|
+ v-if="zhbdspecs.length"
|
|
|
+ class="mt-4 w-full rounded-lg bg-gradient-to-r from-blue-100 to-white p-4 shadow"
|
|
|
+ >
|
|
|
<header class="font-medium text-center w-full">中航北斗</header>
|
|
|
<div class="w-full mt-4 grid grid-cols-4 gap-4" id="dimension">
|
|
|
<div
|
|
|
@@ -349,7 +425,7 @@ onUnmounted(() => {
|
|
|
:class="{
|
|
|
'bg-blue-200': selectSpec[item.modelName]
|
|
|
}"
|
|
|
- @click="handleClickSpec(item.modelName)"
|
|
|
+ @click="!disabledIdentifier.includes(item.identifier) && handleClickSpec(item.modelName)"
|
|
|
>
|
|
|
<span class="text-sm text-[var(--el-text-color-regular)]">{{ item.modelName }}</span>
|
|
|
<span class="text-lg font-medium ms-a">{{ item.value }}</span>
|
|
|
@@ -380,7 +456,12 @@ onUnmounted(() => {
|
|
|
/>
|
|
|
</div>
|
|
|
</header>
|
|
|
- <div ref="chartRef" class="w-full h-158 mt-4 mb-4"></div>
|
|
|
+ <div
|
|
|
+ v-loading="specsLoading"
|
|
|
+ element-loading-background="transparent"
|
|
|
+ ref="chartRef"
|
|
|
+ class="w-full h-158 mt-4 mb-4"
|
|
|
+ ></div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|