Преглед изворни кода

[Feat 0000] 开发并对接监测设备控制下发功能到监测通用组件中并在塔山喷淋中应用

houzekong пре 4 месеци
родитељ
комит
2009727533

+ 166 - 5
src/components/vent/BasicMonitoring.vue

@@ -1,4 +1,5 @@
 <template>
+  <!-- 场景选择下拉框 -->
   <customHeader
     :fieldNames="{ label: 'systemname', value: 'id', options: 'children' }"
     :options="options"
@@ -7,10 +8,21 @@
   >
     {{ mainTitle }}
   </customHeader>
+  <!-- 默认插槽,一般用来放模型 -->
   <slot :monitor-data="monitorData"></slot>
   <div class="scene-box">
     <div class="center-container">
+      <!-- 监测模块 -->
       <template v-if="activeKey == 'monitor'">
+        <slot name="opration">
+          <div class="button-wrapper">
+            <template v-for="item in mainConfig.operations" :key="item.key">
+              <template v-if="hasPermission(item.permission)">
+                <div :class="{ 'button-box': true, 'button-box-disable': item.disabled }" @click="handleOperate(item)">{{ item.label }} </div>
+              </template>
+            </template>
+          </div>
+        </slot>
         <slot name="monitor">
           <ModuleCommon
             v-for="cfg in mainConfig.configs"
@@ -25,6 +37,7 @@
         </slot>
       </template>
       <div v-else class="history-group">
+        <!-- 场景下关联的设备有很多,在这里选择 -->
         <div v-if="showDeviceList && deviceList.length > 0" class="device-button-group">
           <div
             v-for="(device, index) in deviceList"
@@ -70,6 +83,12 @@
     </div>
     <BottomMenu @change="changeActive" />
   </div>
+  <PasswordModal
+    :modal-is-show="passwordModalShown"
+    :modal-title="operatingTarget?.label"
+    @handle-ok="handlePasswordOK"
+    @handle-cancel="passwordModalShown = false"
+  />
 </template>
 
 <script setup lang="ts">
@@ -83,15 +102,27 @@
   import AlarmHistoryTable from '/@/views/vent/monitorManager/comment/AlarmHistoryTable.vue';
   import { useRouter } from 'vue-router';
   import { Config } from '/@/views/vent/deviceManager/configurationTable/types';
-  import { message } from 'ant-design-vue';
+  import { message, Modal } from 'ant-design-vue';
   import _ from 'lodash';
+  import PasswordModal from '/@/views/vent/monitorManager/comment/components/PasswordModal.vue';
+  import { usePermission } from '/@/hooks/web/usePermission';
+  import { deviceControlApi } from '/@/api/vent';
 
   type DeviceType = { deviceType: string; deviceName: string; datalist: any[] };
+  type Operation = {
+    label: string;
+    key: string;
+    value: string;
+    disabled?: boolean;
+    showPassword?: boolean;
+    permission?: string;
+    onOk?: (key: string, value: string, pwd?: string) => Promise<void>;
+  };
 
   const props = withDefaults(
     defineProps<{
       mainTitle: string;
-      /** 是否显示历史数据上方的设备列表 */
+      /** 是否显示历史数据上方的设备类型选择器 */
       showDeviceList?: boolean;
       /** 请求场景数据传入的类型字符 */
       strtype: string;
@@ -101,6 +132,7 @@
       // deviceType: string;
       /** 主要模块配置 */
       mainConfig: {
+        operations: Operation[];
         configs: Config[];
         /** 获取该场景所含设备及其监测信息的API */
         monitorApi?: (params: { deviceType: string; deviceId: number | string }) => Promise<any>;
@@ -141,6 +173,7 @@
     }>(),
     {
       mainConfig: () => ({
+        operations: [],
         configs: [],
       }),
       monitorHistoryConfig: () => ({}),
@@ -152,6 +185,7 @@
   );
 
   const { currentRoute } = useRouter();
+  const { hasPermission } = usePermission();
 
   const activeKey = ref('monitor');
 
@@ -159,7 +193,9 @@
     activeKey.value = activeValue;
   }
 
+  /** 场景选项 */
   const options = ref([]);
+  /** 已选择了的场景的id */
   const optionValue = ref('');
 
   /** 获取左上角场景选择框数据的方法,如果此时初始场景未赋值则选择首项做初始化 */
@@ -180,17 +216,18 @@
     getDeviceList();
   }
 
