160 lines
6.3 KiB
Vue
160 lines
6.3 KiB
Vue
<template>
|
|
<div class="page-container">
|
|
<el-card>
|
|
<template #header>
|
|
<div class="card-header">
|
|
<span>设备合规管理</span>
|
|
<div class="header-right">
|
|
<el-input v-model="keyword" placeholder="设备编号/名称" clearable style="width: 200px" />
|
|
<el-switch v-model="onlyOverdue" active-text="只看超期" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- 合规概览卡片 -->
|
|
<el-row :gutter="16" class="summary-row">
|
|
<el-col :span="6">
|
|
<el-card shadow="never" class="summary-card">
|
|
<div class="summary-count">{{ allEquipments.length }}</div>
|
|
<div class="summary-label">设备总数</div>
|
|
</el-card>
|
|
</el-col>
|
|
<el-col :span="6">
|
|
<el-card shadow="never" class="summary-card" :class="{ danger: overdueCounts.calibration > 0 }">
|
|
<div class="summary-count">{{ overdueCounts.calibration }}</div>
|
|
<div class="summary-label">校准超期</div>
|
|
</el-card>
|
|
</el-col>
|
|
<el-col :span="6">
|
|
<el-card shadow="never" class="summary-card" :class="{ danger: overdueCounts.inspection > 0 }">
|
|
<div class="summary-count">{{ overdueCounts.inspection }}</div>
|
|
<div class="summary-label">检定超期</div>
|
|
</el-card>
|
|
</el-col>
|
|
<el-col :span="6">
|
|
<el-card shadow="never" class="summary-card" :class="{ danger: overdueCounts.maintenance > 0 }">
|
|
<div class="summary-count">{{ overdueCounts.maintenance }}</div>
|
|
<div class="summary-label">保养超期</div>
|
|
</el-card>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<!-- 合规明细表 -->
|
|
<el-table :data="filteredList" border stripe v-loading="loading">
|
|
<el-table-column prop="Code" label="设备编号" width="130" />
|
|
<el-table-column prop="Name" label="设备名称" min-width="140" show-overflow-tooltip />
|
|
<el-table-column label="校准状态" width="95">
|
|
<template #default="{ row }">
|
|
<el-tag :type="calibrationOverdue(row) ? 'danger' : 'success'">
|
|
{{ calibrationOverdue(row) ? '超期' : '正常' }}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="校准日期" width="110">
|
|
<template #default="{ row }">{{ fmtDate(row.LastCalibrationDate) || '-' }}</template>
|
|
</el-table-column>
|
|
<el-table-column label="校准到期" width="110">
|
|
<template #default="{ row }">
|
|
<span :class="{ 'overdue-text': isOverdue(row.NextCalibrationDate) }">
|
|
{{ fmtDate(row.NextCalibrationDate) || '-' }}
|
|
</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="检定日期" width="110">
|
|
<template #default="{ row }">{{ fmtDate(row.InspectionDate) || '-' }}</template>
|
|
</el-table-column>
|
|
<el-table-column label="检定到期" width="110">
|
|
<template #default="{ row }">
|
|
<span :class="{ 'overdue-text': isOverdue(row.NextInspectionDate) }">
|
|
{{ fmtDate(row.NextInspectionDate) || '-' }}
|
|
</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="保养状态" width="95">
|
|
<template #default="{ row }">
|
|
<el-tag :type="maintenanceOverdue(row) ? 'danger' : 'success'">
|
|
{{ maintenanceOverdue(row) ? '超期' : '正常' }}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="保养日期" width="110">
|
|
<template #default="{ row }">{{ fmtDate(row.LastMaintenanceDate) || '-' }}</template>
|
|
</el-table-column>
|
|
<el-table-column label="保养周期到期" width="120">
|
|
<template #default="{ row }">
|
|
<span :class="{ 'overdue-text': isOverdue(row.NextMaintenanceDate) }">
|
|
{{ fmtDate(row.NextMaintenanceDate) || '-' }}
|
|
</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="保修到期" width="110">
|
|
<template #default="{ row }">
|
|
<span :class="{ 'overdue-text': isOverdue(row.WarrantyExpireDate) }">
|
|
{{ fmtDate(row.WarrantyExpireDate) || '-' }}
|
|
</span>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</el-card>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, onMounted } from 'vue'
|
|
import { getAllEquipment } from '@/api/equipment'
|
|
import { fmtDate, isOverdue } from '@/utils/format'
|
|
|
|
const loading = ref(false)
|
|
const allEquipments = ref([])
|
|
const keyword = ref('')
|
|
const onlyOverdue = ref(false)
|
|
|
|
async function loadAll() {
|
|
loading.value = true
|
|
try {
|
|
allEquipments.value = await getAllEquipment()
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
// 合规判定:设置了到期日期且早于今天即为超期
|
|
const calibrationOverdue = (row) => isOverdue(row.NextCalibrationDate)
|
|
const maintenanceOverdue = (row) => isOverdue(row.NextMaintenanceDate)
|
|
const anyOverdue = (row) =>
|
|
calibrationOverdue(row) || maintenanceOverdue(row) || isOverdue(row.NextInspectionDate) || isOverdue(row.WarrantyExpireDate)
|
|
|
|
const overdueCounts = computed(() => ({
|
|
calibration: allEquipments.value.filter(calibrationOverdue).length,
|
|
inspection: allEquipments.value.filter(row => isOverdue(row.NextInspectionDate)).length,
|
|
maintenance: allEquipments.value.filter(maintenanceOverdue).length
|
|
}))
|
|
|
|
const filteredList = computed(() => {
|
|
let list = allEquipments.value
|
|
if (onlyOverdue.value) {
|
|
list = list.filter(anyOverdue)
|
|
}
|
|
if (keyword.value) {
|
|
const kw = keyword.value.toLowerCase()
|
|
list = list.filter(e =>
|
|
(e.Code || '').toLowerCase().includes(kw) || (e.Name || '').toLowerCase().includes(kw)
|
|
)
|
|
}
|
|
return list
|
|
})
|
|
|
|
onMounted(loadAll)
|
|
</script>
|
|
|
|
<style scoped>
|
|
.card-header { display: flex; justify-content: space-between; align-items: center; }
|
|
.header-right { display: flex; align-items: center; gap: 16px; }
|
|
.summary-row { margin-bottom: 16px; }
|
|
.summary-card { text-align: center; }
|
|
.summary-card.danger .summary-count { color: var(--el-color-danger); }
|
|
.summary-count { font-size: 26px; font-weight: 600; }
|
|
.summary-label { color: var(--el-text-color-secondary); margin-top: 4px; font-size: 13px; }
|
|
.overdue-text { color: var(--el-color-danger); font-weight: 600; }
|
|
</style>
|