|
@@ -1 +1,339 @@
|
|
|
-<template> xxx </template>
|
|
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="safety-platform-container">
|
|
|
|
|
+ <header class="safety-platform-container__header">
|
|
|
|
|
+ <div class="breadcrumb-title">
|
|
|
|
|
+ <BreadcrumbBack />
|
|
|
|
|
+ 编辑施工安全申请
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </header>
|
|
|
|
|
+ <main class="safety-platform-container__main">
|
|
|
|
|
+ <el-form ref="formRef" :inline="true" label-width="auto" :model="formValue" :rules="rules">
|
|
|
|
|
+ <el-form-item label="项目名称" prop="projectName">
|
|
|
|
|
+ <el-input v-model="formValue.projectName" size="large" placeholder="请输入项目名称" style="width: 330px" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="施工单位" prop="constructionUnit">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="formValue.constructionUnit"
|
|
|
|
|
+ size="large"
|
|
|
|
|
+ placeholder="请输入单位全称"
|
|
|
|
|
+ style="width: 330px"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="施工地点" prop="constructionLocation">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="formValue.constructionLocation"
|
|
|
|
|
+ size="large"
|
|
|
|
|
+ placeholder="楼宇名称/区域"
|
|
|
|
|
+ style="width: 330px"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="施工人数" prop="workerCount">
|
|
|
|
|
+ <el-input-number v-model="formValue.workerCount" size="large" :min="1" style="width: 330px" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="项目负责人" prop="projectManagerName">
|
|
|
|
|
+ <el-input v-model="formValue.projectManagerName" size="large" placeholder="负责人姓名" style="width: 330px" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="负责人电话1" prop="projectManagerPhone1">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="formValue.projectManagerPhone1"
|
|
|
|
|
+ size="large"
|
|
|
|
|
+ placeholder="手机或座机"
|
|
|
|
|
+ style="width: 330px"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="负责人电话2" prop="projectManagerPhone2">
|
|
|
|
|
+ <el-input v-model="formValue.projectManagerPhone2" size="large" placeholder="选填" style="width: 330px" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="现场安全员" prop="siteSafetyManagerName">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="formValue.siteSafetyManagerName"
|
|
|
|
|
+ size="large"
|
|
|
|
|
+ placeholder="安全员姓名"
|
|
|
|
|
+ style="width: 330px"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="安全员电话1" prop="siteSafetyPhone1">
|
|
|
|
|
+ <el-input v-model="formValue.siteSafetyPhone1" size="large" placeholder="手机或座机" style="width: 330px" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="安全员电话2" prop="siteSafetyPhone2">
|
|
|
|
|
+ <el-input v-model="formValue.siteSafetyPhone2" size="large" placeholder="选填" style="width: 330px" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="开始时间" prop="projectStartTime">
|
|
|
|
|
+ <el-date-picker
|
|
|
|
|
+ v-model="formValue.projectStartTime"
|
|
|
|
|
+ type="date"
|
|
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
|
|
+ size="large"
|
|
|
|
|
+ style="width: 330px"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="结束时间" prop="projectEndTime">
|
|
|
|
|
+ <el-date-picker
|
|
|
|
|
+ v-model="formValue.projectEndTime"
|
|
|
|
|
+ type="date"
|
|
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
|
|
+ size="large"
|
|
|
|
|
+ style="width: 330px"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="涉及工种" prop="involvedTrades" style="width: 87.2%">
|
|
|
|
|
+ <el-checkbox-group v-model="tradeArray" @change="handleTradeChange">
|
|
|
|
|
+ <el-checkbox
|
|
|
|
|
+ v-for="t in ['水电', '泥瓦', '木工', '焊接', '气割', '登高', '密闭', '特种驾驶', '其他']"
|
|
|
|
|
+ :key="t"
|
|
|
|
|
+ :label="t"
|
|
|
|
|
+ :value="t"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-checkbox-group>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item v-if="tradeArray.includes('其他')" label="其他工种说明" prop="otherTrade">
|
|
|
|
|
+ <el-input v-model="formValue.otherTrade" size="large" placeholder="请详细补充" style="width: 330px" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="施工内容简述" prop="constructionContent" style="width: 87.2%">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ v-model="formValue.constructionContent"
|
|
|
|
|
+ size="large"
|
|
|
|
|
+ :rows="3"
|
|
|
|
|
+ placeholder="请填写详细施工内容"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="备注说明" prop="otherDescription" style="width: 87.2%">
|
|
|
|
|
+ <el-input type="textarea" v-model="formValue.otherDescription" size="large" :rows="3" placeholder="选填" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <div style="width: 100%; height: 1px; background: #eee; margin: 20px 0"></div>
|
|
|
|
|
+ <div style="width: 100%; margin-bottom: 20px; font-weight: bold; padding-left: 10px">附件清单(全项必填)</div>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item
|
|
|
|
|
+ v-for="item in attachmentConfigs"
|
|
|
|
|
+ :key="item.prop"
|
|
|
|
|
+ :label="item.label"
|
|
|
|
|
+ :prop="item.prop"
|
|
|
|
|
+ style="width: 43.6%"
|
|
|
|
|
+ >
|
|
|
|
|
+ <UploadFiles
|
|
|
|
|
+ label="上传文件"
|
|
|
|
|
+ @upload-success="(fileList) => handleUploadSuccess(item.prop, fileList)"
|
|
|
|
|
+ :fileList="attachmentLists[item.prop]"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <div style="width: 100%; height: 1px; background: #eee; margin: 20px 0"></div>
|
|
|
|
|
+ <el-form-item label="审批流程" prop="templateId" style="width: 87.2%">
|
|
|
|
|
+ <el-select
|
|
|
|
|
+ v-model="formValue.templateId"
|
|
|
|
|
+ placeholder="请选择审批流程"
|
|
|
|
|
+ size="large"
|
|
|
|
|
+ style="width: 330px"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-option v-for="opt in approvalOptions" :key="opt.id" :label="opt.templateName" :value="opt.id" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ </main>
|
|
|
|
|
+ <footer class="safety-platform-container__footer">
|
|
|
|
|
+ <el-button @click="router.back()">返回</el-button>
|
|
|
|
|
+ <el-button type="primary" :loading="submiting" @click="handleSave(0)">保存</el-button>
|
|
|
|
|
+ </footer>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script lang="ts" setup>
|
|
|
|
|
+ import { ref, reactive, onMounted } from 'vue';
|
|
|
|
|
+ import { useRouter, useRoute } from 'vue-router';
|
|
|
|
|
+ import { ElMessage } from 'element-plus';
|
|
|
|
|
+ import dayjs from 'dayjs';
|
|
|
|
|
+ import UploadFiles from '@/components/UploadFiles/UploadFiles.vue';
|
|
|
|
|
+ import { getAllApproval } from '@/api/approval/approval';
|
|
|
|
|
+ import {
|
|
|
|
|
+ constructionSafetyQueryDetailConstruction,
|
|
|
|
|
+ constructionSafetyUpdateConstruction,
|
|
|
|
|
+ } from '@/api/production-safety/responsibility-implementation';
|
|
|
|
|
+ import { unformatAttachment, formatAttachmentList } from '@/components/UploadFiles/utils';
|
|
|
|
|
+
|
|
|
|
|
+ const router = useRouter();
|
|
|
|
|
+ const route = useRoute();
|
|
|
|
|
+ const formRef = ref<any>();
|
|
|
|
|
+ const submiting = ref(false);
|
|
|
|
|
+ const tradeArray = ref<string[]>([]);
|
|
|
|
|
+ const approvalOptions = ref<any[]>([]);
|
|
|
|
|
+
|
|
|
|
|
+ const attachmentConfigs = [
|
|
|
|
|
+ { label: '施工安全交底', prop: 'safetyCommitmentAttachment' },
|
|
|
|
|
+ { label: '安全管理协议', prop: 'safetyAgreementAttachment' },
|
|
|
|
|
+ { label: '安全告知单', prop: 'safetyNoticeAttachment' },
|
|
|
|
|
+ { label: '施工方案', prop: 'constructionPlanAttachment' },
|
|
|
|
|
+ { label: '劳保用品清单', prop: 'ppeListAttachment' },
|
|
|
|
|
+ { label: '施工机械清单', prop: 'equipmentListAttachment' },
|
|
|
|
|
+ { label: '人员身份信息', prop: 'personnelIdAttachment' },
|
|
|
|
|
+ { label: '安全教育记录', prop: 'safetyEducationAttachment' },
|
|
|
|
|
+ { label: '环境承诺书', prop: 'environmentCommitmentAttachment' },
|
|
|
|
|
+ { label: '消防管理承诺', prop: 'fireManagementAttachment' },
|
|
|
|
|
+ { label: '特种作业证', prop: 'specialWorkerCertAttachment' },
|
|
|
|
|
+ { label: '特种设备合格证', prop: 'specialEquipmentCertAttachment' },
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ const attachmentLists = reactive<any>(Object.fromEntries(attachmentConfigs.map((a) => [a.prop, []])));
|
|
|
|
|
+
|
|
|
|
|
+ const formValue = reactive<any>({
|
|
|
|
|
+ id: undefined,
|
|
|
|
|
+ projectName: '',
|
|
|
|
|
+ constructionContent: '',
|
|
|
|
|
+ constructionLocation: '',
|
|
|
|
|
+ constructionUnit: '',
|
|
|
|
|
+ projectManagerName: '',
|
|
|
|
|
+ projectManagerPhone1: '',
|
|
|
|
|
+ projectManagerPhone2: '',
|
|
|
|
|
+ siteSafetyManagerName: '',
|
|
|
|
|
+ siteSafetyPhone1: '',
|
|
|
|
|
+ siteSafetyPhone2: '',
|
|
|
|
|
+ workerCount: undefined,
|
|
|
|
|
+ projectStartTime: '',
|
|
|
|
|
+ projectEndTime: '',
|
|
|
|
|
+ involvedTrades: '',
|
|
|
|
|
+ otherTrade: '',
|
|
|
|
|
+ otherDescription: '',
|
|
|
|
|
+ templateId: '',
|
|
|
|
|
+ ...Object.fromEntries(attachmentConfigs.map((a) => [a.prop, ''])),
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 验证规则定义
|
|
|
|
|
+ const rules = reactive({
|
|
|
|
|
+ projectName: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
|
|
|
|
|
+ constructionUnit: [{ required: true, message: '请输入施工单位', trigger: 'blur' }],
|
|
|
|
|
+ constructionLocation: [{ required: true, message: '请输入施工地点', trigger: 'blur' }],
|
|
|
|
|
+ workerCount: [{ required: true, message: '请输入施工人数', trigger: 'blur' }],
|
|
|
|
|
+ projectManagerName: [{ required: true, message: '请输入项目负责人', trigger: 'blur' }],
|
|
|
|
|
+ projectManagerPhone1: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
|
|
|
|
|
+ siteSafetyManagerName: [{ required: true, message: '请输入现场安全员', trigger: 'blur' }],
|
|
|
|
|
+ siteSafetyPhone1: [{ required: true, message: '请输入安全员电话', trigger: 'blur' }],
|
|
|
|
|
+ projectStartTime: [{ required: true, message: '请选择开始日期', trigger: 'change' }],
|
|
|
|
|
+ projectEndTime: [
|
|
|
|
|
+ { required: true, message: '请选择结束日期', trigger: 'change' },
|
|
|
|
|
+ {
|
|
|
|
|
+ validator: (_rule: any, value: any, callback: any) => {
|
|
|
|
|
+ if (value && formValue.projectStartTime && dayjs(value).isBefore(dayjs(formValue.projectStartTime))) {
|
|
|
|
|
+ callback(new Error('结束时间不能早于开始时间'));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ callback();
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ trigger: 'change',
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ involvedTrades: [{ required: true, message: '请至少选择一个涉及工种', trigger: 'change' }],
|
|
|
|
|
+ otherTrade: [{ required: true, message: '请补充其他工种说明', trigger: 'blur' }],
|
|
|
|
|
+ constructionContent: [{ required: true, message: '请输入施工内容简述', trigger: 'blur' }],
|
|
|
|
|
+ templateId: [{ required: true, message: '请选择审批流程', trigger: 'change' }],
|
|
|
|
|
+ // 自动为所有附件添加必填验证
|
|
|
|
|
+ ...Object.fromEntries(
|
|
|
|
|
+ attachmentConfigs.map((a) => [a.prop, [{ required: true, message: `请上传${a.label}`, trigger: 'change' }]]),
|
|
|
|
|
+ ),
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const handleTradeChange = (val: string[]) => {
|
|
|
|
|
+ formValue.involvedTrades = val.join(',');
|
|
|
|
|
+ formRef.value?.validateField('involvedTrades');
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const handleUploadSuccess = async (prop: string, fileList: any[]) => {
|
|
|
|
|
+ attachmentLists[prop] = fileList;
|
|
|
|
|
+ const formatted = await formatAttachmentList(fileList);
|
|
|
|
|
+ formValue[prop] = formatted.length > 0 ? JSON.stringify(formatted) : '';
|
|
|
|
|
+ // 上传后主动触发单个字段校验,消除错误提示
|
|
|
|
|
+ formRef.value?.validateField(prop);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const initData = async () => {
|
|
|
|
|
+ const id = route.query.id as string;
|
|
|
|
|
+ if (!id) return;
|
|
|
|
|
+ formValue.id = id;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const approvals = await getAllApproval();
|
|
|
|
|
+ approvalOptions.value = approvals || [];
|
|
|
|
|
+
|
|
|
|
|
+ const res = await constructionSafetyQueryDetailConstruction(id);
|
|
|
|
|
+ if (res) {
|
|
|
|
|
+ Object.assign(formValue, res);
|
|
|
|
|
+ if (res.involvedTrades) {
|
|
|
|
|
+ tradeArray.value = res.involvedTrades.split(',');
|
|
|
|
|
+ }
|
|
|
|
|
+ attachmentConfigs.forEach((item) => {
|
|
|
|
|
+ if (res[item.prop]) {
|
|
|
|
|
+ attachmentLists[item.prop] = unformatAttachment(res[item.prop]);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取详情数据失败:', error);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const handleSave = (status: number) => {
|
|
|
|
|
+ // status: 0 保存, 1 提交
|
|
|
|
|
+ formRef.value?.validate(async (valid: boolean) => {
|
|
|
|
|
+ if (valid) {
|
|
|
|
|
+ submiting.value = true;
|
|
|
|
|
+ constructionSafetyUpdateConstruction({ ...formValue, submitStatus: status })
|
|
|
|
|
+ .then(() => {
|
|
|
|
|
+ ElMessage.success(status === 1 ? '提交成功!' : '保存成功!');
|
|
|
|
|
+ router.push({ name: 'constructionSafetyManage' });
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch((err) => {
|
|
|
|
|
+ console.error(err);
|
|
|
|
|
+ })
|
|
|
|
|
+ .finally(() => {
|
|
|
|
|
+ submiting.value = false;
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ onMounted(() => {
|
|
|
|
|
+ initData();
|
|
|
|
|
+ });
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+ @use '@/styles/page-main-layout.scss' as *;
|
|
|
|
|
+ @use '@/styles/page-details-layout.scss' as *;
|
|
|
|
|
+
|
|
|
|
|
+ .safety-platform-container {
|
|
|
|
|
+ &__main {
|
|
|
|
|
+ padding: 24px;
|
|
|
|
|
+ background-color: #fff;
|
|
|
|
|
+ }
|
|
|
|
|
+ :deep(.el-form-item) {
|
|
|
|
|
+ margin-right: 20px;
|
|
|
|
|
+ margin-bottom: 24px;
|
|
|
|
|
+ vertical-align: top;
|
|
|
|
|
+ .el-form-item__label {
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // :deep(.el-input.is-disabled .el-input__wrapper) {
|
|
|
|
|
+ // background-color: #f8f9fb;
|
|
|
|
|
+ // color: #606266;
|
|
|
|
|
+ // }
|
|
|
|
|
+ }
|
|
|
|
|
+</style>
|