瀏覽代碼

合并更改

yanghao 5 天之前
父節點
當前提交
9046db6065

+ 2 - 1
prettier.config.js

@@ -18,5 +18,6 @@ module.exports = {
   proseWrap: 'never',
   htmlWhitespaceSensitivity: 'strict',
   endOfLine: 'auto',
-  rangeStart: 0
+  rangeStart: 0,
+  bracketSameLine: true
 }

+ 71 - 0
src/utils/useSocketBus.ts

@@ -1,5 +1,6 @@
 import { ref, reactive } from 'vue'
 import { useWebSocket } from '@vueuse/core'
+import { neonColors } from './td-color'
 
 type EventHandler = (data: any) => void
 
@@ -118,3 +119,73 @@ export interface Dimensions {
   maxValue?: number
   id?: number
 }
+
+export function hexToRgba(hex: string, alpha: number) {
+  const r = parseInt(hex.slice(1, 3), 16)
+  const g = parseInt(hex.slice(3, 5), 16)
+  const b = parseInt(hex.slice(5, 7), 16)
+  return `rgba(${r}, ${g}, ${b}, ${alpha})`
+}
+
+export function normalizeRangeValue(value: unknown) {
+  if (value === null || value === undefined || value === '') return undefined
+
+  const numberValue = Number(value)
+
+  return Number.isFinite(numberValue) ? numberValue : undefined
+}
+
+export function formatChartValue(value: unknown) {
+  const numberValue = Number(value)
+
+  if (!Number.isFinite(numberValue)) return '--'
+
+  return Number.isInteger(numberValue) ? `${numberValue}` : numberValue.toFixed(2)
+}
+
+export type RawDimension = Omit<Dimensions, 'color' | 'bgHover' | 'bgActive'>
+
+export interface IotTdItem {
+  identifier: string
+  modelName: string
+  modelOrder?: number
+  value: unknown
+  alarmSettingId?: number
+  maxValue?: unknown
+  minValue?: unknown
+}
+
+export function mapToDimension(item: IotTdItem): RawDimension {
+  const { value, suffix, isText } = formatIotValue(item.value)
+
+  return {
+    identifier: item.identifier,
+    name: item.modelName,
+    value,
+    suffix,
+    isText,
+    response: false,
+    id: item.alarmSettingId,
+    maxValue: item.alarmSettingId ? normalizeRangeValue(item.maxValue) : undefined,
+    minValue: item.alarmSettingId ? normalizeRangeValue(item.minValue) : undefined
+  }
+}
+
+export function withDisplayStyle(item: RawDimension, index: number): Dimensions {
+  const color = neonColors[index % neonColors.length]
+
+  return {
+    ...item,
+    color,
+    bgHover: hexToRgba(color, 0.08),
+    bgActive: hexToRgba(color, 0.12)
+  }
+}
+
+export interface RangeSettingDraft {
+  name: string
+  identifier: string
+  color: string
+  minValue?: number
+  maxValue?: number
+}

文件差異過大導致無法顯示
+ 379 - 616
src/views/oli-connection/monitoring-board/chart.vue


+ 26 - 51
src/views/oli-connection/monitoring-board/index.vue

