Kaynağa Gözat

智能注氮系统界面及功能调整-提交

lxh 14 saat önce
ebeveyn
işleme
df3f16e8db

BIN
src/assets/images/beltFire/bg-model-green.png


+ 1 - 1
src/utils/threejs/loadGltf.worker.js

@@ -67,7 +67,7 @@ function loadModal(url) {
           modalVal: data,
           versionStr: version,
         };
-        await db.modal.add(model);
+        await db.modal.put(model);
         self.postMessage({ message: 'save', data: model });
         resolve(model);
       });

+ 73 - 117
src/utils/threejs/useThree.ts

@@ -13,9 +13,7 @@ import Stats from 'three/examples/jsm/libs/stats.module.js';
 import { useModelStore } from '/@/store/modules/threejs';
 import TWEEN from 'three/examples/jsm/libs/tween.module.js';
 import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
-import { getList } from '@/views/vent/sys/resources/file.api';
-import { saveModel } from '/@/utils/threejs/util';
-import { getToken, getTenantId } from '/@/utils/auth';
+import { getToken } from '/@/utils/auth';
 
 import { useGlobSetting } from '/@/hooks/setting';
 import { get } from 'sortablejs';
@@ -220,68 +218,55 @@ class UseThree {
               const modalNameStr = modalNameArr[i];
               let modalValue;
               const modalArr = await db.modal.where('modalName').equals(modalNameStr).toArray();
-              if (modalArr.length > 0 && modalArr[0].modalVal.byteLength > 0) {
+              if (modalArr.length > 0 && modalArr[0].modalVal?.byteLength > 0) {
                 modalValue = modalArr[0].modalVal;
               } else if (modalArr.length > 0) {
-                db.modal.delete(modalArr[0].id);
+                // 主键是 modalName,不是自增 id
+                await db.modal.delete(modalNameStr);
               }
-              if (modalValue) {
-                gltfLoader.parse(
-                  modalValue,
-                  '/model/glft/',
-                  (gltf) => {
-                    let object: THREE.Object3D = gltf.scene;
-                    object.traverse((obj) => {
-                      if (obj instanceof THREE.Mesh) {
-                        obj.material.emissiveIntensity = 1;
-                        obj.material.emissiveMap = obj.material.map;
-                        obj.material.blending = THREE.CustomBlending;
-
-                        if (obj.material.opacity < 1) {
-                          obj.material.transparent = true;
-                        }
-                        if (obj.material.map) {
-                          obj.material.map.colorSpace = THREE.SRGBColorSpace;
-                          obj.material.map.flipY = false;
-                          obj.material.map.anisotropy = 1;
-                        }
-                        if (obj.material.emissiveMap) {
-                          obj.material.emissiveMap.colorSpace = THREE.SRGBColorSpace;
-                          obj.material.emissiveMap.flipY = false;
-                        }
-
-                        if (obj.material.map || obj.material.emissiveMap) {
-                          obj.material.needsUpdate = true;
-                        }
-
-                        // if (envMap) {
-                        //   obj.material.envMap = envMap;
-                        //   obj.material.envMapIntensity = 1;
-                        // }
-                        // obj.renderOrder = 1;
-                      }
-                    });
-                    if (isBlender) {
-                      object = object.children[0];
+
+              const finishObject = (gltf) => {
+                let object: THREE.Object3D = gltf.scene;
+                object.traverse((obj) => {
+                  if (obj instanceof THREE.Mesh) {
+                    obj.material.emissiveIntensity = 1;
+                    obj.material.emissiveMap = obj.material.map;
+                    obj.material.blending = THREE.CustomBlending;
+
+                    if (obj.material.opacity < 1) {
+                      obj.material.transparent = true;
+                    }
+                    if (obj.material.map) {
+                      obj.material.map.colorSpace = THREE.SRGBColorSpace;
+                      obj.material.map.flipY = false;
+                      obj.material.map.anisotropy = 1;
+                    }
+                    if (obj.material.emissiveMap) {
+                      obj.material.emissiveMap.colorSpace = THREE.SRGBColorSpace;
+                      obj.material.emissiveMap.flipY = false;
+                    }
+
+                    if (obj.material.map || obj.material.emissiveMap) {
+                      obj.material.needsUpdate = true;
                     }
-                    object.animations = gltf.animations;
-                    object.name = modalNameStr;
-                    if (group) group.add(object);
-                    childResolve(object);
-                  },
-                  (err) => {
-                    console.log(err);
-                    childResolve(null);
                   }
-                );
-              } else {
-                // 开启线程下载
+                });
+                if (isBlender) {
+                  object = object.children[0];
+                }
+                object.animations = gltf.animations;
+                object.name = modalNameStr;
+                if (group) group.add(object);
+                childResolve(object);
+              };
 
-                const result = (await getList({ fileName: modalNameStr })) || [];
-                const file = result['records'][0];
+              if (modalValue) {
+                gltfLoader.parse(modalValue, '/model/glft/', finishObject, (err) => {
+                  console.log(err);
+                  childResolve(null);
+                });
+              } else {
                 console.log('需要开启线程下载模型资源。。。。。');
-
-                // 如果是常村时
                 const token = getToken();
                 fetch(`${baseApiUrl}/sys/common/static/webfile/${modalNameStr}.glb`, {
                   method: 'GET',
@@ -292,67 +277,38 @@ class UseThree {
                     'X-Access-Token': token,
                     token: token,
                   },
-                }).then(async (data) => {
-                  const arrayBuffer = await data.arrayBuffer();
-                  // 将资源存放到db
-                  const fileName = modalNameStr;
-                  const model = {
-                    modalName: fileName,
-                    modalVal: arrayBuffer,
-                    versionStr: fileName,
-                  };
-                  db.open();
-                  await db.modal.add(model);
-                  gltfLoader.parse(
-                    arrayBuffer,
-                    '/model/glft/',
-                    (gltf) => {
-                      let object: THREE.Object3D = gltf.scene;
-                      // setModalCenter(object);
-                      object.traverse((obj) => {
-                        if (obj instanceof THREE.Mesh) {
-                          obj.material.emissiveIntensity = 1;
-                          obj.material.emissiveMap = obj.material.map;
-                          obj.material.blending = THREE.CustomBlending;
-
-                          if (obj.material.opacity < 1) {
-                            obj.material.transparent = true;
-                          }
-                          if (obj.material.map) {
-                            obj.material.map.colorSpace = THREE.SRGBColorSpace;
-                            obj.material.map.flipY = false;
-                            obj.material.map.anisotropy = 1;
-                          }
-                          if (obj.material.emissiveMap) {
-                            obj.material.emissiveMap.colorSpace = THREE.SRGBColorSpace;
-                            obj.material.emissiveMap.flipY = false;
-                          }
-
-                          if (obj.material.map || obj.material.emissiveMap) {
-                            obj.material.needsUpdate = true;
-                          }
-
-                          // if (envMap) {
-                          //   obj.material.envMap = envMap;
-                          //   obj.material.envMapIntensity = 1;
-                          // }
-                          // obj.renderOrder = 1;
-                        }
-                      });
-                      if (isBlender) {
-                        object = object.children[0];
-                      }
-                      object.animations = gltf.animations;
-                      object.name = modalNameStr;
-                      if (group) group.add(object);
-                      childResolve(object);
-                    },
-                    (err) => {
-                      console.log(err);
+                })
+                  .then(async (data) => {
+                    if (!data.ok) {
+                      console.warn(`[setGLTFModel] 模型下载失败: ${modalNameStr}.glb`, data.status);
                       childResolve(null);
+                      return;
                     }
-                  );
-                });
+                    const arrayBuffer = await data.arrayBuffer();
+                    if (!arrayBuffer || arrayBuffer.byteLength < 1) {
+                      childResolve(null);
+                      return;
+                    }
+                    const model = {
+                      modalName: modalNameStr,
+                      modalVal: arrayBuffer,
+                      versionStr: modalNameStr,
+                    };
+                    try {
+                      // put 可覆盖同名主键,避免 ConstraintError: Key already exists
+                      await db.modal.put(model);
+                    } catch (dbError) {
+                      console.warn(`[setGLTFModel] 缓存模型失败: ${modalNameStr}`, dbError);
+                    }
+                    gltfLoader.parse(arrayBuffer, '/model/glft/', finishObject, (err) => {
+                      console.log(err);
+                      childResolve(null);
+                    });
+                  })
+                  .catch((error) => {
+                    console.warn(`[setGLTFModel] 模型请求异常: ${modalNameStr}`, error);
+                    childResolve(null);
+                  });
               }
             } catch (error) {
               console.log(error);

+ 1 - 5
src/utils/threejs/util.ts

@@ -563,11 +563,7 @@ export function saveModel(fileName, path, version) {
         modalVal: data,
         versionStr: version,
       };
-      const modalArr = await db.modal.where('modalName').equals(fileName).toArray();
-      if (modalArr.length > 0) {
-        db.modal.delete(fileName);
-      }
-      await db.modal.add(model);
+      await db.modal.put(model);
     });
   } catch (error) {}
 }

