|
|
@@ -0,0 +1,378 @@
|
|
|
+<template>
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="4" :xs="24">
|
|
|
+ <ContentWrap class="h-1/1" style="border: 0">
|
|
|
+ <DeptTree @node-click="handleDeptNodeClick" />
|
|
|
+ </ContentWrap>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="20" :xs="24">
|
|
|
+ <!-- 统计卡片 -->
|
|
|
+ <el-row :gutter="18" class="mb-4">
|
|
|
+ <el-col :span="5">
|
|
|
+ <div style="background-color: #fff; border-radius: 10px; cursor: pointer">
|
|
|
+ <div class="stat-card bg-blue-gradient">
|
|
|
+ <Icon icon="ep:histogram" :size="40" />
|
|
|
+ <div class="card-title">故障总数</div>
|
|
|
+ <div class="card-value pt-5">{{
|
|
|
+ statusCount.finished + statusCount.trans + statusCount.reporting
|
|
|
+ }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :span="4">
|
|
|
+ <div style="background-color: #fff; border-radius: 10px">
|
|
|
+ <div class="stat-card bg-green-gradient">
|
|
|
+ <Icon icon="ep:finished" :size="40" />
|
|
|
+ <div class="card-title">维修完成</div>
|
|
|
+ <div class="card-value pt-5">{{ statusCount.finished }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :span="4">
|
|
|
+ <div style="background-color: #fff; border-radius: 10px">
|
|
|
+ <div class="stat-card bg-orange-gradient">
|
|
|
+ <Icon icon="ep:more-filled" :size="40" />
|
|
|
+ <div class="card-title">未完成</div>
|
|
|
+ <div class="card-value pt-5">{{ statusCount.trans }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :span="4">
|
|
|
+ <div style="background-color: #fff; border-radius: 10px">
|
|
|
+ <div class="stat-card bg-red-gradient">
|
|
|
+ <Icon icon="ep:hide" :size="40" />
|
|
|
+ <div class="card-title">上报中</div>
|
|
|
+ <div class="card-value pt-5">{{ statusCount.reporting }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :span="7">
|
|
|
+ <div class="bg-[#fff] p-2 py-4 rounded-lg">
|
|
|
+ <el-form ref="queryFormRef" :model="queryParams">
|
|
|
+ <el-form-item label="上报时间" prop="createTime">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="queryParams.createTime"
|
|
|
+ value-format="YYYY-MM-DD HH:mm:ss"
|
|
|
+ type="daterange"
|
|
|
+ :start-placeholder="t('operationFill.start')"
|
|
|
+ :end-placeholder="t('operationFill.end')"
|
|
|
+ :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
|
|
+ class="!w-220px"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item>
|
|
|
+ <el-button @click="handleQuery"
|
|
|
+ ><Icon icon="ep:search" class="mr-3px" />{{
|
|
|
+ t('operationFill.search')
|
|
|
+ }}</el-button
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item>
|
|
|
+ <el-button @click="resetQuery"
|
|
|
+ ><Icon icon="ep:refresh" class="mr-3px" />
|
|
|
+ {{ t('operationFill.reset') }}</el-button
|
|
|
+ >
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 列表 -->
|
|
|
+ <ContentWrap style="border: 0; margin-top: 10px">
|
|
|
+ <el-table
|
|
|
+ v-loading="loading"
|
|
|
+ :data="list"
|
|
|
+ height="48vh"
|
|
|
+ :stripe="true"
|
|
|
+ :show-overflow-tooltip="true"
|
|
|
+ >
|
|
|
+ <el-table-column :label="t('fault.serial')" width="70" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ {{ scope.$index + 1 }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column
|
|
|
+ :label="t('fault.faultTitle')"
|
|
|
+ prop="failureName"
|
|
|
+ min-width="200"
|
|
|
+ align="center"
|
|
|
+ />
|
|
|
+ <el-table-column
|
|
|
+ :label="t('iotMaintain.deviceCode')"
|
|
|
+ align="center"
|
|
|
+ prop="deviceCode"
|
|
|
+ width="200"
|
|
|
+ />
|
|
|
+ <el-table-column
|
|
|
+ :label="t('fault.deviceName')"
|
|
|
+ align="center"
|
|
|
+ prop="deviceName"
|
|
|
+ min-width="200"
|
|
|
+ />
|
|
|
+ <el-table-column :label="t('fault.status')" align="center" prop="status" min-width="110">
|
|
|
+ <template #default="scope">
|
|
|
+ <dict-tag :type="DICT_TYPE.PMS_FAILURE_STATUS" :value="scope.row.status" />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ :label="t('faultForm.failureType')"
|
|
|
+ align="center"
|
|
|
+ prop="failureType"
|
|
|
+ min-width="110"
|
|
|
+ >
|
|
|
+ <template #default="scope">
|
|
|
+ <dict-tag :type="DICT_TYPE.FAILURE_TYPE" :value="scope.row.failureType" />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column label="故障频次" align="center" prop="failureReason" min-width="200" />
|
|
|
+ <el-table-column
|
|
|
+ :label="t('fault.approvalStatus')"
|
|
|
+ align="center"
|
|
|
+ prop="auditStatus"
|
|
|
+ min-width="130"
|
|
|
+ >
|
|
|
+ <template #default="scope">
|
|
|
+ <dict-tag :type="DICT_TYPE.CRM_AUDIT_STATUS" :value="scope.row.auditStatus" />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column :label="t('fault.solve')" align="center" prop="ifDeal">
|
|
|
+ <template #default="scope">
|
|
|
+ <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.ifDeal" />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ :label="t('fault.failureTime')"
|
|
|
+ align="center"
|
|
|
+ prop="failureTime"
|
|
|
+ :formatter="dateFormatter"
|
|
|
+ min-width="180px"
|
|
|
+ />
|
|
|
+ <el-table-column :label="t('fault.solveTime')" align="center" prop="dealHour">
|
|
|
+ <template #default="scope">
|
|
|
+ {{ scope.row.dealHour && scope.row.dealHour > 0 ? scope.row.dealHour + 'H' : '' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ label="上报时间"
|
|
|
+ align="center"
|
|
|
+ prop="createTime"
|
|
|
+ :formatter="dateFormatter"
|
|
|
+ min-width="180px"
|
|
|
+ />
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <!-- 分页 -->
|
|
|
+ <Pagination
|
|
|
+ :total="total"
|
|
|
+ v-model:page="queryParams.pageNo"
|
|
|
+ v-model:limit="queryParams.pageSize"
|
|
|
+ @pagination="getList"
|
|
|
+ />
|
|
|
+ </ContentWrap>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { IotInspectOrderApi, IotInspectOrderVO } from '@/api/pms/inspect/order'
|
|
|
+
|
|
|
+import { DICT_TYPE } from '@/utils/dict'
|
|
|
+import DeptTree from '@/views/system/user/DeptTree.vue'
|
|
|
+import { dateFormatter } from '@/utils/formatTime'
|
|
|
+
|
|
|
+const { params } = useRoute()
|
|
|
+/** 巡检工单 列表 */
|
|
|
+defineOptions({ name: 'IotInspectOrder' })
|
|
|
+
|
|
|
+const { t } = useI18n() // 国际化
|
|
|
+const loading = ref(true) // 列表的加载中
|
|
|
+const list = ref<IotInspectOrderVO[]>([]) // 列表的数据
|
|
|
+const deptId = params.deptId
|
|
|
+const createTime = params.createTime
|
|
|
+const total = ref(0) // 列表的总页数
|
|
|
+
|
|
|
+const queryParams = reactive({
|
|
|
+ pageNo: 1,
|
|
|
+ pageSize: 10,
|
|
|
+
|
|
|
+ createTime: [],
|
|
|
+ deptId: undefined
|
|
|
+})
|
|
|
+const queryFormRef = ref() // 搜索的表单
|
|
|
+
|
|
|
+/** 部门树节点点击 */
|
|
|
+const handleDeptNodeClick = async (row) => {
|
|
|
+ queryParams.deptId = row.id
|
|
|
+ await getList()
|
|
|
+ await getCounts()
|
|
|
+}
|
|
|
+
|
|
|
+/** 查询列表 */
|
|
|
+const getList = async () => {
|
|
|
+ loading.value = true
|
|
|
+ try {
|
|
|
+ const data = await IotInspectOrderApi.getFaultReportList(queryParams)
|
|
|
+ list.value = data.list
|
|
|
+ total.value = data.total
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** 搜索按钮操作 */
|
|
|
+const handleQuery = () => {
|
|
|
+ queryParams.pageNo = 1
|
|
|
+ getList()
|
|
|
+}
|
|
|
+
|
|
|
+/** 重置按钮操作 */
|
|
|
+const resetQuery = () => {
|
|
|
+ queryFormRef.value.resetFields()
|
|
|
+ handleQuery()
|
|
|
+}
|
|
|
+
|
|
|
+let statusCount = ref({
|
|
|
+ finished: 0,
|
|
|
+ trans: 0,
|
|
|
+ reporting: 0
|
|
|
+})
|
|
|
+async function getCounts() {
|
|
|
+ const res = await IotInspectOrderApi.getFaultReportStatus({
|
|
|
+ deptId: queryParams.deptId,
|
|
|
+ createTime: queryParams.createTime
|
|
|
+ })
|
|
|
+
|
|
|
+ statusCount.value = res
|
|
|
+
|
|
|
+ console.log('statusCount', statusCount.value)
|
|
|
+}
|
|
|
+
|
|
|
+/** 初始化 **/
|
|
|
+onMounted(() => {
|
|
|
+ getCounts()
|
|
|
+
|
|
|
+ if (deptId != null) {
|
|
|
+ queryParams.deptId = deptId
|
|
|
+ }
|
|
|
+
|
|
|
+ if (createTime) {
|
|
|
+ queryParams.createTime = createTime
|
|
|
+ }
|
|
|
+ getList()
|
|
|
+})
|
|
|
+</script>
|
|
|
+<style scoped>
|
|
|
+/* 添加异常行高亮样式 */
|
|
|
+:deep(.exception-row) {
|
|
|
+ background-color: #f29a90 !important;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.exception-row:hover) {
|
|
|
+ background-color: #fff0e0 !important;
|
|
|
+}
|
|
|
+
|
|
|
+.reason-confirm-container {
|
|
|
+ margin: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 调整文本框样式 */
|
|
|
+:deep(.el-textarea__inner) {
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 调整表单项间距 */
|
|
|
+:deep(.el-form-item) {
|
|
|
+ margin-bottom: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-card {
|
|
|
+ padding: 20px;
|
|
|
+ border-radius: 10px;
|
|
|
+ color: white;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 14px;
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
|
+ transition:
|
|
|
+ transform 0.3s ease,
|
|
|
+ box-shadow 0.3s ease;
|
|
|
+ backdrop-filter: blur(12px);
|
|
|
+ height: 200px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+.stat-card::before {
|
|
|
+ position: absolute;
|
|
|
+ filter: blur(20px);
|
|
|
+ z-index: -1;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-card:hover {
|
|
|
+ transform: translateY(-4px);
|
|
|
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.card-title {
|
|
|
+ margin: 8px 0;
|
|
|
+ font-size: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.card-value {
|
|
|
+ font-size: 28px;
|
|
|
+ font-weight: bold;
|
|
|
+ margin: 8px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.card-trend {
|
|
|
+ font-size: 12px;
|
|
|
+ opacity: 0.9;
|
|
|
+}
|
|
|
+
|
|
|
+/* 毛玻璃渐变背景 —— 不再使用 background-image */
|
|
|
+.bg-blue-gradient {
|
|
|
+ background: linear-gradient(135deg, rgba(77, 147, 255, 0.5), rgba(75, 132, 254));
|
|
|
+}
|
|
|
+
|
|
|
+.bg-green-gradient {
|
|
|
+ background: linear-gradient(135deg, rgba(101, 226, 136, 0.1), #52d7a2);
|
|
|
+ background-color: rgba(76, 175, 80, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.bg-orange-gradient {
|
|
|
+ background: linear-gradient(135deg, rgba(152, 82, 4, 0.5), rgba(255, 152, 4, 0.6));
|
|
|
+}
|
|
|
+
|
|
|
+.bg-red-gradient {
|
|
|
+ background: linear-gradient(135deg, rgba(232, 65, 51), rgba(252, 242, 236));
|
|
|
+}
|
|
|
+
|
|
|
+.bg-warn-gradient {
|
|
|
+ background: linear-gradient(135deg, rgba(255, 201, 103), rgba(243, 162, 152));
|
|
|
+}
|
|
|
+
|
|
|
+/* 确保内容不溢出 */
|
|
|
+:deep(.el-row) {
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
+
|
|
|
+.text-truncate {
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+::v-deep .el-table__header-wrapper {
|
|
|
+ position: sticky !important;
|
|
|
+ width: 100%;
|
|
|
+ top: 0px;
|
|
|
+ z-index: 2000;
|
|
|
+}
|
|
|
+</style>
|