yanghao há 8 horas atrás
pai
commit
b5661e1b2f

+ 29 - 0
src/api/pms/qhse/index.ts

@@ -534,3 +534,32 @@ export const QhseMonthReportApi = {
     return await request.download({ url: `/rq/qhse-month-report/export-excel`, params })
   }
 }
+
+// 应检设备证书
+export const InspectDeviceCertApi = {
+  // 获得设备证书分页
+  getInspectDeviceCertList: async (params) => {
+    return await request.get({ url: `/rq/qhse-inspect-device-cert/page`, params })
+  },
+  // 删除设备证书
+  deleteInspectDeviceCert: async (id) => {
+    return await request.delete({ url: `/rq/qhse-inspect-device-cert/delete?id=` +})
+  },
+  // 添加设备证书
+  createInspectDeviceCert: async (data) => {
+    return await request.post({ url: `/rq/qhse-inspect-device-cert/create`, data })
+  },
+  // 获取详情
+  getInspectDeviceCert: async (id) => {
+    return await request.get({ url: `/rq/qhse-inspect-device-cert/get?id=` + id })
+  },
+  // 修改设备证书
+  updateInspectDeviceCert: async (data) => {
+    return await request.put({ url: `/rq/qhse-inspect-device-cert/update`, data })
+  },
+  // 导出设备证书 Excel
+  exportInspectDeviceCert: async (params) => {
+    return await request.download({ url: `/rq/qhse-inspect-device-cert/export-excel`, params })
+  }
+
+}

+ 1 - 0
src/layout/components/Menu/src/components/useRenderMenuItem.tsx

@@ -149,6 +149,7 @@ export const useRenderMenuItem = () =>
                 '职业健康体检',
                 '健康培训',
                 '突发事件处置',
+                'QHSE月报管理',
                 'QHSE资料库',
                 'QHSE资质证书',
                 'QHSE体系文件',

+ 280 - 666
src/views/pms/device/DeviceInfo.vue

@@ -1,267 +1,257 @@
 <template>
-  <div class="device-info-page">
-    <ContentWrap class="device-shell device-shell--hero">
-      <div class="device-hero" v-loading="formLoading">
-        <div class="device-media-card">
-          <div class="device-media-glow"></div>
-          <el-image
-            :src="defaultPicUrl"
-            class="device-image"
-            @click="imagePreview(defaultPicUrl)"
-            fit="contain" />
-          <!-- <div class="device-image-caption">
-            <span class="device-image-tag">ASSET PREVIEW</span>
-            <span class="device-image-hint">点击查看原图</span>
-          </div> -->
-        </div>
-
-        <div class="device-hero-content">
-          <div class="device-hero-heading">
-            <div>
-              <div class="device-kicker">DEVICE PROFILE</div>
-              <h1 class="device-title">{{ displayText(formData.deviceName) }}</h1>
-              <p class="device-subtitle">
-                {{ displayText(formData.assetClassName) }} · {{ displayText(formData.deptName) }}
-              </p>
-            </div>
-            <div class="device-status-cluster">
-              <div class="device-status-pill" :class="statusToneClass">
-                <span class="device-status-dot"></span>
-                {{ deviceStatusText }}
-              </div>
-              <div class="device-meta-chip">
-                {{ t('devicePerson.assets') }} ·
-                {{
-                  displayText(getDictLabel(DICT_TYPE.PMS_ASSET_PROPERTY, formData.assetProperty))
-                }}
-              </div>
-            </div>
-          </div>
-
-          <div class="device-overview-grid">
-            <div class="overview-card overview-card--primary">
-              <span class="overview-label">{{ t('iotDevice.yfCode') }}</span>
-              <span class="overview-value">{{ displayText(formData.yfDeviceCode) }}</span>
-            </div>
-            <div class="overview-card">
-              <span class="overview-label">{{ t('iotDevice.code') }}</span>
-              <span class="overview-value">{{ displayText(formData.deviceCode) }}</span>
-            </div>
-            <div class="overview-card">
-              <span class="overview-label">{{ t('iotDevice.brand') }}</span>
-              <span class="overview-value">{{ displayText(formData.brandName) }}</span>
-            </div>
-            <div class="overview-card">
-              <span class="overview-label">{{ t('deviceForm.model') }}</span>
-              <span class="overview-value">{{ displayText(formData.model) }}</span>
-            </div>
-            <div class="overview-card">
-              <span class="overview-label">{{ t('info.deviceClass') }}</span>
-              <span class="overview-value">{{ displayText(formData.assetClassName) }}</span>
-            </div>
-            <div class="overview-card">
-              <span class="overview-label">{{ t('devicePerson.rp') }}</span>
-              <span class="overview-value">{{ displayText(formData.responsibleNames) }}</span>
-            </div>
-          </div>
-        </div>
+  <ContentWrap>
+    <div style="display: flex; flex-direction: row; height: 12em; margin-top: 2px">
+      <div style="flex: 1; height: 12em; margin-left: 20px">
+        <el-image
+          :key="index"
+          :src="defaultPicUrl"
+          style="width: 35em; height: 12em"
+          @click="imagePreview(defaultPicUrl)"
+          fit="contain" />
       </div>
