浏览代码

Merge branch 'master' of http://39.97.59.228:8013/hrx/mky-vent-base

lxh 3 天之前
父节点
当前提交
25088f9842

+ 11 - 5
src/views/vent/home/configurable/belt/configurable.api.ts

@@ -18,13 +18,17 @@ enum Api {
   // 获取人员定位信息
   findStaffInfoBySystem = '/ventanaly-device/monitor/disaster/findStaffInfoBySystem',
   // 获取皮带巷信息
-  getLeatherInfo = '/modelreq/safety/ventanalyManageSystem/list',
-  // 操作历史
-  baseList = '/safety/ventanalyGate/list',
+  getLeatherInfo = '/safety/ventanalyManageSystem/list',
   // 设备历史
-  deviceHistory = '/modelreq/safety/ventanalyMonitorData/listdays',
+  deviceHistory = '/safety/ventanalyMonitorData/listdays',
   // 获取皮带巷下设备
   getDeviceData = '/ventanaly-device/safety/managesysAlarmInfo/getDevicesInfoBySysId',
+  // 操作历史
+  getDevicesetLog = '/safety/ventanalyDevicesetLog/list',
+  // 获取皮带巷下设备类型
+  systemList = '/monitor/device',
+  // 获取预警历史
+  alarmList = '/safety/managesysAutoLog/list',
 }
 export const getSystem = (params) => defHttp.post({ url: Api.getSystem, params });
 export const getMonitorAndAlertBelt = (params) => defHttp.post({ url: Api.monitorAndAlertBelt, params });
