|
|
@@ -11,99 +11,145 @@
|
|
|
request-api="getSimpleDeptList"
|
|
|
@node-click="handleDeptNodeClick" />
|
|
|
|
|
|
- <div class="mb-1">
|
|
|
- <el-form
|
|
|
- :model="queryParams"
|
|
|
- ref="queryFormRef"
|
|
|
- class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 py-2 pt-4 flex items-center flex-wrap min-w-0">
|
|
|
- <div class="flex items-center gap-4 flex-wrap">
|
|
|
- <el-form-item label="设备名称" prop="deviceName">
|
|
|
- <el-input
|
|
|
- v-model="queryParams.deviceName"
|
|
|
- placeholder="请输入设备名称"
|
|
|
- clearable
|
|
|
- class="!w-150px" />
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item label="检测类型" prop="certType">
|
|
|
- <el-select
|
|
|
- v-model="queryParams.certType"
|
|
|
- placeholder="请选择检测类型"
|
|
|
- clearable
|
|
|
- style="width: 150px">
|
|
|
- <el-option
|
|
|
- v-for="dict in getStrDictOptions(DICT_TYPE.QHSE_DEVICE_CERT_TYPE)"
|
|
|
- :key="dict.value"
|
|
|
- :label="dict.label"
|
|
|
- :value="dict.value" />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="序列号" prop="certNo">
|
|
|
- <el-input
|
|
|
- v-model="queryParams.certNo"
|
|
|
- placeholder="请输入序列号"
|
|
|
- clearable
|
|
|
- class="!w-150px" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="检测日期" prop="certTime">
|
|
|
- <el-date-picker
|
|
|
- v-model="queryParams.certTime"
|
|
|
- value-format="YYYY-MM-DD HH:mm:ss"
|
|
|
- type="daterange"
|
|
|
- start-placeholder="开始日期"
|
|
|
- end-placeholder="结束日期"
|
|
|
- :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
|
|
- class="!w-200px" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="检测单位" prop="certOrg">
|
|
|
- <el-input
|
|
|
- v-model="queryParams.certOrg"
|
|
|
- placeholder="请输入检测单位"
|
|
|
- clearable
|
|
|
- @keyup.enter="handleQuery"
|
|
|
- class="!w-150px" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="有效期" prop="certExpire">
|
|
|
- <el-date-picker
|
|
|
- v-model="queryParams.certExpire"
|
|
|
- value-format="YYYY-MM-DD HH:mm:ss"
|
|
|
- type="daterange"
|
|
|
- start-placeholder="开始日期"
|
|
|
- end-placeholder="结束日期"
|
|
|
- :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
|
|
- class="!w-200px" />
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item>
|
|
|
- <el-button @click="handleQuery" v-hasPermi="['rq:qhse-device-cert:query']">
|
|
|
- <Icon icon="ep:search" class="mr-5px" /> 搜索
|
|
|
- </el-button>
|
|
|
- <el-button @click="resetQuery">
|
|
|
- <Icon icon="ep:refresh" class="mr-5px" /> 重置
|
|
|
- </el-button>
|
|
|
- <el-button
|
|
|
- v-hasPermi="['rq:qhse-device-cert:create']"
|
|
|
- type="primary"
|
|
|
- plain
|
|
|
- @click="openForm('create')">
|
|
|
- <Icon icon="ep:plus" class="mr-5px" /> 新增
|
|
|
- </el-button>
|
|
|
- <el-button
|
|
|
- v-hasPermi="['rq:qhse-device-cert:export']"
|
|
|
- type="success"
|
|
|
- plain
|
|
|
- @click="handleExport"
|
|
|
- :loading="exportLoading">
|
|
|
- <Icon icon="ep:download" class="mr-5px" /> 导出
|
|
|
- </el-button>
|
|
|
- </el-form-item>
|
|
|
+ <div class="stats-cards">
|
|
|
+ <div
|
|
|
+ class="stats-card stats-card--expired stats-card--clickable"
|
|
|
+ @click="handleStatCardClick('expired')">
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
+ <Icon icon="ep:info-filled" color="#de3b3b" />
|
|
|
+ <div class="stats-card__label">已过期</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="stats-card__value">
|
|
|
+ <CountTo
|
|
|
+ :duration="2600"
|
|
|
+ :end-val="expired"
|
|
|
+ :start-val="0"
|
|
|
+ class="stats-card__value text-[40px]! pt-10 text-center! text-[#e35656]!" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="stats-card stats-card--warn stats-card--clickable"
|
|
|
+ @click="handleStatCardClick('warn')">
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
+ <Icon icon="ep:bell-filled" color="#d97706" />
|
|
|
+ <div class="stats-card__label">90天预警(含过期)</div>
|
|
|
+ </div>
|
|
|
+ <div class="stats-card__value">
|
|
|
+ <CountTo
|
|
|
+ :duration="2600"
|
|
|
+ :end-val="warn"
|
|
|
+ :start-val="0"
|
|
|
+ class="stats-card__value text-[40px]! pt-10 text-center! text-[#d97706]!" />
|
|
|
</div>
|
|
|
- </el-form>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="stats-card stats-card--total stats-card--clickable"
|
|
|
+ @click="handleStatCardClick('total')">
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
+ <Icon icon="eos-icons:counting" color="#2563eb" />
|
|
|
+ <div class="stats-card__label">证书总数</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="stats-card__value">
|
|
|
+ <CountTo
|
|
|
+ :duration="2600"
|
|
|
+ :end-val="totalCert"
|
|
|
+ :start-val="0"
|
|
|
+ class="stats-card__value text-[40px]! pt-10 text-center! text-[#2563eb]!" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
- <div class="min-w-0"></div>
|
|
|
+ <el-form
|
|
|
+ :model="queryParams"
|
|
|
+ ref="queryFormRef"
|
|
|
+ class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 py-2 pt-4 flex items-center flex-wrap min-w-0">
|
|
|
+ <div class="flex items-center gap-2 flex-wrap">
|
|
|
+ <el-form-item label="设备名称" prop="deviceName">
|
|
|
+ <el-input
|
|
|
+ v-model="queryParams.deviceName"
|
|
|
+ placeholder="请输入设备名称"
|
|
|
+ clearable
|
|
|
+ class="!w-150px" />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="检测类型" prop="certType">
|
|
|
+ <el-select
|
|
|
+ v-model="queryParams.certType"
|
|
|
+ placeholder="请选择检测类型"
|
|
|
+ clearable
|
|
|
+ style="width: 150px">
|
|
|
+ <el-option
|
|
|
+ v-for="dict in getStrDictOptions(DICT_TYPE.QHSE_DEVICE_CERT_TYPE)"
|
|
|
+ :key="dict.value"
|
|
|
+ :label="dict.label"
|
|
|
+ :value="dict.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="序列号" prop="certNo">
|
|
|
+ <el-input
|
|
|
+ v-model="queryParams.certNo"
|
|
|
+ placeholder="请输入序列号"
|
|
|
+ clearable
|
|
|
+ class="!w-150px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="检测日期" prop="certTime">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="queryParams.certTime"
|
|
|
+ value-format="YYYY-MM-DD HH:mm:ss"
|
|
|
+ type="daterange"
|
|
|
+ start-placeholder="开始日期"
|
|
|
+ end-placeholder="结束日期"
|
|
|
+ :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
|
|
+ class="!w-200px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="检测单位" prop="certOrg">
|
|
|
+ <el-input
|
|
|
+ v-model="queryParams.certOrg"
|
|
|
+ placeholder="请输入检测单位"
|
|
|
+ clearable
|
|
|
+ @keyup.enter="handleQuery"
|
|
|
+ class="!w-150px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="有效期" prop="certExpire">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="queryParams.certExpire"
|
|
|
+ value-format="YYYY-MM-DD HH:mm:ss"
|
|
|
+ type="daterange"
|
|
|
+ start-placeholder="开始日期"
|
|
|
+ end-placeholder="结束日期"
|
|
|
+ :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
|
|
+ class="!w-200px" />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item>
|
|
|
+ <el-button @click="handleQuery" v-hasPermi="['rq:qhse-device-cert:query']">
|
|
|
+ <Icon icon="ep:search" class="mr-5px" /> 搜索
|
|
|
+ </el-button>
|
|
|
+ <el-button @click="resetQuery">
|
|
|
+ <Icon icon="ep:refresh" class="mr-5px" /> 重置
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ v-hasPermi="['rq:qhse-device-cert:create']"
|
|
|
+ type="primary"
|
|
|
+ plain
|
|
|
+ @click="openForm('create')">
|
|
|
+ <Icon icon="ep:plus" class="mr-5px" /> 新增
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ v-hasPermi="['rq:qhse-device-cert:export']"
|
|
|
+ type="success"
|
|
|
+ plain
|
|
|
+ @click="handleExport"
|
|
|
+ :loading="exportLoading">
|
|
|
+ <Icon icon="ep:download" class="mr-5px" /> 导出
|
|
|
+ </el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-form>
|
|
|
|
|
|
- <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg flex flex-col p-2 pt-4 min-w-0">
|
|
|
+ <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg flex flex-col mt-1 p-2 pt-4 min-w-0">
|
|
|
<div class="flex-1 relative min-h-0">
|
|
|
<el-auto-resizer class="absolute">
|
|
|
<template #default="{ width, height }">
|
|
|
@@ -184,7 +230,7 @@
|
|
|
</div>
|
|
|
|
|
|
<div
|
|
|
- class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-3 min-w-0 flex gap-4 justify-between">
|
|
|
+ class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-3 mt-1 min-w-0 flex gap-4 justify-between">
|
|
|
<div
|
|
|
class="bg-[#fef0f0] text-[#f57979] px-3 flex-1 flex items-center justify-center text-center py-2 text-sm rounded-md"
|
|
|
><el-icon class="stats-card__icon" :size="28"> <Icon icon="ep:info-filled" /> </el-icon
|
|
|
@@ -238,7 +284,7 @@ import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
|
|
|
|
|
|
/** 应检设备证书 列表 */
|
|
|
defineOptions({ name: 'QHSEDeviceCert' })
|
|
|
-// const userStore = useUserStore()
|
|
|
+const userStore = useUserStore()
|
|
|
const rootDeptId = 156
|
|
|
const deptId = useUserStore().getUser.deptId || rootDeptId
|
|
|
|
|
|
@@ -303,12 +349,38 @@ const handleQuery = () => {
|
|
|
getList()
|
|
|
}
|
|
|
|
|
|
+const handleStatCardClick = (type: 'expired' | 'warn' | 'total') => {
|
|
|
+ queryParams.pageNo = 1
|
|
|
+
|
|
|
+ if (type === 'expired') {
|
|
|
+ queryParams.expired = true
|
|
|
+ queryParams.alertWarn = undefined
|
|
|
+ queryParams.type = undefined
|
|
|
+ getList()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (type === 'warn') {
|
|
|
+ queryParams.alertWarn = true
|
|
|
+ queryParams.expired = undefined
|
|
|
+ queryParams.type = undefined
|
|
|
+ getList()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ queryParams.type = undefined
|
|
|
+ queryParams.expired = undefined
|
|
|
+ queryParams.alertWarn = undefined
|
|
|
+ getList()
|
|
|
+}
|
|
|
+
|
|
|
const selectedDept = ref<{ id: number; name: string }>()
|
|
|
|
|
|
const handleDeptNodeClick = async (row) => {
|
|
|
selectedDept.value = { id: row.id, name: row.name }
|
|
|
queryParams.deptId = row.id
|
|
|
await getList()
|
|
|
+ await getStatic()
|
|
|
}
|
|
|
|
|
|
const formatDateCorrectly = (timestamp) => {
|
|
|
@@ -422,9 +494,28 @@ const handleDownload = async (url) => {
|
|
|
console.error('下载失败:', error)
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+let totalCert = ref(0)
|
|
|
+let expired = ref(0)
|
|
|
+let warn = ref(0)
|
|
|
+
|
|
|
+async function getStatic() {
|
|
|
+ if (queryParams.deptId) {
|
|
|
+ const res = await InspectDeviceCertApi.getInspectDeviceCertStat(queryParams.deptId)
|
|
|
+ totalCert.value = res.total
|
|
|
+ expired.value = res.expired
|
|
|
+ warn.value = res.warn
|
|
|
+ } else {
|
|
|
+ const res = await InspectDeviceCertApi.getInspectDeviceCertStat(userStore.user.deptId)
|
|
|
+ totalCert.value = res.total
|
|
|
+ expired.value = res.expired
|
|
|
+ warn.value = res.warn
|
|
|
+ }
|
|
|
+}
|
|
|
/** 初始化 **/
|
|
|
onMounted(() => {
|
|
|
getList()
|
|
|
+ getStatic()
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
@@ -438,6 +529,79 @@ onMounted(() => {
|
|
|
color: var(--el-text-color-primary);
|
|
|
}
|
|
|
|
|
|
+.stats-cards {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
|
+ gap: 12px;
|
|
|
+ margin-bottom: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.stats-card {
|
|
|
+ padding: 14px 16px;
|
|
|
+ background: linear-gradient(180deg, #ffffff 0%, #f7faff 100%);
|
|
|
+ border: 1px solid #e4ecf7;
|
|
|
+ border-radius: 10px;
|
|
|
+ box-shadow: 0 4px 12px rgb(31 91 184 / 8%);
|
|
|
+}
|
|
|
+
|
|
|
+.stats-card--clickable {
|
|
|
+ cursor: pointer;
|
|
|
+ transition:
|
|
|
+ transform 0.18s ease,
|
|
|
+ box-shadow 0.18s ease,
|
|
|
+ border-color 0.18s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.stats-card--clickable:hover {
|
|
|
+ transform: translateY(-2px);
|
|
|
+ box-shadow: 0 10px 24px rgb(31 91 184 / 14%);
|
|
|
+}
|
|
|
+
|
|
|
+.stats-card__label {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #6b7280;
|
|
|
+ line-height: 1.4;
|
|
|
+}
|
|
|
+
|
|
|
+.stats-card__value {
|
|
|
+ margin-top: 8px;
|
|
|
+ font-size: 28px;
|
|
|
+ font-weight: 700;
|
|
|
+ line-height: 1;
|
|
|
+ color: #1f5bb8;
|
|
|
+}
|
|
|
+
|
|
|
+.stats-card--expired {
|
|
|
+ background: linear-gradient(180deg, #fff4f4 0%, #ffe8e8 100%);
|
|
|
+ border-color: #ffcfcf;
|
|
|
+}
|
|
|
+
|
|
|
+.stats-card--expired .stats-card__value {
|
|
|
+ color: #de3b3b;
|
|
|
+}
|
|
|
+
|
|
|
+.stats-card--warn {
|
|
|
+ background: linear-gradient(180deg, #fff8ef 0%, #ffeed9 100%);
|
|
|
+ border-color: #ffd7a1;
|
|
|
+}
|
|
|
+
|
|
|
+.stats-card--warn .stats-card__value {
|
|
|
+ color: #d97706;
|
|
|
+}
|
|
|
+
|
|
|
+.stats-card--total .stats-card__value {
|
|
|
+ color: #2563eb;
|
|
|
+}
|
|
|
+
|
|
|
+.stats-card--personal .stats-card__value {
|
|
|
+ color: #16a34a;
|
|
|
+}
|
|
|
+
|
|
|
+.stats-card--organization .stats-card__value {
|
|
|
+ color: #7c3aed;
|
|
|
+}
|
|
|
+
|
|
|
/* 过期行的红色背景 - 基础状态 */
|
|
|
:deep(.el-table__body tr.expired-row > td.el-table__cell) {
|
|
|
background-color: #ffe6e6 !important;
|