<template>
|
<div class="app-container">
|
<el-form :inline="true"
|
:model="queryParams"
|
class="search-form">
|
<el-form-item label="巡检任务名称">
|
<el-input v-model="queryParams.taskName"
|
placeholder="请输入巡检任务名称"
|
clearable
|
style="width: 200px " />
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary"
|
@click="handleQuery">查询</el-button>
|
<el-button @click="resetQuery">重置</el-button>
|
</el-form-item>
|
</el-form>
|
<el-card>
|
<div style="display: flex;flex-direction: row;justify-content: space-between;margin-bottom: 10px;">
|
<el-radio-group v-model="activeRadio"
|
@change="radioChange">
|
<el-radio-button v-for="tab in radios"
|
:key="tab.name"
|
:label="tab.label"
|
:value="tab.name" />
|
</el-radio-group>
|
<el-space v-if="activeRadio !== 'task'">
|
<el-button type="primary"
|
:icon="Plus"
|
@click="handleAdd(undefined)">新建</el-button>
|
<el-button type="danger"
|
:icon="Delete"
|
@click="handleDelete">删除</el-button>
|
<el-button @click="handleOut">导出</el-button>
|
</el-space>
|
<el-space v-else>
|
<el-button @click="handleOut">导出</el-button>
|
</el-space>
|
</div>
|
|
<!-- 巡检任务 -->
|
<div v-show="activeRadio === 'taskManage'">
|
<PIMTable :table-loading="tableLoading"
|
:table-data="tableData"
|
:column="tableColumns"
|
@selection-change="handleSelectionChange"
|
@pagination="handlePagination"
|
:is-selection="true"
|
:border="true"
|
:page="{
|
current: pageNum,
|
size: pageSize,
|
total: total,
|
layout: 'total, sizes, prev, pager, next, jumper'
|
}"
|
height="calc(100vh - 23em)"
|
:table-style="{ width: '100%' }">
|
<template #inspector="{ row }">
|
<div class="person-tags">
|
<template v-if="row.inspector && row.inspector.length > 0">
|
<el-tag v-for="(person, index) in row.inspector"
|
:key="index"
|
size="small"
|
type="primary"
|
class="person-tag">
|
{{ person }}
|
</el-tag>
|
</template>
|
<span v-else class="no-data">--</span>
|
</div>
|
</template>
|
<template #isEnabled="{ row }">
|
<el-tag :type="row.isEnabled === 1 ? 'success' : 'danger'"
|
size="small">
|
{{ row.isEnabled == 1 ? '是' : '否' }}
|
</el-tag>
|
</template>
|
</PIMTable>
|
</div>
|
|
<!-- 巡检记录 - 日期分组折叠 -->
|
<div v-show="activeRadio === 'task'">
|
<el-table
|
:data="groupedInspectionList"
|
border
|
v-loading="tableLoading"
|
:expand-row-keys="inspectionExpandedRowKeys"
|
:row-key="(row) => row.date"
|
@expand-change="onInspectionExpandChange"
|
height="calc(100vh - 23em)"
|
>
|
<el-table-column type="expand">
|
<template #default="props">
|
<el-table :data="props.row.children" border row-key="id">
|
<el-table-column label="巡检任务名称" prop="taskName" align="center" min-width="180" />
|
<el-table-column label="巡检项目" prop="inspectionProject" align="center" min-width="160" />
|
<el-table-column label="巡检人" align="center" min-width="150">
|
<template #default="{ row }">
|
<template v-if="row.inspector && row.inspector.length > 0">
|
<el-tag v-for="(p, i) in row.inspector" :key="i" size="small" type="primary" class="person-tag">{{ p }}</el-tag>
|
</template>
|
<span v-else>--</span>
|
</template>
|
</el-table-column>
|
<el-table-column label="巡检状态" align="center" width="100">
|
<template #default="{ row }">
|
<el-tag :type="row.status === 1 ? 'success' : 'warning'" size="small">
|
{{ row.status === 1 ? '已完成' : '待巡检' }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="巡检结果" prop="inspectionResult" align="center" min-width="120" />
|
<el-table-column label="备注" prop="remarks" align="center" min-width="150" />
|
<el-table-column label="异常描述" prop="abnormalDescription" align="center" min-width="150" />
|
<el-table-column label="操作" align="center" width="200">
|
<template #default="{ row }">
|
<el-button type="primary" link @click="openUploadDialog(row)">上传</el-button>
|
<el-button type="success" link @click="viewFile(row)">查看附件</el-button>
|
<el-button type="warning" link v-if="row.status === 0" @click="handleSingleComplete(row)">巡检完成</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
</template>
|
</el-table-column>
|
<el-table-column label="巡检日期" prop="date" align="center" />
|
<el-table-column label="巡检记录数" prop="count" align="center" />
|
<el-table-column label="待巡检数" align="center" width="120">
|
<template #default="{ row }">
|
{{ row.children.filter(c => c.status === 0).length }}
|
</template>
|
</el-table-column>
|
<el-table-column label="操作" align="center" width="200">
|
<template #default="{ row }">
|
<el-button
|
type="primary"
|
size="small"
|
:disabled="!row.children.some(c => c.status === 0)"
|
@click="handleBatchInspection(row.date)"
|
>
|
一键巡检完成
|
</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
<Pagination
|
v-show="total > 0"
|
:total="total"
|
layout="total, sizes, prev, pager, next, jumper"
|
:page="pageNum"
|
:limit="pageSize"
|
@pagination="handlePagination"
|
/>
|
</div>
|
</el-card>
|
<form-dia ref="formDia"
|
@closeDia="handleQuery"></form-dia>
|
<view-files ref="viewFiles"></view-files>
|
<upload-files ref="uploadFiles"
|
@success="handleQuery"
|
@closeDia="handleQuery"></upload-files>
|
|
</div>
|
</template>
|
|
<script setup>
|
import { Delete, Plus } from "@element-plus/icons-vue";
|
import { onMounted, ref, reactive, getCurrentInstance, nextTick, computed } from "vue";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
import dayjs from "dayjs";
|
|
import PIMTable from "@/components/PIMTable/PIMTable.vue";
|
import FormDia from "@/views/equipmentManagement/inspectionManagement/components/formDia.vue";
|
import UploadFiles from "@/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue";
|
import ViewFiles from "@/views/equipmentManagement/inspectionManagement/components/viewFiles.vue";
|
|
import {
|
delTimingTask,
|
inspectionTaskList,
|
timingTaskList,
|
completeInspection,
|
batchCompleteInspection,
|
} from "@/api/inspectionManagement/index.js";
|
import Pagination from "@/components/PIMTable/Pagination.vue";
|
|
const { proxy } = getCurrentInstance();
|
const formDia = ref();
|
const viewFiles = ref();
|
const uploadFiles = ref();
|
|
const queryParams = reactive({ taskName: "" });
|
|
const activeRadio = ref("taskManage");
|
const radios = reactive([
|
{ name: "taskManage", label: "巡检任务" },
|
{ name: "task", label: "巡检记录" },
|
]);
|
|
const selectedRows = ref([]);
|
const tableData = ref([]);
|
const operationsArr = ref([]);
|
const tableColumns = ref([]);
|
const tableLoading = ref(false);
|
const total = ref(0);
|
const pageNum = ref(1);
|
const pageSize = ref(100);
|
|
const columns = ref([
|
{ prop: "taskName", label: "巡检任务名称", minWidth: 200 },
|
{ prop: "inspectionProject", label: "巡检项目", minWidth: 180 },
|
{ prop: "remarks", label: "备注", minWidth: 180 },
|
{ prop: "inspector", label: "执行巡检人", minWidth: 180, slot: "inspector" },
|
{ prop: "isEnabled", label: "是否启用", minWidth: 100, dataType: "slot", slot: "isEnabled" },
|
{
|
prop: "frequencyType", label: "频次", minWidth: 120,
|
formatData: params => ({ DAILY: "每日", WEEKLY: "每周", MONTHLY: "每月", QUARTERLY: "季度" }[params] || ""),
|
},
|
{
|
prop: "frequencyDetail", label: "开始日期与时间", minWidth: 200,
|
formatter: (row, column, cellValue) => {
|
if (typeof cellValue !== "string") return "";
|
return cellValue.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, match => ({ MON: "周一", TUE: "周二", WED: "周三", THU: "周四", FRI: "周五", SAT: "周六", SUN: "周日" }[match]));
|
},
|
},
|
{ prop: "registrant", label: "登记人", minWidth: 120 },
|
{
|
prop: "createTime", label: "登记日期", minWidth: 180,
|
formatData: cell => { if (!cell) return "-"; try { return dayjs(cell).format("YYYY-MM-DD HH:mm:ss"); } catch { return cell; } },
|
},
|
{ prop: "abnormalDescription", label: "异常描述", minWidth: 150 },
|
]);
|
|
const getOperationColumn = operations => {
|
if (!operations || operations.length === 0) return null;
|
return {
|
label: "操作", width: operations.length > 1 ? 180 : 130, fixed: "right", align: "center", dataType: "action",
|
operation: operations.map(op => {
|
switch (op) {
|
case "edit": return { name: "编辑", clickFun: handleAdd, color: "#409EFF" };
|
case "upload": return { name: "上传", clickFun: openUploadDialog, color: "#409EFF" };
|
case "viewFile": return { name: "查看附件", clickFun: viewFile, color: "#67C23A" };
|
default: return null;
|
}
|
}).filter(Boolean),
|
};
|
};
|
|
// 巡检记录 - 日期分组
|
const inspectionExpandedRowKeys = ref([]);
|
|
const groupInspectionByDate = (list) => {
|
const map = {};
|
list.forEach(item => {
|
const date = item.dateStr || (item.createTime ? dayjs(item.createTime).format('YYYY-MM-DD') : '未知日期');
|
if (!map[date]) map[date] = [];
|
map[date].push(item);
|
});
|
return Object.entries(map).map(([date, children]) => ({ date, children, count: children.length }));
|
};
|
|
const groupedInspectionList = computed(() => groupInspectionByDate(tableData.value));
|
|
const onInspectionExpandChange = (row, expandedRows) => {
|
inspectionExpandedRowKeys.value = expandedRows.map(r => r.date);
|
};
|
|
// 单条巡检完成
|
const handleSingleComplete = async (row) => {
|
try {
|
await ElMessageBox.confirm('确认将该巡检记录标记为完成?', '提示', { type: 'warning' });
|
const res = await completeInspection(row.id);
|
if (res.code === 200) {
|
ElMessage.success('巡检完成');
|
getList();
|
} else {
|
ElMessage.error(res.msg || '操作失败');
|
}
|
} catch { /* 取消 */ }
|
};
|
|
// 一键巡检完成
|
const handleBatchInspection = async (dateStr) => {
|
try {
|
await ElMessageBox.confirm(`确认将 ${dateStr} 的所有待巡检记录标记为完成?`, '提示', { type: 'warning' });
|
const res = await batchCompleteInspection(dateStr);
|
if (res.code === 200) {
|
ElMessage.success(res.msg || '批量完成成功');
|
getList();
|
} else {
|
ElMessage.error(res.msg || '操作失败');
|
}
|
} catch { /* 取消 */ }
|
};
|
|
onMounted(() => { radioChange("taskManage"); });
|
|
const radioChange = value => {
|
inspectionExpandedRowKeys.value = [];
|
if (value === "taskManage") {
|
const operationColumn = getOperationColumn(["edit"]);
|
tableColumns.value = [...columns.value, ...(operationColumn ? [operationColumn] : [])];
|
operationsArr.value = ["edit"];
|
} else if (value === "task") {
|
const operationColumn = getOperationColumn(["upload", "viewFile"]);
|
const taskColumns = columns.value.filter(col => col.prop !== "isEnabled");
|
tableColumns.value = [...taskColumns, ...(operationColumn ? [operationColumn] : [])];
|
operationsArr.value = ["upload", "viewFile"];
|
}
|
pageNum.value = 1;
|
getList();
|
};
|
|
const handleQuery = () => { pageNum.value = 1; getList(); };
|
|
const handlePagination = val => { pageNum.value = val.page; pageSize.value = val.limit; getList(); };
|
|
const getList = () => {
|
tableLoading.value = true;
|
const params = { ...queryParams, size: pageSize.value, current: pageNum.value };
|
const apiCall = activeRadio.value === "task" ? inspectionTaskList(params) : timingTaskList(params);
|
apiCall.then(res => {
|
const rawData = res.data.records || [];
|
tableData.value = rawData.map(item => {
|
const processedItem = { ...item };
|
if (processedItem.inspector) {
|
if (typeof processedItem.inspector === "string") {
|
processedItem.inspector = processedItem.inspector.split(",").map(s => s.trim()).filter(s => s);
|
} else if (!Array.isArray(processedItem.inspector)) {
|
processedItem.inspector = [processedItem.inspector];
|
}
|
} else {
|
processedItem.inspector = [];
|
}
|
return processedItem;
|
});
|
total.value = res.data.total || 0;
|
}).finally(() => { tableLoading.value = false; });
|
};
|
|
const resetQuery = () => { queryParams.taskName = ""; handleQuery(); };
|
|
const handleAdd = row => { nextTick(() => { formDia.value?.openDialog(row ? "edit" : "add", row); }); };
|
const viewFile = row => { nextTick(() => { viewFiles.value?.openDialog(row); }); };
|
const openUploadDialog = row => { nextTick(() => { uploadFiles.value?.openDialog(row); }); };
|
|
const handleDelete = () => {
|
if (!selectedRows.value.length) { proxy.$modal.msgWarning("请选择要删除的数据"); return; }
|
proxy.$modal.confirm("是否确认删除所选数据项?").then(() => delTimingTask(selectedRows.value.map(item => item.id)))
|
.then(() => { proxy.$modal.msgSuccess("删除成功"); handleQuery(); }).catch(() => {});
|
};
|
|
const handleSelectionChange = selection => { selectedRows.value = selection; };
|
|
const handleOut = () => {
|
ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning" })
|
.then(() => {
|
if (activeRadio.value === "taskManage") proxy.download("/timingTask/export", {}, "巡检任务.xlsx");
|
else proxy.download("/inspectionTask/export", {}, "巡检记录.xlsx");
|
}).catch(() => { proxy.$modal.msg("已取消"); });
|
};
|
</script>
|
|
<style scoped>
|
.person-tags { display: flex; flex-wrap: wrap; gap: 4px; }
|
.person-tag { margin-right: 4px; margin-bottom: 2px; }
|
.no-data { color: #909399; font-size: 14px; }
|
</style>
|