-  //关联设备
+  /** 当前场景所关联设备 */
   const deviceList = ref<DeviceType[]>([]);
   const deviceActive = ref('');
   const deviceType = ref('');
 
+  /** 选择设备 */
   function deviceChange(index) {
     deviceType.value = deviceList.value[index]?.deviceType || '';
     deviceActive.value = deviceList.value[index]?.deviceType || '';
   }
 
-  // 查询关联设备列表
+  /** 查询当前场景所关联设备列表 */
   async function getDeviceList() {
     const { msgTxt = [] } = await getDevice({ devicetype: 'sys', systemID: optionValue.value }).catch(() => {
       message.error('获取已绑定设备时发生了错误');
@@ -217,6 +254,7 @@
   }
 
   let timer: NodeJS.Timeout;
+  /** 场景的监测数据 */
   const monitorData = ref<any>({});
   /** 获取本场景下所绑定的设备,将监测数据赋值 */
   async function getMonitor() {
@@ -241,6 +279,59 @@
     }
   }
 
+  /** 密码提示框是否显示 */
+  const passwordModalShown = ref(false);
+  /** 下发操作时的目标配置 */
+  const operatingTarget = ref<Operation>();
+
+  /** 操作按钮点击后根据配置弹出确认框,初始化数据 */
+  function handleOperate(item: Operation) {
+    if (item.disabled) return;
+    operatingTarget.value = item;
+
+    if (item.showPassword) {
+      passwordModalShown.value = true;
+    } else {
+      Modal.confirm({
+        title: '操作确认',
+        content: `确定要进行${operatingTarget.value.label}操作吗?`,
+        iconType: 'info',
+        onOk: () => handlePasswordOK(),
+      });
+    }
+  }
+
+  /** 密码输入后确认的回调 */
+  function handlePasswordOK(pwd?: string) {
+    if (!operatingTarget.value) return message.error('操作目标不存在');
+    const { onOk = deviceControl, key, value } = operatingTarget.value;
+
+    return onOk(key, value, pwd)
+      .then(() => {
+        passwordModalShown.value = false;
+      })
+      .finally(() => {
+        operatingTarget.value = undefined;
+      });
+  }
+
+  function deviceControl(key: string, value: string, pwd?: string) {
+    return deviceControlApi({
+      deviceid: optionValue.value,
+      devicetype: deviceType.value,
+      password: pwd,
+      paramcode: key,
+      value: value,
+    })
+      .then((r) => {
+        if (!r.success) throw r.message || '操作失败';
+        message.success('指令下发成功');
+      })
+      .catch((e) => {
+        message.error(typeof e === 'string' ? e : '指令下发失败');
+      });
+  }
+
   onMounted(async () => {
     if (currentRoute.value && currentRoute.value['query'] && currentRoute.value['query']['id']) {
       optionValue.value = currentRoute.value['query']['id'] as string;
@@ -262,7 +353,9 @@
 <style lang="less" scoped>
   @import '/@/design/vent/modal.less';
   @ventSpace: zxm;
+
   .scene-box {
+    --image-tab-group-bg: url('/@/assets/images/vent/tab-group-bg.png');
     margin-top: 40px;
     pointer-events: none;
     .history-group {
@@ -342,9 +435,77 @@
     }
 
     .@{ventSpace}-input-number {
-      border-color: #ffffff88 !important;
+      border-color: #ffffff88;
     }
 
     margin-right: 10px;
   }
+
+  .button-wrapper {
+    position: relative;
+    top: 30px;
+    left: 500px;
+    display: flex;
+    justify-content: flex-start;
+    align-items: center;
+    margin-top: 10px;
+    width: 1165px !important;
+    height: 75px;
+    background: var(--image-tab-group-bg) no-repeat;
+    background-image: 100% 100%;
+    padding: 0 30px;
+    z-index: 10;
+
+    .button-box {
+      margin: 0 10px;
+    }
+  }
+
+  .button-box {
+    position: relative;
+    padding: 5px;
+    border-radius: 5px;
+    width: auto;
+    height: 34px;
+    border: 1px solid var(--vent-base-border);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    color: var(--vent-font-color);
+    padding: 0 10px;
+    cursor: pointer;
+    pointer-events: all;
+
+    &:hover {
+      background: var(--vent-device-manager-control-btn-hover);
+    }
+
+    &::before {
+      width: calc(100% - 6px);
+      height: 26px;
+      content: '';
+      position: absolute;
+      top: 3px;
+      right: 0;
+      left: 3px;
+      bottom: 0;
+      z-index: -1;
+      border-radius: inherit;
+      /*important*/
+      background: var(--vent-device-manager-control-btn);
+    }
+  }
+
+  .button-box-disable {
+    cursor: not-allowed;
+    border: 1px solid var(--vent-base-border);
+
+    &:hover {
+      background: none;
+    }
+
+    &:before {
+      background: linear-gradient(#5897c299, #4a92a899);
+    }
+  }
 </style>

+ 0 - 1
src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.ssl.ts

@@ -132,7 +132,6 @@ class FireDoorSsl {
    * @param {number} [timeScale=0.01] - 动画时间缩放因子,控制动画播放速度
    */
   play(handlerState, timeScale = 0.01) {
-    console.log('debug rrr', handlerState);
     let handler = () => {};
     switch (handlerState) {
       case 1: // 打开门

+ 30 - 9
src/views/vent/monitorManager/sprayMonitor/index.vue

@@ -4,6 +4,7 @@
     <BasicMonitoring
       main-title="凝胶防灭火材料自动喷洒系统"
       :main-config="{
+        operations: operations,
         configs: configs,
       }"
       :monitor-history-config="{}"
@@ -17,17 +18,17 @@
           <div id="sprayCSS3D" v-show="!loading" style="width: 100%; height: 100%; position: absolute; overflow: hidden; pointer-events: none">
             <FourBorderBg id="sprayCSS3DEnvA">
               <div>送料电机</div>
-              <div>电压US:{{ monitorData.slus }}</div>
-              <div>电流LA:{{ monitorData.slla }}</div>
-              <div>电流LB:{{ monitorData.sllb }}</div>
-              <div>电流LC:{{ monitorData.sllc }}</div>
+              <div>电压US:{{ get(monitorData, 'spray_auto[0].readData.SlDjdy', '-') }}</div>
+              <div>电流LA:{{ get(monitorData, 'spray_auto[0].readData.SlDjAdl', '-') }}</div>
+              <div>电流LB:{{ get(monitorData, 'spray_auto[0].readData.SlDjBdl', '-') }}</div>
+              <div>电流LC:{{ get(monitorData, 'spray_auto[0].readData.SlDjCdl', '-') }}</div>
             </FourBorderBg>
             <FourBorderBg id="sprayCSS3DEnvB">
-              <div>输送电机</div>
-              <div>电压US:{{ monitorData.ssus }}</div>
-              <div>电流LA:{{ monitorData.ssla }}</div>
-              <div>电流LB:{{ monitorData.sslb }}</div>
-              <div>电流LC:{{ monitorData.sslc }}</div>
+              <div>注浆电机</div>
+              <div>电压US:{{ get(monitorData, 'spray_auto[0].readData.ZjDjdy', '-') }}</div>
+              <div>电流LA:{{ get(monitorData, 'spray_auto[0].readData.ZjDjAdl', '-') }}</div>
+              <div>电流LB:{{ get(monitorData, 'spray_auto[0].readData.ZjDjBdl', '-') }}</div>
+              <div>电流LC:{{ get(monitorData, 'spray_auto[0].readData.ZjDjCdl', '-') }}</div>
             </FourBorderBg>
           </div>
         </div>
@@ -42,6 +43,7 @@
   import { useInitConfigs } from '../../home/configurable/hooks/useInit';
   import { mountedThree, setModelType } from './spray.three';
   import FourBorderBg from '/@/components/vent/fourBorderBg.vue';
+  import { get } from 'lodash-es';
 
   const defaultConfigs: Config[] = [
     {
@@ -277,6 +279,25 @@
   const { configs, fetchConfigs } = useInitConfigs();
   const loading = ref(false);
 
+  const operations = ref([
+    {
+      label: '开启控制箱',
+      key: 'run_auto_sign',
+      value: '1',
+      disabled: false,
+      showPassword: true,
+      // permission: 'spray:run_auto_sign',
+    },
+    {
+      label: '关闭控制箱',
+      key: 'run_auto_sign',
+      value: '0',
+      disabled: false,
+      showPassword: true,
+      // permission: 'spray:run_auto_sign',
+    },
+  ]);
+
   onMounted(() => {
     fetchConfigs('spray');
     loading.value = true;

+ 0 - 0
src/views/vent/monitorManager/sprayMonitor/spray.api.ts


+ 2 - 4
src/views/vent/monitorManager/sprayMonitor/spray.three.ts

@@ -28,9 +28,7 @@ function dispatchMouseEvent(event) {
 function initEventListender() {
   if (!model) return;
   model.canvasContainer?.addEventListener('mousedown', (e) => dispatchMouseEvent(e));
-  model.orbitControls?.addEventListener('change', () => {
-    console.log('debug pos', model.camera, model.orbitControls);
-  });
+  // model.orbitControls?.addEventListener('change', () => {});
 }
 
 /** 渲染并更新总模型 */
@@ -65,7 +63,7 @@ export function setModelType(modelType: 'spray') {
           if (!model.scene?.getObjectByName(group.name) && group) {
             model.scene?.add(group);
           }
-          await animateCamera({ x: -693, y: 474, z: 398 }, { x: 0, y: 0, z: 0 }, context.cameraPostion, context.orbitControlPostion, model, 0.8);
+          await animateCamera({ x: -693, y: 474, z: 398 }, { x: 0, y: 0, z: 0 }, context.cameraPostion, context.orbitTarget, model, 0.8);
           resolve(null);
         }, 400);
       }

+ 7 - 12
src/views/vent/monitorManager/sprayMonitor/spray.threejs.base.ts

@@ -13,10 +13,10 @@ class ModelContext {
   group: THREE.Object3D | null = null;
   /** 本模型内支持的锚点位置数组 */
   anchors: [number, number, number][] = [
-    [-52.838, 18.5, 9.219],
+    [-0.6, 0.3, -0.05],
     // [0, 0, 0],
     // 右侧传感器
-    [11.7, -14, 8],
+    [-0.3, 0.3, -0.05],
     // [-25.847, 8.783, 3.267],
     // [31.142, 8.783, 3.267],
   ];
@@ -24,17 +24,12 @@ class ModelContext {
   cssSprites: CSS3DSprite[] = [];
   /** 初始化时用到的摄像头位置参数,可以供外部访问或初始化时使用 */
   cameraPostion = {
-    x: 0.03683131196052705,
-    y: -0.010096816429235923,
-    z: 1.217419706517893,
+    x: 0.05342932338990988,
+    y: 0.08324360118266554,
+    z: 1.2186385420339856,
   };
   /** 初始化时用到的滑轨目标参数,可以供外部访问或初始化时使用,配合摄像头可以实现更精确的控制 */
-  // orbitControlPostion = {
-  //   x: 0.11268219812743818,
-  //   y: 1.33090491940089,
-  //   z: 2.379502155322738,
-  // };
-  orbitControlPostion = {
+  orbitTarget = {
     x: 0,
     y: 0,
     z: 0,
@@ -64,7 +59,7 @@ class ModelContext {
         const css3D = new CSS3DSprite(element);
         this.cssSprites.push(css3D);
         css3D.name = selector;
-        css3D.scale.set(0.05, 0.05, 0.05);
+        css3D.scale.set(0.002, 0.002, 0.002);
         // const ff = gui.addFolder(`css元素${index}`);
         // ff.add(css3D.position, 'x', -100, 100);
         // ff.add(css3D.position, 'y', -100, 100);

+ 0 - 1
src/views/vent/monitorManager/windowMonitor/components/windowDualSVG.vue

@@ -2277,7 +2277,6 @@
 
   /** 根据SVG的使用场景播放动画 */
   function animate(data: any) {
-    console.log('debug data', data.OpenDegree, data.OpenDegree1, data.OpenDegree2);
     // 在SVG图片中,找到需要动起来的元素(类似<use xlink:href="#RE_L_0_Layer0_0_FILL"></use>),并填入id即可控制该元素的动画(如有)
     // 开度 / 最大开度 = 动画进度
     if (data.OpenDegree) {