|
|
@@ -324,9 +324,22 @@
|
|
|
<span v-else>-</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="操作" align="center" width="100" fixed="right">
|
|
|
+ <el-table-column label="审核状态" align="center" prop="auditStatus" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-tag v-if="scope.row.auditStatus" :type="getAuditStatusTag(scope.row.auditStatus)">{{ scope.row.auditStatus }}</el-tag>
|
|
|
+ <span v-else>-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" align="center" width="180" fixed="right">
|
|
|
<template #default="scope">
|
|
|
<el-button link type="primary" @click="handleViewDetail(scope.row)">查看详情</el-button>
|
|
|
+ <el-button
|
|
|
+ v-if="!scope.row.auditStatus || scope.row.auditStatus === '待审核'"
|
|
|
+ v-hasPermi="['risk:inspectionRecord:review']"
|
|
|
+ link
|
|
|
+ type="primary"
|
|
|
+ @click="handleAuditRecord(scope.row)"
|
|
|
+ >审核</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
@@ -350,6 +363,16 @@
|
|
|
</el-descriptions-item>
|
|
|
<el-descriptions-item label="打卡地点">{{ detailForm.checkInLocation }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="问题数/总数">{{ detailForm.problemCount || 0 }}/{{ detailForm.totalCount || 0 }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="审核状态">
|
|
|
+ <el-tag v-if="detailForm.auditStatus" :type="getAuditStatusTag(detailForm.auditStatus)">{{ detailForm.auditStatus }}</el-tag>
|
|
|
+ <span v-else>-</span>
|
|
|
+ </el-descriptions-item>
|
|
|
+ <el-descriptions-item v-if="detailForm.auditorName" label="审核人">{{ detailForm.auditorName }} ({{ detailForm.auditTime || '-' }})</el-descriptions-item>
|
|
|
+ <el-descriptions-item v-if="detailForm.auditOpinion" label="审核意见" :span="1">
|
|
|
+ <span :class="['audit-opinion', detailForm.auditStatus === '审核不通过' ? 'reject' : 'pass']">
|
|
|
+ {{ detailForm.auditOpinion }}
|
|
|
+ </span>
|
|
|
+ </el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
<h4 style="margin: 16px 0 8px">巡检项目明细</h4>
|
|
|
<el-table :data="detailForm.itemList" border size="small">
|
|
|
@@ -373,6 +396,50 @@
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
|
|
|
+ <!-- 审核弹窗 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="auditDialog.visible"
|
|
|
+ title="巡检打卡审核"
|
|
|
+ width="520px"
|
|
|
+ append-to-body
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ @close="closeAuditDialog"
|
|
|
+ >
|
|
|
+ <el-form ref="auditFormRef" :model="auditForm" :rules="auditRules" label-width="100px">
|
|
|
+ <el-form-item label="任务名称">
|
|
|
+ <span class="readonly-text">{{ auditForm.taskName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="打卡人">
|
|
|
+ <span class="readonly-text">{{ auditForm.inspectorName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="打卡时间">
|
|
|
+ <span class="readonly-text">{{ auditForm.checkInTime }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="审核结果" prop="auditStatus">
|
|
|
+ <el-radio-group v-model="auditForm.auditStatus">
|
|
|
+ <el-radio value="审核通过">通过</el-radio>
|
|
|
+ <el-radio value="审核不通过">不通过</el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item v-if="auditForm.auditStatus === '审核不通过'" label="不通过原因" prop="auditOpinion">
|
|
|
+ <el-input
|
|
|
+ v-model="auditForm.auditOpinion"
|
|
|
+ type="textarea"
|
|
|
+ :rows="4"
|
|
|
+ placeholder="请输入不通过原因"
|
|
|
+ maxlength="500"
|
|
|
+ show-word-limit
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button @click="cancelAudit">取消</el-button>
|
|
|
+ <el-button v-hasPermi="['risk:inspectionRecord:review']" type="primary" @click="submitAudit">确认审核</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
@@ -388,11 +455,13 @@ import {
|
|
|
listInspectionRecordByTask
|
|
|
} from '@/api/risk/inspectionTask';
|
|
|
import { listInspectionItemByTask } from '@/api/risk/inspectionItem';
|
|
|
+import { auditInspectionRecord } from '@/api/risk/inspectionRecord';
|
|
|
import type {
|
|
|
RiskInspectionTaskBo,
|
|
|
RiskInspectionTaskVo,
|
|
|
RiskInspectionItemVo,
|
|
|
RiskInspectionRecordVo,
|
|
|
+ RiskInspectionRecordBo,
|
|
|
InspectionStatsVo
|
|
|
} from '@/api/risk/types';
|
|
|
import { listByCurrentDeptChainUsers } from '@/api/system/user';
|
|
|
@@ -510,6 +579,8 @@ const dialog = reactive<DialogOption>({ visible: false, title: '' });
|
|
|
const recordDialog = reactive<DialogOption>({ visible: false, title: '打卡记录' });
|
|
|
const detailDialog = reactive({ visible: false });
|
|
|
const detailForm = ref<any>({ itemList: [] });
|
|
|
+const auditDialog = reactive({ visible: false, title: '巡检打卡审核' });
|
|
|
+const auditFormRef = ref<FormInstance>();
|
|
|
const getList = async () => {
|
|
|
loading.value = true;
|
|
|
try {
|
|
|
@@ -705,6 +776,91 @@ const handleViewDetail = (row: RiskInspectionRecordVo) => {
|
|
|
detailDialog.visible = true;
|
|
|
};
|
|
|
|
|
|
+// ============ 审核相关 ============
|
|
|
+const auditData = reactive({
|
|
|
+ auditForm: {
|
|
|
+ id: undefined as string | number | undefined,
|
|
|
+ taskName: '',
|
|
|
+ inspectorName: '',
|
|
|
+ checkInTime: '',
|
|
|
+ auditStatus: '审核通过',
|
|
|
+ auditOpinion: ''
|
|
|
+ },
|
|
|
+ auditRules: {
|
|
|
+ auditStatus: [{ required: true, message: '请选择审核结果', trigger: 'change' }],
|
|
|
+ auditOpinion: [
|
|
|
+ {
|
|
|
+ validator: (_rule: any, value: any, callback: any) => {
|
|
|
+ if (auditData.auditForm.auditStatus === '审核不通过' && !value) {
|
|
|
+ callback(new Error('审核不通过时必须填写原因'));
|
|
|
+ } else {
|
|
|
+ callback();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ trigger: 'blur'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+const { auditForm, auditRules } = toRefs(auditData);
|
|
|
+
|
|
|
+/** 打卡记录列表 - 打开审核弹窗 */
|
|
|
+const handleAuditRecord = (row: RiskInspectionRecordVo) => {
|
|
|
+ auditForm.value = {
|
|
|
+ id: row.id,
|
|
|
+ taskName: row.taskName || '',
|
|
|
+ inspectorName: row.inspectorName || '',
|
|
|
+ checkInTime: row.checkInTime || '',
|
|
|
+ auditStatus: '审核通过',
|
|
|
+ auditOpinion: ''
|
|
|
+ };
|
|
|
+ auditDialog.visible = true;
|
|
|
+};
|
|
|
+
|
|
|
+/** 审核弹窗 - 提交 */
|
|
|
+const submitAudit = () => {
|
|
|
+ auditFormRef.value?.validate(async (valid: boolean) => {
|
|
|
+ if (!valid) return;
|
|
|
+ const submitData: RiskInspectionRecordBo = {
|
|
|
+ id: auditForm.value.id,
|
|
|
+ auditStatus: auditForm.value.auditStatus,
|
|
|
+ auditOpinion: auditForm.value.auditOpinion
|
|
|
+ };
|
|
|
+ await auditInspectionRecord(submitData);
|
|
|
+ proxy?.$modal.msgSuccess('审核成功');
|
|
|
+ auditDialog.visible = false;
|
|
|
+ // 刷新当前打卡记录列表(若弹窗开着则一起刷新)
|
|
|
+ if (recordDialog.visible && recordList.value.length > 0) {
|
|
|
+ const taskId = recordList.value[0]?.taskId;
|
|
|
+ if (taskId) {
|
|
|
+ const res = await listInspectionRecordByTask(taskId);
|
|
|
+ recordList.value = res.data || [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const cancelAudit = () => {
|
|
|
+ auditDialog.visible = false;
|
|
|
+ auditFormRef.value?.resetFields();
|
|
|
+};
|
|
|
+
|
|
|
+const closeAuditDialog = () => {
|
|
|
+ auditDialog.visible = false;
|
|
|
+ auditFormRef.value?.resetFields();
|
|
|
+};
|
|
|
+
|
|
|
+/** 审核状态 tag 颜色(待审核=warning/审核通过=success/审核不通过=danger) */
|
|
|
+const getAuditStatusTag = (s: string): 'primary' | 'success' | 'warning' | 'info' | 'danger' => {
|
|
|
+ const map: Record<string, 'primary' | 'success' | 'warning' | 'info' | 'danger'> = {
|
|
|
+ 待审核: 'warning',
|
|
|
+ 审核通过: 'success',
|
|
|
+ 审核不通过: 'danger'
|
|
|
+ };
|
|
|
+ return (map[s] || 'info') as any;
|
|
|
+};
|
|
|
+
|
|
|
const handleDelete = async (row: RiskInspectionTaskVo) => {
|
|
|
await proxy?.$modal.confirm('是否确认删除任务 "' + row.taskName + '" ?');
|
|
|
await delInspectionTask(row.id);
|
|
|
@@ -829,4 +985,13 @@ onMounted(async () => {
|
|
|
.stat-icon-red { background: #fef0f0; color: #F56C6C; }
|
|
|
.mb-2 { margin-bottom: 8px; }
|
|
|
.mt-2 { margin-top: 8px; }
|
|
|
+.readonly-text {
|
|
|
+ color: #303133;
|
|
|
+}
|
|
|
+.audit-opinion.pass {
|
|
|
+ color: #67c23a;
|
|
|
+}
|
|
|
+.audit-opinion.reject {
|
|
|
+ color: #f56c6c;
|
|
|
+}
|
|
|
</style>
|