Procházet zdrojové kódy

设备动画调试、界面修改

hongrunxia před 2 roky
rodič
revize
e7c36a196e
34 změnil soubory, kde provedl 1275 přidání a 202 odebrání
  1. 1 1
      src/components/Form/src/BasicForm.vue
  2. 6 0
      src/components/Table/src/BasicTable.vue
  3. 4 2
      src/design/vent/index.less
  4. 2 2
      src/design/vent/modal.less
  5. 1 1
      src/layouts/default/header/index.less
  6. 4 4
      src/layouts/default/sider/bottomSideder.vue
  7. 1 1
      src/views/vent/deviceManager/comment/DeviceModal.vue
  8. 0 1
      src/views/vent/deviceManager/comment/NormalTable.vue
  9. 1 1
      src/views/vent/deviceManager/damperTabel/damper.data.ts
  10. 78 0
      src/views/vent/deviceManager/deviceCategory/category.api.ts
  11. 83 0
      src/views/vent/deviceManager/deviceCategory/category.data.ts
  12. 87 0
      src/views/vent/deviceManager/deviceCategory/components/CategoryModal.vue
  13. 285 0
      src/views/vent/deviceManager/deviceCategory/index.vue
  14. 2 1
      src/views/vent/deviceManager/pointTabel/index.vue
  15. 8 0
      src/views/vent/deviceManager/pointTabel/point.api.ts
  16. 130 5
      src/views/vent/deviceManager/pointTabel/point.data.ts
  17. 46 11
      src/views/vent/deviceManager/substationTabel/substation.data.ts
  18. 0 1
      src/views/vent/deviceManager/tableColumns/tableColumns.data.ts
  19. 27 2
      src/views/vent/deviceManager/windWindowTabel/ventanalyWindow.data.ts
  20. 1 1
      src/views/vent/deviceManager/windfindingTabel/windfinding.data.ts
  21. 1 1
      src/views/vent/monitorManager/comment/MonitorTable.vue
  22. 11 2
      src/views/vent/monitorManager/fanLocalMonitor/fanLocal.three.ts
  23. 5 4
      src/views/vent/monitorManager/fanLocalMonitor/index.vue
  24. 58 28
      src/views/vent/monitorManager/gateMonitor/gate.threejs.ts
  25. 202 23
      src/views/vent/monitorManager/gateMonitor/index.vue
  26. 9 3
      src/views/vent/monitorManager/mainFanMonitor/main.threejs.ts
  27. 7 6
      src/views/vent/monitorManager/sensorMonitor/index.vue
  28. 30 14
      src/views/vent/monitorManager/windowMonitor/index.vue
  29. 8 4
      src/views/vent/monitorManager/windowMonitor/window.threejs.ts
  30. 39 23
      src/views/vent/monitorManager/windrectMonitor/duishe.threejs.ts
  31. 39 2
      src/views/vent/monitorManager/windrectMonitor/index.vue
  32. 53 32
      src/views/vent/monitorManager/windrectMonitor/longmen.threejs.ts
  33. 22 6
      src/views/vent/monitorManager/windrectMonitor/windrect.threejs.ts
  34. 24 20
      src/views/vent/monitorManager/windrectMonitor/zhedie.threejs.ts

+ 1 - 1
src/components/Form/src/BasicForm.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="vent-form">
-    <Form v-bind="getBindValue" :class="getFormClass" ref="formElRef" :model="formModel" @keypress.enter="handleEnterPress">
+    <Form v-bind="getBindValue" :class="getFormClass" ref="formElRef" :model="formModel" @keypress.enter="handleEnterPress" autocomplete="off">
       <Row v-bind="getRow">
         <slot name="formHeader"></slot>
         <template v-for="schema in getSchema" :key="schema.field">

+ 6 - 0
src/components/Table/src/BasicTable.vue

@@ -429,4 +429,10 @@
       }
     }
   }
+  
+</style>
+<style lang="less" scoped>
+  :deep(.ant-select-dropdown) {
+    top: 36px !important;
+  }
 </style>

+ 4 - 2
src/design/vent/index.less

@@ -106,7 +106,7 @@
       border-bottom: 1px solid #ececec66;
       background: #fff;
       left: 0px !important;
-      top: 36px !important;
+      // top: 36px !important;
     }
     .ant-upload.ant-upload-select-picture-card,
     .ant-input-affix-wrapper {
@@ -323,7 +323,7 @@
   border-radius: 2px;
   // background-color: #001d3055;
   -webkit-backdrop-filter: blur(8px);
-  backdrop-filter: blur(8px);
+  // backdrop-filter: blur(8px);
   box-shadow: 0 0 20px #44b4ff33 inset;
   background-color: #ffffff11;
   // background-color: #00b3ff12;
@@ -392,3 +392,5 @@
     margin: 15px 12px;
   }
 }
+
+

+ 2 - 2
src/design/vent/modal.less

