|
@@ -51,7 +51,6 @@
|
|
|
>
|
|
>
|
|
|
<el-option label="全部状态" value="" />
|
|
<el-option label="全部状态" value="" />
|
|
|
<el-option label="待处理" value="待处理" />
|
|
<el-option label="待处理" value="待处理" />
|
|
|
- <el-option label="处理中" value="处理中" />
|
|
|
|
|
<el-option label="已处理" value="已处理" />
|
|
<el-option label="已处理" value="已处理" />
|
|
|
</el-select>
|
|
</el-select>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
@@ -242,19 +241,87 @@
|
|
|
<template #footer>
|
|
<template #footer>
|
|
|
<div class="dialog-footer">
|
|
<div class="dialog-footer">
|
|
|
<el-button @click="cancel">取消</el-button>
|
|
<el-button @click="cancel">取消</el-button>
|
|
|
- <!-- 新增走 risk:hiddenDanger:add,处理走 risk:hiddenDanger:handle -->
|
|
|
|
|
|
|
+ <!-- 新增走 risk:hiddenDanger:add(处理走独立 handleDialog) -->
|
|
|
<el-button
|
|
<el-button
|
|
|
- v-if="!form.id"
|
|
|
|
|
v-hasPermi="['risk:hiddenDanger:add']"
|
|
v-hasPermi="['risk:hiddenDanger:add']"
|
|
|
type="primary"
|
|
type="primary"
|
|
|
@click="submitForm"
|
|
@click="submitForm"
|
|
|
>提交保存</el-button>
|
|
>提交保存</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 安全隐患处理弹窗(独立,字段精简:处理结果/描述/照片) -->
|
|
|
|
|
+ <el-dialog
|
|
|
|
|
+ v-model="handleDialog.visible"
|
|
|
|
|
+ :title="handleDialog.title"
|
|
|
|
|
+ width="640px"
|
|
|
|
|
+ append-to-body
|
|
|
|
|
+ :close-on-click-modal="false"
|
|
|
|
|
+ @close="cancelHandle"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-form ref="handleFormRef" :model="handleForm" :rules="handleRules" label-width="100px">
|
|
|
|
|
+ <el-row :gutter="20">
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="隐患编号">
|
|
|
|
|
+ <span class="readonly-text">{{ handleForm.dangerCode }}</span>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="隐患名称">
|
|
|
|
|
+ <span class="readonly-text">{{ handleForm.dangerTitle }}</span>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+ <el-form-item label="处理结果" prop="handleResult">
|
|
|
|
|
+ <el-select v-model="handleForm.handleResult" placeholder="请选择处理结果" style="width: 100%">
|
|
|
|
|
+ <el-option
|
|
|
|
|
+ v-for="opt in handleResultOptions"
|
|
|
|
|
+ :key="opt.value"
|
|
|
|
|
+ :label="opt.label"
|
|
|
|
|
+ :value="opt.value"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="处理描述" prop="handleMeasures">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="handleForm.handleMeasures"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ :rows="5"
|
|
|
|
|
+ placeholder="请详细描述处理过程和采取的措施..."
|
|
|
|
|
+ maxlength="500"
|
|
|
|
|
+ show-word-limit
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="照片上传">
|
|
|
|
|
+ <div class="upload-row">
|
|
|
|
|
+ <el-button type="primary" plain @click="triggerHandlePhotoUpload">选择文件</el-button>
|
|
|
|
|
+ <span class="upload-tip">{{ handlePhotoFileList.length > 0 ? `已选择 ${handlePhotoFileList.length} 个文件` : '未选择任何文件' }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <input
|
|
|
|
|
+ ref="handlePhotoInputRef"
|
|
|
|
|
+ type="file"
|
|
|
|
|
+ multiple
|
|
|
|
|
+ accept=".jpg,.jpeg,.png"
|
|
|
|
|
+ style="display: none"
|
|
|
|
|
+ @change="onHandlePhotoInputChange"
|
|
|
|
|
+ />
|
|
|
|
|
+ <div v-if="handlePreviewPhotos.length > 0" class="photo-preview-list">
|
|
|
|
|
+ <div v-for="(url, idx) in handlePreviewPhotos" :key="idx" class="photo-thumb">
|
|
|
|
|
+ <el-image :src="url" :preview-src-list="handlePreviewPhotos" :initial-index="idx" fit="cover" />
|
|
|
|
|
+ <el-icon class="photo-remove" @click="removeHandlePhoto(idx)"><CircleCloseFilled /></el-icon>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <div class="dialog-footer">
|
|
|
|
|
+ <el-button @click="cancelHandle">取消</el-button>
|
|
|
<el-button
|
|
<el-button
|
|
|
- v-else
|
|
|
|
|
v-hasPermi="['risk:hiddenDanger:handle']"
|
|
v-hasPermi="['risk:hiddenDanger:handle']"
|
|
|
type="primary"
|
|
type="primary"
|
|
|
- @click="submitForm"
|
|
|
|
|
- >提交保存</el-button>
|
|
|
|
|
|
|
+ @click="submitHandle"
|
|
|
|
|
+ >提交处理结果</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
</el-dialog>
|
|
</el-dialog>
|
|
@@ -402,12 +469,37 @@ const dialog = reactive({
|
|
|
title: '新增安全隐患'
|
|
title: '新增安全隐患'
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
|
|
+// 处理弹窗(独立,字段精简:处理结果/描述/照片)
|
|
|
|
|
+const handleDialog = reactive({
|
|
|
|
|
+ visible: false,
|
|
|
|
|
+ title: '安全隐患处理'
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
const viewDialog = reactive({
|
|
const viewDialog = reactive({
|
|
|
visible: false
|
|
visible: false
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const viewForm = ref<any>({});
|
|
const viewForm = ref<any>({});
|
|
|
|
|
|
|
|
|
|
+// 处理表单(独立,不与新增表单混用)
|
|
|
|
|
+const handleForm = ref<any>({
|
|
|
|
|
+ id: undefined,
|
|
|
|
|
+ dangerCode: '',
|
|
|
|
|
+ dangerTitle: '',
|
|
|
|
|
+ handleResult: '',
|
|
|
|
|
+ handleMeasures: '',
|
|
|
|
|
+ photoList: '[]'
|
|
|
|
|
+});
|
|
|
|
|
+const handleFormRef = ref<FormInstance>();
|
|
|
|
|
+const handleRules = {
|
|
|
|
|
+ handleResult: [{ required: true, message: '请选择处理结果', trigger: 'change' }],
|
|
|
|
|
+ handleMeasures: [{ required: true, message: '请输入处理描述文案', trigger: 'blur' }]
|
|
|
|
|
+};
|
|
|
|
|
+// 处理照片(预览)
|
|
|
|
|
+const handlePreviewPhotos = ref<string[]>([]);
|
|
|
|
|
+const handlePhotoFileList = ref<any[]>([]);
|
|
|
|
|
+const handlePhotoInputRef = ref<HTMLInputElement>();
|
|
|
|
|
+
|
|
|
// 客户端按筛选条件过滤(用于顶部统计的同步展示)
|
|
// 客户端按筛选条件过滤(用于顶部统计的同步展示)
|
|
|
const filteredList = computed(() => {
|
|
const filteredList = computed(() => {
|
|
|
return hiddenDangerList.value;
|
|
return hiddenDangerList.value;
|
|
@@ -436,8 +528,9 @@ const loadStats = async () => {
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
const list = hiddenDangerList.value || [];
|
|
const list = hiddenDangerList.value || [];
|
|
|
statsCards.value[0].value = list.length;
|
|
statsCards.value[0].value = list.length;
|
|
|
|
|
+ // 未处理隐患统计(只统计"待处理")
|
|
|
statsCards.value[1].value = list.filter(
|
|
statsCards.value[1].value = list.filter(
|
|
|
- (it) => it.handleStatus === '待处理' || it.handleStatus === '处理中'
|
|
|
|
|
|
|
+ (it) => it.handleStatus === '待处理'
|
|
|
).length;
|
|
).length;
|
|
|
statsCards.value[2].value = list.filter((it) => it.handleStatus === '已处理').length;
|
|
statsCards.value[2].value = list.filter((it) => it.handleStatus === '已处理').length;
|
|
|
}
|
|
}
|
|
@@ -465,12 +558,15 @@ const handleAdd = () => {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const handleUpdate = async (row: RiskHiddenDangerVo) => {
|
|
const handleUpdate = async (row: RiskHiddenDangerVo) => {
|
|
|
- reset();
|
|
|
|
|
|
|
+ // 重置处理表单 + 加载隐患信息(只读字段)
|
|
|
|
|
+ resetHandleForm();
|
|
|
const res = await getHiddenDanger(row.id);
|
|
const res = await getHiddenDanger(row.id);
|
|
|
- Object.assign(form.value, res.data);
|
|
|
|
|
- loadPhotosToPreview(parsePhotoList(res.data.photoList));
|
|
|
|
|
- dialog.visible = true;
|
|
|
|
|
- dialog.title = '处理安全隐患';
|
|
|
|
|
|
|
+ handleForm.value.id = res.data.id;
|
|
|
|
|
+ handleForm.value.dangerCode = res.data.dangerCode || '';
|
|
|
|
|
+ handleForm.value.dangerTitle = res.data.dangerTitle || '';
|
|
|
|
|
+ // 处理后照片作为历史保留(如有)
|
|
|
|
|
+ handlePreviewPhotos.value = parsePhotoList(res.data.photoList);
|
|
|
|
|
+ handleDialog.visible = true;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const handleView = async (row: RiskHiddenDangerVo) => {
|
|
const handleView = async (row: RiskHiddenDangerVo) => {
|
|
@@ -536,6 +632,63 @@ const closeDialog = () => {
|
|
|
reset();
|
|
reset();
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+// 处理弹窗 - 提交(状态强制变"已处理")
|
|
|
|
|
+const submitHandle = () => {
|
|
|
|
|
+ handleFormRef.value?.validate(async (valid: boolean) => {
|
|
|
|
|
+ if (!valid) return;
|
|
|
|
|
+ handleForm.value.photoList = JSON.stringify(handlePreviewPhotos.value);
|
|
|
|
|
+ await handleHiddenDanger(handleForm.value.id, handleForm.value as RiskHiddenDangerBo);
|
|
|
|
|
+ proxy?.$modal.msgSuccess('处理成功');
|
|
|
|
|
+ handleDialog.visible = false;
|
|
|
|
|
+ await getList();
|
|
|
|
|
+ });
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const cancelHandle = () => {
|
|
|
|
|
+ handleDialog.visible = false;
|
|
|
|
|
+ resetHandleForm();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const resetHandleForm = () => {
|
|
|
|
|
+ handleForm.value = {
|
|
|
|
|
+ id: undefined,
|
|
|
|
|
+ dangerCode: '',
|
|
|
|
|
+ dangerTitle: '',
|
|
|
|
|
+ handleResult: '',
|
|
|
|
|
+ handleMeasures: '',
|
|
|
|
|
+ photoList: '[]'
|
|
|
|
|
+ };
|
|
|
|
|
+ handlePreviewPhotos.value = [];
|
|
|
|
|
+ handlePhotoFileList.value = [];
|
|
|
|
|
+ handleFormRef.value?.resetFields();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// ============ 处理照片上传(独立预览队列) ============
|
|
|
|
|
+const triggerHandlePhotoUpload = () => handlePhotoInputRef.value?.click();
|
|
|
|
|
+const onHandlePhotoInputChange = async (e: Event) => {
|
|
|
|
|
+ const files = (e.target as HTMLInputElement).files;
|
|
|
|
|
+ if (!files || files.length === 0) return;
|
|
|
|
|
+ const list = Array.from(files);
|
|
|
|
|
+ handlePhotoFileList.value = list;
|
|
|
|
|
+ for (const f of list) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const upRes: any = await uploadFile(f as any);
|
|
|
|
|
+ if (upRes?.data?.url) {
|
|
|
|
|
+ handlePreviewPhotos.value.push(upRes.data.url);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ proxy?.$modal.msgError(`照片 ${f.name} 上传失败`);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (handlePhotoInputRef.value) handlePhotoInputRef.value.value = '';
|
|
|
|
|
+};
|
|
|
|
|
+const removeHandlePhoto = (idx: number) => {
|
|
|
|
|
+ handlePreviewPhotos.value.splice(idx, 1);
|
|
|
|
|
+ if (handlePreviewPhotos.value.length === 0) {
|
|
|
|
|
+ handlePhotoFileList.value = [];
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
const disabledFutureDate = (time: Date) => {
|
|
const disabledFutureDate = (time: Date) => {
|
|
|
return time.getTime() > Date.now();
|
|
return time.getTime() > Date.now();
|
|
|
};
|
|
};
|
|
@@ -560,12 +713,20 @@ const getRiskLevelTag = (level: string): any => {
|
|
|
const getStatusTag = (status: string): any => {
|
|
const getStatusTag = (status: string): any => {
|
|
|
const map: Record<string, string> = {
|
|
const map: Record<string, string> = {
|
|
|
待处理: 'danger',
|
|
待处理: 'danger',
|
|
|
- 处理中: 'warning',
|
|
|
|
|
已处理: 'success'
|
|
已处理: 'success'
|
|
|
};
|
|
};
|
|
|
return map[status] || 'info';
|
|
return map[status] || 'info';
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+// 安全隐患处理结果字典(可扩展)
|
|
|
|
|
+const handleResultOptions = ref<Array<{ label: string; value: string }>>([
|
|
|
|
|
+ { label: '隐患已消除', value: '隐患已消除' },
|
|
|
|
|
+ { label: '已设置警戒', value: '已设置警戒' },
|
|
|
|
|
+ { label: '已上报整改', value: '已上报整改' },
|
|
|
|
|
+ { label: '临时管控', value: '临时管控' },
|
|
|
|
|
+ { label: '其他', value: '其他' }
|
|
|
|
|
+]);
|
|
|
|
|
+
|
|
|
// ============ 照片上传(自管理文件 + 预览) ============
|
|
// ============ 照片上传(自管理文件 + 预览) ============
|
|
|
const parsePhotoList = (val: any): string[] => {
|
|
const parsePhotoList = (val: any): string[] => {
|
|
|
if (!val) return [];
|
|
if (!val) return [];
|