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

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

lxh пре 1 година
родитељ
комит
fb39012769

+ 0 - 1
src/components/Form/src/hooks/useForm.ts

@@ -154,6 +154,5 @@ export function useForm(props?: Props): UseFormReturnType {
       return form.validateFields(nameList, options);
     },
   };
-
   return [register, methods];
 }

+ 12 - 6
src/layouts/default/sider/bottomSideder.vue

@@ -11,12 +11,12 @@
               <template v-for="(childMenu, childIndex) in menu.children" :key="childIndex">
                 <template v-if="!childMenu.hideMenu">
                   <template v-if="childMenu['ver'] == 1">
-                    <div class="child-menu-item" @click="handleMenuClick(childMenu)">
+                    <div class="child-menu-item" @click.stop="handleMenuClick(childMenu)">
                       {{ childMenu.name }}
                     </div>
                   </template>
                   <template v-else>
-                    <div class="child-menu-item-disabled" @click="handleMenuClick(childMenu)" :style="{ backgroundColor: '#314671' }">
+                    <div class="child-menu-item-disabled" @click.stop="handleMenuClick(childMenu)" :style="{ backgroundColor: '#314671' }">
                       {{ childMenu.name }}
                     </div>
                   </template>
@@ -34,7 +34,7 @@
               v-if="!programMenu.title.startsWith('首页')"
               class="program-menu"
               :class="{ 'program-menu-active': currentParentRoute == programMenu }"
-              @click="selectMenu(programMenu)"
+              @click="selectMenu($event, programMenu)"
               >{{ programMenu.title }}</div
             >
           </template>
@@ -83,7 +83,9 @@
       const go = useGo();
       const glob = useGlobSetting();
 
-      function selectMenu(programMenu) {
+      function selectMenu(e:Event, programMenu) {
+        debugger
+        e.stopPropagation()
         currentParentRoute.value = programMenu;
       }
 
@@ -181,12 +183,16 @@
           go(glob.homePath || PageEnum.BASE_HOME)
         }
       }