@@ -36,6 +40,8 @@ export const getWarnResult = (params) => defHttp.post({ url: Api.getWarnResult,
 export const getWarnInfo = (params) => defHttp.post({ url: Api.getWarnInfo, params });
 export const getStaffInfo = (params) => defHttp.post({ url: Api.findStaffInfoBySystem, params });
 export const getLeatherInfo = (params) => defHttp.get({ url: Api.getLeatherInfo, params });
-export const getTableList = (params) => defHttp.get({ url: Api.baseList, params });
 export const getDeviceHistoryApi = (params) => defHttp.get({ url: Api.deviceHistory, params });
 export const getDeviceData = (params) => defHttp.post({ url: Api.getDeviceData, params });
+export const getDevicesetLog = (params) => defHttp.get({ url: Api.getDevicesetLog, params });
+export const systemList = (params) => defHttp.post({ url: Api.systemList, params });
+export const getAlarmList = (params) => defHttp.get({ url: Api.alarmList, params });

+ 283 - 118
src/views/vent/home/configurable/belt/history.vue

@@ -2,58 +2,126 @@
   <div class="company-home">
     <div class="border">
       <customHeader>矿井全域皮带巷三级防灭火系统</customHeader>
-      <!-- Tab 切换 -->
-      <div class="tab-box">
-        <div class="tab-item" :class="{ active: activeTab === 'device' }" @click="switchTab('device')"> 设备历史数据 </div>
-        <div class="tab-item" :class="{ active: activeTab === 'operate' }" @click="switchTab('operate')"> 操作历史 </div>
-      </div>
-
-      <div class="box-container">
-        <!-- 设备历史 -->
-        <div v-if="activeTab === 'device'" key="device">
-          <BasicTable ref="historyTable" @register="registerTable" :data-source="dataSource" :scroll="{ x: 1000, y: 500 }" />
-        </div>
-
-        <!-- 操作历史 -->
-        <div v-if="activeTab === 'operate'" key="operate">
-          <BasicTable ref="operateTable" @register="registerOperateTable" :data-source="ctrlSource" :scroll="{ x: 1000, y: 500 }" />
-        </div>
+      <div :style="`padding: 5px; height: ${scroll.y + 100}px`">
+        <a-tabs class="tabs-box" v-model:activeKey="activeKey" @change="tabChange" id="tabsBox">
+          <a-tab-pane key="1" tab="历史数据">
+            <div class="tab-item">
+              <BasicTable ref="historyTable" @register="registerTable" :scroll="{ x: 1000, y: 350 }">
+                <template #bodyCell="{ column, record }">
+                  <a-tag v-if="column.dataIndex === 'warnFlag'" :color="record.warnFlag == '0' ? 'green' : 'red'">
+                    {{ record.warnFlag == '0' ? '正常' : '报警' }}
+                  </a-tag>
+                  <a-tag v-if="column.dataIndex === 'netStatus'" :color="record.netStatus == '0' ? '#f00' : 'green'">
+                    {{ record.netStatus == '0' ? '断开' : '连接' }}
+                  </a-tag>
+                </template>
+              </BasicTable>
+            </div>
+          </a-tab-pane>
+          <a-tab-pane key="2" tab="操作历史">
+            <div class="tab-item">
+              <BasicTable ref="operateTable" @register="registerOperateTable" :scroll="{ x: 1000, y: 350 }" />
+            </div>
+          </a-tab-pane>
+          <a-tab-pane key="3" tab="预警历史">
+            <div class="tab-item">
+              <BasicTable ref="alarmTable" @register="registerAlarmTable" :scroll="{ x: 1000, y: 350 }" />
+            </div>
+          </a-tab-pane>
+        </a-tabs>
       </div>
     </div>
   </div>
 </template>
 
 <script lang="ts" setup>
-import { ref, onMounted, nextTick } from 'vue';
+import { ref, onMounted, reactive, nextTick, watch, computed } from 'vue';
 import { BasicTable } from '/@/components/Table';
 import { useListPage } from '/@/hooks/system/useListPage';
+import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
 import dayjs from 'dayjs';
 import customHeader from './components/customHeader-belt.vue';
-import { getLeatherInfo, getTableList, getDeviceHistoryApi, getDeviceData } from './configurable.api';
+import { getLeatherInfo, getDeviceHistoryApi, getDevicesetLog, systemList, getAlarmList } from './configurable.api';
+
+type DeviceType = { deviceType: string; deviceName: string; datalist: any[] };
+
+const operateColumns = ref([]);
+const alarmColumns = ref([]);
 
-const activeTab = ref('device');
-// 设备下拉选项
 const deviceOptions = ref<any>([]);
-const deviceDataOptions = ref<any>([]);
-const dataSource = ref([]);
-const ctrlSource = ref([]);
-// 工具方法
-function resetFormParam() {
+const deviceList = ref<DeviceType[]>([]);
+// 设备名称选项:用 ref 保证响应式
+const deviceNameOptions = ref<any>([]);
+
+const strtype = ref('');
+const historyType = ref('');
+const columns = ref([]);
+const scroll = reactive({ y: 180 });
+const activeKey = ref('1');
+const deviceActive = ref('');
+
+// 设备类型下拉(计算属性)
+const deviceTypeSelectOptions = computed(() => {
+  return deviceList.value.map((item) => ({
+    label: item.deviceName,
+    value: item.deviceType,
+  }));
+});
+
+function tabChange(activeKeyVal) {
+  activeKey.value = activeKeyVal;
+  activeKey.value === '1' ? reload() : reloadOperate();
+}
+
+async function fetchDeviceHistory() {
   const formData = getForm().getFieldsValue();
   const pagination = getPaginationRef();
+
+  const p = {
+    pageNum: pagination.current,
+    pageSize: pagination.pageSize,
+    ttime_begin: formData.ttime_begin,
+    ttime_end: formData.ttime_end,
+    gdeviceids: formData.gdeviceids,
+    strtype: strtype.value,
+  };
+  const res = await getDeviceHistoryApi(p);
   return {
+    total: res?.datalist?.total || 0,
+    records: res?.datalist?.records?.map((item) => ({ ...item, ...item.readData })) || [],
+  };
+}
+// 获取操作历史
+async function fetchOperateHistory() {
+  const formData = getForm().getFieldsValue();
+  const pagination = getPaginationRef();
+  const p = {
     pageNum: pagination.current,
     pageSize: pagination.pageSize,
-    column: 'createTime',
-    startTime: formData.startTime,
-    endTime: formData.endTime,
-    deviceId: formData.gdeviceids,
-    strtype: 'sys_Leather',
-    sysId: formData.id,
+    createTime_begin: formData.ttime_begin,
+    createTime_end: formData.ttime_end,
+    devicetype: strtype.value ? strtype.value + '*' : '',
   };
+  const res = await getDevicesetLog(p);
+  return { total: res?.total || 0, records: res?.records || [] };
+}
+// 获取预警历史
+
+async function fetchAlarmHistory() {
+  const formData = getForm().getFieldsValue();
+  const pagination = getPaginationRef();
+  const p = {
+    pageNum: pagination.current,
+    pageSize: pagination.pageSize,
+    createTime_begin: formData.ttime_begin,
+    createTime_end: formData.ttime_end,
+    devicetype: strtype.value ? strtype.value + '*' : '',
+    gdeviceids: formData.gdeviceids,
+  };
+  const res = await getAlarmList(p);
+  return { total: res?.total || 0, records: res?.records || [] };
 }
 
-// 获取皮带巷列表
 async function getDeviceList() {
   const res = await getLeatherInfo({
     strtype: 'sys_Leather',
@@ -61,57 +129,95 @@ async function getDeviceList() {
     pageNo: 1,
     pageSize: 999,
   });
-  deviceOptions.value = res.records.map((item) => ({
-    label: item.systemname,
-    value: item.id,
-  }));
-}
-// 获取皮带巷下设备信息
-async function getDevice(id) {
-  const res = await getDeviceData({ sysId: id });
-  deviceDataOptions.value = res.map((item) => ({
-    label: item.deviceName,
-    value: item.deviceId,
-  }));
+  deviceOptions.value = res.records.map((item) => ({ label: item.systemname, value: item.id }));
+
+  if (deviceOptions.value.length > 0) {
+    const firstSysId = deviceOptions.value[0].value;
+    getForm().setFieldsValue({ sysId: firstSysId });
+    await getDeviceTypeList(firstSysId);
+  }
 }
+
+// 查询表单
 const getSchemas = () => [
   {
-    field: 'startTime',
+    field: 'ttime_begin',
     label: '开始时间',
     component: 'DatePicker',
     defaultValue: dayjs().subtract(1, 'day').startOf('day'),
-    componentProps: {
-      showTime: true,
-      valueFormat: 'YYYY-MM-DD HH:mm:ss',
-    },
+    componentProps: { showTime: true, valueFormat: 'YYYY-MM-DD HH:mm:ss' },
     colProps: { span: 4 },
   },
   {
-    field: 'endTime',
+    field: 'ttime_end',
     label: '结束时间',
     component: 'DatePicker',
     defaultValue: dayjs(),
-    componentProps: {
-      showTime: true,
-      valueFormat: 'YYYY-MM-DD HH:mm:ss',
-    },
+    componentProps: { showTime: true, valueFormat: 'YYYY-MM-DD HH:mm:ss' },
     colProps: { span: 4 },
   },
   {
-    field: 'id',
+    field: 'sysId',
     label: '皮带巷',
     component: 'Select',
     componentProps: {
       placeholder: '请选择皮带巷',
       showSearch: true,
       options: deviceOptions,
-      onChange: (e, option) => {
-        getDevice(option.value);
+      onChange: async (value) => {
+        if (value) {
+          getForm().setFieldsValue({ sysId: value, deviceType: undefined, gdeviceids: undefined });
+          strtype.value = '';
+          await getDeviceTypeList(value);
+        }
       },
     },
     required: true,
     colProps: { span: 4 },
   },
+  {
+    field: 'deviceType',
+    label: '设备类型',
+    component: 'Select',
+    componentProps: {
+      placeholder: '请选择设备类型',
+      showSearch: true,
+      options: deviceTypeSelectOptions,
+      onChange: async (value) => {
+        const selectedType = deviceList.value.find((item) => item.deviceType === value);
+        if (selectedType) {
+          // 1. 先更新设备名称选项
+          deviceNameOptions.value = selectedType.datalist.map((item) => ({
+            label: item.strname,
+            value: item.deviceID,
+            deviceKind: item.deviceType,
+          }));
+          deviceNameOptions.value = [...deviceNameOptions.value];
+          console.log(deviceNameOptions.value, '=============');
+          await nextTick();
+          // 4. 设置表单值
+          if (deviceNameOptions.value.length) {
+            getForm().setFieldsValue({
+              gdeviceids: deviceNameOptions.value[0].value,
+            });
+          } else {
+            getForm().setFieldsValue({ gdeviceids: undefined });
+          }
+
+          strtype.value = selectedType.deviceType;
+          historyType.value = selectedType.deviceType;
+
+          if (activeKey.value === '2') {
+            await loadOperateColumns();
+          } else if (activeKey.value === '3') {
+            await loadAlarmColumns();
+          }
+        }
+      },
+    },
+    required: true,
+    colProps: { span: 5 },
+  },
   {
     field: 'gdeviceids',
     label: '设备名称',
@@ -119,41 +225,54 @@ const getSchemas = () => [
     componentProps: {
       placeholder: '请选择设备',
       showSearch: true,
-      options: deviceDataOptions,
-      onChange: (e, option) => {
-        getHistoryData();
+      options: computed(() => deviceNameOptions.value),
+      onChange: (_, option) => {
+        historyType.value = option.deviceKind;
+        strtype.value = option.deviceKind;
+        if (activeKey.value === '2') {
+          loadOperateColumns();
+        } else if (activeKey.value === '3') {
+          loadAlarmColumns();
+        }
       },
     },
     required: true,
+    colProps: { span: 5 },
+  },
+  {
+    label: '间隔时间',
+    field: 'skip',
+    component: 'Select',
+    defaultValue: '8',
+    componentProps: {
+      options: [
+        { label: '1秒', value: '1' },
+        { label: '5秒', value: '2' },
+        { label: '10秒', value: '3' },
+        { label: '30秒', value: '4' },
+        { label: '1分钟', value: '5' },
+        { label: '10分钟', value: '6' },
+        { label: '30分钟', value: '7' },
+        { label: '1小时', value: '8' },
+      ],
+    },
     colProps: { span: 4 },
   },
 ];
 
-//设备历史
-const deviceColumns = ref([
-  { title: '设备名称', dataIndex: 'gdevicename', width: 180 },
-  { title: '设备位置', dataIndex: 'devicePos', width: 180 },
-  { title: '监测值', dataIndex: 'monitorValue', width: 120 },
-  { title: '采集时间', dataIndex: 'gcreatetime', width: 200 },
-]);
-
-async function getHistoryData() {
-  const params = resetFormParam();
-  const res = await getDeviceHistoryApi(params);
-  dataSource.value = res.records;
+function loadOperateColumns() {
+  const cols = getTableHeaderColumns('operator_history');
+  operateColumns.value = cols;
+  setOperateColumns(cols);
 }
 
-const { tableContext: deviceTableContext } = useListPage({
+// 历史数据表格
+const { tableContext } = useListPage({
   tableProps: {
-    api: async (params) => {
-      const res = await getDeviceHistoryApi(params);
-      return {
-        total: res.total || 0,
-        items: res.records || [],
-      };
-    },
-    columns: deviceColumns.value,
+    api: fetchDeviceHistory,
+    columns: columns,
     showIndexColumn: true,
+    showActionColumn: false,
     bordered: true,
     size: 'small',
     formConfig: {
@@ -166,21 +285,15 @@ const { tableContext: deviceTableContext } = useListPage({
     pagination: { pageSize: 20 },
   },
 });
-const [registerTable, { getForm, getPaginationRef }] = deviceTableContext;
-
-//操作历史
-const operateColumns = ref([
-  { title: '操作人', dataIndex: 'operateUser', width: 160 },
-  { title: '操作内容', dataIndex: 'operateContent', width: 300 },
-  { title: '操作时间', dataIndex: 'operateTime', width: 200 },
-  { title: '设备/位置', dataIndex: 'deviceName', width: 180 },
-]);
+const [registerTable, { getForm, setColumns, getPaginationRef, reload }] = tableContext;
 
+// 操作历史表格
 const { tableContext: operateTableContext } = useListPage({
   tableProps: {
-    api: getTableList,
-    columns: operateColumns.value,
+    api: fetchOperateHistory,
+    columns: operateColumns,
     showIndexColumn: true,
+    showActionColumn: false,
     bordered: true,
     size: 'small',
     formConfig: {
@@ -193,16 +306,87 @@ const { tableContext: operateTableContext } = useListPage({
     pagination: { pageSize: 20 },
   },
 });
-const [registerOperateTable] = operateTableContext;
+const [registerOperateTable, { setColumns: setOperateColumns, reload: reloadOperate }] = operateTableContext;
 
-//Tab 切换
-function switchTab(tab) {
-  activeTab.value = tab;
+// 获取设备类型列表
+async function getDeviceTypeList(value) {
+  const res = await systemList({ devicetype: 'sys', systemID: value });
+  const result = res.msgTxt;
+  const deviceArr: DeviceType[] = [];
+
+  result.forEach((item) => {
+    if (item.type !== 'sys' && item.datalist?.length) {
+      deviceArr.push({
+        deviceType: item.type,
+        deviceName: item.typeName || item.datalist[0]?.typeName || '',
+        datalist: item.datalist,
+      });
+    }
+  });
+
+  deviceList.value = deviceArr;
+
+  if (deviceList.value.length) {
+    const firstType = deviceList.value[0];
+    deviceNameOptions.value = firstType.datalist.map((i) => ({
+      label: i.strname || i.deviceName,
+      value: i.deviceID || i.deviceId,
+      deviceKind: i.deviceType || i.deviceKind || firstType.deviceType,
+    }));
+    getForm().setFieldsValue({ deviceType: firstType.deviceType });
+    await nextTick();
+    if (deviceNameOptions.value.length) {
+      getForm().setFieldsValue({
+        gdeviceids: deviceNameOptions.value[0].value,
+      });
+    }
+    strtype.value = firstType.deviceType;
+    historyType.value = firstType.deviceType;
+    await nextTick();
+    const columnKey = `${firstType.deviceType.split('_')[0]}_history`;
+    columns.value = getTableHeaderColumns(columnKey);
+    if (columns.value && columns.value.length) {
+      setColumns(columns.value);
+      reload();
+    }
+  }
 }
+function loadAlarmColumns() {
+  const cols = getTableHeaderColumns('alarm_history');
+  alarmColumns.value = cols;
+  setAlarmColumns(cols);
+}
+// 预警历史表格
+const { tableContext: AlarmTableContext } = useListPage({
+  tableProps: {
+    api: fetchAlarmHistory,
+    columns: alarmColumns,
+    showIndexColumn: true,
+    showActionColumn: false,
+    bordered: true,
+    size: 'small',
+    formConfig: {
+      labelWidth: 80,
+      schemas: getSchemas(),
+      showAdvancedButton: false,
+      autoAdvancedCol: 99,
+      alwaysShowLines: 99,
+    },
+    pagination: { pageSize: 20 },
+  },
+});
+const [registerAlarmTable, { setColumns: setAlarmColumns, reload: reloadAlarm }] = AlarmTableContext;
+
+watch(historyType, async (type) => {
+  if (!type) return;
+  await nextTick();
+  columns.value = getTableHeaderColumns(`${type.split('_')[0]}_history`);
+  setColumns(columns.value);
+  reload();
+});
 
-//初始化
-onMounted(() => {
-  getDeviceList();
+onMounted(async () => {
+  await getDeviceList();
 });
 </script>
 
@@ -213,7 +397,6 @@ onMounted(() => {
   color: #fff;
   background: url('/@/assets/images/beltFire/baseMap.png') no-repeat center;
   background-size: cover;
-
   .border {
     width: 100%;
     height: 94%;
@@ -223,23 +406,5 @@ onMounted(() => {
     box-sizing: border-box;
     margin-top: 50px;
   }
-
-  .tab-box {
-    display: flex;
-    gap: 4px;
-    margin-bottom: 16px;
-
-    .tab-item {
-      padding: 8px 20px;
-      cursor: pointer;
-      border-radius: 6px;
-
-      &.active {
-        background: #1890ff;
-        color: #fff;
-        font-weight: bold;
-      }
-    }
-  }
 }
 </style>

+ 15 - 19
src/views/vent/monitorManager/comment/HistoryTable.vue

@@ -136,7 +136,10 @@ const getExportXlsUrl = () => {
   }
 };
 const emit = defineEmits(['change']);
-const hasMultipleChoice = hasPermission('windrect:hasMultipleChoice');
+const hasWindRectPermission = hasPermission('windrect:hasMultipleChoice');
+const hasMultipleChoice = computed(() => {
+  return hasWindRectPermission && props.deviceType === 'windrect';
+});
 const historyType = ref('');
 const deviceKide = ref('');
 const columns = ref([]);
@@ -319,7 +322,7 @@ async function getDeviceList() {
         readData: item['readData'],
       };
     });
-    if (hasMultipleChoice) {
+    if (hasMultipleChoice.value) {
       deviceOptions.value.unshift({
         label: '全部',
         value: 'ALL',
@@ -367,12 +370,8 @@ function resetFormParam() {
   formData['pageNo'] = pagination['current'];
   formData['pageSize'] = pagination['pageSize'];
   formData['column'] = 'createTime';
-
-  // ===================== 核心:最终完美处理 =====================
   let gdeviceids = formData['gdeviceids'];
   let realDeviceIds = [];
-
-  // 1. 统一转成数组
   if (gdeviceids) {
     if (Array.isArray(gdeviceids)) {
       realDeviceIds = gdeviceids;
@@ -382,22 +381,17 @@ function resetFormParam() {
         .map((i) => i.trim());
     }
   }
-
-  // 2. 过滤 ALL、空值
   realDeviceIds = realDeviceIds.filter((id) => id && id !== 'ALL' && id !== '');
-
-  // 3. 转成逗号分隔字符串(后端要的格式)
   const deviceIdStr = realDeviceIds.join(',');
-
-  // ===================== 你的业务 =====================
   if (stationType.value !== 'redis' && deviceOptions.value[0]) {
-    formData['strtype'] = '*';
-
+    formData['strtype'] = deviceTypeStr.value
+      ? deviceTypeStr.value
+      : deviceOptions.value[0]['strtype']
+      ? deviceOptions.value[0]['strtype']
+      : props.deviceType + '*';
     if (props.sysId) {
       formData['sysId'] = props.sysId;
     }
-
-    // 字符串格式给后端
     formData['gdeviceids'] = deviceIdStr;
     return formData;
   } else {
@@ -407,8 +401,8 @@ function resetFormParam() {
       column: pagination['createTime'],
       startTime: formData['ttime_begin'],
       endTime: formData['ttime_end'],
-      deviceId: deviceIdStr, // 字符串!
-      strtype: '*',
+      deviceId: deviceIdStr,
+      strtype: props.deviceType + '*',
       sysId: props.sysId,
       interval: intervalMap.get(formData['skip']) || '1h',
       isEmployee: props.deviceType.startsWith('vehicle') ? false : true,
@@ -504,13 +498,15 @@ const { tableContext, onExportXls, onExportXlsPost } = useListPage({
                 component: 'Select',
                 required: true,
                 componentProps: computed(() => {
-                  const isMultiple = hasMultipleChoice;
+                  const isMultiple = hasMultipleChoice.value;
                   const ALL_VALUE = 'ALL';
 
                   return {
                     showSearch: true,
                     mode: isMultiple ? 'multiple' : undefined,
                     multiple: isMultiple,
+                    maxTagCount: 1,
+                    maxTagPlaceholder: (omittedValues) => `+ ${omittedValues.length} 项已选择`,
                     optionType: isMultiple ? 'checkbox' : undefined,
                     filterOption: (input: string, option: any) => {
                       return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;