|
|
@@ -8,7 +8,8 @@ import {
|
|
|
CircleCloseFilled,
|
|
|
DataLine,
|
|
|
Crop,
|
|
|
- FullScreen
|
|
|
+ FullScreen,
|
|
|
+ Setting
|
|
|
} from '@element-plus/icons-vue'
|
|
|
import { AnimatedCountTo } from '@/components/AnimatedCountTo'
|
|
|
import { neonColors } from '@/utils/td-color'
|
|
|
@@ -19,6 +20,7 @@ import { Dimensions, formatIotValue, HeaderItem, useSocketBus } from '@/utils/us
|
|
|
import { rangeShortcuts } from '@/utils/formatTime'
|
|
|
import { useFullscreen } from '@vueuse/core'
|
|
|
import { snapdom } from '@zumer/snapdom'
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
|
|
|
const { query } = useRoute()
|
|
|
|
|
|
@@ -180,26 +182,30 @@ async function loadDimensions() {
|
|
|
value: value,
|
|
|
suffix: suffix,
|
|
|
isText: isText,
|
|
|
- response: false
|
|
|
+ response: false,
|
|
|
+ id: item.alarmSettingId,
|
|
|
+ maxValue: Number(item.maxValue),
|
|
|
+ minValue: Number(item.minValue)
|
|
|
}
|
|
|
})
|
|
|
|
|
|
- const car = (((await IotDeviceApi.getIotDeviceZHBDTds(Number(query.id))) as any[]) ?? [])
|
|
|
- .sort((a, b) => b.modelOrder - a.modelOrder)
|
|
|
- .map((item) => {
|
|
|
- const { value, suffix, isText } = formatIotValue(item.value)
|
|
|
- console.log(`${item.modelName} :>> `, value)
|
|
|
- return {
|
|
|
- identifier: item.identifier,
|
|
|
- name: item.modelName,
|
|
|
- value: value,
|
|
|
- suffix: suffix,
|
|
|
- isText: isText,
|
|
|
- response: false
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- const rawList = [...gateway, ...car]
|
|
|
+ // const car = (((await IotDeviceApi.getIotDeviceZHBDTds(Number(query.id))) as any[]) ?? [])
|
|
|
+ // .sort((a, b) => b.modelOrder - a.modelOrder)
|
|
|
+ // .map((item) => {
|
|
|
+ // const { value, suffix, isText } = formatIotValue(item.value)
|
|
|
+ // console.log(`${item.modelName} :>> `, value)
|
|
|
+ // return {
|
|
|
+ // identifier: item.identifier,
|
|
|
+ // name: item.modelName,
|
|
|
+ // value: value,
|
|
|
+ // suffix: suffix,
|
|
|
+ // isText: isText,
|
|
|
+ // response: false
|
|
|
+ // }
|
|
|
+ // })
|
|
|
+
|
|
|
+ // const rawList = [...gateway, ...car]
|
|
|
+ const rawList = [...gateway]
|
|
|
|
|
|
const uniqueMap = new Map()
|
|
|
|
|
|
@@ -224,9 +230,9 @@ async function loadDimensions() {
|
|
|
gatewayDimensions.value = dimensions.value.filter((d) =>
|
|
|
gateway.some((g) => g.identifier === d.identifier)
|
|
|
)
|
|
|
- carDimensions.value = dimensions.value.filter((d) =>
|
|
|
- car.some((c) => c.identifier === d.identifier)
|
|
|
- )
|
|
|
+ // carDimensions.value = dimensions.value.filter((d) =>
|
|
|
+ // car.some((c) => c.identifier === d.identifier)
|
|
|
+ // )
|
|
|
|
|
|
selectedDimension.value = Object.fromEntries(dimensions.value.map((item) => [item.name, false]))
|
|
|
if (dimensions.value.length > 0) {
|
|
|
@@ -592,7 +598,7 @@ async function initLoadChartData(real_time: boolean = true) {
|
|
|
|
|
|
lastTsMap.value[name] = sorted.at(-1)?.ts ?? 0
|
|
|
|
|
|
- genderIntervalArr(true)
|
|
|
+ genderIntervalArr()
|
|
|
|
|
|
updateSingleSeries(name)
|
|
|
|
|
|
@@ -710,6 +716,29 @@ onUnmounted(() => {
|
|
|
const targetArea = ref(null)
|
|
|
|
|
|
const { toggle, isFullscreen } = useFullscreen(targetArea)
|
|
|
+
|
|
|
+async function handleSave(item: Dimensions) {
|
|
|
+ const body = {
|
|
|
+ minValue: item.minValue,
|
|
|
+ maxValue: item.maxValue,
|
|
|
+ deviceId: query.id,
|
|
|
+ propertyCode: item.identifier,
|
|
|
+ alarmProperty: item.name,
|
|
|
+ deviceName: data.value.deviceName,
|
|
|
+ id: item.id
|
|
|
+ }
|
|
|
+
|
|
|
+ const res = await IotDeviceApi.saveMaxMin(body)
|
|
|
+
|
|
|
+ if (res.id) item.id = res.id
|
|
|
+}
|
|
|
+async function handleReset(item: Dimensions) {
|
|
|
+ item.minValue = undefined
|
|
|
+ item.maxValue = undefined
|
|
|
+
|
|
|
+ await IotDeviceApi.deleteMaxMin({ id: item.id })
|
|
|
+ item.id = undefined
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
@@ -755,7 +784,7 @@ const { toggle, isFullscreen } = useFullscreen(targetArea)
|
|
|
</template>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div ref="targetArea" class="h-full min-h-0 relative">
|
|
|
+ <div ref="targetArea" class="relative">
|
|
|
<div class="flex flex-col gap-4 h-full">
|
|
|
<template v-for="citem in dimensionsContent" :key="citem.label">
|
|
|
<template v-if="citem.judgment ? Boolean(citem.value.length) : true">
|
|
|
@@ -797,14 +826,63 @@ const { toggle, isFullscreen } = useFullscreen(targetArea)
|
|
|
>
|
|
|
{{ item.name }}
|
|
|
</span>
|
|
|
- <div
|
|
|
+ <el-popover placement="bottom" :width="280" trigger="click">
|
|
|
+ <template #reference>
|
|
|
+ <el-button class="group" link>
|
|
|
+ <el-icon
|
|
|
+ class="transition-transform duration-500 group-hover:rotate-180"
|
|
|
+ :size="16"
|
|
|
+ >
|
|
|
+ <Setting />
|
|
|
+ </el-icon>
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <div class="flex flex-col gap-3">
|
|
|
+ <div class="text-sm font-bold text-gray-700 pb-1 border-b border-gray-100">
|
|
|
+ 设置范围
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="grid grid-cols-[auto_1fr] gap-y-3 gap-x-2 items-center">
|
|
|
+ <span class="text-xs text-gray-500 text-right">最小值:</span>
|
|
|
+ <el-input-number
|
|
|
+ v-model="item.minValue"
|
|
|
+ size="default"
|
|
|
+ class="!w-full"
|
|
|
+ placeholder="Min"
|
|
|
+ :controls="false"
|
|
|
+ align="left"
|
|
|
+ />
|
|
|
+
|
|
|
+ <span class="text-xs text-gray-500 text-right">最大值:</span>
|
|
|
+ <el-input-number
|
|
|
+ v-model="item.maxValue"
|
|
|
+ size="default"
|
|
|
+ class="!w-full"
|
|
|
+ placeholder="Max"
|
|
|
+ :controls="false"
|
|
|
+ align="left"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="flex justify-end gap-2 pt-1">
|
|
|
+ <el-button size="small" text bg @click="handleReset(item)">
|
|
|
+ 重置
|
|
|
+ </el-button>
|
|
|
+ <el-button size="small" type="primary" @click="handleSave(item)">
|
|
|
+ 保存
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-popover>
|
|
|
+ <!-- <div
|
|
|
class="size-2 rounded-full transition-all duration-300 shadow-sm"
|
|
|
:class="selectedDimension[item.name] ? 'scale-100' : 'scale-0'"
|
|
|
:style="{ backgroundColor: item.color, boxShadow: `0 0 6px ${item.color}` }"
|
|
|
- ></div>
|
|
|
+ ></div> -->
|
|
|
</div>
|
|
|
|
|
|
- <div class="flex items-baseline justify-between relative z-9">
|
|
|
+ <!-- <div class="flex items-baseline justify-between relative z-9">
|
|
|
<animated-count-to
|
|
|
v-if="!item.isText"
|
|
|
:value="Number(item.value)"
|
|
|
@@ -815,6 +893,56 @@ const { toggle, isFullscreen } = useFullscreen(targetArea)
|
|
|
<span v-else class="text-lg font-bold font-mono tracking-tight text-slate-800">
|
|
|
{{ item.value }}
|
|
|
</span>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <div class="flex items-center justify-between relative z-9 mt-1">
|
|
|
+ <div class="flex-1 mr-2">
|
|
|
+ <animated-count-to
|
|
|
+ v-if="!item.isText"
|
|
|
+ :value="Number(item.value)"
|
|
|
+ :duration="500"
|
|
|
+ :suffix="item.suffix"
|
|
|
+ class="text-2xl font-black font-mono tracking-tight text-slate-800 leading-none"
|
|
|
+ />
|
|
|
+ <span
|
|
|
+ v-else
|
|
|
+ class="text-2xl font-black font-mono tracking-tight text-slate-800 leading-none"
|
|
|
+ >
|
|
|
+ {{ item.value }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-if="item.minValue || item.maxValue" class="flex gap-1.5 items-center">
|
|
|
+ <div
|
|
|
+ v-if="item.maxValue"
|
|
|
+ class="flex items-center px-2 py-1 rounded-md bg-emerald-50/80 border border-solid border-emerald-100/80 shadow-sm transition-all duration-300 hover:bg-emerald-100 hover:border-emerald-200"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="flex items-center justify-center w-4 h-4 mr-1 rounded-full bg-emerald-100 text-emerald-600 group-hover/max:bg-white group-hover/max:scale-110 transition-all"
|
|
|
+ >
|
|
|
+ <div class="i-material-symbols:arrow-upward-alt-rounded"></div>
|
|
|
+ </div>
|
|
|
+ <span class="text-[10px] font-bold text-emerald-400/80 mr-1.5">MAX</span>
|
|
|
+ <span class="text-sm font-bold font-mono text-emerald-700">{{
|
|
|
+ item.maxValue
|
|
|
+ }}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ v-if="item.minValue"
|
|
|
+ class="flex items-center px-2 py-0.5 rounded-md bg-rose-50/80 border border-solid border-rose-100/80 shadow-sm transition-all duration-300 hover:bg-rose-100 hover:border-rose-200"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="flex items-center justify-center w-4 h-4 mr-1 rounded-full bg-rose-100 text-rose-600 group-hover/min:bg-white group-hover/min:scale-110 transition-all"
|
|
|
+ >
|
|
|
+ <div class="i-material-symbols:arrow-downward-alt-rounded"></div>
|
|
|
+ </div>
|
|
|
+ <span class="text-[10px] font-bold text-rose-400/80 mr-1.5">MIN</span>
|
|
|
+ <span class="text-sm font-bold font-mono text-rose-700">{{
|
|
|
+ item.minValue
|
|
|
+ }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
<div
|
|
|
class="absolute left-0 top-3 bottom-3 w-1 rounded-r transition-all duration-300"
|
|
|
@@ -832,7 +960,7 @@ const { toggle, isFullscreen } = useFullscreen(targetArea)
|
|
|
</template>
|
|
|
</template>
|
|
|
<div
|
|
|
- class="flex-1 rounded-xl shadow-sm border border-gray-100 border-solid p-4 flex flex-col bg-gradient-to-b from-blue-100 to-white"
|
|
|
+ class="flex-1 min-h-200 rounded-xl shadow-sm border border-gray-100 border-solid p-4 flex flex-col bg-gradient-to-b from-blue-100 to-white"
|
|
|
>
|
|
|
<header class="flex items-center justify-between mb-4">
|
|
|
<h3 class="flex items-center gap-2">
|