5 Commity d4e15216fc ... 8ebd4bea0c

Autor SHA1 Wiadomość Data
  lxh 8ebd4bea0c 更新 3 tygodni temu
  lxh ae2c58c331 Merge branch 'master' of http://39.97.59.228:8013/hrx/hsq-pro 3 tygodni temu
  lxh 8568bdc05a 更新 3 tygodni temu
  lxh 2c36ae5854 红沙泉露天煤矿火灾监测-接口对接-提交 3 tygodni temu
  lxh 92c5992091 红沙泉露天煤矿界面布局更新-提交 1 miesiąc temu
87 zmienionych plików z 4616 dodań i 4860 usunięć
  1. 1 0
      .env.development
  2. BIN
      public/texture/earth.jpg
  3. BIN
      public/texture/earth3.png
  4. BIN
      public/video/fanLocal.webm
  5. 3 0
      src/assets/icons/back-bg.svg
  6. BIN
      src/assets/images/company/home-pageBg.png
  7. BIN
      src/assets/images/fireNew/FireBj.png
  8. BIN
      src/assets/images/gasInjection/login-bg.png
  9. BIN
      src/assets/images/gif/fanlocal.gif
  10. BIN
      src/assets/images/home-container/configurable/hsq/6-1.png
  11. BIN
      src/assets/images/home-container/configurable/hsq/6-2.png
  12. BIN
      src/assets/images/home-container/configurable/minehome/bg.png
  13. BIN
      src/assets/images/home-warn/bg.png
  14. BIN
      src/assets/images/themify/deepblue/home-container/configurable/gasInjection/login-bg.png
  15. BIN
      src/assets/images/vent/homeNew/bg.png
  16. BIN
      src/assets/images/vent/loginDataCenter/dataCenterBg.png
  17. BIN
      src/assets/images/vent/loginNeiye/bg.png
  18. BIN
      src/assets/images/zd-model.png
  19. BIN
      src/assets/video/fanLocal.mp4
  20. BIN
      src/assets/video/gate.mp4
  21. BIN
      src/assets/video/mainFan.mp4
  22. BIN
      src/assets/video/output_video.mp4
  23. 1 1
      src/utils/http/axios/index.ts
  24. 5 5
      src/views/sys/login/Login.vue
  25. 2 2
      src/views/sys/login/LoginDataCenter.vue
  26. 2 2
      src/views/sys/login/LoginForm.vue
  27. 2 2
      src/views/sys/login/LoginNeiye.vue
  28. 182 150
      src/views/system/role/index.vue
  29. 246 214
      src/views/system/user/index.vue
  30. 24 19
      src/views/vent/cad/dwgViewer.vue
  31. 0 88
      src/views/vent/home/configurable/components/ModuleGasInject.vue
  32. 0 2
      src/views/vent/home/configurable/components/content.vue
  33. 0 202
      src/views/vent/home/configurable/components/preset/CustomGalleryNew.vue
  34. 0 78
      src/views/vent/home/configurable/components/preset/ImageCardNew.vue
  35. 0 281
      src/views/vent/home/configurable/components/preset/MeasureDetail.vue
  36. 0 47
      src/views/vent/home/configurable/components/preset/PermissionSet.vue
  37. 0 184
      src/views/vent/home/configurable/components/preset/SearchTable.vue
  38. 0 174
      src/views/vent/home/configurable/components/preset/SelectCs.vue
  39. 0 79
      src/views/vent/home/configurable/components/preset/StatisticDay.vue
  40. 0 229
      src/views/vent/home/configurable/components/preset/UserList.vue
  41. 0 158
      src/views/vent/home/configurable/components/preset/buttonList.vue
  42. 0 59
      src/views/vent/home/configurable/components/preset/cameraModal.vue
  43. 0 262
      src/views/vent/home/configurable/components/preset/cardList.vue
  44. 0 109
      src/views/vent/home/configurable/components/preset/generalList.vue
  45. 0 74
      src/views/vent/home/configurable/components/preset/radioLabel.vue
  46. 1 695
      src/views/vent/home/configurable/configurable.api.ts
  47. 0 881
      src/views/vent/home/configurable/configurable.data.ts
  48. 0 96
      src/views/vent/home/configurable/deviceManger.vue
  49. 0 82
      src/views/vent/home/configurable/fireMonitor.vue
  50. 0 1
      src/views/vent/home/configurable/hooks/helper.ts
  51. 0 172
      src/views/vent/home/configurable/systemManger.vue
  52. 0 101
      src/views/vent/home/configurable/warnMonitor.vue
  53. 130 0
      src/views/vent/monitorManager/hsqHome/components/AlarmMonitor.vue
  54. 69 0
      src/views/vent/monitorManager/hsqHome/components/CommonBd.vue
  55. 246 0
      src/views/vent/monitorManager/hsqHome/components/CommonTable.vue
  56. 364 0
      src/views/vent/monitorManager/hsqHome/components/CustomChart.vue
  57. 136 0
      src/views/vent/monitorManager/hsqHome/components/CustomGalleryNew.vue
  58. 146 87
      src/views/vent/monitorManager/hsqHome/components/DeviceCenter.vue
  59. 59 13
      src/views/vent/monitorManager/hsqHome/components/DeviceLeft.vue
  60. 46 44
      src/views/vent/monitorManager/hsqHome/components/DeviceRight.vue
  61. 6 20
      src/views/vent/monitorManager/hsqHome/components/EnvironmentMonitor.vue
  62. 263 0
      src/views/vent/monitorManager/hsqHome/components/LinkLogPanel.vue
  63. 162 62
      src/views/vent/monitorManager/hsqHome/components/LinkRuleEditor.vue
  64. 140 0
      src/views/vent/monitorManager/hsqHome/components/LinkRuleStats.vue
  65. 218 0
      src/views/vent/monitorManager/hsqHome/components/LinkRuleTable.vue
  66. 7 11
      src/views/vent/monitorManager/hsqHome/components/QuickAction.vue
  67. 100 0
      src/views/vent/monitorManager/hsqHome/components/SystemCenBottom.vue
  68. 93 51
      src/views/vent/monitorManager/hsqHome/components/SystemLeftBottom.vue
  69. 278 0
      src/views/vent/monitorManager/hsqHome/components/SystemLeftTop.vue
  70. 0 0
      src/views/vent/monitorManager/hsqHome/components/SystemRightBot.vue
  71. 63 14
      src/views/vent/monitorManager/hsqHome/components/SystemRightTop.vue
  72. 0 0
      src/views/vent/monitorManager/hsqHome/components/WarnBottom.vue
  73. 40 31
      src/views/vent/monitorManager/hsqHome/components/WarnCenTop.vue
  74. 240 0
      src/views/vent/monitorManager/hsqHome/components/WarnLeftTop.vue
  75. 121 70
      src/views/vent/monitorManager/hsqHome/components/WarnRightTop.vue
  76. 0 0
      src/views/vent/monitorManager/hsqHome/components/basicBorder.vue
  77. 21 8
      src/views/vent/monitorManager/hsqHome/components/basicDevice.vue
  78. 0 0
      src/views/vent/monitorManager/hsqHome/components/navMenu.vue
  79. 108 0
      src/views/vent/monitorManager/hsqHome/deviceManger.vue
  80. 269 0
      src/views/vent/monitorManager/hsqHome/fireMonitor.vue
  81. 77 0
      src/views/vent/monitorManager/hsqHome/hsqHome.api.ts
  82. 181 0
      src/views/vent/monitorManager/hsqHome/hsqHome.data.ts
  83. 114 0
      src/views/vent/monitorManager/hsqHome/index.vue
  84. 0 0
      src/views/vent/monitorManager/hsqHome/largeScreen.vue
  85. 84 0
      src/views/vent/monitorManager/hsqHome/linkConfiguration.vue
  86. 198 0
      src/views/vent/monitorManager/hsqHome/systemManger.vue
  87. 168 0
      src/views/vent/monitorManager/hsqHome/warnMonitor.vue

+ 1 - 0
.env.development

@@ -6,6 +6,7 @@ VITE_PUBLIC_PATH = /
 
 # 跨域代理,您可以配置多个 ,请注意,没有换行符
 #VITE_PROXY = [["/jeecgboot","http://localhost:8080/jeecg-boot"],["/upload","http://localhost:3300/upload"]]
+# VITE_PROXY = [["/sw","http://182.92.126.35:6008"],["/jeecgsystem","http://182.92.126.35:9999"],["/upload","http://39.97.59.228:9999/upload"],["/documents", "http://182.92.126.35:9050"],["/modelreq", "http://39.97.59.228:9999"],["/webRtc", "http://182.92.126.35:8051"], ["/python", "http://127.0.0.1:8008"], ["/tun2D", "http://127.0.0.1:8088/micro-vent-2dModal/tun2D"],["/dataCenter", "http://39.97.59.228:10999"]]
 VITE_PROXY = [["/sw","http://182.92.126.35:6008"],["/jeecgsystem","http://182.92.126.35:9999"],["/upload","http://39.97.59.228:9999/upload"],["/documents", "http://182.92.126.35:9050"],["/modelreq", "http://182.92.126.35:9999"],["/webRtc", "http://182.92.126.35:8051"], ["/python", "http://127.0.0.1:8008"], ["/tun2D", "http://127.0.0.1:8088/micro-vent-2dModal/tun2D"],["/dataCenter", "http://39.97.59.228:10999"]]
 # VITE_PROXY = [["/sw","http://182.92.126.35:6008"],["/jeecgsystem","http://39.97.59.228:9999"],["/upload","http://39.97.59.228:9999/upload"],["/documents", "http://182.92.126.35:9050"],["/modelreq", "http://39.97.59.228:9999"],["/webRtc", "http://182.92.126.35:8051"], ["/python", "http://127.0.0.1:8008"], ["/tun2D", "http://127.0.0.1:8088/micro-vent-2dModal/tun2D"],["/dataCenter", "http://39.97.59.228:10999"]]
 # VITE_PROXY = [["/jeecgsystem","http://192.168.183.88:9999"],["/upload","http://192.168.183.88:9999/upload"],["/documents", "http://192.168.183.88:9050"],["/modelreq", "http://192.168.183.88:9999"],["/webRtc", "http://192.168.183.88:8051"]]

BIN
public/texture/earth.jpg


BIN
public/texture/earth3.png


BIN
public/video/fanLocal.webm


+ 3 - 0
src/assets/icons/back-bg.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="26.273" height="26.099" viewBox="0 0 26.273 26.099">
+  <path id="路径_57984" data-name="路径 57984" d="M107.917,71.526a2.112,2.112,0,0,0-2.831,0l-11.4,10.817a1.1,1.1,0,0,0-.145,1.452c.363.581,1.089.363,1.525,0l.218-.218v11.18a2.343,2.343,0,0,0,.581,1.525,2.71,2.71,0,0,0,1.67.726h6.171V90.692a3.211,3.211,0,0,1,.363-1.089,1.38,1.38,0,0,1,.944-.363h2.831a3.211,3.211,0,0,1,1.089.363,1.783,1.783,0,0,1,.363,1.089v6.389h6.316a2.343,2.343,0,0,0,1.525-.581,2.2,2.2,0,0,0,.581-1.525V83.8a1.2,1.2,0,0,0,1.525,0,.778.778,0,0,0,.363-.726,1.383,1.383,0,0,0-.363-.726Z" transform="translate(-93.332 -70.982)" fill="#fff"/>
+</svg>

BIN
src/assets/images/company/home-pageBg.png


BIN
src/assets/images/fireNew/FireBj.png


BIN
src/assets/images/gasInjection/login-bg.png


BIN
src/assets/images/gif/fanlocal.gif


BIN
src/assets/images/home-container/configurable/hsq/6-1.png


BIN
src/assets/images/home-container/configurable/hsq/6-2.png


BIN
src/assets/images/home-container/configurable/minehome/bg.png


BIN
src/assets/images/home-warn/bg.png


BIN
src/assets/images/themify/deepblue/home-container/configurable/gasInjection/login-bg.png


BIN
src/assets/images/vent/homeNew/bg.png


BIN
src/assets/images/vent/loginDataCenter/dataCenterBg.png


BIN
src/assets/images/vent/loginNeiye/bg.png


BIN
src/assets/images/zd-model.png


BIN
src/assets/video/fanLocal.mp4


BIN
src/assets/video/gate.mp4


BIN
src/assets/video/mainFan.mp4


BIN
src/assets/video/output_video.mp4


+ 1 - 1
src/utils/http/axios/index.ts