@@ -431,7 +431,7 @@
         overflow-y: auto;
         .ant-table-column-title,
         .ant-table-thead > tr > th {
-          color: #39f2ff !important;
+          color: #84f2ff !important;
         }
         .ant-progress-text {
           color: #fff !important;
@@ -567,7 +567,7 @@
   & > tr > th,
   .ant-table-column-title {
     // color: #70f9fc !important;
-    color: #39f2ff !important;
+    color: #84f2ff !important;
     border-color: #91e9fe55 !important;
     border-left: none !important;
     // border-right: none !important;

+ 1 - 1
src/layouts/default/header/index.less

@@ -188,7 +188,7 @@
 
     // background: linear-gradient(#02050c 0%, #03114c 100%);
     // border: none;
-    background: linear-gradient(#003f77, #0a134c);
+    background: linear-gradient(#005177, #0a344c);
     border-bottom: 1px solid #81aabf01;
     padding-bottom: 2px;
     box-shadow: 0 0 20px #44caff55 inset;

+ 4 - 4
src/layouts/default/sider/bottomSideder.vue

@@ -152,7 +152,7 @@
         }
         .child-menu-item {
           width: 100px;
-          background-color: #07476b;
+          background-color: #086193;
           border-radius: 2px;
           display: flex;
           align-items: center;
@@ -171,17 +171,17 @@
       margin: 5px 0;
       .program-menu {
         width: 90px;
-        background: linear-gradient(#214ea5, #0f3075);
+        background:linear-gradient(#217aa5, #0f4f75);
         margin-left: 5px;
         text-align: center;
         border-radius: 2px;
         cursor: pointer;
         &:hover {
-          background: linear-gradient(#4281ff, #1c57d4);
+          background: linear-gradient(#42b7ff, #1ca0d4);
         }
       }
       .program-menu-active {
-        background: linear-gradient(#4281ff, #1c57d4);
+        background: linear-gradient(#42adff, #1a8cbb);
       }
       .icon-style {
         margin-right: 10px;

+ 1 - 1
src/views/vent/deviceManager/comment/DeviceModal.vue

@@ -32,7 +32,7 @@
       <a-tab-pane key="5" tab="摄像头配置"
         ><EditRowTable
           :columns="cameraColumns"
-          :list="cameraList.bind(null, { deviceId: deviceData.id })"
+          :list="cameraList.bind(null, { deviceid: deviceData.id })"
           @saveOrUpdate="saveCameraData"
           @deleteById="deleteCameraById"
           :isAdd="true"

+ 0 - 1
src/views/vent/deviceManager/comment/NormalTable.vue

@@ -37,7 +37,6 @@
   import { BasicTable, TableAction } from '/@/components/Table';
   import { useModal } from '/@/components/Modal';
   import DeviceModal from './DeviceModal.vue';
-  import DeviceModalTable from './pointTabel/DeviceModalTable.vue';
   // import { getToken } from '/@/utils/auth';
   // import { useGlobSetting } from '/@/hooks/setting';
   import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';

+ 1 - 1
src/views/vent/deviceManager/damperTabel/damper.data.ts

@@ -159,7 +159,7 @@ export const formSchema: FormSchema[] = [
     componentProps: {
       api: list,
       labelField: 'strname',
-      valueField: 'nsubstationid',
+      valueField: 'id',
     },
   },
   {

+ 78 - 0
src/views/vent/deviceManager/deviceCategory/category.api.ts

@@ -0,0 +1,78 @@
+import { defHttp } from '/@/utils/http/axios';
+import { Modal } from 'ant-design-vue';
+
+enum Api {
+  list = '/sys/dict/DeviceKind/query',
+  save = '/sys/dict/DeviceKind/add',
+  edit = '/sys/dict/DeviceKind/edit',
+  deleteCategory = '/sys/dict/DeviceKind/delete',
+  deleteBatch = '/sys/category/deleteBatch',
+  importExcel = '/sys/category/importExcel',
+  exportXls = '/sys/category/exportXls',
+  loadTreeData = '/sys/category/loadTreeRoot',
+  getChildList = '/sys/dict/getDictItems/',
+  getChildListBatch = '/sys/category/getChildListBatch',
+}
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+/**
+ * 导入api
+ * @param params
+ */
+export const getImportUrl = Api.importExcel;
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) => defHttp.get({ url: Api.list, params });
+/**
+ * 删除
+ */
+export const deleteCategory = (params, handleSuccess) => {
+  return defHttp.delete({ url: Api.deleteCategory, params }, { joinParamsToUrl: true }).then(() => {
+    handleSuccess();
+  });
+};
+/**
+ * 批量删除
+ * @param params
+ */
+export const batchDeleteCategory = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
+        handleSuccess();
+      });
+    },
+  });
+};
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const saveOrUpdateDict = (params, isUpdate) => {
+  let url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({ url: url, params });
+};
+/**
+ * 查询全部树形节点数据
+ * @param params
+ */
+export const loadTreeData = (params) => defHttp.get({ url: Api.loadTreeData, params });
+/**
+ * 查询子节点数据
+ * @param params
+ */
+export const getChildList = (params) => defHttp.get({ url: Api.getChildList, params });
+/**
+ * 批量查询子节点数据
+ * @param params
+ */
+export const getChildListBatch = (params) => defHttp.get({ url: Api.getChildListBatch, params }, { isTransformResponse: false });

+ 83 - 0
src/views/vent/deviceManager/deviceCategory/category.data.ts

@@ -0,0 +1,83 @@
+import { BasicColumn } from '/@/components/Table';
+import { FormSchema } from '/@/components/Table';
+
+export const columns: BasicColumn[] = [
+  {
+    title: '类型名称',
+    dataIndex: 'itemText',
+    width: 350,
+    align: 'left',
+  },
+  {
+    title: '值',
+    dataIndex: 'itemValue',
+  },
+  {
+    title: 'sortOrder',
+    dataIndex: 'code',
+  },
+  {
+    title: '描述',
+    dataIndex: 'description',
+  },
+];
+
+export const searchFormSchema: FormSchema[] = [
+  {
+    label: '类型名称',
+    field: 'itemText',
+    component: 'Input',
+    colProps: { span: 6 },
+  },
+];
+
+export const formSchema: FormSchema[] = [
+  {
+    label: '',
+    field: 'id',
+    component: 'Input',
+    show: false,
+  },
+  {
+    label: '父级类型',
+    field: 'dictId',
+    component: 'TreeSelect',
+    componentProps: {
+      replaceFields: {
+        value: 'key',
+      },
+      dropdownStyle: {
+        maxHeight: '50vh',
+      },
+      getPopupContainer: () => document.body,
+    },
+    show: ({ values }) => {
+      return values.dictId !== '0';
+    },
+    dynamicDisabled: ({ values }) => {
+      return !!values.id;
+    },
+  },
+  {
+    label: '类型名称',
+    field: 'itemText',
+    required: true,
+    component: 'Input',
+  },
+  {
+    label: '值',
+    field: 'itemValue',
+    required: true,
+    component: 'Input',
+  },
+  {
+    label: '排序',
+    field: 'sortOrder',
+    component: 'InputNumber',
+  },
+  {
+    label: '描述',
+    field: 'description',
+    component: 'InputTextArea',
+  },
+];

+ 87 - 0
src/views/vent/deviceManager/deviceCategory/components/CategoryModal.vue

@@ -0,0 +1,87 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="getTitle" @ok="handleSubmit">
+    <BasicForm @register="registerForm" />
+  </BasicModal>
+</template>
+<script lang="ts" setup>
+  import { ref, computed, unref } from 'vue';
+  import { BasicModal, useModalInner } from '/src/components/Modal';
+  import { BasicForm, useForm } from '/src/components/Form';
+  import { formSchema } from '../category.data';
+  import { loadTreeData, saveOrUpdateDict } from '../category.api';
+  // 获取emit
+  const emit = defineEmits(['register', 'success']);
+  const isUpdate = ref(true);
+  const expandedRowKeys = ref([]);
+  const treeData = ref([]);
+  //表单配置
+  const [registerForm, { resetFields, setFieldsValue, validate, updateSchema }] = useForm({
+    schemas: formSchema,
+    showActionButtonGroup: false,
+    labelCol: {
+      xs: { span: 24 },
+      sm: { span: 4 },
+    },
+    wrapperCol: {
+      xs: { span: 24 },
+      sm: { span: 18 },
+    },
+  });
+  //表单赋值
+  const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
+    //重置表单
+    await resetFields();
+    expandedRowKeys.value = [];
+    setModalProps({ confirmLoading: false, minHeight: 80 });
+    isUpdate.value = !!data?.isUpdate;
+    if (data?.record) {
+      //表单赋值
+      await setFieldsValue({
+        ...data.record,
+      });
+    }
+    //父级节点树信息
+    treeData.value = await loadTreeData({ async: false, pcode: '' });
+    updateSchema({
+      field: 'pid',
+      componentProps: { treeData },
+    });
+  });
+  //设置标题
+  const getTitle = computed(() => (!unref(isUpdate) ? '新增字典' : '编辑字典'));
+
+  /**
+   * 根据pid获取展开的节点
+   * @param pid
+   * @param arr
+   */
+  function getExpandKeysByPid(pid, arr) {
+    if (pid && arr && arr.length > 0) {
+      for (let i = 0; i < arr.length; i++) {
+        if (arr[i].key == pid && unref(expandedRowKeys).indexOf(pid) < 0) {
+          expandedRowKeys.value.push(arr[i].key);
+          getExpandKeysByPid(arr[i]['parentId'], unref(treeData));
+        } else {
+          getExpandKeysByPid(pid, arr[i].children);
+        }
+      }
+    }
+  }
+  //表单提交事件
+  async function handleSubmit() {
+    try {
+      let values = await validate();
+      setModalProps({ confirmLoading: true });
+      //提交表单
+      await saveOrUpdateDict(values, isUpdate.value);
+      //关闭弹窗
+      closeModal();
+      //展开的节点信息
+      await getExpandKeysByPid(values['pid'], unref(treeData));
+      //刷新列表(isUpdate:是否编辑;values:表单信息;expandedArr:展开的节点信息)
+      emit('success', { isUpdate: unref(isUpdate), values: { ...values }, expandedArr: unref(expandedRowKeys).reverse() });
+    } finally {
+      setModalProps({ confirmLoading: false });
+    }
+  }
+</script>

+ 285 - 0
src/views/vent/deviceManager/deviceCategory/index.vue

@@ -0,0 +1,285 @@
+<template>
+  <div class="device-manager-box">
+    <!--引用表格-->
+    <BasicTable
+      @register="registerTable"
+      :rowSelection="rowSelection"
+      :expandedRowKeys="expandedRowKeys"
+      @expand="handleExpand"
+      @fetch-success="onFetchSuccess"
+    >
+      <!--插槽:table标题-->
+      <template #tableTitle>
+        <a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
+        <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
+        <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
+        <a-dropdown v-if="selectedRowKeys.length > 0">
+          <template #overlay>
+            <a-menu>
+              <a-menu-item key="1" @click="batchHandleDelete">
+                <Icon icon="ant-design:delete-outlined" />
+                删除
+              </a-menu-item>
+            </a-menu>
+          </template>
+          <a-button
+            >批量操作
+            <Icon icon="ant-design:down-outlined" />
+          </a-button>
+        </a-dropdown>
+      </template>
+      <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" />
+      </template>
+    </BasicTable>
+    <!--字典弹窗-->
+    <CategoryModal @register="registerModal" @success="handleSuccess" />
+  </div>
+</template>
+
+<script lang="ts" name="system-category" setup>
+  //ts语法
+  import { ref, unref } from 'vue';
+  import { BasicTable, TableAction } from '/@/components/Table';
+  import CategoryModal from './components/CategoryModal.vue';
+  import { useModal } from '/@/components/Modal';
+  // import { useMethods } from '/@/hooks/system/useMethods';
+  import { columns, searchFormSchema } from './category.data';
+  import { list, deleteCategory, batchDeleteCategory, getExportUrl, getImportUrl, getChildList, getChildListBatch } from './category.api';
+  import { useListPage } from '/@/hooks/system/useListPage';
+  import { defHttp } from '/@/utils/http/axios';
+
+  const expandedRowKeys = ref([]);
+  // const { handleExportXls, handleImportXls } = useMethods();
+  //字典model
+  const [registerModal, { openModal }] = useModal();
+  // 列表页面公共参数、方法
+  const { prefixCls, onExportXls, onImportXls, tableContext } = useListPage({
+    designScope: 'category-template',
+    tableProps: {
+      title: '设备分类',
+      api: list,
+      columns: columns,
+      actionColumn: {
+        width: 180,
+      },
+      formConfig: {
+        schemas: searchFormSchema,
+      },
+    },
+    exportConfig: {
+      name: '设备分类列表',
+      url: getExportUrl,
+    },
+    importConfig: {
+      url: getImportUrl,
+    },
+  });
+
+  //注册table数据
+  const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] =
+    tableContext;
+
+  /**
+   * 新增事件
+   */
+  function handleCreate() {
+    openModal(true, {
+      isUpdate: false,
+    });
+  }
+
+  /**
+   * 编辑事件
+   */
+  async function handleEdit(record) {
+    openModal(true, {
+      record,
+      isUpdate: true,
+    });
+  }
+
+  /**
+   * 详情
+   */
+  async function handleDetail(record) {
+    openModal(true, {
+      record,
+      isUpdate: true,
+      hideFooter: true,
+    });
+  }
+
+  /**
+   * 删除事件
+   */
+  async function handleDelete(record) {
+    await deleteCategory({ id: record.id }, importSuccess);
+  }
+
+  /**
+   * 批量删除事件
+   */
+  async function batchHandleDelete() {
+    const ids = selectedRowKeys.value.filter((item) => !item.includes('loading'));
+    await batchDeleteCategory({ ids: ids }, importSuccess);
+  }
+  /**
+   * 导入
+   */
+  function importSuccess() {
+    //update-begin---author:wangshuai ---date:20220530  for:[issues/54]树字典,勾选,然后批量删除,系统错误------------
+    (selectedRowKeys.value = []) && reload();
+    //update-end---author:wangshuai ---date:20220530  for:[issues/54]树字典,勾选,然后批量删除,系统错误--------------
+  }
+  /**
+   * 添加下级
+   */
+  function handleAddSub(record) {
+    openModal(true, {
+      record,
+      isUpdate: false,
+    });
+  }
+  /**
+   * 成功回调
+   */
+  async function handleSuccess({ isUpdate, values, expandedArr }) {
+    if (isUpdate) {
+      //编辑回调
+      updateTableDataRecord(values.id, values);
+    } else {
+      if (!values['pid']) {
+        //新增根节点
+        reload();
+      } else {
+        //新增子集
+        expandedRowKeys.value = [];
+        for (let key of unref(expandedArr)) {
+          await expandTreeNode(key);
+        }
+      }
+    }
+  }
+
+  /**
+   * 接口请求成功后回调
+   */
+  function onFetchSuccess(result) {
+    getDataByResult(result.items) && loadDataByExpandedRows();
+  }
+  /**
+   * 根据已展开的行查询数据(用于保存后刷新时异步加载子级的数据)
+   */
+  async function loadDataByExpandedRows() {
+    if (unref(expandedRowKeys).length > 0) {
+      const res = await getChildListBatch({ parentIds: unref(expandedRowKeys).join(',') });
+      if (res.success && res.result.records.length > 0) {
+        //已展开的数据批量子节点
+        let records = res.result.records;
+        const listMap = new Map();
+        for (let item of records) {
+          let pid = item['pid'];
+          if (unref(expandedRowKeys).includes(pid)) {
+            let mapList = listMap.get(pid);
+            if (mapList == null) {
+              mapList = [];
+            }
+            mapList.push(item);
+            listMap.set(pid, mapList);
+          }
+        }
+        let childrenMap = listMap;
+        let fn = (list) => {
+          if (list) {
+            list.forEach((data) => {
+              if (unref(expandedRowKeys).includes(data.id)) {
+                data.children = getDataByResult(childrenMap.get(data.id));
+                fn(data.children);
+              }
+            });
+          }
+        };
+        fn(getDataSource());
+      }
+    }
+  }
+  /**
+   * 处理数据集
+   */
+  function getDataByResult(result) {
+    if (result && result.length > 0) {
+      return result.map((item) => {
+        //判断是否标记了带有子节点
+        if (item['hasChild'] == '1') {
+          let loadChild = { id: item.id + '_loadChild', name: 'loading...', isLoading: true };
+          item.children = [loadChild];
+        }
+        return item;
+      });
+    }
+  }
+  /**
+   *树节点展开合并
+   * */
+  async function handleExpand(expanded, record) {
+    // 判断是否是展开状态,展开状态(expanded)并且存在子集(children)并且未加载过(isLoading)的就去查询子节点数据
+    if (expanded) {
+      expandedRowKeys.value.push(record.id);
+      if (record.children.length > 0 && !!record.children[0].isLoading) {
+        let result = await defHttp.get({ url: `/sys/dict/getDictItems/${record.devicekind + 'kind'}` }, {}); //defHttp.get({ url: `/sys/dict/getDictItems/${record.devicekind + 'kind'}` }, {})
+        if (result && result.length > 0) {
+          record.children = getDataByResult(result);
+        } else {
+          record.children = null;
+          record.hasChild = '0';
+        }
+      }
+    } else {
+      let keyIndex = expandedRowKeys.value.indexOf(record.id);
+      if (keyIndex >= 0) {
+        expandedRowKeys.value.splice(keyIndex, 1);
+      }
+    }
+  }
+  /**
+   *操作表格后处理树节点展开合并
+   * */
+  async function expandTreeNode(key) {
+    let record = findTableDataRecord(key);
+    expandedRowKeys.value.push(key);
+    let result = await getChildList({ pid: key });
+    if (result && result.length > 0) {
+      record.children = getDataByResult(result);
+    } else {
+      record.children = null;
+      record.hasChild = '0';
+    }
+    updateTableDataRecord(key, record);
+  }
+  /**
+   * 操作栏
+   */
+  function getTableAction(record) {
+    return [
+      {
+        label: '编辑',
+        onClick: handleEdit.bind(null, record),
+      },
+      {
+        label: '删除',
+        popConfirm: {
+          title: '确定删除吗?',
+          confirm: handleDelete.bind(null, record),
+        },
+      },
+      {
+        label: '添加下级',
+        onClick: handleAddSub.bind(null, { pid: record.id }),
+      },
+    ];
+  }
+</script>
+
+<style scoped></style>

+ 2 - 1
src/views/vent/deviceManager/pointTabel/index.vue

@@ -13,7 +13,8 @@
       designScope="point-tabel"
       title="点表列表"
       :showTab="false"
-    />
+    >
+  </NormalTable>>
   </div>
 </template>
 

+ 8 - 0
src/views/vent/deviceManager/pointTabel/point.api.ts

@@ -10,6 +10,7 @@ enum Api {
   deleteBatch = '/sys/user/deleteBatch',
   importExcel = '/sys/user/importExcel',
   exportXls = '/sys/user/exportXls',
+  queryDevice = '/sys/dict/DeviceKind/query',
 }
 /**
  * 导出api
@@ -20,6 +21,13 @@ export const getExportUrl = Api.exportXls;
  * 导入api
  */
 export const getImportUrl = Api.importExcel;
+
+/**
+ * 列表接口
+ * @param params
+ */
+export const queryDeviceList = (params) => defHttp.get({ url: Api.queryDevice, params });
+
 /**
  * 列表接口
  * @param params

+ 130 - 5
src/views/vent/deviceManager/pointTabel/point.data.ts

@@ -1,8 +1,8 @@
 import { BasicColumn } from '/@/components/Table';
 import { FormSchema } from '/@/components/Table';
-import { selectDevice } from './point.api';
-import { rules } from '/@/utils/helper/validator';
-import { render } from '/@/utils/common/renderUtils';
+import { queryDeviceList } from './point.api';
+import { defHttp } from '/@/utils/http/axios';
+
 export const columns: BasicColumn[] = [
   {
     title: '设备类型',
@@ -111,9 +111,54 @@ export const formSchema: FormSchema[] = [
     show: false,
   },
   {
-    label: '设备类',
+    label: '设备类',
     field: 'devicekind',
-    component: 'MTreeSelect',
+    component: 'ApiSelect',
+    // componentProps: {
+    //   dictCode: 'devicekind',
+    //   placeholder: '请选择设备分类',
+    // },
+    componentProps: ({ formModel, formActionType }) => {
+      return {
+        // options: provincesOptions,
+        placeholder: '请选择设备分类',
+        api: queryDeviceList,
+        resultField: 'result',
+        // use name as label
+        labelField: 'itemText',
+        // use id as value
+        valueField: 'itemValue',
+        onChange: (e: any) => {
+          formModel.devicetype = '';
+          const { updateSchema } = formActionType;
+          updateSchema({
+            field: 'devicetype',
+            componentProps: {
+              api: (params) => defHttp.get({ url: `/sys/dict/getDictItems/${e + 'kind'}` }, params),
+              resultField: 'result',
+              labelField: 'title',
+              valueField: 'value',
+            },
+          });
+        },
+      };
+    },
+  },
+  {
+    label: '点表分类',
+    field: 'devicetype',
+    component: 'ApiSelect',
+    componentProps: ({ formModel, formActionType }) => {
+      debugger;
+      return {
+        // options: provincesOptions,
+        componentProps: {},
+        api: (params) => defHttp.get({ url: `/sys/dict/getDictItems/${formModel.devicekind + 'kind'}` }, params),
+        resultField: 'result',
+        labelField: 'title',
+        valueField: 'value',
+      };
+    },
   },
   {
     label: '值名称',
@@ -125,4 +170,84 @@ export const formSchema: FormSchema[] = [
     field: 'valuecode',
     component: 'Input',
   },
+  {
+    label: '值类型',
+    field: 'valuetype',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'valuetype',
+      placeholder: '请选择设备类型',
+      stringToNumber: true,
+    },
+  },
+
+  {
+    label: '数据类型',
+    field: 'datakind',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'datakind',
+      placeholder: '请选择数据类型',
+      stringToNumber: true,
+    },
+  },
+  {
+    label: '最小值',
+    field: 'fmin',
+    component: 'InputNumber',
+  },
+  {
+    label: '最大值',
+    field: 'fmax',
+    component: 'InputNumber',
+  },
+  {
+    label: '模拟最小值',
+    field: 'testlow',
+    component: 'InputNumber',
+  },
+  {
+    label: '模拟最大值',
+    field: 'testup',
+    component: 'InputNumber',
+  },
+  {
+    label: '小数位数',
+    field: 'floatnum',
+    component: 'InputNumber',
+  },
+  {
+    label: '是否保存',
+    field: 'saveflag',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'booltype',
+      placeholder: '是否保存',
+    },
+  },
+  {
+    label: '开始指令',
+    field: 'startcommand ',
+    component: 'InputTextArea',
+  },
+  {
+    label: '结束指令',
+    field: 'endcommand',
+    component: 'InputTextArea',
+  },
+  {
+    label: '指令默认写入值',
+    field: 'value',
+    component: 'Input',
+  },
+  {
+    label: '控制指令设置模拟数据',
+    field: 'setTestdata',
+    component: 'InputTextArea',
+  },
+  {
+    label: '备注',
+    field: 'remark',
+    component: 'InputTextArea',
+  },
 ];

+ 46 - 11
src/views/vent/deviceManager/substationTabel/substation.data.ts

@@ -101,9 +101,39 @@ export const formSchema: FormSchema[] = [
     label: '读取数据方式',
     field: 'strtype',
     component: 'JDictSelectTag',
+    // componentProps: {
+    //   dictCode: 'getdatatype',
+    //   placeholder: '请选择分站用途',
+    // },
+    componentProps: ({ formModel, formActionType, schema }) => {
+      return {
+        dictCode: 'getdatatype',
+        placeholder: '请选择分站用途',
+        onChange: (e: any) => {
+          const { updateSchema } = formActionType;
+          if (e == 'plc') {
+            updateSchema({
+              field: 'plcType',
+              show: true,
+            });
+          } else {
+            updateSchema({
+              field: 'plcType',
+              show: false,
+            });
+          }
+        },
+      };
+    },
+  },
+  {
+    label: 'PLC类型',
+    field: 'plcType',
+    component: 'JDictSelectTag',
+    show: false,
     componentProps: {
-      dictCode: 'getdatatype',
-      placeholder: '请选择分站用途',
+      dictCode: 'plcType',
+      placeholder: '请选择PLC类型',
     },
   },
   {
@@ -122,15 +152,20 @@ export const formSchema: FormSchema[] = [
     component: 'Input',
   },
   {
-    label: '链接状态',
-    field: 'linkstatus',
-    component: 'JDictSelectTag',
-    componentProps: {
-      dictCode: 'linkstatus',
-      placeholder: '请选择链接状态',
-      stringToNumber: true,
-    },
-  },
+    label: '分站端口',
+    field: 'nport',
+    component: 'InputNumber',
+  },
+  // {
+  //   label: '链接状态',
+  //   field: 'linkstatus',
+  //   component: 'JDictSelectTag',
+  //   componentProps: {
+  //     dictCode: 'linkstatus',
+  //     placeholder: '请选择链接状态',
+  //     stringToNumber: true,
+  //   },
+  // },
   {
     label: '备注',
     field: 'strremark',

+ 0 - 1
src/views/vent/deviceManager/tableColumns/tableColumns.data.ts

@@ -42,7 +42,6 @@ export const searchFormSchema: FormSchema[] = [
     component: 'MTreeSelect',
     colProps: { span: 6 },
   },
-
   {
     label: '值名称',
     field: 'valuename',

+ 27 - 2
src/views/vent/deviceManager/windWindowTabel/ventanalyWindow.data.ts

@@ -30,7 +30,7 @@ export const columns: BasicColumn[] = [
   },
   {
     title: '活动扇叶数量',
-    dataIndex: 'nwindow',
+    dataIndex: 'nwindownum',
     width: 100,
   },
   {
@@ -122,6 +122,11 @@ export const formSchema: FormSchema[] = [
     },
   },
   {
+    label: '最大面积(㎡)',
+    field: 'maxarea',
+    component: 'InputNumber',
+  },
+  {
     label: '风窗净宽(m)',
     field: 'fclearwidth',
     component: 'InputNumber',
@@ -132,11 +137,31 @@ export const formSchema: FormSchema[] = [
     component: 'InputNumber',
   },
   {
-    label: '活动扇叶数量',
+    label: '风窗厚度(m)',
+    field: 'fperdepth',
+    component: 'InputNumber',
+  },
+  {
+    label: '风窗道数',
     field: 'nwindownum',
     component: 'InputNumber',
   },
   {
+    label: '活动扇叶数量',
+    field: 'nwindow',
+    component: 'InputNumber',
+  },
+  {
+    label: '前窗脉冲数',
+    field: 'nfrontplusecircle',
+    component: 'InputNumber',
+  },
+  {
+    label: '后窗脉冲数',
+    field: 'nbackplusecircle ',
+    component: 'InputNumber',
+  },
+  {
     label: '所属分站',
     field: 'nsubstationid',
     component: 'ApiSelect',

+ 1 - 1
src/views/vent/deviceManager/windfindingTabel/windfinding.data.ts

@@ -113,7 +113,7 @@ export const formSchema: FormSchema[] = [
     componentProps: {
       api: list,
       labelField: 'strname',
-      valueField: 'nsubstationid',
+      valueField: 'id',
     },
   },
   {

+ 1 - 1
src/views/vent/monitorManager/comment/MonitorTable.vue

@@ -92,7 +92,7 @@
       maxHeight: tableMaxHeight,
       bordered: false,
       rowKey: 'deviceID',
-      striped: true,
+      // striped: true,
       actionColumn: {
         width: 180,
       },

+ 11 - 2
src/views/vent/monitorManager/fanLocalMonitor/fanLocal.three.ts

@@ -6,6 +6,7 @@ import fcFan from './fcfanLocal.three';
 import fmFan from './fmfanLocal.three';
 import Smoke from '/@/views/vent/comment/threejs/Smoke';
 import gsap from 'gsap';
+import { useAppStore } from '/@/store/modules/app';
 
 const modelName = 'jbfj_hd';
 // 模型对象、 文字对象
@@ -20,6 +21,8 @@ let model,
   playerStartClickTime1 = new Date().getTime(),
   playerStartClickTime2 = new Date().getTime();
 
+const appStore = useAppStore();
+
 // 打灯光
 const addLight = (scene) => {
   // const pointLight2 = new THREE.PointLight(0xffeeee, 1.5, 100);
@@ -266,6 +269,7 @@ export const addCssText = () => {
   if (!group.getObjectByName('text4')) {
     const element = document.getElementById('gateBox') as HTMLElement;
     if (element) {
+      element.innerHTML = '';
       const fanLocalCSS3D = new CSS3DObject(element);
       fanLocalCSS3D.name = 'text4';
       fanLocalCSS3D.scale.set(0.04, 0.04, 0.04);
@@ -277,6 +281,7 @@ export const addCssText = () => {
   if (!group.getObjectByName('text5')) {
     const element = document.getElementById('windownBox') as HTMLElement;
     if (element) {
+      element.innerHTML = '';
       const fanLocalCSS3D = new CSS3DObject(element);
       fanLocalCSS3D.name = 'text5';
       fanLocalCSS3D.scale.set(0.07, 0.07, 0.07);
@@ -464,9 +469,13 @@ const startAnimation = () => {
 // 鼠标点击、松开事件
 const mouseEvent = (event) => {
   event.stopPropagation();
+  const widthScale = appStore.getWidthScale;
+  const heightScale = appStore.getHeightScale;
   // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
-  model.mouse.x = ((event.clientX - model.canvasContainer.getBoundingClientRect().left) / model.canvasContainer.clientWidth) * 2 - 1;
-  model.mouse.y = -((event.clientY - model.canvasContainer.getBoundingClientRect().top) / model.canvasContainer.clientHeight) * 2 + 1;
+  model.mouse.x =
+    ((-model.canvasContainer.getBoundingClientRect().left * widthScale + event.clientX) / (model.canvasContainer.clientWidth * widthScale)) * 2 - 1;
+  model.mouse.y =
+    -((-model.canvasContainer.getBoundingClientRect().top + event.clientY) / (model.canvasContainer.clientHeight * heightScale)) * 2 + 1;
   (model.rayCaster as THREE.Raycaster).setFromCamera(model.mouse, model.camera as THREE.Camera);
   if (group) {
     const intersects = model.rayCaster?.intersectObjects(group.children, false) as THREE.Intersection[];

+ 5 - 4
src/views/vent/monitorManager/fanLocalMonitor/index.vue

@@ -23,13 +23,13 @@
             <p>回风侧瓦斯浓度:{{ selectData.gas3 ? selectData.gas3 : '-' }}</p>
           </div>
         </div>
-        <div v-if="selectRowIndex > 0" class="elementTag" id="gateBox">
+        <div class="elementTag" id="gateBox">
           <div class="elementContent">
-            <p>风门状态:关{{ selectRowIndex }}</p>
+            <p>风门状态:关</p>
             <p>风门过风面积:{{ selectData.gas1 ? selectData.gas1 : '-' }}</p>
           </div>
         </div>
-        <div v-if="selectRowIndex == 0" class="elementTag" id="windownBox">
+        <div  class="elementTag" id="windownBox">
           <div class="elementContent">
             <p>风窗开度:{{ selectData.getRotate1 ? selectData.getRotate1 : '-' }}</p>
             <p>过风面积:{{ selectData.getRotate2 ? selectData.getRotate2 : '-' }}</p>
@@ -382,6 +382,7 @@
     } else if (data['fanStart2'] == 1) {
       mainWindIsShow2.value = 'open';
     }
+    addCssText(selectRowIndex.value);
     return;
   };
 
@@ -501,7 +502,7 @@
     mountedThree(player1.value).then(() => {
       nextTick(() => {
         getMonitor();
-        addCssText();
+        // addCssText(selectRowIndex.value);
 
         playSmoke('startSmoke', 'top', frequencyVal.value, 'open');
       });

+ 58 - 28
src/views/vent/monitorManager/gateMonitor/gate.threejs.ts

@@ -29,6 +29,9 @@ let model, //
   playerStartClickTime1 = new Date().getTime(),
   playerStartClickTime2 = new Date().getTime();
 
+const frontClock = new THREE.Clock();
+const backClock = new THREE.Clock();
+
 const appStore = useAppStore();
 
 const clipActionArr = {
@@ -311,6 +314,7 @@ const enterMY = () => {
 };
 
 /* 风门动画 */
+
 const render = () => {
   if (!model) {
     return;
@@ -334,8 +338,10 @@ const render = () => {
   // }
 
   // 风门开关动画
-  const delta = model.clock?.getElapsedTime();
-  if (model.mixers[0]) model.mixers[0]?.update(delta);
+  const frontDelta = frontClock?.getElapsedTime()+0.5;
+  const backDelta = backClock?.getElapsedTime()+0.5;
+  if (model.mixers[0]) model.mixers[0]?.update(frontDelta); //前门
+  if (model.mixers[1]) model.mixers[1]?.update(backDelta); // 后门
 };
 
 // 鼠标点击、松开事件
@@ -434,6 +440,7 @@ const startAnimation = () => {
 
 /* 提取风门序列帧,初始化前后门动画 */
 const initAnimation = () => {
+  model.mixers = [];
   const tracks = model.animations[0].tracks;
   const fontTracks: any[] = [],
     backTracks: any[] = [];
@@ -446,15 +453,20 @@ const initAnimation = () => {
     }
   }
   const frontDoor = new THREE.AnimationClip('frontDoor', 4, fontTracks);
+  const frontMixer = new THREE.AnimationMixer(group);
+  model.mixers.push(frontMixer);
+  const frontClipAction = frontMixer.clipAction(frontDoor, group);
+  frontClipAction.clampWhenFinished = true;
+  frontClipAction.loop = THREE.LoopOnce;
+  clipActionArr.frontDoor = frontClipAction;
+
   const backDoor = new THREE.AnimationClip('backDoor', 4, backTracks);
-  const arr = [frontDoor, backDoor];
-  arr.forEach((animationClip) => {
-    const clipAction = model.mixers[0].clipAction(animationClip, group);
-    clipAction.clampWhenFinished = true;
-    clipAction.loop = THREE.LoopOnce;
-    if (animationClip.name == 'frontDoor') clipActionArr.frontDoor = clipAction;
-    if (animationClip.name == 'backDoor') clipActionArr.backDoor = clipAction;
-  });
+  const backMixer = new THREE.AnimationMixer(group);
+  model.mixers.push(backMixer);
+  const backClipAction = backMixer.clipAction(backDoor, group);
+  backClipAction.clampWhenFinished = true;
+  backClipAction.loop = THREE.LoopOnce;
+  clipActionArr.backDoor = backClipAction;
 };
 
 export const deviceDetailCard = (position = { x: 0, y: 0, z: 0 }) => {
@@ -470,17 +482,18 @@ export const deviceDetailCard = (position = { x: 0, y: 0, z: 0 }) => {
   model.scene.add(deviceDetailCSS3D);
 };
 // 播放动画
-export const play = (handlerState) => {
+export const play = (handlerState, timeScale = 0.01) => {
   let handler = () => {};
   switch (handlerState) {
     case 1: // 打开前门
       handler = () => {
         clipActionArr.frontDoor.paused = true;
         clipActionArr.frontDoor.reset();
-        clipActionArr.frontDoor.time = 0.5;
-        clipActionArr.frontDoor.timeScale = 0.01;
+        clipActionArr.frontDoor.time = 1.2;
+        clipActionArr.frontDoor.timeScale = timeScale;
         clipActionArr.frontDoor.clampWhenFinished = true;
         clipActionArr.frontDoor.play();
+        frontClock.start();
       };
       break;
     case 2: // 关闭前门
@@ -488,19 +501,21 @@ export const play = (handlerState) => {
         clipActionArr.frontDoor.paused = true;
         clipActionArr.frontDoor.reset(); //
         clipActionArr.frontDoor.time = 4;
-        clipActionArr.frontDoor.timeScale = -0.01;
+        clipActionArr.frontDoor.timeScale = -timeScale;
         clipActionArr.frontDoor.clampWhenFinished = true;
         clipActionArr.frontDoor.play();
+        frontClock.start();
       };
       break;
     case 3: // 打开后门
       handler = () => {
         clipActionArr.backDoor.paused = true;
         clipActionArr.backDoor.reset();
-        clipActionArr.backDoor.time = 0.5;
-        clipActionArr.backDoor.timeScale = 0.01;
+        clipActionArr.backDoor.time = 1.2;
+        clipActionArr.backDoor.timeScale = timeScale;
         clipActionArr.backDoor.clampWhenFinished = true;
         clipActionArr.backDoor.play();
+        backClock.start();
       };
       break;
     case 4: // 关闭后门
@@ -508,9 +523,10 @@ export const play = (handlerState) => {
         clipActionArr.backDoor.paused = true;
         clipActionArr.backDoor.reset();
         clipActionArr.backDoor.time = 4;
-        clipActionArr.backDoor.timeScale = -0.01;
+        clipActionArr.backDoor.timeScale = -timeScale;
         clipActionArr.backDoor.clampWhenFinished = true;
         clipActionArr.backDoor.play();
+        backClock.start();
       };
       break;
     case 5: // 打开前后门
@@ -519,16 +535,18 @@ export const play = (handlerState) => {
         clipActionArr.frontDoor.paused = true;
 
         clipActionArr.frontDoor.reset();
-        clipActionArr.frontDoor.time = 0.5;
+        clipActionArr.frontDoor.time = 0;
         clipActionArr.frontDoor.timeScale = 0.01;
         clipActionArr.frontDoor.clampWhenFinished = true;
         clipActionArr.frontDoor.play();
 
         clipActionArr.backDoor.reset();
-        clipActionArr.backDoor.time = 0.5;
+        clipActionArr.backDoor.time = 0;
         clipActionArr.backDoor.timeScale = 0.01;
         clipActionArr.backDoor.clampWhenFinished = true;
         clipActionArr.backDoor.play();
+        frontClock.start();
+        backClock.start();
       };
       break;
     case 6: // 关闭前后门
@@ -546,13 +564,15 @@ export const play = (handlerState) => {
         clipActionArr.backDoor.timeScale = -0.01;
         clipActionArr.backDoor.clampWhenFinished = true;
         clipActionArr.backDoor.play();
+        frontClock.start();
+        backClock.start();
       };
       break;
     default:
   }
 
   handler();
-  model.clock.start();
+  // model.clock.start();
   // const honglvdeng = group.getObjectByName('honglvdeng');
   // const material = honglvdeng.material;
   // setTimeout(() => {
@@ -583,12 +603,14 @@ export const initOpenState = (selectData) => {
         clipActionArr.frontDoor.clampWhenFinished = true;
         clipActionArr.frontDoor.timeScale = 1;
         clipActionArr.frontDoor.play();
+        frontClock.start();
       } else {
         clipActionArr.frontDoor.reset();
         clipActionArr.frontDoor.time = 4;
         clipActionArr.frontDoor.timeScale = -1;
         clipActionArr.frontDoor.clampWhenFinished = true;
         clipActionArr.frontDoor.play();
+        frontClock.start();
       }
       if (selectData.rearGateOpen == 1) {
         clipActionArr.backDoor.reset();
@@ -596,14 +618,15 @@ export const initOpenState = (selectData) => {
         clipActionArr.backDoor.timeScale = 1;
         clipActionArr.backDoor.clampWhenFinished = true;
         clipActionArr.backDoor.play();
+        backClock.start();
       } else {
         clipActionArr.backDoor.reset();
         clipActionArr.backDoor.time = 4;
         clipActionArr.backDoor.timeScale = -1;
         clipActionArr.backDoor.clampWhenFinished = true;
         clipActionArr.backDoor.play();
+        backClock.start();
       }
-      model.clock.start();
     }, 800);
   });
 };
@@ -614,22 +637,22 @@ export const mountedThree = (playerVal1, playerVal2) => {
     model.setEnvMap('test1');
     model.renderer.toneMappingExposure = 0.8;
     model.setModel(modelName).then((gltf) => {
-      if(gltf){
+      if (gltf) {
         console.log('返回的模型内容', gltf);
         // group = gltf
         group = gltf.scene;
         group.layers.enableAll();
         if (gltf.animations && gltf.animations.length > 0) {
-          model.mixers = [];
+          // model.mixers = [];
           model.animations = [];
           gltf.animations.forEach((animation) => {
-            const mixer = new THREE.AnimationMixer(group);
-            model.mixers.push(mixer);
+            // const mixer = new THREE.AnimationMixer(group);
+            // model.mixers.push(mixer);
             model.animations.push(animation);
           });
         }
         model.scene?.add(group);
-        
+
         // resetCamera();
         setModalPosition();
         // 初始化左右摇摆动画;
@@ -637,8 +660,8 @@ export const mountedThree = (playerVal1, playerVal2) => {
         initAnimation();
         drawHots();
 
-        console.log('加载到渲染完所用时间--->', window['startTime']-new Date().getTime());
-        
+        console.log('加载到渲染完所用时间--->', window['startTime'] - new Date().getTime());
+
         // deviceDetailCard();
         // model.camera.position.set(-1000, 100, 500);
         addLight(model.scene);
@@ -691,6 +714,13 @@ export const destroy = () => {
       model.mixers[0].uncacheAction(clipActionArr.frontDoor, group);
       model.mixers[0].uncacheAction(clipActionArr.backDoor, group);
       model.mixers[0].uncacheRoot(group);
+      
+      model.mixers[1].uncacheClip(clipActionArr.frontDoor.getClip());
+      model.mixers[1].uncacheClip(clipActionArr.backDoor.getClip());
+      model.mixers[1].uncacheAction(clipActionArr.frontDoor, group);
+      model.mixers[1].uncacheAction(clipActionArr.backDoor, group);
+      model.mixers[1].uncacheRoot(group);
+      
       model.animations[0].tracks = [];
     }
     clipActionArr.backDoor = undefined;

+ 202 - 23
src/views/vent/monitorManager/gateMonitor/index.vue

@@ -39,7 +39,7 @@
       <div class="top-right row">
         <div class="control-type row">
           <div class="control-title">控制模式:</div>
-          <a-radio-group v-model:value="selectData.autoRoManual" @change="changeType">
+          <a-radio-group v-model:value="selectData.masterComputer" @change="changeType">
             <a-radio :value="`0`">就地</a-radio>
             <a-radio :value="`1`">远程</a-radio>
           </a-radio-group>
@@ -73,12 +73,23 @@
             title="风门监测"
           >
             <template #filterCell="{ column, record }">
-              <a-tag v-if="column.dataIndex === 'frontGateOpen'" :color="record.frontGateOpen == 0 ? 'default' : 'processing'">{{
-                record.frontGateOpen == 0 ? '关闭' : '打开'
-              }}</a-tag>
-              <a-tag v-if="column.dataIndex === 'rearGateOpen'" :color="record.rearGateOpen == 0 ? 'default' : 'processing'">{{
-                record.rearGateOpen == 0 ? '关闭' : '打开'
-              }}</a-tag>
+              <template v-if="record.frontGateOpenCtrl">
+                <a-tag v-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == 0 && record.frontGateClose == 0" color="red">正在打开</a-tag>
+                <a-tag v-else-if="column.dataIndex === 'frontGateOpen'" color="processing">打开</a-tag>
+              </template>
+              <template v-else>
+                <a-tag v-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == 0 && record.frontGateClose == 0" color="red">正在关闭</a-tag>
+                <a-tag v-else-if="column.dataIndex === 'frontGateOpen'" color="default">关闭</a-tag>
+              </template>
+              <template v-if="record.rearGateOpenCtrl">
+                <a-tag v-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == 0 && record.rearGateClose == 0" color="red">正在打开</a-tag>
+                <a-tag v-else-if="column.dataIndex === 'rearGateOpen'" color="processing">打开</a-tag>
+              </template>
+              <template v-else>
+                <a-tag v-if="column.dataIndex === 'rearGateOpen'  && record.rearGateOpen == 0 && record.rearGateClose == 0" color="red">正在关闭</a-tag>
+                <a-tag v-else-if="column.dataIndex === 'rearGateOpen'" color="default">关闭</a-tag>
+              </template>
+              
               <a-tag v-if="column.dataIndex === 'warnFlag'" :color="record.warnFlag == 0 ? 'green' : 'red'">{{
                 record.warnFlag == 0 ? '正常' : '报警'
               }}</a-tag>
@@ -195,7 +206,7 @@
     frontGateOpen: '0',
     rearGateOpen: '0',
     fault: '气源压力超限',
-    autoRoManual: 0,
+    masterComputer: 0,
   };
   // 监测数据
   const selectData = reactive(lodash.cloneDeep(initData));
@@ -222,7 +233,8 @@
             if (dataSource.value.length > selectRowIndex.value) {
               const data: any = toRaw(dataSource.value[selectRowIndex.value]); //maxarea
               Object.assign(selectData, data);
-              addFmText(selectData);
+              addFmText(data);
+              monitorAnimation(data)
               if (timer) {
                 timer = null;
               }
@@ -242,8 +254,8 @@
     const baseData: any = deviceBaseList.value.find((baseData: any) => baseData.id === selectRow.deviceID);
     Object.assign(selectData, initData, selectRow, baseData);
     // selectData = selectRow;
-    frontDoorIsOpen.value = selectData.frontGateOpen === '1';
-    backDoorIsOpen.value = selectData.rearGateOpen === '1';
+    // frontDoorIsOpen.value = selectData.frontGateOpen === '1';
+    // backDoorIsOpen.value = selectData.rearGateOpen === '1';
     initOpenState(selectData)?.then(() => {
       loading.value = false;
     });
@@ -296,6 +308,7 @@
         break;
     }
   };
+  
 
   const handleOK = (passWord, handlerState) => {
     if (passWord !== '123456') {
@@ -303,12 +316,20 @@
       return;
     }
 
+    if(isFrontRunning && (handlerState == 2 || handlerState == 1 || handlerState == 5 || handlerState == 6)){
+      return
+    }
+
+    if (isRearRunning && (handlerState == 3 || handlerState == 4 || handlerState == 5 || handlerState == 6)) {
+      return
+    }
+    
     const data = {
       deviceid: selectData.deviceID,
       devicetype: selectData.deviceType,
       paramcode: '',
       value: null,
-      autoRoManual: selectData.autoRoManual,
+      masterComputer: selectData.masterComputer,
     };
     let handler = () => {};
 
@@ -367,19 +388,177 @@
     if (data.paramcode) {
       deviceControlApi(data)
         .then((res) => {
-          if (res.success) {
-          }
+          // 模拟时开启
+          // if (res.success) {
+          //   modalIsShow.value = false;
+          //   modalTitle.value = '';
+          //   modalType.value = '';
+          //   handler();
+          //   play(Number(handlerState));
+          // }
         })
-        .finally(() => {
-          modalIsShow.value = false;
-          modalTitle.value = '';
-          modalType.value = '';
-          handler();
-          play(Number(handlerState));
-        });
     }
   };
 
+  /** 开关门动画调用 */
+  let isFrontRunning = false //开关门动作是否在进行
+  let isRearRunning = false //开关门动作是否在进行
+  let frontDeviceState = 0 //记录设备状态,为了与下一次监测数据做比较
+  let rearDeviceState = 0 //记录设备状态,为了与下一次监测数据做比较  
+  //backDoorIsOpen frontDoorIsOpen
+  const monitorAnimation = (selectData) => {
+
+    const timeScale = 0.0003
+    if (selectData.frontGateOpenCtrl) {
+
+      if (selectData.frontGateOpen == 0 && selectData.frontGateClose == 0) {
+        //打开前门1
+        
+        frontDoorIsOpen.value = true
+        backDoorIsOpen.value = true
+        if(!isFrontRunning){
+          isFrontRunning = true
+          play(1, timeScale)
+          frontDeviceState = 1
+        }
+        
+      }
+      if (selectData.frontGateOpen == 1 && selectData.frontGateClose == 0) {
+        isFrontRunning = false
+        if (frontDeviceState != 1) {
+          play(1)
+          frontDeviceState = 1
+          frontDoorIsOpen.value = false
+          backDoorIsOpen.value = true
+        }
+      }
+    } else {
+      if (selectData.frontGateOpen == 0 && selectData.frontGateClose == 0) {
+        //关闭前门
+        frontDoorIsOpen.value = true
+        backDoorIsOpen.value = true
+        if(!isFrontRunning){
+          isFrontRunning = true
+          play(2, timeScale)
+          frontDeviceState = 2
+        }
+        
+      }
+      if (selectData.frontGateClose == 1 && selectData.frontGateOpen == 0) {
+        isFrontRunning = false
+        if (frontDeviceState == 1) {
+          play(2)
+          frontDeviceState = 2
+          frontDoorIsOpen.value = false
+          // backDoorIsOpen.value = false
+        }
+      }
+    }
+    
+    if (selectData.rearGateOpenCtrl) {
+      if (selectData.rearGateOpen == 0 && selectData.rearGateClose == 0) {
+        //打开后门
+        frontDoorIsOpen.value = true
+        backDoorIsOpen.value = true
+        if(!isRearRunning){
+          isRearRunning = true
+          play(3, timeScale)
+          rearDeviceState = 3
+        }
+        
+      }
+      if (selectData.rearGateOpen == 1 && selectData.rearGateClose == 0) {
+        isRearRunning = false
+        
+        if (rearDeviceState != 3) {
+          rearDeviceState = 3
+          play(3)
+          backDoorIsOpen.value = false
+          frontDoorIsOpen.value = true
+        }
+      }
+    } else {
+
+      if (selectData.rearGateOpen == 0 && selectData.rearGateClose == 0) {
+        //关闭后门
+        
+        frontDoorIsOpen.value = true
+        backDoorIsOpen.value = true
+        if(!isRearRunning){
+          isRearRunning = true
+          play(4, timeScale)
+          rearDeviceState = 4
+        }
+        
+      }
+      if (selectData.rearGateClose == 1 && selectData.rearGateOpen == 0) {
+        isRearRunning = false
+        
+        if (rearDeviceState == 3) {
+          rearDeviceState = 4
+          play(4)
+          // frontDoorIsOpen.value = false
+          backDoorIsOpen.value = false
+        }
+
+      }
+    }
+    if(!(selectData.frontGateOpen == 0 && selectData.frontGateClose == 0 && selectData.rearGateOpen == 0 && selectData.rearGateClose == 0)) {
+      if (selectData.frontGateOpenCtrl && selectData.rearGateOpenCtrl && selectData.frontGateOpen == 1 && selectData.rearGateOpen == 1) {
+        frontDoorIsOpen.value = true
+        backDoorIsOpen.value = true
+      }
+      if (!selectData.frontGateOpenCtrl && !selectData.rearGateOpenCtrl && selectData.frontGateClose == 1 && selectData.rearGateClose == 1) {
+        frontDoorIsOpen.value = false
+        backDoorIsOpen.value = false
+      }
+    }
+    
+
+    // if (!selectData.frontGateOpenCtrl && selectData.rearGateOpenCtrl) {
+    //   frontDoorIsOpen.value = true
+    //   backDoorIsOpen.value = false
+    // }
+
+    // if (selectData.frontGateOpenCtrl && !selectData.rearGateOpenCtrl) {
+    //   frontDoorIsOpen.value = false
+    //   backDoorIsOpen.value = true
+    // }
+    
+    // if (frontDeviceState == 1 || frontDeviceState == 2) {
+    //   frontDoorIsOpen.value = false
+    //   backDoorIsOpen.value = true
+    // } else if (rearDeviceState == 3 || rearDeviceState == 4) {
+    //   frontDoorIsOpen.value = true
+    //   backDoorIsOpen.value = false
+    // } else {
+    //   frontDoorIsOpen.value = false
+    //   backDoorIsOpen.value = false
+    // }
+    // if(selectData.frontGateOpenCtrl && selectData.rearGateOpenCtrl){
+    //   if (selectData.frontGateOpen == 0 && selectData.frontGateClose == 0 && !isFrontRunning && selectData.rearGateOpen == 0 && selectData.rearGateClose == 0 && !isRearRunning) {
+    //     //打开前后门
+    //     frontDoorIsOpen.value = true
+    //     backDoorIsOpen.value = true
+    //   }
+    //   if (selectData.frontGateOpen == 1 && selectData.frontGateClose == 0 && selectData.rearGateOpen == 1 && selectData.rearGateClose == 0) {
+    //     frontDoorIsOpen.value = true
+    //     backDoorIsOpen.value = true
+    //   }
+    // }
+    // if(!selectData.frontGateOpenCtrl && !selectData.rearGateOpenCtrl){
+    //   if (selectData.frontGateOpen == 0 && selectData.frontGateClose == 0 && !isFrontRunning && selectData.rearGateOpen == 0 && selectData.rearGateClose == 0 && !isRearRunning) {
+    //     //打开前后门
+    //     frontDoorIsOpen.value = true
+    //     backDoorIsOpen.value = true
+    //   }
+    //   if (selectData.frontGateOpen == 0 && selectData.frontGateClose == 1 && selectData.rearGateOpen == 0 && selectData.rearGateClose == 1) {
+    //     frontDoorIsOpen.value = false
+    //     backDoorIsOpen.value = false
+    //   }
+    // }
+  }
+  
   const handleCancel = () => {
     modalIsShow.value = false;
     modalTitle.value = '';
@@ -391,8 +570,8 @@
     const data = {
       deviceid: selectData.deviceID,
       devicetype: selectData.deviceType,
-      paramcode: 'autoRoManual',
-      value: selectData.autoRoManual,
+      paramcode: 'masterComputerControl',
+      value: selectData.masterComputer,
     };
     deviceControlApi(data).then(() => {
       message.success('状态切换成功!');

+ 9 - 3
src/views/vent/monitorManager/mainFanMonitor/main.threejs.ts

@@ -2,7 +2,7 @@ import * as THREE from 'three';
 import { animateCamera, getTextCanvas, renderVideo } from '/@/utils/threejs/util';
 import UseThree from '../../../../utils/threejs/useThree';
 import mainWindRect from './mainWind.threejs';
-import gsap from 'gsap';
+import { useAppStore } from '/@/store/modules/app';
 // import * as dat from 'dat.gui';
 // const gui = new dat.GUI();
 
@@ -13,6 +13,8 @@ let model, //
   mainWindObj,
   modalType = 'mainWind';
 
+const appStore = useAppStore();
+
 // 打灯光
 const addLight = () => {
   const pointLight6 = new THREE.PointLight(0xffffff, 1.5, 0);
@@ -93,9 +95,13 @@ const startAnimation = () => {
 // 鼠标点击、松开事件
 const mouseEvent = (event) => {
   event.stopPropagation();
+  const widthScale = appStore.getWidthScale;
+  const heightScale = appStore.getHeightScale;
   // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
-  model.mouse.x = ((event.clientX - model.canvasContainer.getBoundingClientRect().left) / model.canvasContainer.clientWidth) * 2 - 1;
-  model.mouse.y = -((event.clientY - model.canvasContainer.getBoundingClientRect().top) / model.canvasContainer.clientHeight) * 2 + 1;
+  model.mouse.x =
+    ((-model.canvasContainer.getBoundingClientRect().left * widthScale + event.clientX) / (model.canvasContainer.clientWidth * widthScale)) * 2 - 1;
+  model.mouse.y =
+    -((-model.canvasContainer.getBoundingClientRect().top + event.clientY) / (model.canvasContainer.clientHeight * heightScale)) * 2 + 1;
   (model.rayCaster as THREE.Raycaster).setFromCamera(model.mouse, model.camera as THREE.Camera);
   if (group) {
     const intersects = model.rayCaster?.intersectObjects(group.children, false) as THREE.Intersection[];

+ 7 - 6
src/views/vent/monitorManager/sensorMonitor/index.vue

@@ -318,7 +318,7 @@
     top: 20px;
     padding: 10px;
     z-index: 999;
-    max-height: calc(100vh - 100px);
+    max-height: calc(100vh - 150px);
     .ant-tabs {
       max-height: calc(100vh - 100px);
       .tab-item {
@@ -335,7 +335,7 @@
       color: #fff;
     }
     .table-box {
-      height: calc(60vh - 90px);
+      height: calc(60vh - 150px);
       padding: 20px 10px;
       overflow-y: auto;
     }
@@ -397,18 +397,19 @@
       background: #264d8833 !important;
     }
     .ant-table-row-selected {
-      background: #264d8888 !important;
+      background: #00c0a311  !important;
       td {
         background-color: #00000000 !important;
       }
     }
     .ant-table-thead {
-      background: linear-gradient(#004a8655 0%, #004a86aa 10%) !important;
+      // background: linear-gradient(#004a8655 0%, #004a86aa 10%) !important;
+      background: #3d9dd45d!important;
 
       & > tr > th,
       .ant-table-column-title {
         // color: #70f9fc !important;
-        border-color: #91e9fe !important;
+        border-color: #84f2ff  !important;
         border-left: none !important;
         border-right: none !important;
         padding: 7px;
@@ -421,7 +422,7 @@
       }
     }
     .ant-table-tbody > tr:hover.ant-table-row > td {
-      background-color: #264d8855 !important;
+      background-color: #26648855 !important;
     }
 
     .jeecg-basic-table-row__striped {

+ 30 - 14
src/views/vent/monitorManager/windowMonitor/index.vue

@@ -17,14 +17,19 @@
   </div>
   <div class="scene-box">
     <div class="top-box">
-      <div class="top-center row">
+      <div class="top-center">
         <!-- <div class="input-box">
           <span class="input-title">风窗面积:</span>
           <a-input-number size="small" placeholder="0" :min="0" :max="90" :step="1" v-model:value="windowAngle" />
         </div> -->
-        <div class="button-box" @click="setArea(1)">设定前窗面积</div>
-        <div class="button-box" @click="setArea(2)">设定后窗面积</div>
-        <div class="button-box" @click="setArea(2)" style="display: none">设定风窗面积</div>
+        <div v-if="selectData.nwindownum == 2" class="row">
+          <div class="button-box" @click="setArea(1)">设定前窗面积</div>
+          <div class="button-box" @click="setArea(2)">设定后窗面积</div>
+        </div>
+        <div v-if="selectData.nwindownum == 1" class="row">
+            <div class="button-box" @click="setArea(1)">设定风窗面积</div>
+        </div>
+        
       </div>
       <div class="top-right row">
         <div class="control-type row">
@@ -68,6 +73,7 @@
               <a-tag v-if="column.dataIndex === 'netStatus'" :color="record.netStatus == 0 ? 'default' : 'green'">{{
                 record.netStatus == 0 ? '断开' : '连接'
               }}</a-tag>
+              <div v-if="record.nwindownum == 1 && column.dataIndex === 'rearArea'">/</div>
             </template>
           </MonitorTable>
         </a-tab-pane>
@@ -186,6 +192,7 @@
     frontRearDifference: '-',
     rearPresentValue: '-',
     maxarea: '',
+    nwindownum: 0
   };
 
   // 监测数据
@@ -198,7 +205,7 @@
       timer = setTimeout(async () => {
         const data = await getDataSource();
         Object.assign(selectData, data);
-        playAnimation(data, selectData.maxarea);
+        playAnimation(selectData, selectData.maxarea);
         addFmText(selectData);
         if (timer) {
           timer = null;
@@ -234,7 +241,7 @@
     const baseData: any = deviceBaseList.value.find((baseData: any) => baseData.id === selectRow.deviceID);
     Object.assign(selectData, initData, selectRow, baseData);
 
-    const type = selectRowIndex.value > 6 ? 'doubleWindow' : 'singleWindow';
+    const type = selectData.nwindownum == 1 ? 'singleWindow' : 'doubleWindow';
     setModelType(type).then(() => {
       addFmText(selectData);
       playAnimation(selectRow, baseData.maxarea, true);
@@ -244,19 +251,23 @@
 
   // 判断前后窗的面积是否发生改变,如果改变则开启动画
   const playAnimation = (data, maxarea, isFirst = false) => {
+    if(isFirst){
+      console.log('最大面积---->', maxarea, '前窗实际面积---->', selectData.forntArea, '后窗实际面积---->', selectData.rearArea);
+    }
     rotationParam.frontDeg0 = (90 / maxarea) * Number(isFirst ? 0 : selectData.forntArea);
     rotationParam.backDeg0 = (90 / maxarea) * Number(isFirst ? 0 : selectData.rearArea);
     rotationParam.frontDeg1 = (90 / maxarea) * Number(data.forntArea) || 0;
     rotationParam.backDeg1 = (90 / maxarea) * Number(data.rearArea) || 0;
     if (!rotationParam.frontDeg1 && !rotationParam.backDeg1) {
+      // 当返回值有误时默认关闭
       play(rotationParam, 0);
     } else {
-      if (rotationParam.frontDeg0 >= 0 && rotationParam.frontDeg1 >= 0 && rotationParam.frontDeg0 !== rotationParam.frontDeg1) {
+      if (data.nwindownum == 1 || data.nwindownum == 2) {
         setTimeout(() => {
           play(rotationParam, 1);
         }, 0);
       }
-      if (rotationParam.backDeg0 >= 0 && rotationParam.backDeg1 >= 0 && rotationParam.backDeg0 !== rotationParam.backDeg1) {
+      if (data.nwindownum == 2) {
         setTimeout(() => {
           play(rotationParam, 2);
         }, 0);
@@ -266,13 +277,18 @@
 
   // 设置风窗面积
   const setArea = (flag) => {
-    modalTitle.value = flag === 1 ? '设定前窗面积' : '设定后窗面积';
-    modalType.value = flag;
+    if(selectData.nwindownum == 2){
+      modalTitle.value = flag === 1 ? '设定前窗面积' : '设定后窗面积';
+    }else {
+      modalTitle.value = '设定风窗面积'
+    }
+    
+    modalType.value = flag+'';
     modalIsShow.value = true;
   };
 
-  const handleOK = (passWord, handlerState, windowAngle) => {
-    windowAngle.value = windowAngle;
+  const handleOK = (passWord, handlerState, windowAngleNum) => {
+    windowAngle.value = windowAngleNum;
     if (passWord !== '123456') {
       message.warning('密码不正确,请重新输入');
       return;
@@ -292,6 +308,7 @@
         handleCancel();
       });
   };
+
   const handleCancel = () => {
     modalIsShow.value = false;
     modalTitle.value = '';
@@ -309,13 +326,12 @@
   onBeforeMount(() => {
     // const sendVal = JSON.stringify({ pagetype: 'normal', devicetype: 'window', orgcode: '', ids: '', systemID: '' });
     // initWebSocket(sendVal);
-
     getDeviceBaseList();
   });
 
   onMounted(() => {
     loading.value = true;
-    mountedThree(player1.value).then(async () => {
+    mountedThree(player1.value, player2.value).then(async () => {
       // await setModelType('singleWindow');
       loading.value = false;
       addFmText(selectData);

+ 8 - 4
src/views/vent/monitorManager/windowMonitor/window.threejs.ts

@@ -3,7 +3,7 @@ import UseThree from '../../../../utils/threejs/useThree';
 import singleWindow from './dandaoFc.threejs';
 import doubleWindow from './shuangdaoFc.threejs';
 import { animateCamera } from '/@/utils/threejs/util';
-import gsap from 'gsap';
+import { useAppStore } from '/@/store/modules/app';
 
 // 模型对象、 文字对象
 let model,
@@ -11,7 +11,7 @@ let model,
   doubleWindowObj,
   group,
   windowType = 'singleWindow';
-
+const appStore = useAppStore();
 // 打灯光
 const addLight = () => {
   const pointLight2 = new THREE.PointLight(0xffeeee, 1, 83);
@@ -79,9 +79,13 @@ const startAnimation = () => {
 // 鼠标点击、松开事件
 const mouseEvent = (event) => {
   event.stopPropagation();
+  const widthScale = appStore.getWidthScale;
+  const heightScale = appStore.getHeightScale;
   // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
-  model.mouse.x = ((event.clientX - model.canvasContainer.getBoundingClientRect().left) / model.canvasContainer.clientWidth) * 2 - 1;
-  model.mouse.y = -((event.clientY - model.canvasContainer.getBoundingClientRect().top) / model.canvasContainer.clientHeight) * 2 + 1;
+  model.mouse.x =
+    ((-model.canvasContainer.getBoundingClientRect().left * widthScale + event.clientX) / (model.canvasContainer.clientWidth * widthScale)) * 2 - 1;
+  model.mouse.y =
+    -((-model.canvasContainer.getBoundingClientRect().top + event.clientY) / (model.canvasContainer.clientHeight * heightScale)) * 2 + 1;
   (model.rayCaster as THREE.Raycaster).setFromCamera(model.mouse, model.camera as THREE.Camera);
   if (group) {
     const intersects = model.rayCaster?.intersectObjects(group.children, false) as THREE.Intersection[];

+ 39 - 23
src/views/vent/monitorManager/windrectMonitor/duishe.threejs.ts

@@ -15,6 +15,7 @@ class dsWindRect {
   player1;
   playerStartClickTime1 = new Date().getTime();
   lineLight;
+  isRun = false;
 
   constructor(model, playerVal1) {
     this.model = model;
@@ -303,34 +304,49 @@ class dsWindRect {
   }
 
   // 播放动画
-  play(flag) {
+  play(flag, isDirect = false) {
+    const _this = this;
+    if (this.isRun) return;
     const dsTanTou = this.group?.getObjectByName('dsTanTou') as THREE.Group;
     if (!dsTanTou) return;
-    switch (flag) {
-      case 'up':
-        gsap.to(dsTanTou['position'], {
-          y: 0,
-          duration: Math.abs(dsTanTou['position']['y']) * 5,
-          ease: 'easeQutQuad',
-          overwrite: true,
-        });
-        break;
-      case 'center':
-        gsap.to(dsTanTou['position'], {
-          y: -0.345,
-          duration: Math.abs(dsTanTou['position']['y'] - 0.345) * 5,
-          ease: 'easeQutQuad',
-          overwrite: true,
-        });
-        break;
-      case 'down':
+    if (flag === 'start') {
+      const toDownGsap = gsap.getById('toDown') || null;
+      const toUpGsap = gsap.getById('toUp') || null;
+      if (toDownGsap != null) {
+        toDownGsap.pause();
+        toDownGsap.kill();
+      }
+      if (toUpGsap != null) {
+        toUpGsap.pause();
+        toUpGsap.kill();
+      }
+      if (!gsap.getById('toDown') && !gsap.getById('toUp')) {
+        dsTanTou.position.setY(0);
+        this.isRun = true;
         gsap.to(dsTanTou['position'], {
-          y: -0.69,
-          duration: Math.abs(dsTanTou['position']['y'] - 0.69) * 5,
-          ease: 'easeQutCubic',
+          id: 'toDown',
+          y: -0.49,
+          duration: Math.abs(dsTanTou['position']['y'] - 0.49) * 21,
           overwrite: true,
+          onComplete: function () {
+            setTimeout(() => {
+              gsap.to(dsTanTou['position'], {
+                y: 0,
+                id: 'toUp',
+                duration: Math.abs(dsTanTou['position']['y']) * 21,
+                overwrite: true,
+                onComplete: function () {
+                  _this.isRun = false
+                },
+              });
+            }, 2000);
+          },
         });
-        break;
+      }
+
+      debugger;
+    } else {
+      gsap.getById('toDown').paused();
     }
   }
 

+ 39 - 2
src/views/vent/monitorManager/windrectMonitor/index.vue

@@ -72,8 +72,18 @@
                 <a-tag v-if="record.isRun == -2 || record.isRun == -1" :color="record.isRun == -2 ? '#95CF65' : '#ED5700'">{{
                   record.isRun === -2 ? '空闲' : '等待'
                 }}</a-tag>
+                <a-tag v-else-if="record.isRun == 100" color="#4693FF">完成</a-tag>
                 <Progress v-else :percent="Number(record.isRun)" size="small" status="active" />
               </template>
+              <!-- <a-tag v-if="column.dataIndex === 'sign'" :color="record.sign == 0 ? '#95CF65' : record.sign == 1 ? '#4590EA' : '#9876AA'">{{
+                record.sign == 0 ? '高位' : record.sign == 1 ? '中位' : '低位'
+              }}</a-tag>
+              <template v-if="record && column && column.dataIndex === 'isRun' && record.isRun">
+                <a-tag v-if="record.isRun == -2 || record.isRun == -1" :color="record.isRun == -2 ? '#95CF65' : '#ED5700'">{{
+                  record.isRun === -2 ? '空闲' : '等待'
+                }}</a-tag>
+                <Progress v-else :percent="Number(record.isRun)" size="small" status="active" />
+              </template> -->
             </template>
           </MonitorTable>
         </a-tab-pane>
@@ -150,7 +160,7 @@
   import LivePlayer from '@liveqing/liveplayer-v3';
   import { list, pathList, deviceList, testWind } from './windrect.api';
   import { list as baseList } from '../../deviceManager/windfindingTabel/windfinding.api';
-  import { message, Tag, Progress } from 'ant-design-vue';
+  import { message, Progress } from 'ant-design-vue';
   import { chartsColumns } from './windrect.data';
 
   const modalTable = ref();
@@ -173,6 +183,7 @@
     dataDequivalarea: '-',
     netStatus: '0', //通信状态
     fault: '气源压力超限',
+    sign: -1
   });
 
   const flvURL1 = () => {
@@ -213,6 +224,30 @@
           Object.assign(selectData, data);
           addFmText(selectData);
           // 根据3个点位分别执行动画
+          if(data.deviceType == "windrect_fold"){
+            if (selectData.apparatusRun == 1) {
+              const flag = selectData.sign == 0 ? 'up' : selectData.sign == 1 ? 'center' : selectData.sign == 2 ? 'down' : null
+              if (flag) play(flag);
+            } else {
+              if (selectData.sign == 0) play('reset')
+            }
+          }
+          if(data.deviceType == "windrect_rect"){
+            if (selectData.apparatusRun == 1) {
+              const flag = selectData.sign == 0 ? 'center' : selectData.sign == 1 ? 'down' : selectData.sign == 2 ? 'up' : null
+              if (flag) play(flag);
+            }
+            else {
+              const flag = selectData.sign == 1 ? 'down' : selectData.sign == 2 ? 'up' : null
+              if (flag) play(flag, true);
+            }
+          }
+
+          if (data.deviceType == "windrect_ds") {
+            if (selectData.apparatusRun == 1) {
+              play('start')
+            }
+          }
 
           if (timer) {
             timer = null;
@@ -225,7 +260,9 @@
 
   // 自测动画方法
   const testPlay = (flag) => {
+    debugger
     play(flag);
+    // play('start')
     // setTimeout(() => {
     //   play('up')
     // }, 0)
@@ -245,7 +282,7 @@
     loading.value = true;
     selectRowIndex.value = index;
     // Object.assign(selectData, selectRow);
-    const type = selectRowIndex.value < 3 ? 'lmWindRect' : selectRowIndex.value < 6 ? 'zdWindRect' : 'dsWindRect';
+    const type = selectRow.deviceType == 'windrect_rect' ? 'lmWindRect' : selectRow.deviceType == 'windrect_fold' ? 'zdWindRect' : 'dsWindRect'; 
     await setModelType(type);
     loading.value = false;
   };

+ 53 - 32
src/views/vent/monitorManager/windrectMonitor/longmen.threejs.ts

@@ -14,6 +14,7 @@ class lmWindRect {
   player2;
   playerStartClickTime1 = new Date().getTime();
   playerStartClickTime2 = new Date().getTime();
+  deviceRunState = '';
 
   constructor(model, playerVal1, playerVal2) {
     this.model = model;
@@ -225,23 +226,15 @@ class lmWindRect {
   initAnimation() {
     const windGroup = new THREE.Group();
     windGroup.name = 'lmTanTou';
-    // this.group?.children.forEach((obj) => {
-    //   if (obj.type === 'Mesh' && obj.name && obj.name.startsWith('LMtantou')) {
-    //     if (obj.name.startsWith('LMtantou')) {
-    //       windGroup.add(obj.clone());
-    //       this.group?.remove(obj);
-    //     }
-    //   }
-    // });
     if (this.group?.children.length) {
       for (let i = this.group?.children.length - 1; i > -1; i--) {
         const obj = this.group?.children[i];
-          if (obj.type === 'Mesh' && obj.name && obj.name.startsWith('LMtantou')) {
-            if (obj.name.startsWith('LMtantou')) {
-              windGroup.add(obj.clone());
-              this.group?.remove(obj);
-            }
+        if (obj.type === 'Mesh' && obj.name && obj.name.startsWith('LMtantou')) {
+          if (obj.name.startsWith('LMtantou')) {
+            windGroup.add(obj.clone());
+            this.group?.remove(obj);
           }
+        }
       }
     }
     this.group?.add(windGroup);
@@ -295,33 +288,61 @@ class lmWindRect {
   }
 
   // 播放动画
-  play(flag) {
+  play(flag, isDirect = false) {
+    debugger
     const cfTanTou = this.group?.getObjectByName('lmTanTou') as THREE.Group;
     if (!cfTanTou) return;
     switch (flag) {
       case 'up':
-        gsap.to(cfTanTou['position'], {
-          y: 0,
-          duration: Math.abs(cfTanTou['position']['y'] - 0),
-          ease: 'easeQutQuad',
-          overwrite: true,
-        });
+        if (this.deviceRunState == 'up' || this.deviceRunState == 'center') {
+          return;
+        }
+        this.deviceRunState = 'up';
+        cfTanTou.position.setY(-0.48);
+        if (!isDirect) {
+          gsap.to(cfTanTou['position'], {
+            y: 0,
+            duration: Math.abs(cfTanTou['position']['y'] - 0) * 25,
+            overwrite: true,
+          });
+        } else {
+          cfTanTou.position.setY(0);
+        }
+
         break;
       case 'center':
-        gsap.to(cfTanTou['position'], {
-          y: -0.28,
-          duration: Math.abs(cfTanTou['position']['y'] + 7) / 14,
-          ease: 'easeQutQuad',
-          overwrite: true,
-        });
+        if (this.deviceRunState == 'center') {
+          return;
+        }
+        this.deviceRunState = 'center';
+        cfTanTou.position.setY(0);
+        if (!isDirect) {
+          gsap.to(cfTanTou['position'], {
+            y: -0.24,
+            duration: Math.abs(cfTanTou['position']['y'] + 0.24) * 50,
+            overwrite: true,
+          });
+        } else {
+          cfTanTou.position.setY(-0.24);
+        }
+
         break;
       case 'down':
-        gsap.to(cfTanTou['position'], {
-          y: -0.52,
-          duration: Math.abs(cfTanTou['position']['y'] + 14) / 14,
-          ease: 'easeQutCubic',
-          overwrite: true,
-        });
+        if (this.deviceRunState == 'down') {
+          return;
+        }
+        this.deviceRunState = 'down';
+        cfTanTou.position.setY(-0.24);
+        if (!isDirect) {
+          gsap.to(cfTanTou['position'], {
+            y: -0.48,
+            duration: Math.abs(cfTanTou['position']['y'] + 0.48) * 50,
+            overwrite: true,
+          });
+        } else {
+          cfTanTou.position.setY(-0.48);
+        }
+
         break;
     }
   }

+ 22 - 6
src/views/vent/monitorManager/windrectMonitor/windrect.threejs.ts

@@ -4,6 +4,7 @@ import UseThree from '../../../../utils/threejs/useThree';
 import lmWindRect from './longmen.threejs';
 import zdWindRect from './zhedie.threejs';
 import dsWindRect from './duishe.threejs';
+import { useAppStore } from '/@/store/modules/app';
 import gsap from 'gsap';
 import * as dat from 'dat.gui';
 // const gui = new dat.GUI();
@@ -16,6 +17,8 @@ let model, //
   dsWindRectObj,
   windRectType = 'lmWindRect';
 
+const appStore = useAppStore();
+
 // 打灯光
 const addLight = () => {
   // if (windRectType === 'lmWindRect') {
@@ -97,9 +100,13 @@ const startAnimation = () => {
 // 鼠标点击、松开事件
 const mouseEvent = (event) => {
   event.stopPropagation();
+  const widthScale = appStore.getWidthScale;
+  const heightScale = appStore.getHeightScale;
   // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
-  model.mouse.x = ((event.clientX - model.canvasContainer.getBoundingClientRect().left) / model.canvasContainer.clientWidth) * 2 - 1;
-  model.mouse.y = -((event.clientY - model.canvasContainer.getBoundingClientRect().top) / model.canvasContainer.clientHeight) * 2 + 1;
+  model.mouse.x =
+    ((-model.canvasContainer.getBoundingClientRect().left * widthScale + event.clientX) / (model.canvasContainer.clientWidth * widthScale)) * 2 - 1;
+  model.mouse.y =
+    -((-model.canvasContainer.getBoundingClientRect().top + event.clientY) / (model.canvasContainer.clientHeight * heightScale)) * 2 + 1;
   (model.rayCaster as THREE.Raycaster).setFromCamera(model.mouse, model.camera as THREE.Camera);
   if (group) {
     const intersects = model.rayCaster?.intersectObjects(group.children, false) as THREE.Intersection[];
@@ -127,13 +134,13 @@ export const addFmText = (selectData) => {
   }
 };
 
-export const play = (flag) => {
+export const play = (flag, isDirect = false) => {
   if (windRectType === 'lmWindRect') {
-    return lmWindRectObj.play.call(lmWindRectObj, flag);
+    return lmWindRectObj.play.call(lmWindRectObj, flag, isDirect);
   } else if (windRectType === 'zdWindRect') {
-    return zdWindRectObj.play.call(zdWindRectObj, flag);
+    return zdWindRectObj.play.call(zdWindRectObj, flag, isDirect);
   } else if (windRectType === 'dsWindRect') {
-    return dsWindRectObj.play.call(dsWindRectObj, flag);
+    return dsWindRectObj.play.call(dsWindRectObj, flag, isDirect);
   }
 };
 
@@ -141,11 +148,15 @@ export const play = (flag) => {
 export const setModelType = (type) => {
   windRectType = type;
   model.camera.position.set(-1000, 100, 500);
+
   return new Promise((resolve) => {
     // 显示双道风窗
     if (windRectType === 'lmWindRect') {
       model.startAnimation = lmWindRectObj.render.bind(lmWindRectObj);
       group = lmWindRectObj.group;
+      // const cfTanTou = lmWindRectObj.group?.getObjectByName('lmTanTou') as THREE.Group;
+      // cfTanTou.position.setY(0);
+      lmWindRectObj.deviceRunState == '';
       if (model.scene.getObjectByName('zdcf')) {
         model.scene.remove(zdWindRectObj.group);
       }
@@ -168,6 +179,8 @@ export const setModelType = (type) => {
         );
       }, 300);
     } else if (windRectType === 'zdWindRect') {
+      // 停用混合器上所有预定的动作
+      zdWindRectObj.animationAction.time = 0;
       model.startAnimation = zdWindRectObj.render.bind(zdWindRectObj);
       group = zdWindRectObj.group;
       if (model.scene.getObjectByName('lmcf')) {
@@ -191,8 +204,11 @@ export const setModelType = (type) => {
         );
       }, 300);
     } else if (windRectType === 'dsWindRect') {
+      dsWindRectObj.isRun = false
       model.startAnimation = dsWindRectObj.render.bind(dsWindRectObj);
       group = dsWindRectObj.group;
+      const dsTanTou = dsWindRectObj.group?.getObjectByName('dsTanTou') as THREE.Group;
+      dsTanTou.position.setY(0);
       if (model.scene.getObjectByName('lmcf')) {
         model.scene.remove(lmWindRectObj.group);
       }

+ 24 - 20
src/views/vent/monitorManager/windrectMonitor/zhedie.threejs.ts

@@ -231,9 +231,8 @@ class zdWindRect {
     this.animationAction = this.mixers[0].clipAction(this.animations[0]);
     this.animationAction.clampWhenFinished = true;
     this.animationAction.loop = THREE.LoopOnce;
-    debugger
+    debugger;
     console.log('模型动画-------------->', this.animationAction);
-    
   }
 
   /* 点击风窗,风窗全屏 */
@@ -275,36 +274,41 @@ class zdWindRect {
   }
 
   // 播放动画
-  play(flag) {
-    if (flag === 'up') {
+  play(flag, isDirect = false) {
+    if (flag === 'up' && this.animationAction.time <= 0) {
+      debugger;
       this.animationAction?.reset();
       // @ts-ignore
       this.animationAction.time = 0;
       this.animations[0].duration = 200 / 25;
-      // this.mixers[0].timeScale = 0.1;
+      this.mixers[0].timeScale = 0.15;
       this.animationAction?.play();
-    } else if (flag === 'center') {
+    } else if (flag === 'center' && this.animationAction.time <= 8) {
+      debugger;
       this.animationAction?.reset();
       // @ts-ignore
-      this.animationAction.time = 200 / 25;
+      this.animationAction.time = 200 / 25; // 8
       this.animations[0].duration = 300 / 25;
-      // this.mixers[0].timeScale = 0.1;
+      this.mixers[0].timeScale = 0.15;
       this.animationAction?.play();
-    } else if (flag === 'down') {
+    } else if (flag === 'down' && this.animationAction.time <= 12) {
       this.animationAction?.reset();
+      debugger;
       // @ts-ignore
-      this.animationAction.time = 300 / 25;
-      this.animations[0].duration = 450 / 25;
-      // this.mixers[0].timeScale = 0.1;
-      this.animationAction?.play();
-    } else {
-      this.animationAction?.reset();
-      // @ts-ignore
-      this.animationAction.time = 450 / 25;
+      this.animationAction.time = 300 / 25; // 12
       this.animations[0].duration = 530 / 25;
-      // this.mixers[0].timeScale = 0.1;
+      this.mixers[0].timeScale = 0.12;
       this.animationAction?.play();
-    }
+    } 
+    // else if ((flag === 'reset' && this.animationAction.time != 0 && this.animationAction.time <= 18) || (flag === 'up' && this.animationAction.time == 18)) {
+    //   debugger;
+    //   this.animationAction?.reset();
+    //   // @ts-ignore
+    //   this.animationAction.time = 450 / 25; //
+    //   this.animations[0].duration = 530 / 25;
+    //   this.mixers[0].timeScale = 0.15;
+    //   this.animationAction?.play();
+    // }
   }
 
   mountedThree() {
@@ -312,7 +316,7 @@ class zdWindRect {
       this.model.setModel(this.modelName).then((gltf) => {
         this.group = gltf.scene;
         if (gltf.animations && gltf.animations.length > 0) {
-          console.log('[ 解析后的模型动画 ] >', gltf.animations)
+          console.log('[ 解析后的模型动画 ] >', gltf.animations);
           gltf.animations.forEach((animation) => {
             const mixer = new THREE.AnimationMixer(gltf.scene);
             this.mixers.push(mixer);