|
|
@@ -1,269 +1,267 @@
|
|
|
<template>
|
|
|
- <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 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>
|
|
|
</div>
|
|
|
- <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>
|
|
|
+ </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>
|
|
|
- </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>
|
|
|
+ </ContentWrap>
|
|
|
+ </div>
|
|
|
</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'
|
|
|
@@ -276,25 +274,23 @@ 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 { ref, onMounted } from 'vue'
|
|
|
+import { computed, onMounted, ref } 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 message = useMessage() // 消息弹窗
|
|
|
-const { params } = useRoute() // 查询参数
|
|
|
-const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
|
|
-const activeName = ref('info') // Tag 激活的窗口
|
|
|
-const list = ref([])
|
|
|
+const { t } = useI18n()
|
|
|
+const { params } = useRoute()
|
|
|
+const formLoading = ref(false)
|
|
|
+const activeName = ref('info')
|
|
|
+const list = ref<any[]>([])
|
|
|
const id = params.id
|
|
|
-const fileRef = ref() // 搜索的表单
|
|
|
-// SPU 表单数据
|
|
|
-const formData = ref({
|
|
|
+const fileRef = ref()
|
|
|
+const formData = ref<any>({
|
|
|
id: undefined,
|
|
|
code: undefined,
|
|
|
name: undefined,
|
|
|
@@ -317,29 +313,43 @@ const formData = ref({
|
|
|
totalMonth: undefined,
|
|
|
currency: undefined
|
|
|
})
|
|
|
-const pics = ref([])
|
|
|
-const imgSrc = ref('')
|
|
|
-const loadedTabs = ref(['info']) // 记录已加载的标签
|
|
|
+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 getDetail = async () => {
|
|
|
- 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
|
|
|
+ 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
|
|
|
}
|
|
|
+ } finally {
|
|
|
+ formLoading.value = false
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -355,14 +365,378 @@ 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></style>
|
|
|
+
|
|
|
+<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>
|