<template> <div class="operate"> <el-form ref="operateRuleForm" :model="form" :rules="rules"> <el-divider content-position="left">基本情况</el-divider> <el-row :gutter="20"> <el-col :span="8"> <el-form-item label="项目类别:" prop="projectTypeId"> <el-select v-model="form.projectTypeId" placeholder="请选择项目类别" style="width: 100%" @change="projectTypeChange" > <el-option v-for="dict in props.types" :key="dict.id" :label="dict.projectTypeName" :value="dict.id" /> </el-select> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="项目名称:" prop="projectName" class="formItem"> <el-input v-model="form.projectName" placeholder="请输入项目名称" /> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="建设类别:" prop="buildCategory"> <el-select v-model="form.buildCategory" placeholder="请选择建设类别" style="width: 100%" > <el-option v-for="dict in props.buildCategory" :key="dict.value" :label="dict.label" :value="dict.value" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="8"> <el-form-item label="排水分区:" prop="drainagePartition"> <el-select v-model="form.drainagePartition" placeholder="请选择排水分区" style="width: 100%" > <el-option v-for="dict in drainage_partition" :key="dict.value" :label="dict.label" :value="dict.value" /> </el-select> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="项目日期:" prop="time" class="formItem"> <el-date-picker v-model="form.time" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD" /> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="项目位置:" prop="projectLocation"> <el-button type="primary" @click="selectPos">上传</el-button> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="8"> <el-form-item label="规划条件:" prop="planCondition"> <el-input v-model="form.planCondition" placeholder="请输入规划条件" /> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="项目库类型:" prop="projectLibraryType" class="formItem"> <el-select v-model="form.projectLibraryType" placeholder="请选择项目库类型" style="width: 100%" > <el-option v-for="dict in props.projectLibraryType" :key="dict.value" :label="dict.label" :value="dict.value" /> </el-select> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="任务类型:" prop="taskType"> <el-select v-model="form.taskType" placeholder="请选择任务类型" style="width: 100%" > <el-option v-for="dict in task_type" :key="dict.value" :label="dict.label" :value="dict.value" /> </el-select> </el-form-item> </el-col> </el-row> <el-row> <el-form-item label="项目概况:" prop="projectOverview" style="width: 100%"> <el-input type="textarea" v-model="form.projectOverview" placeholder="请输入项目概况" resize="none" /> </el-form-item> </el-row> <el-divider content-position="left">项目内容</el-divider> <el-card class="box-card" shadow="never" v-for="(item, index) in projectContentList"> <template #header> <div class="card-header"> <span>{{ item.label }}</span> </div> </template> <el-table :data="form[`list${index + 2}`]"> <el-table-column v-for="it in item.list" :label="it.propertyName" align="center" :prop="it.propertyKey" > <template #default="{ row }"> <el-input v-model="row[it.propertyKey]"/> </template> </el-table-column> </el-table> </el-card> <el-divider content-position="left">项目投资</el-divider> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="投资批复文件说明(已批复项目填写):" prop="investFileName"> <el-input v-model="form.investFileName" placeholder="请输入投资批复文件说明"/> </el-form-item> </el-col> <el-col :span="2"> <div class="upload"> <el-upload class="upload-demo" action="/prod-api/system/upload" :headers="uploadHeader" :before-upload="(rawFile) => beforeUpload(rawFile, ['.rar', '.zip', '.doc', '.docx', '.pdf'])" :on-success="(response) => onSuccess(response)" :on-error="(error, uploadFile, uploadFiles) => onError(error, uploadFile, uploadFiles)" :show-file-list="false" > <el-button icon="Upload" size="mini" type="primary" >上传文件</el-button > </el-upload> <div class="fileName" v-show="form.fileName"> <span>{{ form.fileName }}</span> <span class="del" @click="removeFile">删除</span> </div> </div> </el-col> <el-col :span="10"> <span class="tips">支持文件格式:.rar .zip .doc .docx .pdf ,单个文件不能超过500kb</span> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="8"> <el-form-item label="项目总投资(含主体工程)(万元):" prop="totalInvest"> <el-input v-model="form.totalInvest" placeholder="请输入项目总投资" /> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="地方政府投资(万元):" prop="govermentInvest"> <el-input v-model="form.govermentInvest" placeholder="请输入地方政府投资" /> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="社会资本投入(万元):" prop="socialInvest"> <el-input v-model="form.socialInvest" placeholder="请输入社会资本投入" /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="8"> <el-form-item label="项目运作模式:" prop="projectOperationPattern"> <el-select v-model="form.projectOperationPattern" placeholder="请选择项目运作模式" style="width: 100%" > <el-option v-for="dict in project_operation_pattern" :key="dict.value" :label="dict.label" :value="dict.value" /> </el-select> </el-form-item> </el-col> <el-col :span="10"> <el-form-item label="海绵相关投资(不含主体工程)(万元):" prop="spongeInvest"> <el-input v-model="form.spongeInvest" placeholder="请输入海绵相关投资" /> </el-form-item> </el-col> </el-row> <el-table :data="form.list1" v-if="projectInvestList[0]"> <el-table-column v-for="it in projectInvestList[0].list" :label="it.propertyName" align="center" :prop="it.propertyKey" > <template #default="{ row }"> <el-input v-model="row[it.propertyKey]"/> </template> </el-table-column> </el-table> <el-divider content-position="left">责任部门</el-divider> <el-row :gutter="20"> <el-col :span="8"> <el-form-item label="责任部门:" prop="chargeDepartment"> <el-input v-model="form.chargeDepartment" placeholder="请输入责任部门" /> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="责任人:" prop="chargeUser"> <el-input v-model="form.chargeUser" placeholder="请输入责任人" /> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="联系方式:" prop="phone"> <el-input v-model="form.phone" placeholder="请输入联系方式" /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="8"> <el-form-item label="设计单位:" prop="designUnit"> <el-select v-model="form.designUnit" placeholder="请选择设计单位" style="width: 100%" > <el-option v-for="dict in projectCompanyList" :key="dict.id" :label="dict.unitName" :value="dict.id" /> </el-select> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="施工单位:" prop="constructUnit"> <el-select v-model="form.constructUnit" placeholder="请选择施工单位" style="width: 100%" > <el-option v-for="dict in projectCompanyList" :key="dict.id" :label="dict.unitName" :value="dict.id" /> </el-select> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="运维单位:" prop="operationUnit"> <el-select v-model="form.operationUnit" placeholder="请选择运维单位" style="width: 100%" > <el-option v-for="dict in projectCompanyList" :key="dict.id" :label="dict.unitName" :value="dict.id" /> </el-select> </el-form-item> </el-col> </el-row> <el-divider content-position="left">建设进度</el-divider> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="建设状态:" prop="buildStatus"> <el-select v-model="form.buildStatus" placeholder="请选择建设状态" style="width: 100%" > <el-option v-for="dict in build_status" :key="dict.value" :label="dict.label" :value="dict.value" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="建设进度:" prop="projectProgress"> <div style="display: flex;width: 100%"> <el-slider v-model="form.projectProgress" style="flex: 1;" /> <span style="margin-left: 10px;">{{ form.projectProgress + '%' }}</span> </div> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="完成项目总投资(含主体工程)(万元):" prop="accomplishTotalInvest"> <el-input v-model="form.accomplishTotalInvest" placeholder="请输入完成项目总投资" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="完成海绵相关投资(不含主体工程)(万元):" prop="accomplishSpongeInvest"> <el-input v-model="form.accomplishSpongeInvest" placeholder="请输入完成海绵相关投资" /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="建设过程中照片:" prop="underWay"> <div class="upload"> <div class="imgBox" v-if="constractionFlieList.length"> <div class="img" v-for="item in constractionFlieList"> <img :src="item.url" class="avatar" /> <div class="mask"> <el-icon class="icon" :size="20" @click="removeFile1(item)" ><Delete /></el-icon> </div> </div> </div> <el-upload class="avatar-uploader" action="/prod-api/system/upload" :headers="uploadHeader" :before-upload="(rawFile) => beforeUpload(rawFile, ['.png', '.jpg', '.jpeg'])" :on-success="(response) => onSuccess1(response, 'constraction')" :on-error="(error, uploadFile, uploadFiles) => onError(error, uploadFile, uploadFiles)" :show-file-list="false" > <el-icon class="avatar-uploader-icon"><Plus /></el-icon> </el-upload> </div> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="建设完成后照片:" prop="complete"> <div class="upload"> <div class="imgBox" v-if="postConstractionFlieList.length"> <div class="img" v-for="item in postConstractionFlieList"> <img :src="item.url" class="avatar" /> <div class="mask"> <el-icon class="icon" :size="20" @click="removeFile1(item)" ><Delete /></el-icon> </div> </div> </div> <el-upload class="avatar-uploader" action="/prod-api/system/upload" :headers="uploadHeader" :before-upload="(rawFile) => beforeUpload(rawFile, ['.png', '.jpg', '.jpeg'])" :on-success="(response) => onSuccess1(response, 'postConstraction')" :on-error="(error, uploadFile, uploadFiles) => onError(error, uploadFile, uploadFiles)" :show-file-list="false" > <el-icon class="avatar-uploader-icon"><Plus /></el-icon> </el-upload> </div> </el-form-item> </el-col> </el-row> </el-form> <el-dialog v-model="visible" title="选择位置" :close-on-click-modal="false" width="60%" :before-close="dialogClose" class="dialog" > <div class="mapBox" v-if="visible"> <MapBox ref="mapBoxRef" @endDraw="endDraw"></MapBox> </div> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="handleOk">确 定</el-button> <el-button @click="dialogClose">取 消</el-button> </div> </template> </el-dialog> </div> </template> <script setup> import { reactive, onMounted, nextTick, computed } from 'vue' import { required } from '@/utils/validate-helper' import uploadHeader from '@/utils/getUploadHeader' import { useDicts } from '@/hooks' import MapBox from '@/components/Map' import { inheritAttr } from '@/utils/v3' import { getProjectCompanyList, getProjectItemDescriptionConfigList, projectInfoNewAdd, projectInfoNewById, getFileLIst, projectInfoNewEdit } from '@/api/projectInformationNew' import { isSlotOutlet } from '@vue/compiler-core' const { proxy } = getCurrentInstance(); const emit = defineEmits(['close']) const { drainage_partition, task_type, project_operation_pattern, build_status } = useDicts(proxy) const props = defineProps({ curRow: { type: Object, default: () => ({}) }, opts: { type: Object, default: () => ({}) }, types: { type: Array, default: () => ([]) }, buildCategory: { type: Array, default: () => ([]) }, projectLibraryType: { type: Array, default: () => ([]) }, projectContentType: { type: Array, default: () => ([]) } }) const { curRow, opts } = props console.log(curRow, opts) const form = reactive({ projectTypeId: '', projectName: '', buildCategory: '', drainagePartition: '', time: '', startTime: '', endTime: '', projectLocation: '', planCondition: '', projectLibraryType: '', taskType: '', projectOverview: '', investFileName: '', totalInvest: '', govermentInvest: '', socialInvest: '', projectOperationPattern: '', spongeInvest: '', chargeDepartment: '', chargeUser: '', phone: '', designUnit: '', constructUnit: '', operationUnit: '', buildStatus: '', projectProgress: 0, accomplishTotalInvest: '', accomplishSpongeInvest: '', underWay: '', complete: '', fileName: '', list1: [{}], list2: [{}], list3: [{}], list4: [{}], sysFileSaveRequestList: [ { extension: '', name: '', originalName: '', refField: 'investmentApproval', refType: 'projectInfoNew', size: '', url: '' } ], }) const rules = reactive({ projectTypeId: required('项目类别'), projectName: required('项目名称'), buildCategory: required('建设类别'), drainagePartition: required('排水分区'), time: required('项目日期'), projectLocation: required('项目位置'), planCondition: required('规划条件'), projectLibraryType: required('项目库类型'), taskType: required('任务类型'), projectOverview: required('项目概况'), investFileName: required('投资批复文件说明'), totalInvest: required('项目总投资'), govermentInvest: required('地方政府投资'), socialInvest: required('社会资本投入'), projectOperationPattern: required('项目运作模式'), spongeInvest: required('海绵相关投资'), chargeDepartment: required('责任部门'), chargeUser: required('责任人'), phone: required('联系方式'), designUnit: required('设计单位'), constructUnit: required('施工单位'), operationUnit: required('运维单位'), buildStatus: required('建设状态'), projectProgress: required('建设进度'), accomplishTotalInvest: required('完成项目总投资'), accomplishSpongeInvest: required('完成海绵相关投资'), // underWay: required('建设过程中照片'), // complete: required('建设完成后照片'), }) const projectCompanyList = ref([]) const projectItemDescriptionConfigList = ref([]) const projectContentList = ref([]) const projectInvestList = ref([]) const mapForm = reactive({ geometry: '' }) const visible = ref(false) const fileList = ref([]) const constractionFlieList = computed(() => { return fileList.value.filter(item => item.refField === 'constraction') }) const postConstractionFlieList = computed(() => { return fileList.value.filter(item => item.refField === 'postConstraction') }) const dialogClose = () => { visible.value = false } const handleOk = () => { if(!mapForm.geometry) return proxy.$modal.msgError('请选择位置!') form.projectLocation = mapForm.geometry visible.value = false nextTick(() => { proxy.$refs.operateRuleForm.validateField('projectLocation') }) } const endDraw = (val) => { mapForm.geometry = val.geometry; val.geometry && console.log(val.geometry) } const selectPos = () => { visible.value = true form.projectLocation && viewPosition(form.projectLocation) } const viewPosition = (projectLocation) => { console.log(projectLocation) nextTick(() => { let data = []; if(projectLocation.includes('POINT')) { data = [ { type: NewFiberMap.Enum.VectorType.SPECIAL_CIRCLE, id: 'point', style: { radius: 10, clampToGround: false, material: 'rgba(255, 0, 0, 1)' }, geometrys: projectLocation, }, ]; } else if(projectLocation.includes('LINE')) { data = [ { type: NewFiberMap.Enum.VectorType.POLYLINE, id: 'line', geometrys: projectLocation, style: { width: 5, material: "rgba(255,0,0,1)", clampToGround: true, }, }, ] } else if(projectLocation.includes('POLYGON')) { data = [ { type: NewFiberMap.Enum.VectorType.POLYGON, style: { material: "rgba(255,0,0,1)", color: "rgba(255,0,0,1)" }, geometrys: projectLocation, id: 'area' }, ] } if (data.length) { setTimeout(() => { let geojson = NewFiberMap.Data.ToGeoJSON.beansWktToGeoJson(data); toCenterByGeoJson(geojson); newfiberMap.geojsonToMap(geojson); }, 500) } }) } const toCenterByGeoJson = (geojson) => { let coords = turf.getCoords(geojson.features[0].geometry).flat(); let flag = geojson.features.length == 1 && coords.length == 2; if (!!geojson.features.length && !flag) { newfiberMap.getMap().camera.flyTo({destination: new Cesium.Rectangle.fromDegrees(...turf.bbox(turf.transformScale(turf.bboxPolygon(turf.bbox(geojson)), 2)))}); } else { newfiberMap.setCenter({ "roll": 0.01658908985506884, "pitch": -87.24924906709752, "heading": 5.026928271138224, "lng": coords[0], "lat": coords[1], "height": 943.5996932813425 }) } } const beforeUpload = (rawFile, fileType) => { console.log(rawFile) } const onSuccess = (response) => { console.log(response) const { data } = response form.fileName = data.name form.sysFileSaveRequestList[0].extension = data.extension form.sysFileSaveRequestList[0].name = data.name form.sysFileSaveRequestList[0].originalName = data.originalName form.sysFileSaveRequestList[0].size = data.size form.sysFileSaveRequestList[0].url = data.url } const onSuccess1 = (response, refField) => { console.log(response) const { data } = response fileList.value.push({ ...data, refType: 'projectInfoNew', refField }) } const onError = (error, uploadFile, uploadFiles) => { console.log(error, uploadFile, uploadFiles) } const removeFile = () => { proxy.$modal .confirm("是否确认删除?") .then(async () => {1 form.fileName = '' }) .catch(() => {}); } const removeFile1 = (item) => { proxy.$modal .confirm("是否确认删除?") .then(async () => { const index = fileList.value.indexOf(item) fileList.value.splice(index, 1) }) .catch(() => {}); } const submit = () => { proxy.$refs.operateRuleForm.validate(async (valid, fields) => { if (valid) { console.log('submit!', form) const projectItemDescriptionSaveRequestList = [] for (let i = 0; i < projectContentList.value.length; i++) { const formList = form[`list${i + 2}`] const item = projectContentList.value[i] for (const it of item.list) { for (const key in formList[0]) { if (Object.hasOwnProperty.call(formList[0], key)) { const element = formList[0][key]; if(key === it.propertyKey){ it.propertyValue = element } } } projectItemDescriptionSaveRequestList.push(it) } } for (let j = 0; j < projectInvestList.value.length; j++) { const formList = form.list1 const item = projectInvestList.value[j] for (const it of item.list) { for (const key in formList[0]) { if (Object.hasOwnProperty.call(formList[0], key)) { const element = formList[0][key]; if(key === it.propertyKey){ it.propertyValue = element } } } projectItemDescriptionSaveRequestList.push(it) } } let sysFileSaveRequestList = JSON.parse(JSON.stringify(form.sysFileSaveRequestList)) sysFileSaveRequestList = sysFileSaveRequestList.concat(fileList.value) const params = { id: curRow?.id || '', ...form, startTime: form.time[0], endTime: form.time[1], projectItemDescriptionSaveRequestList, sysFileSaveRequestList } delete params.list1 delete params.list2 delete params.list3 delete params.list4 delete params.time let methed = '' if(params.id) { methed = projectInfoNewEdit } else { methed = projectInfoNewAdd } if(!methed) return const res = await methed(params) if(res?.code !== 200) return proxy.$modal.msgSuccess('操作成功!') emit('close', opts.type) } else { console.log('error submit!', fields) } }) } const getProjectCompanyLists =async () => { const res = await getProjectCompanyList() if(res?.code !== 200) return projectCompanyList.value = res?.data || [] } const getProjectItemDescriptionConfigLists = async () => { const res = await getProjectItemDescriptionConfigList({ projectTypeId: form.projectTypeId }) if(res?.code !== 200) return projectItemDescriptionConfigList.value = res?.data || [] console.log(projectItemDescriptionConfigList) projectContentList.value = props.projectContentType.slice(0, 3).map((item, i) => { const list = projectItemDescriptionConfigList.value.filter(it => it.projectContentType === item.value) const obj = {} for (const item of list) { obj[item.propertyKey] = '' } form[`list${i + 2}`] = [obj] return { list: JSON.parse(JSON.stringify(list)), label: item.label } }) projectInvestList.value = props.projectContentType.slice(3).map(item => { const list = projectItemDescriptionConfigList.value.filter(it => it.projectContentType === item.value) const obj = {} for (const item of list) { obj[item.propertyKey] = '' } form.list1 = [obj] return { list: JSON.parse(JSON.stringify(list)), label: item.label } }) console.log(projectContentList, projectInvestList) } const projectTypeChange = () => { form.list1 = [{}] form.list2 = [{}] form.list3 = [{}] form.list4 = [{}] getProjectItemDescriptionConfigLists() } const getDetail = async () => { const res = await projectInfoNewById(curRow.id) if(res?.code !== 200) return console.log(res.data) form.time = [res.data.startTime, res.data.endTime] inheritAttr(res.data, form) projectItemDescriptionConfigList.value = res?.data?.projectItemDescriptionList || [] console.log(projectItemDescriptionConfigList) projectContentList.value = props.projectContentType.slice(0, 3).map((item, i) => { const list = projectItemDescriptionConfigList.value.filter(it => it.projectContentType === item.value) const obj = {} for (const item of list) { obj[item.propertyKey] = item.propertyValue } form[`list${i + 2}`] = [obj] return { list: JSON.parse(JSON.stringify(list)), label: item.label } }) projectInvestList.value = props.projectContentType.slice(3).map(item => { const list = projectItemDescriptionConfigList.value.filter(it => it.projectContentType === item.value) const obj = {} for (const item of list) { obj[item.propertyKey] = item.propertyValue } form.list1 = [obj] return { list: JSON.parse(JSON.stringify(list)), label: item.label } }) getFileInfo(res.data.id, 'projectInfoNew', 'investmentApproval', (data) => { console.log(data) form.fileName = data?.[0]?.name || '' if(data?.[0]) { form.sysFileSaveRequestList[0].extension = data[0].extension form.sysFileSaveRequestList[0].name = data[0].name form.sysFileSaveRequestList[0].originalName = data[0].originalName form.sysFileSaveRequestList[0].size = data[0].size form.sysFileSaveRequestList[0].url = data[0].url } }) fileList.value = res.data.sysFileList || [] for (const item of fileList.value) { item.refType = 'projectInfoNew' } } const getFileInfo = async (id, refType, refField, callback) => { const res = await getFileLIst({ refId: id, refType, refField }) if(res?.code !== 200) return callback && callback(res.data) } onMounted(() => { getProjectCompanyLists() if(curRow?.id) { getDetail() } else { if(props.types.length) { form.projectTypeId = props.types[0].id getProjectItemDescriptionConfigLists() } } }) defineExpose({ submit }) </script> <style lang="scss" scoped> .operate { .box-card { margin-top: 10px; &:first-of-type { margin-top: 0; } } .tips { margin-left: 10px; line-height: 30px } .upload { position: relative; .fileName { position: absolute; left: 0; top: 30px; white-space: nowrap; display: flex; align-items: center; .del { flex-shrink: 0; color: #f56c6c; cursor: pointer; margin-left: 10px; } } .imgBox { display: flex; flex-wrap: wrap; .img { margin-right: 10px; } } } .img { position: relative; width: 178px; height: 178px; img { width: 100%; height: 100%; } .mask { position: absolute; left: 0; right: 0; top: 0; bottom: 0; background-color: rgba(0, 0, 0, .5); display: none; .icon { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); color: #fff; } } &:hover { .mask { display: block; } } } } .mapBox { height: 600px; } </style>