-    </ContentWrap>
-
-    <ContentWrap class="device-shell" v-loading="formLoading">
-      <div class="device-tabs-card">
-        <el-tabs v-model="activeName" class="device-tabs" @tab-click="handleTabClick">
-          <el-tab-pane :label="t('deviceInfo.basicInformation')" name="info">
-            <div class="info-panel">
-              <section class="info-section">
-                <div class="section-heading">
-                  <span class="section-index">01</span>
-                  <div>
-                    <h3>制造与交付</h3>
-                    <p>设备生产、供应与保修信息</p>
-                  </div>
-                </div>
-                <div class="detail-grid">
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.mfg') }}</span>
-                    <span class="detail-value">{{ displayText(formData.zzName) }}</span>
-                  </div>
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.pd') }}</span>
-                    <span class="detail-value">{{ displayDate(formData.manDate) }}</span>
-                  </div>
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.supplier') }}</span>
-                    <span class="detail-value">{{ displayText(formData.supplierName) }}</span>
-                  </div>
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.ni') }}</span>
-                    <span class="detail-value">{{ displayText(formData.nameplate) }}</span>
-                  </div>
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.warranty') }}</span>
-                    <span class="detail-value">{{ displayDate(formData.expires) }}</span>
-                  </div>
-                </div>
-              </section>
-
-              <section class="info-section">
-                <div class="section-heading">
-                  <span class="section-index">02</span>
-                  <div>
-                    <h3>折旧与财务</h3>
-                    <p>采购价格、起始日期与折旧周期</p>
-                  </div>
-                </div>
-                <div class="detail-grid">
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.pp') }}</span>
-                    <span class="detail-value">{{ displayText(formData.plPrice) }}</span>
-                  </div>
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.pdate') }}</span>
-                    <span class="detail-value">{{ displayDate(formData.plDate) }}</span>
-                  </div>
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.dp') }}</span>
-                    <span class="detail-value">{{ displayText(formData.plYear) }}</span>
-                  </div>
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.ds') }}</span>
-                    <span class="detail-value">{{ displayDate(formData.plStartDate) }}</span>
-                  </div>
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.yd') }}</span>
-                    <span class="detail-value">{{ displayText(formData.plMonthed) }}</span>
-                  </div>
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.yy') }}</span>
-                    <span class="detail-value">{{ displayText(formData.plAmounted) }}</span>
-                  </div>
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.sy') }}</span>
-                    <span class="detail-value">{{ displayText(formData.remainAmount) }}</span>
-                  </div>
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.my') }}</span>
-                    <span class="detail-value">{{ displayText(formData.monthAmount) }}</span>
-                  </div>
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.mmy') }}</span>
-                    <span class="detail-value">{{ displayText(formData.totalMonth) }}</span>
-                  </div>
-                  <div class="detail-card">
-                    <span class="detail-label">{{ t('deviceInfo.currency') }}</span>
-                    <span class="detail-value">{{ displayText(formData.currency) }}</span>
-                  </div>
-                </div>
-              </section>
-
-              <!-- <section class="info-section" v-if="list.length">
-                <div class="section-heading">
-                  <span class="section-index">03</span>
-                  <div>
-                    <h3>扩展字段</h3>
-                    <p>来自设备模板的补充属性</p>
-                  </div>
-                </div>
-                <div class="detail-grid">
-                  <div v-for="field in list" :key="field.sort" class="detail-card">
-                    <span class="detail-label">{{ field.name }}</span>
-                    <span class="detail-value">{{ displayText(field.value) }}</span>
-                  </div>
-                </div>
-              </section> -->
-            </div>
-          </el-tab-pane>
-          <el-tab-pane :label="t('deviceInfo.fileLibrary')" name="file">
-            <DeviceFile
-              ref="fileRef"
-              :deviceId="id"
-              :deviceName="formData.deviceName"
-              v-if="loadedTabs.includes('1')" />
-          </el-tab-pane>
-          <el-tab-pane :label="t('deviceInfo.deviceBOM')" name="bom">
-            <BomList
-              ref="bomRef"
-              v-model:activeName="activeName"
-              :deviceId="id"
-              :deviceCategoryName="formData.assetClassName"
-              v-if="loadedTabs.includes('2')" />
-          </el-tab-pane>
-          <el-tab-pane :label="t('deviceInfo.operationRecords')" name="record">
-            <RecordList
-              ref="recordRef"
-              v-model:activeName="activeName"
-              :deviceId="id"
-              v-if="loadedTabs.includes('3')" />
-          </el-tab-pane>
-          <el-tab-pane :label="t('deviceInfo.faultRecords')" name="failure">
-            <FailureList
-              ref="failureRef"
-              v-model:activeName="activeName"
-              :deviceId="id"
-              v-if="loadedTabs.includes('4')" />
-          </el-tab-pane>
-          <el-tab-pane :label="t('deviceInfo.repairRecords')" name="maintain">
-            <MaintainList
-              ref="maintainRef"
-              v-model:activeName="activeName"
-              :deviceId="id"
-              v-if="loadedTabs.includes('5')" />
-          </el-tab-pane>
-          <el-tab-pane :label="t('deviceInfo.maintenanceRecords')" name="maintenance">
-            <MaintenanceList
-              ref="maintenanceRef"
-              v-model:activeName="activeName"
-              :deviceId="id"
-              v-if="loadedTabs.includes('6')" />
-          </el-tab-pane>
-          <el-tab-pane :label="t('deviceInfo.inspectionRecords')" name="inspect">
-            <InspectList
-              ref="inspectRef"
-              v-model:activeName="activeName"
-              :deviceId="id"
-              v-if="loadedTabs.includes('7')" />
-          </el-tab-pane>
-          <el-tab-pane :label="t('deviceInfo.transferRecords')" name="allot">
-            <AllotLogList
-              ref="allotRef"
-              v-model:activeName="activeName"
-              :deviceId="id"
-              v-if="loadedTabs.includes('8')" />
-          </el-tab-pane>
-          <el-tab-pane :label="t('deviceInfo.statusChangeRecords')" name="status">
-            <DeviceStatusLogList
-              ref="statusRef"
-              v-model:activeName="activeName"
-              :deviceId="id"
-              v-if="loadedTabs.includes('9')" />
-          </el-tab-pane>
-          <el-tab-pane :label="t('deviceInfo.RPAdjustmentRecords')" name="person">
-            <PersonList
-              ref="personRef"
-              v-model:activeName="activeName"
-              :deviceId="id"
-              v-if="loadedTabs.includes('10')" />
-          </el-tab-pane>
-          <el-tab-pane :label="t('deviceInfo.associationDevice')" name="association">
-            <AssociationDevices
-              ref="associationRef"
-              v-model:activeName="activeName"
-              :deviceId="id"
-              v-if="loadedTabs.includes('11')" />
-          </el-tab-pane>
-        </el-tabs>
+      <div style="flex: 2; height: 12em; margin-top: 23px">
+        <el-form ref="formRef" :disabled="false" :model="formData" label-width="120px">
+          <el-row>
+            <el-col :span="8">
+              <el-form-item :label="t('iotDevice.yfCode')" prop="yfDeviceCode">
+                {{ formData.yfDeviceCode }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item :label="t('iotDevice.code')" prop="deviceCode">
+                {{ formData.deviceCode }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item :label="t('chooseMaintain.deviceName')" prop="deviceName">
+                {{ formData.deviceName }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item :label="t('iotDevice.brand')" prop="brand">
+                {{ formData.brandName }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item :label="t('iotDevice.dept')" prop="deptId">
+                {{ formData.deptName }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item :label="t('info.deviceClass')" prop="assetClass">
+                {{ formData.assetClassName }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item :label="t('monitor.status')" prop="deviceStatus">
+                {{ getDictLabel(DICT_TYPE.PMS_DEVICE_STATUS, formData.deviceStatus) }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item :label="t('devicePerson.assets')" prop="assetProperty">
+                {{ getDictLabel(DICT_TYPE.PMS_ASSET_PROPERTY, formData.assetProperty) }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item :label="t('deviceForm.model')" prop="model">
+                {{ formData.model ? formData.model : '-' }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item :label="t('devicePerson.rp')" prop="responsibleNames">
+                {{ formData.responsibleNames ? formData.responsibleNames : '-' }}
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
       </div>
-    </ContentWrap>
-  </div>
+    </div>
+  </ContentWrap>
+  <ContentWrap v-loading="formLoading">
+    <el-tabs v-model="activeName" @tab-click="handleTabClick">
+      <el-tab-pane :label="t('deviceInfo.basicInformation')" name="info">
+        <el-form style="margin-top: 5px; margin-left: 35px; margin-right: 35px">
+          <el-row style="border-bottom: 1px solid #dcdfe6">
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.mfg')" prop="manufacturerId">
+                {{ formData.zzName }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.pd')" prop="manDate">
+                {{ formatDate(formData.manDate, 'YYYY-MM-DD') }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.supplier')" prop="supplierId">
+                {{ formData.supplierName ? formData.supplierName : '-' }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.ni')" prop="nameplate">
+                {{ formData.nameplate ? formData.nameplate : '-' }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.warranty')" prop="expires">
+                {{ formData.expires ? formatDate(formData.expires, 'YYYY-MM-DD') : '-' }}
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row style="margin-top: 20px; border-bottom: 1px solid #dcdfe6">
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.pp')" prop="plPrice">
+                {{ formData.plPrice ? formData.plPrice : '-' }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.pdate')" prop="plDate">
+                {{ formData.plDate ? formatDate(formData.plDate, 'YYYY-MM-DD') : '-' }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.dp')" prop="plYear">
+                {{ formData.plYear ? formData.plYear : '-' }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.ds')" prop="plStartDate">
+                {{ formData.plStartDate ? formatDate(formData.plStartDate, 'YYYY-MM-DD') : '-' }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.yd')" prop="plMonthed">
+                {{ formData.plMonthed ? formData.plMonthed : '-' }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.yy')" prop="plAmounted">
+                {{ formData.plAmounted ? formData.plAmounted : '-' }}
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.sy')" prop="remainAmount">
+                {{ formData.remainAmount ? formData.remainAmount : '-' }}
+              </el-form-item>
+            </el-col>
+
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.my')" prop="monthAmount">
+                {{ formData.monthAmount ? formData.monthAmount : '-' }}
+              </el-form-item>
+            </el-col>
+
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.mmy')" prop="totalMonth">
+                {{ formData.totalMonth ? formData.totalMonth : '-' }}
+              </el-form-item>
+            </el-col>
+
+            <el-col :span="6">
+              <el-form-item :label="t('deviceInfo.currency')" prop="currency">
+                {{ formData.currency ? formData.currency : '-' }}
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row style="margin-top: 20px">
+            <el-col v-for="field in list" :key="field.sort" :span="6">
+              <el-form-item :label="field.name" :prop="field.identifier">
+                {{ field.value }}
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </el-tab-pane>
+      <el-tab-pane :label="t('deviceInfo.fileLibrary')" name="file">
+        <!--        <DeviceUpload ref="fileRef" v-if="loadedTabs.includes('1')" />-->
+        <DeviceFile
+          ref="fileRef"
+          :deviceId="id"
+          :deviceName="formData.deviceName"
+          v-if="loadedTabs.includes('1')" />
+      </el-tab-pane>
+      <el-tab-pane :label="t('deviceInfo.deviceBOM')" name="bom">
+        <BomList
+          ref="bomRef"
+          v-model:activeName="activeName"
+          :deviceId="id"
+          :deviceCategoryName="formData.assetClassName"
+          v-if="loadedTabs.includes('2')" />
+      </el-tab-pane>
+      <el-tab-pane :label="t('deviceInfo.operationRecords')" name="record">
+        <RecordList
+          ref="recordRef"
+          v-model:activeName="activeName"
+          :deviceId="id"
+          v-if="loadedTabs.includes('3')" />
+      </el-tab-pane>
+      <el-tab-pane :label="t('deviceInfo.faultRecords')" name="failure">
+        <FailureList
+          ref="failureRef"
+          v-model:activeName="activeName"
+          :deviceId="id"
+          v-if="loadedTabs.includes('4')" />
+      </el-tab-pane>
+      <el-tab-pane :label="t('deviceInfo.repairRecords')" name="maintain">
+        <MaintainList
+          ref="maintainRef"
+          v-model:activeName="activeName"
+          :deviceId="id"
+          v-if="loadedTabs.includes('5')" />
+      </el-tab-pane>
+      <el-tab-pane :label="t('deviceInfo.maintenanceRecords')" name="maintenance">
+        <MaintenanceList
+          ref="maintenanceRef"
+          v-model:activeName="activeName"
+          :deviceId="id"
+          v-if="loadedTabs.includes('6')" />
+      </el-tab-pane>
+      <el-tab-pane :label="t('deviceInfo.inspectionRecords')" name="inspect">
+        <InspectList
+          ref="inspectRef"
+          v-model:activeName="activeName"
+          :deviceId="id"
+          v-if="loadedTabs.includes('7')" />
+      </el-tab-pane>
+      <el-tab-pane :label="t('deviceInfo.transferRecords')" name="allot">
+        <AllotLogList
+          ref="allotRef"
+          v-model:activeName="activeName"
+          :deviceId="id"
+          v-if="loadedTabs.includes('8')" />
+      </el-tab-pane>
+      <el-tab-pane :label="t('deviceInfo.statusChangeRecords')" name="status">
+        <DeviceStatusLogList
+          ref="statusRef"
+          v-model:activeName="activeName"
+          :deviceId="id"
+          v-if="loadedTabs.includes('9')" />
+      </el-tab-pane>
+      <el-tab-pane :label="t('deviceInfo.RPAdjustmentRecords')" name="person">
+        <PersonList
+          ref="personRef"
+          v-model:activeName="activeName"
+          :deviceId="id"
+          v-if="loadedTabs.includes('10')" />
+      </el-tab-pane>
+
+      <!-- 关联设备 -->
+      <el-tab-pane :label="t('deviceInfo.associationDevice')" name="association">
+        <AssociationDevices
+          ref="personRef"
+          v-model:activeName="activeName"
+          :deviceId="id"
+          v-if="loadedTabs.includes('11')" />
+      </el-tab-pane>
+    </el-tabs>
+  </ContentWrap>
 </template>
-
 <script lang="ts" setup>
 import { IotDeviceApi, IotDeviceVO } from '@/api/pms/device'
 import { DICT_TYPE, getDictLabel } from '@/utils/dict'
 import { formatDate } from '../../../utils/formatTime'
+import DeviceUpload from '@/views/pms/device/DeviceUpload.vue'
+import BomInfo from '@/views/pms/device/bom/BomInfo.vue'
 import DeviceFile from '@/views/pms/device/DeviceFile.vue'
 import BomList from '@/views/pms/device/bom/BomList.vue'
 import FailureList from '@/views/pms/device/FailureList.vue'
@@ -274,23 +264,25 @@ import PersonList from '@/views/pms/device/personlog/PersonList.vue'
 import RecordList from '@/views/pms/device/record/RecordList.vue'
 import AssociationDevices from '@/views/pms/device/completeSet/AssociationDevices.vue'
 import { createImageViewer } from '@/components/ImageViewer'
-import { computed, onMounted, ref } from 'vue'
+import { ref, onMounted } from 'vue'
 import { getAccessToken } from '@/utils/auth'
 
 const defaultPicUrl = ref(
   import.meta.env.VITE_BASE_URL + '/admin-api/infra/file/29/get/IntegratedSolution.png'
-)
+) // 默认设备图片
 
 defineOptions({ name: 'DeviceDetailInfo' })
 
-const { t } = useI18n()
-const { params } = useRoute()
-const formLoading = ref(false)
-const activeName = ref('info')
-const list = ref<any[]>([])
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+const { params } = useRoute() // 查询参数
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const activeName = ref('info') // Tag 激活的窗口
+const list = ref([])
 const id = params.id
-const fileRef = ref()
-const formData = ref<any>({
+const fileRef = ref() // 搜索的表单
+// SPU 表单数据
+const formData = ref({
   id: undefined,
   code: undefined,
   name: undefined,
@@ -313,43 +305,29 @@ const formData = ref<any>({
   totalMonth: undefined,
   currency: undefined
 })
-const loadedTabs = ref(['info'])
-
-const deviceStatusText = computed(() =>
-  displayText(getDictLabel(DICT_TYPE.PMS_DEVICE_STATUS, formData.value.deviceStatus))
-)
-
-const statusToneClass = computed(() => {
-  const status = String(formData.value.deviceStatus ?? '')
-  if (status === '1' || status.toLowerCase() === 'online') return 'is-good'
-  if (status === '0' || status.toLowerCase() === 'offline') return 'is-muted'
-  return 'is-warning'
-})
-
-function displayText(value: unknown) {
-  return value === undefined || value === null || value === '' ? '-' : String(value)
-}
-
-function displayDate(value: unknown) {
-  return value ? formatDate(value, 'YYYY-MM-DD') : '-'
-}
+const pics = ref([])
+const imgSrc = ref('')
+const loadedTabs = ref(['info']) // 记录已加载的标签
 
+/** 获得详情 */
 const getDetail = async () => {
-  if (!id) return
-  formLoading.value = true
-  try {
-    const res = (await IotDeviceApi.getIotDevice(id)) as IotDeviceVO
-    formData.value = res
-    if (res?.templateJson) {
-      list.value = JSON.parse(res.templateJson)
-    } else {
-      list.value = []
-    }
-    if (res?.picUrl) {
-      defaultPicUrl.value = res.picUrl
+  if (id) {
+    formLoading.value = true
+    try {
+      const res = (await IotDeviceApi.getIotDevice(id)) as IotDeviceVO
+      formData.value = res
+      pics.value.push(res.picUrl)
+      if (res) {
+        if (res.templateJson) {
+          list.value = JSON.parse(res.templateJson)
+        }
+      }
+      if (formData.value.picUrl) {
+        defaultPicUrl.value = formData.value.picUrl
+      }
+    } finally {
+      formLoading.value = false
     }
-  } finally {
-    formLoading.value = false
   }
 }
 
@@ -365,378 +343,14 @@ const imagePreview = (imgUrl: string) => {
 
 const handleTabClick = (tab) => {
   if (!loadedTabs.value.includes(tab.index)) {
+    // 这里可以添加每个标签对应的加载逻辑,如果有的话
     loadedTabs.value.push(tab.index)
   }
 }
 
+/** 初始化 */
 onMounted(async () => {
   await getDetail()
 })
 </script>
-
-<style scoped>
-.device-info-page {
-  --device-ink: #20304d;
-  --device-muted: #6f809e;
-  display: grid;
-  gap: 16px;
-}
-
-:deep(.device-shell .el-card),
-:deep(.device-shell > .el-card) {
-  border: 1px solid rgba(209, 222, 240, 0.92);
-  border-radius: 24px;
-  overflow: hidden;
-  background: radial-gradient(circle at top left, rgba(162, 193, 248, 0.18), transparent 30%),
-    linear-gradient(180deg, rgba(255, 255, 255, 0.98) 0%, rgba(244, 248, 255, 0.98) 100%);
-  box-shadow:
-    inset 0 1px 0 rgba(255, 255, 255, 0.96),
-    inset 0 -18px 30px rgba(214, 228, 245, 0.18),
-    0 20px 50px rgba(35, 61, 106, 0.08);
-}
-
-:deep(.device-shell .el-card__body) {
-  padding: 0;
-}
-
-.device-hero {
-  display: grid;
-  grid-template-columns: minmax(280px, 360px) minmax(0, 1fr);
-  gap: 24px;
-  padding: 26px;
-  min-width: 0;
-}
-
-.device-media-card {
-  position: relative;
-  min-height: 280px;
-  border-radius: 22px;
-  overflow: hidden;
-  background: radial-gradient(circle at 20% 15%, rgba(170, 201, 249, 0.28), transparent 28%),
-    linear-gradient(160deg, #edf4ff 0%, #ffffff 56%, #edf4ff 100%);
-  border: 1px solid rgba(206, 221, 241, 0.94);
-  box-shadow:
-    inset 0 1px 0 rgba(255, 255, 255, 0.98),
-    inset 0 -18px 26px rgba(205, 221, 244, 0.22),
-    0 18px 36px rgba(55, 88, 140, 0.08);
-}
-
-.device-media-glow {
-  position: absolute;
-  inset: auto -20% -24% auto;
-  width: 220px;
-  height: 220px;
-  border-radius: 999px;
-  background: radial-gradient(circle, rgba(137, 176, 242, 0.28) 0%, transparent 68%);
-  pointer-events: none;
-}
-
-.device-image {
-  width: 100%;
-  height: 100%;
-  min-height: 280px;
-  padding: 26px;
-  cursor: zoom-in;
-}
-
-.device-image-caption {
-  position: absolute;
-  left: 20px;
-  right: 20px;
-  bottom: 18px;
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  gap: 12px;
-  padding: 10px 14px;
-  border-radius: 16px;
-  border: 1px solid rgba(213, 225, 241, 0.96);
-  background: rgba(255, 255, 255, 0.72);
-  backdrop-filter: blur(10px);
-  box-shadow: 0 10px 24px rgba(41, 74, 126, 0.08);
-}
-
-.device-image-tag,
-.device-image-hint {
-  font-family: 'Georgia', 'Times New Roman', serif;
-  letter-spacing: 0.08em;
-  font-size: 12px;
-  color: var(--device-muted);
-}
-
-.device-hero-content {
-  display: grid;
-  gap: 22px;
-  min-width: 0;
-}
-
-.device-hero-heading {
-  display: flex;
-  align-items: flex-start;
-  justify-content: space-between;
-  gap: 16px;
-}
-
-.device-kicker {
-  font-family: 'Georgia', 'Times New Roman', serif;
-  font-size: 12px;
-  letter-spacing: 0.18em;
-  text-transform: uppercase;
-  color: #7d8fae;
-}
-
-.device-title {
-  margin: 10px 0 6px;
-  font-family: 'Georgia', 'Times New Roman', serif;
-  font-size: clamp(28px, 3vw, 42px);
-  line-height: 1.05;
-  color: #1c2c48;
-}
-
-.device-subtitle {
-  margin: 0;
-  color: var(--device-muted);
-  font-size: 14px;
-}
-
-.device-status-cluster {
-  display: grid;
-  gap: 10px;
-  justify-items: end;
-}
-
-.device-status-pill,
-.device-meta-chip {
-  display: inline-flex;
-  align-items: center;
-  gap: 8px;
-  padding: 10px 14px;
-  border-radius: 999px;
-  border: 1px solid rgba(209, 221, 239, 0.96);
-  background: rgba(255, 255, 255, 0.86);
-  box-shadow:
-    inset 0 1px 0 rgba(255, 255, 255, 0.92),
-    0 8px 18px rgba(44, 72, 119, 0.06);
-  color: #344766;
-  white-space: nowrap;
-}
-
-.device-status-pill.is-good {
-  color: #28575c;
-}
-
-.device-status-pill.is-muted {
-  color: #54657e;
-}
-
-.device-status-pill.is-warning {
-  color: #805d28;
-}
-
-.device-status-dot {
-  width: 9px;
-  height: 9px;
-  border-radius: 50%;
-  background: currentColor;
-  box-shadow: 0 0 0 4px rgb(93 121 183 / 12%);
-}
-
-.device-overview-grid {
-  display: grid;
-  grid-template-columns: repeat(3, minmax(0, 1fr));
-  gap: 14px;
-}
-
-.overview-card {
-  display: grid;
-  gap: 10px;
-  min-height: 108px;
-  padding: 18px;
-  border-radius: 18px;
-  border: 1px solid rgba(214, 225, 241, 0.92);
-  background: linear-gradient(180deg, rgba(255, 255, 255, 0.94) 0%, rgba(243, 248, 255, 0.98) 100%);
-  box-shadow:
-    inset 0 1px 0 rgba(255, 255, 255, 0.94),
-    inset 0 -10px 20px rgba(214, 226, 244, 0.18);
-}
-
-.overview-card--primary {
-  background: radial-gradient(circle at top right, rgba(156, 189, 242, 0.2), transparent 28%),
-    linear-gradient(180deg, rgba(255, 255, 255, 0.96) 0%, rgba(240, 246, 255, 1) 100%);
-}
-
-.overview-label {
-  font-size: 12px;
-  letter-spacing: 0.1em;
-  text-transform: uppercase;
-  color: #7d8ea9;
-}
-
-.overview-value {
-  font-size: 18px;
-  line-height: 1.35;
-  color: var(--device-ink);
-  word-break: break-word;
-}
-
-.device-tabs-card {
-  padding: 18px 20px 22px;
-}
-
-:deep(.device-tabs .el-tabs__header) {
-  margin: 0 0 18px;
-}
-
-:deep(.device-tabs .el-tabs__nav-wrap::after) {
-  height: 1px;
-  background: rgba(213, 225, 241, 0.9);
-}
-
-:deep(.device-tabs .el-tabs__item) {
-  height: 42px;
-  padding: 0 16px;
-  color: #667892;
-  font-weight: 600;
-}
-
-:deep(.device-tabs .el-tabs__item.is-active) {
-  color: #29456d;
-}
-
-:deep(.device-tabs .el-tabs__active-bar) {
-  height: 3px;
-  border-radius: 999px;
-  background: linear-gradient(90deg, #8db3f4 0%, #597fca 100%);
-}
-
-.info-panel {
-  display: grid;
-  gap: 18px;
-}
-
-.info-section {
-  padding: 22px;
-  border-radius: 22px;
-  border: 1px solid rgba(210, 223, 241, 0.92);
-  background: radial-gradient(circle at top left, rgba(164, 193, 242, 0.12), transparent 30%),
-    linear-gradient(180deg, rgba(255, 255, 255, 0.96) 0%, rgba(244, 248, 255, 0.98) 100%);
-  box-shadow:
-    inset 0 1px 0 rgba(255, 255, 255, 0.94),
-    inset 0 -12px 22px rgba(213, 226, 243, 0.14);
-}
-
-.section-heading {
-  display: flex;
-  align-items: center;
-  gap: 14px;
-  margin-bottom: 18px;
-}
-
-.section-index {
-  display: inline-flex;
-  align-items: center;
-  justify-content: center;
-  width: 46px;
-  height: 46px;
-  border-radius: 14px;
-  background: linear-gradient(180deg, #ffffff 0%, #eaf2ff 100%);
-  border: 1px solid rgba(205, 219, 240, 0.95);
-  color: #5a79b4;
-  font-family: 'Georgia', 'Times New Roman', serif;
-  font-size: 18px;
-  box-shadow:
-    inset 0 1px 0 rgba(255, 255, 255, 0.96),
-    0 8px 16px rgba(55, 87, 138, 0.06);
-}
-
-.section-heading h3 {
-  margin: 0 0 4px;
-  font-family: 'Georgia', 'Times New Roman', serif;
-  font-size: 22px;
-  color: #223453;
-}
-
-.section-heading p {
-  margin: 0;
-  font-size: 13px;
-  color: var(--device-muted);
-}
-
-.detail-grid {
-  display: grid;
-  grid-template-columns: repeat(4, minmax(0, 1fr));
-  gap: 14px;
-}
-
-.detail-card {
-  display: grid;
-  gap: 10px;
-  min-height: 98px;
-  padding: 16px;
-  border-radius: 18px;
-  border: 1px solid rgba(214, 226, 243, 0.95);
-  background: rgba(255, 255, 255, 0.76);
-  box-shadow:
-    inset 0 1px 0 rgba(255, 255, 255, 0.94),
-    inset 0 -8px 16px rgba(215, 227, 244, 0.14);
-}
-
-.detail-label {
-  font-size: 12px;
-  letter-spacing: 0.06em;
-  text-transform: uppercase;
-  color: #7d8fa9;
-}
-
-.detail-value {
-  color: var(--device-ink);
-  font-size: 16px;
-  line-height: 1.45;
-  word-break: break-word;
-}
-
-@media (max-width: 1440px) {
-  .device-overview-grid,
-  .detail-grid {
-    grid-template-columns: repeat(3, minmax(0, 1fr));
-  }
-}
-
-@media (max-width: 1080px) {
-  .device-hero {
-    grid-template-columns: 1fr;
-  }
-
-  .device-status-cluster {
-    justify-items: start;
-  }
-
-  .device-overview-grid,
-  .detail-grid {
-    grid-template-columns: repeat(2, minmax(0, 1fr));
-  }
-}
-
-@media (max-width: 768px) {
-  .device-hero {
-    padding: 18px;
-  }
-
-  .device-hero-heading {
-    flex-direction: column;
-  }
-
-  .device-tabs-card {
-    padding: 14px;
-  }
-
-  .info-section {
-    padding: 18px;
-  }
-
-  .device-overview-grid,
-  .detail-grid {
-    grid-template-columns: 1fr;
-  }
-}
-</style>
+<style scoped></style>

+ 1 - 1
src/views/pms/qhse/index.vue

@@ -17,7 +17,7 @@
       size="small"
       label-width="auto"
       class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 pt-4 flex items-center flex-wrap min-w-0">
-      <div class="flex items-center gap-4 flex-wrap">
+      <div class="flex items-center gap-1 flex-wrap">
         <el-form-item label="计量器具名称" prop="measureName">
           <el-input
             v-model="queryParams.measureName"