+ 63 - 18
src/views/vent/home/configurable/components/preset/QHCurve.vue

@@ -16,7 +16,14 @@
   //   import { useGlobSetting } from '/@/hooks/setting';
   //   const { sysOrgCode } = useGlobSetting();
 
-  const props = defineProps<{ mainfan: Record<string, any>; /** QH */ fan1Prop: [string, string]; fan2Prop: [string, string] }>();
+  const props = defineProps<{
+    mainfan: Record<string, any>;
+    /** QH */
+    fan1Prop: [string, string];
+    fan2Prop: [string, string];
+    /** 绿色版主通风机:收紧边距、保证刻度与轴名完整显示 */
+    compact?: boolean;
+  }>();
   const selectDataObj = ref({
     dataQ: 0,
     dataH: 0,
@@ -98,6 +105,9 @@
   function getOption() {
     nextTick(() => {
       const myChart = echarts.init(main.value);
+      const compact = !!props.compact;
+      const labelSize = compact ? 11 : 14;
+      const nameSize = compact ? 11 : 12;
       let option = {
         title: {
           textStyle: {
@@ -106,19 +116,30 @@
           },
           text: '',
         },
-        grid: {
-          top: '25%',
-          left: '5%',
-          right: '19%',
-          bottom: '8%',
-          containLabel: true,
-        },
+        grid: compact
+          ? {
+              top: 28,
+              left: 6,
+              right: 52,
+              bottom: 6,
+              containLabel: true,
+            }
+          : {
+              top: '25%',
+              left: '5%',
+              right: '19%',
+              bottom: '8%',
+              containLabel: true,
+            },
         legend: {
           // x:'right',
-          top: '5%',
+          top: compact ? 2 : '5%',
+          itemWidth: compact ? 14 : 25,
+          itemHeight: compact ? 8 : 14,
+          itemGap: compact ? 12 : 10,
           textStyle: {
             color: '#ffffff',
-            fontSize: 14, // 字体颜色
+            fontSize: compact ? 12 : 14, // 字体颜色
           },
           data: ['风量', '负压'],
         },
@@ -137,14 +158,33 @@
             return res;
           },
           trigger: 'item',
+          // 紧凑模式下悬浮卡片下移,避免挡住左上角刻度与单位
+          position: compact
+            ? (point, _params, _dom, _rect, size) => {
+                const contentW = size.contentSize[0];
+                const contentH = size.contentSize[1];
+                const viewW = size.viewSize[0];
+                const viewH = size.viewSize[1];
+                let x = point[0] + 14;
+                let y = point[1] + 36;
+                if (x + contentW > viewW - 4) x = Math.max(4, point[0] - contentW - 14);
+                if (y + contentH > viewH - 4) y = Math.max(4, viewH - contentH - 4);
+                return [x, y];
+              }
+            : undefined,
         },
         color: ['#00bb00', '#ffbb00', '#ff0000', '#0000ff'],
         xAxis: [
           {
-            name: '风量\r\n(m³/min)\r\n',
+            name: compact ? '风量\n(m³/min)' : '风量\r\n(m³/min)\r\n',
+            nameGap: compact ? 4 : 15,
             nameTextStyle: {
               color: '#3df6ff',
-              fontSize: 12,
+              fontSize: nameSize,
+              lineHeight: compact ? 14 : 18,
+              // 紧凑模式下单位上移,避免与横轴刻度重叠
+              padding: compact ? [-20, 0, 0, 2] : undefined,
+              verticalAlign: compact ? 'bottom' : undefined,
             },
             axisLine: {
               lineStyle: {
@@ -162,9 +202,11 @@
             axisLabel: {
               show: true,
               position: 'bottom',
+              hideOverlap: true,
+              margin: compact ? 6 : 8,
               textStyle: {
                 color: '#b3b8cc',
-                fontSize: 14,
+                fontSize: labelSize,
               },
               formatter: function (value) {
                 return value * 60 + '';
@@ -178,7 +220,7 @@
             name: '',
             nameTextStyle: {
               color: '#3df6ff',
-              fontSize: 12,
+              fontSize: nameSize,
             },
             axisTick: {
               show: false,
@@ -201,7 +243,7 @@
               show: false,
               textStyle: {
                 color: '#b3b8cc',
-                fontSize: 14,
+                fontSize: labelSize,
               },
             },
             type: 'value',
@@ -213,10 +255,12 @@
         yAxis: [
           {
             name: '负压(Pa)',
-            splitNumber: 5,
+            splitNumber: compact ? 4 : 5,
+            nameGap: compact ? 6 : 15,
             nameTextStyle: {
               color: '#3df6ff',
-              fontSize: 12,
+              fontSize: nameSize,
+              padding: compact ? [0, 0, 0, 4] : undefined,
             },
             axisLine: {
               show: true,
@@ -234,9 +278,10 @@
             },
             axisLabel: {
               show: true,
+              margin: compact ? 4 : 8,
               textStyle: {
                 color: '#b3b8cc',
-                fontSize: 14,
+                fontSize: labelSize,
               },
             },
             type: 'value',

+ 5 - 5
src/views/vent/home/configurable/configurable.data.ts

@@ -482,11 +482,11 @@ export const testConfigVent: Config[] = [
         items: [
           {
             name: 'board',
-            basis: '38%',
+            basis: '32%',
           },
           {
             name: 'qh_curve',
-            basis: '62%',
+            basis: '68%',
           },
         ],
       },
@@ -527,7 +527,7 @@ export const testConfigVent: Config[] = [
       to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
     },
     showStyle: {
-      size: 'width:390px;height:260px;',
+      size: 'width:390px;height:275px;',
       version: '原版',
       position: 'top:5px;left:15px;',
     },
@@ -589,7 +589,7 @@ export const testConfigVent: Config[] = [
     showStyle: {
       size: 'width:390px;height:260px;',
       version: '原版',
-      position: 'top:290px;left:15px;',
+      position: 'top:305px;left:15px;',
     },
   },
   // {
@@ -6020,7 +6020,7 @@ export const testConfigBDDust: Config[] = [
     showStyle: {
       size: 'width:420px;height:270px;',
       version: '保德',
-      position: 'top:0px;right:10px;',
+      position: 'top:6px;right:10px;',
     },
   },
   {

+ 7 - 0
src/views/vent/home/configurable/green/components/CustomGallery-green.vue

@@ -251,6 +251,13 @@ withDefaults(
   display: block;
 }
 
+/* 智能喷雾降尘装置:与标题留出间距 */
+.gallery_E {
+  margin-top: 8px;
+  height: calc(100% - 8px);
+  box-sizing: border-box;
+}
+
 .gallery-item_center_E {
   background: var(--image-img-8) no-repeat;
   width: 200px;

+ 9 - 2
src/views/vent/home/configurable/green/components/content-green.vue

@@ -89,7 +89,13 @@
           <BlastDelta class="content__module" :pos-monitor="config.data" :canvasSize="{ width: 250, height: 178 }" />
         </template>
         <template v-if="config.name === 'qh_curve'">
-          <QHCurve class="content__module content__qh-curve" :mainfan="config.data" :fan1-prop="config.config.fan1Prop" :fan2-prop="config.config.fan2Prop" />
+          <QHCurve
+            class="content__module content__qh-curve"
+            :mainfan="config.data"
+            :fan1-prop="config.config.fan1Prop"
+            :fan2-prop="config.config.fan2Prop"
+            :compact="deviceType === 'fanmain'"
+          />
         </template>
         <template v-if="config.name === 'device_alarm'">
           <DeviceAlarm class="content__module" :devicedata="config.data" />
@@ -597,9 +603,10 @@
   }
 
   .content__qh-curve {
-    padding-top: 2px;
+    padding: 0 2px 2px;
     box-sizing: border-box;
     overflow: hidden;
+    min-height: 0;
   }
 
   /* 预警监测时间轴圆点/轴线:适配绿色主题,不影响其他页面 */

+ 2 - 0
src/views/vent/home/configurable/green/components/green-nav.vue

@@ -117,6 +117,7 @@
       font-size: 20px;
       letter-spacing: 2px;
       color: #fff;
+      text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9), 0 0 6px rgba(0, 0, 0, 0.75);
     }
 
     .nav-menu {
@@ -146,6 +147,7 @@
       .nav-menu-active {
         background: var(--image-model_nav-menu-active) no-repeat;
         background-size: 100% 100%;
+        text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9), 0 0 6px rgba(0, 0, 0, 0.75);
       }
 
       .nav-menu-item {

+ 5 - 0
src/views/vent/home/configurable/green/dust-green.vue

@@ -166,6 +166,11 @@
       top: 96px;
       z-index: 0;
       pointer-events: auto;
+
+      :deep(.modal-bg) {
+        background: url('/@/assets/images/beltFire/bg-model-green.png') no-repeat center;
+        background-size: cover;
+      }
     }
   }
 

+ 5 - 0
src/views/vent/home/configurable/green/fire-green.vue

@@ -210,6 +210,11 @@
       top: 60px;
       z-index: 0;
       pointer-events: auto;
+
+      :deep(.modal-bg) {
+        background: url('/@/assets/images/beltFire/bg-model-green.png') no-repeat center;
+        background-size: cover;
+      }
     }
   }
 

+ 5 - 0
src/views/vent/home/configurable/green/vent-green.vue

@@ -174,6 +174,11 @@
       top: 110px;
       z-index: 0;
       pointer-events: auto;
+
+      :deep(.modal-bg) {
+        background: url('/@/assets/images/beltFire/bg-model-green.png') no-repeat center;
+        background-size: cover;
+      }
     }
   }
 

+ 6 - 6
src/views/vent/monitorManager/compressor/components/ceshi.json

@@ -28,7 +28,7 @@
                         "syswarnLevel_str": null,
                         "syswarnLevel_des": null,
                         "warnTime": null,
-                        "readTime": "2026-10-16 11:16:35",
+                        "readTime": "2026-10-20 08:59:10",
                         "warnDes": "",
                         "frontGateOpenCtrl": null,
                         "rearGateOpenCtrl": null,
@@ -110,7 +110,7 @@
                             "jz3_fjkz": "0",
                             "jz3_ysj_jw": "20.02",
                             "kyj_6h_yx": "0",
-                            "tTime": "2026-10-16 11:16:31",
+                            "tTime": "2026-10-20 08:59:08",
                             "kyj_2h_pqyl": "0",
                             "jz2_bcljll": "0",
                             "jz2_hyl": "20.50",
@@ -188,13 +188,13 @@
                         "syswarnLevel_str": null,
                         "syswarnLevel_des": null,
                         "warnTime": null,
-                        "readTime": "2026-10-16 11:16:35",
+                        "readTime": "2026-10-20 08:59:10",
                         "warnDes": null,
                         "frontGateOpenCtrl": null,
                         "rearGateOpenCtrl": null,
                         "readData": {
                             "sign": "0",
-                            "tTime": "2026-10-16 11:16:30",
+                            "tTime": "2026-10-20 08:59:05",
                             "isRun": "-2"
                         },
                         "readDataDes": null,
@@ -304,5 +304,5 @@
             }
         ]
     },
-    "timestamp": 1792120599543
-}
+    "timestamp": 1792457952949
+}

+ 2 - 2
src/views/vent/monitorManager/compressor/components/nitrogenHomeNew.vue

@@ -77,7 +77,7 @@
   import { list } from '../nitrogen.api';
   import { SvgIcon } from '/@/components/Icon';
   import BarAndLineCustom from '/@/components/chart/BarAndLineCustom.vue';
-  import { zhudanOption } from '../nitrogen.data.ts';
+  import { zhudanOption } from '../nitrogen.data';
 
   interface PointField {
     code: string;
@@ -190,7 +190,7 @@
 
   async function getReadData() {
     const res = await list({ devicetype: 'sys', systemID: props.deviceId, type: 'all' });
-    const msgTxt = res?.result?.msgTxt || [];
+    const msgTxt = res?.msgTxt || [];
     const nitrogenBlock = msgTxt.find((item) => item.type === 'nitrogen_auto');
     return nitrogenBlock?.datalist?.[0]?.readData || {};
   }

+ 7 - 4
src/views/vent/monitorManager/compressor/nitrogen.threejs.ts

@@ -178,13 +178,16 @@ export const mountedThree = (undergroundModelName = 'nitrogenUnderground') => {
     nitrogenUndergroundObj = new NitrogenUnderground(model, undergroundModelName);
     await nitrogenUndergroundObj.mountedThree();
 
-    // 地下管路模型(基底 + 注氮机),作为新增视图与上面两个共存
-    nitrogenFlexObj = new NitrogenFlex(model);
-    await nitrogenFlexObj.mountedThree();
-
+    // 先展示地下主模型,避免柔性模型资源缺失/缓存异常阻塞整个监控界面
     setModelType('nitrogenUnderground');
     resolve(null);
     model.animate();
+
+    // 地下管路模型(基底 + 注氮机)按需后台加载,失败不影响主界面
+    nitrogenFlexObj = new NitrogenFlex(model);
+    nitrogenFlexObj.mountedThree().catch((error) => {
+      console.warn('[nitrogen] 柔性模型加载失败,已跳过', error);
+    });
   });
 };