Browse Source

Merge branch 'master' of http://182.92.126.35:3000/hrx/mky-vent-base

lxh 1 month ago
parent
commit
1b5e2fa8af
37 changed files with 8967 additions and 1159 deletions
  1. 2 0
      package.json
  2. 7693 510
      pnpm-lock.yaml
  3. BIN
      public/model/img/air.png
  4. 1 1
      src/components/Form/src/jeecg/components/base/JSelectBiz.vue
  5. 11 8
      src/components/Table/src/hooks/useTableFooter.ts
  6. 0 1
      src/components/Table/src/hooks/useTableScroll.ts
  7. 5 7
      src/hooks/vent/useSystemSelect.ts
  8. 9 9
      src/utils/dict/DictColors.js
  9. 1 1
      src/views/system/user/UserDrawer.vue
  10. 12 0
      src/views/system/user/user.data.ts
  11. 105 102
      src/views/vent/comment/history/HistoryTable.vue
  12. 8 0
      src/views/vent/comment/history/history.api.ts
  13. 2 18
      src/views/vent/comment/history/history.data.ts
  14. 1 0
      src/views/vent/gas/components/tab/baseTab.vue
  15. 25 23
      src/views/vent/gas/gasAssessment/components/workFace.vue
  16. 80 60
      src/views/vent/gas/gasAssessment/gasAssessment.data.ts
  17. 6 6
      src/views/vent/gas/gasAssessment/index.vue
  18. 12 11
      src/views/vent/gas/gasHome/components/customHeader.vue
  19. 5 9
      src/views/vent/gas/gasHome/gasHome.data.ts
  20. 14 16
      src/views/vent/gas/gasHome/index.vue
  21. 2 0
      src/views/vent/gas/gasInspectNonfc/gasInspectNonfc.api.ts
  22. 119 5
      src/views/vent/gas/gasInspectNonfc/index2.vue
  23. 6 0
      src/views/vent/gas/gasReport/gas-report.api.ts
  24. 402 237
      src/views/vent/gas/gasReport/index.vue
  25. 107 25
      src/views/vent/gas/gasZk/index.vue
  26. 8 0
      src/views/vent/monitorManager/balancePressMonitor/balancePress.data.ts
  27. 33 2
      src/views/vent/monitorManager/balancePressMonitor/components/balancePressHome.vue
  28. 104 22
      src/views/vent/monitorManager/deviceCameraMonitor/index.vue
  29. 5 22
      src/views/vent/monitorManager/deviceMonitor/components/device/index.vue
  30. 67 3
      src/views/vent/monitorManager/mainFanMonitor/mainWind.threejs.ts
  31. 69 4
      src/views/vent/monitorManager/mainFanMonitor/mainWind.xj.threejs.ts
  32. 6 3
      src/views/vent/monitorManager/safetyMonitor/AlarmHistoryTable.vue
  33. 3 3
      src/views/vent/monitorManager/windowMonitor/components/modal.vue
  34. 2 2
      src/views/vent/monitorManager/windowMonitor/index.vue
  35. 37 30
      src/views/vent/monitorManager/workFaceMonitor/components/workFaceHandleHistory.vue
  36. 3 9
      src/views/vent/monitorManager/workFaceMonitor/components/workFaceHistory.vue
  37. 2 10
      src/views/vent/reportManager/comment/common/cameraTree.vue

+ 2 - 0
package.json

@@ -73,6 +73,7 @@
     "showdown": "^2.1.0",
     "sortablejs": "^1.15.0",
     "three": "^0.162.0",
+    "three.path": "^1.0.1",
     "tinymce": "^5.10.3",
     "vditor": "^3.9.5",
     "vue": "^3.2.0",
@@ -92,6 +93,7 @@
     "xgplayer": "^3.0.14",
     "xgplayer-flv": "^3.0.14",
     "xgplayer-hls": "^3.0.14",
+    "xgplayer-mp4": "^3.0.21",
     "xss": "^1.0.14"
   },
   "devDependencies": {

File diff suppressed because it is too large
+ 7693 - 510
pnpm-lock.yaml


BIN
public/model/img/air.png


+ 1 - 1
src/components/Form/src/jeecg/components/base/JSelectBiz.vue

@@ -22,7 +22,7 @@
           style="width: 100%"
           @click="!disabled && openModal(false)"
           v-bind="attrs"
-        ></a-select>
+        />
       </a-col>
       <a-col v-if="showButton" class="right">
         <a-button v-if="buttonIcon" :preIcon="buttonIcon" type="primary" @click="openModal(true)" :disabled="disabled">选择</a-button>

+ 11 - 8
src/components/Table/src/hooks/useTableFooter.ts

@@ -21,17 +21,20 @@ export function useTableFooter(
   });
 
   // 是否有展开行
