| src/api/safeProduction/lineInspection.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/api/safeProduction/safetyFacility.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/safeProduction/lineInspection/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/safeProduction/safetyFacility/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/safeProduction/lineInspection.js
@@ -7,36 +7,119 @@ // 获取线路巡检列表 export function getLineInspectionList(params) { return request({ url: "/device/lineInspection/list", url: "/safeLineInspection/page", method: "get", params, }); } // 新增或修改线路巡检记录 export function addOrEditLineInspection(data) { // 根据ID获取线路巡检详情 export function getLineInspectionById(id) { return request({ url: "/device/lineInspection/addOrEdit", url: `/safeLineInspection/${id}`, method: "get", }); } // 新增线路巡检 export function addLineInspection(data) { return request({ url: "/safeLineInspection", method: "post", data, }); } // 删除线路巡检记录 export function deleteLineInspection(ids) { // 修改线路巡检 export function updateLineInspection(data) { return request({ url: "/device/lineInspection/delete", method: "delete", data: ids, url: "/safeLineInspection", method: "put", data, }); } // 导出线路巡检记录 export function exportLineInspection(params) { // 删除线路巡检 export function deleteLineInspection(ids) { return request({ url: "/device/lineInspection/export", url: "/safeLineInspection/" + ids.join(","), method: "delete", }); } // 完成巡检 export function completeLineInspection(id) { return request({ url: `/safeLineInspection/complete/${id}`, method: "put", }); } // 获取巡检记录列表 export function getInspectionRecords(inspectionId) { return request({ url: `/safeLineInspectionRecord/list/${inspectionId}`, method: "get", }); } // 新增巡检记录 export function addInspectionRecord(data) { return request({ url: "/safeLineInspectionRecord", method: "post", data, }); } // 批量新增巡检记录 export function batchAddInspectionRecords(data) { return request({ url: "/safeLineInspectionRecord/batch", method: "post", data, }); } // 获取巡检隐患列表 export function getInspectionHazards(params) { return request({ url: "/safeLineInspectionHazard/page", method: "get", params, responseType: 'blob', }); } // 根据巡检任务ID获取隐患列表 export function getHazardsByInspectionId(inspectionId) { return request({ url: `/safeLineInspectionHazard/list/${inspectionId}`, method: "get", }); } // 新增隐患 export function addInspectionHazard(data) { return request({ url: "/safeLineInspectionHazard", method: "post", data, }); } // 修改隐患 export function updateInspectionHazard(data) { return request({ url: "/safeLineInspectionHazard", method: "put", data, }); } // 删除隐患 export function deleteInspectionHazard(ids) { return request({ url: "/safeLineInspectionHazard/" + ids.join(","), method: "delete", }); } src/api/safeProduction/safetyFacility.js
@@ -4,39 +4,137 @@ * 安全设施巡检API接口 */ // 获取安全设施列表 export function getSafetyFacilityList(params) { // ============ 安全设施台账 ============ // 获取安全设施台账列表 export function getFacilityLedgerList(params) { return request({ url: "/device/safetyFacility/list", url: "/safeFacilityLedger/page", method: "get", params, }); } // 新增或修改安全设施 export function addOrEditSafetyFacility(data) { // 根据ID获取安全设施台账详情 export function getFacilityLedgerById(id) { return request({ url: "/device/safetyFacility/addOrEdit", url: `/safeFacilityLedger/${id}`, method: "get", }); } // 新增安全设施台账 export function addFacilityLedger(data) { return request({ url: "/safeFacilityLedger", method: "post", data, }); } // 删除安全设施 export function deleteSafetyFacility(ids) { // 修改安全设施台账 export function updateFacilityLedger(data) { return request({ url: "/device/safetyFacility/delete", method: "delete", data: ids, url: "/safeFacilityLedger", method: "put", data, }); } // 导出安全设施记录 export function exportSafetyFacility(params) { // 删除安全设施台账 export function deleteFacilityLedger(ids) { return request({ url: "/device/safetyFacility/export", method: "post", url: "/safeFacilityLedger/" + ids.join(","), method: "delete", }); } // ============ 安全设施巡检 ============ // 获取安全设施巡检列表 export function getFacilityInspectionList(params) { return request({ url: "/safeFacilityInspection/page", method: "get", params, responseType: 'blob', }); } // 根据ID获取安全设施巡检详情 export function getFacilityInspectionById(id) { return request({ url: `/safeFacilityInspection/${id}`, method: "get", }); } // 新增安全设施巡检 export function addFacilityInspection(data) { return request({ url: "/safeFacilityInspection", method: "post", data, }); } // 修改安全设施巡检 export function updateFacilityInspection(data) { return request({ url: "/safeFacilityInspection", method: "put", data, }); } // 删除安全设施巡检 export function deleteFacilityInspection(ids) { return request({ url: "/safeFacilityInspection/" + ids.join(","), method: "delete", }); } // ============ 安全设施整改 ============ // 获取安全设施整改列表 export function getFacilityRectificationList(params) { return request({ url: "/safeFacilityRectification/page", method: "get", params, }); } // 根据ID获取安全设施整改详情 export function getFacilityRectificationById(id) { return request({ url: `/safeFacilityRectification/${id}`, method: "get", }); } // 新增安全设施整改 export function addFacilityRectification(data) { return request({ url: "/safeFacilityRectification", method: "post", data, }); } // 修改安全设施整改 export function updateFacilityRectification(data) { return request({ url: "/safeFacilityRectification", method: "put", data, }); } // 删除安全设施整改 export function deleteFacilityRectification(ids) { return request({ url: "/safeFacilityRectification/" + ids.join(","), method: "delete", }); } src/views/safeProduction/lineInspection/index.vue
@@ -1,374 +1,918 @@ <template> <div class="line-inspection"> <!-- 搜索区域 --> <div class="search-area"> <el-form :inline="true" :model="searchForm"> <el-form-item label="任务名称"> <el-input v-model="searchForm.taskName" placeholder="请输入任务名称" clearable /> </el-form-item> <el-form-item label="线路名称"> <el-input v-model="searchForm.routeName" placeholder="请输入线路名称" clearable /> </el-form-item> <el-form-item label="巡检人"> <el-input v-model="searchForm.inspector" placeholder="请输入巡检人" clearable /> </el-form-item> <el-form-item label="状态"> <el-select v-model="searchForm.status" placeholder="请选择状态" clearable> <el-option label="待巡检" value="待巡检" /> <el-option label="进行中" value="进行中" /> <el-option label="已完成" value="已完成" /> </el-select> </el-form-item> <el-form-item> <el-button type="primary" @click="handleSearch">搜索</el-button> <el-button @click="resetSearch">重置</el-button> </el-form-item> </el-form> <div class="app-container"> <div class="search_form mb20"> <div> <span class="search_title">巡检编号:</span> <el-input v-model="searchForm.inspectionCode" style="width: 200px" placeholder="请输入巡检编号" @change="handleQuery" clearable :prefix-icon="Search" /> <span class="search_title ml10">巡检名称:</span> <el-input v-model="searchForm.inspectionName" style="width: 200px" placeholder="请输入巡检名称" @change="handleQuery" clearable :prefix-icon="Search" /> <span class="search_title ml10">线路名称:</span> <el-input v-model="searchForm.lineName" style="width: 200px" placeholder="请输入线路名称" @change="handleQuery" clearable :prefix-icon="Search" /> <span class="search_title ml10">状态:</span> <el-select v-model="searchForm.status" clearable @change="handleQuery" style="width: 150px"> <el-option label="待巡检" value="待巡检" /> <el-option label="巡检中" value="巡检中" /> <el-option label="已完成" value="已完成" /> </el-select> <el-button type="primary" @click="handleQuery" style="margin-left: 10px"> 搜索 </el-button> </div> <div> <el-button type="primary" @click="openForm('add')">新增巡检任务</el-button> </div> </div> <!-- 操作按钮 --> <div class="actions"> <el-button type="primary" @click="handleAdd">新增巡检</el-button> <el-button type="success" @click="handleExport">导出</el-button> <div class="table_list"> <PIMTable rowKey="id" :column="tableColumn" :tableData="tableData" :page="page" :isSelection="true" @selection-change="handleSelectionChange" :tableLoading="tableLoading" @pagination="pagination" :total="page.total"></PIMTable> </div> <!-- 巡检列表 --> <el-table :data="inspectionList" style="width: 100%; margin-top: 10px;" border> <el-table-column prop="taskName" label="任务名称" width="180" /> <el-table-column prop="routeName" label="线路名称" width="180" /> <el-table-column prop="deviceName" label="关联设备" width="150" /> <el-table-column prop="inspector" label="巡检人" width="120" /> <el-table-column prop="inspectionTime" label="巡检时间" width="180" /> <el-table-column prop="inspectionResult" label="巡检结果" width="120"> <template #default="{ row }"> <el-tag :type="row.inspectionResult === '正常' ? 'success' : 'danger'"> {{ row.inspectionResult || '未巡检' }} </el-tag> </template> </el-table-column> <el-table-column prop="status" label="状态" width="120"> <template #default="{ row }"> <el-tag :type="getStatusType(row.status)"> {{ row.status }} </el-tag> </template> </el-table-column> <el-table-column label="操作" width="200" fixed="right"> <template #default="{ row }"> <el-button type="primary" link @click="handleEdit(row)">编辑</el-button> <el-button type="danger" link @click="handleDelete(row)">删除</el-button> </template> </el-table-column> </el-table> <!-- 分页 --> <div class="pagination"> <el-pagination v-model:current-page="pagination.currentPage" v-model:page-size="pagination.pageSize" :page-sizes="[10, 20, 50, 100]" :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> <!-- 新增/编辑对话框 --> <el-dialog :title="dialogTitle" v-model="showDialog" width="600px"> <el-form :model="form" :rules="formRules" ref="formRef" label-width="100px"> <el-form-item label="任务名称" prop="taskName"> <el-input v-model="form.taskName" placeholder="请输入任务名称" /> </el-form-item> <el-form-item label="线路名称" prop="routeName"> <el-input v-model="form.routeName" placeholder="请输入线路名称" /> </el-form-item> <el-form-item label="关联设备"> <el-select v-model="form.deviceId" placeholder="请选择设备" clearable> <el-option v-for="item in deviceOptions" :key="item.id" :label="item.deviceName" :value="item.id" /> </el-select> </el-form-item> <el-form-item label="巡检人" prop="inspector"> <el-input v-model="form.inspector" placeholder="请输入巡检人" /> </el-form-item> <el-form-item label="巡检时间"> <el-date-picker v-model="form.inspectionTime" type="datetime" placeholder="请选择巡检时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" /> </el-form-item> <el-form-item label="巡检结果"> <el-radio-group v-model="form.inspectionResult"> <el-radio label="正常">正常</el-radio> <el-radio label="异常">异常</el-radio> </el-radio-group> </el-form-item> <el-form-item label="隐患描述" v-if="form.inspectionResult === '异常'"> <el-input type="textarea" v-model="form.hazardDescription" placeholder="请输入隐患描述" /> </el-form-item> <el-form-item label="备注"> <el-input type="textarea" v-model="form.remarks" placeholder="请输入备注" /> <!-- 新增/编辑巡检任务弹窗 --> <el-dialog v-model="dialogVisible" :title="dialogTitle" width="800px" :close-on-click-modal="false"> <el-form ref="formRef" :model="form" :rules="rules" label-width="120px"> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="巡检编号" prop="inspectionCode"> <el-input v-model="form.inspectionCode" placeholder="请输入巡检编号" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="巡检名称" prop="inspectionName"> <el-input v-model="form.inspectionName" placeholder="请输入巡检名称" /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="线路名称" prop="lineName"> <el-input v-model="form.lineName" placeholder="请输入线路名称" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="巡检类型" prop="inspectionType"> <el-select v-model="form.inspectionType" placeholder="请选择巡检类型" style="width: 100%"> <el-option label="定期巡检" value="定期巡检" /> <el-option label="临时巡检" value="临时巡检" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="计划巡检时间" prop="planTime"> <el-date-picker v-model="form.planTime" type="datetime" placeholder="请选择计划巡检时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="巡检人" prop="inspectorId"> <el-select v-model="form.inspectorIds" placeholder="请选择巡检人(可多选)" filterable multiple collapse-tags collapse-tags-tooltip clearable style="width: 100%"> <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> </el-select> </el-form-item> </el-col> </el-row> <el-form-item label="备注" prop="remark"> <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" /> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button type="primary" @click="submitForm">确定</el-button> <el-button @click="showDialog = false">取消</el-button> <el-button type="primary" @click="submitForm">确定</el-button> <el-button @click="dialogVisible = false">取消</el-button> </span> </template> </el-dialog> <!-- 巡检记录弹窗 --> <el-dialog ref="recordDialogRef" v-model="recordDialogVisible" title="巡检记录" width="70vw" :close-on-click-modal="false" @open="onRecordDialogOpen"> <div class="mb10"> <el-button type="primary" size="small" @click="openRecordForm">新增记录</el-button> </div> <div class="dialog-table-wrapper"> <el-table :data="recordList" border style="width: 100%"> <el-table-column prop="checkPoint" label="检查点" width="150" show-overflow-tooltip /> <el-table-column prop="checkContent" label="检查内容" min-width="200" show-overflow-tooltip /> <el-table-column prop="checkResult" label="检查结果" width="100"> <template #default="{ row }"> <el-tag :type="row.checkResult === '正常' ? 'success' : 'danger'"> {{ row.checkResult }} </el-tag> </template> </el-table-column> <el-table-column prop="checkDesc" label="检查说明" width="200" show-overflow-tooltip /> <el-table-column prop="checkTime" label="检查时间" width="180" /> </el-table> </div> <!-- 新增记录表单 --> <el-dialog v-model="recordFormVisible" title="新增巡检记录" width="600px" append-to-body :close-on-click-modal="false"> <el-form ref="recordFormRef" :model="recordForm" :rules="recordRules" label-width="100px"> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="检查点" prop="checkPoint"> <el-input v-model="recordForm.checkPoint" placeholder="请输入检查点" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="检查结果" prop="checkResult"> <el-radio-group v-model="recordForm.checkResult"> <el-radio label="正常">正常</el-radio> <el-radio label="异常">异常</el-radio> </el-radio-group> </el-form-item> </el-col> </el-row> <el-form-item label="检查内容" prop="checkContent"> <el-input v-model="recordForm.checkContent" type="textarea" :rows="3" placeholder="请输入检查内容" /> </el-form-item> <el-form-item label="检查说明"> <el-input v-model="recordForm.checkDesc" type="textarea" :rows="2" placeholder="请输入检查说明" /> </el-form-item> <el-form-item label="检查时间"> <el-date-picker v-model="recordForm.checkTime" type="datetime" placeholder="请选择检查时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" /> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button type="primary" @click="submitRecordForm">确定</el-button> <el-button @click="recordFormVisible = false">取消</el-button> </span> </template> </el-dialog> </el-dialog> <!-- 隐患管理弹窗 --> <el-dialog ref="hazardDialogRef" v-model="hazardDialogVisible" title="隐患管理" width="75vw" :close-on-click-modal="false" @open="onHazardDialogOpen"> <div class="mb10"> <el-button type="primary" size="small" @click="openHazardForm('add')">上报隐患</el-button> </div> <div class="dialog-table-wrapper"> <el-table :data="hazardList" border style="width: 100%"> <el-table-column prop="hazardCode" label="隐患编号" width="120" show-overflow-tooltip /> <el-table-column prop="hazardDesc" label="隐患描述" min-width="200" show-overflow-tooltip /> <el-table-column prop="hazardLevel" label="隐患等级" width="100"> <template #default="{ row }"> <el-tag :type="row.hazardLevel === '重大' ? 'danger' : 'warning'"> {{ row.hazardLevel }} </el-tag> </template> </el-table-column> <el-table-column prop="hazardLocation" label="隐患位置" width="150" show-overflow-tooltip /> <el-table-column prop="status" label="状态" width="100"> <template #default="{ row }"> <el-tag :type="getHazardStatusType(row.status)"> {{ row.status }} </el-tag> </template> </el-table-column> <el-table-column prop="rectifyUserName" label="整改责任人" width="120" /> <el-table-column label="操作" width="150" fixed="right"> <template #default="{ row }"> <el-button type="primary" link @click="openHazardForm('edit', row)">编辑</el-button> <el-button type="success" link @click="handleRectify(row)" v-if="row.status !== '已整改'">整改</el-button> </template> </el-table-column> </el-table> </div> <!-- 隐患表单 --> <el-dialog v-model="hazardFormVisible" :title="hazardDialogTitle" width="600px" append-to-body :close-on-click-modal="false"> <el-form ref="hazardFormRef" :model="hazardForm" :rules="hazardRules" label-width="100px"> <el-form-item label="隐患描述" prop="hazardDesc"> <el-input v-model="hazardForm.hazardDesc" type="textarea" :rows="3" placeholder="请输入隐患描述" /> </el-form-item> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="隐患等级" prop="hazardLevel"> <el-select v-model="hazardForm.hazardLevel" placeholder="请选择隐患等级" style="width: 100%"> <el-option label="一般" value="一般" /> <el-option label="重大" value="重大" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="隐患位置" prop="hazardLocation"> <el-input v-model="hazardForm.hazardLocation" placeholder="请输入隐患位置" /> </el-form-item> </el-col> </el-row> </el-form> <template #footer> <span class="dialog-footer"> <el-button type="primary" @click="submitHazardForm">确定</el-button> <el-button @click="hazardFormVisible = false">取消</el-button> </span> </template> </el-dialog> <!-- 整改表单 --> <el-dialog v-model="rectifyFormVisible" title="整改" width="500px" append-to-body :close-on-click-modal="false"> <el-form ref="rectifyFormRef" :model="rectifyForm" label-width="100px"> <el-form-item label="整改说明" prop="rectifyDesc"> <el-input v-model="rectifyForm.rectifyDesc" type="textarea" :rows="4" placeholder="请输入整改说明" /> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button type="primary" @click="submitRectifyForm">确定</el-button> <el-button @click="rectifyFormVisible = false">取消</el-button> </span> </template> </el-dialog> </el-dialog> </div> </template> <script setup> import { ref, reactive, onMounted } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' import { Search } from "@element-plus/icons-vue"; import { nextTick, onMounted, ref, reactive, toRefs } from "vue"; import { ElMessage, ElMessageBox } from "element-plus"; import PIMTable from "@/components/PIMTable/PIMTable.vue"; import { userListNoPage } from "@/api/system/user.js"; import { getLineInspectionList, addOrEditLineInspection, addLineInspection, updateLineInspection, deleteLineInspection, exportLineInspection } from '@/api/safeProduction/lineInspection' import { getDeviceLedger } from '@/api/equipmentManagement/ledger' // 搜索表单 const searchForm = reactive({ taskName: '', routeName: '', inspector: '', status: '' }) // 分页数据 const pagination = reactive({ currentPage: 1, pageSize: 10, total: 0 }) // 列表数据 const inspectionList = ref([]) // 设备选项 const deviceOptions = ref([]) // 对话框状态 const showDialog = ref(false) const dialogTitle = ref('新增巡检') // 表单数据 const form = reactive({ id: null, taskName: '', routeName: '', deviceId: null, inspector: '', inspectionTime: '', inspectionResult: '', hazardDescription: '', remarks: '' }) completeLineInspection, getInspectionRecords, addInspectionRecord, getHazardsByInspectionId, addInspectionHazard, updateInspectionHazard } from "@/api/safeProduction/lineInspection"; // 表单验证规则 const formRules = reactive({ taskName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }], routeName: [{ required: true, message: '请输入线路名称', trigger: 'blur' }], inspector: [{ required: true, message: '请输入巡检人', trigger: 'blur' }] }) const rules = { inspectionCode: [{ required: true, message: "请输入巡检编号", trigger: "blur" }], inspectionName: [{ required: true, message: "请输入巡检名称", trigger: "blur" }], lineName: [{ required: true, message: "请输入线路名称", trigger: "blur" }] }; const formRef = ref(null) const recordRules = { checkPoint: [{ required: true, message: "请输入检查点", trigger: "blur" }], checkContent: [{ required: true, message: "请输入检查内容", trigger: "blur" }], checkResult: [{ required: true, message: "请选择检查结果", trigger: "change" }] }; // 获取状态标签类型 const getStatusType = (status) => { const map = { '待巡检': 'info', '进行中': 'warning', '已完成': 'success' } return map[status] || 'info' } const hazardRules = { hazardDesc: [{ required: true, message: "请输入隐患描述", trigger: "blur" }], hazardLevel: [{ required: true, message: "请选择隐患等级", trigger: "change" }], hazardLocation: [{ required: true, message: "请输入隐患位置", trigger: "blur" }] }; // 获取巡检列表 const fetchList = async () => { try { const params = { ...searchForm, current: pagination.currentPage, size: pagination.pageSize } const res = await getLineInspectionList(params) if (res.code === 200) { inspectionList.value = res.data.records || [] pagination.total = res.data.total || 0 } else { ElMessage.error(res.message || '获取列表失败') } } catch (error) { ElMessage.error('获取列表失败') } } // 获取设备列表 const fetchDeviceOptions = async () => { try { const res = await getDeviceLedger() if (res.code === 200) { deviceOptions.value = res.data || [] } } catch (error) { console.error('获取设备列表失败') } } // 搜索 const handleSearch = () => { pagination.currentPage = 1 fetchList() } // 重置搜索 const resetSearch = () => { Object.assign(searchForm, { taskName: '', routeName: '', inspector: '', status: '' }) handleSearch() } // 新增 const handleAdd = () => { dialogTitle.value = '新增巡检' Object.assign(form, { // 响应式数据 const data = reactive({ searchForm: { inspectionCode: "", inspectionName: "", lineName: "", status: "" }, tableLoading: false, page: { current: 1, size: 20, total: 0 }, tableData: [], selectedIds: [], form: { id: null, taskName: '', routeName: '', deviceId: null, inspector: '', inspectionTime: '', inspectionResult: '', hazardDescription: '', remarks: '' }) showDialog.value = true } // 编辑 const handleEdit = (row) => { dialogTitle.value = '编辑巡检' Object.assign(form, { id: row.id, taskName: row.taskName, routeName: row.routeName, deviceId: row.deviceId, inspector: row.inspector, inspectionTime: row.inspectionTime, inspectionResult: row.inspectionResult, hazardDescription: row.hazardDescription, remarks: row.remarks }) showDialog.value = true } // 删除 const handleDelete = async (row) => { try { await ElMessageBox.confirm('确认删除该巡检记录吗?', '提示', { type: 'warning' }) const res = await deleteLineInspection([row.id]) if (res.code === 200) { ElMessage.success('删除成功') fetchList() } else { ElMessage.error(res.message || '删除失败') } } catch (error) { // 取消删除 inspectionCode: "", inspectionName: "", lineName: "", inspectionType: "", planTime: "", inspectorId: "", inspectorIds: [], remark: "" }, dialogVisible: false, dialogTitle: "", dialogType: "add", // 巡检记录 currentInspectionId: null, recordDialogVisible: false, recordFormVisible: false, recordList: [], recordForm: { inspectionId: null, checkPoint: "", checkContent: "", checkResult: "正常", checkDesc: "", checkTime: "" }, // 隐患管理 hazardDialogVisible: false, hazardFormVisible: false, hazardDialogTitle: "上报隐患", hazardList: [], hazardForm: { id: null, inspectionId: null, hazardDesc: "", hazardLevel: "", hazardLocation: "" }, rectifyFormVisible: false, rectifyForm: { id: null, rectifyDesc: "" } } }); const { searchForm, tableLoading, page, tableData, selectedIds, form, dialogVisible, dialogTitle, dialogType, currentInspectionId, recordDialogVisible, recordFormVisible, recordList, recordForm, hazardDialogVisible, hazardFormVisible, hazardDialogTitle, hazardList, hazardForm, rectifyFormVisible, rectifyForm } = toRefs(data); // 表单引用 const formRef = ref(); const recordFormRef = ref(); const hazardFormRef = ref(); const rectifyFormRef = ref(); const userList = ref([]); // 表格列配置 const tableColumn = ref([ { label: "巡检编号", prop: "inspectionCode", showOverflowTooltip: true, minWidth: 150 }, { label: "巡检名称", prop: "inspectionName", showOverflowTooltip: true, minWidth: 180 }, { label: "线路名称", prop: "lineName", showOverflowTooltip: true, minWidth: 150 }, { label: "巡检类型", prop: "inspectionType", showOverflowTooltip: true, minWidth: 100 }, { label: "计划巡检时间", prop: "planTime", showOverflowTooltip: true, minWidth: 180 }, { label: "巡检人", prop: "inspectorName", showOverflowTooltip: true, minWidth: 100 }, { label: "状态", prop: "status", minWidth: 100, dataType: "tag", formatType: params => { const typeMap = { 待巡检: "info", 巡检中: "warning", 已完成: "success" }; return typeMap[params] || "info"; } }, { dataType: "action", label: "操作", align: "center", fixed: "right", width: 350, operation: [ { name: "编辑", type: "text", clickFun: row => { openForm("edit", row); }, show: row => row.status === "待巡检" }, { name: "巡检记录", type: "text", clickFun: row => { openRecordDialog(row); } }, { name: "隐患管理", type: "text", clickFun: row => { openHazardDialog(row); } }, { name: "完成巡检", type: "text", style: { color: "#67C23A" }, clickFun: row => { handleComplete(row); }, show: row => row.status === "巡检中" }, { name: "删除", type: "text", style: { color: "#F56C6C" }, clickFun: row => { handleDelete(row); }, show: row => row.status === "待巡检" } ] } ]); // 生命周期 onMounted(() => { getList(); userListNoPage().then(res => { userList.value = res.data; }); }); // 弹窗固定高度处理 const setDialogFixedHeight = () => { setTimeout(() => { // 直接在 body 上找所有 el-dialog(teleport 渲染到 body) const dialogs = document.body.querySelectorAll('.el-dialog'); const dialog = dialogs[dialogs.length - 1]; // 最后一个就是刚打开的 if (!dialog) return; Object.assign(dialog.style, { height: '70vh', maxHeight: '70vh', overflow: 'hidden', display: 'flex', flexDirection: 'column' }); const body = dialog.querySelector('.el-dialog__body'); if (body) { Object.assign(body.style, { flex: '1', overflow: 'hidden' }); } const wrapper = dialog.querySelector('.dialog-table-wrapper'); if (wrapper) { Object.assign(wrapper.style, { flex: '1', overflowY: 'auto' }); } }, 100); }; const recordDialogRef = ref(null); const hazardDialogRef = ref(null); const onRecordDialogOpen = () => setDialogFixedHeight(); const onHazardDialogOpen = () => setDialogFixedHeight(); const handleQuery = () => { page.value.current = 1; getList(); }; const getList = () => { tableLoading.value = true; getLineInspectionList({ ...page.value, ...searchForm.value }) .then(res => { tableLoading.value = false; tableData.value = res.data.records; page.value.total = res.data.total; }) .catch(() => { tableLoading.value = false; }); }; // 分页处理 const pagination = obj => { page.value.current = obj.page; page.value.size = obj.limit; getList(); }; // 选择变化处理 const handleSelectionChange = selection => { selectedIds.value = selection.map(item => item.id); }; // 获取隐患状态类型 const getHazardStatusType = status => { const map = { 待整改: "danger", 整改中: "warning", 已整改: "success" }; return map[status] || "info"; }; // 打开表单 const openForm = (type, row = null) => { dialogType.value = type; if (type === "add") { dialogTitle.value = "新增巡检任务"; Object.assign(form.value, { id: null, inspectionCode: "", inspectionName: "", lineName: "", inspectionType: "", planTime: "", inspectorId: "", inspectorIds: [], remark: "" }); } else if (type === "edit" && row) { dialogTitle.value = "编辑巡检任务"; // 将逗号分隔的ID字符串转换为数组 const inspectorIds = row.inspectorId ? row.inspectorId.split(",").map(id => parseInt(id.trim())).filter(id => !isNaN(id)) : []; Object.assign(form.value, { id: row.id, inspectionCode: row.inspectionCode, inspectionName: row.inspectionName, lineName: row.lineName, inspectionType: row.inspectionType, planTime: row.planTime, inspectorId: row.inspectorId, inspectorIds: inspectorIds, remark: row.remark }); } dialogVisible.value = true; }; // 提交表单 const submitForm = async () => { if (!formRef.value) return try { await formRef.value.validate() const res = await addOrEditLineInspection(form) await formRef.value.validate(); // 将数组转换为逗号分隔的字符串 const submitData = { ...form.value, inspectorId: form.value.inspectorIds ? form.value.inspectorIds.join(",") : "" }; delete submitData.inspectorIds; const api = dialogType.value === "add" ? addLineInspection : updateLineInspection; const res = await api(submitData); if (res.code === 200) { ElMessage.success('操作成功') showDialog.value = false fetchList() ElMessage.success(dialogType.value === "add" ? "添加成功" : "更新成功"); dialogVisible.value = false; getList(); } else { ElMessage.error(res.message || '操作失败') ElMessage.error(res.msg || "操作失败"); } } catch (error) { ElMessage.error('请填写完整表单信息') console.error("表单验证失败:", error); } } }; // 导出 const handleExport = async () => { // 删除 const handleDelete = row => { ElMessageBox.confirm("确认删除该巡检任务吗?", "删除", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning" }) .then(async () => { const res = await deleteLineInspection([row.id]); if (res.code === 200) { ElMessage.success("删除成功"); getList(); } else { ElMessage.error(res.msg || "删除失败"); } }) .catch(() => {}); }; // 完成巡检 const handleComplete = row => { ElMessageBox.confirm("确认完成该巡检任务吗?", "完成巡检", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning" }) .then(async () => { const res = await completeLineInspection(row.id); if (res.code === 200) { ElMessage.success("巡检已完成"); getList(); } else { ElMessage.error(res.msg || "操作失败"); } }) .catch(() => {}); }; // 打开巡检记录弹窗 const openRecordDialog = row => { currentInspectionId.value = row.id; fetchRecords(row.id); recordDialogVisible.value = true; }; // 获取巡检记录 const fetchRecords = async inspectionId => { const res = await getInspectionRecords(inspectionId); if (res.code === 200) { recordList.value = res.data || []; } }; // 打开记录表单 const openRecordForm = () => { Object.assign(recordForm.value, { inspectionId: currentInspectionId.value, checkPoint: "", checkContent: "", checkResult: "正常", checkDesc: "", checkTime: "" }); recordFormVisible.value = true; }; // 提交记录表单 const submitRecordForm = async () => { try { const res = await exportLineInspection(searchForm) const blob = new Blob([res]) const url = window.URL.createObjectURL(blob) const link = document.createElement('a') link.href = url link.download = '线路巡检记录.xlsx' link.click() window.URL.revokeObjectURL(url) ElMessage.success('导出成功') await recordFormRef.value.validate(); const res = await addInspectionRecord({ ...recordForm.value }); if (res.code === 200) { ElMessage.success("添加成功"); recordFormVisible.value = false; fetchRecords(currentInspectionId.value); } else { ElMessage.error(res.msg || "添加失败"); } } catch (error) { ElMessage.error('导出失败') console.error("表单验证失败:", error); } } }; // 分页大小改变 const handleSizeChange = (val) => { pagination.pageSize = val fetchList() } // 打开隐患管理弹窗 const openHazardDialog = row => { currentInspectionId.value = row.id; fetchHazards(row.id); hazardDialogVisible.value = true; }; // 当前页改变 const handleCurrentChange = (val) => { pagination.currentPage = val fetchList() } // 获取隐患列表 const fetchHazards = async inspectionId => { const res = await getHazardsByInspectionId(inspectionId); if (res.code === 200) { hazardList.value = res.data || []; } }; onMounted(() => { fetchList() fetchDeviceOptions() }) // 打开隐患表单 const openHazardForm = (type, row = null) => { if (type === "add") { hazardDialogTitle.value = "上报隐患"; Object.assign(hazardForm.value, { id: null, inspectionId: currentInspectionId.value, hazardDesc: "", hazardLevel: "", hazardLocation: "" }); } else { hazardDialogTitle.value = "编辑隐患"; Object.assign(hazardForm.value, { id: row.id, inspectionId: row.inspectionId, hazardDesc: row.hazardDesc, hazardLevel: row.hazardLevel, hazardLocation: row.hazardLocation }); } hazardFormVisible.value = true; }; // 提交隐患表单 const submitHazardForm = async () => { try { await hazardFormRef.value.validate(); const api = hazardForm.value.id ? updateInspectionHazard : addInspectionHazard; const res = await api({ ...hazardForm.value }); if (res.code === 200) { ElMessage.success("操作成功"); hazardFormVisible.value = false; fetchHazards(currentInspectionId.value); } else { ElMessage.error(res.msg || "操作失败"); } } catch (error) { console.error("表单验证失败:", error); } }; // 整改 const handleRectify = row => { Object.assign(rectifyForm.value, { id: row.id, rectifyDesc: "" }); rectifyFormVisible.value = true; }; // 提交整改表单 const submitRectifyForm = async () => { const res = await updateInspectionHazard({ id: rectifyForm.value.id, status: "已整改", rectifyDesc: rectifyForm.value.rectifyDesc }); if (res.code === 200) { ElMessage.success("整改成功"); rectifyFormVisible.value = false; fetchHazards(currentInspectionId.value); } else { ElMessage.error(res.msg || "整改失败"); } }; </script> <style scoped> .line-inspection { padding: 20px; .search_title { font-size: 14px; color: #606266; } .search-area { background: #f5f7fa; padding: 20px; border-radius: 4px; margin-bottom: 15px; .mb10 { margin-bottom: 10px; } .actions { margin-bottom: 15px; .mb20 { margin-bottom: 20px; } .pagination { margin-top: 20px; display: flex; justify-content: flex-end; .ml10 { margin-left: 10px; } </style> src/views/safeProduction/safetyFacility/index.vue
@@ -1,151 +1,367 @@ <template> <div class="safety-facility"> <!-- 搜索区域 --> <div class="search-area"> <el-form :inline="true" :model="searchForm"> <el-form-item label="设施名称"> <el-input v-model="searchForm.facilityName" placeholder="请输入设施名称" clearable /> </el-form-item> <el-form-item label="设施类型"> <el-select v-model="searchForm.facilityType" placeholder="请选择类型" clearable> <el-option label="消防器材" value="消防器材" /> <el-option label="安全设备" value="安全设备" /> <el-option label="防护用品" value="防护用品" /> <el-option label="监控设备" value="监控设备" /> </el-select> </el-form-item> <el-form-item label="状态"> <el-select v-model="searchForm.status" placeholder="请选择状态" clearable> <el-option label="正常" value="正常" /> <el-option label="异常" value="异常" /> <el-option label="停用" value="停用" /> </el-select> </el-form-item> <el-form-item> <el-button type="primary" @click="handleSearch">搜索</el-button> <el-button @click="resetSearch">重置</el-button> </el-form-item> </el-form> </div> <div class="app-container"> <el-tabs v-model="activeTab" @tab-click="handleTabClick"> <!-- 安全设施台账 --> <el-tab-pane label="安全设施台账" name="ledger"> <div class="search_form mb20"> <div> <span class="search_title">设施编号:</span> <el-input v-model="ledgerSearchForm.facilityCode" style="width: 200px" placeholder="请输入设施编号" @change="handleLedgerQuery" clearable :prefix-icon="Search" /> <span class="search_title ml10">设施名称:</span> <el-input v-model="ledgerSearchForm.facilityName" style="width: 200px" placeholder="请输入设施名称" @change="handleLedgerQuery" clearable :prefix-icon="Search" /> <span class="search_title ml10">设施类型:</span> <el-select v-model="ledgerSearchForm.facilityType" clearable @change="handleLedgerQuery" style="width: 150px"> <el-option label="消防器材" value="消防器材" /> <el-option label="安全设备" value="安全设备" /> <el-option label="防护用品" value="防护用品" /> <el-option label="监控设备" value="监控设备" /> </el-select> <span class="search_title ml10">状态:</span> <el-select v-model="ledgerSearchForm.status" clearable @change="handleLedgerQuery" style="width: 120px"> <el-option label="正常" value="正常" /> <el-option label="异常" value="异常" /> <el-option label="报废" value="报废" /> </el-select> <el-button type="primary" @click="handleLedgerQuery" style="margin-left: 10px"> 搜索 </el-button> </div> <div> <el-button type="primary" @click="openLedgerForm('add')">新增设施</el-button> </div> </div> <!-- 操作按钮 --> <div class="actions"> <el-button type="primary" @click="handleAdd">新增设施</el-button> <el-button type="success" @click="handleExport">导出</el-button> </div> <div class="table_list"> <PIMTable rowKey="id" :column="ledgerTableColumn" :tableData="ledgerTableData" :page="ledgerPage" :isSelection="true" @selection-change="handleLedgerSelectionChange" :tableLoading="ledgerTableLoading" @pagination="ledgerPagination" :total="ledgerPage.total"></PIMTable> </div> </el-tab-pane> <!-- 设施列表 --> <el-table :data="facilityList" style="width: 100%; margin-top: 10px;" border> <el-table-column prop="facilityName" label="设施名称" width="180" /> <el-table-column prop="facilityType" label="设施类型" width="120" /> <el-table-column prop="location" label="所在位置" width="200" /> <el-table-column prop="deviceName" label="关联设备" width="150" /> <el-table-column prop="status" label="状态" width="100"> <template #default="{ row }"> <el-tag :type="getFacilityStatusType(row.status)"> {{ row.status }} </el-tag> </template> </el-table-column> <el-table-column prop="lastInspectionTime" label="上次巡检" width="180" /> <el-table-column prop="nextInspectionTime" label="下次巡检" width="180" /> <el-table-column prop="responsibilityPerson" label="责任人" width="120" /> <el-table-column label="操作" width="250" fixed="right"> <template #default="{ row }"> <el-button type="primary" link @click="handleEdit(row)">编辑</el-button> <el-button type="warning" link @click="handleInspection(row)">巡检</el-button> <el-button type="danger" link @click="handleDelete(row)">删除</el-button> </template> </el-table-column> </el-table> <!-- 安全设施巡检 --> <el-tab-pane label="安全设施巡检" name="inspection"> <div class="search_form mb20"> <div> <span class="search_title">巡检编号:</span> <el-input v-model="inspectionSearchForm.inspectionCode" style="width: 200px" placeholder="请输入巡检编号" @change="handleInspectionQuery" clearable :prefix-icon="Search" /> <span class="search_title ml10">状态:</span> <el-select v-model="inspectionSearchForm.status" clearable @change="handleInspectionQuery" style="width: 150px"> <el-option label="待巡检" value="待巡检" /> <el-option label="已巡检" value="已巡检" /> </el-select> <el-button type="primary" @click="handleInspectionQuery" style="margin-left: 10px"> 搜索 </el-button> </div> </div> <!-- 分页 --> <div class="pagination"> <el-pagination v-model:current-page="pagination.currentPage" v-model:page-size="pagination.pageSize" :page-sizes="[10, 20, 50, 100]" :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> <div class="table_list"> <PIMTable rowKey="id" :column="inspectionTableColumn" :tableData="inspectionTableData" :page="inspectionPage" :isSelection="false" :tableLoading="inspectionTableLoading" @pagination="inspectionPagination" :total="inspectionPage.total"></PIMTable> </div> </el-tab-pane> <!-- 新增/编辑对话框 --> <el-dialog :title="dialogTitle" v-model="showDialog" width="600px"> <el-form :model="form" :rules="formRules" ref="formRef" label-width="100px"> <el-form-item label="设施名称" prop="facilityName"> <el-input v-model="form.facilityName" placeholder="请输入设施名称" /> </el-form-item> <el-form-item label="设施类型" prop="facilityType"> <el-select v-model="form.facilityType" placeholder="请选择类型"> <el-option label="消防器材" value="消防器材" /> <el-option label="安全设备" value="安全设备" /> <el-option label="防护用品" value="防护用品" /> <el-option label="监控设备" value="监控设备" /> </el-select> </el-form-item> <el-form-item label="所在位置" prop="location"> <el-input v-model="form.location" placeholder="请输入所在位置" /> </el-form-item> <el-form-item label="关联设备"> <el-select v-model="form.deviceId" placeholder="请选择设备" clearable> <el-option v-for="item in deviceOptions" :key="item.id" :label="item.deviceName" :value="item.id" /> </el-select> </el-form-item> <el-form-item label="责任部门"> <el-input v-model="form.responsibilityDept" placeholder="请输入责任部门" /> </el-form-item> <el-form-item label="责任人"> <el-input v-model="form.responsibilityPerson" placeholder="请输入责任人" /> </el-form-item> <el-form-item label="下次巡检"> <el-date-picker v-model="form.nextInspectionTime" type="datetime" placeholder="请选择下次巡检时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" /> </el-form-item> <el-form-item label="备注"> <el-input type="textarea" v-model="form.remarks" placeholder="请输入备注" /> <!-- 整改跟踪 --> <el-tab-pane label="整改跟踪" name="rectification"> <div class="search_form mb20"> <div> <span class="search_title">状态:</span> <el-select v-model="rectificationSearchForm.status" clearable @change="handleRectificationQuery" style="width: 150px"> <el-option label="待整改" value="待整改" /> <el-option label="整改中" value="整改中" /> <el-option label="已整改" value="已整改" /> <el-option label="已验收" value="已验收" /> </el-select> <el-button type="primary" @click="handleRectificationQuery" style="margin-left: 10px"> 搜索 </el-button> </div> </div> <div class="table_list"> <PIMTable rowKey="id" :column="rectificationTableColumn" :tableData="rectificationTableData" :page="rectificationPage" :isSelection="false" :tableLoading="rectificationTableLoading" @pagination="rectificationPagination" :total="rectificationPage.total"></PIMTable> </div> </el-tab-pane> </el-tabs> <!-- 设施台账表单弹窗 --> <el-dialog v-model="ledgerDialogVisible" :title="ledgerDialogTitle" width="800px" :close-on-click-modal="false"> <el-form ref="ledgerFormRef" :model="ledgerForm" :rules="ledgerRules" label-width="120px"> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="设施编号" prop="facilityCode"> <el-input v-model="ledgerForm.facilityCode" placeholder="请输入设施编号" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="设施名称" prop="facilityName"> <el-input v-model="ledgerForm.facilityName" placeholder="请输入设施名称" /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="设施类型" prop="facilityType"> <el-select v-model="ledgerForm.facilityType" placeholder="请选择设施类型" style="width: 100%"> <el-option label="消防器材" value="消防器材" /> <el-option label="安全设备" value="安全设备" /> <el-option label="防护用品" value="防护用品" /> <el-option label="监控设备" value="监控设备" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="规格型号" prop="facilitySpec"> <el-input v-model="ledgerForm.facilitySpec" placeholder="请输入规格型号" /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="安装位置" prop="installLocation"> <el-input v-model="ledgerForm.installLocation" placeholder="请输入安装位置" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="安装时间" prop="installTime"> <el-date-picker v-model="ledgerForm.installTime" type="date" placeholder="请选择安装时间" format="YYYY-MM-DD" value-format="YYYY-MM-DD" style="width: 100%" /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="生产日期" prop="productionDate"> <el-date-picker v-model="ledgerForm.productionDate" type="date" placeholder="请选择生产日期" format="YYYY-MM-DD" value-format="YYYY-MM-DD" style="width: 100%" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="有效期(天)" prop="validPeriod"> <el-input-number v-model="ledgerForm.validPeriod" :min="0" placeholder="请输入有效期" style="width: 100%" /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="状态" prop="status"> <el-select v-model="ledgerForm.status" placeholder="请选择状态" style="width: 100%"> <el-option label="正常" value="正常" /> <el-option label="异常" value="异常" /> <el-option label="报废" value="报废" /> </el-select> </el-form-item> </el-col> </el-row> <el-form-item label="备注" prop="remark"> <el-input v-model="ledgerForm.remark" type="textarea" :rows="3" placeholder="请输入备注" /> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button type="primary" @click="submitForm">确定</el-button> <el-button @click="showDialog = false">取消</el-button> <el-button type="primary" @click="submitLedgerForm">确定</el-button> <el-button @click="ledgerDialogVisible = false">取消</el-button> </span> </template> </el-dialog> <!-- 巡检记录对话框 --> <el-dialog title="记录巡检结果" v-model="showInspectionDialog" width="500px"> <el-form :model="inspectionForm" label-width="100px"> <el-form-item label="设施名称"> <el-input v-model="inspectionForm.facilityName" disabled /> <!-- 巡检表单弹窗 --> <el-dialog v-model="inspectionDialogVisible" :title="inspectionDialogTitle" width="600px" :close-on-click-modal="false"> <el-form ref="inspectionFormRef" :model="inspectionForm" :rules="inspectionRules" label-width="120px"> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="巡检编号" prop="inspectionCode"> <el-input v-model="inspectionForm.inspectionCode" placeholder="请输入巡检编号" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="巡检类型" prop="inspectionType"> <el-select v-model="inspectionForm.inspectionType" placeholder="请选择巡检类型" style="width: 100%"> <el-option label="定期巡检" value="定期巡检" /> <el-option label="临时巡检" value="临时巡检" /> </el-select> </el-form-item> </el-col> </el-row> <el-form-item label="计划巡检时间" prop="planTime"> <el-date-picker v-model="inspectionForm.planTime" type="datetime" placeholder="请选择计划巡检时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" /> </el-form-item> <el-form-item label="巡检结果"> <el-radio-group v-model="inspectionForm.status"> <el-radio label="正常">正常</el-radio> <el-radio label="异常">异常</el-radio> </el-radio-group> <template v-if="inspectionDialogTitle === '巡检'"> <el-form-item label="检查结果" prop="checkResult"> <el-radio-group v-model="inspectionForm.checkResult"> <el-radio label="正常">正常</el-radio> <el-radio label="异常">异常</el-radio> </el-radio-group> </el-form-item> <el-form-item label="检查说明"> <el-input v-model="inspectionForm.checkDesc" type="textarea" :rows="3" placeholder="请输入检查说明" /> </el-form-item> </template> </el-form> <template #footer> <span class="dialog-footer"> <el-button type="primary" @click="submitInspectionForm">确定</el-button> <el-button @click="inspectionDialogVisible = false">取消</el-button> </span> </template> </el-dialog> <!-- 整改表单弹窗 --> <el-dialog v-model="rectificationDialogVisible" :title="rectificationDialogTitle" width="600px" :close-on-click-modal="false"> <el-form ref="rectificationFormRef" :model="rectificationForm" label-width="120px"> <template v-if="rectificationDialogTitle !== '验收'"> <el-form-item label="问题描述"> <el-input v-model="rectificationForm.problemDesc" type="textarea" :rows="3" placeholder="请输入问题描述" /> </el-form-item> <el-form-item label="问题等级"> <el-select v-model="rectificationForm.problemLevel" placeholder="请选择问题等级" style="width: 100%"> <el-option label="一般" value="一般" /> <el-option label="重大" value="重大" /> </el-select> </el-form-item> </template> <el-form-item label="整改说明" v-if="rectificationDialogTitle === '整改'"> <el-input v-model="rectificationForm.rectifyDesc" type="textarea" :rows="3" placeholder="请输入整改说明" /> </el-form-item> <el-form-item label="巡检说明" v-if="inspectionForm.status === '异常'"> <el-input type="textarea" v-model="inspectionForm.description" placeholder="请输入异常说明" /> <el-form-item label="验收说明" v-if="rectificationDialogTitle === '验收'"> <el-input v-model="rectificationForm.verifyDesc" type="textarea" :rows="3" placeholder="请输入验收说明" /> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button type="primary" @click="submitInspection">确定</el-button> <el-button @click="showInspectionDialog = false">取消</el-button> <el-button type="primary" @click="submitRectificationForm">确定</el-button> <el-button @click="rectificationDialogVisible = false">取消</el-button> </span> </template> </el-dialog> @@ -153,287 +369,442 @@ </template> <script setup> import { ref, reactive, onMounted } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' import { Search } from "@element-plus/icons-vue"; import { onMounted, ref, reactive, toRefs } from "vue"; import { ElMessage, ElMessageBox } from "element-plus"; import PIMTable from "@/components/PIMTable/PIMTable.vue"; import { getSafetyFacilityList, addOrEditSafetyFacility, deleteSafetyFacility, exportSafetyFacility } from '@/api/safeProduction/safetyFacility' import { getDeviceLedger } from '@/api/equipmentManagement/ledger' // 搜索表单 const searchForm = reactive({ facilityName: '', facilityType: '', status: '' }) // 分页数据 const pagination = reactive({ currentPage: 1, pageSize: 10, total: 0 }) // 列表数据 const facilityList = ref([]) // 设备选项 const deviceOptions = ref([]) // 对话框状态 const showDialog = ref(false) const dialogTitle = ref('新增设施') // 巡检对话框状态 const showInspectionDialog = ref(false) // 表单数据 const form = reactive({ id: null, facilityName: '', facilityType: '', location: '', deviceId: null, responsibilityDept: '', responsibilityPerson: '', nextInspectionTime: '', remarks: '' }) // 巡检表单数据 const inspectionForm = reactive({ id: null, facilityName: '', status: '正常', description: '' }) getFacilityLedgerList, addFacilityLedger, updateFacilityLedger, deleteFacilityLedger, getFacilityInspectionList, addFacilityInspection, updateFacilityInspection, deleteFacilityInspection, getFacilityRectificationList, addFacilityRectification, updateFacilityRectification } from "@/api/safeProduction/safetyFacility"; // 表单验证规则 const formRules = reactive({ facilityName: [{ required: true, message: '请输入设施名称', trigger: 'blur' }], facilityType: [{ required: true, message: '请选择设施类型', trigger: 'change' }], location: [{ required: true, message: '请输入所在位置', trigger: 'blur' }] }) const ledgerRules = { facilityCode: [{ required: true, message: "请输入设施编号", trigger: "blur" }], facilityName: [{ required: true, message: "请输入设施名称", trigger: "blur" }], facilityType: [{ required: true, message: "请选择设施类型", trigger: "change" }], installLocation: [{ required: true, message: "请输入安装位置", trigger: "blur" }] }; const formRef = ref(null) const inspectionRules = { inspectionCode: [{ required: true, message: "请输入巡检编号", trigger: "blur" }] }; // 获取状态标签类型 const getFacilityStatusType = (status) => { const map = { '正常': 'success', '异常': 'danger', '停用': 'info' } return map[status] || 'info' } // 响应式数据 const data = reactive({ activeTab: "ledger", // 设施台账 ledgerSearchForm: { facilityCode: "", facilityName: "", facilityType: "", status: "" }, ledgerTableLoading: false, ledgerPage: { current: 1, size: 20, total: 0 }, ledgerTableData: [], ledgerSelectedIds: [], ledgerForm: { id: null, facilityCode: "", facilityName: "", facilityType: "", facilitySpec: "", installLocation: "", installTime: "", productionDate: "", validPeriod: null, status: "正常", remark: "" }, ledgerDialogVisible: false, ledgerDialogTitle: "", ledgerDialogType: "add", // 巡检记录 inspectionSearchForm: { inspectionCode: "", status: "" }, inspectionTableLoading: false, inspectionPage: { current: 1, size: 20, total: 0 }, inspectionTableData: [], inspectionForm: { id: null, facilityId: null, inspectionCode: "", inspectionType: "定期巡检", planTime: "", checkResult: "", checkDesc: "" }, inspectionDialogVisible: false, inspectionDialogTitle: "", inspectionDialogType: "add", // 整改跟踪 rectificationSearchForm: { status: "" }, rectificationTableLoading: false, rectificationPage: { current: 1, size: 20, total: 0 }, rectificationTableData: [], rectificationForm: { id: null, inspectionId: null, facilityId: null, problemDesc: "", problemLevel: "", rectifyDesc: "", verifyDesc: "" }, rectificationDialogVisible: false, rectificationDialogTitle: "", rectificationDialogType: "add" }); // 获取设施列表 const fetchList = async () => { try { const params = { ...searchForm, current: pagination.currentPage, size: pagination.pageSize const { activeTab, ledgerSearchForm, ledgerTableLoading, ledgerPage, ledgerTableData, ledgerSelectedIds, ledgerForm, ledgerDialogVisible, ledgerDialogTitle, ledgerDialogType, inspectionSearchForm, inspectionTableLoading, inspectionPage, inspectionTableData, inspectionForm, inspectionDialogVisible, inspectionDialogTitle, inspectionDialogType, rectificationSearchForm, rectificationTableLoading, rectificationPage, rectificationTableData, rectificationForm, rectificationDialogVisible, rectificationDialogTitle, rectificationDialogType } = toRefs(data); // 表单引用 const ledgerFormRef = ref(); const inspectionFormRef = ref(); const rectificationFormRef = ref(); // 设施台账表格列配置 const ledgerTableColumn = ref([ { label: "设施编号", prop: "facilityCode", showOverflowTooltip: true, minWidth: 120 }, { label: "设施名称", prop: "facilityName", showOverflowTooltip: true, minWidth: 150 }, { label: "设施类型", prop: "facilityType", showOverflowTooltip: true, minWidth: 100 }, { label: "规格型号", prop: "facilitySpec", showOverflowTooltip: true, minWidth: 120 }, { label: "安装位置", prop: "installLocation", showOverflowTooltip: true, minWidth: 150 }, { label: "安装时间", prop: "installTime", minWidth: 120 }, { label: "下次检查时间", prop: "nextCheckTime", minWidth: 120 }, { label: "状态", prop: "status", minWidth: 80, dataType: "tag", formatType: params => { const map = { 正常: "success", 异常: "danger", 报废: "info" }; return map[params] || "info"; } const res = await getSafetyFacilityList(params) if (res.code === 200) { facilityList.value = res.data.records || [] pagination.total = res.data.total || 0 } else { ElMessage.error(res.message || '获取列表失败') } } catch (error) { ElMessage.error('获取列表失败') }, { dataType: "action", label: "操作", align: "center", fixed: "right", width: 200, operation: [ { name: "编辑", type: "text", clickFun: row => openLedgerForm("edit", row) }, { name: "发起巡检", type: "text", clickFun: row => openInspectionForm("add", row) }, { name: "删除", type: "text", style: { color: "#F56C6C" }, clickFun: row => handleDeleteLedger(row) } ] } } ]); // 获取设备列表 const fetchDeviceOptions = async () => { try { const res = await getDeviceLedger() if (res.code === 200) { deviceOptions.value = res.data || [] } } catch (error) { console.error('获取设备列表失败') // 巡检记录表格列配置 const inspectionTableColumn = ref([ { label: "巡检编号", prop: "inspectionCode", showOverflowTooltip: true, minWidth: 150 }, { label: "设施名称", prop: "facilityName", showOverflowTooltip: true, minWidth: 150 }, { label: "设施编号", prop: "facilityCode", showOverflowTooltip: true, minWidth: 120 }, { label: "巡检类型", prop: "inspectionType", minWidth: 100 }, { label: "计划巡检时间", prop: "planTime", minWidth: 180 }, { label: "巡检人", prop: "inspectorName", minWidth: 100 }, { label: "实际巡检时间", prop: "actualTime", minWidth: 180 }, { label: "检查结果", prop: "checkResult", minWidth: 100, dataType: "tag", formatType: params => params === "正常" ? "success" : "danger" }, { label: "状态", prop: "status", minWidth: 100, dataType: "tag", formatType: params => params === "待巡检" ? "info" : "success" }, { dataType: "action", label: "操作", align: "center", fixed: "right", width: 200, operation: [ { name: "巡检", type: "text", clickFun: row => openInspectionForm("do", row), show: row => row.status === "待巡检" }, { name: "查看", type: "text", clickFun: row => openInspectionForm("view", row), show: row => row.status !== "待巡检" }, { name: "整改", type: "text", clickFun: row => openRectificationForm("add", row), show: row => row.checkResult === "异常" }, { name: "删除", type: "text", style: { color: "#F56C6C" }, clickFun: row => handleDeleteInspection(row) } ] } } ]); // 搜索 const handleSearch = () => { pagination.currentPage = 1 fetchList() } // 重置搜索 const resetSearch = () => { Object.assign(searchForm, { facilityName: '', facilityType: '', status: '' }) handleSearch() } // 新增 const handleAdd = () => { dialogTitle.value = '新增设施' Object.assign(form, { id: null, facilityName: '', facilityType: '', location: '', deviceId: null, responsibilityDept: '', responsibilityPerson: '', nextInspectionTime: '', remarks: '' }) showDialog.value = true } // 编辑 const handleEdit = (row) => { dialogTitle.value = '编辑设施' Object.assign(form, { id: row.id, facilityName: row.facilityName, facilityType: row.facilityType, location: row.location, deviceId: row.deviceId, responsibilityDept: row.responsibilityDept, responsibilityPerson: row.responsibilityPerson, nextInspectionTime: row.nextInspectionTime, remarks: row.remarks }) showDialog.value = true } // 巡检 const handleInspection = (row) => { Object.assign(inspectionForm, { id: row.id, facilityName: row.facilityName, status: '正常', description: '' }) showInspectionDialog.value = true } // 删除 const handleDelete = async (row) => { try { await ElMessageBox.confirm('确认删除该设施吗?', '提示', { type: 'warning' }) const res = await deleteSafetyFacility([row.id]) if (res.code === 200) { ElMessage.success('删除成功') fetchList() } else { ElMessage.error(res.message || '删除失败') // 整改跟踪表格列配置 const rectificationTableColumn = ref([ { label: "设施名称", prop: "facilityName", showOverflowTooltip: true, minWidth: 150 }, { label: "问题描述", prop: "problemDesc", showOverflowTooltip: true, minWidth: 200 }, { label: "问题等级", prop: "problemLevel", minWidth: 100, dataType: "tag", formatType: params => params === "重大" ? "danger" : "warning" }, { label: "整改责任人", prop: "rectifyUserName", minWidth: 120 }, { label: "计划整改时间", prop: "planTime", minWidth: 180 }, { label: "状态", prop: "status", minWidth: 100, dataType: "tag", formatType: params => { const map = { 待整改: "danger", 整改中: "warning", 已整改: "success", 已验收: "info" }; return map[params] || "info"; } } catch (error) { // 取消删除 }, { label: "验收人", prop: "verifyUserName", minWidth: 120 }, { dataType: "action", label: "操作", align: "center", fixed: "right", width: 200, operation: [ { name: "整改", type: "text", clickFun: row => openRectificationForm("do", row), show: row => row.status === "待整改" || row.status === "整改中" }, { name: "验收", type: "text", clickFun: row => openRectificationForm("verify", row), show: row => row.status === "已整改" }, { name: "查看", type: "text", clickFun: row => openRectificationForm("view", row) } ] } } ]); // 提交表单 const submitForm = async () => { if (!formRef.value) return try { await formRef.value.validate() const res = await addOrEditSafetyFacility(form) if (res.code === 200) { ElMessage.success('操作成功') showDialog.value = false fetchList() } else { ElMessage.error(res.message || '操作失败') } } catch (error) { ElMessage.error('请填写完整表单信息') } } // 提交巡检结果 const submitInspection = async () => { try { const data = { id: inspectionForm.id, status: inspectionForm.status, lastInspectionTime: new Date().toISOString() } const res = await addOrEditSafetyFacility(data) if (res.code === 200) { ElMessage.success('巡检记录成功') showInspectionDialog.value = false fetchList() } else { ElMessage.error(res.message || '操作失败') } } catch (error) { ElMessage.error('操作失败') } } // 导出 const handleExport = async () => { try { const res = await exportSafetyFacility(searchForm) const blob = new Blob([res]) const url = window.URL.createObjectURL(blob) const link = document.createElement('a') link.href = url link.download = '安全设施台账.xlsx' link.click() window.URL.revokeObjectURL(url) ElMessage.success('导出成功') } catch (error) { ElMessage.error('导出失败') } } // 分页大小改变 const handleSizeChange = (val) => { pagination.pageSize = val fetchList() } // 当前页改变 const handleCurrentChange = (val) => { pagination.currentPage = val fetchList() } // 生命周期 onMounted(() => { fetchList() fetchDeviceOptions() }) getLedgerList(); }); // 标签页切换 const handleTabClick = () => { if (activeTab.value === "ledger") getLedgerList(); else if (activeTab.value === "inspection") getInspectionList(); else if (activeTab.value === "rectification") getRectificationList(); }; // ============ 设施台账方法 ============ const handleLedgerQuery = () => { ledgerPage.value.current = 1; getLedgerList(); }; const getLedgerList = () => { ledgerTableLoading.value = true; getFacilityLedgerList({ ...ledgerPage.value, ...ledgerSearchForm.value }) .then(res => { ledgerTableLoading.value = false; ledgerTableData.value = res.data.records; ledgerPage.value.total = res.data.total; }) .catch(() => { ledgerTableLoading.value = false; }); }; const ledgerPagination = obj => { ledgerPage.value.current = obj.page; ledgerPage.value.size = obj.limit; getLedgerList(); }; const handleLedgerSelectionChange = selection => { ledgerSelectedIds.value = selection.map(item => item.id); }; const openLedgerForm = (type, row = null) => { ledgerDialogType.value = type; if (type === "add") { ledgerDialogTitle.value = "新增设施"; Object.assign(ledgerForm.value, { id: null, facilityCode: "", facilityName: "", facilityType: "", facilitySpec: "", installLocation: "", installTime: "", productionDate: "", validPeriod: null, status: "正常", remark: "" }); } else { ledgerDialogTitle.value = "编辑设施"; Object.assign(ledgerForm.value, { ...row }); } ledgerDialogVisible.value = true; }; const submitLedgerForm = async () => { try { await ledgerFormRef.value.validate(); const api = ledgerDialogType.value === "add" ? addFacilityLedger : updateFacilityLedger; const res = await api({ ...ledgerForm.value }); if (res.code === 200) { ElMessage.success(ledgerDialogType.value === "add" ? "添加成功" : "更新成功"); ledgerDialogVisible.value = false; getLedgerList(); } else { ElMessage.error(res.msg || "操作失败"); } } catch (error) { console.error("表单验证失败:", error); } }; const handleDeleteLedger = row => { ElMessageBox.confirm("确认删除该设施吗?", "删除", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning" }).then(async () => { const res = await deleteFacilityLedger([row.id]); if (res.code === 200) { ElMessage.success("删除成功"); getLedgerList(); } }).catch(() => {}); }; // ============ 巡检记录方法 ============ const handleInspectionQuery = () => { inspectionPage.value.current = 1; getInspectionList(); }; const getInspectionList = () => { inspectionTableLoading.value = true; getFacilityInspectionList({ ...inspectionPage.value, ...inspectionSearchForm.value }) .then(res => { inspectionTableLoading.value = false; inspectionTableData.value = res.data.records; inspectionPage.value.total = res.data.total; }) .catch(() => { inspectionTableLoading.value = false; }); }; const inspectionPagination = obj => { inspectionPage.value.current = obj.page; inspectionPage.value.size = obj.limit; getInspectionList(); }; const openInspectionForm = (type, row = null) => { inspectionDialogType.value = type; if (type === "add") { inspectionDialogTitle.value = "发起巡检"; Object.assign(inspectionForm.value, { id: null, facilityId: row.id, inspectionCode: "", inspectionType: "定期巡检", planTime: "", checkResult: "", checkDesc: "" }); } else if (type === "do") { inspectionDialogTitle.value = "巡检"; Object.assign(inspectionForm.value, { id: row.id, facilityId: row.facilityId, inspectionCode: row.inspectionCode, inspectionType: row.inspectionType, planTime: row.planTime, checkResult: "", checkDesc: "" }); } else { inspectionDialogTitle.value = "查看巡检"; Object.assign(inspectionForm.value, { ...row }); } inspectionDialogVisible.value = true; }; const submitInspectionForm = async () => { try { await inspectionFormRef.value.validate(); if (inspectionDialogTitle.value === "巡检") { inspectionForm.value.status = "已巡检"; inspectionForm.value.actualTime = new Date().toISOString().replace("T", " ").substring(0, 19); } const api = inspectionForm.value.id ? updateFacilityInspection : addFacilityInspection; const res = await api({ ...inspectionForm.value }); if (res.code === 200) { ElMessage.success("操作成功"); inspectionDialogVisible.value = false; getInspectionList(); } } catch (error) { console.error("表单验证失败:", error); } }; const handleDeleteInspection = row => { ElMessageBox.confirm("确认删除该巡检记录吗?", "删除", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning" }).then(async () => { const res = await deleteFacilityInspection([row.id]); if (res.code === 200) { ElMessage.success("删除成功"); getInspectionList(); } }).catch(() => {}); }; // ============ 整改跟踪方法 ============ const handleRectificationQuery = () => { rectificationPage.value.current = 1; getRectificationList(); }; const getRectificationList = () => { rectificationTableLoading.value = true; getFacilityRectificationList({ ...rectificationPage.value, ...rectificationSearchForm.value }) .then(res => { rectificationTableLoading.value = false; rectificationTableData.value = res.data.records; rectificationPage.value.total = res.data.total; }) .catch(() => { rectificationTableLoading.value = false; }); }; const rectificationPagination = obj => { rectificationPage.value.current = obj.page; rectificationPage.value.size = obj.limit; getRectificationList(); }; const openRectificationForm = (type, row = null) => { rectificationDialogType.value = type; if (type === "add") { rectificationDialogTitle.value = "新增整改"; Object.assign(rectificationForm.value, { id: null, inspectionId: row.id, facilityId: row.facilityId, problemDesc: "", problemLevel: "", rectifyDesc: "", verifyDesc: "" }); } else if (type === "do") { rectificationDialogTitle.value = "整改"; Object.assign(rectificationForm.value, { id: row.id, inspectionId: row.inspectionId, facilityId: row.facilityId, problemDesc: row.problemDesc, problemLevel: row.problemLevel, rectifyDesc: "", verifyDesc: "" }); } else if (type === "verify") { rectificationDialogTitle.value = "验收"; Object.assign(rectificationForm.value, { id: row.id, inspectionId: row.inspectionId, facilityId: row.facilityId, problemDesc: row.problemDesc, problemLevel: row.problemLevel, rectifyDesc: row.rectifyDesc, verifyDesc: "" }); } else { rectificationDialogTitle.value = "查看整改"; Object.assign(rectificationForm.value, { ...row }); } rectificationDialogVisible.value = true; }; const submitRectificationForm = async () => { if (rectificationDialogType.value === "view") { rectificationDialogVisible.value = false; return; } if (rectificationDialogTitle.value === "整改") { rectificationForm.value.status = "已整改"; rectificationForm.value.actualTime = new Date().toISOString().replace("T", " ").substring(0, 19); } else if (rectificationDialogTitle.value === "验收") { rectificationForm.value.status = "已验收"; rectificationForm.value.verifyTime = new Date().toISOString().replace("T", " ").substring(0, 19); } const api = rectificationForm.value.id ? updateFacilityRectification : addFacilityRectification; const res = await api({ ...rectificationForm.value }); if (res.code === 200) { ElMessage.success("操作成功"); rectificationDialogVisible.value = false; getRectificationList(); } }; </script> <style scoped> .safety-facility { padding: 20px; .search_title { font-size: 14px; color: #606266; } .search-area { background: #f5f7fa; padding: 20px; border-radius: 4px; margin-bottom: 15px; .mb20 { margin-bottom: 20px; } .actions { margin-bottom: 15px; } .pagination { margin-top: 20px; display: flex; justify-content: flex-end; .ml10 { margin-left: 10px; } </style>