Эх сурвалжийг харах

feat(views): 优化“设备列表”,“设备详情”UI与基本功能

wangshun 2 сар өмнө
parent
commit
c63a6069f9

+ 307 - 73
src/views/device-list/DeviceList.vue

@@ -1,6 +1,9 @@
 <script setup lang="ts">
-import { onMounted, ref } from 'vue';
+import { onMounted, ref, useTemplateRef } from 'vue';
+import { useRouter } from 'vue-router';
+import { message } from 'ant-design-vue';
 
+import ConfirmModal from '@/components/ConfirmModal.vue';
 import { useRequest } from '@/hooks/request';
 import { deviceDeletion, getPageList, groupList, queryDevicesList } from '@/api';
 
@@ -12,49 +15,53 @@ const devicesColumns = [
     title: '设备名称',
     dataIndex: 'deviceName',
     key: 'deviceName',
+    ellipsis: true,
   },
   {
     title: '设备组',
     dataIndex: 'groupName',
     key: 'groupName',
+    ellipsis: true,
   },
   {
     title: '设备类别',
     dataIndex: 'deviceTypeName',
     key: 'deviceTypeName',
+    ellipsis: true,
   },
   {
     title: '运行状态',
-    dataIndex: 'operatingStatus',
-    key: 'operatingStatus',
+    dataIndex: 'runningStatus',
+    key: 'runningStatus',
+    ellipsis: true,
   },
   {
     title: '故障状态',
-    dataIndex: 'faultState',
-    key: 'faultState',
-  },
-  {
-    title: '智控状态',
-    dataIndex: 'intelligentStatus',
-    key: 'intelligentStatus',
+    dataIndex: 'errorStatus',
+    key: 'errorStatus',
+    ellipsis: true,
   },
   {
     title: '品牌',
     dataIndex: 'brandName',
     key: 'brandName',
+    ellipsis: true,
   },
   {
     title: '型号',
     dataIndex: 'modelName',
     key: 'modelName',
+    ellipsis: true,
   },
   {
     title: '网关序列号',
     dataIndex: 'snCode',
     key: 'snCode',
+    ellipsis: true,
   },
 ];
 
+const router = useRouter();
 const devicesList = ref<DevicesListItem[]>([]);
 
 const devicesKeys = ref<Key[]>([]);
@@ -71,21 +78,34 @@ const devicePageParam = ref<DevicesList>({
   modelName: undefined,
   gatewaySnCode: undefined,
   deviceName: undefined,
+  runningStatus: undefined,
+  errorStatus: undefined,
 });
 
 const groupIdKeys = ref<number[]>([]);
 
-let deviceGroup: DeviceGroupItem[] = [];
-let equipmentType: EquipmentTypeItem[] = [];
+const deviceGroup = ref<DeviceGroupItem[]>([]);
+const equipmentType = ref<EquipmentTypeItem[]>([]);
+
+const modalComponentRef = useTemplateRef('modalComponent');
 
 const { handleRequest } = useRequest();