-  const hasExpandedRow = computed(() => Object.keys(slots).includes('expandedRowRender'))
+  const hasExpandedRow = computed(() => Object.keys(slots).includes('expandedRowRender'));
 
   const getFooterProps = computed((): Recordable | undefined => {
     const { summaryFunc, showSummary, summaryData, bordered } = unref(propsRef);
-    return showSummary && !unref(getIsEmptyData) ? () => h(TableFooter, {
-      bordered,
-      summaryFunc,
-      summaryData,
-      scroll: unref(scrollRef),
-      hasExpandedRow: hasExpandedRow.value
-    }) : undefined;
+    return showSummary && !unref(getIsEmptyData)
+      ? () =>
+          h(TableFooter, {
+            bordered,
+            summaryFunc,
+            summaryData,
+            scroll: unref(scrollRef),
+            hasExpandedRow: hasExpandedRow.value,
+          })
+      : undefined;
   });
 
   watchEffect(() => {

+ 0 - 1
src/components/Table/src/hooks/useTableScroll.ts

@@ -87,7 +87,6 @@ export function useTableScroll(
 
     bodyEl!.style.height = 'unset';
 
-
     await nextTick();
     //Add a delay to get the correct bottomIncludeBody paginationHeight footerHeight headerHeight
 

+ 5 - 7
src/hooks/vent/useSystemSelect.ts

@@ -31,13 +31,11 @@ export function useSystemSelect(sysType: string, changeModalType?: (param) => vo
         const readData = data.readData;
         return Object.assign(data, readData);
       });
-      if (item.type != 'sys') {
-        deviceArr.unshift({
-          deviceType: item.type,
-          deviceName: item['typeName'] ? item['typeName'] : item['datalist'][0]['typeName'],
-          datalist: data,
-        });
-      }
+      deviceArr.unshift({
+        deviceType: item.type,
+        deviceName: item['typeName'] ? item['typeName'] : item['datalist'][0]['typeName'],
+        datalist: data,
+      });
     });
     deviceList.value = deviceArr;
     if (isFirst) {

+ 9 - 9
src/utils/dict/DictColors.js

@@ -1,5 +1,5 @@
-const whiteColor = '#ffffff'
-const blackColor = '#666666'
+const whiteColor = '#ffffff';
+const blackColor = '#666666';
 
 export const Colors = [
   // 背景颜色,文字颜色
@@ -24,9 +24,9 @@ export const Colors = [
   ['#DEC2FA', blackColor],
   ['#CCD2F1', blackColor],
   ['#D3D3D3', blackColor],
-]
+];
 
-export const NONE_COLOR = ['#e9e9e9', blackColor]
+export const NONE_COLOR = ['#e9e9e9', blackColor];
 
 /**
  * 返回一个颜色迭代器,每次调用返回一个颜色,当颜色用完后,再从头开始
@@ -45,20 +45,20 @@ export function getColorIterator(initIndex = 0) {
       index = (index + 1) % Colors.length;
       return color;
     },
-  }
+  };
 }
 
 /**
  * 根据颜色获取当前坐标和颜色
  */
 export function getItemColor(color) {
-  if(!color){
+  if (!color) {
     return NONE_COLOR[1];
   }
-  let colorIndex = Colors.findIndex((value)=>{
+  let colorIndex = Colors.findIndex((value) => {
     return value[0] === color;
-  })
-  if(colorIndex === -1){
+  });
+  if (colorIndex === -1) {
     return NONE_COLOR[1];
   }
   return Colors[colorIndex][1];

+ 1 - 1
src/views/system/user/UserDrawer.vue

@@ -128,7 +128,7 @@
       //关闭弹窗
       closeDrawer();
       //刷新列表
-      emit('success',{isUpdateVal ,values});
+      emit('success', { isUpdateVal, values });
     } finally {
       setDrawerProps({ confirmLoading: false });
     }

+ 12 - 0
src/views/system/user/user.data.ts

@@ -3,6 +3,7 @@ import { FormSchema } from '/@/components/Table';
 import { getAllRolesList, getAllTenantList } from './user.api';
 import { rules } from '/@/utils/helper/validator';
 import { render } from '/@/utils/common/renderUtils';
+
 export const columns: BasicColumn[] = [
   {
     title: '用户账号',
@@ -278,6 +279,17 @@ export const formSchema: FormSchema[] = [
     },
   },
   {
+    label: '签名',
+    field: 'elcSignPath',
+    component: 'JUpload',
+    componentProps: {
+      fileMax: 1,
+      fileType: 'image',
+      bizPath: 'elcSign',
+      returnUrl: true,
+    },
+  },
+  {
     label: '生日',
     field: 'birthday',
     component: 'DatePicker',

+ 105 - 102
src/views/vent/comment/history/HistoryTable.vue

@@ -19,8 +19,8 @@
 
 <script lang="ts" setup>
   // 场景类历史数据公共组件!
-  // 用于服务场景类历史数据业务,这类数据通常由一条数据返回多个子设备的信息,例如:{ forcFan1Temp, forcFan2Temp };
-  // 而此组件可以将这些数据分类,例如:表格只有 温度 一列,但可以根据所选的子设备展示不同的数据
+  // 用于服务带子设备的设备历史数据业务,这类数据通常由一条数据返回多个子设备的信息,例如:{ forcFan1Temp, forcFan2Temp };
+  // 而此组件可以将这些数据分类,例如:表格只有 温度 一列,但可以根据所选的子设备展示子设备1的数据:forcFan1Temp
   // 综上所述,此组件在基础的历史数据组件上添加了子设备下拉框(由字典驱动),用户选择子设备后表头将动态调整以适配数据展示;
   //
   // 使用方法如下:
@@ -28,7 +28,7 @@
   //
   // 1、配置设备字段(参考公司端综合设备管理-设备字段管理)
   // 以压风机为例,设压风机设备的历史数据编码为forcFan_history。
-  // 那么字段code中需要把所有字段悉数配置,例子如下:
+  // 那么需要把所有字段悉数配置,例子如下:
   //  显示字段    字段code
   //   温度     forcFanTemp
   //  安装位置      name
@@ -51,6 +51,10 @@
   //      温度        安装位置
   // 取forcFan1Temp    取name
   // 当设备字段不含数据字典关键词(forcFan)时不做处理,当设备字段包含关键词但已指定编号(即字段包含数字)时不做处理
+  //
+  // 5、历史数据模式选择
+  // 历史数据的请求分为redis分站模式、其他模式,redis分站模式将不支持子设备选择,参考基础的历史数据组件逻辑(本组件已做兼容)
+  // 历史数据查询模式分为多设备查询模式、单设备查询模式,单设备查询模式将不支持设备多选,两种模式本组件都支持
   import { computed, onMounted, ref, shallowRef } from 'vue';
   import { BasicColumn, PaginationProps, BasicTable } from '/@/components/Table';
   import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
@@ -94,11 +98,11 @@
     }
   );
 
-  // 创建表格,此表格目前不具备常用功能,需要初始化后使用(props指定表格配置时除外)
+  // 未经过处理的原始表头,即项目配置的表头
   let originColumns: BasicColumn[] = [];
-  const scroll = computed(() => {
-    return { ...props.scroll, y: props.scroll.y - 100 };
-  });
+  // 表格数据
+  const data = shallowRef([]);
+
   const { tableContext, onExportXls, onExportXlsPost } = useListPage({
     tableProps: {
       columns: [
@@ -127,7 +131,9 @@
       size: 'small',
       showIndexColumn: true,
       tableLayout: 'auto',
-      scroll: scroll,
+      scroll: computed(() => {
+        return { ...props.scroll, y: props.scroll.y - 100 };
+      }),
       pagination: props.pagination,
     },
     exportConfig: {
@@ -137,16 +143,62 @@
   });
   const [register, { getForm, setLoading, getPaginationRef, setPagination, setColumns }] = tableContext;
 
+  // 已选中的设备信息
+  const deviceInfo = ref<Record<string, unknown>>({});
+  // 设备下拉框选项
+  const deviceOptions = ref<Record<string, unknown>[]>([]);
+  // 子设备下拉框选项
+  const dictOptions = ref<Record<string, unknown>[]>([]);
+
+  /**
+   * 获取设备信息列表、子设备字典,初始化设备可选项、子设备可选项并选中首个设备
+   */
+  async function fetchDevice() {
+    const results = await getDeviceList({ devicetype: props.deviceCode, pageSize: 10000 });
+    const dicts = await initDictOptions(props.dictCode);
+
+    const options = results.map((item) => {
+      return {
+        label: item.strinstallpos,
+        value: item.id || item.deviceID,
+        deviceType: item.strtype || item.deviceType,
+        devicekind: item.devicekind,
+        stationtype: item.stationtype,
+      };
+    });
+    deviceOptions.value = options;
+    dictOptions.value = dicts;
+    onDeviceChangeCallback(null, options[0]);
+  }
+
   /**
-   * 初始化表格,该方法将根据参数设定新的表头、表单,如果提供了自定义的表头、表单配置则不作操作。
+   * 选择任意设备后的回调,根据设备信息刷新表格、表头及其数据
+   */
+  function onDeviceChangeCallback(__, option) {
+    // 生成所有需要查询的表头编码,例如 forcFan_auto 对应 forcFan_auto_history、forcFan_history 这两个
+    const codes: string[] = [];
+    deviceInfo.value = option;
+    if (deviceInfo.value && deviceInfo.value.deviceType) {
+      const arr = (deviceInfo.value.deviceType as string).split('_');
+      while (arr.length) {
+        codes.push(arr.join('_').concat('_history'));
+        arr.pop();
+      }
+    }
+    // 如此,例如deviceType为forcFan_auto, 则查询表头按 forcFan_auto_history、forcFan_history、columnsCode 为顺序
+    initTable(codes.concat(props.columnsCode));
+    search();
+  }
+
+  /**
+   * 初始化表格,该方法将根据参数设定新的表头、表单。
    *
-   * 之所以将设备相关的信息作参数传入,是因为这样可以确认依赖关系,即需要有设备信息之后再初始化表格。
+   * 需要有设备信息之后再初始化表格。
    *
    * @param deviceCodes 获取表头所用的编码,从左到右依次尝试,直到找到第一个有表头信息的为止
-   * @param deviceOptions 设备下拉框对应的选项
    */
-  function initTable(deviceCodes: string[], deviceOptions: any[], dictOptions: any[]) {
-    const defaultSchemas = getDefaultSchemas(dictOptions, deviceOptions, () => search());
+  function initTable(deviceCodes: string[]) {
+    const defaultSchemas = getDefaultSchemas(dictOptions.value, deviceOptions.value, onDeviceChangeCallback);
     for (const code of deviceCodes) {
       const cols = getTableHeaderColumns(code);
       if (cols.length) {
@@ -160,6 +212,35 @@
   }
 
   /**
+   * 搜索,核心方法
+   *
+   * 该方法获取表单、处理表单数据后尝试获取数据并设置表头
+   */
+  async function search() {
+    if (!deviceInfo.value) return;
+
+    const form = getForm();
+    await form.validate();
+    const formData = form.getFieldsValue();
+
+    setLoading(true);
+    const pagination = getPaginationRef() as PaginationProps;
+    const deviceCode = (deviceInfo.value.deviceType || props.deviceCode.concat('*')) as string;
+    const { records, total, current } = await list(deviceCode, deviceInfo, formData, pagination).finally(() => {
+      setLoading(false);
+    });
+    setPagination({
+      current,
+      total,
+    });
+    records.forEach((item) => {
+      Object.assign(item, item.readData);
+    });
+    data.value = records;
+    updateColumns(formData.deviceNum);
+  }
+
+  /**
    * 更新表头,表头默认情况下需要和子设备联动
    * @param prefix 子设备的值,即为表头取数据时字段的前缀
    */
@@ -185,89 +266,14 @@
     setColumns(cols);
   }
 
-  // 表格数据相关的字段
-  const data = shallowRef([]);
-
-  /**
-   * 获取列表的数据
-   *
-   * 这些参数确认了依赖关系,即需要有表单数据、设备信息之后再尝试获取表格数据。
-   *
-   * @param formData 表格上方的表单数据
-   * @param deviceCode 设备编码
-   * @param deviceInfo 设备信息
-   */
-  function fetchData(formData: Record<string, unknown>, deviceCode: string, deviceInfo: any) {
-    setLoading(true);
-    const pagination = getPaginationRef() as PaginationProps;
-    return list(deviceCode, deviceInfo, formData, pagination)
-      .then(({ records, total, current }) => {
-        setPagination({
-          current,
-          total,
-        });
-        records.forEach((item) => {
-          Object.assign(item, item.readData);
-        });
-        data.value = records;
-      })
-      .finally(() => {
-        setLoading(false);
-      });
-  }
-
-  // 设备信息相关的字段
-  const deviceInfo = ref<Record<string, unknown>>({});
-  const deviceOptions = ref<Record<string, unknown>[]>([]);
-  const dictOptions = ref<Record<string, unknown>[]>([]); // 子设备下拉框选项
-
-  /**
-   * 获取设备信息列表,初始化设备信息及设备可选项
-   */
-  async function fetchDevice() {
-    const results = await getDeviceList({ devicetype: props.deviceCode, pageSize: 10000 });
-    const dicts = await initDictOptions(props.dictCode);
-
-    const options = results.map((item) => {
-      return {
-        label: item.strinstallpos,
-        value: item.id || item.deviceID,
-        deviceType: item.strtype || item.deviceType,
-        devicekind: item.devicekind,
-        stationtype: item.stationtype,
-      };
-    });
-    deviceOptions.value = options;
-    deviceInfo.value = results[0] || {};
-    dictOptions.value = dicts;
-  }
-
-  /**
-   * 搜索,核心方法
-   *
-   * 该方法获取表单、处理表单数据后尝试获取数据并设置表头
-   */
-  async function search() {
-    const form = getForm();
-    await form.validate();
-    const formData = form.getFieldsValue();
-    const info = deviceOptions.value.find((opt) => {
-      return opt.value === formData.gdeviceids.split(',')[0];
-    });
-    if (!info) return;
-    deviceInfo.value = info;
-    const code = (deviceInfo.value.deviceType || props.deviceCode.concat('*')) as string;
-    await fetchData(formData, code, deviceInfo.value);
-    updateColumns(formData.deviceNum);
-  }
-
   /** 导出表格内容为excel */
   async function exportXls() {
     const form = getForm();
     await form.validate();
     const formData = form.getFieldsValue();
     const pagination = getPaginationRef() as PaginationProps;
-    const params = adaptFormData(props.deviceCode, deviceInfo.value, formData, pagination);
+    const deviceCode = (deviceInfo.value.deviceType || props.deviceCode.concat('*')) as string;
+    const params = adaptFormData(deviceCode, deviceInfo.value, formData, pagination);
     if (deviceInfo.value.stationtype === 'redis') {
       return onExportXlsPost(params);
     } else {
@@ -275,20 +281,17 @@
     }
   }
 
+  // watch(
+  //   () => props.deviceCode,
+  //   async () => {
+  //     await fetchDevice();
+  //     onDeviceChangeCallback(null, deviceInfo.value);
+  //   }
+  // );
+
   onMounted(async () => {
     await fetchDevice();
-    // 生成所有需要查询的表头编码,例如 forcFan_auto 对应 forcFan_auto_history、forcFan_history 这两个
-    const codes: string[] = [];
-    if (deviceInfo.value && deviceInfo.value.deviceType) {
-      const arr = (deviceInfo.value.deviceType as string).split('_');
-      while (arr.length) {
-        codes.push(arr.join('_').concat('_history'));
-        arr.pop();
-      }
-    }
-    // 如此,例如deviceType为forcFan_auto, 则查询表头按 forcFan_auto_history、forcFan_history、columnsCode 为顺序
-    initTable(codes.concat(props.columnsCode), deviceOptions.value, dictOptions.value);
-    search();
+    onDeviceChangeCallback(null, deviceInfo.value);
   });
 </script>
 

+ 8 - 0
src/views/vent/comment/history/history.api.ts

@@ -28,6 +28,14 @@ const intervalMap = new Map([
   ['8', '1h'],
 ]);
 
+/**
+ * 根据所给设备的分站信息、设备编码等信息生成历史数据/数据导出api所需的请求参数
+ * @param deviceCode
+ * @param deviceInfo
+ * @param formData
+ * @param pagination
+ * @returns
+ */
 export const adaptFormData = (deviceCode: string, deviceInfo: any, formData: any, pagination: PaginationProps) => {
   if (deviceInfo.stationtype === 'redis') {
     return {

+ 2 - 18
src/views/vent/comment/history/history.data.ts

@@ -8,6 +8,7 @@ import { get } from 'lodash-es';
  *
  * @param dictOptions 用于初始化子设备下拉框
  * @param deviceOptions 用于初始化设备下拉框
+ * @param onDeviceChange 设备下拉框选择内容后的回调函数
  * @returns
  */
 export const getDefaultSchemas: (dictOptions: any[], deviceOptions: any[], onDeviceChange?: Function) => FormSchema[] = (
@@ -16,8 +17,8 @@ export const getDefaultSchemas: (dictOptions: any[], deviceOptions: any[], onDev
   onDeviceChange?: Function
 ) => {
   const device = get(deviceOptions, '[0].value', '');
-  const dictcode = get(dictOptions, '[0].value', '');
   const isRedis = get(deviceOptions, '[0].stationtype', 'redis') === 'redis';
+  const dictcode = get(dictOptions, '[0].value', '');
   return [
     {
       field: 'ttime_begin',
@@ -75,29 +76,12 @@ export const getDefaultSchemas: (dictOptions: any[], deviceOptions: any[], onDev
       componentProps: {
         options: dictOptions,
         // onChange: (e, option) => {
-        //   nextTick(async () => {
-        //     await getDataSource();
-        //   });
         // },
       },
       colProps: {
         span: 3,
       },
     },
-    // {
-    //   label: '子设备',
-    //   field: 'deviceNum',
-    //   // component: 'JDictSelectTag',
-    //   // show: Boolean(dictCode),
-    //   componentProps: {
-    //     dictCode,
-    //     showChooseOption: false,
-    //     placeholder: '请选择',
-    //   },
-    //   colProps: {
-    //     span: 4,
-    //   },
-    // },
     {
       label: '间隔时间',
       field: 'skip',

+ 1 - 0
src/views/vent/gas/components/tab/baseTab.vue

@@ -36,6 +36,7 @@
     font-weight: bold;
     background-color: @vent-gas-tab-bg;
     border-radius: 5px 5px 0 0;
+    color: @vent-font-color;
   }
 
   .tabs_pane_actived {

+ 25 - 23
src/views/vent/gas/gasAssessment/components/workFace.vue

@@ -12,7 +12,7 @@
               v-for="(item, index) in gasMonitor"
               :key="index"
               class="w-100% mb-5px"
-              :value="get(dataSource, item.code)"
+              :value="get(workFaceData, item.code)"
               :label="item.title"
               labelWidth="200px"
             />
@@ -24,7 +24,7 @@
             <div>工作面基础信息</div>
           </template>
           <template #container>
-            <CustomChart :chart-config="gasUnitBarOption" :chart-data="mockData" height="280px" />
+            <CustomChart :chart-config="gasUnitBarOption" :chart-data="gasUnitDataSource" height="280px" />
           </template>
         </ventBox1>
       </div>
@@ -41,7 +41,7 @@
                 v-for="(item, index) in gasPumpValve"
                 :key="index"
                 class="w-100% mb-5px"
-                :value="get(dataSource, item.code)"
+                :value="get(workFaceData, item.code)"
                 :label="item.title"
                 labelWidth="200px"
               />
@@ -52,7 +52,7 @@
               <div>工作面基础信息</div>
             </template>
             <template #container>
-              <CustomChart :chart-config="gasUnitPieOption" :chart-data="mockPieData" height="280px" />
+              <CustomChart :chart-config="gasUnitPieOption" :chart-data="gasUnitDataSource" height="280px" />
             </template>
           </ventBox1>
         </div>
@@ -62,37 +62,39 @@
 </template>
 
 <script setup lang="ts">
-  import { ref, onMounted } from 'vue';
+  import { ref, onMounted, watch } from 'vue';
   import ventBox1 from '/@/components/vent/ventBox1.vue';
   import CustomBadges from './customHeader.vue';
   import { gasMonitor, headerBadges, gasPumpValve, gasUnitBarOption, mockData, gasUnitPieOption, mockPieData } from '../gasAssessment.data';
   import ListItem from '@/views/vent/gas/components/list/listItem.vue';
   import { get } from '@/utils/ventutil';
   import CustomChart from '@/views/vent/home/configurable/components/detail/CustomChart.vue';
+  type DeviceType = { deviceType: string; deviceName: string; datalist: any[] };
+  const props = defineProps({
+    dataSource: {
+      type: Object,
+      default: () => {},
+    },
+  });
 
   const loading = ref(false);
-  const dataSource = ref({});
+  const gasUnitDataSource = ref<DeviceType>(); // 抽采单元监测数据
+  const workFaceData = ref<any>({}); // 工作面基础数据
 
-  // // https获取监测数据
-  let timer: null | NodeJS.Timeout = null;
-  function getMonitor(flag?) {
-    if (Object.prototype.toString.call(timer) === '[object Null]') {
-      timer = setTimeout(
-        async () => {
-          if (timer) {
-            timer = null;
-          }
-          await getMonitor();
-          // loading.value = false;
-        },
-        flag ? 0 : 1000
-      );
+  watch(
+    () => props.dataSource,
+    (newValue: DeviceType[]) => {
+      if (newValue && newValue.length > 0) {
+        gasUnitDataSource.value = newValue.find((item) => item.deviceType.startsWith('unit'));
+        const workFaceDataSorce = newValue.find((item) => item.deviceType === 'sys');
+        if (workFaceDataSorce) {
+          workFaceData.value = workFaceDataSorce.datalist[0];
+        }
+      }
     }
-  }
+  );
 
   onMounted(async () => {
-    timer = null;
-    await getMonitor(true);
     loading.value = true;
   });
 </script>

+ 80 - 60
src/views/vent/gas/gasAssessment/gasAssessment.data.ts

@@ -137,53 +137,48 @@ export const echartsOption = reactive({
 
 export const gasMonitor = [
   {
-    title: '工作面编号',
-    code: 'T0',
-    unit: '',
-  },
-  {
-    title: '所属采区',
-    code: 'T1',
-    unit: '',
+    title: '工作面走向长度',
+    code: 'workingFaceZouxiangLength',
+    unit: 'm',
   },
   {
-    title: '开采煤层',
-    code: 'T2',
-    unit: '',
+    title: '煤层厚度',
+    code: 'coalSeamThickness',
+    unit: 'm',
   },
   {
-    title: '工作面走向长度',
-    code: 'CO2',
+    title: '切眼长度',
+    code: 'workingFaceQieyanLength',
     unit: 'm',
   },
   {
-    title: '工作面切眼长度',
-    code: 'gasC',
+    title: '工作面长度',
+    code: 'workingFaceLengeh',
     unit: 'm',
   },
   {
-    title: '工作面煤炭储量',
-    code: 'gasMixMass',
-    unit: 'm³/t',
+    title: '工作面采高',
+    code: 'workingFaceHeight',
+    unit: 'm',
   },
   {
-    title: '原始瓦斯储量',
-    code: 'gasMass',
-    unit: 'm³/t',
+    title: '煤炭储量',
+    code: 'coalReserves',
+    unit: 't',
   },
   {
-    title: '工作面瓦斯含量',
-    code: 'gasMass',
+    title: '原始瓦斯含量',
+    code: 'originalGasContent',
     unit: 'm³/t',
   },
   {
-    title: '预抽瓦斯标量 (m³)',
-    code: 'gasTotalMass',
-    unit: '',
+    title: '工作面瓦斯储量',
+    code: 'gasReserves',
+    unit: '',
   },
   {
-    title: '抽采单元数量',
-    code: 'windPressure',
+    title: '预抽瓦斯认标量',
+    code: 'scalarRecognition',
     unit: '',
   },
 ];
@@ -411,45 +406,70 @@ export const currentGasMonitor = [
 
 export const gasPumpValve = [
   {
-    title: '开抽日期',
-    code: 'T0',
-    unit: '',
-  },
-  {
-    title: '支管抽采负压',
-    code: 'T0',
-    unit: '',
-  },
-  {
-    title: '支管抽采流量',
-    code: 'T0',
-    unit: '',
-  },
-  {
-    title: '抽采管路气体温度',
-    code: 'T0',
+    title: '开始抽采日期',
+    code: 'beginDrainageDate',
     unit: '',
   },
   {
-    title: '抽采管路甲烷浓度',
-    code: 'T0',
-    unit: '',
+    title: '已抽时间',
+    code: 'totalDate',
+    unit: '天',
   },
   {
-    title: '抽采管路一氧化碳浓度',
-    code: 'T0',
+    title: '抽采单元数量',
+    code: 'unitNum',
     unit: '',
   },
   {
     title: '累计流量',
-    code: 'T0',
-    unit: '',
+    code: 'cumulativeFlow',
+    unit: '',
   },
   {
     title: '累计纯量',
-    code: 'T0',
-    unit: '',
+    code: 'cumulativeScalar',
+    unit: '',
   },
+  // {
+  //   title: '开抽日期',
+  //   code: 'T0',
+  //   unit: '',
+  // },
+  // {
+  //   title: '支管抽采负压',
+  //   code: 'T0',
+  //   unit: '',
+  // },
+  // {
+  //   title: '支管抽采流量',
+  //   code: 'T0',
+  //   unit: '',
+  // },
+  // {
+  //   title: '抽采管路气体温度',
+  //   code: 'T0',
+  //   unit: '',
+  // },
+  // {
+  //   title: '抽采管路甲烷浓度',
+  //   code: 'T0',
+  //   unit: '',
+  // },
+  // {
+  //   title: '抽采管路一氧化碳浓度',
+  //   code: 'T0',
+  //   unit: '',
+  // },
+  // {
+  //   title: '累计流量',
+  //   code: 'T0',
+  //   unit: '',
+  // },
+  // {
+  //   title: '累计纯量',
+  //   code: 'T0',
+  //   unit: '',
+  // },
 ];
 
 export const gasUnitDetail = [
@@ -541,9 +561,9 @@ export const gasUnitBarOption: ModuleDataChart = {
   yAxis: [{ show: true, name: '', position: 'left' }],
   series: [
     {
-      readFrom: 'arrayDev',
-      xprop: 'strinstallpos',
-      yprop: 'val',
+      readFrom: 'datalist',
+      xprop: 'strname',
+      yprop: 'unitval',
       label: '',
     },
   ],
@@ -584,9 +604,9 @@ export const gasUnitPieOption: ModuleDataChart = {
   yAxis: [{ show: true, name: '', position: 'left' }],
   series: [
     {
-      readFrom: 'arrayDev',
-      xprop: 'strinstallpos',
-      yprop: 'val',
+      readFrom: 'datalist',
+      xprop: 'strname',
+      yprop: 'unitval',
       label: '',
     },
   ],

+ 6 - 6
src/views/vent/gas/gasAssessment/index.vue

@@ -32,7 +32,7 @@
     </div>
   </div>
   <template v-if="activeKey == 'gasAssessment'">
-    <WorkFace class="point-event" v-if="pageType == 'workFace'" />
+    <WorkFace class="point-event" v-if="pageType == 'workFace'" :data-source="dataSource" />
     <gasUnit class="point-event" v-if="pageType == 'gasUnit'" />
   </template>
   <template v-if="activeKey == 'gasEcharts'">
@@ -64,10 +64,11 @@
   import WorkFace from './components/workFace.vue';
   import GasVideo from './components/gasVideo.vue';
   import BottomMenu from '/@/views/vent/comment/components/bottomMenu.vue';
+  type DeviceType = { deviceType: string; deviceName: string; datalist: any[] };
 
   const activeKey = ref('gasAssessment');
   const loading = ref(false);
-  const dataSource = ref({});
+  const dataSource = ref<DeviceType[]>([]);
   const pageType = ref('workFace');
   const activeUnitId = ref('');
 
@@ -81,7 +82,7 @@
     setModelType(modalType, gasUnitNum.value);
   };
 
-  const { options, optionValue, deviceActive, getSelectRow, getSysDataSource, getDeviceList } = useSystemSelect(
+  const { options, optionValue, deviceActive, deviceValue, getSelectRow, getSysDataSource, getDeviceList } = useSystemSelect(
     'sys_surface_caimei',
     changeModalType
   );
@@ -98,9 +99,8 @@
     if (Object.prototype.toString.call(timer) === '[object Null]') {
       timer = setTimeout(
         async () => {
-          if (deviceActive.value) {
-            await getDeviceList();
-          }
+          debugger;
+          dataSource.value = await getDeviceList();
           if (timer) {
             timer = null;
           }

+ 12 - 11
src/views/vent/gas/gasHome/components/customHeader.vue

@@ -16,9 +16,9 @@
   import Badge01Src from '@/assets/images/vent/home/badge01.png';
   import Badge02Src from '@/assets/images/vent/home/badge02.png';
   import Badge03Src from '@/assets/images/vent/home/badge03.png';
-  import Badge04Src from '@/assets/images/vent/home/badge04.png';
-  import Badge05Src from '@/assets/images/vent/home/badge05.png';
-  import Badge06Src from '@/assets/images/vent/home/badge06.png';
+  // import Badge04Src from '@/assets/images/vent/home/badge04.png';
+  import Badge04Src from '@/assets/images/vent/home/badge05.png';
+  import Badge05Src from '@/assets/images/vent/home/badge06.png';
 
   // @TODO 对组件的颜色、背景等样式进行修改,符合全局规范
 
@@ -29,7 +29,7 @@
 
   const items = [
     {
-      bgSrc: Badge06Src,
+      bgSrc: Badge05Src,
       color: '#d9e6ec',
     },
     {
@@ -41,17 +41,17 @@
       color: '#9ea890',
     },
     {
-      bgSrc: Badge05Src,
+      bgSrc: Badge04Src,
       color: '#d7deea',
     },
     {
       bgSrc: Badge01Src,
       color: '#dbe0d7',
     },
-    {
-      bgSrc: Badge04Src,
-      color: '#d8d5e4',
-    },
+    // {
+    //   bgSrc: Badge04Src,
+    //   color: '#d8d5e4',
+    // },
   ];
 </script>
 
@@ -74,15 +74,16 @@
     background-repeat: no-repeat;
     background-position: center center;
     background-size: 100% auto;
-    width: 185px;
+    width: 235px;
     height: 70px;
     padding-left: 80px;
   }
 
   .custom-header__badge_title {
     font-size: 20px;
+    margin-left: 10px;
   }
   .custom-header__badge_desc {
-    font-size: 12px;
+    font-size: 14px;
   }
 </style>

+ 5 - 9
src/views/vent/gas/gasHome/gasHome.data.ts

@@ -87,19 +87,15 @@ export const caikongqu = [
     code: 'juejin.num',
   },
   {
-    title: '回采工作面位置(?)',
+    title: '采空区数量',
     code: 'caikongqu.num',
   },
   {
-    title: '掘进工作面位置(?)',
-    code: 'caikongqu.num',
+    title: '抽采达标数量',
+    code: 'sysInfo.totalComplteQuantity',
   },
   {
-    title: '采空区数量',
-    code: 'caikongqu.num',
-  },
-  {
-    title: '采空区位置(?)',
-    code: 'caikongqu.num',
+    title: '平均抽采率',
+    code: 'sysInfo.totalAverageRate',
   },
 ];

+ 14 - 16
src/views/vent/gas/gasHome/index.vue

@@ -11,7 +11,7 @@
   </div>
 </template>
 <script lang="ts" setup>
-  import { ref, onBeforeMount, onBeforeUnmount, onMounted } from 'vue';
+  import { ref, onBeforeMount, onBeforeUnmount, onMounted, computed } from 'vue';
   import CustomHeader from '/@/components/vent/customHeader.vue';
   import CustomBadges from './components/customHeader.vue';
   import GasMonitor from './components/gasMonitor.vue';
@@ -21,6 +21,8 @@
   import BottomMenu from '/@/views/vent/comment/components/bottomMenu.vue';
   import { navList } from './gasHome.data';
   import { useRouter } from 'vue-router';
+  import { get } from '@/utils/ventutil';
+
   const router = useRouter();
   const activeKey = ref('gasHome');
   const dataSource = ref<any | null>(null);
@@ -60,30 +62,26 @@
     }
   }
 
-  const headerBadges = ref([
-    {
-      title: 'T1',
-      desc: '累积瓦斯抽采量',
-    },
+  const headerBadges = computed(() => [
     {
-      title: 'T2',
-      desc: '平均瓦斯抽采率',
+      title: get(dataSource.value, 'sysInfo.totalGasVolume'),
+      desc: '累积瓦斯抽采量(万t/d)',
     },
     {
-      title: 'T3',
-      desc: '抽采达标工作面数量',
+      title: get(dataSource.value, 'sysInfo.totalAverageRate'),
+      desc: '平均瓦斯抽采率(%)',
     },
     {
-      title: 'T4',
-      desc: '抽采钻孔类型',
+      title: get(dataSource.value, 'sysInfo.totalComplteQuantity'),
+      desc: '抽采达标工作面数量(个)',
     },
     {
-      title: 'T5',
-      desc: '回采中工作面数量',
+      title: get(dataSource.value, 'sysInfo.useM3Perent'),
+      desc: '有效风量率(%)', //回采中工作面数量
     },
     {
-      title: 'T6',
-      desc: '抽采钻孔总进尺',
+      title: get(dataSource.value, 'sysInfo.drillinFootage'),
+      desc: '抽采钻孔总进尺(m)',
     },
   ]);
 

+ 2 - 0
src/views/vent/gas/gasInspectNonfc/gasInspectNonfc.api.ts

@@ -16,6 +16,7 @@ enum Api {
   addGasReportAddressNew = '/safety/gasDayReport/addGasReportAddressNew', //新增瓦斯巡检地址(新自动排序)
   clearCardInfoNew = '/safety/gasIns/deleteNew', //瓦斯巡检卡信息删除(新自动排序)
   editNew = '/safety/gasIns/editNew', //瓦斯巡检地点编辑(新自动排序)
+  queryHisCurve = '/safety/gasDayReport/queryHisCurve', //瓦斯巡检地点历史数据
 }
 
 /**
@@ -83,3 +84,4 @@ export const taskSubmit = (params) => defHttp.post({ url: Api.taskSubmit, params
 export const addGasReportAddressNew = (params) => defHttp.post({ url: Api.addGasReportAddressNew, params });
 export const clearCardInfoNew = (params) => defHttp.delete({ url: Api.clearCardInfoNew, params }, { joinParamsToUrl: true });
 export const editNew = (params) => defHttp.post({ url: Api.editNew, params });
+export const queryHisCurve = (params) => defHttp.post({ url: Api.queryHisCurve, params });

+ 119 - 5
src/views/vent/gas/gasInspectNonfc/index2.vue

@@ -31,6 +31,7 @@
         @change="pageChange"
       >
         <template #action="{ record }">
+          <a class="table-action-link" @click="handlerCurve(record)">历史曲线</a>
           <a class="table-action-link" @click="handlerEdit(record)">编辑</a>
           <a-popconfirm title="删除内容无法恢复,是否删除" ok-text="确定" cancel-text="取消" @confirm="handleDelCardInfo(record)">
             <a class="table-action-link">删除</a>
@@ -74,6 +75,27 @@
       <a-modal v-model:visible="visibleAddress" width="450px" :footer="null" :title="titleAddress" centered destroyOnClose>
         <addressAdd @confirmAddress="confirmAddress" @cancelAddress="cancelAddress" />
       </a-modal>
+
+      <BasicModal :width="1000" title="历史曲线" @register="registerModal">
+        <Space>
+          <a-range-picker
+            style="width: 220px"
+            :showTime="false"
+            valueFormat="YYYY-MM-DD"
+            :value="[chartParams.startTime, chartParams.endTime]"
+            @change="onRangeChange"
+          />
+          <RadioGroup class="ml-auto" v-model:value="chartParams.category" @change="getChartData">
+            <Radio value="gwSdz">甲烷</Radio>
+            <Radio value="co2">二氧化碳</Radio>
+            <Radio value="co">一氧化碳</Radio>
+            <Radio value="o2">氧气</Radio>
+            <Radio value="temp">温度</Radio>
+          </RadioGroup>
+          <a-button type="primary" :loading="chartLoaing" @click="getChartData">查询</a-button>
+        </Space>
+        <LineMulti height="300px" x-axis-prop-type="time" :chart-data="chartData" :option="chartOption" :prop-type-arr="new Map([['val', '值']])" />
+      </BasicModal>
     </div>
   </div>
 </template>
@@ -85,7 +107,7 @@
   import inspectEdit from './components/inspectEdit2.vue';
   import uploadOrdown from './components/uploadOrdown.vue';
   import addressAdd from './components/addressAdd2.vue';
-  import { message } from 'ant-design-vue';
+  import { message, RadioGroup, Space, Radio } from 'ant-design-vue';
   import { columns2, pagination } from './gasInspectNonfc.data';
   import {
     list,
@@ -96,7 +118,11 @@
     taskSubmit,
     clearCardInfoNew,
     addGasReportAddressNew,
+    queryHisCurve,
   } from './gasInspectNonfc.api';
+  import { BasicModal, useModal } from '/@/components/Modal';
+  import LineMulti from '/@/components/chart/LineMulti.vue';
+  import dayjs from 'dayjs';
 
   let keyActive = ref(0);
   let searchParams = ref('');
@@ -278,7 +304,6 @@
   //确定新增
   async function confirmAddress(param) {
     let res = await addGasReportAddressNew(param);
-    console.log(res, '新增瓦斯巡检地点');
     if (res) {
       visibleAddress.value = false;
       queryByIdList();
@@ -288,6 +313,95 @@
   let cancelAddress = () => {
     visibleAddress.value = false;
   };
+
+  const [registerModal, { openModal }] = useModal();
+  const chartParams = ref({
+    startTime: dayjs().subtract(1, 'day').format('YYYY-MM-DD'),
+    endTime: dayjs().format('YYYY-MM-DD'),
+    category: 'temp',
+    devId: '',
+  });
+  const chartLoaing = ref(false);
+  const chartData = ref<any[]>([]);
+  const chartOption = ref({
+    yAxis: {
+      type: 'value',
+      name: '',
+    },
+  });
+
+  function onRangeChange(__, time) {
+    chartParams.value.startTime = time[0];
+    chartParams.value.endTime = time[1];
+  }
+
+  async function handlerCurve(record) {
+    chartParams.value.devId = record.id;
+    openModal();
+    getChartData();
+  }
+
+  async function getChartData() {
+    chartLoaing.value = true;
+    const result = await queryHisCurve(chartParams.value).finally(() => {
+      chartLoaing.value = false;
+    });
+    switch (chartParams.value.category) {
+      case 'gwSdz':
+        chartData.value = result.map((e) => {
+          return {
+            time: e.time,
+            val: e.gwSdz,
+          };
+        });
+        chartOption.value.yAxis.name = '%';
+        break;
+
+      case 'co2':
+        chartData.value = result.map((e) => {
+          return {
+            time: e.time,
+            val: e.co2,
+          };
+        });
+        chartOption.value.yAxis.name = '%';
+        break;
+
+      case 'co':
+        chartData.value = result.map((e) => {
+          return {
+            time: e.time,
+            val: e.co,
+          };
+        });
+        chartOption.value.yAxis.name = 'ppm';
+        break;
+
+      case 'o2':
+        chartData.value = result.map((e) => {
+          return {
+            time: e.time,
+            val: e.o2,
+          };
+        });
+        chartOption.value.yAxis.name = '%';
+        break;
+
+      case 'temp':
+        chartData.value = result.map((e) => {
+          return {
+            time: e.time,
+            val: e.t,
+          };
+        });
+        chartOption.value.yAxis.name = '℃';
+        break;
+
+      default:
+        break;
+    }
+  }
+
   onMounted(() => {
     queryByIdList();
   });
@@ -338,9 +452,9 @@
     border-right: 1px solid #91e9fe !important;
   }
 
-  :deep(.zxm-picker-input > input) {
-    color: #fff;
-  }
+  // :deep(.zxm-picker-input > input) {
+  //   color: #fff;
+  // }
 
   :deep(.zxm-select:not(.zxm-select-customize-input) .zxm-select-selector) {
     border: 1px solid #3ad8ff77 !important;

+ 6 - 0
src/views/vent/gas/gasReport/gas-report.api.ts

@@ -6,6 +6,8 @@ enum Api {
   expComReportByParam = '/safety/reportInfo/expComReportByParam',
   reviewPass = '/safety/gasDayReport/reviewPass',
   getIsReviewPass = '/safety/gasDayReport/getIsReviewPass',
+  getAllUserInfo = '/safety/gasInsCard/getAllUserInfo',
+  exportReportByPoi = '/safety/reportInfo/exportReportByPoi',
 }
 /**
  * 获取瓦斯日报区队,检测地点下拉选项
@@ -34,3 +36,7 @@ export const reviewPass = (params) => defHttp.post({ url: Api.reviewPass, params
  * @param params
  */
 export const getIsReviewPass = (params) => defHttp.post({ url: Api.getIsReviewPass, params });
+
+export const getAllUserInfo = (params) => defHttp.get({ url: Api.getAllUserInfo, params });
+
+export const exportReportByPoi = (params) => defHttp.post({ url: Api.exportReportByPoi, params, responseType: 'blob' });

+ 402 - 237
src/views/vent/gas/gasReport/index.vue

@@ -6,9 +6,14 @@
         <a-row>
           <a-col :span="4">
             <div class="area-item">
-              <div class="item-text">填报日期:</div>
-              <a-date-picker style="width: 220px" :showTime="false" valueFormat="YYYY-MM-DD"
-                v-model:value="searchData.reportTime" placeholder="请选择填报日期" @change="onChange" />
+              <div class="item-text">日期区间:</div>
+              <a-date-picker
+                style="width: 220px"
+                :showTime="false"
+                valueFormat="YYYY-MM-DD"
+                v-model:value="searchData.reportTime"
+                placeholder="请选择填报日期"
+              />
             </div>
           </a-col>
           <!-- <a-col :span="4">
@@ -30,21 +35,18 @@
             <div class="area-item">
               <div class="item-text">上报地点:</div>
               <a-select v-model:value="searchData.strInstallPos" style="width: 220px" placeholder="请选择上报地点">
-                <a-select-option v-for="item in addressList" :key="item" :value="item.value">{{ item.label
-                }}</a-select-option>
+                <a-select-option v-for="item in addressList" :key="item" :value="item.value">{{ item.label }}</a-select-option>
               </a-select>
             </div>
           </a-col>
 
           <a-button type="primary" preIcon="ant-design:search-outlined" @click="getSearch">查询</a-button>
           <a-button preIcon="ant-design:sync-outlined" style="margin: 0px 10px" @click="onReset">重置</a-button>
-          <a-button type="primary" preIcon="ant-design:check-circle-outlined" style="margin-right: 10px"
-            @click="getPassSh">审核通过</a-button>
+          <a-button type="primary" preIcon="ant-design:check-circle-outlined" style="margin-right: 10px" @click="getPassSh">审核通过</a-button>
           <a-button type="primary" preIcon="ant-design:download-outlined" @click="getExport">导出日报表</a-button>
           <!-- <a-button type="primary" preIcon="ant-design:download-outlined" @click="getExport1"
             style="margin: 0px 10px">导出瓦斯三对照报表</a-button> -->
-          <a-button type="primary" preIcon="ant-design:download-outlined" @click="getExport2"
-          style="margin: 0px 10px">导出瓦斯检查小票</a-button>
+          <a-button type="primary" preIcon="ant-design:download-outlined" @click="getExport2" style="margin: 0px 10px">导出瓦斯检查小票</a-button>
           <a-button type="primary" preIcon="ant-design:download-outlined" @click="handleMenuClick">导出班报表</a-button>
           <!-- <a-dropdown>
             <template #overlay>
@@ -72,288 +74,451 @@
 </a-dropdown> -->
         </a-row>
       </div>
-      <a-table :columns="columns" :data-source="tableData" size="small" :scroll="{ y: 500 }" class="tableW"
-        :pagination="pagination" @change="pageChange">
+      <a-table
+        :columns="columns"
+        :data-source="tableData"
+        size="small"
+        :scroll="{ y: 500 }"
+        class="tableW"
+        :pagination="pagination"
+        @change="pageChange"
+      >
         <template #bodyCell="{ column, text }">
           <template
-            v-if="column.dataIndex == 'o2Night1' || column.dataIndex == 'o2Night2' || column.dataIndex == 'o2Early1' || column.dataIndex == 'o2Early2' || column.dataIndex == 'o2Noon1' || column.dataIndex == 'o2Noon2'">
-            <div :style="{ color: Number(text) >= 18 && Number(text) <= 20.9 ? '#0ae715' : '#ff2313' }">{{ text }}
-            </div>
+            v-if="
+              column.dataIndex == 'o2Night1' ||
+              column.dataIndex == 'o2Night2' ||
+              column.dataIndex == 'o2Early1' ||
+              column.dataIndex == 'o2Early2' ||
+              column.dataIndex == 'o2Noon1' ||
+              column.dataIndex == 'o2Noon2'
+            "
+          >
+            <div :style="{ color: Number(text) >= 18 && Number(text) <= 20.9 ? '#0ae715' : '#ff2313' }">{{ text }} </div>
           </template>
           <template
-            v-if="column.dataIndex == 'coNight1' || column.dataIndex == 'coNight2' || column.dataIndex == 'coEarly1' || column.dataIndex == 'coEarly2' || column.dataIndex == 'coNoon1' || column.dataIndex == 'coNoon2'">
+            v-if="
+              column.dataIndex == 'coNight1' ||
+              column.dataIndex == 'coNight2' ||
+              column.dataIndex == 'coEarly1' ||
+              column.dataIndex == 'coEarly2' ||
+              column.dataIndex == 'coNoon1' ||
+              column.dataIndex == 'coNoon2'
+            "
+          >
             <div :style="{ color: Number(text) >= 0 && Number(text) <= 23 ? '#0ae715' : '#ff2313' }">{{ text }}</div>
           </template>
           <template
-            v-if="column.dataIndex == 'tnight1' || column.dataIndex == 'tnight2' || column.dataIndex == 'tearly1' || column.dataIndex == 'tearly2' || column.dataIndex == 'tnoon1' || column.dataIndex == 'tnoon2'">
+            v-if="
+              column.dataIndex == 'tnight1' ||
+              column.dataIndex == 'tnight2' ||
+              column.dataIndex == 'tearly1' ||
+              column.dataIndex == 'tearly2' ||
+              column.dataIndex == 'tnoon1' ||
+              column.dataIndex == 'tnoon2'
+            "
+          >
             <div :style="{ color: Number(text) >= 3 && Number(text) <= 25 ? '#0ae715' : '#ff2313' }">{{ text }}</div>
           </template>
           <template
-            v-if="column.dataIndex == 'co2Night1' || column.dataIndex == 'co2Night2' || column.dataIndex == 'co2Early1' || column.dataIndex == 'co2Early2' || column.dataIndex == 'co2Noon1' || column.dataIndex == 'co2Noon2'">
-            <div :style="{ color: Number(text) >= 0.04 && Number(text) <= 0.1 ? '#0ae715' : '#ff2313' }">{{ text }}
-            </div>
+            v-if="
+              column.dataIndex == 'co2Night1' ||
+              column.dataIndex == 'co2Night2' ||
+              column.dataIndex == 'co2Early1' ||
+              column.dataIndex == 'co2Early2' ||
+              column.dataIndex == 'co2Noon1' ||
+              column.dataIndex == 'co2Noon2'
+            "
+          >
+            <div :style="{ color: Number(text) >= 0.04 && Number(text) <= 0.1 ? '#0ae715' : '#ff2313' }">{{ text }} </div>
           </template>
           <template
-            v-if="column.dataIndex == 'ch4Night1' || column.dataIndex == 'ch4Night2' || column.dataIndex == 'ch4Early1' || column.dataIndex == 'ch4Early2' || column.dataIndex == 'ch4Noon1' || column.dataIndex == 'ch4Noon2'">
+            v-if="
+              column.dataIndex == 'ch4Night1' ||
+              column.dataIndex == 'ch4Night2' ||
+              column.dataIndex == 'ch4Early1' ||
+              column.dataIndex == 'ch4Early2' ||
+              column.dataIndex == 'ch4Noon1' ||
+              column.dataIndex == 'ch4Noon2'
+            "
+          >
             <div :style="{ color: Number(text) >= 0 && Number(text) <= 0.1 ? '#0ae715' : '#ff2313' }">{{ text }}</div>
           </template>
-
         </template>
       </a-table>
     </div>
+    <BasicModal @register="registerModal" @ok="submitHandler">
+      <BasicForm @register="registerForm" />
+    </BasicModal>
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref, onMounted, computed, reactive } from 'vue';
-import { columns } from './gas-report.data';
-import { getGasAddressList, getList, expComReportByParam, reviewPass, getIsReviewPass } from './gas-report.api';
-import customHeader from '/@/components/vent/customHeader.vue';
-import { message } from 'ant-design-vue';
-import dayjs from 'dayjs';
-
+  import { ref, onMounted, reactive } from 'vue';
+  import { columns } from './gas-report.data';
+  import { getGasAddressList, getList, expComReportByParam, reviewPass, getIsReviewPass, getAllUserInfo, exportReportByPoi } from './gas-report.api';
+  import customHeader from '/@/components/vent/customHeader.vue';
+  import { message } from 'ant-design-vue';
+  import dayjs from 'dayjs';
+  import { BasicModal, useModal } from '/@/components/Modal';
+  import { BasicForm, useForm } from '/@/components/Form';
 
-
-let searchData = reactive({
-  reportTime: dayjs().format('YYYY-MM-DD'),
-  districtTeam: '',
-  sbr: '',
-  strInstallPos: '',
-});
-let qdList = reactive<any[]>([]); //区队下拉列表
-let addressList = reactive<any[]>([]); //上报地点下拉列表
-let pagination = reactive({
-  current: 1, // 当前页码
-  pageSize: 10, // 每页显示条数
-  total: 0, // 总条目数,后端返回
-  // showTotal: (total, range) => `${range[0]}-${range[1]} 条,总共 ${total} 条`, // 分页右下角显示信息
-  showSizeChanger: true, // 是否可改变每页显示条数
-  pageSizeOptions: ['10', '20', '50'], // 可选的每页显示条数
-});
-let tableData = ref<any[]>([]);
-
-function onChange(val, time) {
-  searchData.reportTime = time;
-}
-//获取日报列表数据
-async function getTableList() {
-  let res = await getList({ pageNo: pagination.current, pageSize: pagination.pageSize, ...searchData });
-  console.log(res, '瓦斯日报列表数据-----------');
-  res.records.forEach(el => {
-    el.jwSdzNight1 = el.jwSdzNight1 != null ? el.jwSdzNight1 : '-'
-    el.jwSdzNight2 = el.jwSdzNight2 != null ? el.jwSdzNight2 : '-'
-    el.jwSdzEarly1 = el.jwSdzEarly1 != null ? el.jwSdzEarly1 : '-'
-    el.jwSdzEarly2 = el.jwSdzEarly2 != null ? el.jwSdzEarly2 : '-'
-    el.jwSdzNoon1 = el.jwSdzNoon1 != null ? el.jwSdzNoon1 : '-'
-    el.jwSdzNoon2 = el.jwSdzNoon2 != null ? el.jwSdzNoon2 : '-'
-  })
-  tableData.value = res.records;
-  pagination.total = res.total;
-}
-//查询
-function getSearch() {
-  pagination.current = 1;
-  getTableList();
-}
-//重置
-function onReset() {
-  pagination.current = 1;
-  searchData.districtTeam = '';
-  searchData.reportTime = '';
-  searchData.strInstallPos = '';
-  searchData.sbr = '';
-  getTableList();
-}
-//分页切换
-function pageChange(val) {
-  pagination.current = val.current;
-  pagination.pageSize = val.pageSize;
-  getTableList();
-}
-function uniqueObjectsArray(arr) {
-  const map = new Map();
-  return arr.filter((item) => {
-    const key = JSON.stringify(item);
-    const isNew = !map.has(key);
-    map.set(key, item);
-    return isNew;
+  let searchData = reactive({
+    reportTime: dayjs().format('YYYY-MM-DD'),
+    districtTeam: '',
+    sbr: '',
+    strInstallPos: '',
+  });
+  let qdList = reactive<any[]>([]); //区队下拉列表
+  let addressList = reactive<any[]>([]); //上报地点下拉列表
+  let pagination = reactive({
+    current: 1, // 当前页码
+    pageSize: 10, // 每页显示条数
+    total: 0, // 总条目数,后端返回
+    // showTotal: (total, range) => `${range[0]}-${range[1]} 条,总共 ${total} 条`, // 分页右下角显示信息
+    showSizeChanger: true, // 是否可改变每页显示条数
+    pageSizeOptions: ['10', '20', '50'], // 可选的每页显示条数
   });
-}
-//获取安装位置下拉选项
-async function getSelectList() {
-  let res = await getGasAddressList({ coalseam: '', devicekind: 'gasDayReport' });
-  console.log(res, '区队下拉选项--------');
-  qdList.length = 0;
-  addressList.length = 0;
-  if (res.length != 0) {
-    res.forEach((el) => {
-      qdList.push({ label: el.devgroup_dictText, value: el.devgroup_dictText });
-      addressList.push({ label: el.strinstallpos, value: el.strinstallpos });
+  let tableData = ref<any[]>([]);
+
+  //获取日报列表数据
+  async function getTableList() {
+    let res = await getList({ pageNo: pagination.current, pageSize: pagination.pageSize, ...searchData });
+    res.records.forEach((el) => {
+      el.jwSdzNight1 = el.jwSdzNight1 != null ? el.jwSdzNight1 : '-';
+      el.jwSdzNight2 = el.jwSdzNight2 != null ? el.jwSdzNight2 : '-';
+      el.jwSdzEarly1 = el.jwSdzEarly1 != null ? el.jwSdzEarly1 : '-';
+      el.jwSdzEarly2 = el.jwSdzEarly2 != null ? el.jwSdzEarly2 : '-';
+      el.jwSdzNoon1 = el.jwSdzNoon1 != null ? el.jwSdzNoon1 : '-';
+      el.jwSdzNoon2 = el.jwSdzNoon2 != null ? el.jwSdzNoon2 : '-';
     });
-    qdList = uniqueObjectsArray(qdList);
+    tableData.value = res.records;
+    pagination.total = res.total;
   }
-}
-//导出报表
-async function getExport() {
-  if (getTs()) {
-    message.warning('数据异常!');
-  } else {
-    if (searchData.reportTime) {
-      let data = await getIsReviewPass({ reportTime: searchData.reportTime })
-      if (data == '已审核通过!') {
-        let res = await expComReportByParam({ tempName: 'wsrb', reportTime: searchData.reportTime });
-        console.log(res, '导出------------');
-        let filename = searchData.reportTime + '.xlsx';
-        downFilePublic(res, filename);
-      }
+  //查询
+  function getSearch() {
+    pagination.current = 1;
+    getTableList();
+  }
+  //重置
+  function onReset() {
+    pagination.current = 1;
+    searchData.districtTeam = '';
+    searchData.reportTime = '';
+    searchData.strInstallPos = '';
+    searchData.sbr = '';
+    getTableList();
+  }
+  //分页切换
+  function pageChange(val) {
+    pagination.current = val.current;
+    pagination.pageSize = val.pageSize;
+    getTableList();
+  }
+  function uniqueObjectsArray(arr) {
+    const map = new Map();
+    return arr.filter((item) => {
+      const key = JSON.stringify(item);
+      const isNew = !map.has(key);
+      map.set(key, item);
+      return isNew;
+    });
+  }
+  //获取安装位置下拉选项
+  async function getSelectList() {
+    let res = await getGasAddressList({ coalseam: '', devicekind: 'gasDayReport' });
+    qdList.length = 0;
+    addressList.length = 0;
+    if (res.length != 0) {
+      res.forEach((el) => {
+        qdList.push({ label: el.devgroup_dictText, value: el.devgroup_dictText });
+        addressList.push({ label: el.strinstallpos, value: el.strinstallpos });
+      });
+      qdList = uniqueObjectsArray(qdList);
+    }
+  }
+  //导出报表
+  async function getExport() {
+    if (getTs()) {
+      message.warning('数据异常!');
     } else {
+      if (searchData.reportTime) {
+        let data = await getIsReviewPass({ reportTime: searchData.reportTime });
+        if (data == '已审核通过!') {
+          let res = await expComReportByParam({ tempName: 'wsrb', reportTime: searchData.reportTime });
+          let filename = searchData.reportTime + '.xlsx';
+          downFilePublic(res, filename);
+        }
+      } else {
+        message.warning('请选择需要导出数据的填报日期!');
+      }
+    }
+  }
+  //导出三对照报表
+  // async function getExport1() {
+  //   if (searchData.reportTime) {
+  //     let res = await expComReportByParam({ tempName: 'wssdz', reportTime: searchData.reportTime });
+  //     let filename = searchData.reportTime + '.xlsx';
+  //     downFilePublic(res, filename);
+  //   } else {
+  //     message.warning('请选择需要导出数据的填报日期!');
+  //   }
+  // }
+  //导出瓦斯检查小票
+  async function getExport2() {
+    if (searchData.reportTime) {
+      openModal();
+    } else if (!searchData.reportTime) {
       message.warning('请选择需要导出数据的填报日期!');
+    } else if (!searchData.sbr) {
+      message.warning('请输入检查工名称!');
     }
   }
 
-
-}
-//导出三对照报表
-async function getExport1() {
-  if (searchData.reportTime) {
-    let res = await expComReportByParam({ tempName: 'wssdz', reportTime: searchData.reportTime });
-    console.log(res, '导出------------');
-    let filename = searchData.reportTime + '.xlsx';
-    downFilePublic(res, filename);
-  } else {
-    message.warning('请选择需要导出数据的填报日期!');
-  }
-}
-//导出瓦斯检查小票
-async function getExport2() {
-  if (searchData.reportTime && searchData.sbr) {
-    let res = await expComReportByParam({ tempName: 'wsjcxp', reportTime: searchData.reportTime, checkName: searchData.sbr });
-    console.log(res, '导出------------');
-    let filename = searchData.reportTime + '.xlsx';
-    downFilePublic(res, filename);
-  } else if (!searchData.reportTime) {
-    message.warning('请选择需要导出数据的填报日期!');
-  } else if (!searchData.sbr) {
-    message.warning('请输入上报人名称!');
+  function getTs() {
+    let param = true;
+    tableData.value.forEach((el) => {
+      if (
+        Number(el.o2Night1) >= 18 &&
+        Number(el.o2Night1) <= 20.9 &&
+        Number(el.o2Night2) >= 18 &&
+        Number(el.o2Night2) <= 20.9 &&
+        Number(el.o2Early1) >= 18 &&
+        Number(el.o2Early1) <= 20.9 &&
+        Number(el.o2Early2) >= 18 &&
+        Number(el.o2Early2) <= 20.9 &&
+        Number(el.o2Noon1) >= 18 &&
+        Number(el.o2Noon1) <= 20.9 &&
+        Number(el.o2Noon2) >= 18 &&
+        Number(el.o2Noon2) <= 20.9
+      ) {
+        param = false;
+      } else if (
+        Number(el.coNight1) >= 0 &&
+        Number(el.coNight1) <= 23 &&
+        Number(el.coNight2) >= 0 &&
+        Number(el.coNight2) <= 23 &&
+        Number(el.coEarly1) >= 0 &&
+        Number(el.coEarly1) <= 23 &&
+        Number(el.coEarly2) >= 0 &&
+        Number(el.coEarly2) <= 23 &&
+        Number(el.coNoon1) >= 0 &&
+        Number(el.coNoon1) <= 23 &&
+        Number(el.coNoon2) >= 0 &&
+        Number(el.coNoon2) <= 23
+      ) {
+        param = false;
+      } else if (
+        Number(el.co2Night1) >= 0.04 &&
+        Number(el.co2Night1) <= 0.1 &&
+        Number(el.co2Night2) >= 0.04 &&
+        Number(el.co2Night2) <= 0.1 &&
+        Number(el.co2Early1) >= 0.04 &&
+        Number(el.co2Early1) <= 0.1 &&
+        Number(el.co2Early2) >= 0.04 &&
+        Number(el.co2Early2) <= 0.1 &&
+        Number(el.co2Noon1) >= 0.04 &&
+        Number(el.co2Noon1) <= 0.1 &&
+        Number(el.co2Noon2) >= 0.04 &&
+        Number(el.co2Noon2) <= 0.1
+      ) {
+        param = false;
+      } else if (
+        Number(el.tnight1) >= 3 &&
+        Number(el.tnight1) <= 25 &&
+        Number(el.tnight2) >= 3 &&
+        Number(el.tnight2) <= 25 &&
+        Number(el.tearly1) >= 3 &&
+        Number(el.tearly1) <= 25 &&
+        Number(el.tearly2) >= 3 &&
+        Number(el.tearly2) <= 25 &&
+        Number(el.tnoon1) >= 3 &&
+        Number(el.tnoon1) <= 25 &&
+        Number(el.tnoon2) >= 3 &&
+        Number(el.tnoon2) <= 25
+      ) {
+        param = false;
+      } else if (
+        Number(el.ch4Night1) >= 0 &&
+        Number(el.ch4Night1) <= 0.1 &&
+        Number(el.ch4Night2) >= 0 &&
+        Number(el.ch4Night2) <= 0.1 &&
+        Number(el.ch4Early1) >= 0 &&
+        Number(el.ch4Early1) <= 0.1 &&
+        Number(el.ch4Early2) >= 0 &&
+        Number(el.ch4Early2) <= 0.1 &&
+        Number(el.ch4Noon1) >= 0 &&
+        Number(el.ch4Noon1) <= 0.1 &&
+        Number(el.ch4Noon2) >= 0 &&
+        Number(el.ch4Noon2) <= 0.1
+      ) {
+        param = false;
+      } else {
+        param = true;
+        return;
+      }
+    });
+    return param;
   }
-}
 
-function getTs() {
-  let param = true
-  tableData.value.forEach(el => {
-    if ((Number(el.o2Night1) >= 18 && Number(el.o2Night1) <= 20.9) && (Number(el.o2Night2) >= 18 && Number(el.o2Night2) <= 20.9) && (Number(el.o2Early1) >= 18 && Number(el.o2Early1) <= 20.9) && (Number(el.o2Early2) >= 18 && Number(el.o2Early2) <= 20.9) && (Number(el.o2Noon1) >= 18 && Number(el.o2Noon1) <= 20.9) && (Number(el.o2Noon2) >= 18 && Number(el.o2Noon2) <= 20.9)) {
-      param = false
-    } else if ((Number(el.coNight1) >= 0 && Number(el.coNight1) <= 23) && (Number(el.coNight2) >= 0 && Number(el.coNight2) <= 23) && (Number(el.coEarly1) >= 0 && Number(el.coEarly1) <= 23) && (Number(el.coEarly2) >= 0 && Number(el.coEarly2) <= 23) && (Number(el.coNoon1) >= 0 && Number(el.coNoon1) <= 23) && (Number(el.coNoon2) >= 0 && Number(el.coNoon2) <= 23)) {
-      param = false
-    } else if ((Number(el.co2Night1) >= 0.04 && Number(el.co2Night1) <= 0.1) && (Number(el.co2Night2) >= 0.04 && Number(el.co2Night2) <= 0.1) && (Number(el.co2Early1) >= 0.04 && Number(el.co2Early1) <= 0.1) && (Number(el.co2Early2) >= 0.04 && Number(el.co2Early2) <= 0.1) && (Number(el.co2Noon1) >= 0.04 && Number(el.co2Noon1) <= 0.1) && (Number(el.co2Noon2) >= 0.04 && Number(el.co2Noon2) <= 0.1)) {
-      param = false
-    } else if ((Number(el.tnight1) >= 3 && Number(el.tnight1) <= 25) && (Number(el.tnight2) >= 3 && Number(el.tnight2) <= 25) && (Number(el.tearly1) >= 3 && Number(el.tearly1) <= 25) && (Number(el.tearly2) >= 3 && Number(el.tearly2) <= 25) && (Number(el.tnoon1) >= 3 && Number(el.tnoon1) <= 25) && (Number(el.tnoon2) >= 3 && Number(el.tnoon2) <= 25)) {
-      param = false
-    } else if ((Number(el.ch4Night1) >= 0 && Number(el.ch4Night1) <= 0.1) && (Number(el.ch4Night2) >= 0 && Number(el.ch4Night2) <= 0.1) && (Number(el.ch4Early1) >= 0 && Number(el.ch4Early1) <= 0.1) && (Number(el.ch4Early2) >= 0 && Number(el.ch4Early2) <= 0.1) && (Number(el.ch4Noon1) >= 0 && Number(el.ch4Noon1) <= 0.1) && (Number(el.ch4Noon2) >= 0 && Number(el.ch4Noon2) <= 0.1)) {
-      param = false
+  //审核通过
+  async function getPassSh() {
+    if (getTs()) {
+      message.warning('数据异常!');
     } else {
-      param = true
-      return
+      let res = await reviewPass({ reportTime: searchData.reportTime });
+      if (res) {
+        getTableList();
+      }
     }
-  })
-  return param
-}
+  }
 
-//审核通过
-async function getPassSh() {
-  if (getTs()) {
-    message.warning('数据异常!');
-  } else {
-    let res = await reviewPass({ reportTime: searchData.reportTime })
-    console.log(res, '审核通过')
-    if (res) {
-      getTableList();
+  // 下载公用方法
+  function downFilePublic(content, fileName) {
+    const blob = new Blob([content], { type: 'application/xlsx;charset=UTF-8' }); // 构造一个blob对象来处理数据
+    // 对于<a>标签,只有 Firefox 和 Chrome(内核) 支持 download 属性
+    // IE10以上支持blob但是依然不支持download
+    if ('download' in document.createElement('a')) {
+      // 支持a标签download的浏览器
+      const link = document.createElement('a'); // 创建a标签
+      link.download = fileName; // a标签添加属性
+      link.style.display = 'none';
+      link.href = URL.createObjectURL(blob);
+      document.body.appendChild(link);
+      link.click(); // 执行下载
+      URL.revokeObjectURL(link.href); // 释放url
+      document.body.removeChild(link); // 释放标签
+    } else {
+      // 其他浏览器
+      navigator.msSaveBlob(blob, fileName);
     }
   }
-}
-
-// 下载公用方法
-function downFilePublic(content, fileName) {
-  const blob = new Blob([content], { type: 'application/xlsx;charset=UTF-8' }); // 构造一个blob对象来处理数据
-  // 对于<a>标签,只有 Firefox 和 Chrome(内核) 支持 download 属性
-  // IE10以上支持blob但是依然不支持download
-  if ('download' in document.createElement('a')) {
-    // 支持a标签download的浏览器
-    const link = document.createElement('a'); // 创建a标签
-    link.download = fileName; // a标签添加属性
-    link.style.display = 'none';
-    link.href = URL.createObjectURL(blob);
-    document.body.appendChild(link);
-    link.click(); // 执行下载
-    URL.revokeObjectURL(link.href); // 释放url
-    document.body.removeChild(link); // 释放标签
-  } else {
-    // 其他浏览器
-    navigator.msSaveBlob(blob, fileName);
+  //导出瓦斯班报表
+  async function handleMenuClick(val) {
+    if (searchData.reportTime) {
+      let res = await expComReportByParam({ tempName: 'wsrbshb', reportTime: searchData.reportTime });
+      let filename = searchData.reportTime + '.xlsx';
+      downFilePublic(res, filename);
+    } else {
+      message.warning('请选择需要导出数据的填报日期!');
+    }
   }
-}
-//导出瓦斯班报表
-async function handleMenuClick(val) {
-  if (searchData.reportTime) {
-    let res = await expComReportByParam({ tempName: 'wsrbshb', reportTime: searchData.reportTime });
-    let filename = searchData.reportTime + '.xlsx';
+
+  const [registerModal, { openModal }] = useModal();
+  const [registerForm, { validate, setFieldsValue }] = useForm({
+    schemas: [
+      {
+        label: '检查工',
+        field: 'checkName',
+        component: 'ApiSelect',
+        required: true,
+        show: false,
+      },
+      {
+        label: '交班瓦检员',
+        field: 'agoCheckPerson',
+        component: 'ApiSelect',
+        required: true,
+        componentProps: {
+          api: getAllUserInfo,
+          labelField: 'realname',
+          valueField: 'username',
+          showSearch: true,
+        },
+      },
+      {
+        label: '当班瓦检员',
+        field: 'nowCheckPerson',
+        component: 'ApiSelect',
+        required: true,
+        componentProps: {
+          api: getAllUserInfo,
+          labelField: 'realname',
+          valueField: 'username',
+          showSearch: true,
+          onChange(__, { label }) {
+            setFieldsValue({
+              checkName: label,
+            });
+          },
+        },
+      },
+      {
+        label: '接班瓦检员',
+        field: 'nextCheckPerson',
+        component: 'ApiSelect',
+        required: true,
+        componentProps: {
+          api: getAllUserInfo,
+          labelField: 'realname',
+          valueField: 'username',
+          showSearch: true,
+        },
+      },
+    ],
+    labelWidth: 100,
+    showActionButtonGroup: false,
+  });
+
+  /** 导出瓦斯检查小票 */
+  async function submitHandler() {
+    const params = await validate();
+    const res = await exportReportByPoi({ tempName: 'wsjcxp', reportTime: searchData.reportTime, ...params });
+    const filename = searchData.reportTime + '.xlsx';
     downFilePublic(res, filename);
-  } else {
-    message.warning('请选择需要导出数据的填报日期!');
   }
-}
 
-onMounted(() => {
-  getSelectList();
-  getTableList();
-});
+  onMounted(() => {
+    getSelectList();
+    getTableList();
+  });
 </script>
 
 <style lang="less" scoped>
-@import '/@/design/theme.less';
+  @import '/@/design/theme.less';
 
-.gasReport {
-  width: 100%;
-  height: 100%;
-  padding: 80px 10px 15px 10px;
-  box-sizing: border-box;
-  position: relative;
+  .gasReport {
+    width: 100%;
+    height: 100%;
+    padding: 80px 10px 15px 10px;
+    box-sizing: border-box;
+    position: relative;
 
-  .search-area {
-    margin: 20px 0px;
+    .search-area {
+      margin: 20px 0px;
 
-    .area-item {
-      display: flex;
-      align-items: center;
+      .area-item {
+        display: flex;
+        align-items: center;
 
-      .item-text {
-        color: #fff;
+        .item-text {
+          color: #fff;
+        }
       }
     }
-  }
 
-  .zxm-picker,
-  .zxm-input {
-    border: 1px solid var(--vent-form-item-border) !important;
-    background-color: #ffffff00 !important;
-    color: #fff !important;
+    .zxm-picker,
+    .zxm-input {
+      border: 1px solid var(--vent-form-item-border) !important;
+      background-color: #ffffff00 !important;
+      color: #fff !important;
+    }
   }
-}
 
-:deep(.zxm-table-thead > tr > th:last-child) {
-  border-right: 1px solid #91e9fe !important;
-}
+  :deep(.zxm-table-thead > tr > th:last-child) {
+    border-right: 1px solid #91e9fe !important;
+  }
 
-:deep(.zxm-picker-input > input) {
-  color: #fff;
-}
+  :deep(.zxm-picker-input > input) {
+    color: #fff;
+  }
 
-:deep(.zxm-select:not(.zxm-select-customize-input) .zxm-select-selector) {
-  border: 1px solid var(--vent-form-item-border) !important;
-  background-color: #ffffff00 !important;
-}
+  :deep(.zxm-select:not(.zxm-select-customize-input) .zxm-select-selector) {
+    border: 1px solid var(--vent-form-item-border) !important;
+    background-color: #ffffff00 !important;
+  }
 
-:deep(.zxm-select-selection-item) {
-  color: #fff !important;
-}
+  :deep(.zxm-select-selection-item) {
+    color: #fff !important;
+  }
 </style>

+ 107 - 25
src/views/vent/gas/gasZk/index.vue

@@ -3,11 +3,13 @@
     <customHeader>瓦斯钻孔实时监测</customHeader>
     <div class="content">
       <div class="left-box">
-        <div class="video">
-          <video controls autoplay muted loop fluent style="height: 100%; width: 100%; padding: 30px 20px">
-            <source :src="`${baseApiUrl}/sys/common/static/gif/output_video.mp4`" type="video/mp4" />
-          </video>
-        </div>
+        <a-spin :spinning="loadding" size="large" tip="正在加载视频,请稍等。。。">
+          <div class="video-box" ref="video">
+            <!-- <video controls autoplay muted loop fluent style="height: 100%; width: 100%; padding: 30px 20px">
+              <source :src="`${baseApiUrl}/sys/common/static/gif/output_video.mp4`" type="video/mp4" />
+            </video> -->
+          </div>
+        </a-spin>
       </div>
       <div class="right-box">
         <div class="count">
@@ -34,12 +36,18 @@
   import { getVideoPlayTime, getGasZkStatus } from './gasZk.api';
   import customHeader from '/@/components/vent/customHeader.vue';
   import { useGlobSetting } from '/@/hooks/setting';
+  import Player, { I18N } from 'xgplayer';
+  import ZH from 'xgplayer/es/lang/zh-cn';
+  import Mp4Plugin from 'xgplayer-mp4';
+
   const globSetting = useGlobSetting();
   const baseApiUrl = globSetting.domainUrl;
   const videoPlayTime = ref(0); //视频开始播放时间
   const curStatus = ref(''); //当前状态
   const usedCount = ref(''); //钻孔计数
   const videoUrl = ref('');
+  const video = ref();
+  const loadding = ref(true);
   let timer: IntervalHandle; //定时器
   //时间轮询
   const startPolling = () => {
@@ -70,20 +78,70 @@
     }
   };
 
+  const initPlayer = () => {
+    const player = new Player({
+      url: `${baseApiUrl}/sys/common/static/gif/output_video.mp4`,
+      el: video.value,
+      lang: 'zh',
+      width: '1120',
+      height: '740',
+      poster: '/src/assets/images/vent/noSinge.png',
+      plugins: [Mp4Plugin],
+      // marginControls: false,
+      autoplay: true,
+      loop: true,
+      // fluid: false,
+      isLive: true,
+      playsinline: false,
+      screenShot: false,
+      // closeVideoClick: true,
+      // closeFocusVideoFocus: true,
+      // closePauseVideoFocus: true,
+      // closePlayVideoFocus: true,
+      // topBarAutoHide: false,
+      customConfig: {
+        isClickPlayBack: false,
+      },
+      controls: false,
+      // ignores: ['time', 'start', 'definition', 'error', 'fullscreen', 'i18n', 'loading', 'mobile', 'pc', 'play', 'poster', 'progress', 'replay', 'volume', 'loading', 'pc', 'fullscreen', 'error', 'definition'],
+      mp4plugin: {
+        maxBufferLength: 30,
+        // minBufferLength: 10,
+      },
+    });
+    player.on('play', async () => {
+      try {
+        loadding.value = false;
+        videoPlayTime.value = await getVideoPlayTime();
+        // 第一次请求
+        const res = await getGasZkStatus({
+          playTime: videoPlayTime.value,
+        });
+        usedCount.value = res.usedCount;
+        curStatus.value = res.curStatus;
+        // 启动轮询
+        startPolling();
+      } catch (error) {
+        console.error('初始化失败', error);
+      }
+    });
+  };
+
   onMounted(async () => {
-    try {
-      videoPlayTime.value = await getVideoPlayTime();
-      // 第一次请求
-      const res = await getGasZkStatus({
-        playTime: videoPlayTime.value,
-      });
-      usedCount.value = res.usedCount;
-      curStatus.value = res.curStatus;
-      // 启动轮询
-      startPolling();
-    } catch (error) {
-      console.error('初始化失败', error);
-    }
+    initPlayer();
+    // try {
+    //   videoPlayTime.value = await getVideoPlayTime();
+    //   // 第一次请求
+    //   const res = await getGasZkStatus({
+    //     playTime: videoPlayTime.value,
+    //   });
+    //   usedCount.value = res.usedCount;
+    //   curStatus.value = res.curStatus;
+    //   // 启动轮询
+    //   startPolling();
+    // } catch (error) {
+    //   console.error('初始化失败', error);
+    // }
   });
 
   // 组件卸载时清理
@@ -105,10 +163,9 @@
     --image-border: url('/@/assets/images/fire/border.png');
     position: relative;
     width: calc(100% - 20px);
-    height: calc(100% - 90px);
+    height: calc(100% - 160px);
     position: relative;
     margin: 30px 10px 10px 10px;
-
     .content {
       position: relative;
       width: 100%;
@@ -116,15 +173,40 @@
       display: flex;
       justify-content: space-between;
       align-items: center;
-      margin-top: 80px;
       .left-box {
-        flex: 3;
-        height: 100%;
+        width: 1200px;
+        height: 760px;
         padding: 10px;
         background: var(--image-border) no-repeat center;
         background-size: 100% 100%;
-        .video {
-          height: 100%;
+        position: relative;
+        .video-box {
+          width: 100%;
+          height: 740px !important;
+          padding-top: 0 !important;
+          display: flex;
+          align-items: center;
+          video {
+            height: 740px !important;
+          }
+          :deep(.xgplayer-loading) {
+            display: none;
+          }
+          :deep(.xgplayer-enter) {
+            display: none;
+          }
+          :deep(.xgplayer-start) {
+            display: none;
+          }
+          :deep(.xgplayer-error) {
+            display: none;
+          }
+          :deep(.xgplayer-replay) {
+            display: none;
+          }
+          :deep(.xg-mini-layer) {
+            display: none;
+          }
         }
       }
       .right-box {

+ 8 - 0
src/views/vent/monitorManager/balancePressMonitor/balancePress.data.ts

@@ -83,6 +83,14 @@ export const localFanParam = [
   },
 ];
 
+export const windrectParam = [
+  {
+    title: '风量',
+    code: 'readData.m3',
+    unit: 'm³/min',
+  },
+];
+
 export const monitorParam = [
   // {
   //   title: '安装位置',

+ 33 - 2
src/views/vent/monitorManager/balancePressMonitor/components/balancePressHome.vue

@@ -42,7 +42,33 @@
           </ventBox1>
         </div>
       </div>
-      <div class="lr right-box">
+      <div class="lr right-box ml-auto">
+        <div class="item-box sensor-container">
+          <ventBox1 class="">
+            <template #title>
+              <div>设备监测详情</div>
+            </template>
+            <template #container>
+              <div class="overflow-y-auto max-h-500px">
+                <template v-for="monitor in windrectMonitorData" :key="monitor.deviceId">
+                  <div class="parameter-title group-parameter-title"
+                    ><SvgIcon class="icon" size="14" name="fiber-title" />
+                    <span>测风装置:{{ monitor.strinstallpos }}</span>
+                  </div>
+                  <div class="input-box">
+                    <div v-for="(item, index) in windrectParam" class="input-item" :key="index">
+                      <div class="title">{{ item.title }}</div>
+                      <div class="value">{{ get(monitor, item.code, '-') }}</div>
+                      <div class="unit">{{ item.unit }}</div>
+                    </div>
+                  </div>
+                </template>
+              </div>
+            </template>
+          </ventBox1>
+        </div>
+      </div>
+      <div class="lr right-box ml-5px">
         <div class="item-box sensor-container">
           <ventBox1>
             <template #title>
@@ -110,7 +136,7 @@
   import ventBox1 from '/@/components/vent/ventBox1.vue';
   import { SvgIcon } from '/@/components/Icon';
   import { mountedThree, destroy, setModelType, updateText, play } from '../balancePress.threejs';
-  import { settingParam1, settingParam2, settingParam3, windowParam, localFanParam, monitorParam } from '../balancePress.data';
+  import { settingParam1, settingParam2, settingParam3, windowParam, localFanParam, monitorParam, windrectParam } from '../balancePress.data';
   import { list } from '../balancePress.api';
   import { message } from 'ant-design-vue';
   import { get } from 'lodash-es';
@@ -164,6 +190,7 @@
   const safetyMonitorData = ref<any[]>([]);
   const fanlocalMonitorData = ref<any[]>([]);
   const windowMonitorData = ref<any[]>([]);
+  const windrectMonitorData = ref<any[]>([]);
 
   async function getDataSource(systemID) {
     const res = await list({ devicetype: 'sys', systemID });
@@ -171,6 +198,7 @@
     safetyMonitorData.value = [];
     fanlocalMonitorData.value = [];
     windowMonitorData.value = [];
+    windrectMonitorData.value = [];
     result.forEach((item) => {
       if (item.type.startsWith('safetymonitor')) {
         safetyMonitorData.value.push(...item.datalist);
@@ -186,6 +214,9 @@
       if (item.type.startsWith('window')) {
         windowMonitorData.value.push(...item.datalist);
       }
+      if (item.type.startsWith('windrect')) {
+        windrectMonitorData.value.push(...item.datalist);
+      }
     });
   }
 

+ 104 - 22
src/views/vent/monitorManager/deviceCameraMonitor/index.vue

@@ -25,10 +25,11 @@
             <div class="button-box" @click="playAnimation('后窗1面积设置', 'frontSetValue3')">后窗1面积</div>
             <div class="button-box" @click="playAnimation('后窗2面积设置', 'frontSetValue4')">后窗2面积</div>
           </div>
-
+          <div v-if="hasPermission('window:ldkz')" class="button-box" @click="playAnimation('风窗自主调控', 'ldkz')">风窗自主调控</div>
+          <div v-if="hasPermission('window:sameSet')" class="button-box" @click="playAnimation('风窗面积设置', 'sameSetValue')">设定风窗面积</div>
           <div class="row" v-if="Number(selectData.nwindownum) == 1">
-            <div v-if="hasPermission('window:AreaControl')" class="button-box" @click="setArea(1)">设定风窗面积</div>
-            <div v-if="hasPermission('window:showAngle')" class="button-box" @click="setAngle(1)">设定风窗角度</div>
+            <div v-if="hasPermission('window:AreaControl')" class="button-box" @click="playAnimation('设定风窗面积', 'frontSetValue')">设定风窗面积</div>
+            <div v-if="hasPermission('window:showAngle')" class="button-box" @click="playAnimation('设定风窗角度', 'frontSetValue')">设定风窗角度</div>
           </div>
         </template>
       </div>
@@ -215,11 +216,18 @@
       @handle-ok="handleOK"
       @handle-cancel="handleCancel"
     />
+    <SupplyAir
+      :data="currentData"
+      :targetVolume="targetVolume"
+      :modal-is-show="showTargetModal"
+      :modalType="modalType"
+      @handle-cancel="() => (showTargetModal = false)"
+    />
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref, onMounted, onUnmounted, ComponentOptions, shallowRef, reactive, defineProps, watch, nextTick,unref } from 'vue';
+import { ref, onMounted, onUnmounted, ComponentOptions, shallowRef, reactive, defineProps, watch, toRaw, nextTick,unref, inject } from 'vue';
 import { list, getDeviceList, getDepartmentInfo } from './device.api';
 import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
 import HistoryTable from '../comment/HistoryTable.vue';
@@ -240,12 +248,12 @@ import {
 } from './device.data';
 import { getDictItemsByCode } from '/@/utils/dict';
 import BarAndLine from '/@/components/chart/BarAndLine.vue';
-import { useMethods } from '/@/hooks/system/useMethods';
-import { useGo } from '/@/hooks/web/usePage';
 import { useGlobSetting } from '/@/hooks/setting';
 import { useCamera } from '/@/hooks/system/useCamera';
 import { usePermission } from '/@/hooks/web/usePermission';
 import { deviceControlApi } from '/@/api/vent/index';
+import SupplyAir from '../windowMonitor/components/supplyAir.vue';
+import { updateWindowAutoAdjustStatus } from '../windowMonitor/window.api';
 
 type DeviceType = { deviceType: string; deviceName: string; datalist: any[] };
 const glob = useGlobSetting();
@@ -268,6 +276,23 @@ const echatsOption = {
     feature: {},
   },
 };
+const initData = {
+  deviceID: '',
+  deviceType: '',
+  strname: '',
+  dataDh: '-', //压差
+  dataDtestq: '-', //测试风量
+  sourcePressure: '-', //气源压力
+  dataDequivalarea: '-',
+  netStatus: '0', //通信状态
+  fault: '气源压力超限',
+  forntArea: '0',
+  rearArea: '0',
+  frontRearDifference: '-',
+  rearPresentValue: '-',
+  maxarea: 0,
+  nwindownum: 0,
+};
 const { hasPermission } = usePermission();
 const { getCamera, removeCamera, getPlayer } = useCamera();
 const playerRef = ref()
@@ -289,16 +314,20 @@ const deviceActive = ref('');
 const activeKey = ref('1'); // tab key
 const dataSource = shallowRef([]); // 实时监测数据
 const selectData = ref({})
+const currentData = ref(initData);
 const majorPathEchartsData = ref({}); // 关键路线echarts数据
 const surfaceEchartsData = ref<any[]>(); // 工作面历史记录,echarts数据
 const activeID = ref(''); // 打开详情modal时监测的设备id
 const deviceType = ref(''); // 监测设备类型
 const selectRowIndex = ref(-1)
 const systemID = ref(''); // 系统监测时,系统id
-const cameraAddrs = ref([])
+const cameraAddrs = ref([]);
+const targetVolume = ref(0);
+const showTargetModal = ref(false);
 const scroll = reactive({
   y: 180,
 });
+const globalConfig = inject('globalConfig');
 let departmentInfo: Null | Object = null;
 function tabChange(activeKeyVal) {
   activeKey.value = activeKeyVal;
@@ -313,7 +342,8 @@ function getMonitor(flag?) {
     if (Object.prototype.toString.call(timer) === '[object Null]') {
       timer = setTimeout(
         async () => {
-          await getDataSource();
+          const data = await getDataSource();
+          currentData.value = data
           if (timer) {
             getMonitor();
           }
@@ -334,6 +364,7 @@ async function getDataSource() {
         const readData = data.readData;
         return Object.assign(data, readData);
       });
+      
       if (item.type != 'sys') {
         if (item.type === 'majorpath') {
           deviceArr.unshift({ deviceType: item.type, deviceName: item['typeName'], datalist: item['datalist'][0]['paths'] });
@@ -482,6 +513,8 @@ async function getDataSource() {
       }
     }
   }
+  const data: any = toRaw(dataSource.value[selectRowIndex.value]); //maxarea
+  return data;
 }
 
 
@@ -521,6 +554,7 @@ async function getSelectRow(selectRow, index) {
   if (!selectRow) return;
   selectRowIndex.value = index;
   selectData.value = selectRow;
+  
   cameraAddrs.value = await getCamera(selectRow.deviceID, playerRef.value, null, true);
   if(cameraAddrs.value && cameraAddrs.value.length > 0){
     nextTick(async() => {
@@ -553,29 +587,77 @@ const playAnimation = (title, flag) => {
   modalTitle.value = title;
   modalIsShow.value = true;
 };
-const handleOK = (passWord, handlerState, value) => {
+const handleOK = async(passWord, handlerState, value) => {
   if (!passWord && !globalConfig?.simulatedPassword) {
     message.warning('请输入密码!');
     return;
   }
-  let data = {
-    deviceid: selectData.value.deviceID,
-    devicetype: selectData.value.deviceType,
-    paramcode: handlerState,
-    password: passWord || globalConfig?.simulatedPassword,
-    value: value ? value : null,
-  };
-  deviceControlApi(data)
-    .then((res) => {
+  
+  if (handlerState == 'sameSetValue') {
+    const data1 = {
+      deviceid: selectData.value.deviceID,
+      devicetype: selectData.value.deviceType,
+      paramcode: 'frontSetValue',
+      password: passWord || globalConfig?.simulatedPassword,
+      value: value ? value : null,
+    };
+    const data2 = {
+      deviceid: selectData.value.deviceID,
+      devicetype: selectData.value.deviceType,
+      paramcode: 'rearSetValue',
+      password: passWord || globalConfig?.simulatedPassword,
+      value: value ? value : null,
+    };
+    const res1 = await deviceControlApi(data1);
+    const res2 = await deviceControlApi(data2);
+    if (res1.success && res2.success) {
+      message.success('指令已下发成功!');
+    } else {
+      message.error(res1.message);
+    }
+    handleCancel();
+  }else if(handlerState == 'ldkz') {
+    const params = {
+      windowId: selectData.value.deviceID,
+      auto: 1,
+      fengliangF: value,
+    };
+    updateWindowAutoAdjustStatus(params).then((res) => {
       if (res.success) {
-        message.success('指令已下发成功!');
+        if (globalConfig.History_Type == 'remote') {
+          message.success('指令已下发至生产管控平台成功!');
+        } else {
+          message.success('指令已下发成功!');
+        }
+        handleCancel();
+        targetVolume.value = value;
+        showTargetModal.value = true;
       } else {
         message.error(res.message);
       }
-    })
-    .finally(() => {
-      handleCancel();
     });
+    return;
+  } else{
+    let data = {
+      deviceid: selectData.value.deviceID,
+      devicetype: selectData.value.deviceType,
+      paramcode: handlerState,
+      password: passWord || globalConfig?.simulatedPassword,
+      value: value ? value : null,
+    };
+    deviceControlApi(data)
+      .then((res) => {
+        if (res.success) {
+          message.success('指令已下发成功!');
+        } else {
+          message.error(res.message);
+        }
+      })
+      .finally(() => {
+        handleCancel();
+      });
+  }
+ 
 };
 
 const handleCancel = () => {

+ 5 - 22
src/views/vent/monitorManager/deviceMonitor/components/device/index.vue

@@ -547,27 +547,10 @@
                 <HistoryBall :dataSource="dataSource"></HistoryBall>
               </template>
               <template v-else-if="deviceType.startsWith('fanmain')">
-                <!-- HistoryTableNew 没有监测deviceType 进行动态查询表头导致数据不显示 -->
-                <!-- <HistoryTableNew class="w-100% h-100%" :device-code="`${deviceType}`" :scroll="scroll"
-                  dict-code="fan_dict" /> -->
-                <HistoryTable
-                  ref="historyTable"
-                  :columns-type="`${deviceType}`"
-                  :device-type="deviceType"
-                  designScope="device-history"
-                  :scroll="scroll"
-                />
+                <HistoryTableNew class="w-100% h-100%" :device-code="`${deviceType}`" :scroll="scroll" dict-code="fan_dict" />
               </template>
               <template v-else-if="deviceType.startsWith('fanlocal')">
-                <!-- HistoryTableNew 没有监测deviceType 进行动态查询表头导致数据不显示 -->
-                <!-- <HistoryTableNew class="w-100% h-100%" :device-code="`${deviceType}`" :scroll="scroll" dict-code="fanlocal_dict" /> -->
-                <HistoryTable
-                  ref="historyTable"
-                  :columns-type="`${deviceType}`"
-                  :device-type="deviceType"
-                  designScope="device-history"
-                  :scroll="scroll"
-                />
+                <HistoryTableNew class="w-100% h-100%" :device-code="`${deviceType}`" :scroll="scroll" dict-code="fanlocal_dict" />s
               </template>
               <template v-else>
                 <HistoryTable
@@ -1142,7 +1125,7 @@
         window.open(newPage.href, '_blank');
       } else if (deviceType.value.indexOf('pulping') != -1) {
         // const newPage = router.resolve({ path: '/grout-home', query: { id: activeID.value } });
-        const newPage = router.resolve({ path: '/grout-home',});
+        const newPage = router.resolve({ path: '/grout-home' });
         window.open(newPage.href, '_blank');
       } else if (deviceType.value.indexOf('pressurefan') != -1) {
         const newPage = router.resolve({ path: '/nitrogen/home', query: { id: activeID.value } });
@@ -1164,7 +1147,7 @@
         window.open(newPage.href, '_blank');
       } else if (deviceType.value.indexOf('pulping') != -1) {
         // const newPage = router.resolve({ path: '/grout-home', query: { id: activeID.value } });
-        const newPage = router.resolve({ path: '/grout-home', });
+        const newPage = router.resolve({ path: '/grout-home' });
         window.open(newPage.href, '_blank');
       } else if (deviceType.value.indexOf('gasmonitor') != -1) {
         const newPage = router.resolve({ path: '/gas/warn/home' });
@@ -1199,7 +1182,7 @@
         window.open(newPage.href, '_blank');
       } else if (deviceType.value.indexOf('pulping') != -1) {
         // const newPage = router.resolve({ path: '/grout-home', query: { id: systemID.value } });
-        const newPage = router.resolve({ path: '/grout-home', });
+        const newPage = router.resolve({ path: '/grout-home' });
         window.open(newPage.href, '_blank');
       } else if (deviceType.value.indexOf('gasDay_normal') != -1) {
         const newPage = router.resolve({ path: '/gas/gas-report-inspect/home' });

+ 67 - 3
src/views/vent/monitorManager/mainFanMonitor/mainWind.threejs.ts

@@ -1,7 +1,7 @@
 import * as THREE from 'three';
 import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
 import Smoke from '/@/views/vent/comment/threejs/Smoke';
-import { renderVideo } from '/@/utils/threejs/util';
+import { PathPointList, PathGeometry } from 'three.path';
 import gsap from 'gsap';
 
 class mainWindRect {
@@ -44,7 +44,12 @@ class mainWindRect {
   fbmAnimationClip: THREE.AnimationClip | null = null;
   fbmMixers: THREE.AnimationMixer | null = null;
   fbmOpenAction: THREE.AnimationAction | null = null;
-
+  clock = new THREE.Clock();
+  material;
+  airTexture;
+  offset = 0;
+  direction = 0; // -1 代表反向,1代表正向
+  arrowMesh;
   constructor(model, playerVal1) {
     this.model = model;
     this.player1 = playerVal1;
@@ -149,6 +154,10 @@ class mainWindRect {
       return;
     }
     if (this.fbmMixers) this.fbmMixers?.update(1 / 25);
+    if (this.airTexture) {
+      this.airTexture.offset.x = this.offset;
+      this.offset -= this.clock.getDelta() * 2;
+    }
   }
 
   /* 点击风窗,风窗全屏 */
@@ -230,6 +239,8 @@ class mainWindRect {
   }
 
   async setSmokeDirection(deviceType, smokeDirection) {
+    let smoke;
+    const pathPoints: THREE.Vector3[] = [];
     const windowPositivePath = [
       {
         path0: new THREE.Vector3(4.441, 20.267, 3.614),
@@ -322,7 +333,24 @@ class mainWindRect {
         spreadDirection: 0, // 1是由小变大,-1是由大变小
       },
     ];
-    let smoke;
+    const getPathPoint = () => {
+      this.arrowMesh = this.group?.getObjectByName('arrow');
+      if (this.arrowMesh) return;
+      pathPoints.push(new THREE.Vector3(16.441, 1.485, 2.614), new THREE.Vector3(35.583, 1.485, 2.614));
+      const pathPointList = new PathPointList();
+      const up = new THREE.Vector3(0, 0, 1);
+      pathPointList.set(pathPoints, 0, 0, up, false);
+      const geometry = new PathGeometry(pathPoints.length, false);
+      geometry.update(pathPointList, {
+        width: 2,
+        arrow: false,
+      });
+
+      this.arrowMesh = new THREE.Mesh(geometry, this.material);
+      this.arrowMesh.name = 'arrow';
+      this.group?.add(this.arrowMesh);
+    };
+
     if (deviceType === 'front') {
       smoke = this.frontSmoke;
     } else if (deviceType === 'back') {
@@ -331,17 +359,39 @@ class mainWindRect {
     switch (smokeDirection) {
       case 'tubPositivePath': // 风筒正
         smoke.setPath(tubPositivePath);
+        if (this.direction !== 1) {
+          this.direction = 1;
+          this.airTexture.repeat.x = 1;
+        }
         break;
       case 'tubInversePath': // 风筒反
         smoke.setPath(tubInversePath);
+        if (this.direction !== -1) {
+          this.direction = -1;
+          this.airTexture.repeat.x = -1;
+        }
         break;
       case 'windowPositivePath': // 风窗正
         smoke.setPath(windowPositivePath);
+        if (this.direction !== 1) {
+          this.direction = 1;
+          this.airTexture.repeat.x = 1;
+        }
         break;
       case 'windowInversePath': // 风窗反
         smoke.setPath(windowInversePath);
+        if (this.direction !== -1) {
+          this.direction = -1;
+          this.airTexture.repeat.x = -1;
+        }
         break;
     }
+    getPathPoint();
+    if (deviceType === 'front') {
+      if (this.arrowMesh && this.arrowMesh.position.z !== 2.31) this.arrowMesh.position.set(-2.51, 5.51, 13.25);
+    } else {
+      if (this.arrowMesh && this.arrowMesh.position.z !== -12.99) this.arrowMesh.position.set(-2.2, 5.51, -2.8);
+    }
   }
 
   /* 播放气流动画 */
@@ -774,6 +824,20 @@ class mainWindRect {
         resolve(null);
         this.initWindow();
         this.initFbmAnimation();
+
+        const loader = new THREE.TextureLoader();
+        this.airTexture = loader.load('/model/img/air.png');
+        this.airTexture.wrapS = THREE.RepeatWrapping;
+        this.airTexture.repeat.set(1, 1.2);
+        this.airTexture.offset.y = 0;
+        this.airTexture.matrix.scale(0.5, 0.5);
+        this.airTexture.needsUpdate = true;
+        this.material = new THREE.MeshBasicMaterial({
+          map: this.airTexture,
+          transparent: true,
+          side: THREE.FrontSide,
+        });
+        this.clock.start();
       });
     });
   }

+ 69 - 4
src/views/vent/monitorManager/mainFanMonitor/mainWind.xj.threejs.ts

@@ -1,7 +1,7 @@
 import * as THREE from 'three';
 import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
 import Smoke from '/@/views/vent/comment/threejs/Smoke';
-import { renderVideo } from '/@/utils/threejs/util';
+import { PathPointList, PathGeometry } from 'three.path';
 import gsap from 'gsap';
 
 class mainXjWindRect {
@@ -44,7 +44,12 @@ class mainXjWindRect {
   fbmAnimationClip: THREE.AnimationClip | null = null;
   fbmMixers: THREE.AnimationMixer | null = null;
   fbmOpenAction: THREE.AnimationAction | null = null;
-
+  clock = new THREE.Clock();
+  material;
+  airTexture;
+  offset = 0;
+  direction = 0; // -1 代表反向,1代表正向
+  arrowMesh;
   constructor(model, playerVal1) {
     this.model = model;
     this.player1 = playerVal1;
@@ -145,6 +150,10 @@ class mainXjWindRect {
       return;
     }
     if (this.fbmMixers) this.fbmMixers?.update(1 / 25);
+    if (this.airTexture) {
+      this.airTexture.offset.x = this.offset;
+      this.offset -= this.clock.getDelta() * 2;
+    }
   }
 
   /* 点击风窗,风窗全屏 */
@@ -195,6 +204,7 @@ class mainXjWindRect {
     } else {
       smoke = this.backSmoke;
     }
+
     if (!smoke.frameId) {
       await this.lookMotor(deviceType, 'open', duration);
       // await this.openOrCloseValve(deviceType, 'open', duration);
@@ -227,6 +237,8 @@ class mainXjWindRect {
   }
 
   async setSmokeDirection(deviceType, smokeDirection) {
+    let smoke;
+    const pathPoints: THREE.Vector3[] = [];
     const windowPositivePath = [
       {
         path0: new THREE.Vector3(4.441, 20.267, 3.614),
@@ -250,7 +262,7 @@ class mainXjWindRect {
         path0: new THREE.Vector3(42.741, 5.364, 3.614),
         path1: new THREE.Vector3(44.741, 17.267, 3.614),
         isSpread: true,
-        spreadDirection: 1, // 1是由小变大(出),-1是由大变小(进)
+        spreadDirection: 1, // 1是由小变大(出),-1是由大变小(进)0
       },
     ];
     const windowInversePath = [
@@ -319,7 +331,24 @@ class mainXjWindRect {
         spreadDirection: 0, // 1是由小变大,-1是由大变小
       },
     ];
-    let smoke;
+    const getPathPoint = () => {
+      this.arrowMesh = this.group?.getObjectByName('arrow');
+      if (this.arrowMesh) return;
+      pathPoints.push(new THREE.Vector3(23.441, 1.485, 2.614), new THREE.Vector3(35.583, 1.485, 2.614));
+      const pathPointList = new PathPointList();
+      const up = new THREE.Vector3(0, 0, 1);
+      pathPointList.set(pathPoints, 0, 0, up, false);
+      const geometry = new PathGeometry(pathPoints.length, false);
+      geometry.update(pathPointList, {
+        width: 2,
+        arrow: false,
+      });
+
+      this.arrowMesh = new THREE.Mesh(geometry, this.material);
+      this.arrowMesh.name = 'arrow';
+      this.group?.add(this.arrowMesh);
+    };
+
     if (deviceType === 'front') {
       smoke = this.frontSmoke;
     } else if (deviceType === 'back') {
@@ -327,18 +356,40 @@ class mainXjWindRect {
     }
     switch (smokeDirection) {
       case 'tubPositivePath': // 风筒正
+        if (this.direction !== 1) {
+          this.direction = 1;
+          this.airTexture.repeat.x = 1;
+        }
         smoke.setPath(tubPositivePath);
         break;
       case 'tubInversePath': // 风筒反
+        if (this.direction !== -1) {
+          this.direction = -1;
+          this.airTexture.repeat.x = -1;
+        }
         smoke.setPath(tubInversePath);
         break;
       case 'windowPositivePath': // 风窗正
+        if (this.direction !== 1) {
+          this.direction = 1;
+          this.airTexture.repeat.x = 1;
+        }
         smoke.setPath(windowPositivePath);
         break;
       case 'windowInversePath': // 风窗反
+        if (this.direction !== -1) {
+          this.direction = -1;
+          this.airTexture.repeat.x = -1;
+        }
         smoke.setPath(windowInversePath);
         break;
     }
+    getPathPoint();
+    if (deviceType === 'front') {
+      if (this.arrowMesh && this.arrowMesh.position.z !== 2.31) this.arrowMesh.position.set(3.18, 6.36, 2.31);
+    } else {
+      if (this.arrowMesh && this.arrowMesh.position.z !== -12.99) this.arrowMesh.position.set(3.18, 6.36, -12.99);
+    }
   }
 
   /* 播放气流动画 */
@@ -710,6 +761,20 @@ class mainXjWindRect {
         this.airJin2 = airJinGroup.getObjectByName('pasted__Jin_2') as THREE.Mesh;
         this.airChu1 = airChuGroup.getObjectByName('pasted__Chu_1') as THREE.Mesh;
         this.airChu2 = airChuGroup.getObjectByName('pasted__Chu_2') as THREE.Mesh;
+        const loader = new THREE.TextureLoader();
+
+        this.airTexture = loader.load('/model/img/air.png');
+        this.airTexture.wrapS = THREE.RepeatWrapping;
+        this.airTexture.repeat.set(1, 1.2);
+        this.airTexture.offset.y = 0;
+        this.airTexture.matrix.scale(0.6, 0.6);
+        this.airTexture.needsUpdate = true;
+        this.material = new THREE.MeshBasicMaterial({
+          map: this.airTexture,
+          transparent: true,
+          side: THREE.FrontSide,
+        });
+        this.clock.start();
       });
     });
   }

+ 6 - 3
src/views/vent/monitorManager/safetyMonitor/AlarmHistoryTable.vue

@@ -93,8 +93,11 @@
     },
     async (newVal) => {
       if (!newVal) return;
-
-      const column = getTableHeaderColumns(newVal + '_history');
+      let column;
+      column = getTableHeaderColumns('safetymonitor_warning');
+      if (!column || column.length < 1) {
+        column = getTableHeaderColumns(newVal + '_history');
+      }
       if (column && column.length < 1) {
         const arr = newVal.split('_');
         const columnKey = arr.reduce((prev, cur, index) => {
@@ -139,7 +142,7 @@
     tableProps: {
       api: safetyList,
       columns: props.columnsType ? columns : (props.columns as any[]),
-      canResize: true,
+      canResize: false,
       showTableSetting: false,
       showActionColumn: false,
       bordered: false,

+ 3 - 3
src/views/vent/monitorManager/windowMonitor/components/modal.vue

@@ -5,7 +5,7 @@
         <ExclamationCircleFilled style="color: #ffb700; font-size: 30px" />
         <div class="warning-text">您是否要进行{{ title }}操作?</div>
       </div>
-      <template v-if="type == '1' || type == '2'">
+      <template v-if="type == '1' || type == '2' || type.startsWith('sameSetValue')">
         <div class="vent-flex-row input-box">
           <div class="label">{{ title.includes('角度') ? '风窗角度:' : '风窗面积:' }}</div>
           <a-input-number size="small" placeholder="0" :min="0" v-model:value="data" />
@@ -13,13 +13,13 @@
       </template>
       <template v-if="type == '7'">
         <div class="vent-flex-row input-box">
-          <div class="label">窗目标风量(m³/min):</div>
+          <div class="label">窗目标风量(m³/min):</div>
           <a-input-number size="small" placeholder="0" :min="0" v-model:value="data" />
         </div>
       </template>
       <template v-if="type == '8'">
         <div class="vent-flex-row input-box">
-          <div class="label">窗目标风量(m³/min):</div>
+          <div class="label">窗目标风量(m³/min):</div>
           <a-input-number size="small" placeholder="0" :min="0" v-model:value="data" />
         </div>
       </template>

+ 2 - 2
src/views/vent/monitorManager/windowMonitor/index.vue

@@ -525,14 +525,14 @@
         devicetype: selectData.value.deviceType,
         paramcode: 'frontSetValue',
         password: passWord || globalConfig?.simulatedPassword,
-        value: null,
+        value: value ? value : null,
       };
       const data2 = {
         deviceid: selectData.value.deviceID,
         devicetype: selectData.value.deviceType,
         paramcode: 'rearSetValue',
         password: passWord || globalConfig?.simulatedPassword,
-        value: null,
+        value: value ? value : null,
       };
       const res1 = await deviceControlApi(data1);
       const res2 = await deviceControlApi(data2);

+ 37 - 30
src/views/vent/monitorManager/workFaceMonitor/components/workFaceHandleHistory.vue

@@ -1,41 +1,48 @@
 <template>
   <div class="handle-history">
-    <HandlerHistoryTable v-if="refresh" columns-type="operator_history" :device-type="type" :sys-id="deviceId"
-      designScope="caimei_history" :scroll="{ y: 650 }"/>
+    <HandlerHistoryTable
+      v-if="refresh"
+      columns-type="operator_history"
+      :device-type="type"
+      :sys-id="deviceId"
+      designScope="caimei_history"
+      :scroll="{ y: 650 }"
+    />
   </div>
 </template>
 <script setup lang="ts">
-import { watch, ref, nextTick } from 'vue'
-import HandlerHistoryTable from '../../comment/WorkFaceHandlerHistoryTable.vue';
+  import { watch, ref, nextTick } from 'vue';
+  import HandlerHistoryTable from '../../comment/WorkFaceHandlerHistoryTable.vue';
 
-const props = defineProps({
-  deviceType: {
-    type: String,
-    required: true,
-  },
-  deviceId: {
-    type: String,
-    required: true,
-  }
-})
-
-const type = ref(props.deviceType)
+  const props = defineProps({
+    deviceType: {
+      type: String,
+      required: true,
+    },
+    deviceId: {
+      type: String,
+      required: true,
+    },
+  });
 
-const refresh = ref(true)
-
-watch(() => props.deviceType, (newVal) => {
-  type.value = newVal
-  refresh.value = false
-  nextTick(() => {
-    refresh.value = true
-  })
-})
+  const type = ref(props.deviceType);
 
+  const refresh = ref(true);
 
+  watch(
+    () => props.deviceType,
+    (newVal) => {
+      type.value = newVal;
+      refresh.value = false;
+      nextTick(() => {
+        refresh.value = true;
+      });
+    }
+  );
 </script>
 <style lang="less" scoped>
-.handle-history {
-  width: 100%;
-  pointer-events: auto;
-}
-</style>
+  .handle-history {
+    width: 100%;
+    pointer-events: auto;
+  }
+</style>

+ 3 - 9
src/views/vent/monitorManager/workFaceMonitor/components/workFaceHistory.vue

@@ -1,18 +1,12 @@
 <template>
   <div class="history-box">
-    <HistoryTable
-      :columns-type="`${deviceType}`"
-      :device-type="deviceType"
-      :sysId="deviceId"
-      designScope="pressurefan_history"
-      :scroll="{ y: 650 }"
-    />
+    <HistoryTable :device-code="`${deviceType}`" :dict-code="`${deviceType}_dict`" :scroll="{ y: 650 }" />
   </div>
 </template>
 <script setup lang="ts">
   import { ref, defineProps } from 'vue';
-  import HistoryTable from '../../comment/HistoryTable.vue';
-
+  // import HistoryTable from '../../comment/HistoryTable.vue';
+  import HistoryTable from '/@/views/vent/comment/history/HistoryTable.vue';
   const props = defineProps({
     deviceType: {
       type: String,

+ 2 - 10
src/views/vent/reportManager/comment/common/cameraTree.vue

@@ -1,11 +1,5 @@
 <template>
-  <treeList
-    v-for="model in list"
-    v-bind="$attrs"
-    :model="model"
-    :key="model.id"
-    @detail-node="onDetail"
-  >
+  <treeList v-for="model in list" v-bind="$attrs" :model="model" :key="model.id" @detail-node="onDetail">
     <template #icon="slotProps">
       <slot name="icon" v-bind="slotProps"></slot>
     </template>
@@ -17,7 +11,7 @@
 <script setup lang="ts">
   import { ref } from 'vue';
   import treeList from './treeList.vue';
-  const emit = defineEmits([ 'detailNode']);
+  const emit = defineEmits(['detailNode']);
   interface IFileSystem {
     id: string;
     title: string;
@@ -57,7 +51,5 @@
       eventType: 'detail',
     });
   };
- 
-  
 </script>
 <style scoped></style>

Some files were not shown because too many files changed in this diff