@@ -47,7 +47,7 @@ interface Query {
 
 function getRealtimeTimeRange() {
   return [
-    dayjs().subtract(5, 'minute').format('YYYY-MM-DD HH:mm:ss'),
+    dayjs().subtract(10, 'minute').format('YYYY-MM-DD HH:mm:ss'),
     dayjs().format('YYYY-MM-DD HH:mm:ss')
   ]
 }
@@ -286,21 +286,17 @@ onMounted(() => {
 <template>
   <div
     ref="targetArea"
-    class="relative flex flex-col w-full rounded-lg bg-[#020408] overflow-hidden h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
-  >
+    class="relative flex flex-col w-full rounded-lg bg-[#020408] overflow-hidden h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]">
     <header
-      class="relative w-full h-14 flex items-center justify-center select-none bg-[#0b1121] border-b border-white/5 shadow-lg"
-    >
+      class="relative w-full h-14 flex items-center justify-center select-none bg-[#0b1121] border-b border-white/5 shadow-lg">
       <div
         class="absolute inset-0 opacity-20"
-        style="background-image: radial-gradient(circle at 50% 50%, #083344 0%, transparent 50%)"
-      >
+        style="background-image: radial-gradient(circle at 50% 50%, #083344 0%, transparent 50%)">
       </div>
 
       <div class="absolute bottom-0 left-0 w-full h-[2px] bg-slate-800/50 overflow-hidden z-20">
         <div
-          class="absolute top-0 bottom-0 w-[40%] bg-gradient-to-r from-transparent via-[#22d3ee] to-transparent shadow-[0_0_20px_#22d3ee] animate-scan-line"
-        >
+          class="absolute top-0 bottom-0 w-[40%] bg-gradient-to-r from-transparent via-[#22d3ee] to-transparent shadow-[0_0_20px_#22d3ee] animate-scan-line">
         </div>
       </div>
 
@@ -312,8 +308,7 @@ onMounted(() => {
       </div>
 
       <div
-        class="absolute right-6 top-1/2 -translate-y-1/2 flex items-center gap-1 opacity-80 flex-row-reverse"
-      >
+        class="absolute right-6 top-1/2 -translate-y-1/2 flex items-center gap-1 opacity-80 flex-row-reverse">
         <div class="w-1 h-4 bg-cyan-400 skew-x-[12deg] shadow-[0_0_5px_rgba(34,211,238,0.8)]"></div>
         <div class="w-1 h-3 bg-cyan-700 skew-x-[12deg]"></div>
         <div class="w-1 h-2 bg-cyan-900 skew-x-[12deg]"></div>
@@ -321,8 +316,7 @@ onMounted(() => {
 
       <h1 class="z-10 text-2xl font-bold tracking-[0.5em] uppercase">
         <span
-          class="text-transparent bg-clip-text bg-gradient-to-b from-white via-cyan-100 to-cyan-500 drop-shadow-[0_0_10px_rgba(34,211,238,0.8)]"
-        >
+          class="text-transparent bg-clip-text bg-gradient-to-b from-white via-cyan-100 to-cyan-500 drop-shadow-[0_0_10px_rgba(34,211,238,0.8)]">
           监控看板
         </span>
       </h1>
@@ -336,8 +330,7 @@ onMounted(() => {
           class="custom-btn primary-btn"
           :type="isFullscreen ? 'info' : 'primary'"
           :icon="isFullscreen ? Crop : FullScreen"
-          @click="toggle"
-        >
+          @click="toggle">
           {{ isFullscreen ? '退出全屏' : '全屏' }}
         </el-button>
       </div>
@@ -356,8 +349,7 @@ onMounted(() => {
           <el-button
             class="custom-btn reset-btn"
             :disabled="pageIndex >= totalPages - 1"
-            @click="goNextGroup"
-          >
+            @click="goNextGroup">
             下 5 个
           </el-button>
         </div>
@@ -368,29 +360,25 @@ onMounted(() => {
           <div
             v-if="sideCards[0]"
             class="monitor-card-shell monitor-card-side monitor-card-left-top"
-            @click="setMainCard(sideCards[0])"
-          >
+            @click="setMainCard(sideCards[0])">
             <chart
               :key="sideCards[0].id"
               v-bind="sideCards[0]"
               :date="query.time"
               :is-real-time="isRealTime"
-              :token="token"
-            />
+              :token="token" />
           </div>
 
           <div
             v-if="sideCards[1]"
             class="monitor-card-shell monitor-card-side monitor-card-left-bottom"
-            @click="setMainCard(sideCards[1])"
-          >
+            @click="setMainCard(sideCards[1])">
             <chart
               :key="sideCards[1].id"
               v-bind="sideCards[1]"
               :date="query.time"
               :is-real-time="isRealTime"
-              :token="token"
-            />
+              :token="token" />
           </div>
 
           <div class="monitor-card-shell monitor-card-main" @click="setMainCard(mainCard)">
@@ -399,36 +387,31 @@ onMounted(() => {
               v-bind="mainCard"
               :date="query.time"
               :is-real-time="isRealTime"
-              :token="token"
-            />
+              :token="token" />
           </div>
 
           <div
             v-if="sideCards[2]"
             class="monitor-card-shell monitor-card-side monitor-card-right-top"
-            @click="setMainCard(sideCards[2])"
-          >
+            @click="setMainCard(sideCards[2])">
             <chart
               :key="sideCards[2].id"
               v-bind="sideCards[2]"
               :date="query.time"
               :is-real-time="isRealTime"
-              :token="token"
-            />
+              :token="token" />
           </div>
 
           <div
             v-if="sideCards[3]"
             class="monitor-card-shell monitor-card-side monitor-card-right-bottom"
-            @click="setMainCard(sideCards[3])"
-          >
+            @click="setMainCard(sideCards[3])">
             <chart
               :key="sideCards[3].id"
               v-bind="sideCards[3]"
               :date="query.time"
               :is-real-time="isRealTime"
-              :token="token"
-            />
+              :token="token" />
           </div>
         </div>
       </div>
@@ -439,12 +422,10 @@ onMounted(() => {
       title="筛选条件"
       width="1120px"
       class="monitor-search-dialog"
-      destroy-on-close
-    >
+      destroy-on-close>
       <el-form size="default" class="search-container grid grid-cols-12 gap-6">
         <div
-          class="absolute left-0 top-0 w-[2px] h-full bg-gradient-to-b from-transparent via-cyan-500 to-transparent"
-        ></div>
+          class="absolute left-0 top-0 w-[2px] h-full bg-gradient-to-b from-transparent via-cyan-500 to-transparent"></div>
         <el-form-item class="col-span-3" label="部门">
           <el-cascader
             v-model="deviceQuery.deptId"
@@ -455,8 +436,7 @@ onMounted(() => {
             :show-all-levels="false"
             :props="{ checkStrictly: true, label: 'name', value: 'id' }"
             class="w-full"
-            placeholder="请选择部门"
-          />
+            placeholder="请选择部门" />
         </el-form-item>
         <el-form-item class="col-span-3" label="在线状态">
           <el-select
@@ -467,14 +447,12 @@ onMounted(() => {
             popper-class="poper"
             class="w-full"
             :class="{ selected: Boolean(deviceQuery.ifInline) }"
-            @change="handleInlineChange"
-          >
+            @change="handleInlineChange">
             <el-option
               v-for="dict in getStrDictOptions(DICT_TYPE.IOT_DEVICE_STATUS)"
               :key="dict.value"
               :label="dict.label"
-              :value="dict.value"
-            />
+              :value="dict.value" />
           </el-select>
         </el-form-item>
         <el-form-item class="col-span-6 time-range-item" label="时间范围">
@@ -489,8 +467,7 @@ onMounted(() => {
             :teleported="false"
             popper-class="poper"
             class="w-full time-range-picker"
-            @change="handleTimeChange"
-          />
+            @change="handleTimeChange" />
         </el-form-item>
         <el-form-item class="col-span-12" label="设备">
           <el-select
@@ -503,8 +480,7 @@ onMounted(() => {
             class="w-full"
             tag-type="primary"
             filterable
-            @change="handleDeviceChange"
-          />
+            @change="handleDeviceChange" />
         </el-form-item>
       </el-form>
 
@@ -516,8 +492,7 @@ onMounted(() => {
           <el-button
             size="default"
             class="custom-btn primary-btn"
-            @click="showSearchDialog = false"
-          >
+            @click="showSearchDialog = false">
             关闭
           </el-button>
         </div>

文件差異過大導致無法顯示
+ 550 - 407
src/views/oli-connection/monitoring/detail.vue


部分文件因文件數量過多而無法顯示