@@ -310,7 +310,7 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) {
         // authentication schemes,e.g: Bearer
         // authenticationScheme: 'Bearer',
         authenticationScheme: '',
-        timeout: 60 * 1000,
+        timeout: 60000,
         // 基础接口地址
         // baseURL: globSetting.apiUrl,
         headers: { 'Content-Type': ContentTypeEnum.JSON },

+ 5 - 5
src/views/sys/login/Login.vue

@@ -41,8 +41,8 @@
 
   const formRef = ref();
   let loginForm = reactive({
-    account: 'zhuqi',
-    password: 'zhuqi123zhuqi',
+    account: 'hsq',
+    password: 'hsq123hsq',
     inputCode: '',
   });
   const { validForm } = useFormValid(formRef);
@@ -103,18 +103,18 @@
 
   @{theme-deepblue} {
     .Login {
-      --image-login-bg: url('@/assets/images/themify/deepblue/home-container/configurable/gasInjection/login-bg.png');
+      // --image-login-bg: url('@/assets/images/themify/deepblue/home-container/configurable/gasInjection/login-bg.png');
       --image-login-bd: url('@/assets/images/themify/deepblue/home-container/configurable/gasInjection/login-border.png');
     }
   }
 
   .Login {
-    --image-login-bg: url('@/assets/images/gasInjection/login-bg.png');
+    // --image-login-bg: url('@/assets/images/gasInjection/login-bg.png');
     --image-login-bd: url('@/assets/images/gasInjection/login-border.png');
     position: relative;
     width: 100%;
     height: 100%;
-    background: var(--image-login-bg) no-repeat;
+    // background: var(--image-login-bg) no-repeat;
     background-size: 100% 100%;
 
     .login-container {

+ 2 - 2
src/views/sys/login/LoginDataCenter.vue

@@ -43,7 +43,7 @@ const handleForgotPwd = () => {
 .login-container {
   width: 100%;
   height: 100%;
-  background: url('@/assets/images/vent/loginDataCenter/dataCenterBg.png') no-repeat center;
+  /* background: url('@/assets/images/vent/loginDataCenter/dataCenterBg.png') no-repeat center; */
   background-size: 100% 100%;
   overflow: hidden;
   position: relative;
@@ -128,4 +128,4 @@ const handleForgotPwd = () => {
   background: #2563eb;
   box-shadow: 0 0 15px rgba(59, 130, 246, 0.6);
 }
-</style>
+</style>

+ 2 - 2
src/views/sys/login/LoginForm.vue

@@ -63,8 +63,8 @@
   const rememberMe = ref(false);
 
   const formData = reactive({
-    account: 'zhuqi',
-    password: 'zhuqi123zhuqi',
+    account: 'hsq',
+    password: 'hsq123hsq',
     inputCode: '',
   });
   const randCodeData = reactive({

+ 2 - 2
src/views/sys/login/LoginNeiye.vue

@@ -43,7 +43,7 @@ const handleForgotPwd = () => {
 .login-container {
   width: 100%;
   height: 100%;
-  background: url('@/assets/images/vent/loginNeiye/bg.png') no-repeat center;
+  /* background: url('@/assets/images/vent/loginNeiye/bg.png') no-repeat center; */
   background-size: 100% 100%;
   overflow: hidden;
   position: relative;
@@ -129,4 +129,4 @@ const handleForgotPwd = () => {
   background: #2563eb;
   box-shadow: 0 0 15px rgba(59, 130, 246, 0.6);
 }
-</style>
+</style>

+ 182 - 150
src/views/system/role/index.vue

@@ -1,5 +1,8 @@
 <template>
   <div class="device-manager-box">
+    <div class="back-btn" @click="getBack">
+      <SvgIcon class="box-icon-style" size="20" name="back-bg" />
+    </div>
     <BasicTable @register="registerTable">
       <template #tableTitle>
         <a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
@@ -14,8 +17,7 @@
               </a-menu-item>
             </a-menu>
           </template>
-          <a-button
-            >批量操作
+          <a-button>批量操作
             <Icon icon="mdi:chevron-down" />
           </a-button>
         </a-dropdown>
@@ -37,161 +39,191 @@
   <RoleIndexModal @register="registerIndexModal" />
 </template>
 <script lang="ts" name="system-role" setup>
-  import { ref } from 'vue';
-  import { BasicTable, TableAction } from '/@/components/Table';
-  import { useDrawer } from '/@/components/Drawer';
-  import { useModal } from '/@/components/Modal';
-  import RoleDrawer from './components/RoleDrawer.vue';
-  import RoleDesc from './components/RoleDesc.vue';
-  import RolePermissionDrawer from './components/RolePermissionDrawer.vue';
-  import RoleIndexModal from './components/RoleIndexModal.vue';
-  import RoleUserTable from './components/RoleUserTable.vue';
-  import { columns, searchFormSchema } from './role.data';
-  import { list, deleteRole, batchDeleteRole, getExportUrl, getImportUrl } from './role.api';
-  import { useListPage } from '/@/hooks/system/useListPage';
-  const showFooter = ref(true);
-  const [roleUserDrawer, { openDrawer: openRoleUserDrawer }] = useDrawer();
-  const [registerDrawer, { openDrawer }] = useDrawer();
-  const [registerModal, { openModal }] = useModal();
-  const [registerIndexModal, { openModal: openIndexModal }] = useModal();
-  const [rolePermissionDrawer, { openDrawer: openRolePermissionDrawer }] = useDrawer();
-  const [registerDesc, { openDrawer: openRoleDesc }] = useDrawer();
+import { ref } from 'vue';
+import { BasicTable, TableAction } from '/@/components/Table';
+import { useDrawer } from '/@/components/Drawer';
+import { useModal } from '/@/components/Modal';
+import RoleDrawer from './components/RoleDrawer.vue';
+import RoleDesc from './components/RoleDesc.vue';
+import RolePermissionDrawer from './components/RolePermissionDrawer.vue';
+import RoleIndexModal from './components/RoleIndexModal.vue';
+import RoleUserTable from './components/RoleUserTable.vue';
+import { columns, searchFormSchema } from './role.data';
+import { list, deleteRole, batchDeleteRole, getExportUrl, getImportUrl } from './role.api';
+import { useListPage } from '/@/hooks/system/useListPage';
+import { SvgIcon } from '/@/components/Icon';
 
-  // 列表页面公共参数、方法
-  const { prefixCls, tableContext, onImportXls, onExportXls } = useListPage({
-    designScope: 'role-template',
-    tableProps: {
-      title: '系统角色列表',
-      api: list,
-      columns: columns,
-      formConfig: {
-        // update-begin--author:liaozhiyang---date:20230803---for:【QQYUN-5873】查询区域lablel默认居左
-        labelWidth:65,
-        rowProps: { gutter: 24 },
-        // update-end--author:liaozhiyang---date:20230803---for:【QQYUN-5873】查询区域lablel默认居左
-        schemas: searchFormSchema,
-      },
-      actionColumn: {
-        width: 120,
-      },
-      rowSelection: null,
-      //自定义默认排序
-      defSort: {
-        column: 'id',
-        order: 'desc',
-      },
+const showFooter = ref(true);
+const [roleUserDrawer, { openDrawer: openRoleUserDrawer }] = useDrawer();
+const [registerDrawer, { openDrawer }] = useDrawer();
+const [registerModal, { openModal }] = useModal();
+const [registerIndexModal, { openModal: openIndexModal }] = useModal();
+const [rolePermissionDrawer, { openDrawer: openRolePermissionDrawer }] = useDrawer();
+const [registerDesc, { openDrawer: openRoleDesc }] = useDrawer();
+
+// 列表页面公共参数、方法
+const { prefixCls, tableContext, onImportXls, onExportXls } = useListPage({
+  designScope: 'role-template',
+  tableProps: {
+    title: '系统角色列表',
+    api: list,
+    columns: columns,
+    formConfig: {
+      // update-begin--author:liaozhiyang---date:20230803---for:【QQYUN-5873】查询区域lablel默认居左
+      labelWidth: 65,
+      rowProps: { gutter: 24 },
+      // update-end--author:liaozhiyang---date:20230803---for:【QQYUN-5873】查询区域lablel默认居左
+      schemas: searchFormSchema,
     },
-    exportConfig: {
-      name: '角色列表',
-      url: getExportUrl,
+    actionColumn: {
+      width: 120,
     },
-    importConfig: {
-      url: getImportUrl,
+    rowSelection: null,
+    //自定义默认排序
+    defSort: {
+      column: 'id',
+      order: 'desc',
     },
+  },
+  exportConfig: {
+    name: '角色列表',
+    url: getExportUrl,
+  },
+  importConfig: {
+    url: getImportUrl,
+  },
+});
+const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
+
+/**
+ * 新增
+ */
+function handleCreate() {
+  showFooter.value = true;
+  openDrawer(true, {
+    isUpdate: false,
+  });
+}
+/**
+ * 编辑
+ */
+function handleEdit(record: Recordable) {
+  showFooter.value = true;
+  openDrawer(true, {
+    record,
+    isUpdate: true,
   });
-  const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
+}
+/**
+ * 详情
+ */
+function handleDetail(record) {
+  showFooter.value = false;
+  openRoleDesc(true, {
+    record,
+    isUpdate: true,
+  });
+}
+/**
+ * 删除事件
+ */
+async function handleDelete(record) {
+  await deleteRole({ id: record.id }, reload);
+}
+/**
+ * 批量删除事件
+ */
+async function batchHandleDelete() {
+  await batchDeleteRole({ ids: selectedRowKeys.value }, reload);
+}
+/**
+ * 角色授权弹窗
+ */
+function handlePerssion(record) {
+  openRolePermissionDrawer(true, { roleId: record.id });
+}
 
-  /**
-   * 新增
-   */
-  function handleCreate() {
-    showFooter.value = true;
-    openDrawer(true, {
-      isUpdate: false,
-    });
-  }
-  /**
-   * 编辑
-   */
-  function handleEdit(record: Recordable) {
-    showFooter.value = true;
-    openDrawer(true, {
-      record,
-      isUpdate: true,
-    });
-  }
-  /**
-   * 详情
-   */
-  function handleDetail(record) {
-    showFooter.value = false;
-    openRoleDesc(true, {
-      record,
-      isUpdate: true,
-    });
-  }
-  /**
-   * 删除事件
-   */
-  async function handleDelete(record) {
-    await deleteRole({ id: record.id }, reload);
-  }
-  /**
-   * 批量删除事件
-   */
-  async function batchHandleDelete() {
-    await batchDeleteRole({ ids: selectedRowKeys.value }, reload);
-  }
-  /**
-   * 角色授权弹窗
-   */
-  function handlePerssion(record) {
-    openRolePermissionDrawer(true, { roleId: record.id });
-  }
+/**
+ * 首页配置弹窗
+ */
+function handleIndexConfig(roleCode) {
+  openIndexModal(true, { roleCode });
+}
+/**
+ * 角色用户
+ */
+function handleUser(record) {
+  //onSelectChange(selectedRowKeys)
+  openRoleUserDrawer(true, record);
+}
+/**
+ * 操作栏
+ */
+function getTableAction(record) {
+  return [
+    {
+      label: '用户',
+      onClick: handleUser.bind(null, record),
+    },
+    {
+      label: '授权',
+      onClick: handlePerssion.bind(null, record),
+    },
+  ];
+}
 
-  /**
-   * 首页配置弹窗
-   */
-  function handleIndexConfig(roleCode) {
-    openIndexModal(true, { roleCode });
-  }
-  /**
-   * 角色用户
-   */
-  function handleUser(record) {
-    //onSelectChange(selectedRowKeys)
-    openRoleUserDrawer(true, record);
-  }
-  /**
-   * 操作栏
-   */
-  function getTableAction(record) {
-    return [
-      {
-        label: '用户',
-        onClick: handleUser.bind(null, record),
-      },
-      {
-        label: '授权',
-        onClick: handlePerssion.bind(null, record),
+/**
+ * 下拉操作栏
+ */
+function getDropDownAction(record) {
+  return [
+    {
+      label: '编辑',
+      onClick: handleEdit.bind(null, record),
+    },
+    {
+      label: '详情',
+      onClick: handleDetail.bind(null, record),
+    },
+    {
+      label: '删除',
+      popConfirm: {
+        title: '是否确认删除',
+        confirm: handleDelete.bind(null, record),
       },
-    ];
-  }
+    },
+    {
+      label: '首页配置',
+      onClick: handleIndexConfig.bind(null, record.roleCode),
+    },
+  ];
+}
+/**
+ * 返回上一页
+ *
+ * 使用浏览器的历史记录API返回到上一个页面
+ */
+function getBack() {
+  window.history.back();
+}
+</script>
+<style scoped>
+.device-manager-box {
+  position: relative;
+  width: 100%;
+  height: 100%;
 
-  /**
-   * 下拉操作栏
-   */
-  function getDropDownAction(record) {
-    return [
-      {
-        label: '编辑',
-        onClick: handleEdit.bind(null, record),
-      },
-      {
-        label: '详情',
-        onClick: handleDetail.bind(null, record),
-      },
-      {
-        label: '删除',
-        popConfirm: {
-          title: '是否确认删除',
-          confirm: handleDelete.bind(null, record),
-        },
-      },
-      {
-        label: '首页配置',
-        onClick: handleIndexConfig.bind(null, record.roleCode),
-      },
-    ];
+  .back-btn {
+    position: absolute;
+    left: 5px;
+    top: 5px;
+    color: var(--vent-font-color);
+    background-color: #1580cc;
+    border: 1px solid #1580cc;
+    cursor: pointer;
+    z-index: 9999;
+    padding: 5px 8px;
+    border-radius: 5px;
   }
-</script>
+}
+</style>

+ 246 - 214
src/views/system/user/index.vue

@@ -1,5 +1,8 @@
 <template>
   <div class="device-manager-box">
+    <div class="back-btn" @click="getBack">
+      <SvgIcon class="box-icon-style" size="20" name="back-bg" />
+    </div>
     <!--引用表格-->
     <BasicTable @register="registerTable" :rowSelection="rowSelection">
       <!--插槽:table标题-->
@@ -9,7 +12,8 @@
         <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
         <a-button type="primary" @click="handleSyncUser" preIcon="ant-design:sync-outlined"> 同步流程</a-button>
         <a-button type="primary" @click="openModal(true, {})" preIcon="ant-design:hdd-outlined"> 回收站</a-button>
-        <JThirdAppButton biz-type="user" :selected-row-keys="selectedRowKeys" syncToApp syncToLocal @sync-finally="onSyncFinally" />
+        <JThirdAppButton biz-type="user" :selected-row-keys="selectedRowKeys" syncToApp syncToLocal
+          @sync-finally="onSyncFinally" />
         <a-dropdown v-if="selectedRowKeys.length > 0">
           <template #overlay>
             <a-menu>
@@ -27,8 +31,7 @@
               </a-menu-item>
             </a-menu>
           </template>
-          <a-button
-            >批量操作
+          <a-button>批量操作
             <Icon icon="mdi:chevron-down" />
           </a-button>
         </a-dropdown>
@@ -50,236 +53,265 @@
 </template>
 
 <script lang="ts" name="system-user" setup>
-  //ts语法
-  import { ref, computed, unref } from 'vue';
-  import { BasicTable, TableAction, ActionItem } from '/@/components/Table';
-  import UserDrawer from './UserDrawer.vue';
-  import UserRecycleBinModal from './UserRecycleBinModal.vue';
-  import PasswordModal from './PasswordModal.vue';
-  import UserAgentModal from './UserAgentModal.vue';
-  import JThirdAppButton from '/@/components/jeecg/thirdApp/JThirdAppButton.vue';
-  import { useDrawer } from '/@/components/Drawer';
-  import { useListPage } from '/@/hooks/system/useListPage';
-  import { useModal } from '/@/components/Modal';
-  import { useMessage } from '/@/hooks/web/useMessage';
-  import { columns, searchFormSchema } from './user.data';
-  import { list, deleteUser, batchDeleteUser, getImportUrl, getExportUrl, frozenBatch, syncUser } from './user.api';
-  // import { usePermission } from '/@/hooks/web/usePermission'
-  // const { hasPermission } = usePermission();
+//ts语法
+import { ref, computed, unref } from 'vue';
+import { BasicTable, TableAction, ActionItem } from '/@/components/Table';
+import UserDrawer from './UserDrawer.vue';
+import UserRecycleBinModal from './UserRecycleBinModal.vue';
+import PasswordModal from './PasswordModal.vue';
+import UserAgentModal from './UserAgentModal.vue';
+import JThirdAppButton from '/@/components/jeecg/thirdApp/JThirdAppButton.vue';
+import { useDrawer } from '/@/components/Drawer';
+import { useListPage } from '/@/hooks/system/useListPage';
+import { useModal } from '/@/components/Modal';
+import { useMessage } from '/@/hooks/web/useMessage';
+import { columns, searchFormSchema } from './user.data';
+import { list, deleteUser, batchDeleteUser, getImportUrl, getExportUrl, frozenBatch, syncUser } from './user.api';
+import { SvgIcon } from '/@/components/Icon';
+// import { usePermission } from '/@/hooks/web/usePermission'
+// const { hasPermission } = usePermission();
 
-  const { createMessage, createConfirm } = useMessage();
+const { createMessage, createConfirm } = useMessage();
 
-  //注册drawer
-  const [registerDrawer, { openDrawer }] = useDrawer();
-  //回收站model
-  const [registerModal, { openModal }] = useModal();
-  //密码model
-  const [registerPasswordModal, { openModal: openPasswordModal }] = useModal();
-  //代理人model
-  const [registerAgentModal, { openModal: openAgentModal }] = useModal();
+//注册drawer
+const [registerDrawer, { openDrawer }] = useDrawer();
+//回收站model
+const [registerModal, { openModal }] = useModal();
+//密码model
+const [registerPasswordModal, { openModal: openPasswordModal }] = useModal();
+//代理人model
+const [registerAgentModal, { openModal: openAgentModal }] = useModal();
 
-  // 列表页面公共参数、方法
-  const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
-    designScope: 'user-list',
-    tableProps: {
-      title: '用户列表',
-      api: list,
-      columns: columns,
-      size: 'small',
-      formConfig: {
-        // labelWidth: 200,
-        schemas: searchFormSchema,
-      },
-      actionColumn: {
-        width: 120,
-      },
-      beforeFetch: (params) => {
-        return Object.assign({ column: 'createTime', order: 'desc' }, params);
-      },
+// 列表页面公共参数、方法
+const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
+  designScope: 'user-list',
+  tableProps: {
+    title: '用户列表',
+    api: list,
+    columns: columns,
+    size: 'small',
+    formConfig: {
+      // labelWidth: 200,
+      schemas: searchFormSchema,
     },
-    exportConfig: {
-      name: '用户列表',
-      url: getExportUrl,
+    actionColumn: {
+      width: 120,
     },
-    importConfig: {
-      url: getImportUrl,
+    beforeFetch: (params) => {
+      return Object.assign({ column: 'createTime', order: 'desc' }, params);
     },
-  });
+  },
+  exportConfig: {
+    name: '用户列表',
+    url: getExportUrl,
+  },
+  importConfig: {
+    url: getImportUrl,
+  },
+});
 
-  //注册table数据
-  const [registerTable, { reload, updateTableDataRecord }, { rowSelection, selectedRows, selectedRowKeys }] = tableContext;
+//注册table数据
+const [registerTable, { reload, updateTableDataRecord }, { rowSelection, selectedRows, selectedRowKeys }] = tableContext;
 
-  /**
-   * 新增事件
-   */
-  function handleCreate() {
-    openDrawer(true, {
-      isUpdate: false,
-      showFooter: true,
-    });
-  }
-  /**
-   * 编辑事件
-   */
-  async function handleEdit(record: Recordable) {
-    openDrawer(true, {
-      record,
-      isUpdate: true,
-      showFooter: true,
-    });
-  }
-  /**
-   * 详情
-   */
-  async function handleDetail(record: Recordable) {
-    openDrawer(true, {
-      record,
-      isUpdate: true,
-      showFooter: false,
-    });
-  }
-  /**
-   * 删除事件
-   */
-  async function handleDelete(record) {
-    if ('admin' == record.username) {
-      createMessage.warning('管理员账号不允许此操作!');
-      return;
-    }
-    await deleteUser({ id: record.id }, reload);
+/**
+ * 新增事件
+ */
+function handleCreate() {
+  openDrawer(true, {
+    isUpdate: false,
+    showFooter: true,
+  });
+}
+/**
+ * 编辑事件
+ */
+async function handleEdit(record: Recordable) {
+  openDrawer(true, {
+    record,
+    isUpdate: true,
+    showFooter: true,
+  });
+}
+/**
+ * 详情
+ */
+async function handleDetail(record: Recordable) {
+  openDrawer(true, {
+    record,
+    isUpdate: true,
+    showFooter: false,
+  });
+}
+/**
+ * 删除事件
+ */
+async function handleDelete(record) {
+  if ('admin' == record.username) {
+    createMessage.warning('管理员账号不允许此操作!');
+    return;
   }
-  /**
-   * 批量删除事件
-   */
-  async function batchHandleDelete() {
-    let hasAdmin = unref(selectedRows).filter((item) => item.username == 'admin');
-    if (unref(hasAdmin).length > 0) {
-      createMessage.warning('管理员账号不允许此操作!');
-      return;
-    }
-    await batchDeleteUser({ ids: selectedRowKeys.value }, () => {
-      selectedRowKeys.value = [];
-      reload();
-    });
+  await deleteUser({ id: record.id }, reload);
+}
+/**
+ * 批量删除事件
+ */
+async function batchHandleDelete() {
+  let hasAdmin = unref(selectedRows).filter((item) => item.username == 'admin');
+  if (unref(hasAdmin).length > 0) {
+    createMessage.warning('管理员账号不允许此操作!');
+    return;
   }
-  /**
-   * 成功回调
-   */
-  function handleSuccess() {
+  await batchDeleteUser({ ids: selectedRowKeys.value }, () => {
+    selectedRowKeys.value = [];
     reload();
-  }
+  });
+}
+/**
+ * 成功回调
+ */
+function handleSuccess() {
+  reload();
+}
 
-  /**
-   * 打开修改密码弹窗
-   */
-  function handleChangePassword(username) {
-    openPasswordModal(true, { username });
+/**
+ * 打开修改密码弹窗
+ */
+function handleChangePassword(username) {
+  openPasswordModal(true, { username });
+}
+/**
+ * 打开代理人弹窗
+ */
+function handleAgentSettings(userName) {
+  openAgentModal(true, { userName });
+}
+/**
+ * 冻结解冻
+ */
+async function handleFrozen(record, status) {
+  if ('admin' == record.username) {
+    createMessage.warning('管理员账号不允许此操作!');
+    return;
   }
-  /**
-   * 打开代理人弹窗
-   */
-  function handleAgentSettings(userName) {
-    openAgentModal(true, { userName });
-  }
-  /**
-   * 冻结解冻
-   */
-  async function handleFrozen(record, status) {
-    if ('admin' == record.username) {
-      createMessage.warning('管理员账号不允许此操作!');
-      return;
-    }
-    await frozenBatch({ ids: record.id, status: status }, reload);
-  }
-  /**
-   * 批量冻结解冻
-   */
-  function batchFrozen(status) {
-    let hasAdmin = selectedRows.value.filter((item) => item.username == 'admin');
-    if (unref(hasAdmin).length > 0) {
-      createMessage.warning('管理员账号不允许此操作!');
-      return;
-    }
-    createConfirm({
-      iconType: 'warning',
-      title: '确认操作',
-      content: '是否' + (status == 1 ? '解冻' : '冻结') + '选中账号?',
-      onOk: async () => {
-        await frozenBatch({ ids: unref(selectedRowKeys).join(','), status: status }, reload);
-      },
-    });
+  await frozenBatch({ ids: record.id, status: status }, reload);
+}
+/**
+ * 批量冻结解冻
+ */
+function batchFrozen(status) {
+  let hasAdmin = selectedRows.value.filter((item) => item.username == 'admin');
+  if (unref(hasAdmin).length > 0) {
+    createMessage.warning('管理员账号不允许此操作!');
+    return;
   }
+  createConfirm({
+    iconType: 'warning',
+    title: '确认操作',
+    content: '是否' + (status == 1 ? '解冻' : '冻结') + '选中账号?',
+    onOk: async () => {
+      await frozenBatch({ ids: unref(selectedRowKeys).join(','), status: status }, reload);
+    },
+  });
+}
 
-  /**
-   *同步流程
-   */
-  function handleSyncUser() {
-    syncUser();
-  }
-  /**
-   *同步钉钉和微信回调
-   */
-  function onSyncFinally({ isToLocal }) {
-    // 同步到本地时刷新下数据
-    if (isToLocal) {
-      reload();
-    }
+/**
+ *同步流程
+ */
+function handleSyncUser() {
+  syncUser();
+}
+/**
+ *同步钉钉和微信回调
+ */
+function onSyncFinally({ isToLocal }) {
+  // 同步到本地时刷新下数据
+  if (isToLocal) {
+    reload();
   }
+}
 
-  /**
-   * 操作栏
-   */
-  function getTableAction(record): ActionItem[] {
-    return [
-      {
-        label: '编辑',
-        onClick: handleEdit.bind(null, record),
-        // ifShow: () => hasPermission('system:user:edit'),
-      },
-    ];
-  }
-  /**
-   * 下拉操作栏
-   */
-  function getDropDownAction(record): ActionItem[] {
-    return [
-      {
-        label: '详情',
-        onClick: handleDetail.bind(null, record),
-      },
-      {
-        label: '密码',
-        onClick: handleChangePassword.bind(null, record.username),
-      },
-      {
-        label: '删除',
-        popConfirm: {
-          title: '是否确认删除',
-          confirm: handleDelete.bind(null, record),
-        },
-      },
-      {
-        label: '冻结',
-        ifShow: record.status == 1,
-        popConfirm: {
-          title: '确定冻结吗?',
-          confirm: handleFrozen.bind(null, record, 2),
-        },
+/**
+ * 操作栏
+ */
+function getTableAction(record): ActionItem[] {
+  return [
+    {
+      label: '编辑',
+      onClick: handleEdit.bind(null, record),
+      // ifShow: () => hasPermission('system:user:edit'),
+    },
+  ];
+}
+/**
+ * 下拉操作栏
+ */
+function getDropDownAction(record): ActionItem[] {
+  return [
+    {
+      label: '详情',
+      onClick: handleDetail.bind(null, record),
+    },
+    {
+      label: '密码',
+      onClick: handleChangePassword.bind(null, record.username),
+    },
+    {
+      label: '删除',
+      popConfirm: {
+        title: '是否确认删除',
+        confirm: handleDelete.bind(null, record),
       },
-      {
-        label: '解冻',
-        ifShow: record.status == 2,
-        popConfirm: {
-          title: '确定解冻吗?',
-          confirm: handleFrozen.bind(null, record, 1),
-        },
+    },
+    {
+      label: '冻结',
+      ifShow: record.status == 1,
+      popConfirm: {
+        title: '确定冻结吗?',
+        confirm: handleFrozen.bind(null, record, 2),
       },
-      {
-        label: '代理人',
-        onClick: handleAgentSettings.bind(null, record.username),
+    },
+    {
+      label: '解冻',
+      ifShow: record.status == 2,
+      popConfirm: {
+        title: '确定解冻吗?',
+        confirm: handleFrozen.bind(null, record, 1),
       },
-    ];
-  }
+    },
+    {
+      label: '代理人',
+      onClick: handleAgentSettings.bind(null, record.username),
+    },
+  ];
+}
+
+/**
+ * 返回上一页
+ *
+ * 使用浏览器的历史记录API返回到上一个页面
+ */
+function getBack() {
+  window.history.back();
+}
 </script>
 
-<style scoped></style>
+<style scoped>
+.device-manager-box {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .back-btn {
+    position: absolute;
+    left: 5px;
+    top: 5px;
+    color: var(--vent-font-color);
+    background-color: #1580cc;
+    border: 1px solid #1580cc;
+    cursor: pointer;
+    z-index: 9999;
+    padding: 5px 8px;
+    border-radius: 5px;
+  }
+}
+</style>

+ 24 - 19
src/views/vent/cad/dwgViewer.vue

@@ -96,6 +96,7 @@
 
   // ==================== 表格 ====================
 
+  // 设备列表表格列
   const columns = [
     { title: '#', key: 'index', width: 36 },
     { title: '设备名称', dataIndex: 'name', ellipsis: true },
@@ -104,25 +105,26 @@
     { title: '操作', key: 'action', width: 56 },
     { title: '布点', key: 'markerStatus', width: 48 },
   ];
-
+  // 设备列表数据
   const devices = ref<DeviceInfo[]>([
-    { id: 'd001', name: '1#瓦斯传感器', type: '传感器', status: 'online', markerId: null },
-    { id: 'd002', name: '2#瓦斯传感器', type: '传感器', status: 'online', markerId: null },
-    { id: 'd003', name: '主通风机', type: '风机', status: 'online', markerId: null },
-    { id: 'd004', name: '局部通风机', type: '风机', status: 'offline', markerId: null },
-    { id: 'd005', name: '风门A', type: '风门', status: 'online', markerId: null },
-    { id: 'd006', name: '风速传感器-1', type: '传感器', status: 'alarm', markerId: null },
-    { id: 'd007', name: '温度传感器-1', type: '传感器', status: 'online', markerId: null },
-    { id: 'd008', name: '风窗B', type: '风窗', status: 'online', markerId: null },
+    // { id: 'd001', name: '1#瓦斯传感器', type: '传感器', status: 'online', markerId: null },
+    // { id: 'd002', name: '2#瓦斯传感器', type: '传感器', status: 'online', markerId: null },
+    // { id: 'd003', name: '主通风机', type: '风机', status: 'online', markerId: null },
+    // { id: 'd004', name: '局部通风机', type: '风机', status: 'offline', markerId: null },
+    // { id: 'd005', name: '风门A', type: '风门', status: 'online', markerId: null },
+    // { id: 'd006', name: '风速传感器-1', type: '传感器', status: 'alarm', markerId: null },
+    // { id: 'd007', name: '温度传感器-1', type: '传感器', status: 'online', markerId: null },
+    // { id: 'd008', name: '风窗B', type: '风窗', status: 'online', markerId: null },
   ]);
-
+  // 状态颜色映射
   function statusColor(s: string) {
     return { online: 'green', offline: 'gray', alarm: 'red' }[s] || 'default';
   }
+  // 状态文本映射
   function statusText(s: string) {
     return { online: '在线', offline: '离线', alarm: '报警' }[s] || s;
   }
-
+  // 模拟监测数据
   function getMockMonitoring(deviceId: string) {
     const d = devices.value.find((x) => x.id === deviceId);
     return {
@@ -217,13 +219,13 @@
 
     console.log(`[布点] 进入放置模式: ${device.name}`);
   }
-
+  // 退出放置模式
   function exitPlacingMode() {
     placingMode.value = false;
     placingDevice.value = null;
     if (floatingDot) floatingDot.style.display = 'none';
   }
-
+  // 放置 marker
   function placeMarker(device: DeviceInfo, location: { x: number; y: number }) {
     if (!viewer) return;
     markerIdCounter++;
@@ -287,7 +289,7 @@
     console.log(`[布点] 设备=${device.name} X=${location.x.toFixed(2)} Y=${location.y.toFixed(2)} r=${radius.toFixed(2)}`);
     exitPlacingMode();
   }
-
+  // 移除 marker
   function removeMarker(markerId: string) {
     if (!viewer) return;
     const m = markersMap.get(markerId);
@@ -311,8 +313,8 @@
   }
 
   let infoPanel: HTMLElement | null = null;
-
-  function showMarkerInfo(markerId: string) {
+  // 显示 marker 信息面板
+   function showMarkerInfo(markerId: string) {
     const m = markersMap.get(markerId);
     if (!m || !viewer) return;
     const data = getMockMonitoring(m.deviceId);
@@ -356,7 +358,7 @@
     };
     setTimeout(() => document.addEventListener('click', closeHandler), 100);
   }
-
+  // 点击 marker 事件
   function onMarkerClick(markerId: string) {
     console.log(`[标记点击] marker=${markerId}`);
     showMarkerInfo(markerId);
@@ -365,6 +367,7 @@
   // ==================== 初始化 ====================
 
   onMounted(async () => {
+    // 初始化 viewer
     try {
       viewer = new Viewer2d({
         containerId,
@@ -450,12 +453,14 @@
       console.error('[DWG] 初始化失败:', err);
     }
   });
-
+  /** 键盘事件处理:Esc 键退出放置模式 */
   const onKeydown = (e: KeyboardEvent) => {
     if (e.key === 'Escape' && placingMode.value) exitPlacingMode();
   };
-  onMounted(() => window.addEventListener('keydown', onKeydown));
+  // 注册键盘事件监听
+   onMounted(() => window.addEventListener('keydown', onKeydown));
 
+  /** 组件卸载时清理:移除事件监听、销毁所有 marker、释放 viewer 资源 */
   onUnmounted(() => {
     window.removeEventListener('keydown', onKeydown);
     floatingDot?.remove();

+ 0 - 88
src/views/vent/home/configurable/components/ModuleGasInject.vue

@@ -1,88 +0,0 @@
-<template>
-  <!-- 红沙泉露天煤矿 -->
-  <component
-    :is="getModuleComponent(showStyle)"
-    :style="style"
-    :title="moduleName"
-    :visible="visible"
-    :visibleDetail="visibleDetail"
-    :class="{ 'cursor-pointer': !!moduleData.to }"
-    @close="$emit('close')"
-    @click="redirectTo"
-    @handleClickDetail="handleClickDetail"
-  >
-    <slot>
-      <Header :deviceType="deviceType" :moduleData="moduleData" :data="data" @select="selectedData = $event" />
-      <Content :style="{ height: header.show ? 'calc(100% - 30px)' : '100%' }" :moduleData="moduleData" :data="selectedData" />
-      <DetailInfo :showDetail="showDetail" :deviceType="deviceType" :data="data" @closeModal="closeModal"></DetailInfo>
-    </slot>
-  </component>
-</template>
-<script lang="ts" setup>
-  import Header from './header.vue';
-  import Content from './content.vue';
-  import ModuleLeft from './gasInject/moduleLeft.vue';
-  import ModuleRight from './gasInject/moduleRight.vue';
-  import ModuleBottom from './gasInject/moduleBottom.vue';
-  import DetailInfo from './gasInject/DetailInfo.vue';
-  import { computed, ref } from 'vue';
-  import { openWindow } from '/@/utils';
-  import { getFormattedText } from '../hooks/helper';
-  // import { ModuleProps } from '../types';
-
-  const props = defineProps<{
-    /** 配置的详细模块信息 */
-    moduleData: any;
-    /** 配置的详细样式信息 */
-    showStyle: any;
-    /** 该模块配置中的设备标识符 */
-    deviceType: string;
-    /** api返回的数据 */
-    data: any;
-    moduleName: string;
-    visible: boolean;
-    visibleDetail: boolean;
-  }>();
-  defineEmits(['close', 'click']);
-
-  const { header } = props.moduleData;
-  const selectedData = ref();
-  //是否显示详情信息
-  const showDetail = ref(false);
-
-  const style = computed(() => {
-    const size = props.showStyle.size;
-    const position = props.showStyle.position;
-    return size + position;
-  });
-
-  // 根据配置里的定位判断应该使用哪个module组件
-  function getModuleComponent({ size, position }) {
-    const [_, width] = size.match(/width:([0-9]+)px/) || [];
-    if (position.includes('bottom') || parseInt(width) > 800) {
-      return ModuleBottom;
-    }
-    if (position.includes('left')) {
-      return ModuleLeft;
-    }
-    if (position.includes('right')) {
-      return ModuleRight;
-    }
-    return ModuleBottom;
-  }
-
-  function redirectTo() {
-    const { to } = props.moduleData;
-    if (!to) return;
-    openWindow(getFormattedText(selectedData.value, to));
-  }
-
-  //详情点击
-  function handleClickDetail() {
-    showDetail.value = true;
-  }
-  //关闭弹窗
-  function closeModal(param) {
-    showDetail.value = param;
-  }
-</script>

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

@@ -262,11 +262,9 @@ import { clone } from 'lodash-es';
 import { getData, getFormattedText } from '../hooks/helper';
 import BlastDelta from '../../../monitorManager/deviceMonitor/components/device/modal/blastDelta.vue';
 import QHCurve from './preset/QHCurve.vue';
-import MeasureDetail from './preset/MeasureDetail.vue';
 import CustomTabs from './preset/CustomTabs.vue';
 import AIChat from '/@/components/AIChat/MiniChat.vue';
 import DeviceAlarm from './preset/DeviceAlarm.vue';
-import SelectCs from './preset/SelectCs.vue';
 import MiniBoardNew from './detail/MiniBoard-New.vue';
 import Partition from './preset/partition.vue';
 import SelectorDualChart from './preset/selectorDualChart.vue';

+ 0 - 202
src/views/vent/home/configurable/components/preset/CustomGalleryNew.vue

@@ -1,202 +0,0 @@
-<template>
-  <div class="custom-gallery-new">
-    <div :class="`gallery-new-box-${type}`">
-      <div :class="`gallery-content-${type}`" v-for="(item, index) in option" :key="index">
-        <SvgIcon v-if="type == 'B'" :class="index % 2 == 0 ? 'icon-style' : 'icon-style1'" size="20"
-          :name="item.iconName" />
-        <div :class="index % 2 == 0 ? 'gallery-content-text' : 'gallery-content-text-r'">{{ item.label }}</div>
-        <div :class="index % 2 == 0 ? 'gallery-content-value' : 'gallery-content-value-r'">{{ galleryData ?
-          galleryData[item.value] : 0}}</div>
-      </div>
-      <div :class="`gallery-content-${type}`">
-        <SvgIcon  class="icon-style2" size="30" :name="type=='B' ? 'zsj' : 'device-status'" />
-        <!-- <div v-else class="gallery-content-text1">{{ galleryData?.totalNum || 0 }}</div> -->
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { ref, watch } from 'vue'
-import { SvgIcon } from '/@/components/Icon';
-
-let props = defineProps({
-  type: {
-    type: String
-  },
-  option: {
-    type: Array as any
-  },
-  galleryData: {
-    type: Object
-  }
-})
-
-</script>
-
-<style lang="less" scoped>
-@import '/@/design/theme.less';
-
-@{theme-deepblue} {}
-
-.custom-gallery-new {
-  --image-gallery-bg: url('@/assets/images/home-container/configurable/dusthome/gallery-bg.png');
-  --image-gallery-bg-b: url('@/assets/images/home-container/configurable/dusthome/gallery-bg-b.png');
-  position: relative;
-  padding: 10px 15px;
-
-  .gallery-new-box-A {
-    position: relative;
-    width: 100%;
-    height: 100%;
-    background: var(--image-gallery-bg) no-repeat;
-    background-size: 100% 100%;
-
-  }
-
-  .gallery-new-box-B {
-    position: relative;
-    width: 100%;
-    height: 100%;
-    background: var(--image-gallery-bg-b) no-repeat;
-    background-size: 100% 100%;
-
-  }
-
-  .gallery-content-A {
-    position: absolute;
-
-    &:nth-child(1) {
-      left: 22px;
-      top: 1px;
-    }
-
-    &:nth-child(2) {
-      display: flex;
-      flex-direction: column;
-      align-items: flex-end;
-      right: 24px;
-      top: 1px;
-    }
-
-    &:nth-child(3) {
-      left: 22px;
-      top: 61px;
-    }
-
-    &:nth-child(4) {
-      display: flex;
-      flex-direction: column;
-      align-items: flex-end;
-      right: 24px;
-      top: 61px;
-    }
-
-    &:nth-child(5) {
-      left: 50%;
-      top: 50%;
-      transform: translate(-50%, -50%);
-    }
-
-    .gallery-content-text {
-      margin-bottom: 2px;
-    }
-
-    .gallery-content-text-r {
-      margin-bottom: 2px;
-    }
-
-    .gallery-content-text1 {
-      font-size: 24px;
-      font-family: 'douyuFont';
-    }
-
-    .gallery-content-value,
-    .gallery-content-value-r {
-      font-family: 'douyuFont';
-      color: #fff;
-    }
-
-  }
-
-  .gallery-content-B {
-    position: absolute;
-    width: 160px;
-    height: 80px;
-
-    &:nth-child(1) {
-      left: 0px;
-      top: 0px;
-    }
-
-    &:nth-child(2) {
-      right: 0px;
-      top: 0px;
-    }
-
-    &:nth-child(3) {
-      left: 0px;
-      top: 99px;
-    }
-
-    &:nth-child(4) {
-      right: 0px;
-      top: 98px;
-    }
-
-    &:nth-child(5) {
-      left: 50%;
-      top: 50%;
-      transform: translate(-50%, -50%);
-    }
-
-    .icon-style {
-      position: absolute;
-      left: 15px;
-      top: 8px;
-    }
-
-    .icon-style1 {
-      position: absolute;
-      right: 15px;
-      top: 8px;
-    }
-
-    .icon-style2 {
-      position: absolute;
-      left: 65px;
-      top: 25px;
-    }
-
-    .gallery-content-text {
-      position: absolute;
-      left: 42px;
-      top: 6px;
-    }
-
-    .gallery-content-text-r {
-      position: absolute;
-      right: 42px;
-      top: 6px;
-    }
-
-    .gallery-content-value {
-      position: absolute;
-      left: 42px;
-      top: 50px;
-      font-family: 'douyuFont';
-      color: #b9f3ff;
-    }
-
-    .gallery-content-value-r {
-      position: absolute;
-      right: 42px;
-      top: 50px;
-      font-family: 'douyuFont';
-      color: #b9f3ff;
-    }
-  }
-
-
-}
-</style>

+ 0 - 78
src/views/vent/home/configurable/components/preset/ImageCardNew.vue

@@ -1,78 +0,0 @@
-<template>
-  <div class="ImageCardNew">
-    <div class="card-item" v-for="(item, index) in option" :key="index">
-      <div class="item-value">{{ cardData[item.value] }}</div>
-      <div class="item-label">{{ item.label }}</div>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { ref } from 'vue'
-
-let props=defineProps({
-  option:{
-    type:Array as any
-  },
-  cardData:{
-    type:Object as any,
-    default:()=>{
-      return {
-          dayWarn:12,
-      warnOk:2,
-      warnUnOk:10
-      }
-    }
-  }
-})
-</script>
-
-<style lang="less" scoped>
-@import '/@/design/theme.less';
-
-@{theme-deepblue} {}
-
-.ImageCardNew {
-  --image-card-bg: url('@/assets/images/home-container/configurable/hsq/1-7.png');
-  --image-card-bg1: url('@/assets/images/home-container/configurable/hsq/1-8.png');
-  display: flex;
-  justify-content: space-around;
-  align-items: center;
-  width: calc(100% - 20px);
-  height: 100%;
-  background: var(--image-card-bg) no-repeat bottom;
-  background-size: 100% auto;
-  margin: 0px 10px;
-
-  .card-item {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-    width: 89px;
-    height: 49px;
-    background: var(--image-card-bg1) no-repeat;
-    background-size: 100% 100%;
-
-    &:nth-child(1) {
-      .item-value {
-        font-family: 'douyuFont';
-        color: #ff3d3d;
-      }
-    }
-     &:nth-child(2) {
-      .item-value {
-        font-family: 'douyuFont';
-        color: #ff983d;
-      }
-    }
-     &:nth-child(3) {
-      .item-value {
-        font-family: 'douyuFont';
-        color: #3dff69;
-      }
-    }
-  }
-
-}
-</style>

+ 0 - 281
src/views/vent/home/configurable/components/preset/MeasureDetail.vue

@@ -1,281 +0,0 @@
-<template>
-  <div class="content-box">
-    <div class="dust-scroll-content">
-      <a-carousel dot-position="left" dotsClass="dots-class" :dots="true" :autoplay="true">
-        <template v-for="(data, selectIndex) in selectData" :key="selectIndex">
-          <div class="monitor-item">
-            <div class="title-box">{{ data['devicePos'] }}</div>
-            <div class="monitor-content-top">
-              <div v-for="(dustItem, index) in topConfig" :key="index" class="top-item-box" :class="`top-item-box-${index + 1}`">
-                <div class="item-top-title">{{ dustItem.title }}</div>
-                <div class="item-top-value">{{ data[dustItem.code] }}</div>
-              </div>
-            </div>
-            <div class="monitor-content-bottom">
-              <div v-for="(dustItem, index) in btnConfig" :key="index" class="bottom-item-box" :class="`bottom-item-box-${index + 1}`">
-                <div class="item-bottom-title">{{ dustItem.title }}</div>
-                <div class="item-bottom-value">{{ data[dustItem.code] }}</div>
-              </div>
-            </div>
-          </div>
-        </template>
-      </a-carousel>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-  import { ref, watch } from 'vue';
-
-  let props = defineProps({
-    compositeData: {
-      type: Array,
-      default: () => {
-        return [];
-      },
-    },
-    topconfig: {
-      type: Array,
-      default: () => {
-        return [
-          {
-            title: '粉尘类型',
-            code: 'dustType',
-            value: '',
-          },
-          {
-            title: '火焰长度(mm)',
-            code: 'fireLen',
-            value: '',
-          },
-          {
-            title: '爆炸性',
-            code: 'isBlast',
-            value: '',
-          },
-          {
-            title: '风量(m³/min)',
-            code: 'airQuantity',
-            value: '',
-          },
-        ];
-      },
-    },
-    btnconfig: {
-      type: Array,
-      default: () => {
-        return [
-          {
-            title: '总粉尘浓度 (mg/m³)',
-            code: 'dustCon',
-            value: '',
-          },
-          {
-            title: '呼尘浓度 (mg/m³)',
-            code: 'respirableDustCon',
-            value: '',
-          },
-          {
-            title: '二氧化硅含量 (%)',
-            code: 'SiO2Content',
-            value: '',
-          },
-          {
-            title: '呼尘颗粒占比 (%)',
-            code: 'respirableDustRatio',
-            value: '',
-          },
-        ];
-      },
-    },
-  });
-  const selectData = ref<any>([]);
-  const topConfig: any = props.topconfig;
-  const btnConfig: any = props.btnconfig;
-  watch(
-    () => props.compositeData,
-    (newS) => {
-      selectData.value = newS;
-    },
-    {
-      immediate: true,
-      deep: true,
-    }
-  );
-</script>
-
-<style lang="less" scoped>
-  @font-face {
-    font-family: 'douyuFont';
-    src: url('/@/assets/font/douyuFont.otf');
-  }
-
-  .content-box {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    width: 100%;
-    height: 100%;
-
-    .dust-scroll-content {
-      width: 400px;
-      height: 420px;
-      overflow-y: auto;
-      overflow-x: hidden;
-      .monitor-item {
-        margin-bottom: 15px;
-        .title-box {
-          color: #fff;
-          width: 100%;
-          height: 40px;
-          margin-left: 5px;
-          margin-top: 00px;
-          margin-bottom: 5px;
-          padding-left: 40px;
-          padding-top: 6px;
-          background: url('/@/assets//images//company//lentj.png') no-repeat;
-          background-size: 199px 100%;
-          font-size: 15px;
-          font-weight: 600;
-        }
-        .monitor-content-top {
-          width: 100%;
-          display: flex;
-          flex-direction: row;
-          flex-wrap: wrap;
-          color: #fff;
-          .top-item-box {
-            width: 193px;
-            height: 64px;
-            display: flex;
-            justify-content: space-between;
-            align-items: center;
-            padding: 0 28px;
-          }
-          .top-item-box-1 {
-            background: url('/@/assets//images//company//dust//tip-bg-1.png');
-          }
-          .top-item-box-2 {
-            background: url('/@/assets//images//company//dust//tip-bg-2.png');
-          }
-          .top-item-box-3 {
-            background: url('/@/assets//images//company//dust//tip-bg-3.png');
-          }
-          .top-item-box-4 {
-            background: url('/@/assets//images//company//dust//tip-bg-4.png');
-          }
-        }
-        .monitor-content-bottom {
-          padding: 0 20px;
-          color: #fff;
-          .bottom-item-box {
-            width: 358px;
-            height: 43px;
-            display: flex;
-            justify-content: space-between;
-            align-items: center;
-            margin-top: 14px;
-            position: relative;
-            .item-bottom-title {
-              margin-left: 65px;
-            }
-            .item-bottom-value {
-              margin-right: 20px;
-            }
-          }
-          .bottom-item-box-1 {
-            background: url('/@/assets//images//company//dust//tip-bg1-1.png');
-            &::after {
-              content: '';
-              width: 25px;
-              height: 25px;
-              position: absolute;
-              left: 13px;
-              top: 7px;
-              background: url('/@/assets//images//company//dust//dustCon-icon.png');
-            }
-          }
-          .bottom-item-box-2 {
-            background: url('/@/assets//images//company//dust//tip-bg1-2.png');
-            &::after {
-              content: '';
-              width: 25px;
-              height: 25px;
-              position: absolute;
-              left: 12px;
-              top: 6px;
-              background: url('/@/assets//images//company//dust//respirableDustCon-icon.png');
-            }
-          }
-          .bottom-item-box-3 {
-            background: url('/@/assets//images//company//dust//tip-bg1-1.png');
-            &::after {
-              content: '';
-              width: 28px;
-              height: 22px;
-              position: absolute;
-              left: 10px;
-              top: 7px;
-              background: url('/@/assets//images//company//dust//SiO2Content-icon.png');
-            }
-          }
-          .bottom-item-box-4 {
-            background: url('/@/assets//images//company//dust//tip-bg1-2.png');
-            &::after {
-              content: '';
-              width: 26px;
-              height: 20px;
-              position: absolute;
-              left: 11px;
-              top: 8px;
-              background: url('/@/assets//images//company//dust//respirableDustRatio-icon.png');
-            }
-          }
-        }
-      }
-    }
-  }
-  .dots-class {
-    width: 8px;
-  }
-  ::v-deep .slick-dots-left {
-    left: 0 !important;
-  }
-  ::v-deep .zxm-select-single:not(.zxm-select-customize-input) .zxm-select-selector {
-    height: 24px;
-  }
-
-  ::v-deep .zxm-select-single:not(.zxm-select-customize-input) .zxm-select-selector .zxm-select-selection-search-input {
-    height: 24px;
-  }
-
-  ::v-deep .zxm-select-selection-placeholder {
-    color: #fff !important;
-    line-height: 22px !important;
-  }
-
-  ::v-deep .zxm-select-single:not(.zxm-select-customize-input) .zxm-select-selector::after {
-    line-height: 24px;
-  }
-
-  ::v-deep .zxm-select:not(.zxm-select-customize-input) .zxm-select-selector {
-    background-color: transparent;
-    border-top: 0px;
-    border-bottom: 0px;
-    border-left: 2px solid;
-    border-right: 2px solid;
-    border-image: linear-gradient(to bottom, transparent, rgba(49, 184, 255, 1), transparent) 1 1 1;
-  }
-
-  ::v-deep .zxm-select-arrow {
-    color: #fff !important;
-  }
-
-  ::v-deep .zxm-select-selection-item {
-    color: #fff !important;
-  }
-
-  ::v-deep .zxm-select-single .zxm-select-selector .zxm-select-selection-item {
-    line-height: 24px !important;
-  }
-</style>

+ 0 - 47
src/views/vent/home/configurable/components/preset/PermissionSet.vue

@@ -1,47 +0,0 @@
-<template>
-  <div class="permission-set">
-    <basicBorder title="安全主管【权限配置】" color-v="orange" :width-v="174">
-      <a-checkbox-group v-model:value="value" name="checkboxgroup" :options="plainOptions" />
-    </basicBorder>
-
-  </div>
-</template>
-
-<script setup lang="ts">
-import { ref } from 'vue'
-import basicBorder from '../basicBorder.vue'
-
-let value = ref<any[]>([])
-let plainOptions = ref<any[]>([
-  { label: '一张图查看', value: '1' },
-  { label: '报警确认处理', value: '2' },
-  { label: '报警解除', value: '3' },
-  { label: '视频调取查看', value: '4' },
-  { label: '设备状态查看', value: '5' },
-  { label: '设备参数配置', value: '6' },
-  { label: '设备重启', value: '7' },
-  { label: '联动规则编辑', value: '8' },
-  { label: '联动规则查看', value: '9' },
-  { label: '联动日志查看', value: '10' },
-  { label: '用户管理', value: '11' },
-  { label: '角色权限管理', value: '12' },
-])
-</script>
-
-<style lang="less" scoped>
-.permission-set {
-  position: relative;
-  width: 100%;
-  height: 100%;
-  padding: 15px;
-  box-sizing: border-box;
- 
-}
-:deep(.zxm-checkbox-group-item){
-    width: 50% !important;
-    margin: 0px 0px 15px 0px !important;
-    padding: 0px 15px !important;
-      background: linear-gradient(to right, #134c77, transparent) !important;
-      color: #fff !important;
-  }
-</style>

+ 0 - 184
src/views/vent/home/configurable/components/preset/SearchTable.vue

@@ -1,184 +0,0 @@
-<template>
-  <div class="search-table">
-    <div class="search-area">
-      <a-input v-model:value="searchWarn" placeholder="搜索报警" size="small" />
-      <div class="search-btn">
-        <div class="btn-item">筛选</div>
-      </div>
-    </div>
-    <div class="content-area">
-      <div class="content-title">
-        <div class="title-item" v-for="(item, index) in titleList" :key="index">{{ item.label }}</div>
-      </div>
-      <div class="table-content">
-        <div class="content-item" v-for="(item, index) in tableData" :key="index">
-          <div class="item-text">{{ item.time }}</div>
-          <div class="item-text">{{ item.address }}
-          </div>
-          <div class="item-text item-text1">{{ item.grade }}</div>
-          <div class="item-text item-text2">{{ item.status }}</div>
-          <div class="item-text">
-            <span class="text-look">确认</span>
-            <span class="text-look">详情</span>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { ref } from 'vue'
-
-let searchWarn = ref('')
-let titleList = ref<any[]>([
-  { label: '时间', value: '1' },
-  { label: '位置', value: '2' },
-  { label: '级别', value: '3' },
-  { label: '状态', value: '4' },
-  { label: '操作', value: '5' },
-])
-let tableData = ref<any[]>([
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-])
-</script>
-
-<style lang="less" scoped>
-@import '/@/design/theme.less';
-
-@{theme-deepblue} {
-  .search-table {}
-}
-
-.search-table {
-  --image-box-bg1: url('@/assets/images/home-container/configurable/hsq/2-6.png');
-  --image-box-bg2: url('@/assets/images/home-container/configurable/hsq/2-24.png');
-  position: relative;
-  width: 100%;
-  height: 100%;
-  padding: 15px;
-  box-sizing: border-box;
-}
-
-.search-area {
-  height: 42px;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 5px;
-}
-
-.search-btn {
-  width: 85px;
-  height: 30px;
-  border: 1px solid #01fefc;
-  border-radius: 4px;
-  padding: 3px;
-  cursor: pointer;
-}
-
-.btn-item {
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  width: 100%;
-  height: 100%;
-  background-color: rgba(32, 166, 169);
-}
-
-
-.content-area {
-  height: calc(100% - 47px);
-}
-
-.content-title {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  height: 34px;
-  background: var(--image-box-bg2) no-repeat;
-  background-size: 100% 100%;
-  margin-bottom: 6px;
-}
-
-.title-item {
-  display: flex;
-  flex: 1;
-  justify-content: center;
-  align-items: center;
-  color: #01fefc;
-}
-
-.table-content {
-  height: calc(100% - 40px);
-  overflow-y: auto;
-}
-
-.content-item {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  height: 36px;
-
-  &:nth-child(odd) {
-    background-color: #0e3455;
-  }
-
-  &:nth-child(even) {
-    background-color: #114268;
-  }
-}
-
-.item-text {
-  display: flex;
-  flex: 1;
-  justify-content: center;
-  align-items: center;
-}
-
-.item-text1 {
-  color: #fc002a;
-}
-
-.item-text2 {
-  color: orange;
-}
-
-.text-look {
-  padding: 0px 3px;
-  margin: 0px 2px;
-  border-radius: 2px;
-  background-color: #2484bc;
-  cursor: pointer;
-}
-
-.zxm-input {
-  height: 42px;
-  color: #fff;
-  background-color: transparent;
-  border: none;
-  background: var(--image-box-bg1) no-repeat;
-  background-size: 100% 100%;
-}
-
-.zxm-input-sm {
-  padding: 0px 20px;
-}
-::-webkit-scrollbar{
-    display: none;
-  }
-</style>

+ 0 - 174
src/views/vent/home/configurable/components/preset/SelectCs.vue

@@ -1,174 +0,0 @@
-<template>
-  <div class="select-cs">
-    <div class="select-item">
-      <div class="select-item-box">
-        <a-select v-model:value="selectVal" :bordered="false" style="width: 100%">
-          <a-select-option v-for="item in options" :key="item.value" :value="item.value">{{ item.label }}</a-select-option>
-        </a-select>
-      </div>
-      <div class="select-item-box">
-        <span>{{ config.switch1.label[0] }}</span>
-        <a-switch
-          :disabled="config.switch1.disabled"
-          :checked="getFormattedText(devicedata, config.switch1.value, config.switch1.trans)"
-          @update:checked="handlUpdate($event, config.switch1)"
-        />
-        <span>{{ config.switch1.label[1] }}</span>
-      </div>
-    </div>
-    <div class="select-item">
-      <div class="select-item-box1">
-        <span>{{ config.switch2.label[0] }}</span>
-        <a-switch
-          :disabled="config.switch2.disabled"
-          :checked="getFormattedText(devicedata, config.switch2.value, config.switch2.trans)"
-          @update:checked="handlUpdate($event, config.switch2)"
-        />
-      </div>
-      <div class="select-item-box1">
-        <span>{{ config.switch3.label[0] }}</span>
-        <a-switch
-          :disabled="config.switch3.disabled"
-          :checked="getFormattedText(devicedata, config.switch3.value, config.switch3.trans)"
-          @update:checked="handlUpdate($event, config.switch3)"
-        />
-      </div>
-    </div>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import { computed, ref } from 'vue';
-  import { getData, getFormattedText } from '../../hooks/helper';
-  import { deviceControlApi } from '/@/api/vent';
-  import { message } from 'ant-design-vue';
-
-  interface SwitchConfig {
-    /** 提交控制时 启动 状态对应的key */
-    keyOn: string;
-    /** 提交控制时 关闭 状态对应的key */
-    keyOff: string;
-    /** 提交控制时 启动 状态对应的value */
-    valueOn: string;
-    /** 提交控制时 关闭 状态对应的value */
-    valueOff: string;
-    /** 提示文本,按需从数组中依次读取内容 */
-    label: string[];
-    disabled?: boolean;
-    /** 判断该项的默认状态时用到的value,formatter格式 */
-    value: string;
-    /** 如果value不是boolean类型,需要给出trans转换 */
-    trans: any;
-  }
-  interface CSConfig {
-    selector: {
-      label: string;
-      value: string;
-      readFrom: string;
-    };
-    switch1: SwitchConfig;
-    switch2: SwitchConfig;
-    switch3: SwitchConfig;
-  }
-
-  const props = defineProps<{
-    config: CSConfig;
-    devicedata: Record<string, any>;
-  }>();
-
-  const options = computed(() => {
-    const { readFrom, value, label } = props.config.selector;
-    const res = getData(props.devicedata.value, readFrom);
-    return (Array.isArray(res) ? res : [res]).map((item) => {
-      return {
-        label: getFormattedText(item, label),
-        value: getFormattedText(item, value),
-      };
-    });
-  });
-
-  const selectVal = ref(undefined);
-
-  function handlUpdate(checked: boolean, item: SwitchConfig) {
-    deviceControlApi({
-      deviceid: selectVal,
-      paramcode: checked ? item.keyOn : item.keyOff,
-      value: checked ? item.valueOn : item.valueOff,
-    })
-      .then((r) => {
-        if (!r.success) throw r.message || '操作失败';
-        message.success('指令下发成功');
-      })
-      .catch((e) => {
-        message.error(typeof e === 'string' ? e : '指令下发失败');
-      });
-  }
-</script>
-
-<style lang="less" scoped>
-  .select-cs {
-    height: 100%;
-    padding: 5px 15px;
-    box-sizing: border-box;
-    width: 100%;
-    overflow-y: auto;
-
-    .select-item {
-      display: flex;
-      width: 100%;
-      height: calc(50% - 2px);
-
-      &:nth-child(1) {
-        margin-bottom: 2px;
-        padding: 0px 10px;
-        background: url('@/assets/images/vent/homeNew/databg/11.png') no-repeat;
-        background-size: 100% 100%;
-      }
-
-      &:nth-child(2) {
-        margin-top: 2px;
-      }
-
-      .select-item-box {
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        width: 50%;
-        height: 34px;
-        padding-top: 6px;
-        box-sizing: border-box;
-
-        &:nth-child(1) {
-          background: url('@/assets/images/vent/homeNew/databg/bg-line.png') no-repeat right;
-        }
-
-        span {
-          margin: 0px 10px;
-        }
-      }
-
-      .select-item-box1 {
-        display: flex;
-        justify-content: space-between;
-        width: 100%;
-        height: 100%;
-        padding: 10px 20px 0px 20px;
-        box-sizing: border-box;
-        background: url('@/assets/images/vent/homeNew/databg/13.png') no-repeat;
-        background-size: 100% 100%;
-      }
-    }
-
-    ::v-deep .zxm-select-selector {
-      background-color: transparent;
-      height: 28px;
-      padding: 0 10px;
-    }
-
-    ::v-deep .zxm-switch {
-      border-top: 1px solid rgba(45, 187, 255);
-      border-bottom: 1px solid rgba(45, 187, 255);
-      border-right: 1px solid rgba(45, 187, 255);
-    }
-  }
-</style>

+ 0 - 79
src/views/vent/home/configurable/components/preset/StatisticDay.vue

@@ -1,79 +0,0 @@
-<template>
-  <div class="statistic-day">
-    <div class="list-title">今日登录统计</div>
-     <div class="list-content">
-        <basicBorder title="最近登录">
-          <div class="basic-box">
-            <div class="box-item" v-for="(item,index) in list" :key="index">
-              <span style="margin-right: 10px;">{{ `${item.label} : ` }}</span>
-              <span>{{ item.value }}</span>
-            </div>
-          </div>
-        </basicBorder>
-     </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { ref } from 'vue'
-import basicBorder from '../basicBorder.vue'
-
-let list=ref<any[]>([
-  {label:'名称',value:'14:15:33 192.168.1.42'},
-  {label:'名称',value:'14:15:33 192.168.1.42'},
-  {label:'名称',value:'14:15:33 192.168.1.42'},
-  {label:'名称',value:'14:15:33 192.168.1.42'},
-  {label:'名称',value:'14:15:33 192.168.1.42'},
-  {label:'名称',value:'14:15:33 192.168.1.42'},
-])
-</script>
-
-<style lang="less" scoped>
-@import '/@/design/theme.less';
-
-@{theme-deepblue} {
-  .statistic-day {}
-}
-
-.statistic-day {
-  --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-5.png');
-  position: relative;
-  width: 100%;
-  height: 100%;
-  padding: 15px;
-  box-sizing: border-box;
-
-  .list-title {
-    width: 177px;
-    height: 30px;
-    line-height: 22px;
-    padding-left: 16px;
-    color: #01fefc;
-    font-weight: bolder;
-    background: var(--image-box-bg) no-repeat;
-    background-size: 100% 100%;
-    margin-bottom: 5px;
-  }
-   .list-content {
-    width: 100%;
-    height: calc(100% - 35px);
-  }
-  .basic-box{
-    height: 100%;
-    overflow-y: auto;
-  }
-  .box-item{
-    display: flex;
-    // justify-content: space-between;
-    align-items: center;
-    height: 26px;
-    margin-bottom: 6px;
-    padding: 0px 10px;
-    box-sizing: border-box;
-     background: linear-gradient(to right, #134c77, transparent);
-  }
-   ::-webkit-scrollbar {
-    display: none;
-  }
-}
-</style>

+ 0 - 229
src/views/vent/home/configurable/components/preset/UserList.vue

@@ -1,229 +0,0 @@
-<template>
-  <div class="user-list">
-    <div class="list-title">
-      <div class="title-l">用户列表</div>
-      <div class="title-r">
-        <div class="basic-btn">新增用户</div>
-      </div>
-    </div>
-    <div class="list-content">
-      <div class="search-area">
-        <a-input v-model:value="searchData" placeholder="搜索" size="small" />
-        <div class="search-btn">
-          <div class="basic-btn">筛选</div>
-        </div>
-      </div>
-      <div class="content-area">
-        <div class="content-title">
-          <div class="title-item" v-for="(item, index) in titleList" :key="index">{{ item.label }}</div>
-        </div>
-        <div class="table-content">
-          <div class="content-item" v-for="(item, index) in tableData" :key="index">
-            <div class="item-text">{{ item.id}}</div>
-            <div class="item-text">{{ item.address }}
-            </div>
-            <div class="item-text item-text1">{{ item.grade }}</div>
-            <div class="item-text item-text2">{{ item.status }}</div>
-            <div class="item-text">
-              <span class="text-look">确认</span>
-              <span class="text-look">详情</span>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { ref } from 'vue';
-
-let searchData = ref('')
-let titleList = ref<any[]>([
-  { label: 'ID', value: '1' },
-  { label: '用户名', value: '2' },
-  { label: '姓名', value: '3' },
-  { label: '角色', value: '4' },
-  { label: '部门', value: '5' },
-  { label: '电话', value: '5' },
-  { label: '状态', value: '5' },
-  { label: '操作', value: '5' },
-])
-let tableData = ref<any[]>([
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-])
-</script>
-
-<style lang="less" scoped>
-@import '/@/design/theme.less';
-
-@{theme-deepblue} {
-  .user-list {}
-}
-
-.user-list {
-  --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-5.png');
-  --image-box-bg1: url('@/assets/images/home-container/configurable/hsq/2-6.png');
-  --image-box-bg2: url('@/assets/images/home-container/configurable/hsq/2-24.png');
-  position: relative;
-  width: 100%;
-  height: 100%;
-  padding: 15px;
-  box-sizing: border-box;
-
-  .list-title {
-    display: flex;
-    justify-content: space-between;
-    width: 100%;
-    height: 30px;
-    line-height: 22px;
-    margin-bottom: 10px;
-  }
-
-  .title-l {
-    width: 177px;
-    height: 100%;
-    color: #01fefc;
-    font-weight: bolder;
-    padding-left: 16px;
-    background: var(--image-box-bg) no-repeat;
-    background-size: 100% 100%;
-  }
-
-  .title-r {
-    width: 85px;
-    height: 30px;
-    border: 1px solid #01fefc;
-    border-radius: 4px;
-    padding: 3px;
-    cursor: pointer;
-    // margin-right: 16px;
-  }
-
-  .basic-btn {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    width: 100%;
-    height: 100%;
-    background-color: rgba(32, 166, 169);
-  }
-
-  .list-content {
-    height: calc(100% - 40px);
-  }
-
-  .search-area {
-    height: 42px;
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    margin-bottom: 5px;
-  }
-
-  .search-btn {
-    width: 85px;
-    height: 30px;
-    border: 1px solid #01fefc;
-    border-radius: 4px;
-    padding: 3px;
-    cursor: pointer;
-  }
-
-  .content-area {
-    height: calc(100% - 47px);
-  }
-
-  .content-title {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    height: 34px;
-    background: var(--image-box-bg2) no-repeat;
-    background-size: 100% 100%;
-    margin-bottom: 6px;
-  }
-
-  .title-item {
-    display: flex;
-    flex: 1;
-    justify-content: center;
-    align-items: center;
-    color: #01fefc;
-  }
-
-  .table-content {
-    height: calc(100% - 40px);
-    overflow-y: auto;
-  }
-
-  .content-item {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    height: 36px;
-
-    &:nth-child(odd) {
-      background-color: #0e3455;
-    }
-
-    &:nth-child(even) {
-      background-color: #114268;
-    }
-  }
-
-  .item-text {
-    display: flex;
-    flex: 1;
-    justify-content: center;
-    align-items: center;
-  }
-
-  .item-text1 {
-    color: #fc002a;
-  }
-
-  .item-text2 {
-    color: orange;
-  }
-
-  .text-look {
-    padding: 0px 3px;
-    margin: 0px 2px;
-    border-radius: 2px;
-    background-color: #2484bc;
-    cursor: pointer;
-  }
-
-  .zxm-input {
-    height: 42px;
-    color: #fff;
-    background-color: transparent;
-    border: none;
-    background: var(--image-box-bg1) no-repeat;
-    background-size: 100% 100%;
-  }
-
-  .zxm-input-sm {
-    padding: 0px 20px;
-  }
-
-  ::-webkit-scrollbar {
-    display: none;
-  }
-}
-</style>

+ 0 - 158
src/views/vent/home/configurable/components/preset/buttonList.vue

@@ -1,158 +0,0 @@
-<template>
-  <div ref="buttonContainer">
-    <div :class="`button-block_${type}`" v-if="type === 'A'">
-      <div :class="`button-item_${type}`" v-for="button in buttonList" :key="button.value">
-        <div v-if="button.isShowInput" :class="`input-area_${type}`">
-          <a-input v-model:value="button.inputValue" :placeholder="button.inputContent" />
-          <a-button type="primary" @click="handleData(button)">{{ button.label }}</a-button>
-        </div>
-        <div v-else>
-          <a-button type="primary" @click="handleData(button)">{{ button.label }}</a-button>
-        </div>
-      </div>
-    </div>
-    <div :class="`button-block_${type}`" v-if="type === 'B'">
-      <!-- 遍历分组后的按钮组 -->
-      <div :class="`button-group_${type}`" v-for="(group, groupIndex) in groupedButtons" :key="groupIndex">
-        <!-- 遍历每组中的按钮 -->
-        <div :class="`button-item_${type}`" v-for="button in group" :key="button.value">
-          <a-button type="primary" @click="handleData(button)">{{ button.label }}</a-button>
-        </div>
-      </div>
-    </div>
-  </div>
-  <ConfirmModal v-model:visible="modalVisible" @ok="handleConfirm" @cancel="handleCancel" class="btn-confirm-modal">
-    <SvgIcon class="icon" size="34" name="warning-icon-gas" />
-    <span> {{ currentButton?.content }} </span>
-    <inputPassword v-model:value="password" placeholder="请输入密码校验(必填)" class="pswInput" />
-    <div class="warn-text">
-      <span>{{ inputWarn }}</span>
-    </div>
-  </ConfirmModal>
-</template>
-
-<script lang="ts" setup>
-  defineOptions({ name: 'ButtonList' });
-  import ConfirmModal from '/@/views/vent/comment/components/modal/confirmModal.vue';
-  import { computed, ref, inject } from 'vue';
-  import { InputPassword } from 'ant-design-vue';
-  // 定义组件属性
-  const props = defineProps<{
-    type: string;
-    config: any;
-    buttonList: ButtonItem[];
-  }>();
-  // 定义按钮项的类型
-  interface ButtonItem {
-    isShowInput: boolean;
-    inputContent: string;
-    inputValue: string | number;
-    value: string | number;
-    label: string;
-    content: string;
-    // 可以根据实际需求添加其他属性
-  }
-  const password = ref('');
-  const inputWarn = ref('密码错误请重新输入');
-  const modalVisible = ref(false);
-  const currentButton = ref<ButtonItem | null>(null); // 记录当前点击的按钮
-
-  const groupedButtons = computed<ButtonItem[][]>(() => {
-    if (props.type !== 'B') return [];
-    const groups: ButtonItem[][] = [];
-    for (let i = 0; i < props.buttonList.length; i += 2) {
-      groups.push(props.buttonList.slice(i, i + 2));
-    }
-    return groups;
-  });
-  // 注入祖父组件提供的处理函数
-  const handleButtonConfirm = inject<(button: ButtonItem) => void>(
-    'handleButtonConfirm',
-    () => console.warn('未提供handleButtonConfirm函数') // 默认值,避免报错
-  );
-  const handleData = (button: ButtonItem) => {
-    modalVisible.value = !modalVisible.value;
-    currentButton.value = button;
-  };
-  const handleConfirm = () => {
-    if (!currentButton.value) return;
-    password.value = '';
-    inputWarn.value = '';
-    handleButtonConfirm(currentButton.value);
-  };
-  const handleCancel = () => {
-    password.value = '';
-    inputWarn.value = '';
-  };
-</script>
-
-<style lang="less">
-  .button-block_A {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    padding: 0 15px;
-    flex-wrap: wrap;
-    margin-bottom: 20px;
-    .input-area_A {
-      height: 50px;
-      width: 250px;
-      display: flex;
-      background: url('@/assets/images/vent/homeNew/databg/11.png') no-repeat;
-      background-size: 100% 100%;
-      align-items: center;
-      justify-content: space-between;
-      margin: 5px 0;
-      padding: 3px 18px 3px 13px;
-      input {
-        height: 23px;
-        width: 120px;
-        background-color: #09172c;
-        border: solid 1px #1f7394;
-        color: #fff;
-      }
-      button {
-        height: 24px;
-        width: 50px;
-        padding: 0 10px;
-      }
-    }
-  }
-  .button-block_B {
-    display: flex;
-    justify-content: space-between;
-    padding: 0 10px 10px 10px;
-    .button-group_B {
-      background: url('/@/assets/images/home-container/configurable/minehome/button-bg-a.png') no-repeat;
-      background-size: 100% 100%;
-      width: 130px;
-      height: 100px;
-      display: flex;
-      align-items: center;
-      flex-wrap: wrap;
-      justify-content: center;
-      padding: 10px 0;
-    }
-  }
-  .btn-confirm-modal {
-    .zxm-modal-content {
-      height: 330px !important;
-      background-size: 100% 100%;
-      .zxm-modal-body {
-        height: 260px;
-        padding-top: 85px;
-      }
-      .zxm-modal-footer {
-        text-align: center;
-      }
-    }
-  }
-  .pswInput {
-    margin-top: 55px;
-    width: 80%;
-  }
-  .warn-text {
-    color: red;
-    font-size: 15px;
-  }
-</style>

+ 0 - 59
src/views/vent/home/configurable/components/preset/cameraModal.vue

@@ -1,59 +0,0 @@
-<template>
-  <div class="camera-modal">
-    <div v-if="renderPlayer" ref="playerRef" style="
-     display: flex;
-      width: 100%;
-      height: 100%;
-      overflow-y: auto;
-      pointer-events: none;
-    ">
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { onMounted, onUnmounted, ref, reactive, onBeforeUnmount } from 'vue';
-import { useCamera } from '/@/hooks/system/useCamera';
-
-let props = defineProps({
-  deviceId: {
-    type: String,
-    default: ''
-  },
-});
-const { getCamera, removeCamera } = useCamera();
-const playerRef = ref();
-const renderPlayer = ref(true);
-
-onMounted(async () => {
-  await getCamera(props.deviceId, playerRef, renderPlayer);
-});
-
-onBeforeUnmount(() => {
-  removeCamera(playerRef);
-});
-</script>
-
-<style lang="less" scoped>
-:deep(#LivePlayerBox) {
-  display: flex;
-  flex-direction: row;
-  justify-content: flex-start;
-  flex-wrap: wrap;
-  pointer-events: none;
-
-  .liveVideo {
-    width: 525px !important;
-    height: 312px !important;
-    padding: 15px !important;
-    align-self: auto !important;
-    margin: 10px 8px !important;
-    background-size: 100% 100% !important;
-  }
-
-  .video-parent {
-    pointer-events: auto !important;
-    align-self: auto !important;
-  }
-}
-</style>

+ 0 - 262
src/views/vent/home/configurable/components/preset/cardList.vue

@@ -1,262 +0,0 @@
-<template>
-  <div class="card-list">
-    <div class="list-box">
-      <div class="box-item-title">{{ cardData.title }}</div>
-      <div class="box-item-content">
-        <div class="content-area">
-          <img src="@/assets/images/home-container/configurable/electroChamper/2-6.png" alt="">
-          <div class="item-text">{{ cardData.areaText }}</div>
-          <div class="item-val">{{ cardData.areaVal }}</div>
-        </div>
-         <div class="content-module">
-          <img src="@/assets/images/home-container/configurable/electroChamper/2-8.png" alt="">
-          <div class="item-text">{{ cardData.moduleText }}</div>
-          <div class="item-val">{{ cardData.moduleVal }}</div>
-        </div>
-        <div class="content-status">
-          <img src="@/assets/images/home-container/configurable/electroChamper/2-6.png" alt="">
-          <div class="item-text">{{ cardData.statusText }}</div>
-          <div class="item-val">{{ cardData.statusVal }}</div>
-        </div>
-        <div class="content-card-box">
-          <div class="card-box-item">
-            <div class="item-common item-green">
-              <div class="common-text">{{ cardData.phoneText }}</div>
-              <div class="common-val val-green">{{ cardData.phoneVal }}</div>
-            </div>
-            <div class="item-common item-blue">
-              <div class="common-text">{{ cardData.tempNowText }}</div>
-              <div class="common-val val-blue">{{ `${cardData.tempNowVal}℃` }}</div>
-            </div>
-            <div class="item-common item-green">
-              <div class="common-text">{{ cardData.tempOpenText }}</div>
-              <div class="common-val val-green">{{ `${cardData.tempOpenVal}℃` }}</div>
-            </div>
-            <div class="item-common item-blue">
-              <div class="common-text">{{ cardData.timeText }}</div>
-              <div class="common-val val-blue">{{ `${cardData.timeVal}s` }}</div>
-            </div>
-          </div>
-          <div class="card-box-item">
-            <div class="item-common item-blue item-switch">
-              <div>开启</div>
-              <a-switch v-model:checked="checked" size="small" />
-              <div>关闭</div>
-            </div>
-            <div class="item-common item-green">
-              <div class="common-text">{{ cardData.tempMaxText }}</div>
-              <div class="common-val val-green">{{ `${cardData.tempMaxVal}℃` }}</div>
-            </div>
-            <div class="item-common item-blue">
-              <div class="common-text">{{ cardData.tempCloseText }}</div>
-              <div class="common-val val-blue">{{ `${cardData.tempCloseVal}℃` }}</div>
-            </div>
-            <div class="item-common item-green">
-              <div class="common-text">{{ cardData.time3Text }}</div>
-              <div class="common-val val-green">{{ `${cardData.time3Val}s` }}</div>
-            </div>
-          </div>
-        </div>
-      </div>
-
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { ref,watchEffect } from 'vue'
-
-let props=defineProps({
-  cardData:{
-    type:Object,
-    default:()=>{
-      return {}
-    }
-  }
-})
-//设备开关状态
-let checked = ref(true)
-watchEffect(()=>{
-  console.log(props.cardData,'888999000')
-  checked.value=props.cardData.deviceSTAT
-})
-</script>
-
-<style lang="less" scoped>
-@import '/@/design/theme.less';
-
-@{theme-deepblue} {
-  .card-list {
-    --image-title: url('@/assets/images/themify/deepblue/home-container/configurable/electroChamper/2-3.png');
-    --image-list-box: url('@/assets/images/themify/deepblue/home-container/configurable/electroChamper/2-4.png');
-    --image-content-area: url('@/assets/images/themify/deepblue/home-container/configurable/electroChamper/2-5.png');
-    --image-content-status: url('@/assets/images/themify/deepblue/home-container/configurable/electroChamper/2-7.png');
-    --image-blue: url('@/assets/images/themify/deepblue/home-container/configurable/electroChamper/2-9.png');
-    --image-green: url('@/assets/images/themify/deepblue/home-container/configurable/electroChamper/2-10.png');
-  }
-}
-
-.card-list {
-  --image-title: url('@/assets/images/home-container/configurable/electroChamper/2-3.png');
-  --image-list-box: url('@/assets/images/home-container/configurable/electroChamper/2-4.png');
-  --image-content-area: url('@/assets/images/home-container/configurable/electroChamper/2-5.png');
-  --image-content-status: url('@/assets/images/home-container/configurable/electroChamper/2-7.png');
-  --image-blue: url('@/assets/images/home-container/configurable/electroChamper/2-9.png');
-  --image-green: url('@/assets/images/home-container/configurable/electroChamper/2-10.png');
-  position: relative;
-  width: 100%;
-  height: 100%;
-  padding: 5px 15px 0px 15px;
-  box-sizing: border-box;
-  overflow-y: auto;
-
-  .list-box {
-    width: 100%;
-    // height: calc(50% - 5px);
-    // margin-bottom: 5px;
-    height: 100%;
-    background: var(--image-list-box) no-repeat;
-    background-size: 100% 100%;
-
-    .box-item-title {
-      width: 100%;
-      height: 38px;
-      line-height: 38px;
-      text-align: center;
-      background: var(--image-title) no-repeat;
-      background-size: 100% 100%;
-    }
-
-    .box-item-content {
-      display: flex;
-      flex-direction: column;
-      justify-content: space-around;
-      width: 100%;
-      height: calc(100% - 38px);
-      padding: 0px 8px;
-      box-sizing: border-box;
-      // font-size: 12px;
-
-      .content-area {
-        position: relative;
-        width: 100%;
-        height: 38px;
-        line-height: 38px;
-        background: var(--image-content-area) no-repeat;
-        background-size: 100% 100%;
-      }
-        .content-module {
-        position: relative;
-        width: 100%;
-        height: 38px;
-        line-height: 38px;
-        background: var(--image-content-status) no-repeat;
-        background-size: 100% 100%;
-      }
-
-      .content-status {
-        position: relative;
-        width: 100%;
-        height: 38px;
-        line-height: 38px;
-        background: var(--image-content-area) no-repeat;
-        background-size: 100% 100%;
-      }
-
-      .content-card-box {
-        display: flex;
-        justify-content: space-between;
-
-        .card-box-item {
-          width: calc(50% - 5px);
-          height: 100%;
-
-          .item-common {
-            position: relative;
-            width: 100%;
-            height: 38px;
-            margin-bottom: 16px;
-          }
-
-          .item-green {
-            background: var(--image-green) no-repeat;
-            background-size: 100% 100%;
-          }
-
-          .item-blue {
-            background: var(--image-blue) no-repeat;
-            background-size: 100% 100%;
-          }
-
-          .item-switch {
-            display: flex;
-            justify-content: center;
-            align-items: center;
-          }
-
-          .common-text {
-            position: absolute;
-            left: 10px;
-            top: 50%;
-            transform: translate(0, -50%);
-            // font-size: 12px;
-          }
-
-          .common-val {
-            position: absolute;
-            right: 15px;
-            top: 50%;
-            transform: translate(0, -50%);
-            font-size: 12px;
-          }
-
-          .val-green {
-            font-family: 'douyuFont';
-            color: #2af7d7;
-          }
-
-          .val-blue {
-            font-family: 'douyuFont';
-            color: #91e0ff;
-          }
-        }
-      }
-
-      img {
-        position: absolute;
-        left: 12px;
-        top: 50%;
-        transform: translate(0, -50%);
-        width: 19px;
-        height: 17px;
-      }
-
-      .item-text {
-        position: absolute;
-        left: 52px;
-        top: 50%;
-        transform: translate(0, -50%);
-        // font-size: 12px;
-
-      }
-
-      .item-val {
-        position: absolute;
-        right: 16px;
-        top: 50%;
-        transform: translate(0, -50%);
-        // font-size: 12px;
-      }
-    }
-  }
-
-  ::v-deep .zxm-switch-small {
-    min-width: 36px;
-  }
-
-  ::v-deep .zxm-switch {
-    margin: 0px 5px;
-  }
-
-}
-</style>

+ 0 - 109
src/views/vent/home/configurable/components/preset/generalList.vue

@@ -1,109 +0,0 @@
-<template>
-  <div class="general-list">
-    <div class="general-content-box" v-for="(item, index) in generalData" :key="index">
-      <div class="general-icon" :class="index % 2 == 0 ? 'icon-blue' : 'icon-green'"></div>
-      <div class="general-label">{{ item.areaName }}</div>
-      <div class="general-status" :class="index % 2 == 0 ? 'text-blue' : 'text-green'">{{ item.CORealtime || '-' }}</div>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { ref } from 'vue'
-
-let props = defineProps({
-  generalData: {
-    type: Array,
-    default: () => {
-      return []
-    }
-  }
-})
-
-</script>
-
-<style lang="less" scoped>
-@import '/@/design/theme.less';
-
-@{theme-deepblue} {
-  .card-list {
-    --image-bg-green: url('@/assets/images/themify/deepblue/home-container/configurable/electroChamper/3-3.png');
-    --image-bg-blue: url('@/assets/images/themify/deepblue/home-container/configurable/electroChamper/3-4.png');
-    --image-bg-green-icon: url('@/assets/images/themify/deepblue/home-container/configurable/electroChamper/3-3.png');
-    --image-bg-blue-icon: url('@/assets/images/themify/deepblue/home-container/configurable/electroChamper/3-2.png');
-
-  }
-}
-
-.general-list {
-  --image-bg-green: url('@/assets/images/home-container/configurable/electroChamper/3-3.png');
-  --image-bg-blue: url('@/assets/images/home-container/configurable/electroChamper/3-1.png');
-  --image-bg-green-icon: url('@/assets/images/home-container/configurable/electroChamper/3-4.png');
-  --image-bg-blue-icon: url('@/assets/images/home-container/configurable/electroChamper/3-2.png');
-  width: 100%;
-  height: 100%;
-  padding: 10px 15px;
-  box-sizing: border-box;
-
-  .general-content-box {
-    position: relative;
-    width: 100%;
-    height: 36px;
-    margin-bottom: 10px;
-    display: flex;
-    align-items: center;
-
-    &:nth-child(odd) {
-      background: var(--image-bg-blue) no-repeat;
-      background-size: 100% 100%;
-    }
-
-    &:nth-child(even) {
-      background: var(--image-bg-green) no-repeat;
-      background-size: 100% 100%;
-    }
-
-    .general-label {
-      position: absolute;
-      left: 60px;
-    }
-
-    .general-status {
-      position: absolute;
-      right: 98px;
-    }
-
-  }
-
-  .general-icon {
-    position: absolute;
-    width: 22px;
-    height: 22px;
-    left: 12px;
-    top: 50%;
-    transform: translate(0, -50%);
-  }
-
-  .icon-green {
-    background: var(--image-bg-green-icon) no-repeat;
-    background-size: 100% 100%;
-  }
-
-  .icon-blue {
-    background: var(--image-bg-blue-icon) no-repeat;
-    background-size: 100% 100%;
-  }
-
-  .text-green {
-    font-size: 12px;
-    font-family: 'douyuFont';
-    color: #2af7d7;
-  }
-
-  .text-blue {
-    font-size: 12px;
-    font-family: 'douyuFont';
-    color: #91e0ff;
-  }
-}
-</style>

+ 0 - 74
src/views/vent/home/configurable/components/preset/radioLabel.vue

@@ -1,74 +0,0 @@
-<template>
-  <div ref="radioContainer">
-    <div :class="`radio-block_${type}`">
-      <div :class="`left-label_${type}`">
-        <span>{{ props.config.leftLabel }}</span>
-      </div>
-      <div :class="`left-label_${type}`" v-if="props.config.isShowRadio">
-        <a-radio-group v-model:value="defaultValue" :options="options" @change="handleChange" />
-      </div>
-      <div :class="`right-label_${type}`" v-else>
-        <span>{{ props.config.rightLbel }}</span>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  defineOptions({ name: 'PresetRadio' });
-
-  import { onMounted, ref, inject } from 'vue';
-  import { RadioGroupProps } from 'ant-design-vue';
-  // 定义组件属性
-  const props = defineProps<{
-    type: any;
-    config: any;
-  }>();
-
-  // 定义选项数据
-  let options: RadioGroupProps['options'] = [];
-  // 定义各个单选组的默认值
-  const defaultValue = ref('');
-  // 组件挂载时初始化一次
-  onMounted(() => {
-    initData();
-    // 设置默认选中项
-  });
-  // 初始化数据
-  const initData = () => {
-    if (props.config) {
-      // 从数据中获取第一个选择器的选项
-      options = props.config.options || [];
-      // 从数据中获取第二个选择器的选项
-      defaultValue.value = props.config.defaultValue || '';
-    }
-  };
-  // 注入祖父组件提供的处理函数(关键:跨层级获取)
-  const handleRadioChange = inject<(value: string) => void>(
-    'handleRadioChange', // 注入的key,需与祖父组件保持一致
-    () => console.warn('未提供handleRadioChange函数') // 默认值,避免报错
-  );
-
-  // 处理单选框变化,触发原生DOM事件
-  const handleChange = (value: string) => {
-    handleRadioChange(value);
-  };
-</script>
-
-<style lang="less" scoped>
-  .radio-block_A {
-    height: 50px;
-    display: flex;
-    justify-content: space-between;
-    background: url('@/assets/images/vent/homeNew/databg/11.png') no-repeat;
-    background-size: 100% 100%;
-    align-items: center;
-    padding: 0 15px 0 25px;
-    margin: 10px 8px 5px 8px;
-    .right-label_A {
-      margin-right: 10px;
-      font-family: 'douyuFont';
-      font-size: 12px;
-    }
-  }
-</style>

+ 1 - 695
src/views/vent/home/configurable/configurable.api.ts

@@ -4,6 +4,7 @@ import { get } from '../billboard/utils';
 import { useGlobSetting } from '/@/hooks/setting';
 import { ref, reactive } from 'vue';
 import _ from 'lodash';
+import LongList from './components/preset/LongList.vue';
 
 enum Api {
   list = '/safety/ventanalyDevice/homedata2',
@@ -42,698 +43,3 @@ export const getMonitorAndAlertBelt = (params) => defHttp.post({ url: Api.monito
 // 这会导致相同的请求被同时发送多次。
 const cache = new Map<string, Promise<any>>();
 
-/**
- * 列表接口,5.5专用,和6.0的getHomeData基本一致
- * @param params
- */
-export const list = (params) => {
-  const key = `${Api.list}?${JSON.stringify(params)}`;
-  if (!cache.has(key)) {
-    cache.set(
-      key,
-      defHttp.post({ url: Api.list, params }).finally(() => {
-        cache.delete(key);
-      })
-    );
-  }
-  return (cache.get(key) as Promise<any>).then((res) => {
-    if (res.fanmain) {
-      // 处理频率字段,为了兼容旧版保留,现配置项已支持一级动态字段
-      res.fanmain.forEach((e) => {
-        if (e.readData.Fan2StartStatus === '1') {
-          e.current = '二号';
-          e.readData.FanFreqHz = e.readData.Fan2FreqHz;
-        } else {
-          e.current = '一号';
-          e.readData.FanFreqHz = e.readData.Fan1FreqHz;
-        }
-      });
-    }
-    if (res.fanlocal) {
-      res.fanlocal.forEach((e) => {
-        e.chartData = [
-          {
-            x: '吸风量',
-            yRealtime: e.readData.windQuantity1,
-            yMock: floor(parseFloat(e.inletAirVolume_merge) * random(0.98, 1, false), 2),
-            y: e.inletAirVolume_merge,
-          },
-          {
-            x: '供风量',
-            yRealtime: e.readData.windQuantity2,
-            yMock: floor(parseFloat(e.ductOutletAirVolume_merge) * random(0.98, 1, false), 2),
-            y: e.ductOutletAirVolume_merge,
-          },
-        ];
-        if (e.readData.Fan2StartStatus === '1') {
-          e.current = '二号';
-          e.readData.FanfHz = e.readData.Fan2fHz;
-        } else {
-          e.current = '一号';
-          e.readData.FanfHz = e.readData.Fan1fHz;
-        }
-      });
-    }
-    if (res.sys_majorpath) {
-      res.sys_majorpath.forEach((e) => {
-        const { drag_1, drag_2, drag_3, drag_total } = e.majorpath;
-        const { fy_merge = { value: '1' } } = e.readData;
-        const drag_merge = parseInt(fy_merge.value);
-        // const m3_merge = parseInt(retM3_merge.value);
-
-        e.piechart = [
-          { val: drag_1, valMock: floor((drag_1 / drag_total) * drag_merge), label: '进风区' },
-          { val: drag_2, valMock: floor((drag_2 / drag_total) * drag_merge), label: '用风区' },
-          { val: drag_3, valMock: floor((drag_3 / drag_total) * drag_merge), label: '回风区' },
-        ];
-        e.readData.dengjikong_merge = get(res, 'midinfo[0].sysinfo.equalarea');
-        e.readData.fy_merge_int = drag_merge;
-        // e.dengjikong_merge = floor((1.19 * (m3_merge / 60)) / Math.sqrt(drag_merge), 2);
-      });
-    }
-    if (res.sys_surface_caimei) {
-      res.sys_surface_caimei.forEach((e) => {
-        if (isArray(e.history)) {
-          e.history = slice(e.history, e.history.length - 30, e.history.length);
-        }
-        if (isArray(e.history_report)) {
-          e.history_report = slice(e.history_report, e.history_report.length - 30, e.history_report.length);
-        }
-      });
-    }
-    if (res.device_arr) {
-      res.device_arr = Object.values(res.device);
-    }
-    if (res.sys_wind) {
-      res.sys_wind.forEach((e) => {
-        if (e.readData.m3) {
-          e.readData.m3 = e.readData.m3.replace('-', '');
-        }
-        if (e.readData.va) {
-          e.readData.va = e.readData.va.replace('-', '');
-        }
-      });
-    }
-    if (res.windrect) {
-      res.windrect.forEach((e) => {
-        if (e.readData.m3) {
-          e.readData.m3 = e.readData.m3.replace('-', '');
-        }
-        if (e.readData.va) {
-          e.readData.va = e.readData.va.replace('-', '');
-        }
-      });
-    }
-    if (res.safetymonitor) {
-      const { sysOrgCode } = useGlobSetting();
-      // 沙坪
-      if (sysOrgCode === 'jsnyspmy') {
-        res.safetymonitor = _.sortBy(res.safetymonitor, (e) => {
-          const map = new Map([
-            ['1960160466651189249', 1],
-            ['1960160465543892994', 2],
-            ['1960160465376120833', 3],
-            ['1960160466168844289', 4],
-            ['1960160465736830977', 5],
-            ['1960160466026237954', 6],
-            ['1960160407146598402', 7],
-          ]);
-
-          const inx = map.get(e.deviceID) || 9999;
-
-          return inx;
-        });
-      }
-    }
-
-    return res;
-  });
-};
-
-export const getHomeData = (params) => {
-  const key = `${Api.getHomeData}?${JSON.stringify(params)}`;
-  if (!cache.has(key)) {
-    cache.set(
-      key,
-      defHttp.post({ url: Api.getHomeData, params }).finally(() => {
-        cache.delete(key);
-      })
-    );
-  }
-  return (cache.get(key) as Promise<any>).then((res) => {
-    res.fanmain.forEach((e) => {
-      if (e.readData.Fan2StartStatus === '1') {
-        e.current = '二号';
-        e.readData.FanFreqHz = e.readData.Fan2FreqHz;
-      } else {
-        e.current = '一号';
-        e.readData.FanFreqHz = e.readData.Fan1FreqHz;
-      }
-    });
-    res.fanlocal.forEach((e) => {
-      e.chartData = [
-        {
-          x: '吸风量',
-          y: e.readData.windQuantity1,
-        },
-        {
-          x: '供风量',
-          y: e.readData.windQuantity2,
-        },
-      ];
-      if (e.readData.Fan2StartStatus === '1') {
-        e.current = '二号';
-        e.readData.FanfHz = e.readData.Fan2fHz;
-      } else {
-        e.current = '一号';
-        e.readData.FanfHz = e.readData.Fan1fHz;
-      }
-    });
-    res.sys_majorpath.forEach((e) => {
-      e.piechart = [
-        { val: e.majorpath.drag_1, label: '进风区' },
-        { val: e.majorpath.drag_2, label: '用风区' },
-        { val: e.majorpath.drag_3, label: '回风区' },
-      ];
-    });
-
-    return res;
-  });
-};
-
-export const getBDDustData = (params) => {
-  const key = `${Api.getBDDustData}?${JSON.stringify(params)}`;
-  if (!cache.has(key)) {
-    cache.set(
-      key,
-      defHttp.post({ url: Api.getBDDustData, params }).finally(() => {
-        cache.delete(key);
-      })
-    );
-  }
-  return cache.get(key) as Promise<any>;
-};
-
-// 塔山火灾预警页面获取数据接口
-export const getDeviceSys = (params) => {
-  const key = `${Api.getDeviceSys}?${JSON.stringify(params)}`;
-  if (!cache.has(key)) {
-    cache.set(
-      key,
-      defHttp.post({ url: Api.getDeviceSys, params }).finally(() => {
-        cache.delete(key);
-      })
-    );
-  }
-  return (cache.get(key) as Promise<any>).then((res) => {
-    return res;
-  });
-};
-
-export const getAlarmRecord = (params) => {
-  const key = `${Api.getAlarmRecord}?${JSON.stringify(params)}`;
-  if (!cache.has(key)) {
-    cache.set(
-      key,
-      defHttp.post({ url: Api.getAlarmRecord, params }).finally(() => {
-        cache.delete(key);
-      })
-    );
-  }
-  return (cache.get(key) as Promise<any>).then((res) => {
-    return res;
-  });
-};
-
-export const getDisHome = (params) => {
-  // 生成缓存key,基于接口地址和参数
-  const key = `${Api.getDisHome}?${JSON.stringify(params)}`;
-
-  // 缓存不存在时发起请求
-  if (!cache.has(key)) {
-    cache.set(
-      key,
-      defHttp.post({ url: Api.getDisHome, params }).finally(() => {
-        // 请求完成后删除缓存,保证下次请求能获取最新数据
-        cache.delete(key);
-      })
-    );
-  }
-
-  // 返回缓存中的Promise并处理响应数据
-  return (cache.get(key) as Promise<any>).then((res) => {
-    // 1. 处理 pdArray 中的光纤温度数据(解析JSON字符串)
-    if (res.pdArray && Array.isArray(res.pdArray)) {
-      res.pdArray.forEach((e) => {
-        // 先校验 arrayFiber 是数组,避免forEach报错
-        if (e.arrayFiber && Array.isArray(e.arrayFiber)) {
-          e.arrayFiber.forEach((j) => {
-            // 安全解析 JSON,避免 undefined/无效JSON 导致报错
-            j.fibreTemperatureArr = safeJsonParse(j.fibreTemperature, []);
-          });
-        }
-      });
-    }
-
-    // 2. 处理 sgGxObj 下的设备数据
-    if (res.sgGxObj) {
-      // 2.1 解析 devGxcw 中的光纤温度
-      if (res.sgGxObj.devGxcw && Array.isArray(res.sgGxObj.devGxcw)) {
-        res.sgGxObj.devGxcw.forEach((e) => {
-          e.fibreTemperatureArr = safeJsonParse(e.fibreTemperature, []);
-        });
-      }
-
-      // 2.2 为 devSgjc 中的气体字段设置默认值
-      if (res.sgGxObj.devSgjc && Array.isArray(res.sgGxObj.devSgjc)) {
-        res.sgGxObj.devSgjc.forEach((e) => {
-          e.o2val = e.o2Val || 0;
-          e.coval = e.coVal || 0;
-          e.gasval = e.gasVal || 0;
-          e.ch2val = e.ch2Val || 0;
-          e.chval = e.chVal || 0;
-        });
-      }
-    }
-
-    // 3. 重组 obfObj 为按气体类型分类的结构
-    if (res.obfObj && Array.isArray(res.obfObj.arrayDev)) {
-      res.obfObj.obfObjModded = [
-        { objType: '氧气', arrayDev: mapObfDev(res.obfObj.arrayDev, 'o2Val') },
-        { objType: '甲烷', arrayDev: mapObfDev(res.obfObj.arrayDev, 'ch4Val') },
-        { objType: '一氧化碳', arrayDev: mapObfDev(res.obfObj.arrayDev, 'coVal') },
-        { objType: '乙炔', arrayDev: mapObfDev(res.obfObj.arrayDev, 'c2h2Val') },
-        { objType: '二氧化碳', arrayDev: mapObfDev(res.obfObj.arrayDev, 'co2Val') },
-        { objType: '乙烯', arrayDev: mapObfDev(res.obfObj.arrayDev, 'c2h4Val') },
-        { objType: '压差', arrayDev: mapObfDev(res.obfObj.arrayDev, 'dpVal') },
-        { objType: '温度', arrayDev: mapObfDev(res.obfObj.arrayDev, 'tempVal') },
-      ];
-    }
-
-    return res;
-  });
-};
-
-/**
- * 安全解析 JSON 字符串的工具函数
- * @param {string} jsonStr - 要解析的JSON字符串
- * @param {any} defaultValue - 解析失败/值无效时的默认值
- * @returns {any} 解析结果或默认值
- */
-function safeJsonParse(jsonStr, defaultValue = null) {
-  // 先校验值是否为有效字符串
-  if (!jsonStr || typeof jsonStr !== 'string') {
-    return defaultValue;
-  }
-  // 捕获解析异常
-  try {
-    return JSON.parse(jsonStr);
-  } catch (err) {
-    console.warn('JSON解析失败', jsonStr, err);
-    return defaultValue;
-  }
-}
-
-/**
- * 映射 obfObj.arrayDev 数据的工具函数,减少重复代码
- * @param {Array} devArray - 设备数组
- * @param {string} valKey - 要取值的字段名
- * @returns {Array} 映射后的数组
- */
-function mapObfDev(devArray, valKey) {
-  return devArray.map((e) => ({
-    strinstallpos: e.strinstallpos,
-    val: e[valKey] || 0,
-  }));
-}
-//获取通风监测预警图表数据
-export const sysTypeWarnList = (params) => {
-  const key = `${Api.sysTypeWarnList}?${JSON.stringify(params)}`;
-  if (!cache.has(key)) {
-    cache.set(
-      key,
-      defHttp.post({ url: Api.sysTypeWarnList, params }).finally(() => {
-        cache.delete(key);
-      })
-    );
-  }
-  return (cache.get(key) as Promise<any>).then((res) => {
-    return res;
-  });
-};
-//获取多灾融合预警-风险权重比例数据
-export const getDisasterProportion = (params) => {
-  const key = `${Api.getDisasterProportion}?${JSON.stringify(params)}`;
-  if (!cache.has(key)) {
-    cache.set(
-      key,
-      defHttp.post({ url: Api.getDisasterProportion, params }).finally(() => {
-        cache.delete(key);
-      })
-    );
-  }
-  return (cache.get(key) as Promise<any>).then((res) => {
-    return res;
-  });
-};
-
-//多灾融合预警
-function getLevelNum() {
-  return new Promise(async (resolve) => {
-    const list: Record<string, any> = {};
-    const typeArr = ['fire', 'dust', 'vent', 'gas'];
-    for (let i = 0; i < typeArr.length; i++) {
-      const type = typeArr[i];
-      const result = await sysTypeWarnList({ type });
-      if (type == 'fire') {
-        list.fire = result.length || 0;
-      } else if (type == 'dust') {
-        list.dust = result.length || 0;
-      } else if (type == 'vent') {
-        list.vent = result.length || 0;
-      } else if (type == 'gas') {
-        list.gas = result.length || 0;
-      }
-    }
-    resolve(list);
-  });
-}
-export const getTotal = (params) => {
-  const { sysDataType } = useGlobSetting();
-
-  const key = `${Api.getTotal}?${JSON.stringify(params)}`;
-  if (!cache.has(key)) {
-    cache.set(
-      key,
-      defHttp.get({ url: Api.getTotal, params }).finally(() => {
-        cache.delete(key);
-      })
-    );
-  }
-  return (cache.get(key) as Promise<any>).then(async (res) => {
-    let dataVent = await getLevelNum();
-    const levelsList = [
-      {
-        name: '报警',
-        value: 0,
-      },
-      {
-        name: '重大风险',
-        value: 0,
-      },
-      {
-        name: '较大风险',
-        value: 0,
-      },
-      {
-        name: '一般风险',
-        value: 0,
-      },
-      {
-        name: '低风险',
-        value: dataVent.vent || 0,
-      },
-    ];
-    //通风监测预警数据
-    switch (sysDataType) {
-      case 'monitor':
-        res.ventWarn = {
-          ventJf: res.ventInfo.zongjinfeng,
-          ventXf: res.ventInfo.xufengliang,
-          ventHf: res.ventInfo.zonghuifeng,
-        };
-        res.ventData = [
-          {
-            name: '报警',
-            value: res.info.sysInfo.ventS.levels.alarm,
-          },
-          {
-            name: '重大风险',
-            value: res.info.sysInfo.ventS.levels.red,
-          },
-          {
-            name: '较大风险',
-            value: res.info.sysInfo.ventS.levels.orange,
-          },
-          {
-            name: '一般风险',
-            value: res.info.sysInfo.ventS.levels.yellow,
-          },
-          {
-            name: '低风险',
-            value: dataVent.vent ? dataVent.vent : res.info.sysInfo.ventS.levels.blue,
-          },
-        ];
-
-        break;
-      case 'report':
-        res.ventWarn = {
-          ventJf: res.ventInfo.totalIntM3,
-          ventXf: res.ventInfo.xufengliang,
-          ventHf: res.ventInfo.totalRetM3,
-        };
-        res.ventData = levelsList;
-        break;
-      default:
-        res.ventWarn = {
-          ventJf: res.ventInfo.totalIntM3,
-          ventXf: res.ventInfo.xufengliang,
-          ventHf: res.ventInfo.totalRetM3,
-        };
-        res.ventData = levelsList;
-    }
-    //设备监测预警数据
-    res.deviceWarn = reactive({});
-    Object.keys(res.info.devicekindInfo).forEach((el) => {
-      res.deviceWarn[`${el}_all`] = res.info.devicekindInfo[el].totalcount;
-      res.deviceWarn[`${el}_warn`] = res.info.devicekindInfo[el].count;
-      res.deviceWarn[`${el}_close`] = res.info.devicekindInfo[el].netstatus;
-    });
-    //瓦斯监测预警数据
-    res.gasData = reactive({});
-    res.gasData.safety_sum = res.info.sysInfo.gasS.devices.reduce((a, b) => a + b.gasNumber, 0);
-    res.gasData.gas_sum = res.info.sysInfo.gasS.devices.reduce((a, b) => a + b.pumpNumber, 0);
-    res.gasData.monitorData = res.info.sysInfo.gasS.devices.map((el) => {
-      return {
-        label: el.systemname,
-        value: el.gasNumber,
-        value1: el.pumpNumber,
-      };
-    });
-
-    //火灾监测预警数据
-    res.fireInfos = reactive({});
-    res.fireInfos.dataOn = [];
-
-    if (res.bundletubeInfo && res.bundletubeInfo.msgTxt.length != 0 && res.bundletubeInfo.msgTxt[0].datalist.length != 0) {
-      res.bundletubeInfo.msgTxt[0].datalist.forEach((el) => {
-        res.fireInfos.dataOn.push({
-          warnLevel: el.syswarnLevel_str,
-          smokeJd: el.syswarnLevel_des,
-          value1: el.strinstallpos,
-        });
-      });
-    } else {
-      res.fireInfos.dataOn = [];
-    }
-    res.fireInfos.tempVal = res.info.sysInfo.fireS.summaryInfo
-      ? res.info.sysInfo.fireS.summaryInfo.external.temperature && res.info.sysInfo.fireS.summaryInfo.external.temperature.maxlevel == '0'
-        ? '低风险'
-        : '低风险'
-      : '';
-    res.fireInfos.smokeVal = res.info.sysInfo.fireS.summaryInfo
-      ? res.info.sysInfo.fireS.summaryInfo.external.smokeval &&
-        res.info.sysInfo.fireS.summaryInfo.external.smokeval.maxlevel &&
-        res.info.sysInfo.fireS.summaryInfo.external.smokeval.maxlevel == '0'
-        ? '低风险'
-        : '低风险'
-      : '';
-
-    res.fireInfos.fireVal = res.info.sysInfo.fireS.summaryInfo
-      ? res.info.sysInfo.fireS.summaryInfo.external.fireval &&
-        res.info.sysInfo.fireS.summaryInfo.external.fireval.maxlevel &&
-        res.info.sysInfo.fireS.summaryInfo.external.fireval.maxlevel == '0'
-        ? '低风险'
-        : '低风险'
-      : '';
-
-    res.fireInfos.coVal = res.info.sysInfo.fireS.summaryInfo
-      ? res.info.sysInfo.fireS.summaryInfo.external.coval && res.info.sysInfo.fireS.summaryInfo.external.coval.value
-        ? res.info.sysInfo.fireS.summaryInfo.external.coval.value
-        : '-'
-      : '';
-    //粉尘监测预警数据
-    res.dustInfo = [
-      {
-        name: '报警',
-        value: res.info.sysInfo.dustS.levels.alarm,
-      },
-      {
-        name: '重大风险',
-        value: res.info.sysInfo.dustS.levels.red,
-      },
-      {
-        name: '较大风险',
-        value: res.info.sysInfo.dustS.levels.orange,
-      },
-      {
-        name: '一般风险',
-        value: res.info.sysInfo.dustS.levels.yellow,
-      },
-      {
-        name: '低风险',
-        value: dataVent.dust ? dataVent.dust : res.info.sysInfo.dustS.levels.blue,
-      },
-    ];
-
-    return res;
-  });
-};
-
-//机电硐室
-export const getElectroData = (params) => {
-  const key = `${Api.system}?${JSON.stringify(params)}`;
-  if (!cache.has(key)) {
-    cache.set(
-      key,
-      defHttp.post({ url: Api.system, params }).finally(() => {
-        cache.delete(key);
-      })
-    );
-  }
-  return (cache.get(key) as Promise<any>).then(async (res) => {
-    let data = res.msgTxt.find((el) => el.type == 'ballvalve_auto');
-    data.tempData = data?.datalist?.map((el, index) => {
-      return {
-        areaName: el.readData.areaName,
-        tempStart: el.readData.tempStart,
-        tempStop: el.readData.tempStop,
-        CORealtime: el.readData.CORealtime,
-      };
-    });
-    if (data?.datalist) {
-      data.datalist.forEach((el) => {
-        el.cardData = {
-          title: el.strinstallpos,
-          areaText: '区域',
-          areaVal: el.readData.areaName,
-          moduleText: '模式',
-          moduleVal: el.readData.smokePattern,
-          statusText: '烟雾传感器状态',
-          statusVal: el.readData.smokeSensorStatus == 'False' ? '正常-低电平' : '异常',
-          phoneText: '机号',
-          phoneVal: el.readData.deviceName,
-          tempNowText: '实时测温',
-          tempNowVal: el.readData.tempRealtime,
-          tempOpenText: '开启温度',
-          tempOpenVal: el.readData.tempStart,
-          timeText: '延时t1',
-          timeVal: 0,
-          tempMaxText: '最高温度',
-          tempMaxVal: el.readData.tempMax,
-          tempCloseText: '关闭温度',
-          tempCloseVal: el.readData.tempMin,
-          time3Text: '延时t3',
-          time3Val: 0,
-          deviceSTAT: el.readData.deviceSTAT == '1' ? true : false,
-        };
-      });
-      data.chartData = data.datalist.map((el) => {
-        return {
-          time: el.readData.areaName,
-          coRealTime: el.readData.CORealtime,
-          coWarn: el.readData.COWarn,
-        };
-      });
-    }
-    return data;
-  });
-};
-
-//获取红沙泉露天煤矿数据
-export const getSystemApi = (params) => {
-  const key = `${Api.getSystem}?${JSON.stringify(params)}`;
-  if (!cache.has(key)) {
-    cache.set(
-      key,
-      defHttp.post({ url: Api.getSystem, params }).finally(() => {
-        cache.delete(key);
-      })
-    );
-  }
-  return (cache.get(key) as Promise<any>).then(async (res) => {
-    //设备状态总览
-    res.deviceStatusNum = {
-      zxNum: 5,
-      lxNum: 5,
-      gzNum: 5,
-      bjNum: 5,
-    };
-    res.deviceStatusData = [
-      { deviceName: 'CAM-001', status: '在线', remark: '正常' },
-      { deviceName: 'CAM-002', status: '在线', remark: '正常' },
-      { deviceName: 'CAM-003', status: '报警', remark: '高温' },
-      { deviceName: 'CAM-001', status: '在线', remark: '正常' },
-      { deviceName: 'CAM-002', status: '在线', remark: '正常' },
-      { deviceName: 'CAM-003', status: '报警', remark: '高温' },
-    ];
-    //实时温度曲线
-    res.temptureLineData = [
-      { pos: '1', value: '12' },
-      { pos: '2', value: '44' },
-      { pos: '3', value: '44' },
-      { pos: '4', value: '20' },
-    ];
-    //最近处理记录
-    res.processingRecordData = [
-      { time: '14:25:10', deviceName: 'CAM-001', status: '在线' },
-      { time: '14:25:10', deviceName: 'CAM-002', status: '在线' },
-      { time: '14:25:10', deviceName: 'CAM-003', status: '报警' },
-      { time: '14:25:10', deviceName: 'CAM-001', status: '在线' },
-      { time: '14:25:10', deviceName: 'CAM-002', status: '在线' },
-      { time: '14:25:10', deviceName: 'CAM-003', status: '报警' },
-    ];
-    //报警监控
-    res.alarmMonitoringDataT = {
-      dayWarn: 12,
-      warnOk: 2,
-      warnUnOk: 10,
-    };
-    res.alarmMonitoringData = [
-      { time: '14:25:10', address: '采掘场A区', grade: '一级' },
-      { time: '14:25:10', address: '采掘场B区', grade: '一级' },
-      { time: '14:25:10', address: '采掘场C区', grade: '一级' },
-      { time: '14:25:10', address: '采掘场D区', grade: '一级' },
-      { time: '14:25:10', address: '采掘场E区', grade: '一级' },
-      { time: '14:25:10', address: '采掘场F区', grade: '一级' },
-    ];
-    //
-    res.areaTemptureData = [
-      { x: '1', y: '12' },
-      { x: '2', y: '44' },
-      { x: '3', y: '44' },
-      { x: '4', y: '20' },
-    ];
-    //环境监测数据
-    res.environmentalMonitoringData = {
-      tempHj: '-8.5',
-      fsfx: '3.2',
-      temp: '42',
-      coval: '12',
-      co2val: '380',
-      o2val: '20.9',
-      ch4val: '0.02',
-      fcnd: '0.08',
-      ywzs: '0.15',
-      tempDb: '28',
-    };
-    //快捷操作
-    res.quickOperationData = {
-      time: '128天06:32:18',
-      sjsx: '实时',
-      wlyc: '12s',
-    };
-    console.log(res, '红沙泉---');
-    return res;
-  });
-};

+ 0 - 881
src/views/vent/home/configurable/configurable.data.ts

@@ -2,888 +2,7 @@ import { Config } from '../../deviceManager/configurationTable/types';
 // import { BDdustMock, BDfireMock } from './configurable.data.bd';
 import { getThemifyImagesURL } from '/@/utils/ui';
 
-//火灾实时监测一张图
-export const testConfigFire: Config[] = [
-  {
-    deviceType: 'deviceStatus',
-    moduleName: '设备状态总览',
-    pageType: 'gas_injection',
-    moduleData: {
-      header: {
-        show: false,
-        readFrom: '',
-        selector: {
-          show: false,
-          value: '${strinstallpos}',
-        },
-        slot: {
-          show: false,
-          value: '',
-          trans: {},
-        },
-      },
-      background: {
-        show: false,
-        type: 'video',
-        link: '',
-      },
-      layout: {
-        direction: 'column',
-        items: [
-          {
-            name: 'gallery_new',
-            basis: '40%',
-          },
-          {
-            name: 'table',
-            basis: '60%',
-            overflow: true,
-          },
-        ],
-      },
-      board: [],
-      list: [],
-      chart: [],
-      table: [
-        {
-          type: 'A',
-          //parser: 'json',
-          readFrom: 'deviceStatusData',
-          columns: [
-            {
-              name: '设备名称',
-              prop: 'deviceName',
-            },
-            {
-              name: '状态',
-              prop: 'status',
-            },
-            {
-              name: '备注',
-              prop: 'remark',
-            },
-          ],
-        },
-      ],
-      gallery: [],
-      complex_list: [],
-      gallery_list: [],
-      preset: [
-        {
-          type: 'A',
-          readFrom: 'deviceStatusNum',
-          items: [
-            {
-              label: '在线设备',
-              value: 'zxNum',
-            },
-            {
-              label: '离线设备',
-              value: 'lxNum',
-            },
-            {
-              label: '故障设备',
-              value: 'gzNum',
-            },
-            {
-              label: '报警设备',
-              value: 'bjNum',
-            },
-          ],
-        },
-      ],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
-    },
-    showStyle: {
-      size: 'width:420px;height:360px;',
-      version: '普通版',
-      position: 'top:0px;left:10px;',
-    },
-  },
-  {
-    deviceType: 'temptureLine',
-    moduleName: '实时温度曲线',
-    pageType: 'gas_injection',
-    moduleData: {
-      header: {
-        show: false,
-        readFrom: '',
-        selector: {
-          show: false,
-          value: '${strinstallpos}',
-        },
-        slot: {
-          show: false,
-          value: '',
-          trans: {},
-        },
-      },
-      background: {
-        show: false,
-        type: 'video',
-        link: '',
-      },
-      layout: {
-        direction: 'column',
-        items: [
-          {
-            name: 'chart',
-            basis: '100%',
-          },
-        ],
-      },
-      board: [],
-      list: [],
-      chart: [
-        {
-          type: 'line_area',
-          readFrom: '',
-          // parser: 'json',
-          grid: {
-            top: 40,
-            left: 50,
-            bottom: 14,
-            right: 50,
-          },
-          legend: { show: false },
-          xAxis: [{ show: true }],
-          yAxis: [{ show: true, name: '(℃)', position: 'left' }],
-          series: [
-            {
-              label: '温度',
-              readFrom: 'temptureLineData',
-              xprop: 'pos',
-              yprop: 'value',
-            },
-          ],
-        },
-      ],
-      table: [],
-      gallery: [],
-      complex_list: [],
-      gallery_list: [],
-      preset: [],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
-    },
-    showStyle: {
-      size: 'width:420px;height:220px;',
-      version: '普通版',
-      position: 'top:370px;left:10px;',
-    },
-  },
-  {
-    deviceType: 'processingRecord',
-    moduleName: '最近处理记录',
-    pageType: 'gas_injection',
-    moduleData: {
-      header: {
-        show: false,
-        readFrom: '',
-        selector: {
-          show: false,
-          value: '${strinstallpos}',
-        },
-        slot: {
-          show: false,
-          value: '',
-          trans: {},
-        },
-      },
-      background: {
-        show: false,
-        type: 'video',
-        link: '',
-      },
-      layout: {
-        direction: 'column',
-        items: [
-          {
-            name: 'table',
-            basis: '100%',
-            overflow: true,
-          },
-        ],
-      },
-      board: [],
-      list: [],
-      chart: [],
-      table: [
-        {
-          type: 'A',
-          // parser: 'json',
-          readFrom: 'processingRecordData',
-          columns: [
-            {
-              name: '时间',
-              prop: 'time',
-            },
-            {
-              name: '设备',
-              prop: 'deviceName',
-            },
-            {
-              name: '状态',
-              prop: 'status',
-            },
-          ],
-        },
-      ],
-      gallery: [],
-      complex_list: [],
-      gallery_list: [],
-      preset: [],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
-    },
-    showStyle: {
-      size: 'width:420px;height:250px;',
-      version: '普通版',
-      position: 'top:600px;left:10px;',
-    },
-  },
-  {
-    deviceType: 'alarmMonitoring',
-    moduleName: '报警监控',
-    pageType: 'gas_injection',
-    moduleData: {
-      header: {
-        show: false,
-        readFrom: '',
-        selector: {
-          show: false,
-          value: '${strinstallpos}',
-        },
-        slot: {
-          show: false,
-          value: '',
-          trans: {},
-        },
-      },
-      background: {
-        show: false,
-        type: 'video',
-        link: '',
-      },
-      layout: {
-        direction: 'column',
-        items: [
-          {
-            name: 'card_new',
-            basis: '25%',
-          },
-          {
-            name: 'table',
-            basis: '75%',
-            overflow: true,
-          },
-        ],
-      },
-      board: [],
-      list: [],
-      chart: [],
-      table: [
-        {
-          type: 'A',
-          //parser: 'json',
-          readFrom: 'alarmMonitoringData',
-          columns: [
-            {
-              name: '时间',
-              prop: 'time',
-            },
-            {
-              name: '位置',
-              prop: 'address',
-            },
-            {
-              name: '级别',
-              prop: 'grade',
-            },
-          ],
-        },
-      ],
-      gallery: [],
-      complex_list: [],
-      gallery_list: [],
-      preset: [
-        {
-          readFrom: 'alarmMonitoringDataT',
-          items: [
-            { label: '今日报警', value: 'dayWarn' },
-            { label: '未处理', value: 'warnOk' },
-            { label: '已处理', value: 'warnUnOk' },
-          ],
-        },
-      ],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
-    },
-    showStyle: {
-      size: 'width:420px;height:360px;',
-      version: '普通版',
-      position: 'top:0px;right:10px;',
-    },
-  },
-  {
-    deviceType: 'areaTempture',
-    moduleName: '区域温度统计',
-    pageType: 'gas_injection',
-    moduleData: {
-      header: {
-        show: false,
-        readFrom: '',
-        selector: {
-          show: false,
-          value: '${strinstallpos}',
-        },
-        slot: {
-          show: false,
-          value: '',
-          trans: {},
-        },
-      },
-      background: {
-        show: false,
-        type: 'video',
-        link: '',
-      },
-      layout: {
-        direction: 'column',
-        items: [
-          {
-            name: 'chart',
-            basis: '100%',
-          },
-        ],
-      },
-      board: [],
-      list: [],
-      chart: [
-        {
-          type: 'bar_cylinder_wide',
-          readFrom: '',
-          grid: {
-            top: 40,
-            left: 50,
-            bottom: 14,
-            right: 50,
-          },
-          legend: { show: false },
-          xAxis: [{ show: true }],
-          yAxis: [{ show: true, name: '', position: 'left' }],
-          series: [{ readFrom: 'areaTemptureData', xprop: 'x', yprop: 'y', label: '温度' }],
-        },
-      ],
-      table: [],
-      gallery: [],
-      complex_list: [],
-      gallery_list: [],
-      preset: [],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
-    },
-    showStyle: {
-      size: 'width:420px;height:220px;',
-      version: '普通版',
-      position: 'top:370px;right:10px;',
-    },
-  },
-  {
-    deviceType: 'environmentalMonitoring',
-    moduleName: '环境监测数据',
-    pageType: 'gas_injection',
-    moduleData: {
-      header: {
-        show: false,
-        readFrom: '',
-        selector: {
-          show: false,
-          value: '${strinstallpos}',
-        },
-        slot: {
-          show: false,
-          value: '',
-          trans: {},
-        },
-      },
-      background: {
-        show: false,
-        type: 'video',
-        link: '',
-      },
-      layout: {
-        direction: 'column',
-        items: [
-          {
-            name: 'btn_new',
-            basis: '100%',
-          },
-        ],
-      },
-      board: [],
-      list: [],
-      chart: [],
-      table: [],
-      gallery: [],
-      complex_list: [],
-      gallery_list: [],
-      preset: [
-        {
-          readFrom: 'environmentalMonitoringData',
-          items: [
-            { label: '环境温度', value: 'tempHj', unit: '℃' },
-            { label: '风速风向', value: 'fsfx', unit: 'm/s' },
-            { label: '温度', value: 'temp', unit: '%' },
-            { label: 'CO浓度', value: 'coval', unit: 'ppm' },
-            { label: 'CO2浓度', value: 'co2val', unit: 'ppm' },
-            { label: 'O2浓度', value: 'o2val', unit: '%' },
-            { label: 'Ch4浓度', value: 'ch4val', unit: '%' },
-            { label: '粉尘浓度', value: 'fcnd', unit: 'mg/m³' },
-            { label: '烟雾指数', value: 'ywzs', unit: '' },
-            { label: '地表温度', value: 'tempDb', unit: '℃' },
-          ],
-        },
-      ],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
-    },
-    showStyle: {
-      size: 'width:420px;height:250px;',
-      version: '普通版',
-      position: 'top:600px;right:10px;',
-    },
-  },
-  {
-    deviceType: 'quickOperation',
-    moduleName: '快捷操作',
-    pageType: 'gas_injection',
-    moduleData: {
-      header: {
-        show: false,
-        readFrom: '',
-        selector: {
-          show: false,
-          value: '${strinstallpos}',
-        },
-        slot: {
-          show: false,
-          value: '',
-          trans: {},
-        },
-      },
-      background: {
-        show: false,
-        type: 'video',
-        link: '',
-      },
-      layout: {
-        direction: 'column',
-        items: [
-          {
-            name: 'oerate_new',
-            basis: '100%',
-          },
-        ],
-      },
-      board: [],
-      list: [],
-      chart: [],
-      table: [],
-      gallery: [],
-      complex_list: [],
-      gallery_list: [],
-      preset: [
-        {
-          readFrom: 'quickOperationData',
-          items: [
-            { label: '系统运行时间', value: 'time', iconName: 'time-run' },
-            { label: '数据刷新', value: 'sjsx', iconName: 'data-reset' },
-            { label: '网络延迟', value: 'wlyc', iconName: 'internet-on' },
-          ],
-          option: [
-            { firstLabel: '报警确认', secondLabel: '视屏调取', thirdLabel: '联动控制' },
-            { firstLabel: '数据导出', secondLabel: '生成报表', thirdLabel: '定位追踪' },
-            { firstLabel: '声光关闭', secondLabel: '应急广播', thirdLabel: '系统设置' },
-          ],
-        },
-      ],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
-    },
-    showStyle: {
-      size: 'width:calc(100% - 880px);height:155px;',
-      version: '普通版',
-      position: 'bottom:10px;left:440px;',
-    },
-  },
-];
-
-//设备管理
-export const testConfigDevice: Config[] = [
-  {
-    deviceType: 'deviceList',
-    moduleName: '设备列表',
-    pageType: 'gas_injection',
-    moduleData: {
-      header: {
-        show: false,
-        readFrom: '',
-        selector: {
-          show: false,
-          value: '${strinstallpos}',
-        },
-        slot: {
-          show: false,
-          value: '',
-          trans: {},
-        },
-      },
-      background: {
-        show: false,
-        type: 'video',
-        link: '',
-      },
-      layout: {
-        direction: 'column',
-        items: [
-          {
-            name: 'long_list',
-            basis: '100%',
-          },
-        ],
-      },
-      board: [],
-      list: [],
-      chart: [],
-      table: [],
-      gallery: [],
-      complex_list: [],
-      gallery_list: [],
-      preset: [
-        {
-          readFrom: '',
-        },
-      ],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
-    },
-    showStyle: {
-      size: 'width:420px;height:calc(100% - 10px);',
-      version: '普通版',
-      position: 'top:0px;left:10px;',
-    },
-  },
-  {
-    deviceType: 'deviceDetail',
-    moduleName: '设备详情',
-    pageType: 'gas_injection',
-    moduleData: {
-      header: {
-        show: false,
-        readFrom: '',
-        selector: {
-          show: false,
-          value: '${strinstallpos}',
-        },
-        slot: {
-          show: false,
-          value: '',
-          trans: {},
-        },
-      },
-      background: {
-        show: false,
-        type: 'video',
-        link: '',
-      },
-      layout: {
-        direction: 'column',
-        items: [
-          {
-            name: 'long_list1',
-            basis: '100%',
-          },
-        ],
-      },
-      board: [],
-      list: [],
-      chart: [],
-      table: [],
-      gallery: [],
-      complex_list: [],
-      gallery_list: [],
-      preset: [
-        {
-          readFrom: 'deviceStatusNum',
-        },
-      ],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
-    },
-    showStyle: {
-      size: 'width:1020px;height:calc(100% - 76px);',
-      version: '普通版',
-      position: 'top:65px;left:440px;',
-    },
-  },
-  {
-    deviceType: 'deviceStatus',
-    moduleName: '设备配置',
-    pageType: 'gas_injection',
-    moduleData: {
-      header: {
-        show: false,
-        readFrom: '',
-        selector: {
-          show: false,
-          value: '${strinstallpos}',
-        },
-        slot: {
-          show: false,
-          value: '',
-          trans: {},
-        },
-      },
-      background: {
-        show: false,
-        type: 'video',
-        link: '',
-      },
-      layout: {
-        direction: 'column',
-        items: [
-          {
-            name: 'long_list2',
-            basis: '100%',
-          },
-        ],
-      },
-      board: [],
-      list: [],
-      chart: [],
-      table: [],
-      gallery: [],
-      complex_list: [],
-      gallery_list: [],
-      preset: [
-        {
-          readFrom: 'deviceStatusNum',
-        },
-      ],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
-    },
-    showStyle: {
-      size: 'width:420px;height:calc(100% - 10px);',
-      version: '普通版',
-      position: 'top:0px;right:10px;',
-    },
-  },
-];
 
-//监测预警
-export const testConfigWarn: Config[] = [
-  {
-    deviceType: 'listLeft',
-    moduleName: '',
-    pageType: 'gas_injection',
-    moduleData: {
-      header: {
-        show: false,
-        readFrom: '',
-        selector: {
-          show: false,
-          value: '${strinstallpos}',
-        },
-        slot: {
-          show: false,
-          value: '',
-          trans: {},
-        },
-      },
-      background: {
-        show: false,
-        type: 'video',
-        link: '',
-      },
-      layout: {
-        direction: 'column',
-        items: [
-          {
-            name: 'search_table',
-            basis: '100%',
-          },
-        ],
-      },
-      board: [],
-      list: [],
-      chart: [],
-      table: [],
-      gallery: [],
-      complex_list: [],
-      gallery_list: [],
-      preset: [
-        {
-          readFrom: '',
-        },
-      ],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
-    },
-    showStyle: {
-      size: 'width:420px;height:calc(100% - 200px);',
-      version: '普通版',
-      position: 'top:0px;left:10px;',
-    },
-  },
-  {
-    deviceType: 'listCenter',
-    moduleName: '',
-    pageType: 'gas_injection',
-    moduleData: {
-      header: {
-        show: false,
-        readFrom: '',
-        selector: {
-          show: false,
-          value: '${strinstallpos}',
-        },
-        slot: {
-          show: false,
-          value: '',
-          trans: {},
-        },
-      },
-      background: {
-        show: false,
-        type: 'video',
-        link: '',
-      },
-      layout: {
-        direction: 'column',
-        items: [
-          {
-            name: 'mixed_warn',
-            basis: '100%',
-          },
-        ],
-      },
-      board: [],
-      list: [],
-      chart: [],
-      table: [],
-      gallery: [],
-      complex_list: [],
-      gallery_list: [],
-      preset: [
-        {
-          readFrom: '',
-        },
-      ],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
-    },
-    showStyle: {
-      size: 'width:1020px;height:calc(100% - 265px);',
-      version: '普通版',
-      position: 'top:65px;left:440px;',
-    },
-  },
-  {
-    deviceType: 'warnRule',
-    moduleName: '预警规则配置',
-    pageType: 'gas_injection',
-    moduleData: {
-      header: {
-        show: false,
-        readFrom: '',
-        selector: {
-          show: false,
-          value: '${strinstallpos}',
-        },
-        slot: {
-          show: false,
-          value: '',
-          trans: {},
-        },
-      },
-      background: {
-        show: false,
-        type: 'video',
-        link: '',
-      },
-      layout: {
-        direction: 'column',
-        items: [
-          {
-            name: 'rule_list',
-            basis: '100%',
-          },
-        ],
-      },
-      board: [],
-      list: [],
-      chart: [],
-      table: [],
-      gallery: [],
-      complex_list: [],
-      gallery_list: [],
-      preset: [
-        {
-          readFrom: '',
-        },
-      ],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
-    },
-    showStyle: {
-      size: 'width:420px;height:calc(100% - 200px);',
-      version: '普通版',
-      position: 'top:0px;right:10px;',
-    },
-  },
-  {
-    deviceType: 'warnCount',
-    moduleName: '',
-    pageType: 'gas_injection',
-    moduleData: {
-      header: {
-        show: false,
-        readFrom: '',
-        selector: {
-          show: false,
-          value: '${strinstallpos}',
-        },
-        slot: {
-          show: false,
-          value: '',
-          trans: {},
-        },
-      },
-      background: {
-        show: false,
-        type: 'video',
-        link: '',
-      },
-      layout: {
-        direction: 'column',
-        items: [
-          {
-            name: 'echart_bar_new',
-            basis: '100%',
-          },
-        ],
-      },
-      board: [],
-      list: [],
-      chart: [],
-      table: [],
-      gallery: [],
-      complex_list: [],
-      gallery_list: [],
-      preset: [
-        {
-          readFrom: '',
-        },
-      ],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=fanmain',
-    },
-    showStyle: {
-      size: 'width:calc(100% - 10px);height:180px;',
-      version: '普通版',
-      position: 'bottom:10px;bottom:10px;',
-    },
-  },
-];
 //联动配置
 export const testConfigLink: Config[] = [
   {

+ 0 - 96
src/views/vent/home/configurable/deviceManger.vue

@@ -1,96 +0,0 @@
-<template>
-  <div class="device-manger">
-    <ModuleCommonHsq
-      v-for="cfg in configs"
-      :key="cfg.deviceType"
-      :show-style="cfg.showStyle"
-      :module-data="cfg.moduleData"
-      :module-name="cfg.moduleName"
-      :device-type="cfg.deviceType"
-      :data="data"
-      :visible="true"
-    />
-  </div>
-</template>
-<script lang="ts" setup>
-import { onMounted, onUnmounted, ref, computed, nextTick, onBeforeMount, watch } from 'vue';
-import { useInitConfigs, useInitPage } from './hooks/useInit';
-import ModuleCommonHsq from './components/ModuleCommonHsq.vue';
-import { getSystemApi } from './configurable.api';
-import { testConfigDevice } from './configurable.data';
-
-const { configs, fetchConfigs } = useInitConfigs();
-const { data, updateData } = useInitPage('红沙泉露天煤矿系统');
-let interval: number | undefined;
-
-// https获取监测数据
-let timer: null | NodeJS.Timeout = null;
-function getMonitor() {
-  timer = setTimeout(async () => {
-    getSystemApi({ devicetype: 'sys', systemID: '2036323791827165185' }).then(updateData);
-    if (timer) {
-      timer = null;
-    }
-    getMonitor();
-  }, 10000);
-}
-
-onMounted(() => {
-  fetchConfigs('gas_injection').then(() => {
-    configs.value = testConfigDevice;
-    getSystemApi({ devicetype: 'sys', systemID: '2036323791827165185' }).then(updateData);
-  });
-  getMonitor();
-});
-
-watch(
-  () => data.value,
-  (newData, oldData) => {}
-);
-
-onUnmounted(() => {
-  clearInterval(interval);
-});
-</script>
-
-<style lang="less" scoped>
-@import '/@/design/theme.less';
-
-@{theme-deepblue} {
-  .device-manger {
-  }
-}
-
-.device-manger {
-  --image-box1-bg: url('@/assets/images/home-container/configurable/hsq/2-4.png');
-  --image-box1-bg1: url('@/assets/images/home-container/configurable/hsq/2-10.png');
-  width: 100%;
-  height: 100%;
-  color: @white;
-  position: relative;
-  padding: 0px 10px;
-  box-sizing: border-box;
-  background-color: #09172c;
-}
-
-.vent-box1-bg {
-  &:nth-child(1) {
-    background: var(--image-box1-bg) no-repeat;
-    background-size: 100% 100%;
-  }
-
-  &:nth-child(2) {
-    background: var(--image-box1-bg1) no-repeat;
-    background-size: 100% 100%;
-  }
-
-  &:nth-child(3) {
-    background: var(--image-box1-bg) no-repeat;
-    background-size: 100% 100%;
-  }
-}
-
-:deep(.loading-box) {
-  position: unset;
-}
-</style>

+ 0 - 82
src/views/vent/home/configurable/fireMonitor.vue

@@ -1,82 +0,0 @@
-<template>
-  <div class="fire-monitor">
-    <!-- 模型区域 -->
-    <div class="model-box">
-      <dwgViewer />
-    </div>
-    <ModuleCommon v-for="cfg in configs" :key="cfg.deviceType" :show-style="cfg.showStyle" :module-data="cfg.moduleData"
-      :module-name="cfg.moduleName" :device-type="cfg.deviceType" :data="data" :visible="true" />
-  </div>
-</template>
-<script lang="ts" setup>
-import { onMounted, onUnmounted, ref, computed, nextTick, onBeforeMount, watch } from 'vue';
-import { useInitConfigs, useInitPage } from './hooks/useInit';
-import ModuleCommon from './components/ModuleCommon.vue';
-import dwgViewer from '../../cad/dwgViewer.vue'
-import { getSystemApi } from './configurable.api';
-import { testConfigFire } from './configurable.data';
-
-const { configs, fetchConfigs } = useInitConfigs();
-const { data, updateData } = useInitPage('红沙泉露天煤矿系统');
-let interval: number | undefined;
-
-// https获取监测数据
-let timer: null | NodeJS.Timeout = null;
-function getMonitor() {
-  timer = setTimeout(async () => {
-    getSystemApi({ devicetype: 'sys', systemID: '2036323791827165185' }).then(updateData);
-    if (timer) {
-      timer = null;
-    }
-    getMonitor();
-  }, 10000);
-}
-
-onMounted(() => {
-  fetchConfigs('gas_injection').then(() => {
-    configs.value = testConfigFire;
-    getSystemApi({ devicetype: 'sys', systemID: '2036323791827165185' }).then(updateData);
-  });
-  getMonitor();
-});
-
-watch(
-  () => data.value,
-  (newData, oldData) => { }
-);
-
-onUnmounted(() => {
-  clearInterval(interval);
-});
-</script>
-
-<style lang="less" scoped>
-@import '/@/design/theme.less';
-
-@{theme-deepblue} {
-  .fire-monitor {}
-}
-
-.fire-monitor {
-  width: 100%;
-  height: 100%;
-  color: @white;
-  position: relative;
-  padding: 0px 10px;
-  box-sizing: border-box;
-
-  .model-box {
-    position: absolute;
-    top: 63px;
-    left: 50%;
-    transform: translateX(-50%);
-    width: 1000px;
-    height: 615px;
-  border: 1px solid rgba(40, 165, 232, 0.8);
-  }
-}
-
-:deep(.loading-box) {
-  position: unset;
-}
-</style>

+ 0 - 1
src/views/vent/home/configurable/hooks/helper.ts

@@ -40,7 +40,6 @@ export function getRawProp(formatter: string): string {
 // 获取模块所依赖的数据的方法
 export function getData(raw, readFrom, parser?) {
   const result = readFrom ? get(raw, readFrom) : raw;
-  console.log()
   if (!result) return result;
   switch (parser) {
     case 'json':

+ 0 - 172
src/views/vent/home/configurable/systemManger.vue

@@ -1,172 +0,0 @@
-<template>
-  <div class="system-manger">
-    <div class="nav-menu">
-      <div
-        :class="activeIndex == index ? 'nav-item-active' : 'nav-item'"
-        v-for="(item, index) in navList"
-        :key="index"
-        @click="handleChange(item, index)"
-        >{{ item.label }}</div
-      >
-    </div>
-    <ModuleCommonHsq
-      v-for="cfg in configs"
-      :key="cfg.deviceType"
-      :show-style="cfg.showStyle"
-      :module-data="cfg.moduleData"
-      :module-name="cfg.moduleName"
-      :device-type="cfg.deviceType"
-      :data="data"
-      :visible="true"
-    />
-  </div>
-</template>
-<script lang="ts" setup>
-import { onMounted, onUnmounted, ref, computed, nextTick, onBeforeMount, watch } from 'vue';
-import { useInitConfigs, useInitPage } from './hooks/useInit';
-import ModuleCommonHsq from './components/ModuleCommonHsq.vue';
-import { getSystemApi } from './configurable.api';
-import { testConfigSystem } from './configurable.data';
-
-const { configs, fetchConfigs } = useInitConfigs();
-const { data, updateData } = useInitPage('红沙泉露天煤矿系统');
-let activeIndex = ref(0);
-let interval: number | undefined;
-let navList = ref<any[]>([
-  { label: '角色权限', value: '1' },
-  { label: '用户管理', value: '2' },
-  { label: '日志审计', value: '3' },
-  { label: '系统配置', value: '4' },
-  { label: '数据备份', value: '5' },
-]);
-
-// https获取监测数据
-let timer: null | NodeJS.Timeout = null;
-function getMonitor() {
-  timer = setTimeout(async () => {
-    getSystemApi({ devicetype: 'sys', systemID: '2036323791827165185' }).then(updateData);
-    if (timer) {
-      timer = null;
-    }
-    getMonitor();
-  }, 10000);
-}
-
-//nav选项切换
-function handleChange(item, index) {
-  activeIndex.value = index;
-}
-
-onMounted(() => {
-  fetchConfigs('gas_injection').then(() => {
-    configs.value = testConfigSystem;
-    getSystemApi({ devicetype: 'sys', systemID: '2036323791827165185' }).then(updateData);
-  });
-  getMonitor();
-});
-
-watch(
-  () => data.value,
-  (newData, oldData) => {}
-);
-
-onUnmounted(() => {
-  clearInterval(interval);
-});
-</script>
-
-<style lang="less" scoped>
-@import '/@/design/theme.less';
-
-@{theme-deepblue} {
-  .system-manger {
-  }
-}
-
-.system-manger {
-  --image-box1-bg: url('@/assets/images/home-container/configurable/hsq/5-1.png');
-  --image-box1-bg1: url('@/assets/images/home-container/configurable/hsq/5-3.png');
-  --image-box1-bg2: url('@/assets/images/home-container/configurable/hsq/5-4.png');
-  --image-box1-bg3: url('@/assets/images/home-container/configurable/hsq/5-2.png');
-  --image-box1-bg4: url('@/assets/images/home-container/configurable/hsq/5-6.png');
-  --image-box1-bg5: url('@/assets/images/home-container/configurable/hsq/5-5.png');
-  width: 100%;
-  height: 100%;
-  color: @white;
-  position: relative;
-  padding: 0px 10px;
-  box-sizing: border-box;
-  background-color: #09172c;
-}
-
-.vent-box1-bg {
-  &:nth-child(2) {
-    background: var(--image-box1-bg) no-repeat;
-    background-size: 100% 100%;
-  }
-
-  &:nth-child(3) {
-    background: var(--image-box1-bg) no-repeat;
-    background-size: 100% 100%;
-  }
-
-  &:nth-child(4) {
-    background: var(--image-box1-bg1) no-repeat;
-    background-size: 100% 100%;
-  }
-
-  &:nth-child(5) {
-    background: var(--image-box1-bg3) no-repeat;
-    background-size: 100% 100%;
-  }
-
-  &:nth-child(6) {
-    background: var(--image-box1-bg3) no-repeat;
-    background-size: 100% 100%;
-  }
-
-  &:nth-child(7) {
-    background: var(--image-box1-bg2) no-repeat;
-    background-size: 100% 100%;
-  }
-}
-
-.nav-menu {
-  position: absolute;
-  left: 0;
-  top: 0;
-  width: 450px;
-  height: 52px;
-  padding-left: 10px;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  box-sizing: border-box;
-}
-
-.nav-item {
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  width: 100px;
-  height: 36px;
-  background: var(--image-box1-bg4) no-repeat;
-  background-size: 100% 100%;
-  cursor: pointer;
-}
-
-.nav-item-active {
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  width: 100px;
-  height: 36px;
-  background: var(--image-box1-bg5) no-repeat;
-  background-size: 100% 100%;
-  cursor: pointer;
-}
-
-:deep(.loading-box) {
-  position: unset;
-}
-</style>

+ 0 - 101
src/views/vent/home/configurable/warnMonitor.vue

@@ -1,101 +0,0 @@
-<template>
-  <div class="warn-monitor">
-    <ModuleCommonHsq
-      v-for="cfg in configs"
-      :key="cfg.deviceType"
-      :show-style="cfg.showStyle"
-      :module-data="cfg.moduleData"
-      :module-name="cfg.moduleName"
-      :device-type="cfg.deviceType"
-      :data="data"
-      :visible="true"
-    />
-  </div>
-</template>
-<script lang="ts" setup>
-import { onMounted, onUnmounted, ref, computed, nextTick, onBeforeMount, watch } from 'vue';
-import { useInitConfigs, useInitPage } from './hooks/useInit';
-import ModuleCommonHsq from './components/ModuleCommonHsq.vue';
-import { getSystemApi } from './configurable.api';
-import { testConfigWarn } from './configurable.data';
-
-const { configs, fetchConfigs } = useInitConfigs();
-const { data, updateData } = useInitPage('红沙泉露天煤矿系统');
-let interval: number | undefined;
-
-// https获取监测数据
-let timer: null | NodeJS.Timeout = null;
-function getMonitor() {
-  timer = setTimeout(async () => {
-    getSystemApi({ devicetype: 'sys', systemID: '2036323791827165185' }).then(updateData);
-    if (timer) {
-      timer = null;
-    }
-    getMonitor();
-  }, 10000);
-}
-
-onMounted(() => {
-  fetchConfigs('gas_injection').then(() => {
-    configs.value = testConfigWarn;
-    getSystemApi({ devicetype: 'sys', systemID: '2036323791827165185' }).then(updateData);
-  });
-  getMonitor();
-});
-
-watch(
-  () => data.value,
-  (newData, oldData) => {}
-);
-
-onUnmounted(() => {
-  clearInterval(interval);
-});
-</script>
-
-<style lang="less" scoped>
-@import '/@/design/theme.less';
-
-@{theme-deepblue} {
-  .warn-monitor {
-  }
-}
-
-.warn-monitor {
-  --image-box1-bg: url('@/assets/images/home-container/configurable/hsq/2-4.png');
-  --image-box1-bg1: url('@/assets/images/home-container/configurable/hsq/2-10.png');
-  --image-box1-bg2: url('@/assets/images/home-container/configurable/hsq/3-3.png');
-  width: 100%;
-  height: 100%;
-  color: @white;
-  position: relative;
-  padding: 0px 10px;
-  box-sizing: border-box;
-  background-color: #09172c;
-}
-
-.vent-box1-bg {
-  &:nth-child(1) {
-    background: var(--image-box1-bg) no-repeat;
-    background-size: 100% 100%;
-  }
-
-  &:nth-child(2) {
-    background: var(--image-box1-bg1) no-repeat;
-    background-size: 100% 100%;
-  }
-
-  &:nth-child(3) {
-    background: var(--image-box1-bg) no-repeat;
-    background-size: 100% 100%;
-  }
-  &:nth-child(4) {
-    background: var(--image-box1-bg2) no-repeat;
-    background-size: 100% 100%;
-  }
-}
-
-:deep(.loading-box) {
-  position: unset;
-}
-</style>

+ 130 - 0
src/views/vent/monitorManager/hsqHome/components/AlarmMonitor.vue

@@ -0,0 +1,130 @@
+<template>
+  <div class="alarm-monitor">
+    <div class="alarm-top">
+      <div class="card-item" v-for="(item, index) in option" :key="index">
+        <div class="item-value">{{ cardData[item.value] }}</div>
+        <div class="item-label">{{ item.label }}</div>
+      </div>
+    </div>
+    <div class="alarm-bot">
+      <CommonTable :columns="alarmColumns" :table-data="tableData"></CommonTable>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { onMounted, ref } from 'vue';
+import CommonTable from './CommonTable.vue';
+import { autoLogList } from '../hsqHome.api';
+import {alarmColumns} from '../hsqHome.data'
+
+let props = defineProps({
+  /**
+   * 顶部卡片配置项
+   * 每项包含 label(显示名称)和 value(对应 cardData 中的 key)
+   */
+  option: {
+    type: Array as any
+  },
+  /**
+   * 卡片数据对象
+   * key 对应 option 中每项的 value,value 为实际展示数值
+   */
+  cardData: {
+    type: Object as any,
+    default: () => {
+      return {}
+    }
+  }
+})
+
+// 表格数据源:从后端获取报警日志列表数据
+let tableData = ref<any[]>([])
+
+/**
+ * 获取报警日志列表数据
+ *
+ * 调用 autoLogList API,默认查询第1页、每页10条记录,
+ * 将返回的报警日志数据填充到表格中用于展示
+ *
+ * @returns {Promise<void>}
+ */
+async function getAlarmData() {
+  let res = await autoLogList({ pageNum: 1, pageSize: 100, sysId: '2074416476136718337',  });
+  tableData.value = res.records.map(el=>{
+    return {
+      ...el,
+      // 将数字类型的报警等级映射为中文描述
+      // 101:低风险  102:一般风险  103:较大风险  104:重大风险  201:报警
+      alarmLevelC: el.alarmLevel == 101 ? '低风险' : el.alarmLevel == 102 ? '一般风险' : el.alarmLevel == 103 ? '较大风险' : el.alarmLevel == 104 ? '重大风险' : el.alarmLevel == 201 ? '报警' : '低风险'  
+    }
+  });
+}
+
+// 组件挂载后立即获取报警日志数据
+onMounted(() => {
+  getAlarmData();
+})
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+.alarm-monitor {
+  --image-card-bg: url('@/assets/images/home-container/configurable/hsq/1-7.png');
+  --image-card-bg1: url('@/assets/images/home-container/configurable/hsq/1-8.png');
+  position: relative;
+  width: 100%;
+  height: 100%;
+  padding: 10px;
+  box-sizing: border-box;
+
+  .alarm-top {
+    display: flex;
+    justify-content: space-around;
+    align-items: center;
+    width: calc(100% - 20px);
+    height: 25%;
+    background: var(--image-card-bg) no-repeat bottom;
+    background-size: 100% auto;
+    margin: 0px 10px;
+  }
+
+  .alarm-bot {
+    width: 100%;
+    height: 75%;
+  }
+
+  .card-item {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    width: 89px;
+    height: 49px;
+    background: var(--image-card-bg1) no-repeat;
+    background-size: 100% 100%;
+
+    &:nth-child(1) {
+      .item-value {
+        font-family: 'douyuFont';
+        color: #ff3d3d;
+      }
+    }
+
+    &:nth-child(2) {
+      .item-value {
+        font-family: 'douyuFont';
+        color: #ff983d;
+      }
+    }
+
+    &:nth-child(3) {
+      .item-value {
+        font-family: 'douyuFont';
+        color: #3dff69;
+      }
+    }
+  }
+}
+</style>

+ 69 - 0
src/views/vent/monitorManager/hsqHome/components/CommonBd.vue

@@ -0,0 +1,69 @@
+<template>
+  <div class="common-bd">
+    <div class="basic-bd-top">{{ title }}</div>
+    <div class="basic-bd-cen">
+      <slot></slot>
+    </div>
+    <div class="basic-bd-bot"></div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+
+let props = defineProps({
+  title: {
+    type: String,
+    default: ''
+  }
+});
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+.common-bd {
+  --image-box1-top: url('/@/assets/images/vent/box-top-bg.png');
+  --image-box1-bottom: url('/@/assets/images/vent/box-bottom-bg.png');
+  --container-image: linear-gradient(#3df6ff00, #3df6ff, #3df6ff00);
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .basic-bd-top {
+    display: flex;
+    align-items: center;
+   justify-content: center;
+    color: #fff;
+    font-weight: 700;
+
+    width: 100%;
+    height: 36px;
+    background: var(--image-box1-top) no-repeat;
+    background-size: 100% 100%;
+  }
+
+  .basic-bd-cen {
+    width: 100%;
+    height: calc(100% - 36px);
+    border-left-width: 1px;
+    border-left-style: solid;
+    border-right-width: 1px;
+    border-right-style: solid;
+    border-image-source: var(--container-image);
+    border-image-slice: 1;
+    border-image-repeat: stretch;
+  }
+
+  .basic-bd-bot {
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    width: 100%;
+    height: 36px;
+    background: var(--image-box1-bottom) no-repeat;
+    background-size: 100% 100%;
+  }
+
+}
+</style>

+ 246 - 0
src/views/vent/monitorManager/hsqHome/components/CommonTable.vue

@@ -0,0 +1,246 @@
+<template>
+  <div class="common-table">
+    <div class="table__content_label">
+      <div class="label-t" v-for="(item, index) in columns" :key="`svvhbcth-${index}`" :style="{ flexBasis }">{{
+        item.name }}</div>
+    </div>
+    <div ref="scrollRef" class="table__content_list">
+      <div class="table__content_list_row" v-for="(item, index) in tableData" :key="`svvhbct-${index}`">
+        <div v-for="(t, i) in columns" :key="`svvhbctr-${i}`" :style="{ flexBasis }" class="table__content__list_item">
+          <slot :name="t.prop" :scope="item">
+            <span v-if="t.prop == 'syswarnLevel'" style="display: flex; align-items: center;justify-content: center;">
+              <span :class="get(item, t.prop) ? 'icon-pie1' : 'icon-pie'">
+                <span :class="get(item, t.prop) ? 'icon-item1' : 'icon-item'"></span>
+              </span>
+              <span>{{ get(item, t.prop) ? '报警' : '正常' }}</span>
+            </span>
+            <span v-else-if="t.prop == 'netStatus'" style="display: flex; align-items: center;justify-content: center;">
+              <span :class="get(item, t.prop) ? 'icon-pie' : 'icon-pie1'">
+                <span :class="get(item, t.prop) ? 'icon-item' : 'icon-item1'"></span>
+              </span>
+              <span>{{ get(item, t.prop) ? '在线' : '离线' }}</span>
+            </span>
+            <span v-else-if="t.prop == 'alarmLevelC'"
+              :style="{ color: item.alarmLevelC == '低风险' ? '#00d8ff' : item.alarmLevelC == '一般风险' ? '#fcfc22' : item.alarmLevelC == '较大风险' ? '#ff7010' : item.alarmLevelC == '重大风险' ? '#df4e43' : item.alarmLevelC == '报警' ? '#ff0000' : '' }">{{
+                get(item, t.prop) }}</span>
+            <span v-else>{{ get(item, t.prop) }}</span>
+          </slot>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+import { useAutoScroll } from '/@/hooks/core/useAutoScroll';
+import _ from 'lodash';
+
+let props = defineProps({
+
+  columns: {
+    type: Array as any
+  },
+  autoScroll: {
+    type: Boolean,
+    default: false
+  },
+  tableData: {
+    type: Array as any
+  },
+  defaultValue: {
+    type: String,
+    default: ''
+  }
+})
+
+const scrollRef = ref(null);
+if (props.autoScroll) {
+  useAutoScroll(scrollRef);
+}
+
+const flexBasis = computed(() => {
+  return Math.fround(100 / props.columns.length) + '%';
+});
+
+/**
+ * 安全获取对象属性值,当值为 null/undefined/空字符串时返回默认值
+ *
+ * @param o 要访问的对象
+ * @param p 对象属性路径
+ * @returns 属性值或默认值
+ */
+function get(o, p) {
+  const d = _.get(o, p);
+  return _.isNil(d) ? props.defaultValue : d === '' ? props.defaultValue : d;
+}
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+.common-table {
+  --image-content-label: url('/@/assets/images/home-container/configurable/hsq/1-5.png');
+  --image-content-text: url('/@/assets/images/company/content-text.png');
+  --image-list-head: url('/@/assets/images/home-container/configurable/firehome/list-head.png');
+  --image-content-label-d: url(/@/assets/images/home-container/configurable/minehome/content-label.png);
+  --image-content-body-d: url('/@/assets/images/home-container/configurable/minehome/content-body.png');
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  position: relative;
+  width: 100%;
+  height: 100%;
+  padding: 10px 0px 0px 0px;
+  box-sizing: border-box;
+
+  .gallery-content {
+    position: absolute;
+
+    &:nth-child(1) {
+      left: 22px;
+      top: 4px;
+    }
+
+    &:nth-child(2) {
+      display: flex;
+      flex-direction: column;
+      align-items: flex-end;
+      right: 24px;
+      top: 4px;
+    }
+
+    &:nth-child(3) {
+      left: 22px;
+      top: 72px;
+    }
+
+    &:nth-child(4) {
+      display: flex;
+      flex-direction: column;
+      align-items: flex-end;
+      right: 24px;
+      top: 72px;
+    }
+
+    &:nth-child(5) {
+      left: 50%;
+      top: 50%;
+      transform: translate(-50%, -50%);
+    }
+
+    .gallery-content-text {
+      margin-bottom: 2px;
+    }
+
+    .gallery-content-text-r {
+      margin-bottom: 2px;
+    }
+
+    .gallery-content-text1 {
+      font-size: 24px;
+      font-family: 'douyuFont';
+    }
+
+    .gallery-content-value,
+    .gallery-content-value-r {
+      font-family: 'douyuFont';
+      color: #fff;
+    }
+
+  }
+
+  .table__content_label {
+    width: 400px;
+    height: 32px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    background-image: var(--image-content-label);
+    background-size: 100% 100%;
+    background-repeat: no-repeat;
+    color: #3df6ff;
+
+    .label-t {
+      text-align: center;
+      font-size: 14px;
+    }
+  }
+
+  .table__content_list {
+    height: calc(100% - 32px);
+    width: 400px;
+    display: flex;
+    flex-direction: column;
+    padding: 5px 0;
+    box-sizing: border-box;
+    overflow-y: auto;
+
+    .table__content_list_row {
+      width: 100%;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      color: #fff;
+      margin-bottom: 5px;
+      background-size: 100% auto;
+      background-repeat: no-repeat;
+      background-position: center bottom;
+      background-image: var(--image-content-text);
+
+      span {
+        display: inline-block;
+        text-align: center;
+      }
+    }
+  }
+
+  .table__content__list_item {
+    text-align: center;
+  }
+
+  .icon-pie {
+    position: relative;
+    width: 12px;
+    height: 12px;
+    border-radius: 50%;
+    background-color: rgba(79, 255, 173, .3);
+    margin-right: 5px;
+  }
+
+  .icon-pie1 {
+    position: relative;
+    width: 12px;
+    height: 12px;
+    border-radius: 50%;
+    background-color: rgba(255, 79, 79, .3);
+    margin-right: 5px;
+  }
+
+  .icon-item {
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    width: 6px;
+    height: 6px;
+    border-radius: 50%;
+    background-color: rgba(79, 255, 173);
+  }
+
+  .icon-item1 {
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    width: 6px;
+    height: 6px;
+    border-radius: 50%;
+    background-color: rgba(255, 79, 79);
+  }
+
+  ::-webkit-scrollbar {
+    display: none;
+  }
+}
+</style>

Plik diff jest za duży
+ 364 - 0
src/views/vent/monitorManager/hsqHome/components/CustomChart.vue


+ 136 - 0
src/views/vent/monitorManager/hsqHome/components/CustomGalleryNew.vue

@@ -0,0 +1,136 @@
+<template>
+  <div class="custom-gallery-new">
+    <div class="custom-top">
+      <div class="gallery-new-box">
+        <div class="gallery-content" v-for="(item, index) in option" :key="index">
+          <div :class="index % 2 == 0 ? 'gallery-content-text' : 'gallery-content-text-r'">{{ item.label }}</div>
+          <div :class="index % 2 == 0 ? 'gallery-content-value' : 'gallery-content-value-r'">{{ galleryData ?
+            galleryData[item.value] : 0 }}</div>
+        </div>
+        <div class="gallery-content">
+          <SvgIcon class="icon-style2" size="30" name="device-status" />
+        </div>
+      </div>
+    </div>
+    <div class="custom-bottom">
+      <CommonTable :columns="deviceColumns" :table-data="tableData"></CommonTable>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, onMounted, ref } from 'vue';
+import { SvgIcon } from '/@/components/Icon';
+import CommonTable from './CommonTable.vue';
+import { deviceColumns } from '../hsqHome.data.js';
+
+let props = defineProps({
+  option: {
+    type: Array as any
+  },
+  galleryData: {
+    type: Object
+  },
+  tableData: {
+    type: Array as any
+  },
+})
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+.custom-gallery-new {
+  --image-gallery-bg: url('@/assets/images/home-container/configurable/dusthome/gallery-bg.png');
+  --image-gallery-bg-b: url('@/assets/images/home-container/configurable/dusthome/gallery-bg-b.png');
+  --image-content-label: url('/@/assets/images/home-container/configurable/hsq/1-5.png');
+  --image-content-text: url('/@/assets/images/company/content-text.png');
+  --image-list-head: url('/@/assets/images/home-container/configurable/firehome/list-head.png');
+  --image-content-label-d: url(/@/assets/images/home-container/configurable/minehome/content-label.png);
+  --image-content-body-d: url('/@/assets/images/home-container/configurable/minehome/content-body.png');
+  position: relative;
+  width: 100%;
+  height: 100%;
+  padding: 10px;
+  box-sizing: border-box;
+
+  .custom-top {
+    width: 100%;
+    height: 40%;
+  }
+
+  .custom-bottom {
+    width: 100%;
+    height: 60%;
+    box-sizing: border-box;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+  }
+
+  .gallery-new-box {
+    position: relative;
+    width: 100%;
+    height: 100%;
+    background: var(--image-gallery-bg) no-repeat;
+    background-size: 100% 100%;
+  }
+
+  .gallery-content {
+    position: absolute;
+
+    &:nth-child(1) {
+      left: 22px;
+      top: 4px;
+    }
+
+    &:nth-child(2) {
+      display: flex;
+      flex-direction: column;
+      align-items: flex-end;
+      right: 24px;
+      top: 4px;
+    }
+
+    &:nth-child(3) {
+      left: 22px;
+      top: 72px;
+    }
+
+    &:nth-child(4) {
+      display: flex;
+      flex-direction: column;
+      align-items: flex-end;
+      right: 24px;
+      top: 72px;
+    }
+
+    &:nth-child(5) {
+      left: 50%;
+      top: 50%;
+      transform: translate(-50%, -50%);
+    }
+
+    .gallery-content-text {
+      margin-bottom: 2px;
+    }
+
+    .gallery-content-text-r {
+      margin-bottom: 2px;
+    }
+
+    .gallery-content-text1 {
+      font-size: 24px;
+      font-family: 'douyuFont';
+    }
+
+    .gallery-content-value,
+    .gallery-content-value-r {
+      font-family: 'douyuFont';
+      color: #fff;
+    }
+
+  }
+
+}
+</style>

+ 146 - 87
src/views/vent/home/configurable/components/preset/LongList1.vue → src/views/vent/monitorManager/hsqHome/components/DeviceCenter.vue

@@ -3,11 +3,13 @@
     <div class="list-title">
       <div class="title-l">
         <span>设备详情-</span>
-        <span style="margin-left: 5px;">{{ deviceModel }}</span>
+        <span style="margin-left: 5px;">{{ detailDatas.strserno }}</span>
       </div>
       <div class="title-r">
-        <span class="icon-pie"></span>
-        <span>报警中</span>
+        <span :class="detailDatas.syswarnLevel ? 'icon-pie1' : 'icon-pie'">
+          <span :class="detailDatas.syswarnLevel ? 'pie-item1' : 'pie-item'"></span>
+        </span>
+        <span>{{ detailDatas.syswarnLevel ? '报警' : '正常' }}</span>
       </div>
     </div>
     <div class="basic-box">
@@ -16,37 +18,37 @@
           <div class="card-t">
             <div class="card-item">
               <div class="label-text">设备编号</div>
-              <div class="value-text">{{ cardData.deviceCode }}</div>
+              <div class="value-text">{{ detailDatas.strserno || '-' }}</div>
             </div>
             <div class="card-item">
               <div class="label-text">设备名称</div>
-              <div class="value-text">{{ cardData.deviceName }}</div>
+              <div class="value-text">{{ detailDatas.strname || '-' }}</div>
             </div>
             <div class="card-item">
               <div class="label-text">设备类型</div>
-              <div class="value-text">{{ cardData.deviceType }}</div>
+              <div class="value-text">{{ detailDatas.typeName || '-' }}</div>
             </div>
             <div class="card-item">
               <div class="label-text">安装位置</div>
-              <div class="value-text">{{ cardData.address }}</div>
+              <div class="value-text">{{ detailDatas.strinstallpos || '-' }}</div>
             </div>
           </div>
           <div class="card-b">
             <div class="card-item">
               <div class="label-text">安装时间</div>
-              <div class="value-text">{{ cardData.time }}</div>
+              <div class="value-text">{{ detailDatas.readTime || '-' }}</div>
             </div>
             <div class="card-item">
               <div class="label-text">生产厂家</div>
-              <div class="value-text">{{ cardData.company }}</div>
+              <div class="value-text">{{ detailDatas.manufacturer || '-' }}</div>
             </div>
             <div class="card-item">
               <div class="label-text">Ip地址</div>
-              <div class="value-text">{{ cardData.ip }}</div>
+              <div class="value-text">{{ detailDatas.ip || '-' }}</div>
             </div>
             <div class="card-item">
               <div class="label-text">固件版本</div>
-              <div class="value-text">{{ cardData.version }}</div>
+              <div class="value-text">{{ detailDatas.version || '-' }}</div>
             </div>
           </div>
         </div>
@@ -59,14 +61,14 @@
             <div class="card-item">
               <SvgIcon class="icon-style" size="20" name="yxzt" />
               <div class="label-status-text">运行状态</div>
-              <div :class="statusData.runstatus == '报警' ? 'value-status-warn' : 'value-status-text'">{{
-                statusData.runstatus }}</div>
+              <div :class="detailDatas.netStatus == 0 ? 'value-status-warn' : 'value-status-text'">{{
+                detailDatas.netStatus==1 ? '在线' : detailDatas.status==0 ? '离线' : '-' }}</div>
             </div>
             <div class="card-item">
               <SvgIcon class="icon-style" size="20" name="wlyc" />
               <div class="label-status-text">网络延迟</div>
               <div class="value-status-text">
-                <span>{{ statusData.internet }}</span>
+                <span>{{ detailDatas.wlyc || '-' }}</span>
                 <span>ms</span>
               </div>
             </div>
@@ -74,7 +76,7 @@
               <SvgIcon class="icon-style" size="20" name="spml" />
               <div class="label-status-text">视频码率</div>
               <div class="value-status-text">
-                <sapn>{{ statusData.videocode }}</sapn>
+                <sapn>{{ detailDatas.spml || '-' }}</sapn>
                 <sapn>Mbps</sapn>
               </div>
             </div>
@@ -85,7 +87,7 @@
               <SvgIcon class="icon-style" size="20" name="sswd" />
               <div class="label-status-text">实时温度</div>
               <div class="value-status-text">
-                <span> {{ statusData.temp }}</span>
+                <span> {{ detailDatas.temperature || '-' }}</span>
                 <span> ℃</span>
 
               </div>
@@ -93,12 +95,12 @@
             <div class="card-item">
               <SvgIcon class="icon-style" size="20" name="zl" />
               <div class="label-status-text">帧率</div>
-              <div class="value-status-text">{{ statusData.framerate }}</div>
+              <div class="value-status-text">{{ detailDatas.zl || '-' }}</div>
             </div>
             <div class="card-item">
               <SvgIcon class="icon-style" size="20" name="csb" />
               <div class="label-status-text">传输比</div>
-              <div class="value-status-text">{{ statusData.ratio }}</div>
+              <div class="value-status-text">{{ detailDatas.csb || '-' }}</div>
             </div>
           </div>
         </div>
@@ -108,24 +110,13 @@
       <basicBorder title="历史报警记录">
         <div class="basic-history">
           <div class="history-title">
-            <div class="title-item" v-for="(item, index) in titleList" :key="index">{{ item.label }}</div>
+            <div class="title-item" v-for="(item, index) in alarmColumns" :key="index">{{ item.name }}</div>
           </div>
           <div class="history-content">
             <div class="content-item" v-for="(item, index) in tableData" :key="index">
-              <div class="item-text">{{ item.time }}</div>
-              <div class="item-text item-text1">
-                <span>{{ item.temp }}</span>
-                <span>℃</span>
-              </div>
-              <div class="item-text">
-                <span> {{ item.durTime }}</span>
-                <span>min</span>
-              </div>
-              <div class="item-text item-text1">{{ item.grade }}</div>
-              <div class="item-text item-text2">{{ item.status }}</div>
-              <div class="item-text">{{ item.person }}</div>
-              <div class="item-text">
-                <span class="text-look">查看</span>
+              <div class="item-text" v-for="(ite,ind) in alarmColumns" :key="ind">
+                <div v-if="ite.prop=='alarmLevelC'"  :style="{ color: item.alarmLevelC == '低风险' ? '#00d8ff' : item.alarmLevelC == '一般风险' ? '#fcfc22' : item.alarmLevelC == '较大风险' ? '#ff7010' : item.alarmLevelC == '重大风险' ? '#df4e43' : item.alarmLevelC == '报警' ? '#ff0000' : '' }">{{item[ite.prop]  }}</div>
+                <div v-else>{{ item[ite.prop] }}</div>
               </div>
             </div>
           </div>
@@ -136,53 +127,64 @@
 </template>
 
 <script setup lang="ts">
-import { reactive, ref } from 'vue'
-import basicBorder from '../basicBorder.vue'
+import { onUnmounted, reactive, ref, watch, onMounted } from 'vue'
+import basicBorder from './basicBorder.vue'
 import { SvgIcon } from '/@/components/Icon';
-
-let deviceModel = ref('CAM-001')
-let cardData = reactive({
-  deviceCode: 'CAM-001',
-  deviceName: '双光谱摄像机',
-  deviceType: '双光谱热成像',
-  address: '采掘场A区',
-  time: '2024-06-15',
-  company: 'xxx',
-  ip: '192.168.10.13',
-  version: 'v2.4.1',
+import { autoLogList } from '../hsqHome.api.js'
+import {alarmColumns} from '../hsqHome.data.js'
+
+let props = defineProps({
+  detailData: {
+    type: Object,
+    default: () => { },
+  },
 })
-let statusData = reactive({
-  runstatus: '报警',
-  internet: '12',
-  videocode: '3',
-  temp: '65.5',
-  framerate: 'xxx',
-  ratio: 'xxxx',
-})
-let titleList = ref<any[]>([
-  { label: '时间', value: '1' },
-  { label: '最高温度', value: '2' },
-  { label: '持续时间', value: '3' },
-  { label: '报警级别', value: '4' },
-  { label: '处理状态', value: '5' },
-  { label: '处理人', value: '6' },
-  { label: '操作', value: '7' },
-])
-let tableData = ref<any[]>([
-  { time: '14:31:22', temp: 65.3, durTime: 15, grade: '一级', status: '未处理', person: '张三', },
-  { time: '14:31:22', temp: 65.3, durTime: 15, grade: '一级', status: '未处理', person: '张三', },
-  { time: '14:31:22', temp: 65.3, durTime: 15, grade: '一级', status: '未处理', person: '张三', },
-  { time: '14:31:22', temp: 65.3, durTime: 15, grade: '一级', status: '未处理', person: '张三', },
-  { time: '14:31:22', temp: 65.3, durTime: 15, grade: '一级', status: '未处理', person: '张三', },
-  { time: '14:31:22', temp: 65.3, durTime: 15, grade: '一级', status: '未处理', person: '张三', },
-  { time: '14:31:22', temp: 65.3, durTime: 15, grade: '一级', status: '未处理', person: '张三', },
-  { time: '14:31:22', temp: 65.3, durTime: 15, grade: '一级', status: '未处理', person: '张三', },
-  { time: '14:31:22', temp: 65.3, durTime: 15, grade: '一级', status: '未处理', person: '张三', },
-  { time: '14:31:22', temp: 65.3, durTime: 15, grade: '一级', status: '未处理', person: '张三', },
-])
 
-</script>
+let detailDatas = ref<any>({})
+let tableData = ref<any[]>([])
+// https获取监测数据
+let timer: null | NodeJS.Timeout = null;
+
+/**
+ * 定时获取监测数据
+ * 通过定时器循环调用数据获取方法,更新表格数据
+ *
+ * @param flag - 是否立即执行(首次调用时传true跳过延时)
+ */
+function getMonitor(flag?: boolean) {
+  timer = setTimeout(async () => {
+    await getAutoLogList();
+
+    if (timer) {
+      timer = null;
+    }
+    getMonitor();
+  }, flag ? 0 : 30000);
+}
+
+async function getAutoLogList() {
+  let res = await autoLogList({ pageNum: 1, pageSize: 100, sysId: '2074416476136718337', });
+  tableData.value = res.records.map(el => {
+    return {
+      ...el,
+      alarmLevelC: el.alarmLevel == 101 ? '低风险' : el.alarmLevel == 102 ? '一般风险' : el.alarmLevel == 103 ? '较大风险' : el.alarmLevel == 104 ? '重大风险' : el.alarmLevel == 201 ? '报警' : '低风险'
+    }
+  });
+}
+
+watch(() => props.detailData, (newVal, oldVal) => {
+  detailDatas.value =Object.assign({},newVal.readData,newVal,)
+}, { immediate: true })
 
+onMounted(() => {
+  getMonitor(true);
+});
+onUnmounted(() => {
+  if (timer) {
+    clearTimeout(timer);
+  }
+});
+</script>
 <style lang="less" scoped>
 @import '/@/design/theme.less';
 
@@ -225,17 +227,52 @@ let tableData = ref<any[]>([
 
   .title-r {
     padding-right: 16px;
+    display: flex;
+    align-items: center;
   }
 
   .icon-pie {
     display: inline-block;
-    width: 10px;
-    height: 10px;
+    position: relative;
+    width: 14px;
+    height: 14px;
+    border-radius: 50%;
+    background-color: rgba(79, 255, 173, .3);
+    margin-right: 5px;
+  }
+
+  .pie-item {
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    width: 7px;
+    height: 7px;
+    border-radius: 50%;
+    background-color: rgba(79, 255, 173);
+  }
+
+  .icon-pie1 {
+    display: inline-block;
+    position: relative;
+    width: 14px;
+    height: 14px;
     border-radius: 50%;
-    background-color: #fc002a;
+    background-color: rgba(255, 0, 42, .3);
     margin-right: 5px;
   }
 
+  .pie-item1 {
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    width: 7px;
+    height: 7px;
+    border-radius: 50%;
+    background-color: rgba(255, 0, 42);
+  }
+
   .basic-box {
     height: 180px;
     margin-bottom: 10px;
@@ -258,16 +295,25 @@ let tableData = ref<any[]>([
       display: flex;
       justify-content: space-between;
       align-items: center;
-      width: 25%;
+      width: calc(25% - 10px);
       height: 100%;
-      padding: 0px 40px;
+      // padding: 0px 40px;
+      margin: 0 5px;
+      padding: 0px 24px;
 
       &:nth-child(odd) {
         background: var(--image-box-bg1) no-repeat center;
+        background-size: 100% auto;
       }
 
       &:nth-child(even) {
         background: var(--image-box-bg2) no-repeat center;
+        background-size: 100% auto;
+      }
+
+      .value-text {
+        width: 100px;
+        text-align: right;
       }
     }
   }
@@ -306,16 +352,25 @@ let tableData = ref<any[]>([
       display: flex;
       justify-content: space-between;
       align-items: center;
-      width: 25%;
+      width: calc(25% - 10px);
       height: 100%;
-      padding: 0px 40px;
+      // padding: 0px 40px;
+      margin: 0px 5px;
+      padding: 0px 24px;
 
       &:nth-child(even) {
         background: var(--image-box-bg1) no-repeat center;
+        background-size: 100% auto;
       }
 
       &:nth-child(odd) {
         background: var(--image-box-bg2) no-repeat center;
+        background-size: 100% auto;
+      }
+
+      .value-text {
+        width: 100px;
+        text-align: right;
       }
     }
   }
@@ -424,19 +479,23 @@ let tableData = ref<any[]>([
     justify-content: center;
     align-items: center;
   }
-  .item-text1{
+
+  .item-text1 {
     color: #fc002a;
   }
-   .item-text2{
+
+  .item-text2 {
     color: orange;
   }
-  .text-look{
+
+  .text-look {
     padding: 0px 5px;
     border-radius: 2px;
     background-color: #2484bc;
     cursor: pointer;
   }
-   ::-webkit-scrollbar{
+
+  ::-webkit-scrollbar {
     display: none;
   }
 }

+ 59 - 13
src/views/vent/home/configurable/components/preset/LongList.vue → src/views/vent/monitorManager/hsqHome/components/DeviceLeft.vue

@@ -1,4 +1,3 @@
-
 <template>
   <div class="long-list">
     <div class="list-title">
@@ -15,7 +14,8 @@
             :key="index" @click="changeNav(item, index)">{{ item.label }}</div>
         </div>
         <div class="content-box">
-          <basicDevice v-for="(item,index) in 10" :key="index"></basicDevice>
+          <basicDevice v-for="(item, index) in listData" :key="index" :deviceData="item" @detail="handlerDetail">
+          </basicDevice>
         </div>
       </div>
     </div>
@@ -24,9 +24,12 @@
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue'
-import basicDevice from '../basicDevice.vue'
+import { onMounted, onUnmounted, ref } from 'vue'
+import basicDevice from './basicDevice.vue'
+import { managesysList, monitorSystem } from '../hsqHome.api.js'
 
+//场景ID
+let systemId = ref('')
 //设备列表数量
 let count = ref(0)
 //搜索条件
@@ -34,20 +37,61 @@ let searchData = ref('')
 //当前激活nav选项
 let activeIndex = ref(0)
 let navList = ref<any[]>([
-  { label: '全部', value: '0' },
-  { label: 'xxx', value: '1' },
-  { label: 'xxx', value: '2' },
-  { label: 'xxx', value: '3' },
-  { label: 'xxx', value: '4' },
-  { label: 'xxx', value: '5' },
+  { label: '光谱摄像机', value: '0' },
 ])
+let listData = ref<any[]>([])
+let $emit = defineEmits(['details'])
+// https获取监测数据
+let timer: null | NodeJS.Timeout = null;
+
+/**
+ * 定时获取监测数据
+ * 通过定时器循环调用数据获取方法,更新表格数据
+ *
+ * @param flag - 是否立即执行(首次调用时传true跳过延时)
+ */
+function getMonitor(flag?: boolean) {
+  timer = setTimeout(async () => {
+    await getData()
+    if (timer) {
+      timer = null;
+    }
+    getMonitor();
+  }, flag ? 0 : 30000);
+}
 
 //nav选项切换
 function changeNav(item, index) {
   activeIndex.value = index
 }
-</script>
 
+async function getData() {
+  const res = await monitorSystem({ type: 'all', systemID: systemId.value, devicetype: '' });
+  console.log(res, '设备列表数据')
+  listData.value = res.deviceInfo.duaSpeCamera.datalist || [];
+  count.value = res.deviceInfo.duaSpeCamera.datalist.length;
+}
+
+function handlerDetail(item) {
+  $emit('details', item)
+}
+
+async function getManagesysList() {
+  const res = await managesysList({ strtype: 'sys_openair_fire', pagetype: 'normal' });
+  if (res && res.records) {
+    systemId.value = res.records[0].id
+  }
+}
+onMounted(async () => {
+  await getManagesysList()
+  getMonitor(true)
+})
+onUnmounted(() => {
+  if (timer) {
+    clearTimeout(timer)
+  }
+})
+</script>
 <style lang="less" scoped>
 @import '/@/design/theme.less';
 
@@ -119,7 +163,8 @@ function changeNav(item, index) {
     background-color: #1d73a8;
     border-bottom: 2px solid #36c7ff;
   }
-  .content-box{
+
+  .content-box {
     height: calc(100% - 42px);
     overflow-y: auto;
   }
@@ -136,7 +181,8 @@ function changeNav(item, index) {
   .zxm-input-sm {
     padding: 0px 20px;
   }
-  ::-webkit-scrollbar{
+
+  ::-webkit-scrollbar {
     display: none;
   }
 }

+ 46 - 44
src/views/vent/home/configurable/components/preset/LongList2.vue → src/views/vent/monitorManager/hsqHome/components/DeviceRight.vue

@@ -9,27 +9,27 @@
           :key="index" @click="changeNav(item, index)">{{ item.label }}</div>
       </div>
       <div class="basic-box">
-        <basicBorder title="【温度报警阈值】">
+        <basicBorder title="【设备基本信息】">
           <div class="temp-warn">
             <div class="warn-item">
-              <div class="item-label">一级报警温度 : </div>
-              <a-input class="item-input" v-model:value="formData.tempOne" placeholder="请输入" size="small" />
+              <div class="item-label">安装位置 : </div>
+              <a-input class="item-input" v-model:value="formData.strinstallpos" placeholder="请输入" size="small" />
             </div>
             <div class="warn-item">
-              <div class="item-label">二级报警温度 : </div>
-              <a-input class="item-input" v-model:value="formData.tempTwo" placeholder="请输入" size="small" />
+              <div class="item-label">设备编码 : </div>
+              <a-input class="item-input" v-model:value="formData.strserno" placeholder="请输入" size="small" />
             </div>
             <div class="warn-item">
-              <div class="item-label">三级报警温度 : </div>
-              <a-input class="item-input" v-model:value="formData.tempThree" placeholder="请输入" size="small" />
+              <div class="item-label">生产厂家 : </div>
+              <a-input class="item-input" v-model:value="formData.manufacturer" placeholder="请输入" size="small" />
             </div>
             <div class="warn-item">
-              <div class="item-label">温升速率阈值 : </div>
-              <a-input class="item-input" v-model:value="formData.tempMax" placeholder="请输入" size="small" />
+              <div class="item-label">坐标x : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_east" placeholder="请输入" size="small" />
             </div>
             <div class="warn-item">
-              <div class="item-label">持续时间 : </div>
-              <a-input class="item-input" v-model:value="formData.time" placeholder="请输入" size="small" />
+              <div class="item-label">坐标y : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
             </div>
           </div>
         </basicBorder>
@@ -40,41 +40,41 @@
             <div class="warn-item">
               <div class="item-basic">
                 <div class="item-label">亮度 : </div>
-                <a-input class="item-input" v-model:value="formData.tempOne" placeholder="请输入" size="small" />
+                <a-input class="item-input" v-model:value="formData.x" placeholder="请输入" size="small" />
               </div>
               <div class="item-basic">
                 <div class="item-label">对比度 : </div>
-                <a-input class="item-input" v-model:value="formData.tempOne" placeholder="请输入" size="small" />
+                <a-input class="item-input" v-model:value="formData.x" placeholder="请输入" size="small" />
               </div>
             </div>
             <div class="warn-item">
               <div class="item-basic">
                 <div class="item-label">饱和度 : </div>
-                <a-input class="item-input" v-model:value="formData.tempOne" placeholder="请输入" size="small" />
+                <a-input class="item-input" v-model:value="formData.x" placeholder="请输入" size="small" />
               </div>
               <div class="item-basic">
                 <div class="item-label">锐度 : </div>
-                <a-input class="item-input" v-model:value="formData.tempOne" placeholder="请输入" size="small" />
+                <a-input class="item-input" v-model:value="formData.x" placeholder="请输入" size="small" />
               </div>
             </div>
             <div class="warn-item">
               <div class="item-basic">
                 <div class="item-label">色温 : </div>
-                <a-input class="item-input" v-model:value="formData.tempOne" placeholder="请输入" size="small" />
+                <a-input class="item-input" v-model:value="formData.x" placeholder="请输入" size="small" />
               </div>
               <div class="item-basic">
                 <div class="item-label">增益 : </div>
-                <a-input class="item-input" v-model:value="formData.tempOne" placeholder="请输入" size="small" />
+                <a-input class="item-input" v-model:value="formData.x" placeholder="请输入" size="small" />
               </div>
             </div>
             <div class="warn-item">
               <div class="item-basic">
                 <div class="item-label">曝光 : </div>
-                <a-input class="item-input" v-model:value="formData.tempOne" placeholder="请输入" size="small" />
+                <a-input class="item-input" v-model:value="formData.x" placeholder="请输入" size="small" />
               </div>
               <div class="item-basic">
                 <div class="item-label">白平衡 : </div>
-                <a-input class="item-input" v-model:value="formData.tempOne" placeholder="请输入" size="small" />
+                <a-input class="item-input" v-model:value="formData.x" placeholder="请输入" size="small" />
               </div>
             </div>
           </div>
@@ -86,41 +86,41 @@
             <div class="warn-item">
               <div class="item-basic">
                 <div class="item-label1">声光报警器联动 : </div>
-                <a-switch v-model:checked="formData.checked" />
+                <a-switch v-model:checked="formData.x" />
               </div>
               <div class="item-basic">
                 <div class="item-label1">短信通知联动 : </div>
-                <a-switch v-model:checked="formData.checked" />
+                <a-switch v-model:checked="formData.x" />
               </div>
             </div>
             <div class="warn-item">
               <div class="item-basic">
                 <div class="item-label1">视频录制联动 : </div>
-                <a-switch v-model:checked="formData.checked" />
+                <a-switch v-model:checked="formData.x" />
               </div>
               <div class="item-basic">
                 <div class="item-label1">消防系统联动 : </div>
-                <a-switch v-model:checked="formData.checked" />
+                <a-switch v-model:checked="formData.x" />
               </div>
             </div>
             <div class="warn-item">
               <div class="item-basic">
                 <div class="item-label1">应急广播联动 : </div>
-                <a-switch v-model:checked="formData.checked" />
+                <a-switch v-model:checked="formData.x" />
               </div>
               <div class="item-basic">
                 <div class="item-label1">大屏显示联动 : </div>
-                <a-switch v-model:checked="formData.checked" />
+                <a-switch v-model:checked="formData.x" />
               </div>
             </div>
             <div class="warn-item">
               <div class="item-basic">
                 <div class="item-label1">GIS定位联动 : </div>
-                <a-switch v-model:checked="formData.checked" />
+                <a-switch v-model:checked="formData.x" />
               </div>
               <div class="item-basic">
                 <div class="item-label1">数据记录联动 : </div>
-                <a-switch v-model:checked="formData.checked" />
+                <a-switch v-model:checked="formData.x" />
               </div>
             </div>
           </div>
@@ -137,32 +137,33 @@
 </template>
 
 <script setup lang="ts">
-import { reactive, ref } from 'vue'
-import basicBorder from '../BasicBorder.vue'
+import { reactive, ref, watch } from 'vue'
+import basicBorder from './basicBorder.vue'
+
+let props = defineProps({
+  detailData: {
+    type: Object,
+    default: () => { },
+  },
+})
 
 //当前激活nav选项
 let activeIndex = ref(0)
 let navList = ref<any[]>([
-  { label: '报警阈值', value: '0' },
-  { label: 'xxx', value: '1' },
-  { label: 'xxx', value: '2' },
-  { label: 'xxx', value: '3' },
-  { label: 'xxx', value: '4' },
-  { label: 'xxx', value: '5' },
+  { label: '光谱摄像机', value: '0' },
 ])
-let formData = reactive({
-  tempOne: '',
-  tempTwo: '',
-  tempThree: '',
-  tempMax: '',
-  time: '',
-  checked: true
-})
+
+let formData = ref<any>({})
 
 //nav选项切换
 function changeNav(item, index) {
   activeIndex.value = index
 }
+
+watch(() => props.detailData, (newVal, oldVal) => {
+  console.log(newVal,'9900')
+  formData.value =Object.assign({},newVal.readData,newVal,)
+}, { immediate: true })
 </script>
 
 <style lang="less" scoped>
@@ -308,7 +309,8 @@ function changeNav(item, index) {
     height: 100%;
     background-color: rgba(32, 166, 169);
   }
-   ::-webkit-scrollbar{
+
+  ::-webkit-scrollbar {
     display: none;
   }
 }

+ 6 - 20
src/views/vent/home/configurable/components/preset/BtnListNew.vue → src/views/vent/monitorManager/hsqHome/components/EnvironmentMonitor.vue

@@ -1,9 +1,9 @@
 <template>
-  <div class="BtnListNew">
+  <div class="environ-box">
     <div class="basic-btn" v-for="(item, index) in option" :key="index">
       <div class="btn-label">{{ item.label }}</div>
       <div class="btn-value">
-        <div class="text-value">{{ data[item.value] }}</div>
+        <div class="text-value">{{ environData[item.value] }}</div>
         <div class="text-value unit-value">{{ item.unit }}</div>
       </div>
     </div>
@@ -11,28 +11,16 @@
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue'
+import { ref } from 'vue';
 
 let props = defineProps({
   option: {
     type: Array as any
   },
-  data: {
+ environData: {
     type: Object,
     default: () => {
-      return {
-        tempHj: '',
-        fsfx: '',
-        temp: '',
-        coval: '',
-        co2val: '',
-        o2val: '',
-        ch4val: '',
-        fcnd: '',
-        ywzs: '',
-        tempDb: '',
-
-      }
+      return {}
     }
   }
 })
@@ -41,9 +29,7 @@ let props = defineProps({
 <style lang="less" scoped>
 @import '/@/design/theme.less';
 
-@{theme-deepblue} {}
-
-.BtnListNew {
+.environ-box {
   --image-btn-bg: url('@/assets/images/home-container/configurable/hsq/1-9.png');
   display: flex;
   flex-wrap: wrap;

+ 263 - 0
src/views/vent/monitorManager/hsqHome/components/LinkLogPanel.vue

@@ -0,0 +1,263 @@
+<template>
+  <div class="search-table">
+    <div class="list-title">
+      <span>联动日志</span>
+    </div>
+    <div class="search-area">
+      <div class="title-top">
+        <a-input v-model:value="searchWarn" placeholder="搜索" size="small" class="zxm-input zxm-input-sm" />
+        <div class="search-btn">
+          <div class="btn-item">筛选</div>
+        </div>
+      </div>
+    </div>
+
+    <div class="time-select">
+      <span class="span">时间范围:</span>
+      <div
+        class="btn"
+        :class="{ active: timeType === item.value }"
+        v-for="item in timeOptions"
+        :key="item.value"
+        @click="timeType = item.value"
+      >
+        {{ item.label }}
+      </div>
+    </div>
+    <div class="content-area">
+      <div class="content-title">
+        <div class="title-item col-time">时间</div>
+        <div class="title-item col-rule">规则</div>
+        <div class="title-item col-grade">动作</div>
+        <div class="title-item col-status">说明</div>
+      </div>
+      <div class="history-content">
+        <div class="content-item" v-for="(item, index) in tableData" :key="index">
+          <div class="item-text col-time">{{ item.time }}</div>
+          <div class="item-text col-rule">{{ item.rule }}</div>
+          <div class="item-text col-grade item-text2">{{ item.grade }}</div>
+          <div class="item-text col-status item-text1">{{ item.status }}</div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+
+interface ILogItem {
+  time: string;
+  rule: string;
+  grade: string;
+  status: string;
+}
+
+interface ITimeOption {
+  label: string;
+  value: number;
+}
+
+const searchWarn = ref('');
+const timeType = ref(1);
+
+const timeOptions: ITimeOption[] = [
+  { label: '今日', value: 1 },
+  { label: '近三天', value: 2 },
+  { label: '近七天', value: 3 },
+  { label: '自定义', value: 4 },
+];
+
+const tableData = ref<ILogItem[]>([
+  { time: '14:31:22', rule: '001', grade: '触发', status: '温度65.3℃超过阈值' },
+  { time: '14:31:22', rule: '001', grade: '触发', status: '温度65.3℃超过阈值' },
+  { time: '14:31:22', rule: '001', grade: '触发', status: '温度65.3℃超过阈值' },
+  { time: '14:31:22', rule: '001', grade: '触发', status: '温度65.3℃超过阈值' },
+  { time: '14:31:22', rule: '001', grade: '触发', status: '温度65.3℃超过阈值' },
+  { time: '14:31:22', rule: '001', grade: '触发', status: '温度65.3℃超过阈值' },
+  { time: '14:31:22', rule: '001', grade: '触发', status: '温度65.3℃超过阈值' },
+  { time: '14:31:22', rule: '001', grade: '触发', status: '温度65.3℃超过阈值' },
+  { time: '14:31:22', rule: '001', grade: '触发', status: '温度65.3℃超过阈值' },
+]);
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+.search-table {
+  --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-5.png');
+  --image-box-bg1: url('@/assets/images/home-container/configurable/hsq/2-6.png');
+  --image-box-bg2: url('@/assets/images/home-container/configurable/hsq/2-24.png');
+  position: relative;
+  width: 100%;
+  height: 100%;
+  padding: 15px;
+  box-sizing: border-box;
+}
+
+.list-title {
+  width: 177px;
+  height: 30px;
+  line-height: 22px;
+  color: #01fefc;
+  font-weight: bolder;
+  background: var(--image-box-bg) no-repeat;
+  background-size: 80% 100%;
+  margin-bottom: 5px;
+}
+
+.search-area {
+  margin-bottom: 5px;
+}
+
+.title-top {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.search-btn {
+  width: 85px;
+  height: 30px;
+  border: 1px solid #01fefc;
+  border-radius: 4px;
+  padding: 3px;
+  cursor: pointer;
+  flex-shrink: 0;
+}
+
+.time-select {
+  display: flex;
+  align-items: center;
+  padding-left: 10px;
+  margin-bottom: 8px;
+  gap: 6px;
+  white-space: nowrap;
+
+  .span {
+    color: #fff;
+    font-size: 13px;
+  }
+
+  .btn {
+    padding: 3px 8px;
+    background: #114268;
+    border: 1px solid transparent;
+    border-radius: 4px;
+    color: #fff;
+    cursor: pointer;
+    margin-right: 4px;
+    font-size: 13px;
+    white-space: nowrap;
+    transition: all 0.2s;
+
+    &.active {
+      background-color: #185f8e;
+      border-color: #2084c0;
+    }
+  }
+}
+
+.btn-item {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(32, 166, 169);
+}
+
+.content-area {
+  height: calc(100% - 120px);
+}
+
+.content-title {
+  display: flex;
+  align-items: center;
+  height: 34px;
+  background: var(--image-box-bg2) no-repeat;
+  background-size: 100% 100%;
+  margin-bottom: 6px;
+}
+
+.title-item {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  color: #01fefc;
+}
+
+.history-content {
+  height: calc(100% - 40px);
+  overflow-y: auto;
+
+  &::-webkit-scrollbar {
+    display: none;
+  }
+}
+
+.content-item {
+  display: flex;
+  align-items: center;
+  height: 36px;
+
+  &:nth-child(odd) {
+    background-color: #0e3455;
+  }
+
+  &:nth-child(even) {
+    background-color: #114268;
+  }
+}
+
+.item-text {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.col-time {
+  width: 90px;
+  flex-shrink: 0;
+}
+
+.col-rule {
+  width: 70px;
+  flex-shrink: 0;
+}
+
+.col-grade {
+  width: 70px;
+  flex-shrink: 0;
+}
+
+.col-status {
+  flex: 1;
+  padding: 0 10px;
+  justify-content: center;
+}
+
+.item-text1 {
+  color: #fc002a;
+}
+
+.item-text2 {
+  color: orange;
+}
+
+.zxm-input {
+  height: 42px;
+  color: #fff;
+  background-color: transparent;
+  border: none;
+  background: var(--image-box-bg1) no-repeat;
+  background-size: 100% 100%;
+}
+
+.zxm-input-sm {
+  padding: 0 20px;
+}
+</style>

+ 162 - 62
src/views/vent/home/configurable/components/preset/linkRuleEdit.vue → src/views/vent/monitorManager/hsqHome/components/LinkRuleEditor.vue

@@ -31,22 +31,22 @@
           </div>
           <div class="table-content">
             <div class="content-item" v-for="(item, index) in tableData" :key="index">
-              <div class="item-text">{{ item.indnex }}</div>
+              <div class="item-text">{{ item.index }}</div>
               <div class="item-text item-text1">
                 <span>{{ item.actionType }}</span>
               </div>
               <div class="item-text">
-                <span> {{ item.action }}</span>
+                <span>{{ item.action }}</span>
               </div>
               <div class="item-text">
-                <div class="switch" :class="{ active: item.qy === 1 }">
+                <div class="switch" :class="{ active: item.qy === 1 }" @click="toggleSwitch(item)">
                   <div class="switch-dot"></div>
                 </div>
               </div>
               <div class="item-text">{{ item.delayTime }}</div>
               <div class="item-text">{{ item.duration }}</div>
               <div class="item-text">
-                <span class="text-look">查看</span>
+                <span class="text-look">配置</span>
               </div>
             </div>
           </div>
@@ -58,11 +58,12 @@
         <div class="workflow-container">
           <div class="steps-wrapper">
             <div v-for="(step, index) in steps" :key="index" class="step-item">
-              <div class="step-icon" :class="`icon-${step.id}`"></div>
-              <div class="step-frame" :class="`frame-${step.id}`">
+              <div class="step-icon" :class="`icon-${step.id}`">
+                <span class="icon-inner"></span>
+              </div>
+              <div class="step-frame">
                 <span class="step-text">{{ step.name }}</span>
               </div>
-              <!-- 底部小圆点 -->
               <div class="step-dot">
                 <div class="dot" :class="{ active: step.status === 1 }"></div>
               </div>
@@ -87,25 +88,48 @@ const props = defineProps<{
 const linkRuleStore = useLinkRuleStore();
 const currentSelectedRow = computed(() => linkRuleStore.getSelectedRow);
 
-let titleList = ref<any[]>([
-  { label: '序号', value: '1' },
-  { label: '动作类型', value: '2' },
-  { label: '动作说明', value: '3' },
-  { label: '启用', value: '4' },
-  { label: '延迟', value: '5' },
-  { label: '持续', value: '6' },
-  { label: '操作', value: '7' },
+interface ITitleItem {
+  label: string;
+}
+
+interface IActionItem {
+  index: string;
+  actionType: string;
+  action: string;
+  qy: number;
+  delayTime: string;
+  duration: string;
+}
+
+interface IStepItem {
+  id: string;
+  name: string;
+  status: number;
+}
+
+interface IFormField {
+  label: string;
+  key: keyof typeof formData;
+}
+
+const titleList = ref<ITitleItem[]>([
+  { label: '序号' },
+  { label: '动作类型' },
+  { label: '动作说明' },
+  { label: '启用' },
+  { label: '延迟' },
+  { label: '持续' },
+  { label: '操作' },
 ]);
 
-let tableData = ref<any[]>([
-  { indnex: '1', actionType: '声光报警器', action: '触发报警声+红色闪烁', qy: 1, delayTime: '0s', duration: '300s' },
-  { indnex: '2', actionType: '声光报警器', action: '触发报警声', qy: 1, delayTime: '1s', duration: '200s' },
-  { indnex: '3', actionType: '声光报警器', action: '红色闪烁', qy: 0, delayTime: '2s', duration: '180s' },
+const tableData = ref<IActionItem[]>([
+  { index: '1', actionType: '声光报警器', action: '触发报警声+红色闪烁', qy: 1, delayTime: '0s', duration: '300s' },
+  { index: '2', actionType: '声光报警器', action: '触发报警声', qy: 1, delayTime: '1s', duration: '200s' },
+  { index: '3', actionType: '声光报警器', action: '红色闪烁', qy: 0, delayTime: '2s', duration: '180s' },
 ]);
 
-// 流程图,添加 status 字段
-const steps = ref([
-  { id: 'alarm', name: '报警触发', status: 0 },
+const steps = ref<IStepItem[]>([
+  { id: 'alarm', name: '报警触发', status: 1 },
   { id: 'condition', name: '条件判断', status: 0 },
   { id: 'search', name: '查找规则', status: 0 },
   { id: 'action', name: '执行动作', status: 0 },
@@ -211,11 +235,6 @@ const updateFormData = (row: any) => {
 
 .long-list1 {
   --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-5.png');
-  --image-box-bg1: url('@/assets/images/home-container/configurable/hsq/2-13.png');
-  --image-box-bg2: url('@/assets/images/home-container/configurable/hsq/2-14.png');
-  --image-box-bg3: url('@/assets/images/home-container/configurable/hsq/2-15.png');
-  --image-box-bg4: url('@/assets/images/home-container/configurable/hsq/2-16.png');
-  --image-box-bg5: url('@/assets/images/home-container/configurable/hsq/2-17.png');
   --image-box-bg6: url('@/assets/images/home-container/configurable/hsq/2-24.png');
 
   position: relative;
@@ -236,7 +255,22 @@ const updateFormData = (row: any) => {
   }
   .basic-box2 {
     margin-top: 10px;
+
+    :deep(.basic-border) {
+      height: 100%;
+    }
+  }
+
+  .basic-box2 {
+    flex: 0.85;
+    min-height: 0;
+    margin-top: 10px;
+
+    :deep(.basic-border) {
+      height: 100%;
+    }
   }
+
   .edit-wrap {
     display: flex;
     width: 100%;
@@ -249,7 +283,9 @@ const updateFormData = (row: any) => {
     width: 80px;
     text-align: right;
     margin-right: 5px;
+    flex-shrink: 0;
   }
+
   .edit-right {
     background: #0e395d;
     width: 100%;
@@ -315,6 +351,24 @@ const updateFormData = (row: any) => {
     line-height: 25px;
     font-weight: bold;
     padding: 0 5px;
+
+    &:nth-child(1) {
+      color: #fc002a;
+    }
+
+    &:nth-child(2),
+    &:nth-child(3),
+    &:nth-child(4) {
+      color: #29a1d4;
+    }
+
+    &:nth-child(5) {
+      color: #46e8a3;
+    }
+
+    &:nth-child(6) {
+      margin-top: 10px;
+    }
   }
   .right-item:nth-child(4) {
     color: #fc002a;
@@ -336,17 +390,13 @@ const updateFormData = (row: any) => {
     background: var(--image-box-bg) no-repeat;
     background-size: 80% 100%;
     margin-bottom: 5px;
+    flex-shrink: 0;
   }
 
   .basic-table {
     height: 100%;
   }
 
-  .item-label1 {
-    width: 105px;
-    text-align: right;
-    margin-right: 5px;
-  }
   .table-title {
     display: flex;
     align-items: center;
@@ -370,15 +420,21 @@ const updateFormData = (row: any) => {
   .table-content {
     height: calc(100% - 40px);
     overflow-y: auto;
+
+    &::-webkit-scrollbar {
+      display: none;
+    }
   }
 
   .content-item {
     display: flex;
     align-items: center;
     height: 36px;
+
     &:nth-child(odd) {
       background-color: #0e3455;
     }
+
     &:nth-child(even) {
       background-color: #114268;
     }
@@ -398,9 +454,6 @@ const updateFormData = (row: any) => {
   .item-text1 {
     color: #fc002a;
   }
-  .item-text2 {
-    color: orange;
-  }
 
   .switch {
     width: 36px;
@@ -411,6 +464,7 @@ const updateFormData = (row: any) => {
     transition: all 0.2s ease;
     cursor: pointer;
     border: 1px solid #35d9e5;
+
     .switch-dot {
       width: 14px;
       height: 14px;
@@ -421,9 +475,10 @@ const updateFormData = (row: any) => {
       left: 1px;
       transition: all 0.2s ease;
     }
-  }
-  .switch.active .switch-dot {
-    left: 20px;
+
+    &.active .switch-dot {
+      left: 20px;
+    }
   }
 
   .text-look {
@@ -432,20 +487,24 @@ const updateFormData = (row: any) => {
   }
 }
 
-/*流程图*/
 .workflow-container {
   width: 100%;
-  padding: 20px 0;
+  height: 100%;
+  padding: 10px 0;
   position: relative;
+  display: flex;
+  align-items: center;
 }
 
 .steps-wrapper {
   display: flex;
   justify-content: space-between;
   align-items: flex-end;
+  width: 100%;
   padding: 0 20px;
   position: relative;
   z-index: 2;
+
   &::before {
     content: '';
     position: absolute;
@@ -457,6 +516,7 @@ const updateFormData = (row: any) => {
     background: #4a9eff;
     z-index: 1;
   }
+
   &::after {
     content: '';
     position: absolute;
@@ -468,6 +528,7 @@ const updateFormData = (row: any) => {
     background: #4a9eff;
     z-index: 1;
   }
+
   .steps-arrow {
     position: absolute;
     left: 5%;
@@ -478,10 +539,12 @@ const updateFormData = (row: any) => {
     background: url('@/assets/images/home-container/configurable/hsq/arrow.svg') center / contain no-repeat;
     z-index: 2;
   }
+
   .step-item:first-child .steps-arrow {
     display: none;
   }
 }
+
 .step-item {
   display: flex;
   flex-direction: column;
@@ -493,26 +556,62 @@ const updateFormData = (row: any) => {
 .step-icon {
   width: 56px;
   height: 56px;
-  background-size: contain;
-  background-repeat: no-repeat;
-  background-position: center;
+  display: flex;
+  align-items: center;
+  justify-content: center;
   margin-bottom: -6px;
-}
+  position: relative;
 
-.icon-alarm {
-  background-image: url('@/assets/images/home-container/configurable/hsq/bjcf.png');
-}
-.icon-condition {
-  background-image: url('@/assets/images/home-container/configurable/hsq/tjpd.png');
-}
-.icon-search {
-  background-image: url('@/assets/images/home-container/configurable/hsq/czgz.png');
-}
-.icon-action {
-  background-image: url('@/assets/images/home-container/configurable/hsq/zxdz.png');
+  .icon-inner {
+    width: 36px;
+    height: 36px;
+    border: 2px solid #4facfe;
+    transform: rotate(45deg);
+    background: linear-gradient(135deg, rgba(20, 80, 140, 0.9), rgba(10, 40, 80, 0.9));
+    box-shadow: 0 0 12px rgba(79, 172, 254, 0.5);
+    position: relative;
+
+    &::after {
+      content: '';
+      position: absolute;
+      inset: 6px;
+      border: 1px solid rgba(79, 172, 254, 0.6);
+    }
+  }
+
+  &.icon-alarm .icon-inner {
+    background: linear-gradient(135deg, rgba(180, 40, 40, 0.8), rgba(80, 20, 20, 0.9));
+    border-color: #ff6b6b;
+    box-shadow: 0 0 12px rgba(255, 77, 77, 0.5);
+  }
+
+  &.icon-condition .icon-inner {
+    background: linear-gradient(135deg, rgba(30, 100, 160, 0.9), rgba(15, 50, 90, 0.9));
+  }
+
+  &.icon-search .icon-inner {
+    background: linear-gradient(135deg, rgba(40, 120, 100, 0.9), rgba(20, 60, 50, 0.9));
+    border-color: #46e8a3;
+    box-shadow: 0 0 12px rgba(70, 232, 163, 0.4);
+  }
+
+  &.icon-action .icon-inner {
+    background: linear-gradient(135deg, rgba(160, 100, 30, 0.9), rgba(80, 50, 15, 0.9));
+    border-color: #ffa500;
+    box-shadow: 0 0 12px rgba(255, 165, 0, 0.4);
+  }
+
+  &.icon-log .icon-inner {
+    background: linear-gradient(135deg, rgba(60, 80, 160, 0.9), rgba(30, 40, 80, 0.9));
+  }
 }
+
+.icon-alarm,
+.icon-condition,
+.icon-search,
+.icon-action,
 .icon-log {
-  background-image: url('@/assets/images/home-container/configurable/hsq/jlrz.png');
+  background-image: none;
 }
 
 .step-frame {
@@ -557,10 +656,11 @@ const updateFormData = (row: any) => {
   background: #2c5a8c;
   border: 1px solid #4a9eff;
   transition: all 0.3s ease;
+
+  &.active {
+    background: #4facfe;
+    border-color: #4facfe;
+    box-shadow: 0 0 6px rgba(79, 172, 254, 0.6);
+  }
 }
-.dot.active {
-  background: #4facfe;
-  border-color: #4facfe;
-  box-shadow: 0 0 6px rgba(79, 172, 254, 0.6);
-}
-</style>
+</style>

+ 140 - 0
src/views/vent/monitorManager/hsqHome/components/LinkRuleStats.vue

@@ -0,0 +1,140 @@
+<template>
+  <div class="long-list">
+    <div class="list-title">
+      <span>规则统计</span>
+    </div>
+    <div class="list-content">
+      <div class="stat-item" :class="item.type" v-for="(item, index) in statList" :key="index">
+        <div class="icon-wrap" :class="`icon-${index + 1}`"></div>
+        <div class="label-wrap">
+          <span>{{ item.label }}</span>
+        </div>
+        <div class="num-wrap">
+          <span>{{ item.value }}</span>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+
+interface IStatItem {
+  label: string;
+  value: number;
+  type: 'blue' | 'green';
+}
+
+const statList = ref<IStatItem[]>([
+  { label: '总规则', value: 10, type: 'blue' },
+  { label: '已启用', value: 7, type: 'green' },
+  { label: '已禁用', value: 2, type: 'green' },
+  { label: '触发中', value: 2, type: 'blue' },
+]);
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+.long-list {
+  --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-5.png');
+  --image-box-bg-green: url('@/assets/images/home-container/configurable/hsq/4-2.png');
+  --image-box-bg-blue: url('@/assets/images/home-container/configurable/hsq/4-3.png');
+  --image-box-svg1: url('@/assets/images/home-container/configurable/hsq/4-total.svg');
+  --image-box-svg2: url('@/assets/images/home-container/configurable/hsq/4-cf.svg');
+  --image-box-svg3: url('@/assets/images/home-container/configurable/hsq/4-qy.svg');
+  --image-box-svg4: url('@/assets/images/home-container/configurable/hsq/4-jy.svg');
+
+  position: relative;
+  width: 100%;
+  height: 100%;
+  padding: 10px 15px;
+  box-sizing: border-box;
+
+  .list-title {
+    width: 177px;
+    height: 30px;
+    line-height: 22px;
+    color: #01fefc;
+    font-weight: bolder;
+    background: var(--image-box-bg) no-repeat;
+    background-size: 80% 100%;
+    margin-bottom: 10px;
+  }
+
+  .list-content {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 16px 20px;
+  }
+
+  .stat-item {
+    width: calc(50% - 10px);
+    display: flex;
+    align-items: center;
+    height: 40px;
+    padding-left: 6px;
+    box-sizing: border-box;
+    background-repeat: no-repeat;
+    background-position: center;
+    background-size: 100% 100%;
+
+    &.blue {
+      background-image: var(--image-box-bg-blue);
+    }
+
+    &.green {
+      background-image: var(--image-box-bg-green);
+    }
+  }
+
+  .icon-wrap {
+    width: 30px;
+    height: 30px;
+    flex-shrink: 0;
+    background-repeat: no-repeat;
+    background-position: center;
+    background-size: 60% 70%;
+
+    &.icon-1 {
+      background-image: var(--image-box-svg1);
+    }
+
+    &.icon-2 {
+      background-image: var(--image-box-svg3);
+    }
+
+    &.icon-3 {
+      background-image: var(--image-box-svg4);
+    }
+
+    &.icon-4 {
+      background-image: var(--image-box-svg2);
+    }
+  }
+
+  .label-wrap {
+    margin-left: 10px;
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    color: #fff;
+    font-size: 14px;
+    white-space: nowrap;
+  }
+
+  .num-wrap {
+    width: 100px;
+    height: 100%;
+    flex-shrink: 0;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    color: #fff;
+    font-size: 16px;
+    font-weight: bold;
+  }
+}
+</style>

+ 218 - 0
src/views/vent/monitorManager/hsqHome/components/LinkRuleTable.vue

@@ -0,0 +1,218 @@
+<template>
+  <div class="search-table">
+    <div class="search-area">
+      <div class="list-title">
+        <span>联动规则列表</span>
+      </div>
+      <div class="search-btn">
+        <div class="btn-item">新增</div>
+      </div>
+    </div>
+    <div class="content-area">
+      <div class="content-title">
+        <div class="title-item" v-for="(item, index) in titleList" :key="index">{{ item.label }}</div>
+      </div>
+      <div class="history-content">
+        <div
+          class="content-item"
+          :class="{ 'row-active': activeIndex === index }"
+          v-for="(item, index) in tableData"
+          :key="index"
+          @click="activeIndex = index"
+        >
+          <div class="item-text">{{ item.ruleId }}</div>
+          <div class="item-text">{{ item.ruleName }}</div>
+          <div class="item-text item-text1">{{ item.condition }}</div>
+          <div class="item-text">{{ item.action }}</div>
+          <div class="item-text item-text2">{{ item.status }}</div>
+          <div class="item-text">
+            <span class="text-look">编辑</span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+
+interface ITitleItem {
+  label: string;
+}
+
+interface IRuleItem {
+  ruleId: string;
+  ruleName: string;
+  condition: string;
+  action: string;
+  status: string;
+}
+
+const activeIndex = ref(1);
+
+const titleList = ref<ITitleItem[]>([
+  { label: '规则ID' },
+  { label: '规则名称' },
+  { label: '触发条件' },
+  { label: '联动动作' },
+  { label: '状态' },
+  { label: '操作' },
+]);
+
+const tableData = ref<IRuleItem[]>([
+  { ruleId: 'LINK001', ruleName: '温度报警联动', condition: '温度>60℃', action: '声光报警', status: '启用' },
+  { ruleId: 'LINK001', ruleName: '温度报警联动', condition: '温度>60℃', action: '声光报警', status: '启用' },
+  { ruleId: 'LINK001', ruleName: '温度报警联动', condition: '温度>60℃', action: '声光报警', status: '启用' },
+  { ruleId: 'LINK001', ruleName: '温度报警联动', condition: '温度>60℃', action: '声光报警', status: '启用' },
+  { ruleId: 'LINK001', ruleName: '温度报警联动', condition: '温度>60℃', action: '声光报警', status: '启用' },
+  { ruleId: 'LINK001', ruleName: '温度报警联动', condition: '温度>60℃', action: '声光报警', status: '启用' },
+  { ruleId: 'LINK001', ruleName: '温度报警联动', condition: '温度>60℃', action: '声光报警', status: '启用' },
+]);
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+.search-table {
+  --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-5.png');
+  --image-box-bg2: url('@/assets/images/home-container/configurable/hsq/2-24.png');
+  position: relative;
+  width: 100%;
+  height: 100%;
+  padding: 10px;
+  box-sizing: border-box;
+}
+
+.list-title {
+  width: 177px;
+  height: 30px;
+  line-height: 22px;
+  color: #01fefc;
+  font-weight: bolder;
+  background: var(--image-box-bg) no-repeat;
+  background-size: 80% 100%;
+  margin-bottom: 5px;
+}
+
+.search-area {
+  height: 42px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 5px;
+}
+
+.search-btn {
+  width: 85px;
+  height: 30px;
+  border: 1px solid #01fefc;
+  border-radius: 4px;
+  padding: 3px;
+  cursor: pointer;
+}
+
+.btn-item {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(32, 166, 169);
+}
+
+.content-area {
+  height: calc(100% - 47px);
+}
+
+.content-title {
+  display: flex;
+  align-items: center;
+  height: 34px;
+  background: var(--image-box-bg2) no-repeat;
+  background-size: 100% 100%;
+  margin-bottom: 6px;
+}
+
+.title-item {
+  display: flex;
+  flex: 1;
+  justify-content: center;
+  align-items: center;
+  color: #01fefc;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.history-content {
+  height: calc(100% - 40px);
+  overflow-y: auto;
+
+  &::-webkit-scrollbar {
+    display: none;
+  }
+}
+
+.content-item {
+  display: flex;
+  align-items: center;
+  height: 36px;
+  cursor: pointer;
+
+  &:nth-child(odd) {
+    background-color: #0e3455;
+  }
+
+  &:nth-child(even) {
+    background-color: #114268;
+  }
+
+  &.row-active {
+    border: 1px solid #f4933d;
+    box-shadow: inset 0 0 6px rgba(244, 147, 61, 0.3);
+  }
+}
+
+.item-text {
+  display: flex;
+  flex: 1;
+  justify-content: center;
+  align-items: center;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  padding: 0 4px;
+}
+
+.title-item:nth-child(2),
+.item-text:nth-child(2) {
+  flex: 1.8;
+}
+
+.title-item:nth-child(3),
+.item-text:nth-child(3) {
+  flex: 1.5;
+}
+
+.title-item:nth-child(4),
+.item-text:nth-child(4) {
+  flex: 1.5;
+}
+
+.item-text1 {
+  color: #f4933d;
+}
+
+.item-text2 {
+  color: #4cf3a6;
+}
+
+.text-look {
+  padding: 0 3px;
+  margin: 0 2px;
+  border-radius: 2px;
+  background-color: #2484bc;
+  cursor: pointer;
+}
+</style>

+ 7 - 11
src/views/vent/home/configurable/components/preset/OperateNew.vue → src/views/vent/monitorManager/hsqHome/components/QuickAction.vue

@@ -1,10 +1,10 @@
 <template>
-  <div class="OperateNew">
+  <div class="quick-action">
     <div class="basic-box basic-boxT">
-      <div class="nav-box" v-for="(item, index) in option" :key="index">
+      <div class="nav-box" v-for="(item, index) in quickOption" :key="index">
         <SvgIcon class="box-icon-style" size="20" :name="item.iconName" />
         <div class="box-label">{{ item.label }}</div>
-        <div class="box-value">{{ data[item.value] }}</div>
+        <div class="box-value">{{ quickData[item.value] }}</div>
       </div>
     </div>
     <div class="basic-box basic-boxB">
@@ -18,17 +18,17 @@
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue'
+import { ref } from 'vue';
 import { SvgIcon } from '/@/components/Icon';
 
 let props = defineProps({
-  option: {
+  quickOption: {
     type: Array as any
   },
   btnOption: {
     type: Array as any
   },
-  data: {
+  quickData: {
     type: Object,
     default: () => {
       return {
@@ -39,15 +39,12 @@ let props = defineProps({
     }
   }
 })
-
 </script>
 
 <style lang="less" scoped>
 @import '/@/design/theme.less';
 
-@{theme-deepblue} {}
-
-.OperateNew {
+.quick-action {
   --image-card-bg: url('@/assets/images/home-container/configurable/hsq/1-10.png');
   --image-card-bg1: url('@/assets/images/home-container/configurable/hsq/1-11.png');
   --image-card-bg2: url('@/assets/images/home-container/configurable/hsq/1-15.png');
@@ -159,6 +156,5 @@ let props = defineProps({
       cursor: pointer;
     }
   }
-
 }
 </style>

+ 100 - 0
src/views/vent/monitorManager/hsqHome/components/SystemCenBottom.vue

@@ -0,0 +1,100 @@
+<template>
+  <div class="system-box">
+    <div class="basic-box">
+      <div class="list-title">今日登录统计</div>
+      <div class="list-content">
+        <basicBorder title="最近登录">
+          <div class="basic-box1">
+            <div class="box-item" v-for="(item, index) in data" :key="index">
+              <span style="margin-right: 10px;">{{ `${item.userName} : ` }}</span>
+              <span>{{ item.lastLoginTime }}</span>
+            </div>
+          </div>
+        </basicBorder>
+      </div>
+    </div>
+    <div class="basic-box">
+        <CustomChart :chart-config="dayLoginConfig" :chart-data="dayChartData"></CustomChart>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref,watch} from 'vue'
+import basicBorder from './basicBorder.vue'
+import CustomChart from './CustomChart.vue';
+import { dayLoginConfig, } from '../hsqHome.data';
+
+const props = defineProps<{ data: Array<{
+  [x: string]:
+  any; userName: string; value: string 
+}> }>()
+
+let dayChartData = ref<any[]>([])
+
+watch(()=>props.data,(newV,oldV)=>{
+  if(newV){
+    dayChartData.value=newV.map(el=>{
+      return {
+        x:el.userName,
+        y:parseFloat(el.loginCount),
+      }
+    })
+  }
+},{immediate:true})
+</script>
+
+<style lang="less" scoped>
+.system-box {
+   --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-5.png');
+  position: relative;
+  display: flex;
+  justify-content: space-between;
+  width: 100%;
+  height: 100%;
+
+  .basic-box {
+    width: 50%;
+    height: 100%;
+    padding: 15px;
+    box-sizing: border-box;
+  }
+
+  .list-title {
+    width: 177px;
+    height: 30px;
+    line-height: 22px;
+    padding-left: 16px;
+    color: #01fefc;
+    font-weight: bolder;
+    background: var(--image-box-bg) no-repeat;
+    background-size: 100% 100%;
+    margin-bottom: 5px;
+  }
+
+  .list-content {
+    width: 100%;
+    height: calc(100% - 35px);
+  }
+
+  .basic-box1 {
+    height: 100%;
+    overflow-y: auto;
+  }
+
+  .box-item {
+    display: flex;
+    // justify-content: space-between;
+    align-items: center;
+    height: 26px;
+    margin-bottom: 6px;
+    padding: 0px 10px;
+    box-sizing: border-box;
+    background: linear-gradient(to right, #134c77, transparent);
+  }
+
+  ::-webkit-scrollbar {
+    display: none;
+  }
+}
+</style>

+ 93 - 51
src/views/vent/home/configurable/components/preset/LogAudit.vue → src/views/vent/monitorManager/hsqHome/components/SystemLeftBottom.vue

@@ -1,27 +1,22 @@
 <template>
   <div class="log-audit">
     <div class="list-title">
-      <div class="title-l">日志审计</div>
+      <div class="title-l">{{ title }}</div>
       <div class="title-r">
-        <div :class="activeIndex == index ? 'basic-btn-active' : 'basic-btn'" v-for="(item, index) in btnList"
+        <div :class="activeIndex == index ? 'basic-btn-active' : 'basic-btn'" v-for="(item, index) in btnOption"
           :key="index" @click="handleClick(item, index)">{{
             item.label }}</div>
       </div>
     </div>
     <div class="list-content">
       <div class="content-title">
-        <div class="title-item" v-for="(item, index) in titleList" :key="index">{{ item.label }}</div>
+        <div class="title-item" v-for="(item, index) in titleOption" :key="index">{{ item.label }}</div>
       </div>
       <div class="table-content">
-        <div class="content-item" v-for="(item, index) in tableData" :key="index">
-          <div class="item-text">{{ item.id }}</div>
-          <div class="item-text">{{ item.address }}
-          </div>
-          <div class="item-text item-text1">{{ item.grade }}</div>
-          <div class="item-text item-text2">{{ item.status }}</div>
-          <div class="item-text">
-            <span class="text-look">确认</span>
-            <span class="text-look">详情</span>
+        <div class="content-item" v-for="(item, index) in data" :key="index">
+          <div class="item-text" v-for="(ite, ind) in titleOption" :key="ind">
+            <div :class="ite.value == 'username' ? 'status-text' : ''">{{ ite.value ? item[ite.value] : '-' }}
+            </div>
           </div>
         </div>
       </div>
@@ -31,45 +26,38 @@
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue'
+import { ref, type PropType } from 'vue'
+
+interface BtnOption {
+  label: string
+  value?: string | number
+}
 
+let props = defineProps({
+  title: {
+    type: String,
+    default: '',
+  },
+  data: {
+    type: Array as PropType<any[]>,
+    default: () => [],
+  },
+  btnOption: {
+    type: Array as PropType<BtnOption[]>,
+    default: () => [],
+  },
+  titleOption: {
+    type: Array as PropType<BtnOption[]>,
+    default: () => [],
+  }
+})
 let activeIndex = ref(0)
-let btnList = ref<any[]>([
-  { label: '全部', value: '1' },
-  { label: '登录日志', value: '2' },
-  { label: '操作日志', value: '3' },
-  { label: '报警日志', value: '4' },
-])
-let titleList = ref<any[]>([
-  { label: '时间', value: '1' },
-  { label: '用户名', value: '2' },
-  { label: '操作类型', value: '3' },
-  { label: '操作内容', value: '4' },
-  { label: 'IP地址', value: '5' },
-  { label: '结果', value: '5' },
-  { label: '详情', value: '5' },
-])
-let tableData = ref<any[]>([
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-  // { time: '14:31:22', address: '采掘场A区', grade: '一级', status: '未处理', },
-])
-
-//menu选项切换
+let $emit=defineEmits(['changeTab'])
+
+//tab选项切换
 function handleClick(item, index) {
   activeIndex.value = index
+  $emit('changeTab',item.value)
 }
 </script>
 
@@ -155,10 +143,34 @@ function handleClick(item, index) {
 
   .title-item {
     display: flex;
-    flex: 1;
+    // flex: 1;
     justify-content: center;
     align-items: center;
     color: #01fefc;
+
+    &:nth-child(1) {
+      flex: 1
+    }
+
+    &:nth-child(2) {
+      flex: 1
+    }
+
+    &:nth-child(3) {
+      flex: 2
+    }
+
+    &:nth-child(4) {
+      flex: 2
+    }
+
+    &:nth-child(5) {
+      flex: 2
+    }
+
+    &:nth-child(6) {
+      flex: 1
+    }
   }
 
   .table-content {
@@ -183,13 +195,40 @@ function handleClick(item, index) {
 
   .item-text {
     display: flex;
-    flex: 1;
+    // flex: 1;
     justify-content: center;
     align-items: center;
+     text-overflow: ellipsis;
+    white-space: nowrap;
+    overflow: hidden;
+
+    &:nth-child(1) {
+      flex: 1
+    }
+
+    &:nth-child(2) {
+      flex: 1
+    }
+
+    &:nth-child(3) {
+      flex: 2
+    }
+
+    &:nth-child(4) {
+      flex: 2
+    }
+
+    &:nth-child(5) {
+      flex: 2
+    }
+
+    &:nth-child(6) {
+      flex: 1
+    }
   }
 
-  .item-text1 {
-    color: #fc002a;
+  .status-text {
+     color: orange;
   }
 
   .item-text2 {
@@ -203,5 +242,8 @@ function handleClick(item, index) {
     background-color: #2484bc;
     cursor: pointer;
   }
+  ::-webkit-scrollbar {
+    display: none;
+  }
 }
 </style>

+ 278 - 0
src/views/vent/monitorManager/hsqHome/components/SystemLeftTop.vue

@@ -0,0 +1,278 @@
+<template>
+  <div class="user-list">
+    <div class="list-title">
+      <div class="title-l">用户列表</div>
+      <div class="title-r">
+        <div class="basic-btn" @click="handleDetail">详情</div>
+      </div>
+    </div>
+    <div class="list-content">
+      <!-- <div class="search-area">
+        <a-input v-model:value="searchData" placeholder="搜索" size="small" />
+        <div class="search-btn">
+          <div class="basic-btn">筛选</div>
+        </div>
+      </div> -->
+      <!-- <div class="content-area"> -->
+      <div class="content-title">
+        <div class="title-item" v-for="(item, index) in option" :key="index">{{ item.label }}</div>
+      </div>
+      <div class="table-content">
+        <div class="content-item" v-for="(item, index) in data" :key="index">
+          <div class="item-text" v-for="(ite, ind) in option" :key="ind">
+            <!-- <div v-if="ite.value == 'operation'">
+                <span class="text-look">编辑</span>
+                <span class="text-look">更多</span>
+              </div> -->
+            <div :class="ite.value == 'status_dictText' ? 'status-text' : ''">{{ item[ite.value] || '-' }}
+            </div>
+          </div>
+        </div>
+      </div>
+      <!-- </div> -->
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, type PropType } from 'vue';
+import { useRouter } from 'vue-router'
+
+let props = defineProps({
+  data: {
+    type: Array as PropType<Record<string, any>[]>,
+    default: () => [],
+  },
+  option: {
+    type: Object as PropType<Record<string, any>>,
+    default: () => ({}),
+  },
+})
+
+// let searchData = ref('')
+let router = useRouter()
+
+//详情跳转
+function handleDetail() {
+  router.push({
+    path: '/monitorChannel/system/user',
+    query: {},
+  })
+}
+
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+@{theme-deepblue} {
+  .user-list {}
+}
+
+.user-list {
+  --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-5.png');
+  --image-box-bg1: url('@/assets/images/home-container/configurable/hsq/2-6.png');
+  --image-box-bg2: url('@/assets/images/home-container/configurable/hsq/2-24.png');
+  position: relative;
+  width: 100%;
+  height: 100%;
+  padding: 15px 30px;
+  box-sizing: border-box;
+
+  .list-title {
+    display: flex;
+    justify-content: space-between;
+    width: 100%;
+    height: 30px;
+    line-height: 22px;
+    margin-bottom: 10px;
+  }
+
+  .title-l {
+    width: 177px;
+    height: 100%;
+    color: #01fefc;
+    font-weight: bolder;
+    padding-left: 16px;
+    background: var(--image-box-bg) no-repeat;
+    background-size: 100% 100%;
+  }
+
+  .title-r {
+    width: 85px;
+    height: 30px;
+    border: 1px solid #01fefc;
+    border-radius: 4px;
+    padding: 3px;
+    cursor: pointer;
+    // margin-right: 16px;
+  }
+
+  .basic-btn {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(32, 166, 169);
+  }
+
+  .list-content {
+    height: calc(100% - 40px);
+  }
+
+  // .search-area {
+  //   height: 42px;
+  //   display: flex;
+  //   justify-content: space-between;
+  //   align-items: center;
+  //   margin-bottom: 5px;
+  // }
+
+  // .search-btn {
+  //   width: 85px;
+  //   height: 30px;
+  //   border: 1px solid #01fefc;
+  //   border-radius: 4px;
+  //   padding: 3px;
+  //   cursor: pointer;
+  // }
+
+  // .content-area {
+  //   height: calc(100% - 47px);
+  // }
+
+  .content-title {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    height: 34px;
+    background: var(--image-box-bg2) no-repeat;
+    background-size: 100% 100%;
+    margin-bottom: 6px;
+  }
+
+  .title-item {
+    display: flex;
+    // flex: 1;
+    justify-content: center;
+    align-items: center;
+    color: #01fefc;
+
+    &:nth-child(1) {
+      flex: 1;
+    }
+
+    &:nth-child(2) {
+      flex: 1.5;
+    }
+
+    &:nth-child(3) {
+      flex: 1.5;
+    }
+
+    &:nth-child(4) {
+      flex: 1.5;
+    }
+
+    &:nth-child(5) {
+      flex: 1;
+    }
+
+    &:nth-child(6) {
+      flex: 1;
+    }
+
+    &:nth-child(7) {
+      flex: 1;
+    }
+  }
+
+  .table-content {
+    height: calc(100% - 40px);
+    overflow-y: auto;
+  }
+
+  .content-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    height: 36px;
+
+    &:nth-child(odd) {
+      background-color: #0e3455;
+    }
+
+    &:nth-child(even) {
+      background-color: #114268;
+    }
+  }
+
+  .item-text {
+    display: flex;
+    // flex: 1;
+    justify-content: center;
+    align-items: center;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    overflow: hidden;
+
+    &:nth-child(1) {
+      flex: 1;
+    }
+
+    &:nth-child(2) {
+      flex: 1.5;
+    }
+
+    &:nth-child(3) {
+      flex: 1.5;
+    }
+
+    &:nth-child(4) {
+      flex: 1.5;
+    }
+
+    &:nth-child(5) {
+      flex: 1;
+    }
+
+    &:nth-child(6) {
+      flex: 1;
+    }
+
+    &:nth-child(7) {
+      flex: 1;
+    }
+  }
+
+  .status-text {
+    color: #15f00d;
+  }
+
+  .text-look {
+    padding: 0px 3px;
+    margin: 0px 2px;
+    border-radius: 2px;
+    background-color: #2484bc;
+    cursor: pointer;
+  }
+
+  .zxm-input {
+    height: 42px;
+    color: #fff;
+    background-color: transparent;
+    border: none;
+    background: var(--image-box-bg1) no-repeat;
+    background-size: 100% 100%;
+  }
+
+  .zxm-input-sm {
+    padding: 0px 20px;
+  }
+
+  ::-webkit-scrollbar {
+    display: none;
+  }
+}
+</style>

+ 0 - 0
src/views/vent/home/configurable/components/preset/SystemView.vue → src/views/vent/monitorManager/hsqHome/components/SystemRightBot.vue


+ 63 - 14
src/views/vent/home/configurable/components/preset/PermissionManager.vue → src/views/vent/monitorManager/hsqHome/components/SystemRightTop.vue

@@ -1,8 +1,13 @@
 <template>
   <div class="permission-manager">
-    <div class="list-title">角色权限管理</div>
+    <div class="list-title">
+      <div class="title-l">角色权限管理</div>
+      <div class="title-r">
+        <div class="basic-btn" @click="handleDetail">详情</div>
+      </div>
+    </div>
     <div class="list-content">
-      <div class="per-box" v-for="(item, index) in perList" :key="index">
+      <div class="per-box" v-for="(item, index) in userInfo" :key="index">
         <div class="box-label">{{ item.label }}</div>
         <div class="box-value">{{ item.value }}</div>
       </div>
@@ -12,15 +17,26 @@
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue'
-
-let perList = ref<any[]>([
-  { label: '超级管理员(全部权限)', value: '1' },
-  { label: '安全主管(报警处理+设备管理)', value: '2' },
-  { label: '值班员(监控+报警确认)', value: '2' },
-  { label: '设备维护(设备管理+配置)', value: '2' },
-  { label: '访客(仅查看)', value: '2' },
-])
+import { useRouter } from 'vue-router'
+
+interface UserInfoItem {
+  label: string
+  value: string
+}
+
+const props = defineProps<{
+  userInfo?: UserInfoItem[]
+}>()
+
+const router = useRouter()
+
+// 详情跳转
+function handleDetail() {
+  router.push({
+    path: '/monitorChannel/system/role',
+    query: {},
+  })
+}
 </script>
 
 <style lang="less" scoped>
@@ -44,20 +60,47 @@ let perList = ref<any[]>([
   box-sizing: border-box;
 
   .list-title {
-    width: 177px;
+    display: flex;
+    justify-content: space-between;
+    width: 100%;
     height: 30px;
     line-height: 22px;
-    padding-left: 16px;
+    margin-bottom: 10px;
+  }
+
+  .title-l {
+    width: 177px;
+    height: 100%;
     color: #01fefc;
     font-weight: bolder;
+    padding-left: 16px;
     background: var(--image-box-bg5) no-repeat;
     background-size: 100% 100%;
-    margin-bottom: 5px;
+  }
+
+  .title-r {
+    width: 85px;
+    height: 30px;
+    border: 1px solid #01fefc;
+    border-radius: 4px;
+    padding: 3px;
+    cursor: pointer;
+    // margin-right: 16px;
+  }
+
+  .basic-btn {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(32, 166, 169);
   }
 
   .list-content {
     width: 100%;
     height: calc(100% - 35px);
+    overflow-y: auto;
   }
 
   .per-box {
@@ -67,6 +110,8 @@ let perList = ref<any[]>([
     height: 40px;
     padding: 0px 40px;
     margin-bottom: 10px;
+    background: var(--image-box-bg2) no-repeat;
+    background-size: 100% 100%;
 
     &:nth-child(1) {
       background: var(--image-box-bg) no-repeat;
@@ -119,5 +164,9 @@ let perList = ref<any[]>([
     font-family: 'douyuFont';
 
   }
+
+  ::-webkit-scrollbar {
+    display: none;
+  }
 }
 </style>

+ 0 - 0
src/views/vent/home/configurable/components/preset/EchartBarNew.vue → src/views/vent/monitorManager/hsqHome/components/WarnBottom.vue


+ 40 - 31
src/views/vent/home/configurable/components/preset/MixedWarn.vue → src/views/vent/monitorManager/hsqHome/components/WarnCenTop.vue

@@ -27,27 +27,33 @@
           <div class="warn-detail">
             <div class="warn-item">
               <div class="item-label">报警级别 : </div>
-              <div class="item-val text-val"> {{ warnDetail.grade }}</div>
+              <div class="item-val"
+                :style="{ color: warnData.alarmLevel == 101 ? '#00d8ff' : warnData.alarmLevel == 102 ? '#fcfc22' : warnData.alarmLevel == 103 ? '#ff7010' : warnData.alarmLevel == 104 ? '#df4e43' : warnData.alarmLevel == 201 ? '#ff0000' : '' }">
+                {{ warnData.alarmLevel == 101 ? '低风险' : warnData.alarmLevel ==
+                  102 ? '一般风险' :
+                  warnData.alarmLevel == 103 ? '较大风险' : warnData.alarmLevel == 104 ? '重大风险' : warnData.alarmLevel == 201 ?
+                    '报警' :
+                '低风险' }}</div>
             </div>
             <div class="warn-item">
               <div class="item-label">报警时间 : </div>
-              <div class="item-val"> {{ warnDetail.time }}</div>
+              <div class="item-val"> {{ warnData.starttime || '-' }}</div>
             </div>
             <div class="warn-item">
               <div class="item-label">报警位置 : </div>
-              <div class="item-val"> {{ warnDetail.address }}</div>
+              <div class="item-val"> {{ warnData.alarmName || '-' }}</div>
             </div>
             <div class="warn-item">
               <div class="item-label">监测设备 : </div>
-              <div class="item-val"> {{ warnDetail.device }}</div>
+              <div class="item-val"> {{ warnData.device || '-' }}</div>
             </div>
             <div class="warn-item">
               <div class="item-label ">最高温度 : </div>
-              <div class="item-val text-val"> {{ warnDetail.maxtemp }}</div>
+              <div class="item-val text-val"> {{ warnData.maxtemp || '-' }}</div>
             </div>
             <div class="warn-item">
               <div class="item-label">平均速度 : </div>
-              <div class="item-val text-val1"> {{ warnDetail.speed }}</div>
+              <div class="item-val text-val1"> {{ warnData.speed || '-' }}</div>
             </div>
           </div>
         </basicBorder>
@@ -73,7 +79,7 @@
           </div>
           <div class="flow-step">
             <a-steps progress-dot :current="1">
-              <a-step title="" description="" v-for="(item,index) in 5" :key="index" />
+              <a-step title="" description="" v-for="(item, index) in 5" :key="index" />
             </a-steps>
           </div>
         </div>
@@ -84,22 +90,21 @@
 
 <script setup lang="ts">
 import { reactive, ref } from 'vue'
-import basicBorder from '../BasicBorder.vue'
+import basicBorder from './basicBorder.vue'
 import { getAssetURL } from '/@/utils/ui';
 
-let deviceModel = ref('CAM-001')
-let warnDetail = reactive({
-  grade: '一级报警(严重)',
-  time: '2024-12-20 14:31:22',
-  address: '采掘场A区,东经87.6,北纬43.8',
-  device: '双光谱相机',
-  maxtemp: '65.3',
-  speed: '48.7'
+let props = defineProps({
+  warnData: {
+    type: Object,
+    required: true
+  }
 })
+
+let deviceModel = ref('-')
 let picList = ref([
   { src: getAssetURL('home-container/configurable/hsq/4-1.png'), label: '1.报警触发' },
-  { src: getAssetURL('home-container/configurable/hsq/4-2.png'), label: '2.系统确认' },
-  { src: getAssetURL('home-container/configurable/hsq/4-3.png'), label: '3.通知值班' },
+  { src: getAssetURL('home-container/configurable/hsq/6-1.png'), label: '2.系统确认' },
+  { src: getAssetURL('home-container/configurable/hsq/6-2.png'), label: '3.通知值班' },
   { src: getAssetURL('home-container/configurable/hsq/4-4.png'), label: '4.现场处置' },
   { src: getAssetURL('home-container/configurable/hsq/4-5.png'), label: '5.确认解除' },
 ])
@@ -286,22 +291,26 @@ let picList = ref([
       border-radius: 5px;
     }
   }
-  .flow-step{
-      width: 100%;
-      position: absolute;
-      bottom: 0px;
-      left: 0;
-      padding: 0px 30px;
-    }
-  
+
+  .flow-step {
+    width: 100%;
+    position: absolute;
+    bottom: 0px;
+    left: 0;
+    padding: 0px 30px;
+  }
+
 }
-:deep(.zxm-steps-icon .zxm-steps-icon-dot){
+
+:deep(.zxm-steps-icon .zxm-steps-icon-dot) {
   border: 1px solid #2cb6ff !important;
 }
-:deep(.zxm-steps-item-process > .zxm-steps-item-container > .zxm-steps-item-tail::after){
-     background-color: rgba(28, 118, 172,.6) !important;
+
+:deep(.zxm-steps-item-process > .zxm-steps-item-container > .zxm-steps-item-tail::after) {
+  background-color: rgba(28, 118, 172, .6) !important;
 }
-:deep(.zxm-steps-item-wait > .zxm-steps-item-container > .zxm-steps-item-tail::after){
-   background-color: rgba(28, 118, 172,.6) !important;
+
+:deep(.zxm-steps-item-wait > .zxm-steps-item-container > .zxm-steps-item-tail::after) {
+  background-color: rgba(28, 118, 172, .6) !important;
 }
 </style>

+ 240 - 0
src/views/vent/monitorManager/hsqHome/components/WarnLeftTop.vue

@@ -0,0 +1,240 @@
+<!-- 报警信息左侧顶部组件:包含报警搜索、报警列表展示及详情查看功能 -->
+<template>
+  <div class="search-table">
+    <!-- 搜索区域:包含搜索输入框和筛选按钮 -->
+    <div class="search-area">
+      <a-input v-model:value="searchWarn" placeholder="搜索报警" size="small" />
+      <div class="search-btn">
+        <div class="btn-item">筛选</div>
+      </div>
+    </div>
+    <!-- 内容区域:包含表头和表格数据 -->
+    <div class="content-area">
+      <!-- 表头:根据 warnTitle 配置动态渲染列标题 -->
+      <div class="content-title">
+        <div class="title-item" v-for="(item, index) in warnTitle" :key="index">{{ item.label }}</div>
+      </div>
+      <!-- 表格数据列表:遍历 tableData 渲染每行报警信息 -->
+      <div class="table-content">
+        <div class="content-item" v-for="(item, index) in tableData" :key="index">
+          <div class="item-text" v-for="(ite, ind) in warnTitle" :key="ind">
+            <!-- 报警时间列 -->
+            <div v-if="ite.value == 'starttime'">{{ item[ite.value] }}</div>
+            <!-- 报警名称列 -->
+            <div v-if="ite.value == 'alarmName'">{{ item[ite.value] }}</div>
+            <!-- 报警等级列:根据不同等级码显示对应颜色和文字 -->
+            <!-- 101-低风险(蓝色) 102-一般风险(黄色) 103-较大风险(橙色) 104-重大风险(红色) 201-报警(深红色) -->
+            <div v-if="ite.value == 'alarmLevel'"
+              :style="{ color: item[ite.value] == 101 ? '#00d8ff' : item[ite.value] == 102 ? '#fcfc22' : item[ite.value] == 103 ? '#ff7010' : item[ite.value] == 104 ? '#df4e43' : item[ite.value] == 201 ? '#ff0000' : '' }">
+              {{ item[ite.value] == 101 ? '低风险' : item[ite.value] ==
+                102 ? '一般风险' :
+                item[ite.value] == 103 ? '较大风险' : item[ite.value] == 104 ? '重大风险' : item[ite.value] == 201 ? '报警' :
+                  '低风险' }}</div>
+            <!-- 处理状态列:0-未处理(红色) 其他-已处理(绿色) -->
+            <div v-if="ite.value == 'isok'" :style="{ color: item[ite.value] === 0 ? '#fd0404' : '#0eca74' }">{{
+              item[ite.value] === 0 ? '未处理' : '已处理' }}</div>
+            <!-- 操作列:点击"详情"触发详情查看 -->
+            <div v-if="ite.value == 'operation'">
+              <span class="text-look" @click="handlerDetail(item)">详情</span>
+            </div>
+          </div>
+
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, type PropType } from 'vue'
+import { warnTitle } from '../hsqHome.data'
+
+// 接收父组件传入的报警数据列表
+let props = defineProps({
+  tableData: {
+    type: Array as PropType<any[]>,
+    default: () => [],
+  },
+})
+// 报警搜索关键词
+let searchWarn = ref('')
+// 定义事件:detail - 查看报警详情
+let $emit = defineEmits(['detail'])
+
+// 点击"详情"按钮,向父组件派发 detail 事件并传递当前行数据
+function handlerDetail(item: any) {
+  $emit('detail', item)
+}
+</script>
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+@{theme-deepblue} {
+  .search-table {}
+}
+
+/* 整体容器:定义背景图片变量及基础布局 */
+.search-table {
+  --image-box-bg1: url('@/assets/images/home-container/configurable/hsq/2-6.png');
+  --image-box-bg2: url('@/assets/images/home-container/configurable/hsq/2-24.png');
+  position: relative;
+  width: 100%;
+  height: 100%;
+  padding: 15px;
+  box-sizing: border-box;
+}
+
+/* 搜索区域:输入框与筛选按钮水平排列 */
+.search-area {
+  height: 42px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 5px;
+}
+
+/* 筛选按钮外框 */
+.search-btn {
+  width: 85px;
+  height: 30px;
+  border: 1px solid #01fefc;
+  border-radius: 4px;
+  padding: 3px;
+  cursor: pointer;
+}
+
+/* 筛选按钮内部填充 */
+.btn-item {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(32, 166, 169);
+}
+
+/* 内容区域:占据搜索区域以下的所有空间 */
+.content-area {
+  height: calc(100% - 47px);
+}
+
+/* 表头行:使用背景图片装饰 */
+.content-title {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  height: 34px;
+  background: var(--image-box-bg2) no-repeat;
+  background-size: 100% 100%;
+  margin-bottom: 6px;
+}
+
+/* 表头列项:统一居中,青色文字,按列分配 flex 比例 */
+.title-item {
+  display: flex;
+
+  justify-content: center;
+  align-items: center;
+  color: #01fefc;
+
+  &:nth-child(1) {
+    flex: 2;
+  }
+
+  &:nth-child(2) {
+    flex: 2;
+  }
+
+  &:nth-child(3) {
+    flex: 1;
+  }
+
+  &:nth-child(4) {
+    flex: 1;
+  }
+
+  &:nth-child(5) {
+    flex: 1;
+  }
+}
+
+/* 表格内容区:可纵向滚动 */
+.table-content {
+  height: calc(100% - 40px);
+  overflow-y: auto;
+}
+
+/* 数据行:奇偶行交替背景色 */
+.content-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  height: 36px;
+
+  &:nth-child(odd) {
+    background-color: #0e3455;
+  }
+
+  &:nth-child(even) {
+    background-color: #114268;
+  }
+}
+
+/* 数据单元格:居中对齐,按列分配 flex 比例(与表头一致) */
+.item-text {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  text-align: center;
+
+  &:nth-child(1) {
+    flex: 2;
+  }
+
+  &:nth-child(2) {
+    flex: 2;
+  }
+
+  &:nth-child(3) {
+    flex: 1;
+  }
+
+  &:nth-child(4) {
+    flex: 1;
+  }
+
+  &:nth-child(5) {
+    flex: 1;
+  }
+
+}
+
+/* "详情"操作按钮样式 */
+.text-look {
+  padding: 0px 3px;
+  margin: 0px 2px;
+  border-radius: 2px;
+  background-color: #2484bc;
+  cursor: pointer;
+}
+
+/* 搜索输入框:自定义背景图片,去除默认边框 */
+.zxm-input {
+  height: 42px;
+  color: #fff;
+  background-color: transparent;
+  border: none;
+  background: var(--image-box-bg1) no-repeat;
+  background-size: 100% 100%;
+}
+
+/* 小尺寸输入框内边距 */
+.zxm-input-sm {
+  padding: 0px 20px;
+}
+
+/* 隐藏滚动条 */
+::-webkit-scrollbar {
+  display: none;
+}
+</style>

+ 121 - 70
src/views/vent/home/configurable/components/preset/RuleList.vue → src/views/vent/monitorManager/hsqHome/components/WarnRightTop.vue

@@ -1,7 +1,11 @@
 <template>
   <div class="rule-list">
-    <div class="list-title"> 预警规则配置 </div>
+    <div class="list-title"> 设备操作记录 </div>
     <div class="list-content">
+      <div class="content-nav">
+        <div :class="activeIndex == index ? 'nav-item-active' : 'nav-item'" v-for="(item, index) in navList"
+          :key="index" @click="changeNav(item, index)">{{ item.label }}</div>
+      </div>
       <div class="basic-list-content">
         <div class="content-title">
           <div class="title-item" v-for="(item, index) in titleList" :key="index">{{ item.label }}</div>
@@ -14,91 +18,98 @@
             <div class="item-text">
               <a-switch v-model:checked="item.status" size="small" />
             </div>
-            <div class="item-text">
-              <span class="text-look">编辑</span>
-            </div>
           </div>
         </div>
       </div>
-      <div class="basic-list-content">
-        <basicBorder :widthV="298" colorV="orange" title="【编辑规则】一级温度报警(Rule-001)">
-          <div class="temp-warn">
-            <div class="warn-item">
-              <div class="item-label">规则名称 : </div>
-              <a-input class="item-input" v-model:value="rulesData.ruleName" placeholder="请输入" size="small" />
-            </div>
-            <div class="warn-item">
-              <div class="item-label">报警级别 : </div>
-              <a-input class="item-input" v-model:value="rulesData.grade" placeholder="请输入" size="small" />
-            </div>
-            <div class="warn-item">
-              <div class="item-label">温度阈值 : </div>
-              <a-input class="item-input" v-model:value="rulesData.temp" placeholder="请输入" size="small" />
-            </div>
-            <div class="warn-item">
-              <div class="item-label">持续时间 : </div>
-              <a-input class="item-input" v-model:value="rulesData.time" placeholder="请输入" size="small" />
-            </div>
-            <div class="warn-item">
-              <div class="item-label">联动动作 : </div>
-              <a-input class="item-input" v-model:value="rulesData.lddz" placeholder="请输入" size="small" />
-            </div>
-            <div class="warn-item">
-              <div class="item-label">通知对象 : </div>
-              <a-input class="item-input" v-model:value="rulesData.person" placeholder="请输入" size="small" />
-            </div>
-            <div class="btn-box">
-              <div class="baisc-btn">取消</div>
-              <div class="baisc-btn">
-                <div class="btn-item">保存</div>
-              </div>
-            </div>
-          </div>
-        </basicBorder>
-      </div>
+
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
-import { reactive, ref } from 'vue';
-import basicBorder from '../BasicBorder.vue';
-import { rules } from '/@/utils/helper/validator.js';
+import { onMounted, onUnmounted, reactive, ref } from 'vue';
+import {deviceSetLog} from '../hsqHome.api'
 
+//当前激活nav选项
+let activeIndex = ref(0)
+let devicetype=ref('duaSpeCamera')
+let navList = ref<any[]>([
+  { label: '光谱摄像机', value: 'duaSpeCamera' },
+  { label: '火灾探测器', value: 'imgFireDet' }
+])
 let titleList = ref<any[]>([
-  { label: '规则ID', value: '1' },
-  { label: '规则名称', value: '2' },
-  { label: '触发条件', value: '3' },
-  { label: '启用', value: '4' },
-  { label: '操作', value: '5' },
+  { label: '用户', value: '1' },
+  { label: '操作设备', value: '2' },
+  { label: '操作记录', value: '3' },
+  { label: '登录IP', value: '4' },
+  { label: '时间', value: '5' },
 ]);
 let tableData = ref<any[]>([
-  { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
-  { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
-  { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: false },
-  { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
-  { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
-  { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
-  { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
-  { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
-  { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
+  // { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
+  // { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
+  // { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: false },
+  // { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
+  // { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
+  // { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
+  // { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
+  // { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
+  // { ruleId: 'Rule-001', ruleName: '一级温度报警', fctj: '温度>=60℃', status: true },
 ]);
-let rulesData = reactive({
-  ruleName: '',
-  grade: '',
-  temp: '',
-  time: '',
-  lddz: '',
-  person: '',
-});
+let timer: null | NodeJS.Timeout = null;
+/**
+ * 定时获取监测数据
+ * 
+ * @param flag 是否立即执行(默认false,延迟30秒)
+ */
+function getMonitor(flag?: boolean) {
+  timer = setTimeout(async () => {
+    await getDeviceSetLogList(devicetype.value);
+    if (timer) {
+      timer = null;
+    }
+    getMonitor();
+  }, flag ? 0 : 30000);
+}
+//nav选项切换
+function changeNav(item, index) {
+  activeIndex.value = index
+  devicetype.value=item.value
+  switch (index) {
+    case 0:
+      // 处理光谱摄像机逻辑
+      getDeviceSetLogList(devicetype.value)
+      break;
+    case 1:
+      // 处理火灾探测器逻辑
+      getDeviceSetLogList(devicetype.value)
+      break;
+  }
+}
+
+/**
+ * 获取设备操作记录列表
+ * @param param - 设备类型参数
+ * @returns 异步请求设备操作记录,分页查询第1页共100条数据
+ */
+async function getDeviceSetLogList(param) {
+  const res = await deviceSetLog({pageNo:1,pageSize:100,devicetype:param})
+  console.log(res,'设备操作记录')
+}
+
+onMounted(()=>{
+  getMonitor(true)
+})
+onUnmounted(()=>{
+  timer = null
+  clearTimeout(timer);
+})
 </script>
 
 <style lang="less" scoped>
 @import '/@/design/theme.less';
 
 @{theme-deepblue} {
-  .rule-list {
-  }
+  .rule-list {}
 }
 
 .rule-list {
@@ -107,7 +118,7 @@ let rulesData = reactive({
   position: relative;
   width: 100%;
   height: 100%;
-  padding: 10px 15px;
+  padding: 15px;
   box-sizing: border-box;
 
   .list-title {
@@ -127,12 +138,41 @@ let rulesData = reactive({
     justify-content: space-between;
     align-items: center;
     width: 100%;
-    height: calc(100% - 35px);
+    height: calc(100% - 40px);
+  }
+
+  .content-nav {
+    display: flex;
+    align-items: center;
+    height: 32px;
+    width: 100%;
+    margin: 0px 5px 10px 5px;
+    background-color: #15517b;
+  }
+
+  .nav-item {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 120px;
+    height: 100%;
+    cursor: pointer;
+  }
+
+  .nav-item-active {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 120px;
+    height: 100%;
+    cursor: pointer;
+    background-color: #1d73a8;
+    border-bottom: 2px solid #36c7ff;
   }
 
   .basic-list-content {
     width: 100%;
-    height: calc(50% - 5px);
+    height: calc(100% - 42px);
   }
 
   .content-title {
@@ -151,9 +191,11 @@ let rulesData = reactive({
     justify-content: center;
     align-items: center;
     color: #01fefc;
+
     &:nth-child(2) {
       flex: 1.5;
     }
+
     &:nth-child(3) {
       flex: 1.5;
     }
@@ -185,9 +227,11 @@ let rulesData = reactive({
     flex: 1;
     justify-content: center;
     align-items: center;
+
     &:nth-child(2) {
       flex: 1.5;
     }
+
     &:nth-child(3) {
       flex: 1.5;
     }
@@ -196,6 +240,7 @@ let rulesData = reactive({
   .item-text1 {
     color: orange;
   }
+
   .text-look {
     padding: 0px 3px;
     margin: 0px 2px;
@@ -203,10 +248,12 @@ let rulesData = reactive({
     background-color: #2484bc;
     cursor: pointer;
   }
+
   .temp-warn {
     position: relative;
     height: 100%;
   }
+
   .warn-item {
     display: flex;
     align-items: center;
@@ -220,16 +267,19 @@ let rulesData = reactive({
       margin-bottom: 0;
     }
   }
+
   .item-label {
     width: 100px;
     text-align: right;
     margin-right: 5px;
   }
+
   .zxm-input {
     background-color: transparent;
     border: 1px solid #2792c2;
     color: #fff;
   }
+
   .btn-box {
     width: 140px;
     display: flex;
@@ -260,6 +310,7 @@ let rulesData = reactive({
     height: 100%;
     background-color: rgba(32, 166, 169);
   }
+
   ::-webkit-scrollbar {
     display: none;
   }

+ 0 - 0
src/views/vent/home/configurable/components/basicBorder.vue → src/views/vent/monitorManager/hsqHome/components/basicBorder.vue


+ 21 - 8
src/views/vent/home/configurable/components/basicDevice.vue → src/views/vent/monitorManager/hsqHome/components/basicDevice.vue

@@ -4,24 +4,24 @@
       <div class="icon-item"></div>
     </div>
     <div class="basic-title">
-      <div class="title-text">CAM-001</div>
+      <div class="title-text">{{deviceData.strserno || '-' }}</div>
       <div class="title-btn">
-        <div class="btn">详情</div>
-        <div class="btn">配置</div>
-        <div class="btn">重启</div>
+        <div class="btn" @click="handlerClick('detail')">详情</div>
+        <div class="btn" @click="handlerClick('config')">配置</div>
+        <div class="btn" @click="handlerClick('restart')">重启</div>
       </div>
     </div>
     <div class="basic-content">
-      <div class="content-item">双光谱摄像机#1</div>
+      <div class="content-item">{{deviceData.strname || '-' }}</div>
       <div class="content-item">
         <span class="icon-pie">
           <span class="pie-item"></span>
         </span>
-        <span>在线</span>
+        <span>{{deviceData.syswarnLevel ? '报警' : '正常' }}</span>
       </div>
-      <div class="content-item">采掘场A区</div>
+      <div class="content-item">{{deviceData.strinstallpos || '-' }}</div>
       <div class="content-item">
-        <span>32</span>
+        <span>{{deviceData.readData.temperature || '-'}}</span>
         <span>℃</span>
       </div>
     </div>
@@ -31,6 +31,19 @@
 <script setup lang="ts">
 import { ref } from 'vue'
 
+let props = defineProps({
+  deviceData: {
+    type: Object,
+    required: true
+  }
+})
+
+let $emit=defineEmits(['detail'])
+
+function handlerClick(type) {
+  $emit('detail', {type:type,value:props.deviceData})
+}
+
 </script>
 
 <style lang="less" scoped>

+ 0 - 0
src/views/vent/home/configurable/components/navMenu.vue → src/views/vent/monitorManager/hsqHome/components/navMenu.vue


+ 108 - 0
src/views/vent/monitorManager/hsqHome/deviceManger.vue

@@ -0,0 +1,108 @@
+<template>
+  <div class="device-manger">
+    <div class="basic-box">
+      <DeviceLeft @details="handlerDetail"></DeviceLeft>
+    </div>
+    <div class="basic-box">
+      <DeviceCenter :detailData="detailData"></DeviceCenter>
+    </div>
+    <div class="basic-box">
+      <DeviceRight :detailData="configData"></DeviceRight>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import { onMounted, onUnmounted, ref, computed, nextTick, onBeforeMount, watch, reactive } from 'vue';
+import DeviceLeft from './components/DeviceLeft.vue'
+import DeviceCenter from './components/DeviceCenter.vue'
+import DeviceRight from './components/DeviceRight.vue'
+
+// 设备详情
+let strserno = ref<any>({})
+let detailData = ref<any>({})
+// 配置详情
+let configData = ref<any>({})
+
+
+
+function handlerDetail(item: any) {
+  console.log(item, '详情--handlerDetail')
+  switch (item.type) {
+    case 'detail':
+      detailData.value = item.value
+      break
+    case 'config':
+      configData.value = item.value
+      break
+    case 'restart':
+      configData.value = item.value
+      break
+    default:
+    // 其他 cases 待添加
+  }
+}
+/** 初始化页面数据(当前已注释,包含获取配置、系统接口数据及监控信息的逻辑) */
+onMounted(() => {
+
+});
+
+onUnmounted(() => {
+
+});
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+@{theme-deepblue} {
+  .device-manger {}
+}
+
+.device-manger {
+  --image-box1-bg: url('@/assets/images/home-container/configurable/hsq/2-4.png');
+  --image-box1-bg1: url('@/assets/images/home-container/configurable/hsq/2-10.png');
+  display: flex;
+  justify-content: space-between;
+  width: 100%;
+  height: calc(100% - 10px);
+  color: @white;
+  position: relative;
+  margin-bottom: 10px;
+  background-color: #09172c;
+
+  .basic-box {
+    &:nth-child(1) {
+      width: 430px;
+      height: 100%;
+      background: var(--image-box1-bg) no-repeat;
+      background-size: 100% 100%;
+      margin-right: 10px;
+    }
+
+    &:nth-child(2) {
+      position: absolute;
+      top: 63px;
+      left: 50%;
+      transform: translate(-50%, 0);
+      width: calc(100% - 880px);
+      height: calc(100% - 63px);
+      background: var(--image-box1-bg1) no-repeat;
+      background-size: 100% 100%;
+    }
+
+    &:nth-child(3) {
+      width: 430px;
+      height: 100%;
+      background: var(--image-box1-bg) no-repeat;
+      background-size: 100% 100%;
+      margin-left: 10px;
+    }
+  }
+}
+
+
+
+:deep(.loading-box) {
+  position: unset;
+}
+</style>

+ 269 - 0
src/views/vent/monitorManager/hsqHome/fireMonitor.vue

@@ -0,0 +1,269 @@
+<template>
+  <div class="fire-monitor">
+    <div class="basic-fire-box">
+      <div class="box-top">
+        <CommonBd title="设备状态总览">
+          <CustomGalleryNew :option="option" :galleryData="galleryData" :tableData="tableData"></CustomGalleryNew>
+        </CommonBd>
+      </div>
+      <div class="box-cen">
+        <CommonBd title="光谱摄像机">
+          <CommonTable :columns="deviceColumns" :table-data="tableDataGp"></CommonTable>
+        </CommonBd>
+      </div>
+      <div class="box-bot">
+        <CommonBd title="火灾探测器">
+          <CommonTable :columns="deviceColumns" :table-data="tableDataHz"></CommonTable>
+        </CommonBd>
+      </div>
+    </div>
+    <div class="basic-fire-box1">
+      <!-- 模型区域 -->
+      <div class="model-box">
+        <dwgViewer />
+      </div>
+      <div class="box1-bot">
+        <CommonBd title="快捷操作">
+          <QuickAction :quick-option="quickOption" :btn-option="btnOption" :quick-data="quickData"></QuickAction>
+        </CommonBd>
+      </div>
+    </div>
+    <div class="basic-fire-box">
+      <div class="box-top">
+        <CommonBd title="报警监控">
+          <AlarmMonitor :option="alarmOption" :cardData="alarmData"></AlarmMonitor>
+        </CommonBd>
+      </div>
+      <div class="box-cen">
+        <!-- <CommonBd title="区域温度统计">
+          <CustomChart :chart-config="chartTempConfig" :chart-data="chartTempData"></CustomChart>
+        </CommonBd> -->
+        <CommonBd title="实时温度曲线">
+          <CustomChart :chart-config="chartConfig" :chart-data="chartData"></CustomChart>
+        </CommonBd>
+      </div>
+      <div class="box-bot">
+        <CommonBd title="环境监测数据">
+          <EnvironmentMonitor :option="envOption" :environData="envData"></EnvironmentMonitor>
+        </CommonBd>
+      </div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import { onMounted, onUnmounted, ref, computed, nextTick, onBeforeMount, watch, reactive, inject, Ref } from 'vue';
+import CommonBd from './components/CommonBd.vue';
+import CustomGalleryNew from './components/CustomGalleryNew.vue';
+import CustomChart from './components/CustomChart.vue';
+import CommonTable from './components/CommonTable.vue';
+import AlarmMonitor from './components/AlarmMonitor.vue';
+import EnvironmentMonitor from './components/EnvironmentMonitor.vue';
+import QuickAction from './components/QuickAction.vue';
+import dwgViewer from '../../cad/dwgViewer.vue';
+import { option, chartConfig, deviceColumns, quickOption, btnOption, alarmOption, chartTempConfig, } from './hsqHome.data';
+import { managesysList, monitorSystem, deviceList, monitorDevice, getManagesysDeviceNum } from './hsqHome.api';
+
+/** 当前系统ID */
+let systemId = ref('')
+/** 设备状态总览卡片数据 */
+let galleryData = ref({})
+/** 设备列表表格数据(包含双光谱相机和火灾探测器) */
+let tableData = ref<any[]>([])
+/** 光谱摄像机表格数据 */
+let tableDataGp = ref<any[]>([])
+/** 火灾探测器表格数据 */
+let tableDataHz = ref<any[]>([])
+/** 实时温度曲线图表数据 */
+let chartData = ref<any[]>([])
+/** 报警监控卡片数据 */
+let alarmData = ref<any>({
+  dayWarn: 0,
+  warnOk: 0,
+  warnUnOk: 0
+})
+
+
+let chartTempData = [
+  { x: '1', y: 12 },
+  { x: '2', y: 44 },
+  { x: '3', y: 44 },
+  { x: '4', y: 20 },
+]
+
+/** 环境监测设备选项配置 */
+let envOption = ref<any[]>([])
+/** 环境监测数据 */
+let envData = reactive({})
+
+/** 快捷操作面板数据 */
+let quickData = reactive({
+  time: '128天06:32:18',
+  sjsx: '实时',
+  wlyc: '12s',
+})
+/** 定时获取监测数据定时器 */
+let timer: null | NodeJS.Timeout = null;
+
+/**
+ * 定时获取监测数据
+ * 通过定时器循环调用数据获取方法,更新表格数据
+ *
+ * @param flag - 是否立即执行(首次调用时传true跳过延时)
+ */
+function getMonitor(flag?: boolean) {
+  timer = setTimeout(async () => {
+    await getManagesysDeviceNumTj();
+    await getTableData();
+    await getDeviceMonitor();
+    if (timer) {
+      timer = null;
+    }
+    getMonitor();
+  }, flag ? 0 : 30000);
+}
+
+/**
+ * 获取管理系统设备数量统计
+ * 调用 getManagesysDeviceNum 接口,根据当前系统ID获取设备数量统计信息
+ */
+async function getManagesysDeviceNumTj() {
+  const res = await getManagesysDeviceNum({ sysId: systemId.value });
+  galleryData.value = res || {};
+}
+/**
+ * 获取设备列表数据
+ *
+ * 调用 deviceList 接口获取双光谱相机设备列表,
+ * 并将返回数据赋值给 tableData
+ */
+async function getTableData() {
+  const res = await monitorSystem({ type: 'all', systemID: systemId.value, devicetype: '' });
+  tableData.value = [...res.deviceInfo.duaSpeCamera.datalist, ...res.deviceInfo.imgFireDet.datalist]
+  tableDataGp.value = res.deviceInfo.duaSpeCamera.datalist || [];
+  tableDataHz.value = res.deviceInfo.imgFireDet.datalist || [];
+  chartData.value = tableData.value.map(v => ({
+    pos: v.strname,
+    value: v.readData.temperature
+  }))
+  console.log(chartData.value, 'chartData.value')
+}
+
+/**
+ * 获取环境监测设备数据
+ * 调用 monitorDevice 接口,查询指定系统的户外火灾相关监测设备状态
+ */
+async function getDeviceMonitor() {
+  const res = await monitorDevice({ devicetype: 'sys', systemID: systemId.value, types: 'sys_openair_fire' });
+  envOption.value = res.msgTxt.filter(v => v.type.indexOf('modelsensor') != -1).map(el => {
+    return {
+      label: el.datalist[0].typeName,
+      value: Object.keys(el.datalist[0].readData).filter(v => v.endsWith('val') || v.endsWith('ture'))[0],
+      unit: ''
+    }
+  })
+  envData = Object.assign({}, ...res.msgTxt.filter(v => v.type.indexOf('modelsensor') != -1).map(el => el.datalist[0].readData))
+}
+/**
+ * 获取管理系统列表
+ * 调用 managesysList 接口获取户外火灾相关系统列表,并取第一个系统ID作为当前系统
+ */
+async function getManagesysList() {
+  const res = await managesysList({ strtype: 'sys_openair_fire', pagetype: 'normal' });
+  if (res && res.records) {
+    systemId.value = res.records[0].id
+  }
+}
+
+/**
+ * 组件挂载完成
+ * 先获取管理系统列表初始化系统ID,然后立即启动定时获取监测数据
+ */
+onMounted(async () => {
+  await getManagesysList();
+  getMonitor(true);
+});
+
+
+/**
+ * 组件卸载前
+ * 清理定时器,停止轮询获取监测数据
+ */
+onUnmounted(() => {
+  timer = null
+  clearTimeout(timer);
+});
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+
+.fire-monitor {
+  position: relative;
+  width: 100%;
+  height: calc(100% - 10px);
+  color: @white;
+  margin-bottom: 10px;
+  display: flex;
+  justify-content: space-between;
+
+  .basic-fire-box {
+    width: 430px;
+    height: 100%;
+
+
+    &:nth-child(1) {
+      margin-right: 10px;
+    }
+
+    &:nth-child(3) {
+      margin-left: 10px;
+    }
+  }
+
+  .basic-fire-box1 {
+    position: relative;
+    width: calc(100% - 880px);
+    height: 100%;
+  }
+
+  .model-box {
+    position: absolute;
+    top: 63px;
+    left: 0;
+    width: 100%;
+    height: 615px;
+    border: 1px solid rgba(40, 165, 232, 0.8);
+    margin-bottom: 10px;
+  }
+
+  .box1-bot {
+    position: absolute;
+    bottom: 0px;
+    left: 0;
+    width: 100%;
+    height: 155px;
+  }
+
+  .box-top {
+    height: 360px;
+    margin-bottom: 10px;
+
+  }
+
+  .box-cen {
+    height: 220px;
+    margin-bottom: 10px;
+
+  }
+
+  .box-bot {
+    height: 250px;
+  }
+
+}
+
+:deep(.loading-box) {
+  position: unset;
+}
+</style>

+ 77 - 0
src/views/vent/monitorManager/hsqHome/hsqHome.api.ts

@@ -0,0 +1,77 @@
+import { defHttp } from '/@/utils/http/axios';
+
+enum Api {
+  userList = '/sys/user/list',//用户列表接口
+  LongList = '/sys/log/list',//日志列表接口
+  getUserLoginStats = '/sys/log/getUserLoginStats',//今日登录统计
+  deviceList = '/safety/ventanalyDeviceInfo/list',//设备列表
+  autoLogList = '/safety/managesysAutoLog/list',//报警监控接口
+  monitorDevice = '/ventanaly-device/monitor/device', //设备监控
+  deviceSetLog = '/safety/ventanalyDevicesetLog/list', //设备操作记录
+  getManagesysDeviceNum = '/ventanaly-device/safety/ventanalyManageSystem/getManagesysDeviceNum', //设备数量统计
+  managesysList = '/safety/ventanalyManageSystem/list', //获取场景信息
+  monitorSystem = '/monitor/system', //场景设备列表
+  queryRoleAndUserNum = '/sys/role/queryRoleAndUserNum', //查询角色和用户数量
+
+}
+/**
+* 日志列表接口
+* @param params
+*/
+export const LongList = (params) => defHttp.get({ url: Api.LongList, params });
+/**
+* 用户列表接口
+* @param params
+*/
+export const userList = (params) => defHttp.get({ url: Api.userList, params });
+
+//设备列表
+export const deviceList = (params) => defHttp.get({ url: Api.deviceList, params });
+
+/**
+* 今日登录统计
+* @param params
+*/
+export const getUserLoginStats = (params) => defHttp.post({ url: Api.getUserLoginStats, params });
+
+/**
+* 报警监控接口
+* @param params
+*/
+export const autoLogList = (params) => defHttp.get({ url: Api.autoLogList, params });
+
+/**
+* 设备监控接口
+* @param params
+*/
+export const monitorDevice = (params) => defHttp.post({ url: Api.monitorDevice, params });
+
+/**
+* 设备操作记录接口
+* @param params
+*/
+export const deviceSetLog = (params) => defHttp.get({ url: Api.deviceSetLog, params });
+
+/**
+* 设备数量统计接口
+* @param params
+*/
+export const getManagesysDeviceNum = (params) => defHttp.get({ url: Api.getManagesysDeviceNum, params });
+
+/**
+* 获取场景信息接口
+* @param params
+*/
+export const managesysList = (params) => defHttp.get({ url: Api.managesysList, params });
+
+/**
+* 场景设备列表接口
+* @param params
+*/
+export const monitorSystem = (params) => defHttp.post({ url: Api.monitorSystem, params });
+
+/**
+* 查询角色和用户数量接口
+* @param params
+*/
+export const queryRoleAndUserNum = (params) => defHttp.get({ url: Api.queryRoleAndUserNum, params });

+ 181 - 0
src/views/vent/monitorManager/hsqHome/hsqHome.data.ts

@@ -0,0 +1,181 @@
+//设备状态总览
+export let option = [
+  {
+    label: '在线设备',
+    value: 'onlineNum',
+  },
+  {
+    label: '离线设备',
+    value: 'offlineNum',
+  },
+  {
+    label: '故障设备',
+    value: 'faultNum',
+  },
+  {
+    label: '报警设备',
+    value: 'alarmNum',
+  },
+]
+
+//实时温度曲线
+export const chartConfig: any = {
+  type: 'line_area',
+  grid: {
+    top: 40,
+    left: 30,
+    bottom: 14,
+    right: 30,
+  },
+  legend: { show: false },
+  xAxis: [{ show: true }],
+  yAxis: [{ show: true, name: '(℃)', position: 'left' }],
+  series: [
+    {
+      label: '温度',
+      readFrom: '',
+      xprop: 'pos',
+      yprop: 'value',
+      color: ['rgba(52, 193, 248,.8)', 'rgba(52, 193, 248,.2)'],
+    },
+  ],
+};
+
+//设备状态表格
+export let deviceColumns: any[] = [
+  {
+    name: '设备名称',
+    prop: 'strname',
+  },
+  {
+    name: '在线状态',
+    prop: 'netStatus',
+  },
+  {
+    name: '报警状态',
+    prop: 'syswarnLevel',
+  },
+]
+
+//快捷操作
+export let quickOption = [
+  { label: '系统运行时间', value: 'time', iconName: 'time-run' },
+  { label: '数据刷新', value: 'sjsx', iconName: 'data-reset' },
+  { label: '网络延迟', value: 'wlyc', iconName: 'internet-on' },
+]
+export let btnOption = [
+  { firstLabel: '报警确认', secondLabel: '视屏调取', thirdLabel: '联动控制' },
+  { firstLabel: '数据导出', secondLabel: '生成报表', thirdLabel: '定位追踪' },
+  { firstLabel: '声光关闭', secondLabel: '应急广播', thirdLabel: '系统设置' },
+]
+
+//报警监控
+export let alarmOption = [
+  {
+    label: '今日报警',
+    value: 'dayWarn',
+  },
+  {
+    label: '已处理',
+    value: 'warnOk',
+  },
+  {
+    label: '未处理',
+    value: 'warnUnOk',
+  },
+]
+
+//区域温度统计
+export let chartTempConfig: any = {
+  type: 'bar_cylinder_wide',
+  readFrom: '',
+  grid: {
+    top: 40,
+    left: 50,
+    bottom: 14,
+    right: 50,
+  },
+  legend: { show: false },
+  xAxis: [{ show: true }],
+  yAxis: [{ show: true, name: '', position: 'left' }],
+  series: [{ readFrom: '', xprop: 'x', yprop: 'y', label: '温度' }],
+}
+
+
+//export let envOption = [
+//  { label: '环境温度', value: 'tempHj', unit: '℃' },
+//  { label: '风速风向', value: 'fsfx', unit: 'm/s' },
+//  { label: '温度', value: 'temp', unit: '%' },
+//  { label: 'CO浓度', value: 'coval', unit: 'ppm' },
+//  { label: 'CO2浓度', value: 'co2val', unit: 'ppm' },
+//  { label: 'O2浓度', value: 'o2val', unit: '%' },
+//  { label: 'Ch4浓度', value: 'ch4val', unit: '%' },
+//  { label: '粉尘浓度', value: 'fcnd', unit: 'mg/m³' },
+//  { label: '烟雾指数', value: 'ywzs', unit: '' },
+//  { label: '地表温度', value: 'tempDb', unit: '℃' },
+//]
+
+//用户列表
+export let optionUser = [
+  { label: '用户账号', value: 'username' },
+  { label: '用户姓名', value: 'realname' },
+  { label: '所属角色', value: 'userRolesStr' },
+  { label: '部门', value: 'orgCodeTxt' },
+  { label: '手机号', value: 'phone' },
+  { label: '状态', value: 'status_dictText' },
+]
+
+//日志审计
+export let logbtnOption = [
+  { label: '登录日志', value: 'login' },
+  { label: '操作日志', value: 'operate' },
+  { label: '浏览日志', value: 'look' },
+]
+export let titleOption = [
+  { label: '操作人ID', value: 'userid' },
+  { label: '操作人', value: 'username' },
+  { label: '日志内容', value: 'logContent' },
+  { label: 'IP', value: 'ip' },
+  { label: '创建时间', value: 'createTime' },
+  { label: '日志类型', value: 'logType_dictText' },
+]
+
+//今日登录统计
+export let dayLoginConfig: any = {
+  type: 'bar_cylinder_wide',
+  readFrom: '',
+  grid: {
+    top: 55,
+    left: 20,
+    bottom: 25,
+    right: 20,
+  },
+  legend: { show: false },
+  xAxis: [{ show: true }],
+  yAxis: [{ show: true, name: '', position: 'left' }],
+  series: [{ readFrom: '', xprop: 'x', yprop: 'y', label: '次数' }],
+}
+
+//报警列表表头
+export let warnTitle = [
+  { label: '时间', value: 'starttime' },
+  { label: '位置', value: 'alarmName' },
+  { label: '级别', value: 'alarmLevel' },
+  { label: '状态', value: 'isok' },
+  { label: '操作', value: 'operation' },
+]
+
+export let alarmColumns:any[] =[
+  {
+    name: '时间',
+    prop: 'starttime',
+  },
+  {
+    name: '位置',
+    prop: 'alarmName',
+  },
+  {
+    name: '报警级别',
+    prop: 'alarmLevelC',
+  },
+]

+ 114 - 0
src/views/vent/monitorManager/hsqHome/index.vue

@@ -0,0 +1,114 @@
+<template>
+  <div class="hsq-home">
+    <div class="top-bg">
+      <div class="main-title">{{ mainTitle }}</div>
+    </div>
+    <div class="nav">
+      <navMenu :activeIndex="activeIndex" @changeMenu="changeMenu"></navMenu>
+    </div>
+    <div class="main-container">
+      <component :is="activeComponente"></component>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, type Component, type Ref, watch, onMounted, provide } from 'vue';
+import navMenu from './components/navMenu.vue'
+import fireMonitor from './fireMonitor.vue'
+import deviceManger from './deviceManger.vue'
+import warnMonitor from './warnMonitor.vue'
+import systemManger from './systemManger.vue'
+import largeScreen from './largeScreen.vue'
+import linkConfiguration from './linkConfiguration.vue'
+
+
+/** 菜单键值映射接口,定义各导航菜单项对应的 key 标识 */
+interface IMenuKeyMap {
+  yzt: 'yzt'
+  jcyj: 'jcyj'
+  sbgl: 'sbgl'
+  ldpz: 'ldpz'
+  xtgl: 'xtgl'
+  dpzs: 'dpzs'
+}
+/** 菜单 key 类型,从 IMenuKeyMap 中提取所有键的联合类型 */
+type MenuKey = IMenuKeyMap[keyof IMenuKeyMap]
+/** 组件引用类型,继承 Vue 的 Ref<Component>,用于动态组件切换 */
+interface IComponentReference extends Ref<Component> { }
+
+// 当前激活的菜单项
+const activeIndex = ref<number>(0);
+// 主标题
+const mainTitle = ref<string>('红沙泉露天煤矿火灾监测预警系统');
+//当前激活界面
+const activeComponente = ref<Component>(fireMonitor) as IComponentReference;
+/** 菜单 key 与组件的映射表,用于根据导航菜单项动态切换显示组件 */
+const menuComponentMap: Record<MenuKey, Component> = {
+  yzt: fireMonitor,
+  jcyj: warnMonitor,
+  sbgl: deviceManger,
+  ldpz: linkConfiguration,
+  xtgl: systemManger,
+  dpzs: largeScreen,
+}
+
+/**
+ * 导航菜单切换事件
+ * 根据菜单 key 从映射表中查找对应组件,更新当前激活的动态组件
+ * @param param - 菜单标识 key,对应 menuComponentMap 中的键
+ */
+function changeMenu(param: MenuKey) {
+  activeComponente.value = menuComponentMap[param];
+  activeIndex.value = Object.keys(menuComponentMap).indexOf(param);
+}
+</script>
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+.hsq-home {
+  --image-modal-top: url('@/assets/images/vent/vent-header1.png');
+  position: relative;
+  width: 100%;
+  height: 100%;
+  color: #fff;
+
+  .top-bg {
+    width: 100%;
+    height: 80px;
+    background: var(--image-modal-top) no-repeat center;
+    background-size: 100% 100%;
+    position: absolute;
+    z-index: 1;
+
+    .main-title {
+      height: 80px;
+      line-height: 62px;
+      font-family: 'douyuFont';
+      font-size: 22px;
+      letter-spacing: 2px;
+      display: flex;
+      justify-content: center;
+    }
+  }
+
+  .nav {
+    position: absolute;
+    left: 50%;
+    top: 60px;
+    transform: translate(-50%, 0);
+    width: 1000px;
+    height: 68px;
+    z-index: 9999;
+  }
+
+  .main-container {
+    position: absolute;
+    top: 70px;
+    width: 100%;
+    height: calc(100% - 70px);
+    padding: 0px 10px;
+    box-sizing: border-box;
+  }
+}
+</style>

+ 0 - 0
src/views/vent/home/configurable/largeScreen.vue → src/views/vent/monitorManager/hsqHome/largeScreen.vue


+ 84 - 0
src/views/vent/monitorManager/hsqHome/linkConfiguration.vue

@@ -0,0 +1,84 @@
+<template>
+  <div class="link-configuration">
+    <div class="link-left">
+      <div class="link-left-top">
+        <LinkRuleTable />
+      </div>
+      <div class="link-left-bottom">
+        <LinkRuleStats />
+      </div>
+    </div>
+    <div class="link-center">
+      <LinkRuleEditor />
+    </div>
+    <div class="link-right">
+      <LinkLogPanel />
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import LinkRuleTable from './components/LinkRuleTable.vue';
+import LinkRuleStats from './components/LinkRuleStats.vue';
+import LinkRuleEditor from './components/LinkRuleEditor.vue';
+import LinkLogPanel from './components/LinkLogPanel.vue';
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+@{theme-deepblue} {}
+
+.link-configuration {
+  --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-4.png');
+  --image-box-bg1: url('@/assets/images/home-container/configurable/hsq/2-10.png');
+  display: flex;
+  justify-content: space-between;
+  width: 100%;
+  height: calc(100% - 10px);
+  color: @white;
+  position: relative;
+  margin-bottom: 10px;
+  background-color: #09172c;
+
+  .link-left {
+    width: 430px;
+    height: 100%;
+    margin-right: 10px;
+    display: flex;
+    flex-direction: column;
+    background: var(--image-box-bg) no-repeat;
+    background-size: 100% 100%;
+  }
+
+  .link-left-top {
+    flex: 1;
+    min-height: 0;
+    overflow: hidden;
+  }
+
+  .link-left-bottom {
+    height: 190px;
+    flex-shrink: 0;
+  }
+
+  .link-center {
+    position: absolute;
+    top: 63px;
+    left: 50%;
+    transform: translate(-50%, 0);
+    width: calc(100% - 880px);
+    height: calc(100% - 63px);
+    background: var(--image-box-bg1) no-repeat;
+    background-size: 100% 100%;
+  }
+
+  .link-right {
+    width: 430px;
+    height: 100%;
+    margin-left: 10px;
+    background: var(--image-box-bg) no-repeat;
+    background-size: 100% 100%;
+  }
+}
+</style>

+ 198 - 0
src/views/vent/monitorManager/hsqHome/systemManger.vue

@@ -0,0 +1,198 @@
+<template>
+  <div class="system-manger">
+    <div class="basic-top-box">
+      <div class="system-box-t">
+        <SystemLeftTop :option="optionUser" :data="listData"></SystemLeftTop>
+      </div>
+      <div class="system-box-t">
+        <SystemRightTop :userInfo="userInfo"></SystemRightTop>
+      </div>
+    </div>
+    <div class="basic-bot-box">
+      <div class="system-box-b">
+        <!-- <SystemLeftBottom :btnOption="logbtnOption" :titleOption="titleOption" :data="logList" @changeTab="changeTab">
+        </SystemLeftBottom> -->
+        <SystemLeftBottom title="登录日志"  :titleOption="titleOption" :data="logList" >
+        </SystemLeftBottom>
+      </div>
+      <div class="system-box-b">
+        <!-- <SystemCenBottom :data="dayList"></SystemCenBottom> -->
+          <SystemLeftBottom title="浏览日志" :titleOption="titleOption" :data="lookLogList" >
+        </SystemLeftBottom>
+      </div>
+      <!-- <div class="system-box-b">
+        <SystemRightBot></SystemRightBot>
+      </div> -->
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import { onMounted, onUnmounted, reactive, ref, watch } from 'vue';
+import SystemLeftTop from './components/SystemLeftTop.vue';
+import SystemRightTop from './components/SystemRightTop.vue';
+import SystemLeftBottom from './components/SystemLeftBottom.vue';
+import SystemCenBottom from './components/SystemCenBottom.vue';
+import SystemRightBot from './components/SystemRightBot.vue';
+import { userList, LongList, getUserLoginStats ,queryRoleAndUserNum} from './hsqHome.api.js'
+import { optionUser, logbtnOption, titleOption } from './hsqHome.data.js'
+import dayjs from 'dayjs';
+
+let listData = ref([])
+// let logType = ref(1)
+let logList = ref([])
+let lookLogList = ref([])
+// let searchData = reactive({
+//   dayEnd: dayjs().format('YYYY-MM-DD') ,
+//   dayStart:dayjs().startOf('date').subtract(7, 'day').format('YYYY-MM-DD'),
+// })
+let userInfo=ref<any[]>([])
+
+//获取用户列表
+async function getUserList() {
+  let res = await userList({ order: 'desc', pageNo: 1, pageSize: 1000 })
+  listData.value = res.records || []
+}
+
+//获取日志列表
+async function getLogList() {
+  let res = await LongList({ logType: 1, pageNo: 1, pageSize: 1000 })
+  logList.value = res.records || []
+}
+async function getLookLogList() {
+  let res = await LongList({ logType: 3, pageNo: 1, pageSize: 1000 })
+  lookLogList.value = res.records || []
+}
+// //日志选项切换
+// function changeTab(param) {
+//   switch (param) {
+//     case 'login':
+//       logType.value = 1
+//       getLogList()
+//       break;
+//     case 'operate':
+//       logType.value = 2
+//       getLogList()
+//       break;
+//     case 'look':
+//       logType.value = 3
+//       getLogList()
+//       break;
+//   }
+// }
+//今日统计列表
+// async function getDayTjList() {
+//   let res = await getUserLoginStats({ pageNoL: 1, pageSize: 100, ...searchData })
+//   console.log(res,'今日统计---')
+//   dayList.value = res.records || []
+// }
+//查询角色和用户数量
+async function queryRoleAndUserNumInfo() {
+  let res = await queryRoleAndUserNum({})
+  console.log(res,'角色和用户数量---')
+  if(res && res.length){
+    userInfo.value = res.map(item => ({
+      label: item.roleName,
+      value: item.userNum,
+    }))
+  }
+}
+
+onMounted(() => {
+  getUserList()
+  getLogList()
+  getLookLogList()
+  // getDayTjList()
+  queryRoleAndUserNumInfo()
+});
+
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+@{theme-deepblue} {
+  .system-manger {}
+}
+
+.system-manger {
+  --image-box1-bg: url('@/assets/images/home-container/configurable/hsq/3-2.png');
+  --image-box1-bg1: url('@/assets/images/home-container/configurable/hsq/5-3.png');
+  --image-box1-bg2: url('@/assets/images/home-container/configurable/hsq/5-4.png');
+  --image-box1-bg3: url('@/assets/images/home-container/configurable/hsq/5-2.png');
+  --image-box1-bg4: url('@/assets/images/home-container/configurable/hsq/5-6.png');
+  --image-box1-bg5: url('@/assets/images/home-container/configurable/hsq/5-5.png');
+  width: 100%;
+  height: calc(100% - 10px);
+  color: @white;
+  position: relative;
+  margin-bottom: 10px;
+  background-color: #09172c;
+
+  .basic-top-box {
+    position: relative;
+    height: calc(100% - 280px);
+    margin-bottom: 10px;
+  }
+
+  .basic-bot-box {
+    display: flex;
+    justify-content: space-between;
+    height: 270px;
+  }
+
+  .system-box-t {
+    &:nth-child(1) {
+      position: absolute;
+      top: 63px;
+      left: 0;
+      width: calc(100% - 440px);
+      height: calc(100% - 63px);
+      background: var(--image-box1-bg) no-repeat;
+      background-size: 100% 100%;
+    }
+
+    &:nth-child(2) {
+      position: absolute;
+      top: 63px;
+      right: 0;
+      width: 430px;
+      height: calc(100% - 63px);
+      margin-left: 10px;
+      background: var(--image-box1-bg1) no-repeat;
+      background-size: 100% 100%;
+    }
+  }
+
+  .system-box-b {
+    &:nth-child(1) {
+      width: calc(50% - 5px);
+      height: 100%;
+      margin-right: 5px;
+      background: var(--image-box1-bg3) no-repeat;
+      background-size: 100% 100%;
+    }
+
+    &:nth-child(2) {
+      width: calc(50% - 5px);
+      height: 100%;
+      margin-left: 5px;
+        background: var(--image-box1-bg3) no-repeat;
+         background-size: 100% 100%;
+    }
+
+    // &:nth-child(3) {
+    //   width: 430px;
+    //   height: 100%;
+    //   margin-left: 10px;
+    //   background: var(--image-box1-bg2) no-repeat;
+    //   background-size: 100% 100%;
+    // }
+  }
+}
+
+
+
+:deep(.loading-box) {
+  position: unset;
+}
+</style>

+ 168 - 0
src/views/vent/monitorManager/hsqHome/warnMonitor.vue

@@ -0,0 +1,168 @@
+<template>
+  <!-- 告警监控主容器 -->
+  <div class="warn-monitor">
+    <!-- 顶部区域:三个面板横向排列 -->
+    <div class="warn-top-box">
+      <!-- 左侧面板:告警列表 -->
+      <div class="baisc-box">
+        <WarnLeftTop :tableData="tableData" @detail="handlerDetail"></WarnLeftTop>
+      </div>
+      <!-- 中间面板:告警详情展示 -->
+      <div class="baisc-box">
+        <WarnCenTop :warnData="warnData"></WarnCenTop>
+      </div>
+      <!-- 右侧面板:告警统计 -->
+      <div class="baisc-box">
+        <WarnRightTop></WarnRightTop>
+      </div>
+    </div>
+    <!-- 底部区域:告警趋势/历史记录 -->
+    <div class="warn-bot-box">
+      <WarnBottom></WarnBottom>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import { onMounted, onUnmounted, ref, computed, nextTick, onBeforeMount, watch } from 'vue';
+import WarnLeftTop from './components/WarnLeftTop.vue';
+import WarnCenTop from './components/WarnCenTop.vue'
+import WarnRightTop from './components/WarnRightTop.vue'
+import WarnBottom from './components/WarnBottom.vue'
+import { autoLogList, managesysList } from './hsqHome.api'
+
+// 告警列表数据
+let tableData = ref<any[]>([])
+// 当前选中的告警详情数据
+let warnData = ref({})
+// 系统ID,用于筛选数据
+let systemId = ref('')
+
+// 定时器引用,用于页面卸载时清理
+let timer: null | NodeJS.Timeout = null;
+/**
+ * 定时获取监测数据
+ * 
+ * @param flag 是否立即执行(默认false,延迟30秒执行)
+ */
+function getMonitor(flag?: boolean) {
+  timer = setTimeout(async () => {
+    // 获取告警列表数据
+    await getWarnList();
+    if (timer) {
+      timer = null;
+    }
+    // 递归调用实现持续轮询
+    getMonitor();
+  }, flag ? 0 : 30000);
+}
+
+/**
+ * 获取告警列表数据
+ * 根据systemId筛选告警记录,最多返回100条
+ */
+async function getWarnList() {
+  let res = await autoLogList({ pageNum: 1, pageSize: 100, sysId: systemId.value });
+  tableData.value = res.records || []
+}
+
+/**
+ * 处理告警详情点击事件
+ * 将选中的告警项数据传递给中间面板显示
+ * 
+ * @param item 选中的告警记录
+ */
+function handlerDetail(item: any) {
+  warnData.value = item
+}
+
+/**
+ * 获取系统列表并设置默认系统ID
+ * 用于初始化时获取systemId,供后续接口调用使用
+ */
+async function getManagesysList() {
+  const res = await managesysList({ strtype: 'sys_openair_fire', pagetype: 'normal' });
+  if (res && res.records) {
+    systemId.value = res.records[0].id
+  }
+}
+
+// 页面加载时初始化数据并启动定时轮询
+onMounted(async() => {
+   await getManagesysList();
+   getMonitor(true);
+});
+
+// 页面卸载时清理定时器,防止内存泄漏
+onUnmounted(() => {
+  timer = null
+  clearTimeout(timer);
+});
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+@{theme-deepblue} {
+  .warn-monitor {}
+}
+
+.warn-monitor {
+  --image-box1-bg: url('@/assets/images/home-container/configurable/hsq/2-4.png');
+  --image-box1-bg1: url('@/assets/images/home-container/configurable/hsq/2-10.png');
+  --image-box1-bg2: url('@/assets/images/home-container/configurable/hsq/3-3.png');
+  width: 100%;
+  height: calc(100% - 10px);
+  color: @white;
+  position: relative;
+  background-color: #09172c;
+  margin-bottom: 10px;
+}
+
+.warn-top-box {
+  position: relative;
+  display: flex;
+  justify-content: space-between;
+  height: calc(100% - 200px);
+  margin-bottom: 10px;
+}
+
+.warn-bot-box {
+  width: 100%;
+  height: 190px;
+  background: var(--image-box1-bg2) no-repeat;
+  background-size: 100% 100%;
+}
+
+.baisc-box {
+  &:nth-child(1) {
+    width: 430px;
+    height: 100%;
+    background: var(--image-box1-bg) no-repeat;
+    background-size: 100% 100%;
+    margin-right: 10px;
+  }
+
+  &:nth-child(2) {
+    position: absolute;
+    top: 63px;
+    left: 50%;
+    transform: translate(-50%, 0);
+    width: calc(100% - 880px);
+    height: calc(100% - 63px);
+    background: var(--image-box1-bg1) no-repeat;
+    background-size: 100% 100%;
+  }
+
+  &:nth-child(3) {
+    width: 430px;
+    height: 100%;
+    background: var(--image-box1-bg) no-repeat;
+    background-size: 100% 100%;
+    margin-left: 10px;
+  }
+}
+
+:deep(.loading-box) {
+  position: unset;
+}
+</style>

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików