| | |
| | | <template> |
| | | <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 class="app-container line-inspection-page"> |
| | | <div class="module-tabs"> |
| | | <button |
| | | v-for="tab in moduleTabs" |
| | | :key="tab.value" |
| | | class="module-tab" |
| | | :class="{ active: activeTab === tab.value }" |
| | | type="button" |
| | | @click="handleModuleTabChange(tab.value)" |
| | | > |
| | | {{ tab.label }} |
| | | </button> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">新增巡检任务</el-button> |
| | | |
| | | <div class="search_form line-search-panel mb20"> |
| | | <div class="search-left"> |
| | | <template v-if="activeTab === 'task'"> |
| | | <div class="filter-item"> |
| | | <span class="search_title">巡检任务名称:</span> |
| | | <el-input |
| | | v-model="taskSearchForm.inspectionName" |
| | | class="filter-control is-wide" |
| | | placeholder="请输入巡检任务名称" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="handleQuery" |
| | | /> |
| | | </div> |
| | | <div class="filter-item"> |
| | | <span class="search_title">线路名称:</span> |
| | | <el-input |
| | | v-model="taskSearchForm.lineName" |
| | | class="filter-control" |
| | | placeholder="请输入线路名称" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="handleQuery" |
| | | /> |
| | | </div> |
| | | <div class="filter-item"> |
| | | <span class="search_title">是否启用:</span> |
| | | <el-select |
| | | v-model="taskSearchForm.isEnabled" |
| | | class="filter-control is-short" |
| | | clearable |
| | | placeholder="请选择" |
| | | @change="handleQuery" |
| | | > |
| | | <el-option label="是" :value="1" /> |
| | | <el-option label="否" :value="0" /> |
| | | </el-select> |
| | | </div> |
| | | </template> |
| | | <template v-else-if="activeTab === 'record'"> |
| | | <div class="filter-item"> |
| | | <span class="search_title">巡检编号:</span> |
| | | <el-input |
| | | v-model="recordSearchForm.inspectionCode" |
| | | class="filter-control" |
| | | placeholder="请输入巡检编号" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="handleQuery" |
| | | /> |
| | | </div> |
| | | <div class="filter-item"> |
| | | <span class="search_title">巡检名称:</span> |
| | | <el-input |
| | | v-model="recordSearchForm.inspectionName" |
| | | class="filter-control" |
| | | placeholder="请输入巡检名称" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="handleQuery" |
| | | /> |
| | | </div> |
| | | <div class="filter-item"> |
| | | <span class="search_title">线路名称:</span> |
| | | <el-input |
| | | v-model="recordSearchForm.lineName" |
| | | class="filter-control" |
| | | placeholder="请输入线路名称" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="handleQuery" |
| | | /> |
| | | </div> |
| | | </template> |
| | | <template v-else> |
| | | <div class="filter-item"> |
| | | <span class="search_title">隐患编号:</span> |
| | | <el-input |
| | | v-model="rectifySearchForm.hazardCode" |
| | | class="filter-control" |
| | | placeholder="请输入隐患编号" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="handleQuery" |
| | | /> |
| | | </div> |
| | | <div class="filter-item"> |
| | | <span class="search_title">隐患描述:</span> |
| | | <el-input |
| | | v-model="rectifySearchForm.hazardDesc" |
| | | class="filter-control" |
| | | placeholder="请输入隐患描述" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="handleQuery" |
| | | /> |
| | | </div> |
| | | <div class="filter-item"> |
| | | <span class="search_title">整改状态:</span> |
| | | <el-select |
| | | v-model="rectifySearchForm.status" |
| | | class="filter-control is-short" |
| | | clearable |
| | | placeholder="请选择" |
| | | @change="handleQuery" |
| | | > |
| | | <el-option label="待整改" value="待整改" /> |
| | | <el-option label="整改中" value="整改中" /> |
| | | <el-option label="已整改" value="已整改" /> |
| | | </el-select> |
| | | </div> |
| | | </template> |
| | | <div class="filter-buttons"> |
| | | <el-button type="primary" @click="handleQuery">搜索</el-button> |
| | | <el-button @click="resetQuery">重置</el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="table_list"> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | <div class="table-toolbar" v-if="activeTab === 'task'"> |
| | | <div></div> |
| | | <div class="toolbar-actions"> |
| | | <el-button type="primary" :icon="Plus" @click="openTaskDialog('add')">新增巡检任务</el-button> |
| | | <el-button type="danger" :icon="Delete" :disabled="selectedIds.length === 0" @click="handleBatchDeleteTask">删除</el-button> |
| | | </div> |
| | | </div> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="tableColumns" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | :total="page.total" |
| | | :height="'calc(100vh - 25em)'" |
| | | :table-style="{ width: '100%' }" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="pagination" |
| | | :total="page.total"></PIMTable> |
| | | > |
| | | <template #taskName="{ row }"> |
| | | <el-button class="task-name-link" type="primary" link @click="openTaskDetail(row)"> |
| | | {{ row.inspectionName || "--" }} |
| | | </el-button> |
| | | </template> |
| | | <template #inspectionCode="{ row }"> |
| | | <el-button class="code-link" type="primary" link @click="openInspectionDetailEntry(row)"> |
| | | {{ row.inspectionCode || "--" }} |
| | | </el-button> |
| | | </template> |
| | | <template #inspectionResult="{ row }"> |
| | | <el-tag :type="getInspectionResultType(row.inspectionResult)" size="small"> |
| | | {{ row.inspectionResult || "未巡检" }} |
| | | </el-tag> |
| | | </template> |
| | | <template #inspectorName="{ row }"> |
| | | <div class="person-tags"> |
| | | <template v-if="getInspectorNames(row).length"> |
| | | <el-tag |
| | | v-for="name in getInspectorNames(row)" |
| | | :key="name" |
| | | size="small" |
| | | type="primary" |
| | | class="person-tag" |
| | | > |
| | | {{ name }} |
| | | </el-tag> |
| | | </template> |
| | | <span v-else class="no-data">--</span> |
| | | </div> |
| | | </template> |
| | | <template #isEnabled="{ row }"> |
| | | <el-tag :type="row.isEnabled === 1 ? 'success' : 'info'" size="small"> |
| | | {{ row.isEnabled === 1 ? "是" : "否" }} |
| | | </el-tag> |
| | | </template> |
| | | <template #status="{ row }"> |
| | | <el-tag :type="getInspectionStatusType(row.status)" size="small"> |
| | | {{ row.status || "--" }} |
| | | </el-tag> |
| | | </template> |
| | | <template #hazardLevel="{ row }"> |
| | | <el-tag :type="getRiskLevelType(row.hazardLevel)" size="small"> |
| | | {{ row.hazardLevel || "--" }} |
| | | </el-tag> |
| | | </template> |
| | | <template #hazardStatus="{ row }"> |
| | | <el-tag :type="getHazardStatusType(row.status)" size="small"> |
| | | {{ row.status || "--" }} |
| | | </el-tag> |
| | | </template> |
| | | <template #rectifyPhotos="{ row }"> |
| | | <el-tag :type="hasAttachments(getAttachments(row)) ? 'success' : 'info'" size="small"> |
| | | {{ hasAttachments(getAttachments(row)) ? "已上传" : "未上传" }} |
| | | </el-tag> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <!-- 新增/编辑巡检任务弹窗 --> |
| | | <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-dialog |
| | | v-model="taskDetailVisible" |
| | | title="巡检任务详情" |
| | | width="780px" |
| | | :close-on-click-modal="false" |
| | | > |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions-item label="巡检任务名称"> |
| | | {{ taskDetail.inspectionName || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="线路名称"> |
| | | {{ taskDetail.lineName || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="执行巡检人"> |
| | | {{ getInspectorNames(taskDetail).join("、") || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="是否启用"> |
| | | <el-tag :type="taskDetail.isEnabled === 1 ? 'success' : 'info'" size="small"> |
| | | {{ taskDetail.isEnabled === 1 ? "是" : "否" }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="频次"> |
| | | {{ frequencyTypeMap[taskDetail.frequencyType] || taskDetail.frequencyType || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="开始日期与时间"> |
| | | {{ formatFrequencyDetail(taskDetail.frequencyDetail) }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="下次执行时间"> |
| | | {{ taskDetail.nextExecutionTime || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="最后执行时间"> |
| | | {{ taskDetail.lastExecutionTime || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="巡检项目" :span="2"> |
| | | {{ taskDetail.inspectionProject || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="备注" :span="2"> |
| | | {{ taskDetail.remark || "--" }} |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button type="primary" @click="taskDetailVisible = false">关闭</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <el-dialog |
| | | v-model="taskHistoryVisible" |
| | | title="历史巡检记录" |
| | | width="1280px" |
| | | :close-on-click-modal="false" |
| | | > |
| | | <el-descriptions class="history-summary" :column="3" border> |
| | | <el-descriptions-item label="巡检任务名称"> |
| | | {{ taskHistoryTask.inspectionName || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="线路名称"> |
| | | {{ taskHistoryTask.lineName || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="频次"> |
| | | {{ frequencyTypeMap[taskHistoryTask.frequencyType] || taskHistoryTask.frequencyType || "--" }} |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="taskHistoryColumns" |
| | | :tableData="taskHistoryData" |
| | | :page="taskHistoryPage" |
| | | :tableLoading="taskHistoryLoading" |
| | | :total="taskHistoryPage.total" |
| | | :height="420" |
| | | :table-style="{ width: '100%' }" |
| | | @pagination="taskHistoryPagination" |
| | | > |
| | | <template #inspectionCode="{ row }"> |
| | | <el-button class="code-link" type="primary" link @click="openInspectionDetail(row)"> |
| | | {{ row.inspectionCode || "--" }} |
| | | </el-button> |
| | | </template> |
| | | <template #inspectionResult="{ row }"> |
| | | <el-tag :type="getInspectionResultType(row.inspectionResult)" size="small"> |
| | | {{ row.inspectionResult || "未巡检" }} |
| | | </el-tag> |
| | | </template> |
| | | <template #inspectorName="{ row }"> |
| | | <div class="person-tags"> |
| | | <template v-if="getInspectorNames(row).length"> |
| | | <el-tag |
| | | v-for="name in getInspectorNames(row)" |
| | | :key="name" |
| | | size="small" |
| | | type="primary" |
| | | class="person-tag" |
| | | > |
| | | {{ name }} |
| | | </el-tag> |
| | | </template> |
| | | <span v-else class="no-data">--</span> |
| | | </div> |
| | | </template> |
| | | <template #status="{ row }"> |
| | | <el-tag :type="getInspectionStatusType(row.status)" size="small"> |
| | | {{ row.status || "--" }} |
| | | </el-tag> |
| | | </template> |
| | | </PIMTable> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button type="primary" @click="taskHistoryVisible = false">关闭</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <el-dialog |
| | | v-model="inspectionDetailVisible" |
| | | title="巡检详情" |
| | | width="960px" |
| | | :close-on-click-modal="false" |
| | | > |
| | | <el-descriptions :column="3" border> |
| | | <el-descriptions-item label="巡检编号"> |
| | | {{ inspectionDetail.inspectionCode || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="巡检名称"> |
| | | {{ inspectionDetail.inspectionName || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="线路名称"> |
| | | {{ inspectionDetail.lineName || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="计划巡检时间"> |
| | | {{ inspectionDetail.planTime || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="实际巡检时间"> |
| | | {{ inspectionDetail.actualInspectionTime || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="巡检结果"> |
| | | <el-tag :type="getInspectionResultType(inspectionDetail.inspectionResult)" size="small"> |
| | | {{ inspectionDetail.inspectionResult || "未巡检" }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="巡检人"> |
| | | {{ getInspectorNames(inspectionDetail).join("、") || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="状态"> |
| | | <el-tag :type="getInspectionStatusType(inspectionDetail.status)" size="small"> |
| | | {{ inspectionDetail.status || "--" }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="巡检类型"> |
| | | {{ inspectionDetail.inspectionType || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="巡检项目" :span="3"> |
| | | {{ inspectionDetail.inspectionProject || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="备注" :span="3"> |
| | | {{ inspectionDetail.remark || "--" }} |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | |
| | | <div class="detail-section-title">巡检执行记录</div> |
| | | <el-table v-loading="inspectionDetailLoading" :data="inspectionDetailRecords" border> |
| | | <el-table-column prop="checkResult" label="结果" width="90" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.checkResult === '正常' ? 'success' : 'danger'" size="small"> |
| | | {{ row.checkResult || "--" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="checkContent" label="巡检项目" min-width="180" show-overflow-tooltip /> |
| | | <el-table-column prop="checkDesc" label="巡检说明" min-width="180" show-overflow-tooltip /> |
| | | <el-table-column prop="checkTime" label="巡检时间" width="170" align="center" /> |
| | | <el-table-column label="现场照片" min-width="180" align="center"> |
| | | <template #default="{ row }"> |
| | | <div v-if="getAttachments(row).length" class="photo-list"> |
| | | <el-image |
| | | v-for="(item, index) in getAttachments(row)" |
| | | :key="item.storageAttachmentId || item.id || index" |
| | | class="record-photo" |
| | | :src="getAttachmentPreviewUrl(item)" |
| | | :preview-src-list="getAttachmentPreviewUrls(row)" |
| | | fit="cover" |
| | | preview-teleported |
| | | /> |
| | | </div> |
| | | <span v-else class="no-data">--</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <div class="detail-section-title">整改跟踪</div> |
| | | <el-table v-loading="inspectionDetailLoading" :data="inspectionDetailHazards" border> |
| | | <el-table-column prop="hazardCode" label="隐患编号" width="145" align="center" show-overflow-tooltip /> |
| | | <el-table-column prop="hazardDesc" label="异常描述" min-width="170" show-overflow-tooltip /> |
| | | <el-table-column prop="hazardLocation" label="异常位置" min-width="130" show-overflow-tooltip /> |
| | | <el-table-column prop="hazardLevel" label="风险等级" width="105" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getRiskLevelType(row.hazardLevel)" size="small"> |
| | | {{ row.hazardLevel || "--" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="rectifyUserName" label="整改责任人" width="120" align="center" show-overflow-tooltip /> |
| | | <el-table-column prop="rectifyDeadline" label="整改期限" width="120" align="center" /> |
| | | <el-table-column prop="rectifyDesc" label="整改说明" min-width="170" show-overflow-tooltip> |
| | | <template #default="{ row }"> |
| | | {{ row.rectifyDesc || "--" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="rectifyTime" label="整改时间" width="165" align="center"> |
| | | <template #default="{ row }"> |
| | | {{ row.rectifyTime || "--" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="整改照片" min-width="150" align="center"> |
| | | <template #default="{ row }"> |
| | | <div v-if="getAttachments(row).length" class="photo-list"> |
| | | <el-image |
| | | v-for="(item, index) in getAttachments(row)" |
| | | :key="item.storageAttachmentId || item.id || index" |
| | | class="record-photo" |
| | | :src="getAttachmentPreviewUrl(item)" |
| | | :preview-src-list="getAttachmentPreviewUrls(row)" |
| | | fit="cover" |
| | | preview-teleported |
| | | /> |
| | | </div> |
| | | <span v-else class="no-data">--</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="status" label="整改状态" width="100" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getHazardStatusType(row.status)" size="small"> |
| | | {{ row.status || "--" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button type="primary" @click="inspectionDetailVisible = false">关闭</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <el-dialog |
| | | v-model="executeDialogVisible" |
| | | title="执行巡检" |
| | | width="820px" |
| | | :close-on-click-modal="false" |
| | | @closed="resetExecuteForm" |
| | | > |
| | | <el-descriptions :column="2" border class="execute-summary"> |
| | | <el-descriptions-item label="巡检编号"> |
| | | {{ currentInspection.inspectionCode || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="巡检名称"> |
| | | {{ currentInspection.inspectionName || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="线路名称"> |
| | | {{ currentInspection.lineName || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="计划时间"> |
| | | {{ currentInspection.planTime || "--" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="巡检项目" :span="2"> |
| | | {{ currentInspection.inspectionProject || "--" }} |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | |
| | | <el-form ref="executeFormRef" :model="executeForm" :rules="executeRules" 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 label="巡检结果" prop="checkResult"> |
| | | <el-radio-group v-model="executeForm.checkResult" @change="handleExecuteResultChange"> |
| | | <el-radio label="正常">正常</el-radio> |
| | | <el-radio label="异常">异常</el-radio> |
| | | </el-radio-group> |
| | | </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 label="巡检时间" prop="checkTime"> |
| | | <el-date-picker |
| | | v-model="executeForm.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-col> |
| | | </el-row> |
| | | <el-form-item v-if="executeForm.checkResult === '正常'" label="巡检说明" prop="checkDesc"> |
| | | <el-input |
| | | v-model="executeForm.checkDesc" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请输入正常巡检情况说明" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <template v-if="executeForm.checkResult === '异常'"> |
| | | <el-form-item label="异常照片" prop="storageBlobDTOs"> |
| | | <ImageUpload v-model:file-list="executeForm.storageBlobDTOs" :limit="6" button-text="上传照片" /> |
| | | </el-form-item> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="隐患类型" prop="hiddenType"> |
| | | <el-select v-model="executeForm.hiddenType" placeholder="请选择隐患类型" clearable style="width: 100%"> |
| | | <el-option |
| | | v-for="item in hiddenTypeOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="风险等级" prop="riskLevel"> |
| | | <el-select v-model="executeForm.riskLevel" placeholder="请选择风险等级" clearable style="width: 100%"> |
| | | <el-option v-for="item in riskLevelList" :key="item.value" :label="item.label" :value="item.value" /> |
| | | </el-select> |
| | | </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 label="隐患位置" prop="hazardLocation"> |
| | | <el-input v-model="executeForm.hazardLocation" 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-form-item label="整改责任人" prop="rectifyUserId"> |
| | | <el-select |
| | | v-model="executeForm.rectifyUserId" |
| | | placeholder="请选择整改责任人" |
| | | filterable |
| | | clearable |
| | | style="width: 100%" |
| | | @change="handleRectifyUserChange" |
| | | > |
| | | <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-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="整改期限" prop="rectifyTime"> |
| | | <el-date-picker |
| | | v-model="executeForm.rectifyTime" |
| | | type="date" |
| | | placeholder="请选择整改期限" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-form-item label="异常描述/整改要求" prop="hazardDesc"> |
| | | <el-input |
| | | v-model="executeForm.hazardDesc" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请描述异常情况和整改要求" |
| | | /> |
| | | </el-form-item> |
| | | </template> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button type="primary" @click="submitExecuteForm">提交</el-button> |
| | | <el-button @click="executeDialogVisible = false">取消</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <el-dialog |
| | | v-model="taskDialogVisible" |
| | | :title="taskDialogTitle" |
| | | width="960px" |
| | | :close-on-click-modal="false" |
| | | @closed="resetTaskForm" |
| | | > |
| | | <el-form ref="taskFormRef" :model="taskForm" :rules="taskRules" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="巡检任务名称" prop="inspectionName"> |
| | | <el-input v-model="taskForm.inspectionName" placeholder="请输入巡检任务名称" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="线路名称" prop="lineName"> |
| | | <el-input v-model="taskForm.lineName" placeholder="请输入线路名称" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="巡检人" prop="inspectorIds"> |
| | | <el-select |
| | | v-model="taskForm.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-col :span="12"> |
| | | <el-form-item label="是否启用" prop="isEnabled"> |
| | | <el-radio-group v-model="taskForm.isEnabled"> |
| | | <el-radio :label="1">是</el-radio> |
| | | <el-radio :label="0">否</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="巡检项目" prop="inspectionProject"> |
| | | <el-input |
| | | v-model="taskForm.inspectionProject" |
| | | type="textarea" |
| | | :autosize="{ minRows: 3, maxRows: 6 }" |
| | | placeholder="请输入巡检项目" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="备注"> |
| | | <el-input |
| | | v-model="taskForm.remark" |
| | | type="textarea" |
| | | :autosize="{ minRows: 3, maxRows: 6 }" |
| | | placeholder="请输入备注" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="任务频率" prop="frequencyType"> |
| | | <el-select |
| | | v-model="taskForm.frequencyType" |
| | | placeholder="请选择" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="handleFrequencyTypeChange" |
| | | > |
| | | <el-option label="每日" value="DAILY" /> |
| | | <el-option label="每周" value="WEEKLY" /> |
| | | <el-option label="每月" value="MONTHLY" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col v-if="taskForm.frequencyType === 'DAILY'" :span="12"> |
| | | <el-form-item class="frequency-detail-item" label="日期" prop="frequencyDetail"> |
| | | <el-time-picker |
| | | v-model="taskForm.frequencyDetail" |
| | | placeholder="选择时间" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col v-if="taskForm.frequencyType === 'WEEKLY'" :span="12"> |
| | | <el-form-item class="frequency-detail-item" label="日期" prop="frequencyDetail"> |
| | | <div class="frequency-row"> |
| | | <el-select v-model="taskForm.week" class="frequency-day-select" placeholder="请选择" clearable> |
| | | <el-option v-for="item in weekOptions" :key="item.value" :label="item.label" :value="item.value" /> |
| | | </el-select> |
| | | <el-time-picker |
| | | v-model="taskForm.time" |
| | | class="frequency-time-picker" |
| | | placeholder="选择时间" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | /> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col v-if="taskForm.frequencyType === 'MONTHLY'" :span="12"> |
| | | <el-form-item class="frequency-detail-item" label="日期" prop="frequencyDetail"> |
| | | <div class="frequency-row"> |
| | | <el-select v-model="taskForm.day" class="frequency-day-select" placeholder="请选择" clearable> |
| | | <el-option v-for="item in dayOptions" :key="item.value" :label="item.label" :value="item.value" /> |
| | | </el-select> |
| | | <el-time-picker |
| | | v-model="taskForm.time" |
| | | class="frequency-time-picker" |
| | | placeholder="选择时间" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | /> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button type="primary" @click="submitTaskForm">保存</el-button> |
| | | <el-button @click="taskDialogVisible = false">取消</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <el-dialog |
| | | v-model="inspectionDialogVisible" |
| | | title="编辑巡检记录" |
| | | width="800px" |
| | | :close-on-click-modal="false" |
| | | @closed="resetInspectionForm" |
| | | > |
| | | <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="inspectionName"> |
| | | <el-input v-model="inspectionForm.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="inspectionForm.lineName" 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-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="计划巡检时间" |
| | | prop="planTime"> |
| | | <el-date-picker v-model="form.planTime" |
| | | <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%" /> |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="巡检人" |
| | | prop="inspectorIds"> |
| | | <el-select v-model="form.inspectorIds" |
| | | placeholder="请选择巡检人(可多选)" |
| | | <el-form-item label="巡检人" prop="inspectorIds"> |
| | | <el-select |
| | | v-model="inspectionForm.inspectorIds" |
| | | placeholder="请选择巡检人" |
| | | filterable |
| | | multiple |
| | | collapse-tags |
| | | collapse-tags-tooltip |
| | | clearable |
| | | style="width: 100%"> |
| | | <el-option v-for="item in userList" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in userList" |
| | | :key="item.userId" |
| | | :label="item.nickName" |
| | | :value="item.userId" /> |
| | | :value="item.userId" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-form-item label="备注" |
| | | prop="remark"> |
| | | <el-input v-model="form.remark" |
| | | <el-form-item label="巡检项目"> |
| | | <el-input |
| | | v-model="inspectionForm.inspectionProject" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请输入备注" /> |
| | | placeholder="请输入巡检项目" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="备注"> |
| | | <el-input v-model="inspectionForm.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="dialogVisible = false">取消</el-button> |
| | | <el-button type="primary" @click="submitInspectionForm">确定</el-button> |
| | | <el-button @click="inspectionDialogVisible = false">取消</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- 巡检记录弹窗 --> |
| | | <el-dialog ref="recordDialogRef" |
| | | <el-dialog |
| | | ref="recordDialogRef" |
| | | v-model="recordDialogVisible" |
| | | title="巡检记录" |
| | | width="70vw" |
| | | :close-on-click-modal="false" |
| | | @open="onRecordDialogOpen"> |
| | | @open="onRecordDialogOpen" |
| | | > |
| | | <div class="mb10"> |
| | | <el-button type="primary" |
| | | <el-button |
| | | type="primary" |
| | | size="small" |
| | | :disabled="currentInspectionStatus === '已完成'" |
| | | @click="openRecordForm">新增记录</el-button> |
| | | @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 :data="recordList" border style="width: 100%"> |
| | | <el-table-column prop="checkPoint" label="检查点" min-width="140" 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> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="checkDesc" label="检查说明" width="200" show-overflow-tooltip /> |
| | | <el-table-column prop="checkDesc" label="检查说明" min-width="180" show-overflow-tooltip /> |
| | | <el-table-column label="现场照片" width="100"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="hasAttachments(row.storageBlobVOs) ? 'success' : 'info'"> |
| | | {{ hasAttachments(row.storageBlobVOs) ? '已上传' : '未上传' }} |
| | | {{ hasAttachments(row.storageBlobVOs) ? "已上传" : "未上传" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="checkTime" label="检查时间" width="180" /> |
| | | <el-table-column label="操作" width="120" fixed="right"> |
| | | <el-table-column label="操作" width="130" fixed="right"> |
| | | <template #default="{ row }"> |
| | | <el-button type="primary" link :disabled="currentInspectionStatus === '已完成'" @click="openEditRecordForm(row)">编辑</el-button> |
| | | <el-button type="danger" link :disabled="currentInspectionStatus === '已完成'" @click="handleDeleteRecord(row)">删除</el-button> |
| | |
| | | </el-table> |
| | | </div> |
| | | |
| | | <!-- 新增记录表单 --> |
| | | <el-dialog v-model="recordFormVisible" |
| | | <el-dialog |
| | | v-model="recordFormVisible" |
| | | :title="recordForm.id ? '编辑巡检记录' : '新增巡检记录'" |
| | | width="600px" |
| | | append-to-body |
| | | :close-on-click-modal="false"> |
| | | <el-form ref="recordFormRef" |
| | | :model="recordForm" |
| | | :rules="recordRules" |
| | | label-width="100px"> |
| | | :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 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-form-item label="检查结果" prop="checkResult"> |
| | | <el-radio-group v-model="recordForm.checkResult"> |
| | | <el-radio label="正常">正常</el-radio> |
| | | <el-radio label="异常">异常</el-radio> |
| | |
| | | </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 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-input v-model="recordForm.checkDesc" type="textarea" :rows="2" placeholder="请输入检查说明" /> |
| | | </el-form-item> |
| | | <el-form-item v-if="recordForm.checkResult === '异常'" label="现场照片"> |
| | | <ImageUpload v-model:file-list="recordForm.storageBlobDTOs" |
| | | :limit="6" |
| | | button-text="上传照片" /> |
| | | <ImageUpload v-model:file-list="recordForm.storageBlobDTOs" :limit="6" button-text="上传照片" /> |
| | | </el-form-item> |
| | | <el-form-item label="检查时间"> |
| | | <el-date-picker v-model="recordForm.checkTime" |
| | | <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%" /> |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button type="primary" |
| | | @click="submitRecordForm">确定</el-button> |
| | | <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" |
| | | <el-dialog |
| | | ref="hazardDialogRef" |
| | | v-model="hazardDialogVisible" |
| | | title="隐患管理" |
| | | width="75vw" |
| | | :close-on-click-modal="false" |
| | | @open="onHazardDialogOpen"> |
| | | @open="onHazardDialogOpen" |
| | | > |
| | | <div class="mb10"> |
| | | <el-button type="primary" |
| | | <el-button |
| | | type="primary" |
| | | size="small" |
| | | :disabled="currentInspectionStatus === '已完成'" |
| | | @click="openHazardForm('add')">上报隐患</el-button> |
| | | @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 :data="hazardList" border style="width: 100%"> |
| | | <el-table-column prop="hazardCode" label="隐患编号" min-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> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="hazardLocation" label="隐患位置" width="150" show-overflow-tooltip /> |
| | | <el-table-column prop="hazardLocation" label="隐患位置" min-width="150" show-overflow-tooltip /> |
| | | <el-table-column prop="status" label="状态" width="100"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getHazardStatusType(row.status)"> |
| | |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="rectifyUserName" label="整改责任人" width="120" /> |
| | | <el-table-column prop="rectifyUserName" label="整改责任人" min-width="120" /> |
| | | <el-table-column label="操作" width="150" fixed="right"> |
| | | <template #default="{ row }"> |
| | | <el-button type="primary" link :disabled="currentInspectionStatus === '已完成'" @click="openHazardForm('edit', row)">编辑</el-button> |
| | | <el-button type="success" link :disabled="currentInspectionStatus === '已完成'" @click="handleRectify(row)" v-if="row.status !== '已整改'">整改</el-button> |
| | | <el-button |
| | | v-if="row.status !== '已整改'" |
| | | type="success" |
| | | link |
| | | :disabled="currentInspectionStatus === '已完成'" |
| | | @click="handleRectify(row)" |
| | | > |
| | | 整改 |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <!-- 隐患表单 --> |
| | | <el-dialog v-model="hazardFormVisible" |
| | | <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="请输入隐患描述" /> |
| | | :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-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 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 type="primary" @click="submitHazardForm">确定</el-button> |
| | | <el-button @click="hazardFormVisible = false">取消</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- 整改表单 --> |
| | | <el-dialog v-model="rectifyFormVisible" |
| | | </el-dialog> |
| | | |
| | | <el-dialog |
| | | v-model="rectifyFormVisible" |
| | | title="整改" |
| | | width="500px" |
| | | width="620px" |
| | | 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="请输入整改说明" /> |
| | | :close-on-click-modal="false" |
| | | @closed="resetRectifyForm" |
| | | > |
| | | <el-form ref="rectifyFormRef" :model="rectifyForm" :rules="rectifyRules" 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-item label="整改后照片" prop="storageBlobDTOs"> |
| | | <ImageUpload v-model:file-list="rectifyForm.storageBlobDTOs" :limit="6" button-text="上传照片" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button type="primary" |
| | | @click="submitRectifyForm">确定</el-button> |
| | | <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 { Search } from "@element-plus/icons-vue"; |
| | | import { onMounted, ref, reactive, toRefs } from "vue"; |
| | | import { computed, getCurrentInstance, onMounted, reactive, ref } from "vue"; |
| | | import { Delete, Plus, Search } from "@element-plus/icons-vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import PIMTable from "@/components/PIMTable/PIMTable.vue"; |
| | | import ImageUpload from "@/components/AttachmentUpload/image/index.vue"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { |
| | | getLineInspectionTaskList, |
| | | addLineInspectionTask, |
| | | updateLineInspectionTask, |
| | | deleteLineInspectionTask, |
| | | getLineInspectionList, |
| | | addLineInspection, |
| | | getLineInspectionById, |
| | | updateLineInspection, |
| | | deleteLineInspection, |
| | | completeLineInspection, |
| | | executeLineInspection, |
| | | getInspectionRecords, |
| | | addInspectionRecord, |
| | | updateInspectionRecord, |
| | | deleteInspectionRecord, |
| | | getInspectionHazards, |
| | | getHazardsByInspectionId, |
| | | addInspectionHazard, |
| | | updateInspectionHazard |
| | | } from "@/api/safeProduction/lineInspection"; |
| | | |
| | | // 表单验证规则 |
| | | const rules = { |
| | | const ENABLED = 1; |
| | | const { proxy } = getCurrentInstance(); |
| | | const { hidden_danger_type } = proxy.useDict("hidden_danger_type"); |
| | | const userStore = useUserStore(); |
| | | const currentUserId = computed(() => Number(userStore.id)); |
| | | |
| | | const activeTab = ref("task"); |
| | | const tableLoading = ref(false); |
| | | const tableData = ref([]); |
| | | const selectedIds = ref([]); |
| | | const userList = ref([]); |
| | | const taskDialogVisible = ref(false); |
| | | const taskDetailVisible = ref(false); |
| | | const taskHistoryVisible = ref(false); |
| | | const taskHistoryLoading = ref(false); |
| | | const inspectionDetailVisible = ref(false); |
| | | const inspectionDetailLoading = ref(false); |
| | | const executeDialogVisible = ref(false); |
| | | const inspectionDialogVisible = ref(false); |
| | | const recordDialogVisible = ref(false); |
| | | const recordFormVisible = ref(false); |
| | | const hazardDialogVisible = ref(false); |
| | | const hazardFormVisible = ref(false); |
| | | const rectifyFormVisible = ref(false); |
| | | const taskDialogTitle = ref("新增巡检任务"); |
| | | const hazardDialogTitle = ref("上报隐患"); |
| | | const currentInspectionId = ref(null); |
| | | const currentInspectionStatus = ref(""); |
| | | const currentInspection = ref({}); |
| | | const inspectionDetail = ref({}); |
| | | const taskHistoryTask = ref({}); |
| | | const taskHistoryData = ref([]); |
| | | const inspectionDetailRecords = ref([]); |
| | | const inspectionDetailHazards = ref([]); |
| | | const recordList = ref([]); |
| | | const hazardList = ref([]); |
| | | |
| | | const taskFormRef = ref(); |
| | | const inspectionFormRef = ref(); |
| | | const recordFormRef = ref(); |
| | | const hazardFormRef = ref(); |
| | | const executeFormRef = ref(); |
| | | const rectifyFormRef = ref(); |
| | | |
| | | const moduleTabs = [ |
| | | { label: "巡检任务", value: "task" }, |
| | | { label: "巡检记录", value: "record" }, |
| | | { label: "整改跟踪", value: "rectify" } |
| | | ]; |
| | | |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 20, |
| | | total: 0, |
| | | layout: "total, sizes, prev, pager, next, jumper" |
| | | }); |
| | | |
| | | const taskHistoryPage = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | total: 0, |
| | | layout: "total, sizes, prev, pager, next, jumper" |
| | | }); |
| | | |
| | | const taskSearchForm = reactive({ |
| | | inspectionName: "", |
| | | lineName: "", |
| | | isEnabled: "" |
| | | }); |
| | | |
| | | const recordSearchForm = reactive({ |
| | | inspectionCode: "", |
| | | inspectionName: "", |
| | | lineName: "" |
| | | }); |
| | | |
| | | const rectifySearchForm = reactive({ |
| | | hazardCode: "", |
| | | hazardDesc: "", |
| | | status: "" |
| | | }); |
| | | |
| | | const createTaskForm = () => ({ |
| | | id: null, |
| | | inspectionName: "", |
| | | lineName: "", |
| | | inspectionProject: "", |
| | | inspectorId: "", |
| | | inspectorIds: [], |
| | | frequencyType: "", |
| | | frequencyDetail: "", |
| | | week: "", |
| | | day: "", |
| | | time: "", |
| | | isEnabled: ENABLED, |
| | | remark: "" |
| | | }); |
| | | |
| | | const createInspectionForm = () => ({ |
| | | id: null, |
| | | scheduleTaskId: null, |
| | | inspectionCode: "", |
| | | inspectionName: "", |
| | | lineName: "", |
| | | inspectionType: "定期巡检", |
| | | inspectionProject: "", |
| | | planTime: "", |
| | | inspectorId: "", |
| | | inspectorIds: [], |
| | | status: "", |
| | | remark: "" |
| | | }); |
| | | |
| | | const taskForm = reactive(createTaskForm()); |
| | | const taskDetail = ref({}); |
| | | const inspectionForm = reactive(createInspectionForm()); |
| | | |
| | | const recordForm = reactive({ |
| | | id: null, |
| | | inspectionId: null, |
| | | checkPoint: "", |
| | | checkContent: "", |
| | | checkResult: "正常", |
| | | checkDesc: "", |
| | | checkTime: "", |
| | | storageBlobDTOs: [] |
| | | }); |
| | | |
| | | const hazardForm = reactive({ |
| | | id: null, |
| | | inspectionId: null, |
| | | hazardDesc: "", |
| | | hazardLevel: "", |
| | | hazardLocation: "" |
| | | }); |
| | | |
| | | const rectifyForm = reactive({ |
| | | id: null, |
| | | rectifyDesc: "", |
| | | storageBlobDTOs: [] |
| | | }); |
| | | |
| | | const createExecuteForm = () => ({ |
| | | inspectionId: null, |
| | | checkResult: "正常", |
| | | checkDesc: "", |
| | | checkTime: "", |
| | | storageBlobDTOs: [], |
| | | hiddenType: "", |
| | | riskLevel: "", |
| | | hazardLocation: "", |
| | | hazardDesc: "", |
| | | rectifyUserId: "", |
| | | rectifyUserMobile: "", |
| | | rectifyTime: "" |
| | | }); |
| | | |
| | | const executeForm = reactive(createExecuteForm()); |
| | | |
| | | const weekOptions = [ |
| | | { label: "周一", value: "MON" }, |
| | | { label: "周二", value: "TUE" }, |
| | | { label: "周三", value: "WED" }, |
| | | { label: "周四", value: "THU" }, |
| | | { label: "周五", value: "FRI" }, |
| | | { label: "周六", value: "SAT" }, |
| | | { label: "周日", value: "SUN" } |
| | | ]; |
| | | |
| | | const dayOptions = Array.from({ length: 31 }, (_, index) => { |
| | | const value = String(index + 1).padStart(2, "0"); |
| | | return { label: `${index + 1}日`, value }; |
| | | }); |
| | | |
| | | const frequencyTypeMap = { |
| | | DAILY: "每日", |
| | | WEEKLY: "每周", |
| | | MONTHLY: "每月" |
| | | }; |
| | | |
| | | const weekLabelMap = weekOptions.reduce((map, item) => { |
| | | map[item.value] = item.label; |
| | | return map; |
| | | }, {}); |
| | | |
| | | const validateFrequencyDetail = (rule, value, callback) => { |
| | | if (!taskForm.frequencyType) { |
| | | callback(new Error("请选择任务频率")); |
| | | return; |
| | | } |
| | | if (taskForm.frequencyType === "DAILY" && !taskForm.frequencyDetail) { |
| | | callback(new Error("请选择时间")); |
| | | return; |
| | | } |
| | | if (taskForm.frequencyType === "WEEKLY" && (!taskForm.week || !taskForm.time)) { |
| | | callback(new Error("请选择星期和时间")); |
| | | return; |
| | | } |
| | | if (taskForm.frequencyType === "MONTHLY" && (!taskForm.day || !taskForm.time)) { |
| | | callback(new Error("请选择日期和时间")); |
| | | return; |
| | | } |
| | | callback(); |
| | | }; |
| | | |
| | | const taskRules = { |
| | | inspectionName: [{ required: true, message: "请输入巡检任务名称", trigger: "blur" }], |
| | | lineName: [{ required: true, message: "请输入线路名称", trigger: "blur" }], |
| | | inspectionProject: [{ required: true, message: "请输入巡检项目", trigger: "blur" }], |
| | | inspectorIds: [{ type: "array", required: true, message: "请选择巡检人", trigger: "change" }], |
| | | frequencyType: [{ required: true, message: "请选择任务频率", trigger: "change" }], |
| | | frequencyDetail: [{ required: true, validator: validateFrequencyDetail, trigger: "change" }] |
| | | }; |
| | | |
| | | const inspectionRules = { |
| | | inspectionCode: [{ required: true, message: "请输入巡检编号", trigger: "blur" }], |
| | | inspectionName: [{ required: true, message: "请输入巡检名称", trigger: "blur" }], |
| | | lineName: [{ required: true, message: "请输入线路名称", trigger: "blur" }], |
| | | inspectorIds: [{ required: true, message: "请选择巡检人", trigger: "change" }] |
| | | inspectorIds: [{ type: "array", required: true, message: "请选择巡检人", trigger: "change" }] |
| | | }; |
| | | |
| | | const recordRules = { |
| | |
| | | hazardLocation: [{ required: true, message: "请输入隐患位置", trigger: "blur" }] |
| | | }; |
| | | |
| | | // 响应式数据 |
| | | const data = reactive({ |
| | | searchForm: { |
| | | inspectionCode: "", |
| | | inspectionName: "", |
| | | lineName: "", |
| | | status: "" |
| | | }, |
| | | tableLoading: false, |
| | | page: { |
| | | current: 1, |
| | | size: 20, |
| | | total: 0 |
| | | }, |
| | | tableData: [], |
| | | selectedIds: [], |
| | | form: { |
| | | id: null, |
| | | inspectionCode: "", |
| | | inspectionName: "", |
| | | lineName: "", |
| | | inspectionType: "", |
| | | planTime: "", |
| | | inspectorId: "", |
| | | inspectorIds: [], |
| | | remark: "" |
| | | }, |
| | | dialogVisible: false, |
| | | dialogTitle: "", |
| | | dialogType: "add", |
| | | // 巡检记录 |
| | | currentInspectionId: null, |
| | | currentInspectionStatus: "", |
| | | recordDialogVisible: false, |
| | | recordFormVisible: false, |
| | | recordList: [], |
| | | recordForm: { |
| | | id: null, |
| | | inspectionId: null, |
| | | checkPoint: "", |
| | | checkContent: "", |
| | | checkResult: "正常", |
| | | checkDesc: "", |
| | | checkTime: "", |
| | | storageBlobDTOs: [] |
| | | }, |
| | | // 隐患管理 |
| | | hazardDialogVisible: false, |
| | | hazardFormVisible: false, |
| | | hazardDialogTitle: "上报隐患", |
| | | hazardList: [], |
| | | hazardForm: { |
| | | id: null, |
| | | inspectionId: null, |
| | | hazardDesc: "", |
| | | hazardLevel: "", |
| | | hazardLocation: "" |
| | | }, |
| | | rectifyFormVisible: false, |
| | | rectifyForm: { |
| | | id: null, |
| | | rectifyDesc: "" |
| | | } |
| | | const rectifyRules = { |
| | | rectifyDesc: [{ required: true, message: "请输入整改说明", trigger: "blur" }], |
| | | storageBlobDTOs: [{ required: true, message: "请上传整改后照片", trigger: "change" }] |
| | | }; |
| | | |
| | | const riskLevelList = [ |
| | | { value: "重大风险", label: "重大风险" }, |
| | | { value: "较大风险", label: "较大风险" }, |
| | | { value: "一般风险", label: "一般风险" }, |
| | | { value: "低风险", label: "低风险" } |
| | | ]; |
| | | |
| | | const hiddenTypeOptions = computed(() => { |
| | | const list = hidden_danger_type?.value || []; |
| | | return list.length ? list : [{ label: "线路巡检", value: "线路巡检" }]; |
| | | }); |
| | | |
| | | const { |
| | | searchForm, |
| | | tableLoading, |
| | | page, |
| | | tableData, |
| | | selectedIds, |
| | | form, |
| | | dialogVisible, |
| | | dialogTitle, |
| | | dialogType, |
| | | currentInspectionId, |
| | | currentInspectionStatus, |
| | | 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"; |
| | | const validateAbnormalRequired = message => (rule, value, callback) => { |
| | | if (executeForm.checkResult !== "异常") { |
| | | callback(); |
| | | return; |
| | | } |
| | | if (Array.isArray(value) ? value.length === 0 : value === "" || value === null || value === undefined) { |
| | | callback(new Error(message)); |
| | | return; |
| | | } |
| | | callback(); |
| | | }; |
| | | |
| | | const executeRules = { |
| | | checkResult: [{ required: true, message: "请选择巡检结果", trigger: "change" }], |
| | | checkTime: [{ required: true, message: "请选择巡检时间", trigger: "change" }], |
| | | storageBlobDTOs: [{ validator: validateAbnormalRequired("巡检异常时请上传异常照片"), trigger: "change" }], |
| | | hiddenType: [{ validator: validateAbnormalRequired("请选择隐患类型"), trigger: "change" }], |
| | | riskLevel: [{ validator: validateAbnormalRequired("请选择风险等级"), trigger: "change" }], |
| | | hazardLocation: [{ validator: validateAbnormalRequired("请输入隐患位置"), trigger: "blur" }], |
| | | hazardDesc: [{ validator: validateAbnormalRequired("请输入异常描述/整改要求"), trigger: "blur" }], |
| | | rectifyUserId: [{ validator: validateAbnormalRequired("请选择整改责任人"), trigger: "change" }], |
| | | rectifyTime: [{ validator: validateAbnormalRequired("请选择整改期限"), trigger: "change" }] |
| | | }; |
| | | |
| | | const taskColumns = [ |
| | | { label: "巡检任务名称", prop: "inspectionName", minWidth: 165, dataType: "slot", slot: "taskName", align: "left" }, |
| | | { label: "线路名称", prop: "lineName", minWidth: 150, showOverflowTooltip: true, align: "left" }, |
| | | { label: "巡检项目", prop: "inspectionProject", minWidth: 175, showOverflowTooltip: true, align: "left" }, |
| | | { label: "执行巡检人", prop: "inspectorName", minWidth: 145, dataType: "slot", slot: "inspectorName", align: "center" }, |
| | | { label: "是否启用", prop: "isEnabled", minWidth: 90, dataType: "slot", slot: "isEnabled", align: "center" }, |
| | | { |
| | | label: "频次", |
| | | prop: "frequencyType", |
| | | minWidth: 85, |
| | | align: "center", |
| | | formatData: value => frequencyTypeMap[value] || value || "--" |
| | | }, |
| | | { |
| | | label: "开始日期与时间", |
| | | prop: "frequencyDetail", |
| | | minWidth: 150, |
| | | align: "center", |
| | | formatData: value => formatFrequencyDetail(value) |
| | | }, |
| | | { label: "下次执行时间", prop: "nextExecutionTime", minWidth: 170, showOverflowTooltip: true, align: "center" }, |
| | | { |
| | | dataType: "action", |
| | | label: "操作", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 350, |
| | | width: 220, |
| | | operation: [ |
| | | { |
| | | name: "历史巡检", |
| | | type: "text", |
| | | clickFun: row => openTaskHistory(row) |
| | | }, |
| | | { |
| | | name: "编辑", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openForm("edit", row); |
| | | }, |
| | | disabled: 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 === "巡检中" |
| | | clickFun: row => openTaskDialog("edit", row) |
| | | }, |
| | | { |
| | | name: "删除", |
| | | type: "text", |
| | | style: { color: "#F56C6C" }, |
| | | clickFun: row => { |
| | | handleDelete(row); |
| | | clickFun: row => handleDeleteTask(row) |
| | | } |
| | | ] |
| | | } |
| | | ]; |
| | | |
| | | const taskHistoryColumns = [ |
| | | { label: "巡检编号", prop: "inspectionCode", width: 190, dataType: "slot", slot: "inspectionCode", align: "center" }, |
| | | { label: "巡检名称", prop: "inspectionName", minWidth: 135, showOverflowTooltip: true, align: "left" }, |
| | | { label: "线路名称", prop: "lineName", minWidth: 130, showOverflowTooltip: true, align: "left" }, |
| | | { label: "巡检项目", prop: "inspectionProject", minWidth: 150, showOverflowTooltip: true, align: "left" }, |
| | | { label: "计划巡检时间", prop: "planTime", width: 165, showOverflowTooltip: true, align: "center" }, |
| | | { label: "巡检结果", prop: "inspectionResult", width: 90, dataType: "slot", slot: "inspectionResult", align: "center" }, |
| | | { label: "实际巡检时间", prop: "actualInspectionTime", width: 165, showOverflowTooltip: true, align: "center" }, |
| | | { label: "巡检人", prop: "inspectorName", minWidth: 105, dataType: "slot", slot: "inspectorName", align: "center" }, |
| | | { label: "状态", prop: "status", width: 90, dataType: "slot", slot: "status", align: "center" } |
| | | ]; |
| | | |
| | | const recordColumns = [ |
| | | { label: "巡检编号", prop: "inspectionCode", width: 190, dataType: "slot", slot: "inspectionCode", align: "center" }, |
| | | { label: "巡检名称", prop: "inspectionName", minWidth: 135, showOverflowTooltip: true, align: "left" }, |
| | | { label: "线路名称", prop: "lineName", minWidth: 130, showOverflowTooltip: true, align: "left" }, |
| | | { label: "巡检项目", prop: "inspectionProject", minWidth: 145, showOverflowTooltip: true, align: "left" }, |
| | | { label: "计划巡检时间", prop: "planTime", width: 165, showOverflowTooltip: true, align: "center" }, |
| | | { label: "巡检结果", prop: "inspectionResult", width: 90, dataType: "slot", slot: "inspectionResult", align: "center" }, |
| | | { label: "实际巡检时间", prop: "actualInspectionTime", width: 165, showOverflowTooltip: true, align: "center" }, |
| | | { label: "巡检人", prop: "inspectorName", minWidth: 105, dataType: "slot", slot: "inspectorName", align: "center" }, |
| | | { label: "状态", prop: "status", width: 90, dataType: "slot", slot: "status", align: "center" }, |
| | | { |
| | | dataType: "action", |
| | | label: "操作", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 125, |
| | | operation: [ |
| | | { |
| | | name: "执行巡检", |
| | | type: "text", |
| | | clickFun: row => openExecuteDialog(row), |
| | | show: row => row.status !== "已完成" && row.status !== "待整改" |
| | | }, |
| | | { |
| | | name: "删除", |
| | | type: "text", |
| | | style: { color: "#F56C6C" }, |
| | | clickFun: row => handleDeleteInspection(row), |
| | | disabled: row => row.status !== "待巡检" |
| | | } |
| | | ] |
| | | } |
| | | ]); |
| | | ]; |
| | | |
| | | // 生命周期 |
| | | const rectifyColumns = [ |
| | | { label: "隐患编号", prop: "hazardCode", width: 135, showOverflowTooltip: true, align: "center" }, |
| | | { label: "巡检编号", prop: "inspectionCode", width: 190, dataType: "slot", slot: "inspectionCode", align: "center" }, |
| | | { label: "巡检名称", prop: "inspectionName", minWidth: 120, showOverflowTooltip: true, align: "left" }, |
| | | { label: "线路名称", prop: "lineName", minWidth: 120, showOverflowTooltip: true, align: "left" }, |
| | | { label: "异常描述", prop: "hazardDesc", minWidth: 160, showOverflowTooltip: true, align: "left" }, |
| | | { label: "异常位置", prop: "hazardLocation", minWidth: 130, showOverflowTooltip: true, align: "left" }, |
| | | { label: "风险等级", prop: "hazardLevel", width: 95, dataType: "slot", slot: "hazardLevel", align: "center" }, |
| | | { label: "整改责任人", prop: "rectifyUserName", minWidth: 110, showOverflowTooltip: true, align: "center" }, |
| | | { label: "整改期限", prop: "rectifyDeadline", width: 110, showOverflowTooltip: true, align: "center" }, |
| | | { label: "整改状态", prop: "status", width: 95, dataType: "slot", slot: "hazardStatus", align: "center" }, |
| | | { |
| | | dataType: "action", |
| | | label: "操作", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 85, |
| | | operation: [ |
| | | { |
| | | name: "整改", |
| | | type: "text", |
| | | color: "#67C23A", |
| | | clickFun: row => handleRectify(row), |
| | | show: row => row.status !== "已整改" && canRectify(row) |
| | | } |
| | | ] |
| | | } |
| | | ]; |
| | | |
| | | const tableColumns = computed(() => { |
| | | if (activeTab.value === "task") { |
| | | return taskColumns; |
| | | } |
| | | if (activeTab.value === "record") { |
| | | return recordColumns; |
| | | } |
| | | return rectifyColumns; |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | userListNoPage().then(res => { |
| | | userList.value = res.data; |
| | | 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 = () => { |
| | | const getList = async () => { |
| | | 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; |
| | | try { |
| | | const params = cleanParams({ |
| | | current: page.current, |
| | | size: page.size, |
| | | ...getActiveSearchForm() |
| | | }); |
| | | const api = getActiveListApi(); |
| | | const res = await api(params); |
| | | tableData.value = res.data?.records || []; |
| | | page.total = res.data?.total || 0; |
| | | } finally { |
| | | tableLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | // 分页处理 |
| | | const pagination = obj => { |
| | | page.value.current = obj.page; |
| | | page.value.size = obj.limit; |
| | | const getActiveSearchForm = () => { |
| | | if (activeTab.value === "task") { |
| | | return taskSearchForm; |
| | | } |
| | | if (activeTab.value === "record") { |
| | | return recordSearchForm; |
| | | } |
| | | return rectifySearchForm; |
| | | }; |
| | | |
| | | const getActiveListApi = () => { |
| | | if (activeTab.value === "task") { |
| | | return getLineInspectionTaskList; |
| | | } |
| | | if (activeTab.value === "record") { |
| | | return getLineInspectionList; |
| | | } |
| | | return getInspectionHazards; |
| | | }; |
| | | |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | // 选择变化处理 |
| | | const resetQuery = () => { |
| | | page.current = 1; |
| | | if (activeTab.value === "task") { |
| | | Object.assign(taskSearchForm, { inspectionName: "", lineName: "", isEnabled: "" }); |
| | | } else if (activeTab.value === "record") { |
| | | Object.assign(recordSearchForm, { inspectionCode: "", inspectionName: "", lineName: "" }); |
| | | } else { |
| | | Object.assign(rectifySearchForm, { hazardCode: "", hazardDesc: "", status: "" }); |
| | | } |
| | | getList(); |
| | | }; |
| | | |
| | | const handleTabChange = () => { |
| | | selectedIds.value = []; |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const handleModuleTabChange = tab => { |
| | | if (activeTab.value === tab) { |
| | | return; |
| | | } |
| | | activeTab.value = tab; |
| | | handleTabChange(); |
| | | }; |
| | | |
| | | const pagination = obj => { |
| | | page.current = obj.page; |
| | | page.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 openTaskDetail = row => { |
| | | taskDetail.value = { ...row }; |
| | | taskDetailVisible.value = true; |
| | | }; |
| | | |
| | | const getAttachments = row => row?.storageBlobDTOs || row?.storageBlobVOs || []; |
| | | const hasAttachments = attachments => Array.isArray(attachments) && attachments.length > 0; |
| | | const openTaskHistory = row => { |
| | | taskHistoryTask.value = { ...row }; |
| | | taskHistoryPage.current = 1; |
| | | taskHistoryVisible.value = true; |
| | | fetchTaskHistory(); |
| | | }; |
| | | |
| | | // 打开表单 |
| | | 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: "" |
| | | const fetchTaskHistory = async () => { |
| | | if (!taskHistoryTask.value?.id) { |
| | | taskHistoryData.value = []; |
| | | taskHistoryPage.total = 0; |
| | | return; |
| | | } |
| | | taskHistoryLoading.value = true; |
| | | try { |
| | | const res = await getLineInspectionList( |
| | | cleanParams({ |
| | | current: taskHistoryPage.current, |
| | | size: taskHistoryPage.size, |
| | | scheduleTaskId: taskHistoryTask.value.id |
| | | }) |
| | | ); |
| | | taskHistoryData.value = res.data?.records || []; |
| | | taskHistoryPage.total = res.data?.total || 0; |
| | | } finally { |
| | | taskHistoryLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const taskHistoryPagination = obj => { |
| | | taskHistoryPage.current = obj.page; |
| | | taskHistoryPage.size = obj.limit; |
| | | fetchTaskHistory(); |
| | | }; |
| | | |
| | | const openInspectionDetailEntry = row => { |
| | | if (activeTab.value === "rectify") { |
| | | openInspectionDetailById(row.inspectionId, row); |
| | | return; |
| | | } |
| | | openInspectionDetail(row); |
| | | }; |
| | | |
| | | const openInspectionDetailById = async (inspectionId, fallback = {}) => { |
| | | let row = { |
| | | id: inspectionId, |
| | | inspectionCode: fallback.inspectionCode, |
| | | inspectionName: fallback.inspectionName, |
| | | lineName: fallback.lineName |
| | | }; |
| | | if (inspectionId) { |
| | | const res = await getLineInspectionById(inspectionId); |
| | | if (res.code === 200 && res.data) { |
| | | row = { ...row, ...res.data }; |
| | | } |
| | | } |
| | | openInspectionDetail(row); |
| | | }; |
| | | |
| | | const openInspectionDetail = async row => { |
| | | if (!row?.id) { |
| | | ElMessage.warning("巡检记录不存在"); |
| | | return; |
| | | } |
| | | inspectionDetail.value = { ...row }; |
| | | inspectionDetailVisible.value = true; |
| | | inspectionDetailLoading.value = true; |
| | | try { |
| | | const [recordsRes, hazardsRes] = await Promise.all([ |
| | | getInspectionRecords(row.id), |
| | | getHazardsByInspectionId(row.id) |
| | | ]); |
| | | inspectionDetailRecords.value = recordsRes.code === 200 ? recordsRes.data || [] : []; |
| | | inspectionDetailHazards.value = hazardsRes.code === 200 ? hazardsRes.data || [] : []; |
| | | } finally { |
| | | inspectionDetailLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const openExecuteDialog = row => { |
| | | currentInspection.value = { ...row }; |
| | | Object.assign(executeForm, createExecuteForm(), { |
| | | inspectionId: row.id, |
| | | checkTime: formatDateTime(new Date()), |
| | | hazardLocation: row.lineName || "" |
| | | }); |
| | | } 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, { |
| | | executeDialogVisible.value = true; |
| | | }; |
| | | |
| | | const resetExecuteForm = () => { |
| | | Object.assign(executeForm, createExecuteForm()); |
| | | currentInspection.value = {}; |
| | | executeFormRef.value?.clearValidate?.(); |
| | | }; |
| | | |
| | | const handleExecuteResultChange = () => { |
| | | if (executeForm.checkResult === "异常") { |
| | | executeForm.hazardLocation = executeForm.hazardLocation || currentInspection.value.lineName || ""; |
| | | executeForm.checkDesc = ""; |
| | | } |
| | | executeFormRef.value?.clearValidate?.(); |
| | | }; |
| | | |
| | | const handleRectifyUserChange = userId => { |
| | | const selectedUser = userList.value.find(user => Number(user.userId) === Number(userId)); |
| | | executeForm.rectifyUserMobile = selectedUser?.phonenumber || ""; |
| | | }; |
| | | |
| | | const submitExecuteForm = async () => { |
| | | try { |
| | | await executeFormRef.value.validate(); |
| | | const payload = { ...executeForm }; |
| | | if (payload.checkResult === "正常") { |
| | | Object.assign(payload, { |
| | | storageBlobDTOs: [], |
| | | hiddenType: "", |
| | | riskLevel: "", |
| | | hazardLocation: "", |
| | | hazardDesc: "", |
| | | rectifyUserId: "", |
| | | rectifyUserMobile: "", |
| | | rectifyTime: "" |
| | | }); |
| | | } else { |
| | | payload.checkDesc = ""; |
| | | } |
| | | const res = await executeLineInspection(payload); |
| | | if (res.code === 200) { |
| | | ElMessage.success(payload.checkResult === "异常" ? "异常已上报整改" : "巡检已完成"); |
| | | executeDialogVisible.value = false; |
| | | getList(); |
| | | } else { |
| | | ElMessage.error(res.msg || "巡检提交失败"); |
| | | } |
| | | } catch (error) { |
| | | console.error("执行巡检表单校验失败:", error); |
| | | } |
| | | }; |
| | | |
| | | const openTaskDialog = (type, row = null) => { |
| | | resetTaskForm(); |
| | | taskDialogTitle.value = type === "add" ? "新增巡检任务" : "编辑巡检任务"; |
| | | if (type === "edit" && row) { |
| | | Object.assign(taskForm, { |
| | | id: row.id, |
| | | inspectionCode: row.inspectionCode, |
| | | inspectionName: row.inspectionName, |
| | | lineName: row.lineName, |
| | | inspectionType: row.inspectionType, |
| | | planTime: row.planTime, |
| | | inspectionProject: row.inspectionProject, |
| | | inspectorId: row.inspectorId, |
| | | inspectorIds: inspectorIds, |
| | | inspectorIds: parseInspectorIds(row.inspectorId), |
| | | frequencyType: row.frequencyType, |
| | | frequencyDetail: row.frequencyDetail, |
| | | isEnabled: row.isEnabled ?? ENABLED, |
| | | remark: row.remark |
| | | }); |
| | | parseFrequencyDetail(row.frequencyType, row.frequencyDetail); |
| | | } |
| | | dialogVisible.value = true; |
| | | taskDialogVisible.value = true; |
| | | }; |
| | | |
| | | // 提交表单 |
| | | const submitForm = async () => { |
| | | const resetTaskForm = () => { |
| | | Object.assign(taskForm, createTaskForm()); |
| | | taskFormRef.value?.clearValidate?.(); |
| | | }; |
| | | |
| | | const handleFrequencyTypeChange = () => { |
| | | Object.assign(taskForm, { frequencyDetail: "", week: "", day: "", time: "" }); |
| | | taskFormRef.value?.clearValidate?.("frequencyDetail"); |
| | | }; |
| | | |
| | | const parseFrequencyDetail = (frequencyType, frequencyDetail) => { |
| | | if (!frequencyDetail) { |
| | | return; |
| | | } |
| | | if (frequencyType === "DAILY") { |
| | | taskForm.frequencyDetail = frequencyDetail; |
| | | return; |
| | | } |
| | | const [firstPart, timePart] = frequencyDetail.split(","); |
| | | taskForm.frequencyDetail = ""; |
| | | taskForm.time = timePart || ""; |
| | | if (frequencyType === "WEEKLY") { |
| | | taskForm.week = firstPart || ""; |
| | | } |
| | | if (frequencyType === "MONTHLY") { |
| | | taskForm.day = String(firstPart || "").padStart(2, "0"); |
| | | } |
| | | }; |
| | | |
| | | const submitTaskForm = async () => { |
| | | try { |
| | | await formRef.value.validate(); |
| | | // 将数组转换为逗号分隔的字符串 |
| | | const submitData = { |
| | | ...form.value, |
| | | inspectorId: form.value.inspectorIds ? form.value.inspectorIds.join(",") : "" |
| | | await taskFormRef.value.validate(); |
| | | const payload = { |
| | | id: taskForm.id, |
| | | inspectionName: taskForm.inspectionName, |
| | | lineName: taskForm.lineName, |
| | | inspectionProject: taskForm.inspectionProject, |
| | | inspectorId: taskForm.inspectorIds.join(","), |
| | | frequencyType: taskForm.frequencyType, |
| | | frequencyDetail: buildFrequencyDetail(), |
| | | isEnabled: taskForm.isEnabled, |
| | | remark: taskForm.remark |
| | | }; |
| | | delete submitData.inspectorIds; |
| | | |
| | | const api = dialogType.value === "add" ? addLineInspection : updateLineInspection; |
| | | const res = await api(submitData); |
| | | const api = taskForm.id ? updateLineInspectionTask : addLineInspectionTask; |
| | | const res = await api(payload); |
| | | if (res.code === 200) { |
| | | ElMessage.success(dialogType.value === "add" ? "添加成功" : "更新成功"); |
| | | dialogVisible.value = false; |
| | | ElMessage.success(taskForm.id ? "修改成功" : "新增成功"); |
| | | taskDialogVisible.value = false; |
| | | getList(); |
| | | } else { |
| | | ElMessage.error(res.msg || "操作失败"); |
| | | } |
| | | } catch (error) { |
| | | console.error("表单验证失败:", error); |
| | | console.error("任务表单校验失败:", error); |
| | | } |
| | | }; |
| | | |
| | | // 删除 |
| | | 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 || "删除失败"); |
| | | const buildFrequencyDetail = () => { |
| | | if (taskForm.frequencyType === "DAILY") { |
| | | return taskForm.frequencyDetail; |
| | | } |
| | | }) |
| | | .catch(() => {}); |
| | | if (taskForm.frequencyType === "WEEKLY") { |
| | | return `${taskForm.week},${taskForm.time}`; |
| | | } |
| | | if (taskForm.frequencyType === "MONTHLY") { |
| | | return `${taskForm.day},${taskForm.time}`; |
| | | } |
| | | return ""; |
| | | }; |
| | | |
| | | // 完成巡检 |
| | | const handleComplete = row => { |
| | | ElMessageBox.confirm("确认完成该巡检任务吗?", "完成巡检", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning" |
| | | }) |
| | | .then(async () => { |
| | | const res = await completeLineInspection(row.id); |
| | | const handleDeleteTask = row => { |
| | | confirmDelete("确认删除该定时巡检任务吗?", async () => { |
| | | const res = await deleteLineInspectionTask([row.id]); |
| | | handleDeleteResult(res); |
| | | }); |
| | | }; |
| | | |
| | | const handleBatchDeleteTask = () => { |
| | | if (selectedIds.value.length === 0) { |
| | | ElMessage.warning("请选择要删除的巡检任务"); |
| | | return; |
| | | } |
| | | confirmDelete("确认删除选中的定时巡检任务吗?", async () => { |
| | | const res = await deleteLineInspectionTask(selectedIds.value); |
| | | handleDeleteResult(res); |
| | | }); |
| | | }; |
| | | |
| | | const openInspectionDialog = row => { |
| | | resetInspectionForm(); |
| | | Object.assign(inspectionForm, { |
| | | id: row.id, |
| | | scheduleTaskId: row.scheduleTaskId, |
| | | inspectionCode: row.inspectionCode, |
| | | inspectionName: row.inspectionName, |
| | | lineName: row.lineName, |
| | | inspectionType: row.inspectionType, |
| | | inspectionProject: row.inspectionProject, |
| | | planTime: row.planTime, |
| | | inspectorId: row.inspectorId, |
| | | inspectorIds: parseInspectorIds(row.inspectorId), |
| | | status: row.status, |
| | | remark: row.remark |
| | | }); |
| | | inspectionDialogVisible.value = true; |
| | | }; |
| | | |
| | | const resetInspectionForm = () => { |
| | | Object.assign(inspectionForm, createInspectionForm()); |
| | | inspectionFormRef.value?.clearValidate?.(); |
| | | }; |
| | | |
| | | const submitInspectionForm = async () => { |
| | | try { |
| | | await inspectionFormRef.value.validate(); |
| | | const payload = { |
| | | ...inspectionForm, |
| | | inspectorId: inspectionForm.inspectorIds.join(",") |
| | | }; |
| | | delete payload.inspectorIds; |
| | | const res = await updateLineInspection(payload); |
| | | if (res.code === 200) { |
| | | ElMessage.success("巡检已完成"); |
| | | ElMessage.success("修改成功"); |
| | | inspectionDialogVisible.value = false; |
| | | getList(); |
| | | } else { |
| | | ElMessage.error(res.msg || "操作失败"); |
| | | } |
| | | }) |
| | | .catch(() => {}); |
| | | } catch (error) { |
| | | console.error("巡检记录表单校验失败:", error); |
| | | } |
| | | }; |
| | | |
| | | // 打开巡检记录弹窗 |
| | | const handleDeleteInspection = row => { |
| | | confirmDelete("确认删除该巡检记录吗?", async () => { |
| | | const res = await deleteLineInspection([row.id]); |
| | | handleDeleteResult(res); |
| | | }); |
| | | }; |
| | | |
| | | const openRecordDialog = row => { |
| | | currentInspectionId.value = row.id; |
| | | currentInspectionStatus.value = row.status; |
| | |
| | | recordDialogVisible.value = true; |
| | | }; |
| | | |
| | | // 获取巡检记录 |
| | | const fetchRecords = async inspectionId => { |
| | | const res = await getInspectionRecords(inspectionId); |
| | | if (res.code === 200) { |
| | |
| | | } |
| | | }; |
| | | |
| | | // 打开记录表单 |
| | | const openRecordForm = () => { |
| | | Object.assign(recordForm.value, { |
| | | Object.assign(recordForm, { |
| | | id: null, |
| | | inspectionId: currentInspectionId.value, |
| | | checkPoint: "", |
| | |
| | | recordFormVisible.value = true; |
| | | }; |
| | | |
| | | // 打开编辑记录表单 |
| | | const openEditRecordForm = (row) => { |
| | | Object.assign(recordForm.value, { |
| | | const openEditRecordForm = row => { |
| | | Object.assign(recordForm, { |
| | | id: row.id, |
| | | inspectionId: row.inspectionId, |
| | | checkPoint: row.checkPoint, |
| | |
| | | recordFormVisible.value = true; |
| | | }; |
| | | |
| | | // 删除巡检记录 |
| | | const handleDeleteRecord = (row) => { |
| | | ElMessageBox.confirm("确认删除该巡检记录吗?", "删除", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning" |
| | | }).then(async () => { |
| | | const handleDeleteRecord = row => { |
| | | confirmDelete("确认删除该巡检记录明细吗?", async () => { |
| | | const res = await deleteInspectionRecord([row.id]); |
| | | if (res.code === 200) { |
| | | ElMessage.success("删除成功"); |
| | |
| | | } else { |
| | | ElMessage.error(res.msg || "删除失败"); |
| | | } |
| | | }).catch(() => {}); |
| | | }); |
| | | }; |
| | | |
| | | // 提交记录表单 |
| | | const submitRecordForm = async () => { |
| | | try { |
| | | await recordFormRef.value.validate(); |
| | | if (recordForm.value.checkResult === "异常" && !hasAttachments(recordForm.value.storageBlobDTOs)) { |
| | | if (recordForm.checkResult === "异常" && !hasAttachments(recordForm.storageBlobDTOs)) { |
| | | ElMessage.warning("巡检结果异常时请上传现场照片"); |
| | | return; |
| | | } |
| | | const api = recordForm.value.id ? updateInspectionRecord : addInspectionRecord; |
| | | const res = await api({ ...recordForm.value }); |
| | | const api = recordForm.id ? updateInspectionRecord : addInspectionRecord; |
| | | const res = await api({ ...recordForm }); |
| | | if (res.code === 200) { |
| | | ElMessage.success(recordForm.value.id ? "修改成功" : "添加成功"); |
| | | ElMessage.success(recordForm.id ? "修改成功" : "添加成功"); |
| | | recordFormVisible.value = false; |
| | | fetchRecords(currentInspectionId.value); |
| | | getList(); |
| | | } else { |
| | | ElMessage.error(res.msg || "操作失败"); |
| | | } |
| | | } catch (error) { |
| | | console.error("表单验证失败:", error); |
| | | console.error("巡检记录明细表单校验失败:", error); |
| | | } |
| | | }; |
| | | |
| | | // 打开隐患管理弹窗 |
| | | const openHazardDialog = row => { |
| | | currentInspectionId.value = row.id; |
| | | currentInspectionStatus.value = row.status; |
| | |
| | | hazardDialogVisible.value = true; |
| | | }; |
| | | |
| | | // 获取隐患列表 |
| | | const fetchHazards = async inspectionId => { |
| | | const res = await getHazardsByInspectionId(inspectionId); |
| | | if (res.code === 200) { |
| | |
| | | } |
| | | }; |
| | | |
| | | // 打开隐患表单 |
| | | const openHazardForm = (type, row = null) => { |
| | | if (type === "add") { |
| | | hazardDialogTitle.value = "上报隐患"; |
| | | Object.assign(hazardForm.value, { |
| | | Object.assign(hazardForm, { |
| | | id: null, |
| | | inspectionId: currentInspectionId.value, |
| | | hazardDesc: "", |
| | |
| | | }); |
| | | } else { |
| | | hazardDialogTitle.value = "编辑隐患"; |
| | | Object.assign(hazardForm.value, { |
| | | Object.assign(hazardForm, { |
| | | id: row.id, |
| | | inspectionId: row.inspectionId, |
| | | hazardDesc: row.hazardDesc, |
| | |
| | | hazardFormVisible.value = true; |
| | | }; |
| | | |
| | | // 提交隐患表单 |
| | | const submitHazardForm = async () => { |
| | | try { |
| | | await hazardFormRef.value.validate(); |
| | | const api = hazardForm.value.id ? updateInspectionHazard : addInspectionHazard; |
| | | const res = await api({ ...hazardForm.value }); |
| | | const api = hazardForm.id ? updateInspectionHazard : addInspectionHazard; |
| | | const res = await api({ ...hazardForm }); |
| | | if (res.code === 200) { |
| | | ElMessage.success("操作成功"); |
| | | hazardFormVisible.value = false; |
| | |
| | | ElMessage.error(res.msg || "操作失败"); |
| | | } |
| | | } catch (error) { |
| | | console.error("表单验证失败:", error); |
| | | console.error("隐患表单校验失败:", error); |
| | | } |
| | | }; |
| | | |
| | | // 整改 |
| | | const handleRectify = row => { |
| | | Object.assign(rectifyForm.value, { |
| | | if (!canRectify(row)) { |
| | | ElMessage.warning("只有整改责任人可以进行整改"); |
| | | return; |
| | | } |
| | | currentInspectionId.value = row.inspectionId || currentInspectionId.value; |
| | | Object.assign(rectifyForm, { |
| | | id: row.id, |
| | | rectifyDesc: "" |
| | | rectifyDesc: "", |
| | | storageBlobDTOs: [] |
| | | }); |
| | | rectifyFormVisible.value = true; |
| | | }; |
| | | |
| | | // 提交整改表单 |
| | | const resetRectifyForm = () => { |
| | | Object.assign(rectifyForm, { |
| | | id: null, |
| | | rectifyDesc: "", |
| | | storageBlobDTOs: [] |
| | | }); |
| | | rectifyFormRef.value?.clearValidate?.(); |
| | | }; |
| | | |
| | | const submitRectifyForm = async () => { |
| | | await rectifyFormRef.value.validate(); |
| | | if (!hasAttachments(rectifyForm.storageBlobDTOs)) { |
| | | ElMessage.warning("请上传整改后照片"); |
| | | return; |
| | | } |
| | | const res = await updateInspectionHazard({ |
| | | id: rectifyForm.value.id, |
| | | id: rectifyForm.id, |
| | | status: "已整改", |
| | | rectifyDesc: rectifyForm.value.rectifyDesc |
| | | rectifyDesc: rectifyForm.rectifyDesc, |
| | | storageBlobDTOs: rectifyForm.storageBlobDTOs |
| | | }); |
| | | if (res.code === 200) { |
| | | ElMessage.success("整改成功"); |
| | | rectifyFormVisible.value = false; |
| | | if (currentInspectionId.value) { |
| | | fetchHazards(currentInspectionId.value); |
| | | } |
| | | getList(); |
| | | } else { |
| | | ElMessage.error(res.msg || "整改失败"); |
| | | } |
| | | }; |
| | | |
| | | const canRectify = row => { |
| | | return Number(row?.rectifyUserId) === currentUserId.value; |
| | | }; |
| | | |
| | | const confirmDelete = (message, onConfirm) => { |
| | | ElMessageBox.confirm(message, "删除", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning" |
| | | }) |
| | | .then(onConfirm) |
| | | .catch(() => {}); |
| | | }; |
| | | |
| | | const handleDeleteResult = res => { |
| | | if (res.code === 200) { |
| | | ElMessage.success("删除成功"); |
| | | selectedIds.value = []; |
| | | getList(); |
| | | } else { |
| | | ElMessage.error(res.msg || "删除失败"); |
| | | } |
| | | }; |
| | | |
| | | const cleanParams = params => { |
| | | return Object.fromEntries( |
| | | Object.entries(params).filter(([, value]) => value !== "" && value !== null && value !== undefined) |
| | | ); |
| | | }; |
| | | |
| | | const getInspectionStatusType = status => { |
| | | const map = { |
| | | 待巡检: "info", |
| | | 巡检中: "warning", |
| | | 待整改: "danger", |
| | | 已完成: "success" |
| | | }; |
| | | return map[status] || "info"; |
| | | }; |
| | | |
| | | const getInspectionResultType = result => { |
| | | const map = { |
| | | 正常: "success", |
| | | 异常: "danger" |
| | | }; |
| | | return map[result] || "info"; |
| | | }; |
| | | |
| | | const getHazardStatusType = status => { |
| | | const map = { |
| | | 待整改: "danger", |
| | | 整改中: "warning", |
| | | 已整改: "success" |
| | | }; |
| | | return map[status] || "info"; |
| | | }; |
| | | |
| | | const getRiskLevelType = level => { |
| | | const map = { |
| | | 重大风险: "danger", |
| | | 较大风险: "warning", |
| | | 一般风险: "primary", |
| | | 低风险: "info", |
| | | 重大: "danger", |
| | | 一般: "warning" |
| | | }; |
| | | return map[level] || "info"; |
| | | }; |
| | | |
| | | const getInspectorNames = row => { |
| | | if (Array.isArray(row.inspector)) { |
| | | return row.inspector.filter(Boolean); |
| | | } |
| | | if (!row.inspectorName && row.inspectorId) { |
| | | return parseInspectorIds(row.inspectorId) |
| | | .map(id => userList.value.find(user => Number(user.userId) === Number(id))?.nickName) |
| | | .filter(Boolean); |
| | | } |
| | | return String(row.inspectorName || "") |
| | | .split(",") |
| | | .map(item => item.trim()) |
| | | .filter(Boolean); |
| | | }; |
| | | |
| | | const parseInspectorIds = inspectorId => { |
| | | return String(inspectorId || "") |
| | | .split(",") |
| | | .map(item => Number(item.trim())) |
| | | .filter(item => !Number.isNaN(item)); |
| | | }; |
| | | |
| | | const formatFrequencyDetail = value => { |
| | | if (!value) { |
| | | return "--"; |
| | | } |
| | | return String(value).replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, match => weekLabelMap[match] || match); |
| | | }; |
| | | |
| | | const getAttachments = row => row?.storageBlobDTOs || row?.storageBlobVOs || []; |
| | | const hasAttachments = attachments => Array.isArray(attachments) && attachments.length > 0; |
| | | const getAttachmentPreviewUrl = row => row?.previewURL || row?.previewUrl || row?.url || row?.downloadURL || row?.downloadUrl || ""; |
| | | const getAttachmentPreviewUrls = row => getAttachments(row).map(getAttachmentPreviewUrl).filter(Boolean); |
| | | |
| | | const formatDateTime = date => { |
| | | const pad = value => String(value).padStart(2, "0"); |
| | | return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`; |
| | | }; |
| | | |
| | | const setDialogFixedHeight = () => { |
| | | setTimeout(() => { |
| | | 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 onRecordDialogOpen = () => setDialogFixedHeight(); |
| | | const onHazardDialogOpen = () => setDialogFixedHeight(); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .line-inspection-page :deep(.table_list) { |
| | | width: 100%; |
| | | } |
| | | |
| | | .module-tabs { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 42px; |
| | | min-height: 58px; |
| | | margin-bottom: 16px; |
| | | padding: 0 28px; |
| | | border-bottom: 1px solid #d7e2f1; |
| | | } |
| | | |
| | | .module-tab { |
| | | position: relative; |
| | | border: 0; |
| | | background: transparent; |
| | | color: #1f2d3d; |
| | | font-size: 16px; |
| | | line-height: 58px; |
| | | cursor: pointer; |
| | | padding: 0; |
| | | } |
| | | |
| | | .module-tab.active { |
| | | color: #003bb3; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .module-tab.active::after { |
| | | position: absolute; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | height: 2px; |
| | | background: #003bb3; |
| | | content: ""; |
| | | } |
| | | |
| | | .line-search-panel { |
| | | justify-content: flex-start; |
| | | align-items: center; |
| | | gap: 16px; |
| | | min-height: 44px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .search-left { |
| | | display: flex; |
| | | flex: 1 1 auto; |
| | | flex-wrap: nowrap; |
| | | align-items: center; |
| | | gap: 14px; |
| | | min-width: 0; |
| | | padding-right: 12px; |
| | | } |
| | | |
| | | .filter-item, |
| | | .filter-buttons, |
| | | .toolbar-actions { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10px; |
| | | flex: 0 0 auto; |
| | | } |
| | | |
| | | .filter-control { |
| | | width: 210px; |
| | | } |
| | | |
| | | .filter-control.is-wide { |
| | | width: 240px; |
| | | } |
| | | |
| | | .filter-control.is-short { |
| | | width: 150px; |
| | | } |
| | | |
| | | .table-toolbar { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | gap: 16px; |
| | | margin-bottom: 12px; |
| | | min-height: 40px; |
| | | } |
| | | |
| | | .search_title { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .person-tags { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 4px; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .person-tag { |
| | | margin: 0; |
| | | } |
| | | |
| | | .task-name-link { |
| | | max-width: 100%; |
| | | padding: 0; |
| | | font-weight: 600; |
| | | vertical-align: middle; |
| | | } |
| | | |
| | | .task-name-link :deep(span), |
| | | .code-link :deep(span) { |
| | | display: inline-block; |
| | | max-width: 100%; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .code-link { |
| | | max-width: 100%; |
| | | padding: 0; |
| | | font-weight: 600; |
| | | vertical-align: middle; |
| | | } |
| | | |
| | | .detail-section-title { |
| | | margin: 18px 0 10px; |
| | | color: #1f2d3d; |
| | | font-size: 15px; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .history-summary { |
| | | margin-bottom: 14px; |
| | | } |
| | | |
| | | .execute-summary { |
| | | margin-bottom: 18px; |
| | | } |
| | | |
| | | .photo-list { |
| | | display: flex; |
| | | justify-content: center; |
| | | gap: 6px; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .record-photo { |
| | | width: 46px; |
| | | height: 46px; |
| | | border-radius: 4px; |
| | | border: 1px solid #dcdfe6; |
| | | } |
| | | |
| | | .frequency-row { |
| | | display: grid; |
| | | grid-template-columns: 132px minmax(170px, 1fr); |
| | | gap: 10px; |
| | | width: 100%; |
| | | } |
| | | |
| | | .frequency-day-select, |
| | | .frequency-time-picker { |
| | | width: 100%; |
| | | } |
| | | |
| | | :deep(.frequency-detail-item .el-form-item__label) { |
| | | width: 72px !important; |
| | | flex: 0 0 72px; |
| | | } |
| | | |
| | | .no-data { |
| | | color: #909399; |
| | | } |
| | | |
| | | .mb10 { |
| | |
| | | .ml10 { |
| | | margin-left: 10px; |
| | | } |
| | | |
| | | @media (max-width: 1500px) { |
| | | .line-search-panel { |
| | | align-items: flex-start; |
| | | } |
| | | |
| | | .search-left { |
| | | flex-wrap: wrap; |
| | | } |
| | | } |
| | | </style> |