-const postDeviceDeletion = () => {
+
+const confirm = () => {
   handleRequest(async () => {
     await deviceDeletion(devicesKeys.value as number[]);
+    modalComponentRef.value?.hideView();
     addQueryDevicesList();
   });
 };
 
+const postDeviceDeletion = () => {
+  if (devicesKeys.value.length === 0) {
+    return message.warning('请选择删除项');
+  }
+  modalComponentRef.value?.showView();
+};
+
 const addQueryDevicesList = () => {
   devicePageParam.value.pageIndex = 1;
   postQueryDevicesList();
@@ -115,11 +135,36 @@ const devicesChange = (selectedRowKeys: Key[], selectedRows: DevicesListItem[])
 const switchPages = () => {
   postQueryDevicesList();
 };
+
+const addQueryReset = () => {
+  devicePageParam.value = {
+    pageIndex: 1,
+    pageSize: 10,
+    groupId: undefined,
+    deviceType: undefined,
+    searchContent: undefined,
+    brandName: undefined,
+    modelName: undefined,
+    gatewaySnCode: undefined,
+    deviceName: undefined,
+    runningStatus: undefined,
+    errorStatus: undefined,
+  };
+  groupIdKeys.value = [];
+  devicesKeys.value = [];
+
+  addQueryDevicesList();
+};
+
+const addEquipmentDetails = (id: number) => {
+  router.push(`${'/device-manage/equipment-details/'}${id}`);
+};
+
 onMounted(() => {
   handleRequest(async () => {
-    deviceGroup = await getPageList();
+    deviceGroup.value = await getPageList();
 
-    equipmentType = await groupList({
+    equipmentType.value = await groupList({
       dataType: 1,
     });
     addQueryDevicesList();
@@ -129,75 +174,264 @@ onMounted(() => {
 
 <template>
   <div>
-    <div>设备列表</div>
-    <br />
-    <br />
-    <AButton type="primary" @click="addQueryDevicesList">查询</AButton>
-    <AButton type="primary" @click="postDeviceDeletion">删除设备</AButton>
-    <br />
-    <br />
-
-    <ATable
-      :row-selection="{
-        type: 'checkbox',
-        selectedRowKeys: devicesKeys,
-        onChange: devicesChange,
-      }"
-      row-key="id"
-      :columns="devicesColumns"
-      :data-source="devicesList"
-      :pagination="false"
-    >
-      <template #headerCell="{ column }">
-        <template v-if="column.key === 'deviceName'">
-          <div>{{ column.title }}</div>
-          <AInput style="width: 100px" v-model:value="devicePageParam.deviceName" />
-        </template>
-        <template v-else-if="column.key === 'groupName'">
-          <div>{{ column.title }}</div>
+    <AFlex justify="space-between">
+      <div class="text-top">设备管理</div>
+      <div>
+        <AButton class="deletion-button default-button" @click="postDeviceDeletion">
+          <AFlex align="center">
+            <SvgIcon style="margin-right: 4px" name="delete" />
+
+            <span> 删除 </span>
+          </AFlex>
+        </AButton>
+        <AButton type="primary">
+          <AFlex align="center">
+            <SvgIcon style="margin-right: 4px" name="plus" />
+            <span> 添加 </span>
+          </AFlex>
+        </AButton>
+      </div>
+    </AFlex>
+
+    <div class="content">
+      <AFlex wrap="wrap" justify="space-between">
+        <div>
+          <div class="query-text">搜索</div>
+          <AInput
+            placeholder="请输入设备名称、品牌、型号、网关序列号"
+            class="query-input"
+            v-model:value="devicePageParam.searchContent"
+          />
+        </div>
+        <div>
+          <div class="query-text">设备组</div>
           <ACascader
             v-model:value="groupIdKeys"
+            class="query-input"
             :field-names="{ label: 'groupName', value: 'id', children: 'deviceGroupChilds' }"
             :options="deviceGroup"
             change-on-select
+            placeholder="请选择"
           />
-        </template>
-        <template v-else-if="column.key === 'deviceType'">
-          <div>{{ column.title }}</div>
+        </div>
+        <div>
+          <div class="query-text">设备类别</div>
+
           <ASelect
-            style="width: 120px"
+            class="query-input"
             v-model:value="devicePageParam.deviceType"
             :options="equipmentType"
             :field-names="{ label: 'dataName', value: 'id' }"
+            placeholder="请选择"
           />
+        </div>
+        <div>
+          <div class="query-text">运行状态</div>
+          <ASelect
+            class="query-input"
+            v-model:value="devicePageParam.runningStatus"
+            placeholder="请选择"
+            :allow-clear="true"
+          >
+            <ASelectOption :value="0">离线</ASelectOption>
+            <ASelectOption :value="1">停机</ASelectOption>
+            <ASelectOption :value="2">运行</ASelectOption>
+          </ASelect>
+        </div>
+        <div>
+          <div class="query-text">故障状态</div>
+          <ASelect
+            class="query-input"
+            v-model:value="devicePageParam.errorStatus"
+            placeholder="请选择"
+            :allow-clear="true"
+          >
+            <ASelectOption :value="0">正常</ASelectOption>
+            <ASelectOption :value="1">故障</ASelectOption>
+          </ASelect>
+        </div>
+        <!-- <div>
+          <div class="query-text">智控状态</div>
+          <ASelect
+            class="query-input"
+            v-model:value="devicePageParam.deviceType"
+            :options="equipmentType"
+            :field-names="{ label: 'dataName', value: 'id' }"
+            placeholder="请选择"
+          />
+        </div> -->
+      </AFlex>
+      <AFlex justify="flex-end">
+        <AButton type="primary" class="query-button" @click="addQueryDevicesList">查询</AButton>
+        <AButton class="default-button" @click="addQueryReset">重置</AButton>
+      </AFlex>
+      <ATable
+        :row-selection="{
+          type: 'checkbox',
+          selectedRowKeys: devicesKeys,
+          onChange: devicesChange,
+        }"
+        row-key="id"
+        :columns="devicesColumns"
+        :data-source="devicesList"
+        :pagination="false"
+      >
+        <template #bodyCell="{ column, record }">
+          <template v-if="column.key === 'deviceName'">
+            <span class="equipment-name" @click="addEquipmentDetails(record.id)">{{ record.deviceName }}</span>
+          </template>
+          <template v-if="column.key === 'runningStatus'">
+            <div v-if="record.runningStatus == 2" class="tag-style success">运行</div>
+            <div v-else-if="record.runningStatus == 1" class="tag-style failure">停机</div>
+            <div v-else class="tag-style default">停机</div>
+          </template>
+          <template v-if="column.key === 'errorStatus'">
+            <div v-if="record.errorStatus == 0" class="tag-style success">正常</div>
+            <div v-else class="tag-style failure" style="width: 64px">设备故障</div>
+          </template>
+
+          <template v-if="column.key === 'snCode'">
+            {{ record.gatewayInfos ? record.gatewayInfos[0].snCode : '' }}
+          </template>
         </template>
-        <template v-if="column.key === 'brandName'">
-          <div>{{ column.title }}</div>
-          <AInput style="width: 100px" v-model:value="devicePageParam.brandName" />
-        </template>
-        <template v-if="column.key === 'modelName'">
-          <div>{{ column.title }}</div>
-          <AInput style="width: 100px" v-model:value="devicePageParam.modelName" />
-        </template>
-        <template v-if="column.key === 'snCode'">
-          <div>{{ column.title }}</div>
-          <AInput style="width: 100px" v-model:value="devicePageParam.gatewaySnCode" />
-        </template>
-      </template>
-      <template #bodyCell="{ column, record }">
-        <template v-if="column.key === 'snCode'">
-          {{ record.gatewayInfos ? record.gatewayInfos[0].snCode : '' }}
-        </template>
-      </template>
-    </ATable>
-    <br />
-    <br />
-    <APagination
-      v-model:current="devicePageParam.pageIndex"
-      v-model:page-size="devicePageParam.pageSize"
-      :total="devicesTotal"
-      :show-size-changer="true"
-      @change="switchPages"
-    />
+      </ATable>
+      <br />
+      <br />
+      <AFlex justify="flex-end" class="footer">
+        <APagination
+          v-model:current="devicePageParam.pageIndex"
+          v-model:page-size="devicePageParam.pageSize"
+          :total="devicesTotal"
+          :show-size-changer="true"
+          @change="switchPages"
+          show-quick-jumper
+          :show-total="(total) => `共有${total}条`"
+        />
+      </AFlex>
+    </div>
   </div>
+  <ConfirmModal
+    ref="modalComponent"
+    :title="'删除确定'"
+    :description-text="'是否确认删除?'"
+    :icon="{ name: 'delete' }"
+    :icon-bg-color="'#F56C6C'"
+    @confirm="confirm"
+  />
 </template>
+
+<style lang="scss" scoped>
+.text-top {
+  font-size: 20px;
+  font-style: normal;
+  font-weight: 500;
+  line-height: 28px;
+  color: rgb(0 0 0 / 85%);
+  text-align: left;
+}
+
+.deletion-button {
+  width: 84px;
+  height: 32px;
+  margin-right: 16px;
+}
+
+.content {
+  padding: 24px;
+  margin-top: 24px;
+  background: #fff;
+  border-radius: 16px;
+}
+
+.query-text {
+  display: inline-block;
+  width: 56px;
+  margin-right: 12px;
+  font-size: 14px;
+  font-style: normal;
+  font-weight: 400;
+  line-height: 22px;
+  color: rgb(0 0 0 / 85%);
+  text-align: right;
+}
+
+.equipment-name {
+  font-size: 14px;
+  font-style: normal;
+  font-weight: 400;
+  line-height: 24px;
+  color: #32bac0;
+  text-align: left;
+  cursor: pointer;
+}
+
+.query-input {
+  width: 256px;
+  margin-bottom: 16px;
+}
+
+.query-button {
+  margin-right: 12px;
+  margin-bottom: 16px;
+}
+
+.tag-style {
+  display: flex;
+  align-items: center; /* 垂直居中 */
+  justify-content: center; /* 水平居中 */
+  height: 24px;
+  font-size: 12px;
+  border-radius: 4px;
+}
+
+.success {
+  width: 40px;
+  color: #52c41a;
+  background: #f6ffed;
+  border: 1px solid #b7eb8f;
+}
+
+.failure {
+  width: 40px;
+  color: #f5222d;
+  background: #fff1f0;
+  border: 1px solid #ffa39e;
+}
+
+.default {
+  width: 40px;
+  color: #666;
+  background: #f8f8f8;
+  border: 1px solid #e5e5e5;
+}
+
+:deep(.footer) {
+  .ant-pagination-item {
+    background-color: #fff;
+    border-color: #d6d6d6;
+  }
+
+  .ant-pagination-item a {
+    color: #666;
+  }
+
+  .ant-pagination .ant-pagination-item-active {
+    background-color: var(--antd-color-primary-hover);
+  }
+
+  .ant-pagination .ant-pagination-item-active a {
+    color: #fff;
+  }
+
+  .ant-pagination-item-link {
+    color: #666;
+    border: 1px solid #d6d6d6;
+  }
+
+  .ant-pagination-total-text {
+    font-size: 14px;
+    font-weight: 400;
+    color: #666;
+  }
+}
+</style>

+ 797 - 0
src/views/equipment-details/EquipmentDetails.vue

@@ -0,0 +1,797 @@
+<script setup lang="ts">
+import { onMounted, ref, watch } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+
+import { useRequest } from '@/hooks/request';
+import { t } from '@/i18n';
+import { equipmentDetails, noPaginationDevicesList, postParameterVerification } from '@/api';
+
+import type {
+  AllDevicesList,
+  AssociatedGatewayParameters,
+  ConfigureDeviceParameters,
+  CustomParametersItem,
+  ParameterVerification,
+} from '@/types';
+
+interface EquipmentDetailsItem {
+  deviceName: string;
+  runningStatus: number;
+  errorStatus: number;
+  groupName: string;
+  deviceTypeName: string;
+  brandName: string;
+  modelName: string;
+  modelTypeName: string;
+  controlTypeName: string;
+  compressionLevelName: string;
+  voltageLevelName: string;
+  powerRating?: number;
+  powerUnload?: number;
+  maximumFlow?: number;
+  pressure?: number;
+  pressureMax?: number;
+  productionDate: string;
+  department: string;
+  respPerson: string;
+  phone: string;
+  serviceLife?: number;
+  remarks: string;
+}
+
+const columns = [
+  {
+    title: t('createDevice.gatewaySerialNumber'),
+    dataIndex: 'snCode',
+    key: 'snCode',
+    ellipsis: true,
+  },
+  {
+    title: t('createDevice.gatewayModel'),
+    dataIndex: 'modelName',
+    key: 'modelName',
+    ellipsis: true,
+  },
+  {
+    title: t('createDevice.physicalInterface'),
+    dataIndex: 'linkName',
+    key: 'linkName',
+    ellipsis: true,
+  },
+
+  {
+    title: t('createDevice.parameters'),
+    key: 'tags',
+    ellipsis: true,
+  },
+];
+
+const devColumns = [
+  {
+    title: t('createDevice.equipmentParameterCoding'),
+    dataIndex: 'deviceParamCode',
+    key: 'deviceParamCode',
+    ellipsis: true,
+  },
+  {
+    title: t('createDevice.equipmentParameterName'),
+    dataIndex: 'deviceParamName',
+    key: 'deviceParamName',
+    ellipsis: true,
+  },
+  {
+    title: t('createDevice.gatewayParameterEncoding'),
+    dataIndex: 'gatewayParamCode',
+    ellipsis: true,
+  },
+  {
+    title: '网关参数名称',
+    dataIndex: 'gatewayParamName',
+    ellipsis: true,
+  },
+  {
+    title: t('setupProtocol.protocolParamFields.unit'),
+    dataIndex: 'unit',
+    ellipsis: true,
+  },
+  {
+    title: t('createDevice.groupName'),
+    dataIndex: 'groupName',
+    key: 'groupName',
+    ellipsis: true,
+  },
+  {
+    title: t('createDevice.whetherProcessData'),
+    dataIndex: 'isProcessData',
+    key: 'isProcessData',
+    ellipsis: true,
+  },
+];
+
+const customizationColumns = [
+  {
+    title: t('createDevice.equipmentSequenceNumber'),
+    dataIndex: 'index',
+    key: 'index',
+    ellipsis: true,
+  },
+  {
+    title: t('createDevice.equipmentParameterCoding'),
+    dataIndex: 'deviceParamCode',
+    key: 'deviceParamCode',
+    ellipsis: true,
+  },
+  {
+    title: t('createDevice.equipmentParameterName'),
+    dataIndex: 'deviceParamName',
+    key: 'deviceParamName',
+    ellipsis: true,
+  },
+  {
+    title: t('createDevice.customFormula'),
+    dataIndex: 'customFormula',
+    key: 'customFormula',
+    ellipsis: true,
+  },
+  {
+    title: '单位',
+    dataIndex: 'unit',
+    key: 'unit',
+    ellipsis: true,
+  },
+  {
+    title: t('createDevice.keepDecimalPlaces'),
+    dataIndex: 'decimalDigits',
+    key: 'decimalDigits',
+    ellipsis: true,
+  },
+  {
+    title: t('createDevice.groupName'),
+    dataIndex: 'groupName',
+    key: 'groupName',
+    ellipsis: true,
+  },
+  {
+    title: t('createDevice.whetherProcessData'),
+    dataIndex: 'isProcessData',
+    key: 'isProcessData',
+    ellipsis: true,
+  },
+];
+
+const route = useRoute();
+const { handleRequest } = useRequest();
+const router = useRouter();
+const devicesList = ref<AllDevicesList[]>([]);
+const parameterVerificationList = ref<ParameterVerification[]>([]);
+const showTabs = ref<boolean>(false);
+const gatewayList = ref<AssociatedGatewayParameters[]>([]);
+const gatewayData = ref<ConfigureDeviceParameters[]>([]);
+const gatewayRemoteData = ref<ConfigureDeviceParameters[]>([]);
+const customizationData = ref<CustomParametersItem[]>([]);
+const agreementListKey = ref<string>('monitoring');
+
+let deviceId: number;
+
+const equipmentDetailsItem = ref<EquipmentDetailsItem>({
+  deviceName: '',
+  runningStatus: 0,
+  errorStatus: 0,
+  groupName: '',
+  deviceTypeName: '',
+  brandName: '',
+  modelName: '',
+  modelTypeName: '',
+  controlTypeName: '',
+  compressionLevelName: '',
+  voltageLevelName: '',
+  powerRating: undefined,
+  powerUnload: undefined,
+  maximumFlow: undefined,
+  pressure: undefined,
+  pressureMax: undefined,
+  productionDate: '',
+  department: '',
+  respPerson: '',
+  phone: '',
+  serviceLife: undefined,
+  remarks: '',
+});
+
+const colorShow = (value: number | string) => {
+  if (value) {
+    return 'color:#666666';
+  } else {
+    return 'color:#F56C6C';
+  }
+};
+
+const selectDeviceId = () => {
+  router.push(`/device-manage/equipment-details/${deviceId}`);
+};
+
+const switchDevices = (value: number) => {
+  router.push(`/device-manage/equipment-details/${getPreviousIdById(devicesList.value, deviceId, value)}`);
+};
+
+const getPreviousIdById = (array: AllDevicesList[], targetId: number, value: number) => {
+  for (let i = 0; i < array.length; i++) {
+    if (array[i].id === targetId) {
+      return array[obtainSubscript(i, array.length, value)].id;
+    }
+  }
+  return null;
+};
+
+const obtainSubscript = (i: number, length: number, value: number) => {
+  if (value === 1) {
+    if (i === 0) {
+      return length - 1;
+    }
+    return i - 1;
+  } else {
+    if (i + 1 === length) {
+      return 0;
+    }
+    return i + 1;
+  }
+};
+
+const addSwitchTabs = () => {
+  showTabs.value = !showTabs.value;
+};
+
+const switchTabs = (value: number) => {
+  if (value === 1) {
+    return !showTabs.value ? 'select-but details-but' : 'details-but';
+  } else {
+    return showTabs.value ? 'select-but details-but' : 'details-but';
+  }
+};
+
+const obtainDeviceDetails = () => {
+  if (route.params.id) {
+    deviceId = Number(route.params.id);
+  }
+
+  handleRequest(async () => {
+    gatewayData.value = [];
+    gatewayRemoteData.value = [];
+    const { deviceQueryVo, gatewayInfoVos, protocolParamDeviceInfoVos, protocolParamCustomDevVos } =
+      await equipmentDetails(deviceId);
+    const {
+      deviceName,
+      runningStatus,
+      errorStatus,
+      groupName,
+      deviceTypeName,
+      brandName,
+      modelName,
+      modelTypeName,
+      controlTypeName,
+      compressionLevelName,
+      voltageLevelName,
+      powerRating,
+      powerUnload,
+      maximumFlow,
+      pressure,
+      pressureMax,
+      productionDate,
+      department,
+      respPerson,
+      phone,
+      serviceLife,
+      remarks,
+    } = deviceQueryVo;
+    equipmentDetailsItem.value = {
+      deviceName,
+      runningStatus,
+      errorStatus,
+      groupName,
+      deviceTypeName,
+      brandName,
+      modelName,
+      modelTypeName,
+      controlTypeName,
+      compressionLevelName,
+      voltageLevelName,
+      powerRating,
+      powerUnload,
+      maximumFlow,
+      pressure,
+      pressureMax,
+      productionDate,
+      department,
+      respPerson,
+      phone,
+      serviceLife,
+      remarks,
+    };
+    if (gatewayInfoVos.length) {
+      gatewayList.value = gatewayInfoVos;
+    } else {
+      gatewayList.value = [];
+    }
+    if (protocolParamDeviceInfoVos.length) {
+      protocolParamDeviceInfoVos.forEach((item) => {
+        if (item.readWriteTypeCode === 'read_only') {
+          gatewayData.value.push(item);
+        } else if (item.readWriteTypeCode === 'read_write') {
+          gatewayRemoteData.value.push(item);
+        }
+      });
+    } else {
+      gatewayData.value = [];
+    }
+    if (protocolParamCustomDevVos.length) {
+      customizationData.value = protocolParamCustomDevVos;
+    } else {
+      customizationData.value = [];
+    }
+
+    parameterVerificationList.value = await postParameterVerification(deviceId);
+    devicesList.value = await noPaginationDevicesList();
+  });
+};
+
+watch(
+  () => route.params.id,
+  () => {
+    obtainDeviceDetails();
+  },
+);
+
+onMounted(() => {
+  obtainDeviceDetails();
+});
+</script>
+
+<template>
+  <div>
+    <AFlex justify="space-between">
+      <AFlex align="center">
+        <div class="return" @click="$router.push('/device-manage/device-list')">
+          <SvgIcon name="left" />
+        </div>
+
+        <div class="description">设备详情</div>
+      </AFlex>
+      <div>
+        <ASelect
+          class="devices-select"
+          v-model:value="deviceId"
+          :options="devicesList"
+          :field-names="{ label: 'deviceName', value: 'id' }"
+          placeholder="请选择"
+          @change="selectDeviceId"
+        />
+        <AButton class="default-button previous" @click="switchDevices(1)">上一个</AButton>
+        <AButton class="default-button" @click="switchDevices(2)">下一个</AButton>
+      </div>
+    </AFlex>
+    <AFlex class="equipment-details">
+      <div class="equipment-details-img">
+        <img src="@/assets/img/equipment-details-img.png" alt="" />
+      </div>
+      <div>
+        <span class="equipment-name">{{ equipmentDetailsItem.deviceName }}</span>
+        <div>
+          <AFlex align="center">
+            <div class="equipment-status">运行状态</div>
+            <div v-if="equipmentDetailsItem.runningStatus == 2" class="tag-style success">运行</div>
+            <div v-else-if="equipmentDetailsItem.runningStatus == 1" class="tag-style failure">停机</div>
+            <div v-else class="tag-style default">停机</div>
+            <div class="equipment-status equipment-status-left">故障状态</div>
+            <div v-if="equipmentDetailsItem.errorStatus == 0" class="tag-style success">正常</div>
+            <div v-else class="tag-style failure failure-width">设备故障</div>
+          </AFlex>
+        </div>
+      </div>
+    </AFlex>
+
+    <AFlex justify="space-between" align="center">
+      <AFlex>
+        <div :class="switchTabs(1)" @click="addSwitchTabs">实时监控</div>
+        <div :class="switchTabs(2)" @click="addSwitchTabs">基本信息</div>
+      </AFlex>
+      <AFlex v-if="showTabs" align="center" class="pointer">
+        <SvgIcon name="edit-o" />
+        <div class="editor-style">编辑</div>
+      </AFlex>
+    </AFlex>
+
+    <div class="details-data" v-if="!showTabs">
+      <div v-for="item in parameterVerificationList" :key="item.id">
+        <AFlex align="center" class="dev-bottom">
+          <div class="details-icon"></div>
+          <div class="details-header-text">{{ item.deviceParamGroupName }}</div>
+        </AFlex>
+        <AFlex wrap="wrap">
+          <div v-for="ite in item.valueVos" :key="ite.valueId" class="div-bottom details-text">
+            <span :style="colorShow(ite.value)">{{ ite.paramName }}:</span>
+            <span class="details-content-color">
+              <span>{{ ite.value }}{{ ite.value ? ite.unit : '' }}</span>
+            </span>
+          </div>
+        </AFlex>
+      </div>
+    </div>
+
+    <div v-else class="details-data">
+      <AFlex align="center" class="dev-bottom">
+        <div class="details-icon"></div>
+        <div class="details-header-text">基础信息</div>
+      </AFlex>
+      <AFlex>
+        <ARow class="details-text basic-information">
+          <ACol :span="6">
+            <span
+              >设备组: <span class="details-content-color">{{ equipmentDetailsItem.groupName }}</span></span
+            >
+          </ACol>
+          <ACol :span="6">
+            <span
+              >设备类型: <span class="details-content-color">{{ equipmentDetailsItem.deviceTypeName }}</span>
+            </span>
+          </ACol>
+          <ACol :span="6">
+            <span
+              >设备名:<span class="details-content-color">{{ equipmentDetailsItem.deviceName }}</span>
+            </span>
+          </ACol>
+        </ARow>
+      </AFlex>
+
+      <AFlex align="center" class="dev-bottom">
+        <div class="details-icon"></div>
+        <div class="details-header-text">详细信息</div>
+      </AFlex>
+      <ARow class="details-text detailed-information">
+        <ACol :span="6">
+          <span
+            >品牌: <span class="details-content-color">{{ equipmentDetailsItem.brandName }}</span></span
+          >
+        </ACol>
+        <ACol :span="6">
+          <span
+            >型号: <span class="details-content-color">{{ equipmentDetailsItem.modelName }}</span>
+          </span>
+        </ACol>
+        <ACol :span="6">
+          <span
+            >控制器型号:<span class="details-content-color">{{ equipmentDetailsItem.modelTypeName }}</span>
+          </span>
+        </ACol>
+        <ACol :span="6">
+          <span
+            >调节方式:<span class="details-content-color">{{ equipmentDetailsItem.controlTypeName }}</span>
+          </span>
+        </ACol>
+      </ARow>
+      <ARow class="detailed-information details-text">
+        <ACol :span="6">
+          <span
+            >压缩级别: <span class="details-content-color">{{ equipmentDetailsItem.compressionLevelName }}</span></span
+          >
+        </ACol>
+        <ACol :span="6">
+          <span
+            >电压等级: <span class="details-content-color">{{ equipmentDetailsItem.voltageLevelName }}</span>
+          </span>
+        </ACol>
+        <ACol :span="6">
+          <span
+            >额定功率:<span class="details-content-color">{{ equipmentDetailsItem.powerRating }}</span>
+          </span>
+        </ACol>
+        <ACol :span="6">
+          <span
+            >卸载功率:<span class="details-content-color">{{ equipmentDetailsItem.powerUnload }}</span>
+          </span>
+        </ACol>
+      </ARow>
+      <ARow class="detailed-information details-text">
+        <ACol :span="6">
+          <span
+            >公称容积流量 (m’/min):
+            <span class="details-content-color">{{ equipmentDetailsItem.maximumFlow }}</span></span
+          >
+        </ACol>
+        <ACol :span="6">
+          <span
+            >额定工作压力 (bar): <span class="details-content-color">{{ equipmentDetailsItem.pressure }}</span>
+          </span>
+        </ACol>
+        <ACol :span="6">
+          <span>
+            最大工作压力 (bar):<span class="details-content-color">{{ equipmentDetailsItem.pressureMax }}</span>
+          </span>
+        </ACol>
+        <ACol :span="6">
+          <span
+            >出厂日期:<span class="details-content-color">{{ equipmentDetailsItem.productionDate }}</span>
+          </span>
+        </ACol>
+      </ARow>
+      <ARow class="detailed-information details-text">
+        <ACol :span="6">
+          <span
+            >使用部门: <span class="details-content-color">{{ equipmentDetailsItem.department }}</span></span
+          >
+        </ACol>
+        <ACol :span="6">
+          <span
+            >负责人: <span class="details-content-color">{{ equipmentDetailsItem.respPerson }}</span>
+          </span>
+        </ACol>
+        <ACol :span="6">
+          <span>
+            联系电话:<span class="details-content-color">{{ equipmentDetailsItem.phone }}</span>
+          </span>
+        </ACol>
+        <ACol :span="6">
+          <span>
+            使用年限 (年):<span class="details-content-color">{{ equipmentDetailsItem.serviceLife }}</span>
+          </span>
+        </ACol>
+      </ARow>
+      <ARow class="detailed-information details-text">
+        <ACol :span="6">
+          <span
+            >备注: <span class="details-content-color">{{ equipmentDetailsItem.remarks }}</span></span
+          >
+        </ACol>
+      </ARow>
+
+      <AFlex align="center" class="dev-margin">
+        <div class="details-icon"></div>
+        <div class="details-header-text">关联网关参数</div>
+      </AFlex>
+      <ATable :columns="columns" :data-source="gatewayList" :pagination="false" />
+
+      <AFlex align="center" class="dev-margin">
+        <div class="details-icon"></div>
+        <div class="details-header-text">配置设备参数</div>
+      </AFlex>
+      <ATabs v-model:active-key="agreementListKey">
+        <ATabPane key="monitoring" tab="数据监控">
+          <ATable :columns="devColumns" :data-source="gatewayData" :pagination="false">
+            <template #bodyCell="{ column, record }">
+              <template v-if="column.key === 'isProcessData'">
+                {{ record.isProcessData ? '是' : '否' }}
+              </template>
+            </template>
+          </ATable>
+        </ATabPane>
+        <ATabPane key="remote" tab="远程控制" force-render>
+          <ATable :columns="devColumns" :data-source="gatewayRemoteData" :pagination="false">
+            <template #bodyCell="{ column, record }">
+              <template v-if="column.key === 'isProcessData'">
+                {{ record.isProcessData ? '是' : '否' }}
+              </template>
+            </template>
+          </ATable>
+        </ATabPane>
+      </ATabs>
+
+      <AFlex align="center" class="dev-margin">
+        <div class="details-icon"></div>
+        <div class="details-header-text">自定义监控参数</div>
+      </AFlex>
+      <ATable :columns="customizationColumns" :data-source="customizationData" :pagination="false">
+        <template #bodyCell="{ column, record, index }">
+          <template v-if="column.key === 'index'">
+            {{ index + 1 }}
+          </template>
+          <template v-if="column.key === 'isProcessData'">
+            {{ record.isProcessData ? '是' : '否' }}
+          </template>
+        </template>
+      </ATable>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.pointer {
+  cursor: pointer;
+}
+
+.editor-style {
+  margin-right: 26px;
+  margin-left: 5px;
+  font-size: 14px;
+  font-style: normal;
+  font-weight: 400;
+  line-height: 24px;
+  color: #666;
+  text-align: left;
+}
+
+.dev-margin {
+  margin-top: 40px;
+  margin-bottom: 16px;
+}
+
+.dev-bottom {
+  margin-bottom: 16px;
+}
+
+.detailed-information {
+  width: 100%;
+  margin-bottom: 16px;
+}
+
+.basic-information {
+  width: 100%;
+  margin-bottom: 40px;
+}
+
+.div-bottom {
+  margin-right: 120px;
+  margin-bottom: 40px;
+}
+
+.details-text {
+  font-size: 14px;
+  font-style: normal;
+  font-weight: 400;
+  line-height: 24px;
+  color: #666;
+  text-align: left;
+}
+
+.details-content-color {
+  margin-left: 5px;
+  color: #333;
+}
+
+.return {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 40px;
+  height: 32px;
+  font-size: 14px;
+  cursor: pointer;
+  background: #fff;
+  border: 1px solid #d6d6d6;
+  border-radius: 4px;
+}
+
+.description {
+  margin-left: 16px;
+  font-size: 20px;
+  font-style: normal;
+  font-weight: 500;
+  line-height: 28px;
+  color: rgb(0 0 0 / 85%);
+  text-align: left;
+}
+
+.previous {
+  margin: 0 16px;
+}
+
+.devices-select {
+  width: 192px;
+  border-radius: 4px;
+}
+
+.equipment-details {
+  height: 160px;
+  padding: 16px;
+  margin-top: 22px;
+  margin-bottom: 16px;
+  background: #fff;
+  border-radius: 16px;
+}
+
+.equipment-details-img {
+  width: 192px;
+  height: 128px;
+  margin-right: 24px;
+  border-radius: 12px;
+}
+
+.equipment-name {
+  display: inline-block;
+  margin-top: 32px;
+  margin-bottom: 16px;
+  font-size: 16px;
+  font-style: normal;
+  font-weight: 500;
+  line-height: 24px;
+  color: #333;
+  text-align: left;
+}
+
+.tag-style {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 24px;
+  font-size: 12px;
+  border-radius: 4px;
+}
+
+.success {
+  width: 40px;
+  color: #52c41a;
+  background: #f6ffed;
+  border: 1px solid #b7eb8f;
+}
+
+.failure {
+  width: 40px;
+  color: #f5222d;
+  background: #fff1f0;
+  border: 1px solid #ffa39e;
+}
+
+.failure-width {
+  width: 64px;
+}
+
+.default {
+  width: 40px;
+  color: #666;
+  background: #f8f8f8;
+  border: 1px solid #e5e5e5;
+}
+
+.equipment-status {
+  margin-right: 12px;
+  font-size: 14px;
+  font-style: normal;
+  font-weight: 400;
+  line-height: 24px;
+  color: #000;
+  text-align: left;
+}
+
+.equipment-status-left {
+  margin-left: 40px;
+}
+
+.details-but {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 88px;
+  height: 40px;
+  margin-right: 16px;
+  color: var(--antd-color-primary-hover);
+  cursor: pointer;
+  background: rgb(50 186 192 / 15%);
+  border-radius: 8px;
+}
+
+.select-but {
+  color: #fff;
+  background: var(--antd-color-primary-hover);
+}
+
+.details-data {
+  padding: 24px;
+  margin-top: 16px;
+  background: #fff;
+  border-radius: 16px;
+}
+
+.details-icon {
+  width: 2px;
+  height: 16px;
+  margin-right: 8px;
+  background: var(--antd-color-primary-hover);
+}
+
+.details-header-text {
+  font-size: 16px;
+  font-style: normal;
+  font-weight: 500;
+  line-height: 24px;
+  color: #000;
+  text-align: left;
+}
+</style>