-      function closeMenu() {
+      function closeMenu(e?:Event) {
+        e?.stopPropagation()
         isShowMenu.value = 0;
+        document.removeEventListener('click', closeMenu);
       };
 
-      function openMenu() {
+      function openMenu(e:Event) {
+        e.stopPropagation()
         isShowMenu.value = -1;
+        document.addEventListener('click', closeMenu);
       }
 
       onMounted(async () => {

+ 1 - 1
src/qiankun/index.ts

@@ -32,7 +32,7 @@ const mountMicroApp = (path, toPath?) => {
       instance.update()
     } else {
       if(toPath){
-        app['props']['publicPath'] = toPath
+        app['props']['data']['publicPath'] = toPath
       }
       activeApps[app['activeRule']] = loadMicroApp(app) // 手动加载子应用
     }

+ 3 - 1
src/router/guard/index.ts

@@ -40,9 +40,11 @@ function createPageGuard(router: Router) {
 
   router.beforeEach(async (to) => {
     if (!to.path.startsWith('/micro-vent-3dModal')) {
-      debugger
       unmountMicroApps(['/micro-vent-3dModal']);
     }
+    if (!to.path.startsWith('/micro-need-air')) {
+      unmountMicroApps(['/micro-need-air']);
+    }
     // The page has already been loaded, it will be faster to open it again, you don’t need to do loading and other processing
     to.meta.loaded = !!loadedPageMap.get(to.path);
     // Notify routing changes

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

@@ -8,6 +8,7 @@
     :showOkBtn="false"
     :footer="null"
     destroyOnClose
+    :mask-closable="false"
     @cancel="closeModalFn"
   >
     <a-tabs v-if="props.showTab" v-model:activeKey="activeKey">

+ 12 - 5
src/views/vent/monitorManager/comment/GroupMonitorTable.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="vent-table">
     <a-radio-group v-model:value="selectRowIndex" @change="setSelectedRowKeys" style="width: 100%">
-      <a-table :columns="columns" :pagination="false" :data-source="dataTableSource" bordered style="margin-top: 5px" :scroll="tableScroll">
+      <a-table :columns="columns" :pagination="false" :data-source="dataTableSource" bordered style="margin-top: 5px" :scroll="tableScroll" :selectType="'radio'" :customRow="rowClick">
         <template #bodyCell="{ column, record }">
           <template v-if="column.dataIndex === 'isCheck'">
             <a-radio :value="record.deviceID" />
@@ -24,7 +24,7 @@
 
 <script lang="ts" setup>
   //ts语法
-  import { toRaw, watch, ref, onMounted, onUnmounted } from 'vue';
+  import { toRaw, watch, ref, onMounted, onUnmounted, nextTick } from 'vue';
   import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
   const props = defineProps({
     columnsType: {
@@ -66,9 +66,16 @@
   // 默认初始是第一行
   const selectRowIndex = ref(-1);
 
+  const rowClick = (record) => {
+    return {
+      onClick: () => {
+        setSelectedRowKeys(record['deviceID'])
+      },
+    };
+  };
+
   const setSelectedRowKeys = (target) => {
     console.log(target, Object.prototype.toString.call(target));
-
     if (Object.prototype.toString.call(target) === '[object String]') {
       selectRowIndex.value = target;
       emits('selectRow', target);
@@ -84,7 +91,7 @@
     const isCheckColumn = {
       title: '',
       dataIndex: 'isCheck',
-      width: 120,
+      width: 40,
       align: 'center',
       customCell: (_, index) => {
         if (index % 2 == 0) {
@@ -159,7 +166,7 @@
     () => {
       return props.columnsType;
     },
-    (newVal) => {
+    (newVal, oldVal) => {
       if (!newVal) return
       setColumns(newVal)
     },

+ 3 - 0
src/views/vent/monitorManager/comment/HistoryTable.vue

@@ -175,6 +175,7 @@ import { onMounted } from 'vue';
               label: '时间区间',
               field: 'tickectDate',
               component: 'TimeRangePicker',
+              defaultValue: dayjs('HH:mm:ss'),
               componentProps: {
                 placeholder: ['开始时间', '结束时间'],
                 valueFormat: 'HH:mm:ss',
@@ -317,6 +318,7 @@ import { onMounted } from 'vue';
             field: 'startTime',
             label: '开始时间',
             component: 'DatePicker',
+            defaultValue: dayjs().startOf('date'),
             required: true,
             componentProps: {
               showTime: true,
@@ -328,6 +330,7 @@ import { onMounted } from 'vue';
             field: 'endTime',
             label: '结束时间',
             component: 'DatePicker',
+            defaultValue: dayjs(),
             required: true,
             componentProps: {
               showTime: true,

+ 20 - 0
src/views/vent/monitorManager/comment/comment.api.ts

@@ -0,0 +1,20 @@
+import { defHttp } from '/@/utils/http/axios';
+
+enum Api {
+  list = '/safety/ventanalyDeviceInfo/list',
+  edit = '/safety/ventanalyDeviceInfo/edit',
+  input = '/safety/ventanalyDeviceInfo/input',
+}
+
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) => defHttp.get({ url: Api.list, params });
+/**
+ * 保存或者更新用户
+ * @param params
+ */
+export const updateDeviceInfo = (params) => defHttp.put({ url: Api.edit, params });
+
+export const updateReportInfo = (params) => defHttp.put({ url: Api.input, params });

+ 1 - 1
src/views/vent/monitorManager/comment/components/DetailModal.vue

@@ -9,13 +9,13 @@
 
 import { onMounted, ref, defineEmits, onUnmounted, watch } from 'vue';
 import { BasicModal, useModalInner } from '/@/components/Modal';
+import deviceTable from '/@/views/vent/deviceManager/deviceTable/index.vue'
 
 const emit = defineEmits(['close', 'register'])
 const props = defineProps({
   
 })
 
-
 // 注册 modal
 const [register, { closeModal }] = useModalInner();
 

+ 199 - 0
src/views/vent/monitorManager/comment/components/DeviceBaseInfo.vue

@@ -0,0 +1,199 @@
+<template>
+  <BasicModal @register="register" :title="tabType =='deviceInfo' ? '设备编辑' : '报表录入'" width="1000px" v-bind="$attrs" @ok="onSubmit" :mask-closable="false">
+    <BasicForm ref="FormRef" @register="registerForm"/>
+  </BasicModal>
+</template>
+<script lang="ts" setup>
+
+import { onMounted, ref, defineEmits, onUnmounted, watch, PropType, nextTick } from 'vue';
+import { BasicModal, useModalInner } from '/@/components/Modal';
+import { BasicForm, useForm } from '/@/components/Form/index';
+import { FormSchema } from '/@/components/Form';
+import { getFormSchemaColumns } from '/@/hooks/web/useWebColumns';
+import { list as substationList } from '/@/views/vent/deviceManager/substationTabel/substation.api';
+import {list, updateDeviceInfo, updateReportInfo } from '../comment.api'
+
+const emit = defineEmits(['close', 'register'])
+const props = defineProps({
+  formSchema: {
+    type: Array as PropType <FormSchema[]> ,
+    default: () => []
+  },
+  deviceType: {
+    type: String,
+    default: ''
+  },
+})
+const FormRef = ref()
+const tabType = ref('deviceInfo')
+const formSchema = ref<FormSchema[]>([])
+const formData = ref({})
+const deviceTypeName = ref('')
+
+const arrToFormColumns = (tableHeaderColumns = [], devicetype) => {
+  const columnList: any[] = [];
+  tableHeaderColumns.forEach((item: any) => {
+    let columnsItem;
+    if (item.type == 1 || item.type == 10) {
+      columnsItem = {
+        label: item.unit ? `${item.des}(${item.unit})` : item.des, //_dictText
+        field: item.monitorcode,
+        component: item.type == 1 ? 'Input' : item.type == 10 ? 'InputTextArea' : '',
+      };
+    } else {
+      if (item.type == 2 && item['monitorcode'] == 'nsubstationid') {
+        columnsItem = {
+          label: item.unit ? `${item.des}(${item.unit})` : item.des, //_dictText
+          field: item.monitorcode,
+          component: 'ApiSelect',
+          componentProps: {
+            api: substationList,
+            labelField: 'strname',
+            valueField: 'id',
+          },
+        };
+      }
+      if (item.type == 3) {
+        columnsItem = {
+          label: item.unit ? `${item.des}(${item.unit})` : item.des, //_dictText
+          field: item.monitorcode,
+          component: 'RadioGroup',
+          defaultValue: 1,
+          componentProps: () => {
+            return {
+              options: [
+                { label: '是', value: 1, key: '1' },
+                { label: '否', value: 0, key: '2' },
+              ],
+              stringToNumber: true,
+            };
+          },
+        };
+      }
+      if (item.type == 4) {
+        columnsItem = {
+          label: item.unit ? `${item.des}(${item.unit})` : item.des, //_dictText
+          field: item.monitorcode,
+          component: 'JDictSelectTag',
+          componentProps: {
+            dictCode: item.dict,
+            placeholder: '请选择',
+            stringToNumber: true,
+          },
+        };
+      }
+    }
+    columnList.push(columnsItem);
+  });
+  formSchema.value = columnList
+  if(tabType.value === 'deviceInfo'){
+    formSchema.value.unshift(
+      {
+        label: '设备id', //_dictText
+        field: 'id',
+        component: 'Input',
+        componentProps: {
+          disabled: true,
+          show: false
+        },
+      },
+      {
+        label: '点表',
+        field: 'strtype',
+        component: 'JDictSelectTag',
+        componentProps: {
+          dictCode: `${devicetype.split('_')[0]}kind`,
+          placeholder: '请选择点表',
+        },
+      })
+      formSchema.value.push(
+      {
+        label: '备用分站',
+        field: 'stationids',
+        component: 'ApiSelect',
+        componentProps: {
+          api: substationList,
+          labelField: 'strname',
+          valueField: 'id',
+        },
+      },
+    )
+  }else{
+    formSchema.value.unshift(
+      {
+        label: '设备id', //_dictText
+        field: 'id',
+        component: 'Input',
+        componentProps: {
+          disabled: true,
+          show: false
+        },
+      })
+  }
+};
+
+// 注册 modal
+const [register, { closeModal, setModalProps }] = useModalInner(async (data) => {
+  debugger
+  tabType.value = data.type
+  const deviceId = data.deviceId
+  if (FormRef.value) {
+    setModalProps({ confirmLoading: false });
+    getColumns()
+    resetSchema(formSchema.value)
+    resetFields()
+    const result = await list({ id: deviceId })
+    formData.value = result['records'][0]
+    await setFieldsValue({
+      ...formData.value,
+    });
+  }
+});
+
+const [registerForm, { resetSchema, getFieldsValue, setFieldsValue, resetFields }] = useForm({
+  schemas: <FormSchema[]>formSchema.value,
+  showActionButtonGroup: false,
+});
+
+function getColumns() {
+  let formSchemaArr = getFormSchemaColumns(tabType.value === 'deviceInfo' ? `${deviceTypeName.value}_edit` : `${deviceTypeName.value}_input`) || []
+  if (formSchemaArr && formSchemaArr.length < 1) {
+    const arr = deviceTypeName.value.split('_')
+    formSchemaArr = getFormSchemaColumns(tabType.value === 'deviceInfo' ? arr[0] + '_edit' : arr[0] + '_input') || []
+  }
+  arrToFormColumns(formSchemaArr, deviceTypeName.value)
+} 
+
+watch(() => props.deviceType, (devicetype) => {
+  deviceTypeName.value = devicetype
+  getColumns()
+  if(FormRef.value)resetSchema(formSchema.value)
+})
+
+
+async function onSubmit() {
+  
+  let formValue = getFieldsValue();
+  setModalProps({ confirmLoading: true });
+  if(tabType.value === 'deviceInfo'){
+    await updateDeviceInfo(formValue)
+  }else{
+    await updateReportInfo(formValue)
+  }
+  
+  setModalProps({ confirmLoading: false });
+  emit('close')
+  closeModal();
+}
+
+onMounted(async () => {
+  debugger
+});
+onUnmounted(() => {
+
+});
+</script>
+<style scoped lang="less">
+@import '/@/design/vent/color.less';
+@import '/@/design/vent/modal.less';
+</style>

+ 1 - 1
src/views/vent/monitorManager/deviceMonitor/components/device/device.data.ts

@@ -254,7 +254,7 @@ export const haveDetailArr = [
   'fanmain',
   'fiber',
   'bundletube',
-  // 'dusting',
+  'dusting',
   'pump',
   'safetymonitor',
   'nitrogen',

+ 21 - 17
src/views/vent/monitorManager/deviceMonitor/components/device/index.vue

@@ -72,22 +72,22 @@
             <template v-if="(deviceType.startsWith('fanlocal') || deviceType.startsWith('fanmain')) && activeKey == '1'">
               <GroupMonitorTable  ref="MonitorDataTable" :dataSource="dataSource" :columnsType="`${deviceType}_monitor`" :scroll="scroll" :isAction="true" :isShowSelect="false">
                 <template #action="{ record }">
-                    <TableAction :actions="haveDetailArr.find((item) => deviceType.startsWith(item)) ? [
-                      {
-                        label: '详情',
-                        onClick: goDetail.bind(null, record),
-                      },
-                      {
-                        label: '定位',
-                        onClick: goLocation.bind(null, record),
-                      },
-                    ] : [
-                      {
-                        label: '定位',
-                        onClick: goLocation.bind(null, record),
-                      },
-                    ]" />
-                  </template>
+                  <TableAction :actions="haveDetailArr.find((item) => deviceType.startsWith(item)) ? [
+                    {
+                      label: '详情',
+                      onClick: goDetail.bind(null, record),
+                    },
+                    {
+                      label: '定位',
+                      onClick: goLocation.bind(null, record),
+                    },
+                  ] : [
+                    {
+                      label: '定位',
+                      onClick: goLocation.bind(null, record),
+                    },
+                  ]" />
+                </template>
               </GroupMonitorTable>
             </template>
             <template v-else-if="deviceType == 'majorpath' && activeKey == '1'">
@@ -295,6 +295,7 @@ import { TableAction } from '/@/components/Table';
 import FiberModal from './modal/fiber.modal.vue';
 import BundleModal from './modal/bundle.modal.vue'
 import DustModal from './modal/dust.modal.vue'
+import BallvalveModal from './modal/ballvalve.modal.vue'
 import { SvgIcon } from '/@/components/Icon';
 import { getActions } from '/@/qiankun/state';
 import { useRouter } from 'vue-router';
@@ -584,8 +585,11 @@ function goDetail(record?) {
       currentModal.value = DustModal
       modalVisible.value = true;
     } else if (deviceType.value.startsWith('bundletube')) {
-      currentModal.value = BundleModal
+      currentModal.value = BallvalveModal
       modalVisible.value = true;
+    } else if (deviceType.value.startsWith('bundletube')) {
+      // currentModal.value = BundleModal
+      // modalVisible.value = true;
     } else if (deviceType.value.indexOf("gate") != -1) {
       const newPage = router.resolve({ path: '/monitorChannel/monitor-gate', query: { id: activeID.value } })
       window.open(newPage.href, '_blank')

+ 553 - 0
src/views/vent/monitorManager/deviceMonitor/components/device/modal/ballvalve.modal.vue

@@ -0,0 +1,553 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="register" :title="`束管监测详情    ${currentTime}`" width="1200px" @ok="handleOk"
+    @cancel="handleCancel">
+    <div class="fiber-modal">
+      <div class="modal-left">
+        <div v-for="device in deviceList" class="link-item"
+          :class="{ 'active-device-title': device.deviceID === activeDeviceID }" :key="device.deviceID">
+          <span class="" @click="selectDevice(device.deviceID)">{{ device.strinstallpos }}</span>
+        </div>
+      </div>
+      <div class="modal-right">
+        <!-- <span class="base-title">基本信息</span>
+        <div>
+          <div>
+            <span>监测区域范围:</span>
+            <span>{{ 0 }} - {{ 1 }}</span>
+          </div>
+        </div> -->
+        <span class="base-title">实时监测参数</span>
+        <div class="right-top">
+          <!-- 温度 -->
+           <div class="top-item">
+            <div class="icon">
+              <SvgIcon class="icon-style max-temperature" size="38" name="max-temperature" />
+            </div>
+            <div class="item-container">
+              <div class="title">最高温度</div>
+              <div class="value">{{ posMonitor.fmax }} <span>℃</span> </div>
+            </div>
+          </div>
+          <div class="top-item">
+            <div class="icon">
+              <SvgIcon class="icon-style min-temperature" size="38" name="min-temperature" />
+            </div>
+            <div class="item-container">
+              <div class="title">最低温度</div>
+              <div class="value">{{ posMonitor.fmin }} <span>℃</span></div>
+            </div>
+          </div>
+          <div class="top-item">
+            <div class="icon">
+              <SvgIcon class="icon-style aveg-temperature" size="38" name="aveg-temperature" />
+            </div>
+            <div class="item-container">
+              <div class="title">平均温度</div>
+              <div class="value">{{ posMonitor.favg }} <span>℃</span></div>
+            </div>
+          </div>
+          <div class="top-item warning-box">
+            <div class="icon">
+              <SvgIcon class="icon-style" size="38" name="risk-level" />
+            </div>
+            <div class="item-container">
+              <div class="title">风险等级</div>
+              <div class="warning-value">低风险</div>
+            </div>
+          </div>
+          <div class="top-item item-data">
+            <div class="icon">
+              <SvgIcon class="icon-style" name="coval" style="width: 62px; height: 38px; margin-top: 10px;" />
+            </div>
+            <div class="item-container">
+              <div class="title">温度</div>
+              <div class="value">{{ (posMonitor.coval !== undefined && posMonitor.coval !== null) ? posMonitor.coval : '-'
+              }} <span>ppm</span> </div>
+              <div>报警阈值:12</div>
+            </div>
+          </div>
+          <div class="top-item item-data">
+            <div class="icon">
+              <SvgIcon class="icon-style" name="coval" style="width: 62px; height: 38px; margin-top: 10px;" />
+            </div>
+            <div class="item-container">
+              <div class="title">一氧化碳</div>
+              <div class="value">{{ (posMonitor.coval !== undefined && posMonitor.coval !== null) ? posMonitor.coval : '-'
+              }} <span>ppm</span> </div>
+              <div>报警阈值:12</div>
+            </div>
+          </div>
+          <div class="top-item item-data">
+            <div class="icon">
+              <SvgIcon class="icon-style" name="co2val" style="width: 72px; height: 46px;" />
+            </div>
+            <div class="item-container">
+              <div class="title">二氧化碳</div>
+              <div class="value">{{ (posMonitor.co2val !== undefined && posMonitor.co2val !== null) ? posMonitor.co2val :
+                '-' }} <span>%</span></div>
+            </div>
+          </div>
+          <div class="top-item item-data">
+            <div class="icon">
+              <SvgIcon class="icon-style" name="gasval" style="width: 72px; height: 46px;" />
+            </div>
+            <div class="item-container">
+              <div class="title">甲烷</div>
+              <div class="value">{{ (posMonitor.gasval !== undefined && posMonitor.gasval !== null) ? posMonitor.gasval :
+                '-' }} <span>%</span></div>
+            </div>
+          </div>
+          <div class="top-item item-data">
+            <div class="icon">
+              <SvgIcon class="icon-style" name="ch2val" style="width: 76px; height: 42px;" />
+            </div>
+            <div class="item-container">
+              <div class="title">乙烯</div>
+              <div class="value">{{ (posMonitor.ch2val !== undefined && posMonitor.ch2val !== null) ? posMonitor.ch2val :
+                '-' }} <span>ppm</span></div>
+            </div>
+          </div>
+          <div class="top-item">
+            <div class="icon">
+              <SvgIcon class="icon-style" name="chval" style="width: 76px; height: 42px;" />
+            </div>
+            <div class="item-container">
+              <div class="title">乙炔</div>
+              <div class="value">{{ (posMonitor.chval !== undefined && posMonitor.chval !== null) ? posMonitor.chval : '-'
+              }} <span>ppm</span></div>
+            </div>
+          </div>
+          <div class="top-item">
+            <div class="icon">
+              <SvgIcon class="icon-style" name="o2val" style="width: 76px; height: 50px;" />
+            </div>
+            <div class="item-container">
+              <div class="title">氧气</div>
+              <div class="value">{{ (posMonitor.o2val !== undefined && posMonitor.o2val !== null) ? posMonitor.o2val : '-'
+              }} <span>%</span></div>
+            </div>
+          </div>
+          <div class="top-item warning-box">
+            <div class="icon">
+              <SvgIcon class="icon-style" size="42" name="alarm-warning" style="margin-top: 5px;" />
+            </div>
+            <div class="item-container">
+              <div class="title">风险等级</div>
+              <div class="warning-value">{{ posMonitor['warnLevel_str'] ? posMonitor['warnLevel_str'] : '-' }}</div>
+            </div>
+          </div>
+          <div class="top-item warning-box">
+            <div class="icon">
+              <SvgIcon class="icon-style" size="42" name="link" style="margin-top: 5px;" />
+            </div>
+            <div class="item-container">
+              <div class="title">连接状态</div>
+              <div class="warning-value">{{ posMonitor['netStatus'] == 1 ? '连接' : '未连接' }}</div>
+            </div>
+          </div>
+        </div>
+        <div class="right-bottom">
+          <span class="base-title">设备监测曲线</span>
+          <div class="echarts-box">
+            <BarAndLine class="echarts-line" xAxisPropType="time" :dataSource="historyList" height="100%"
+              :chartsColumns="chartsColumns" :option="echatsOption" chartsType="listMonitor" />
+          </div>
+        </div>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+import { defineComponent, ref, watch, shallowRef } from 'vue';
+import { BasicModal, useModalInner } from '/@/components/Modal';
+import BarAndLine from '/@/components/chart/BarAndLine.vue';
+import { SvgIcon } from '/@/components/Icon';
+import { Decoration7 as DvDecoration7, ScrollBoard as DvScrollBoard } from '@kjgl77/datav-vue3';
+import dayjs from 'dayjs'
+
+export default defineComponent({
+  components: { BasicModal, BarAndLine, SvgIcon, DvScrollBoard, DvDecoration7 },
+  props: {
+    dataSource: { type: Array },
+    activeID: { type: String }
+  },
+  setup(props) {
+    const currentTime = ref(dayjs().format('YYYY-MM-DD HH:mm:ss'))
+    const modelRef = ref({});
+    const loading = ref(true);
+    const activeDeviceID = ref('');
+    const deviceList = ref<any[]>([])
+    const historyList = ref<any[]>([])
+    const posList = ref<any[]>([])
+    const posMonitor = shallowRef({})
+
+    const echatsOption = {
+      grid: {
+        top: '25%',
+        left: '30',
+        right: '45',
+        bottom: '3%',
+        containLabel: true
+      },
+      toolbox: {
+        feature: {}
+      },
+    }
+
+    const chartsColumns = [
+      {
+        legend: '一氧化碳',
+        seriesName: '(ppm)',
+        ymax: 10,
+        yname: 'ppm',
+        linetype: 'line',
+        yaxispos: 'left',
+        color: '#FDB146',
+        sort: 1,
+        xRotate: 0,
+        dataIndex: 'coval',
+      },
+      {
+        legend: '乙炔',
+        seriesName: '',
+        ymax: 10,
+        yname: 'ppm',
+        linetype: 'line',
+        yaxispos: 'left',
+        color: '#00FFA8',
+        sort: 1,
+        xRotate: 0,
+        dataIndex: 'chval',
+      },
+      {
+        legend: '乙烯',
+        seriesName: '',
+        ymax: 10,
+        yname: 'ppm',
+        linetype: 'line',
+        yaxispos: 'left',
+        color: '#AE19FF',
+        sort: 1,
+        xRotate: 0,
+        dataIndex: 'ch2val',
+      },
+      {
+        legend: '二氧化碳',
+        seriesName: '(%)',
+        ymax: 20,
+        yname: '1%',
+        linetype: 'line',
+        yaxispos: 'right',
+        color: '#9C83D9',
+        sort: 2,
+        xRotate: 0,
+        dataIndex: 'co2val',
+      },
+      {
+        legend: '甲烷',
+        seriesName: '',
+        ymax: 20,
+        yname: '1%',
+        linetype: 'line',
+        yaxispos: 'right',
+        color: '#DA3914',
+        sort: 2,
+        xRotate: 0,
+        dataIndex: 'gasval',
+      },
+      {
+        legend: '氧气',
+        seriesName: '(氧气%)',
+        ymax: 30,
+        yname: '2%',
+        linetype: 'line',
+        yaxispos: 'right',
+        color: '#03C2EC',
+        sort: 3,
+        xRotate: 0,
+        dataIndex: 'o2val',
+      },
+
+    ]
+    const [register, { setModalProps, closeModal }] = useModalInner();
+
+    function handleVisibleChange(visible) {
+      if (visible) {
+        loading.value = true;
+        setModalProps({ loading: true, confirmLoading: true });
+
+        setTimeout(() => {
+          loading.value = false;
+          setModalProps({ loading: false, confirmLoading: false });
+        }, 1000);
+      }
+    }
+
+    // 选择监测
+    function selectDevice(id) {
+      loading.value = true;
+      setModalProps({ loading: true, confirmLoading: true });
+      setTimeout(() => {
+        loading.value = false;
+        activeDeviceID.value = id
+        setModalProps({ loading: false, confirmLoading: false });
+      }, 300);
+    }
+
+    function handleOk(e) {
+      e.preventDefault()
+      closeModal()
+    }
+
+    function handleCancel(e) {
+      e.preventDefault()
+      closeModal()
+    }
+
+    watch([() => props.dataSource, () => props.activeID], ([newDataSource, newActiveID], [oldDataSource, oldActiveID]) => {
+      if (newActiveID != oldActiveID) {
+        activeDeviceID.value = newActiveID as string
+      }
+      deviceList.value = newDataSource?.filter((item: any, index) => {
+        if ((!activeDeviceID.value && index == 0) || item.deviceID === activeDeviceID.value) {
+          activeDeviceID.value = item.deviceID
+          posMonitor.value = Object.assign(item, item.readData)
+          historyList.value = item['history']
+        }
+        item.readTime = item.readTime?.substring(11)
+        return item
+      })
+    })
+
+    return { register, model: modelRef, currentTime, handleVisibleChange, selectDevice, handleOk, handleCancel, deviceList, historyList, activeDeviceID, posMonitor, echatsOption, posList, chartsColumns };
+  },
+
+});
+</script>
+<style lang="less" scoped>
+.fiber-modal {
+  width: 100%;
+  height: 650px;
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+
+  .modal-left {
+    width: 200px;
+    height: 100%;
+    overflow-y: auto;
+    background: #ffffff11;
+    padding: 5px;
+    border-radius: 5px;
+
+    .active-device-title {
+      color: aqua;
+    }
+
+    .link-item {
+      position: relative;
+      cursor: pointer;
+      line-height: 30px;
+      padding-left: 30px;
+
+      span:hover {
+        color: #89ffff;
+      }
+
+      &::after {
+        content: '';
+        position: absolute;
+        display: block;
+        width: 8px;
+        height: 8px;
+        top: 12px;
+        left: 10px;
+        transform: rotateZ(45deg) skew(10deg, 10deg);
+        background: #45d3fd;
+      }
+    }
+  }
+
+  .modal-right {
+    width: calc(100% - 220px);
+
+    .base-title {
+      line-height: 32px;
+      position: relative;
+      padding-left: 20px;
+
+      &::after {
+        content: '';
+        position: absolute;
+        display: block;
+        width: 4px;
+        height: 12px;
+        top: 4px;
+        left: 10px;
+        background: #45d3fd;
+        border-radius: 4px;
+      }
+    }
+
+    .right-top {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      flex-wrap: wrap;
+      margin-bottom: 10px;
+
+      .top-item {
+        width: 220px;
+        height: 100px;
+        display: flex;
+        flex-direction: row;
+        justify-content: center;
+        border: 1px solid rgba(25, 237, 255, .4);
+        box-shadow: inset 0 0 10px rgba(0, 197, 255, .6);
+        background: rgba(0, 0, 0, .06666666666666667);
+        padding-top: 20px;
+        margin: 10px 0;
+
+        .icon {
+          margin-right: 10px;
+          margin-top: 5px;
+          color: #FDB146;
+        }
+
+        .item-container {
+          width: 100px;
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+
+          div {
+            text-align: center;
+          }
+
+          .title {
+            font-size: 18px;
+          }
+
+          .value {
+            text-shadow: 0 0 25px #00fbfe;
+            background: linear-gradient(0deg, #45d3fd, #45d3fd, #61ddb1, #61ddb1);
+            font-style: normal;
+            background-size: cover;
+            font-family: electronicFont;
+            font-size: 30px;
+            -webkit-background-clip: text;
+            background-clip: text;
+            -webkit-text-fill-color: transparent;
+            position: relative;
+            top: -8px;
+
+            span {
+              font-family: Arial, Helvetica, sans-serif;
+              font-size: 18px;
+              color: aliceblue;
+            }
+
+          }
+
+        }
+      }
+      .item-data{
+        height: 130px;
+        padding-top: 0;
+        .icon{
+          margin-right: 30px;
+          margin-top: 25px;
+        }
+        .item-container{
+          .value{
+            top: 0px;
+          }
+          .rang{
+            color: #ff8663;;
+          }
+        }
+      }
+
+      .warning-box {
+        padding-top: 0px;
+
+        .icon {
+          margin-top: 20px;
+
+          :deep(.icon-style) {
+            width: auto;
+            color: #FDB146;
+          }
+        }
+
+        .warning-value {
+          font-size: 18px;
+          color: #61ddb1;
+        }
+      }
+    }
+
+    .right-center {
+      margin-top: 20px;
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+
+      .table-box {
+        position: relative;
+        width: 500px;
+        height: 250px;
+      }
+
+      .warning-box {
+        width: calc(100% - 520px);
+
+        .warning-container {
+          width: 100%;
+          height: convert;
+          background: #009acd00;
+
+          :deep(.dv-scroll-board) {
+            .row-item {
+              height: 40px !important;
+              line-height: 40px !important;
+            }
+
+            .header-item {
+              border-top: 1px solid #91e9fe !important;
+              border-bottom: 1px solid #91e9fe !important;
+            }
+          }
+
+        }
+      }
+    }
+
+    .right-bottom {
+      margin-top: 20px;
+
+      .echarts-box {
+        width: 100%;
+        height: 320px;
+        position: relative;
+
+        .echarts-line {
+          width: calc(100% + 80px);
+          position: absolute
+        }
+      }
+    }
+  }
+}
+
+:deep(.zxm-table-body) {
+  border: 1px solid rgba(57, 232, 255, 0.2) !important;
+
+  .zxm-table-tbody>tr>td {
+    border: none !important;
+  }
+}
+
+:deep(.zxm-table-cell) {
+  border-right: none !important;
+}</style>

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

@@ -25,7 +25,6 @@ const NetworkRef = ref(null)
 const routerParam = ref('home')
 const pageData = ref({})
 const pageResult = ref({})
-const { type, deviceType } = route.query
 
 // actions.setGlobalState({ url: { path: '/micro-vent-3dModal/dashboard/analysis', query: { type, deviceType } } });
 
@@ -45,10 +44,10 @@ watch(() => route.fullPath, (fullPath) => {
 })
 
 onMounted(() => {
-  mountMicroApp('/micro-vent-3dModal', '/dashboard/analysis')
-  
-  // start()
-  
+  debugger
+  const { type, deviceType } = route.query
+  mountMicroApp('/micro-vent-3dModal')
+
   if (type === 'network') {
     routerParam.value = 'network'
     actions.setGlobalState({ pageObj: { pageType: 'network' } });

+ 54 - 44
src/views/vent/monitorManager/fanLocalMonitor/index.vue

@@ -56,40 +56,6 @@
     </div>
     <div class="data-show-box" v-if="!loading">
       <div class="data-item" v-if="leftColumns.length > 0">
-        <div class="item-header">环境监测</div>
-        <div class="item-container">
-          <div class="tab">
-            <div class="tab-item" :class="{ 'tab-item-active-r': dataMonitorRowIndex == 0 }" @click="selectDevice('dataMonitorRowIndex', 0)"
-              >1#风机</div
-            >
-            <div class="tab-item" :class="{ 'tab-item-active-r': dataMonitorRowIndex == 1 }" @click="selectDevice('dataMonitorRowIndex', 1)"
-              >2#风机</div
-            >
-          </div>
-          <div class="container-group container-group-l" >
-            <template v-if="!loading">
-              <div class="container-item" v-for="(data, index) in leftColumns" :key="index">
-                <div class="item-icon">
-                  <SvgIcon class="icon-style" size="18" name="temperature" />
-                </div>
-                <div class="item-name">{{ data.title }}</div>
-                <div v-if="data.dataIndex.startsWith('Fan')">
-                  <div class="item-value" v-if="dataMonitorRowIndex == 0">{{
-                    selectData[data.dataIndex.replace('Fan', 'Fan1')] ? selectData[data.dataIndex.replace('Fan', 'Fan1')] : '-'
-                  }}</div>
-                  <div class="item-value" v-if="dataMonitorRowIndex == 1">{{
-                    selectData[data.dataIndex.replace('Fan', 'Fan2')] ? selectData[data.dataIndex.replace('Fan', 'Fan2')] : '-'
-                  }}</div>
-                </div>
-                <div v-else>
-                  <div class="item-value">{{ selectData[data.dataIndex] ? selectData[data.dataIndex] : '-' }}</div>
-                </div>
-              </div>
-            </template>
-          </div>
-        </div>
-      </div>
-      <div class="data-item" v-if="rightColumns.length > 0">
         <div class="item-header">设备状态</div>
         <div class="item-container">
           <div class="tab">
@@ -113,7 +79,7 @@
             </div>
             <div class="warning-group">
               <template v-if="selectData.deviceType">
-                <div class="warning-item" v-for="(state, index) in rightColumns" :key="index">
+                <div class="warning-item" v-for="(state, index) in leftColumns" :key="index">
                   <div class="item-name"><div class="icon"></div> {{ state.title }}</div>
                   <div v-if="state.dataIndex.startsWith('Fan')">
                     <div class="signal-item" v-if="warningMonitorRowIndex == 0">
@@ -172,6 +138,40 @@
           </div>
         </div>
       </div>
+      <div class="data-item" v-if="rightColumns.length > 0"> 
+          <div class="item-header">环境监测</div>
+          <div class="item-container">
+            <div class="tab">
+              <div class="tab-item" :class="{ 'tab-item-active-r': dataMonitorRowIndex == 0 }" @click="selectDevice('dataMonitorRowIndex', 0)"
+                >1#风机</div
+              >
+              <div class="tab-item" :class="{ 'tab-item-active-r': dataMonitorRowIndex == 1 }" @click="selectDevice('dataMonitorRowIndex', 1)"
+                >2#风机</div
+              >
+            </div>
+            <div class="container-group container-group-l" >
+              <template v-if="!loading">
+                <div class="container-item" v-for="(data, index) in rightColumns" :key="index">
+                  <div class="item-icon">
+                    <SvgIcon class="icon-style" size="18" name="temperature" />
+                  </div>
+                  <div class="item-name">{{ data.title }}</div>
+                  <div v-if="data.dataIndex.startsWith('Fan')">
+                    <div class="item-value" v-if="dataMonitorRowIndex == 0">{{
+                      selectData[data.dataIndex.replace('Fan', 'Fan1')] ? selectData[data.dataIndex.replace('Fan', 'Fan1')] : '-'
+                    }}</div>
+                    <div class="item-value" v-if="dataMonitorRowIndex == 1">{{
+                      selectData[data.dataIndex.replace('Fan', 'Fan2')] ? selectData[data.dataIndex.replace('Fan', 'Fan2')] : '-'
+                    }}</div>
+                  </div>
+                  <div v-else>
+                    <div class="item-value">{{ selectData[data.dataIndex] ? selectData[data.dataIndex] : '-' }}</div>
+                  </div>
+                </div>
+              </template>
+            </div>
+          </div>
+      </div>
     </div>
     <div class="bottom-tabs-box" @mousedown="setDivHeight($event, 170, scroll, 180)">
       <dv-border-box8 :dur="5" class="dv_border_8"  :style="`bottom: 20px; padding: 5px; height: ${scroll.y + 140}px`" >
@@ -180,7 +180,12 @@
         </div> -->
         <a-tabs class="tabs-box" v-model:activeKey="activeKey" @change="tabChange">
           <a-tab-pane key="1" tab="实时监测">
-            <GroupMonitorTable  v-if="activeKey === '1'" ref="MonitorDataTable" :dataSource="dataSource" :columnsType="`${selectData.deviceType}_monitor`" @selectRow="getSelectRow" :scroll="scroll"/>
+            <GroupMonitorTable  v-if="activeKey === '1'" ref="MonitorDataTable" :dataSource="dataSource" :columnsType="`${selectData.deviceType}_monitor`" @selectRow="getSelectRow" :scroll="scroll" :is-action="true">
+              <template #action="{ record }">
+                <a class="table-action-link" @click="deviceEdit($event, 'reportInfo', record)">报表录入</a>
+                <a class="table-action-link" @click="deviceEdit($event, 'deviceInfo', record)">设备编辑</a>
+              </template>
+            </GroupMonitorTable>
           </a-tab-pane>
           <a-tab-pane key="2" tab="实时曲线图" force-render>
             <div class="tab-item" v-if="activeKey === '2'">
@@ -315,7 +320,7 @@
       </div>
     </div>
   </a-modal>
-  <!-- <DetailModal @register="registerModal"/> -->
+  <DeviceBaseInfo @register="registerModal" :device-type="selectData['deviceType']"/>
 </template>
 
 <script setup lang="ts">
@@ -326,7 +331,7 @@
   import HistoryTable from '../comment/HistoryTable.vue';
   import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
   import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
-  // import DetailModal from './components/DetailModal.vue';
+  import DeviceBaseInfo from '../comment/components/DeviceBaseInfo.vue';
   import { mountedThree, setModelType, destroy, addCssText, addText, playSmoke } from './fanLocal.three';
   import lodash from 'lodash';
   import { getTableList, list } from '/@/views/vent/monitorManager/fanLocalMonitor/fanLocal.api';
@@ -345,6 +350,7 @@
   import { getPopupContainer } from '/@/utils';
   import { getDictItemsByCode } from '/@/utils/dict';
   import { message } from 'ant-design-vue';
+  import { TableAction } from '/@/components/Table';
 
   const globalConfig = inject('globalConfig');
 
@@ -620,18 +626,15 @@
   function getSelectRow(id) {
     console.log('选中的设备id------->', id)
 
-    if (!id) return;
-    loading.value = true;
+    if (!id || id == selectData['deviceID']) return;
+    // loading.value = true;
     const selectIndex: any = dataSource.value.findIndex((baseData: any) => baseData.deviceID == id);
     selectRowIndex.value = selectIndex;
     modalType.value = selectIndex > 0 ? 'fm' : 'fc';
 
-    const baseData = deviceBaseList.value.find(item => item['id'] == id) || {}
-    selectData = Object.assign({}, lodash.cloneDeep(initData), baseData)
-
     nextTick(() => {
       setModelType(modalType.value).then(() => {
-        loading.value = false;
+        // loading.value = false;
       });
       
       const data = dataSource.value[selectIndex];
@@ -809,6 +812,13 @@
     }
   };
 
+  function deviceEdit(e:Event, type:string, record) {
+    e.stopPropagation()
+    openModal(true, {
+     type,
+     deviceId: record['deviceID']
+    })
+  }
 
   onBeforeMount(() => {
     getDeviceBaseList();