applications/drone-command/src/views/areaManage/sceneConfig/FormDiaLog.vue
@@ -23,7 +23,7 @@ <div class="detail-title">场景详情</div> <el-row> <el-col :span="24"> <div class="label">场景名称</div> <div class="label">场景配置名称</div> <div class="val">{{ formData.sceneName }}</div> </el-col> <el-col :span="24"> @@ -60,7 +60,7 @@ :disabled="readonly" label-width="96px" > <el-form-item label="场景名称" prop="sceneName"> <el-form-item label="场景配置名称" prop="sceneName"> <el-input class="command-input" v-model="formData.sceneName" @@ -165,7 +165,7 @@ import { AREA_TYPE_STYLE_MAP, BUFFER_LEVEL_STYLES, DEFAULT_AREA_STYLE } from '@ztzf/constants' const initForm = () => ({ sceneName: '', // 场景名称 sceneName: '', // 场景配置名称 sceneType: '', // 场景类型 deviceMode: '', // 设备模式 areaDivideIds: '', // 关联区域ID applications/drone-command/src/views/areaManage/sceneConfig/index.vue
@@ -1,7 +1,7 @@ <template> <basic-container> <el-form ref="queryParamsRef" :model="searchParams" class="command-page-history-search"> <el-form-item label="场景名称" prop="sceneName"> <el-form-item label="场景配置名称" prop="sceneName"> <el-input class="command-input" v-model="searchParams.sceneName" @@ -46,7 +46,7 @@ <el-table-column type="selection" width="46" /> <el-table-column type="index" show-overflow-tooltip width="64" label="序号" /> <el-table-column prop="sceneName" show-overflow-tooltip label="场景名称" /> <el-table-column prop="sceneName" show-overflow-tooltip label="场景配置名称" /> <el-table-column prop="sceneType" show-overflow-tooltip label="场景类型"> <template v-slot="{ row }"> {{ getDictLabel(row.sceneType, dictObj.CommandSceneType) }} @@ -93,7 +93,7 @@ import { useRoute } from 'vue-router' const initSearchParams = () => ({ sceneName: '', // 场景名称 sceneName: '', // 场景配置名称 sceneType: '', // 场景类型 current: 1, // 当前页 size: 10, // 每页大小 applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue
@@ -20,35 +20,33 @@ </div> <div class="content" v-if="readonly"> <div class="detail-title">场景详情</div> <div class="detail-title">场景管理详情</div> <el-row> <el-col :span="24"> <div class="label">场景名称</div> <div class="val">{{ formData.sceneName }}</div> </el-col> <el-col :span="24"> <div class="label">场景类型</div> <div class="val">{{ getDictLabel(formData.sceneType, dictObj.CommandSceneType) }}</div> <div class="label">负责人</div> <div class="val">{{ formData.defenseLeader }}</div> </el-col> <el-col :span="24"> <div class="label">设备模式</div> <div class="val">{{ getDictLabel(formData.deviceMode, dictObj.deviceMode) }}</div> <div class="label">负责人电话</div> <div class="val">{{ formData.leaderPhone }}</div> </el-col> <el-col :span="24"> <div class="label">有效时间</div> <div class="val">{{ formatEffectiveDate(formData) }}</div> </el-col> <el-col :span="24"> <div class="label">指挥点位置</div> <div class="val">{{ formatLocation(formData) }}</div> </el-col> <el-col :span="24"> <div class="label">关联场景配置</div> <div class="val">{{ getSceneConfigName(formData.defenseSceneId) }}</div> </el-col> </el-row> <div class="detail-title">关联区域</div> <div class="command-table-container"> <div class="command-table-content"> <el-table class="command-table" ref="areaTableRef" :data="areaList" row-key="id"> <el-table-column prop="areaName" label="区域名称" /> <el-table-column prop="areaType" label="区域类型"> <template v-slot="{ row }"> {{ getDictLabel(row.areaType, dictObj.areaType) }} </template> </el-table-column> </el-table> </div> </div> </div> <el-form @@ -58,7 +56,7 @@ :model="formData" :rules="rules" :disabled="readonly" label-width="96px" label-width="110px" > <el-form-item label="场景名称" prop="sceneName"> <el-input @@ -69,66 +67,52 @@ clearable /> </el-form-item> <el-form-item label="场景类型" prop="sceneType"> <el-form-item label="关联场景配置" prop="defenseSceneId"> <el-select class="command-select" popper-class="command-select-popper" v-model="formData.sceneType" v-model="formData.defenseSceneId" placeholder="请选择" clearable > <el-option v-for="item in dictObj.CommandSceneType" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> <el-option v-for="item in sceneConfigList" :key="item.id" :label="item.sceneName" :value="item.id" /> </el-select> </el-form-item> <el-form-item label="设备模式" prop="deviceMode"> <el-select class="command-select" popper-class="command-select-popper" v-model="formData.deviceMode" placeholder="请选择" <el-form-item label="负责人" prop="defenseLeader"> <el-input class="command-input" v-model="formData.defenseLeader" maxlength="50" placeholder="请输入" clearable > <el-option v-for="item in dictObj.deviceMode" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> </el-select> /> </el-form-item> <div class="search-table-container"> <div class="search-box"> <div class="label">关联区域</div> <el-input class="command-input" v-model="searchName" placeholder="请输入" clearable></el-input> </div> <el-form-item prop="areaDivideIds" label-width="0"> <el-table class="command-table" ref="areaTableRef" :data="areaList.filter(item => item.areaName.includes(searchName))" row-key="id" @selection-change="handleAreaSelectionChange" > <el-table-column type="selection" width="55" :reserve-selection="true" /> <el-table-column prop="areaName" show-overflow-tooltip label="区域名称" /> <el-table-column prop="areaType" show-overflow-tooltip label="区域类型"> <template v-slot="{ row }"> {{ getDictLabel(row.areaType, dictObj.areaType) }} </template> </el-table-column> </el-table> </el-form-item> </div> <el-form-item label="负责人电话" prop="leaderPhone"> <el-input class="command-input" v-model="formData.leaderPhone" maxlength="50" placeholder="请输入" clearable /> </el-form-item> <el-form-item label="有效时间范围" prop="effectiveDateStart"> <el-date-picker class="command-date-picker" popper-class="command-date-picker-popper" v-model="effectiveDateRange" type="datetimerange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" value-format="YYYY-MM-DD HH:mm:ss" clearable /> </el-form-item> <el-form-item label="指挥点位置" prop="longitude"> <div class="val">{{ formatLocation(formData) }}</div> </el-form-item> </el-form> <div class="footer"> <el-button v-if="dialogMode != 'view'" color="#2B2B4C" @click="handleCancel"> {{ readonly ? '关闭' : '取消' }} @@ -152,24 +136,27 @@ <script setup> import { Close } from '@element-plus/icons-vue' import { computed, inject, nextTick, onMounted, ref, watch } from 'vue' import { computed, nextTick, onMounted, ref, watch } from 'vue' import { ElMessage } from 'element-plus' import { fwDefenseSceneDetailApi, fwDefenseSceneSubmitApi } from './sceneConfigApi' import { fieldRules, geomAnalysis, getDictLabel } from '@ztzf/utils' import { fwDefenseSceneManageDetailApi, fwDefenseSceneManageSubmitApi } from './sceneManageApi' import { fwDefenseSceneListApi } from '../sceneConfig/sceneConfigApi' import { fieldRules } from '@ztzf/utils' import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue' import * as Cesium from 'cesium' import { fwAreaDivideDetailApi, fwAreaDivideListApi } from '../partition/partitionApi' import { DrawPolygon } from '@/utils/cesium/DrawPolygon' import commandPost from '@/assets/images/dataCockpit/legend/command-post.png' import { saveOperationLog } from '@ztzf/apis' import { useRoute } from 'vue-router' // 初始化表单数据 const initForm = () => ({ sceneName: '', // 场景名称 sceneType: '', // 场景类型 deviceMode: '', // 设备模式 areaDivideIds: '', // 关联区域ID areaCount: 0, // 区域数量 defenseLeader: '', // 防控负责人 leaderPhone: '', // 防控负责人电话 effectiveDateStart: '', // 有效时间-开始 effectiveDateEnd: '', // 有效时间-结束 longitude: null, // 指挥点经度 latitude: null, // 指挥点纬度 defenseSceneId: '', // 关联场景配置ID }) const emit = defineEmits(['success']) @@ -180,22 +167,22 @@ const submitting = ref(false) // 提交中 const readonly = computed(() => dialogMode.value === 'view') const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' }) const areaTableRef = ref(null) const searchName = ref('') const areaList = ref([]) // 关联区域列表 const selectedAreaRows = ref([]) //选中列表 const dictObj = inject('dictObj') const effectiveDateRange = ref([]) // 有效时间范围 const sceneConfigList = ref([]) // 场景配置列表 const mapRef = ref(null) const route = useRoute() let viewer let redPointEntity let leftClickBound = false // 表单验证规则 const rules = { sceneName: fieldRules(true, 50), sceneType: fieldRules(true), deviceMode: fieldRules(true), areaDivideIds: fieldRules(false), defenseLeader: fieldRules(true, 50), leaderPhone: fieldRules(true, 50), effectiveDateStart: fieldRules(true), longitude: fieldRules(true), defenseSceneId: fieldRules(true), } // 关闭弹框 @@ -209,13 +196,10 @@ if (!isValid) return submitting.value = true try { const ids = selectedAreaRows.value.map(item => item.id) formData.value.areaDivideIds = ids.join(',') formData.value.areaCount = ids.length await fwDefenseSceneSubmitApi(formData.value) await fwDefenseSceneManageSubmitApi(formData.value) saveOperationLog({ requestUri: route.path, title: `${route.name || '场景配置管理'}-${dialogMode.value === 'add' ? '新增' : '编辑'}`, title: `${route.name || '场景管理'}-${dialogMode.value === 'add' ? '新增' : '编辑'}`, type: 1, }) ElMessage.success(dialogMode.value === 'add' ? '新增成功' : '更新成功') @@ -226,128 +210,135 @@ } } // 监听有效时间范围变化,同步到表单数据 watch( () => effectiveDateRange.value, () => { formData.value.effectiveDateStart = effectiveDateRange.value?.[0] || '' formData.value.effectiveDateEnd = effectiveDateRange.value?.[1] || '' } ) // 加载详情 async function loadDetail() { if (!formData.value.id) return const res = await fwDefenseSceneDetailApi({ id: formData.value.id }) const res = await fwDefenseSceneManageDetailApi({ id: formData.value.id }) formData.value = res?.data?.data ?? initForm() // 同步有效时间范围 effectiveDateRange.value = [formData.value.effectiveDateStart, formData.value.effectiveDateEnd].filter(Boolean) } // 获取区域列表 async function getAreaList() { if (areaList.value.length) return const res = await fwAreaDivideListApi({ filterSelected: 1, sceneId: formData.value.id }) areaList.value = res?.data?.data ?? [] // 获取场景配置列表 async function getSceneConfigList() { if (sceneConfigList.value.length) return const res = await fwDefenseSceneListApi({unbound: 1}) sceneConfigList.value = res?.data?.data ?? [] } // 关联区域变更 async function handleAreaSelectionChange(rows) { const selectedRows = await ensureAreaGeom(rows) selectedAreaRows.value = selectedRows const ids = selectedRows.map(item => item.id) formData.value.areaDivideIds = ids.join(',') formData.value.areaCount = ids.length // 获取场景配置名称 function getSceneConfigName(id) { if (!id) return '' const item = sceneConfigList.value.find(item => item.id === id) return item?.sceneName || id } // 渲染面 function renderingSurface() { if (!geometricSource) { initMap() } if (!geometricSource) return geometricSource && geometricSource.entities.removeAll() selectedAreaRows.value.forEach(item => { if (item.geom) { const pointList = geomAnalysis(item.geom) const result = pointList.map(item => [item.longitude, item.latitude]).flat() geometricSource.entities?.add({ customType: 'control_group', position: Cesium.Cartesian3.fromDegrees(result[0], result[1]), polyline: { positions: Cesium.Cartesian3.fromDegreesArray(result), clampToGround: true, width: 3, material: Cesium.Color.RED, }, }) } }) // 格式化指挥点位置 function formatLocation(row) { if (row?.longitude == null || row?.latitude == null) return '' return `${_.round(row.longitude, 6)}, ${_.round(row.latitude, 6)}` } watch(() => selectedAreaRows.value, renderingSurface) async function ensureAreaGeom(rows) { const missingRows = rows.filter(row => row?.id && !row.geom) if (!missingRows.length) return rows const detailList = await Promise.all( missingRows.map(row => fwAreaDivideDetailApi({ id: row.id }) .then(res => res?.data?.data) .catch(() => null) ) ) const detailMap = new Map(detailList.filter(Boolean).map(item => [String(item.id), item])) if (!detailMap.size) return rows areaList.value = areaList.value.map(item => { const detail = detailMap.get(String(item.id)) return detail ? { ...item, ...detail } : item }) return rows.map(item => { const detail = detailMap.get(String(item.id)) return detail ? { ...item, ...detail } : item }) // 格式化有效时间 function formatEffectiveDate(row) { if (!row?.effectiveDateStart && !row?.effectiveDateEnd) return '' return `${row.effectiveDateStart || '-'} ~ ${row.effectiveDateEnd || '-'}` } // 同步关联区域 function syncAreaSelection() { if (!areaTableRef.value) return areaTableRef.value.clearSelection() const rows = [] const areaDivideIds = formData.value.areaDivideIds const arr = Array.isArray(areaDivideIds) ? areaDivideIds.map(item => String(item)) : String(areaDivideIds || '') .split(',') .filter(Boolean) areaList.value.forEach(row => { if (arr.includes(String(row.id))) { areaTableRef.value.toggleRowSelection(row, true) rows.push(row) } }) selectedAreaRows.value = rows if (!rows.length) return formData.value.areaCount = rows.length } let geometricSource // 初始化地图实例 function initMap() { if (viewer) return const map = mapRef.value?.getMap() if (!map?.viewer) return viewer = map.viewer if (!geometricSource) { geometricSource = new Cesium.CustomDataSource('geometricSource') viewer.dataSources.add(geometricSource) if (!readonly.value && !leftClickBound) { map.publicCesium?.addLeftClickEvent?.(null, LeftClickEvent) leftClickBound = true } } // 地图左键点击事件 function LeftClickEvent(click) { const pos = click.position // 优先使用 pickPosition 获取贴地坐标(包含地形高度) let cartesian3 = viewer.scene.pickPosition(pos) // 如果 pickPosition 失败,回退到 pickEllipsoid if (!cartesian3 || !Cesium.defined(cartesian3)) { cartesian3 = viewer.camera.pickEllipsoid(pos, viewer.scene.globe.ellipsoid) } if (!cartesian3) return const carto = Cesium.Cartographic.fromCartesian(cartesian3) const longitude = Cesium.Math.toDegrees(carto.longitude) const latitude = Cesium.Math.toDegrees(carto.latitude) formData.value.longitude = _.round(longitude, 6) formData.value.latitude = _.round(latitude, 6) setMapPoint(formData.value.longitude, formData.value.latitude) } // 设置地图点位 function setMapPoint(longitude, latitude) { if (!viewer || longitude == null || latitude == null) return if (!redPointEntity) { redPointEntity = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(longitude, latitude), billboard: { image: commandPost, width: 40, height: 56, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, }, label: { text: `${longitude.toFixed(6)}, ${latitude.toFixed(6)}`, font: '14px', fillColor: Cesium.Color.WHITE, backgroundColor: Cesium.Color.BLACK.withAlpha(0.6), backgroundPadding: new Cesium.Cartesian2(5, 5), showBackground: true, style: Cesium.LabelStyle.FILL_AND_OUTLINE, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.CENTER, outlineWidth: 1, outlineColor: Cesium.Color.WHITE, pixelOffset: new Cesium.Cartesian2(0, -72), heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, }, }) } else { redPointEntity.position = Cesium.Cartesian3.fromDegrees(longitude, latitude) redPointEntity.label.text = `${longitude.toFixed(6)}, ${latitude.toFixed(6)}` } } // 打开弹框 async function open({ mode, row } = {}) { dialogMode.value = mode || 'add' formData.value = dialogMode.value === 'add' ? initForm() : row selectedAreaRows.value = [] formData.value = dialogMode.value === 'add' ? initForm() : { ...row } effectiveDateRange.value = [] redPointEntity = null await nextTick() initMap() await getAreaList() await getSceneConfigList() if (dialogMode.value !== 'add') { await loadDetail() } await nextTick() syncAreaSelection() setMapPoint(formData.value.longitude, formData.value.latitude) } onMounted(() => { getSceneConfigList() }) defineExpose({ open, }) applications/drone-command/src/views/areaManage/sceneManage/index.vue
@@ -11,24 +11,6 @@ /> </el-form-item> <el-form-item label="场景类型" prop="sceneType"> <el-select class="command-select" popper-class="command-select-popper" v-model="searchParams.sceneType" placeholder="请选择" clearable @change="handleSearch" > <el-option v-for="item in dictObj.CommandSceneType" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> </el-select> </el-form-item> <el-form-item class="history-search-actions"> <el-button :icon="RefreshRight" @click="resetForm"></el-button> <el-button class="search-btn" :icon="Search" @click="handleSearch"></el-button> @@ -47,14 +29,19 @@ <el-table-column type="index" show-overflow-tooltip width="64" label="序号" /> <el-table-column prop="sceneName" show-overflow-tooltip label="场景名称" /> <el-table-column prop="sceneType" show-overflow-tooltip label="场景类型"> <el-table-column show-overflow-tooltip label="指挥点经度纬度"> <template v-slot="{ row }"> {{ getDictLabel(row.sceneType, dictObj.CommandSceneType) }} {{ formatLocation(row) }} </template> </el-table-column> <el-table-column prop="areaCount" show-overflow-tooltip label="区域数量" /> <el-table-column prop="counterDeviceCount" show-overflow-tooltip label="反制设备数量" /> <el-table-column prop="detectDeviceCount" show-overflow-tooltip label="探测设备数量" /> <el-table-column prop="defenseLeader" show-overflow-tooltip label="防控负责人" /> <el-table-column prop="leaderPhone" show-overflow-tooltip label="防控负责人电话" /> <el-table-column show-overflow-tooltip label="有效时间"> <template v-slot="{ row }"> {{ formatEffectiveDate(row) }} </template> </el-table-column> <el-table-column prop="defenseSceneId" show-overflow-tooltip label="关联场景配置ID" /> <el-table-column label="操作" class-name="operation-btns"> <template v-slot="{ row }"> <el-link @click="openForm('view', row)">查看</el-link> @@ -83,18 +70,16 @@ <script setup> import { Search, RefreshRight, Plus, Delete } from '@element-plus/icons-vue' import { nextTick, onMounted, provide, ref } from 'vue' import { nextTick, onMounted, ref } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' import { fwDefenseScenePageApi, fwDefenseSceneRemoveApi } from './sceneConfigApi' import { fwDefenseSceneManagePageApi, fwDefenseSceneManageRemoveApi } from './sceneManageApi' import FormDiaLog from './FormDiaLog.vue' import { getDictionaryByCode } from '@/api/system/dictbiz' import { getDictLabel } from '@ztzf/utils' import { saveOperationLog } from '@ztzf/apis' import { useRoute } from 'vue-router' // 初始化查询参数 const initSearchParams = () => ({ sceneName: '', // 场景名称 sceneType: '', // 场景类型 current: 1, // 当前页 size: 10, // 每页大小 }) @@ -109,11 +94,11 @@ const dialogVisible = ref(false) const route = useRoute() // 获取列表 // 获取列表数据 async function getList() { loading.value = true try { const res = await fwDefenseScenePageApi(searchParams.value) const res = await fwDefenseSceneManagePageApi(searchParams.value) list.value = res?.data?.data?.records ?? [] total.value = res?.data?.data?.total ?? 0 } finally { @@ -144,10 +129,10 @@ cancelButtonClass: 'command-message-box-cancel', }) const ids = row ? row.id : selectedIds.value.join(',') await fwDefenseSceneRemoveApi({ ids }) await fwDefenseSceneManageRemoveApi({ ids }) saveOperationLog({ requestUri: route.path, title: `${route.name || '场景配置管理'}-删除`, title: `${route.name || '场景管理'}-删除`, type: 1, }) ElMessage.success('删除成功') @@ -160,23 +145,16 @@ selectedIds.value = rows.map(item => item.id) } // 格式化指挥点位置 function formatLocation(row) { if (row?.longitude == null || row?.latitude == null) return '' return `${_.round(row.longitude, 6)}, ${_.round(row.latitude, 6)}` } const dictObj = ref({ sceneType: [], // 场景类型 deviceMode: [], // 设备模式 areaType: [], // 区域类型 }) provide('dictObj', dictObj) // 获取字典 function getDictList() { getDictionaryByCode('CommandSceneType,deviceMode,areaType').then(res => { dictObj.value = res.data.data }) // 格式化有效时间 function formatEffectiveDate(row) { if (!row?.effectiveDateStart && !row?.effectiveDateEnd) return '' return `${row.effectiveDateStart || '-'} ~ ${row.effectiveDateEnd || '-'}` } // 新增/编辑/查看 弹框 @@ -189,7 +167,6 @@ onMounted(() => { getList() getDictList() }) </script> <style scoped lang="scss"></style> applications/drone-command/src/views/areaManage/sceneManage/sceneConfigApi.js
File was deleted applications/drone-command/src/views/areaManage/sceneManage/sceneManageApi.js
New file @@ -0,0 +1,38 @@ import request from '@/axios' // 分页查询场景管理列表 export const fwDefenseSceneManagePageApi = params => { return request({ url: `/drone-fw/area/fwDefenseSceneManage/page`, method: 'get', params: { descs: 'update_time', ...params }, }) } // 获取场景管理详情 export const fwDefenseSceneManageDetailApi = params => { return request({ url: `/drone-fw/area/fwDefenseSceneManage/detail`, method: 'get', params, }) } // 新增或修改场景管理 export const fwDefenseSceneManageSubmitApi = data => { return request({ url: `/drone-fw/area/fwDefenseSceneManage/submit`, method: 'post', data, }) } // 删除场景管理 export const fwDefenseSceneManageRemoveApi = params => { return request({ url: `/drone-fw/area/fwDefenseSceneManage/remove`, method: 'post', params, }) } applications/task-work-order/src/views/orderView/orderDataManage/appInnovation/FormDiaLog.vue
@@ -6,6 +6,7 @@ @closed="visible = false" destroy-on-close :close-on-click-modal="false" width="800px" > <div class="detail-container" v-if="dialogReadonly"> <el-row class="detail-row-view"> applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/FormDiaLog.vue
@@ -218,6 +218,42 @@ <!-- <el-button color="#F2F3F5" :loading="submitting" :disabled="submitting" @click="visible = false">关闭</el-button>--> </template> </template> <!-- 申请弹框 --> <el-dialog class="gd-dialog" v-model="showApplyDialog" title="申请" @closed="handleApplyDialogClosed" width="500px" destroy-on-close :close-on-click-modal="false" > <el-form class="gd-dialog-form" ref="applyFormRef" :model="applyFormData" :rules="applyRules"> <el-row> <el-col :span="24"> <el-form-item label="申请对象部门" prop="applyTargetDeptId"> <el-tree-select class="gd-select" popper-class="gd-tree-select-popper" v-model="applyFormData.applyTargetDeptId" node-key="id" :data="deptTree" :props="treeProps" check-strictly clearable /> </el-form-item> </el-col> </el-row> </el-form> <template #footer> <el-button color="#F2F3F5" @click="showApplyDialog = false">取消</el-button> <el-button class="" color="#4C34FF" :loading="applying" :disabled="applying" @click="handleApplySubmit"> 确认 </el-button> </template> </el-dialog> </el-dialog> </template> @@ -283,6 +319,14 @@ const attachmentDetailsList = ref([]) const uploading = ref(false) // 文件上传中状态 // 申请弹框相关 const showApplyDialog = ref(false) const applyFormRef = ref(null) const applying = ref(false) const applyFormData = ref({ applyTargetDeptId: '' }) // 表单校验规则 const rules = { title: fieldRules(true), @@ -300,6 +344,11 @@ const feedbackRules = { otherObjectionDetail: fieldRules(true), reviewOpinion: fieldRules(true), } // 申请弹框校验规则 const applyRules = { applyTargetDeptId: fieldRules(true), } // 自定义上传请求 @@ -323,9 +372,6 @@ } // 文件移除 // const handleFileRemove = (file, fileListVal) => { // uploadedFiles.value = fileListVal // } const handleFileRemove = (file, fileListVal) => { // 从展示列表中移除 fileList.value = fileListVal @@ -409,13 +455,6 @@ }), objectionStatus: objectionStatus } // 如果是编辑且没有修改附件,可以保留原有附件ID if (dialogMode.value === 'edit' && formData.value.attachIds) { // 这里可以根据业务需求决定是否保留原附件ID // 如果接口支持更新时重新上传附件ID列表,可以这样做 } await gdDataObjectionSubmitApi(submitData) ElMessage.success(dialogMode.value === 'add' ? '新增成功' : '更新成功') visible.value = false @@ -430,9 +469,66 @@ await submitForm('0') } // 申请提交 // 申请弹框关闭处理 function handleApplyDialogClosed() { applyFormData.value.applyTargetDeptId = '' } // 申请 async function handleApply() { await submitForm('1') formData.value.attachId = uploadedFiles.value.length > 0 ? uploadedFiles.value.length : '' // 先验证主表单 const mainFormValid = await formRef.value?.validate().catch(() => false) if (!mainFormValid) return showApplyDialog.value = true } // 申请提交 async function handleApplySubmit() { const isValid = await applyFormRef.value?.validate().catch(() => false) if (!isValid) return applying.value = true try { // 构建申请数据 const applyData = { ...formData.value, objectionStatus: '1', applyTargetDeptId: applyFormData.value.applyTargetDeptId } // 构建符合接口要求的提交数据 const submitData = { // 编辑模式下传递id ...(applyData.id && { id: applyData.id }), title: applyData.title, objectionType: applyData.objectionType, submitter: applyData.submitter, submitterContact: applyData.submitterContact, catalogResourceName: applyData.catalogResourceName, objectionDesc: applyData.objectionDesc, objectionBasis: applyData.objectionBasis, areaCode: applyData.areaCode || '', handleUnit: applyData.handleUnit || '', // 构建附件列表 - 使用当前已上传的文件(包括回显的) ...(uploadedFiles.value.length > 0 && { attachmentList: uploadedFiles.value.map(file => ({ attachId: file.attachId, attachName: file.originalName, })), }), objectionStatus: applyData.objectionStatus, applyTargetDeptId: applyData.applyTargetDeptId } await gdDataObjectionSubmitApi(submitData) ElMessage.success('申请成功') showApplyDialog.value = false visible.value = false emit('success') } finally { applying.value = false } } // 处理异议反馈提交 @@ -510,8 +606,6 @@ ElMessage.warning('没有可下载的附件') return } // 顺序下载每个附件 for (let i = 0; i < attachmentDetailsList.value.length; i++) { const attach = attachmentDetailsList.value[i] @@ -522,10 +616,6 @@ } try { // 显示当前下载的文件信息 const currentFileName = attach.originalName || attach.name || `附件_${i + 1}` const response = await fetch(attach.link) const blob = await response.blob() const url = window.URL.createObjectURL(blob) @@ -569,8 +659,6 @@ } } // 打开弹框 async function open({ mode = 'add', row } = {}) { dialogMode.value = mode @@ -581,6 +669,8 @@ formData.value = dialogMode.value === 'add' ? initForm() : row // 重置反馈表单数据 feedbackFormData.value = initFeedbackForm() // 重置申请弹框数据 applyFormData.value.applyTargetDeptId = '' if (dialogMode.value !== 'add') { // 如果是编辑,设置ID并加载详情 applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/index.vue
@@ -59,7 +59,7 @@ {{ getDictLabel(row.objectionStatus, dictObj.objectionStatus) }} </template> </el-table-column> <el-table-column prop="catalogResourceName" width="130" show-overflow-tooltip label="目录/申请资源名称" /> <el-table-column prop="catalogResourceName" width="140" show-overflow-tooltip label="目录/申请资源名称" /> <el-table-column prop="otherObjectionDetail" show-overflow-tooltip label="其他异议详情" /> <el-table-column prop="submitter" show-overflow-tooltip label="问题提交人" /> <el-table-column prop="submitterContact" show-overflow-tooltip width="120" label="提交人联系方式" /> applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/FormDiaLog.vue
@@ -8,7 +8,7 @@ :close-on-click-modal="false" > <div class="detail-container" v-if="dialogReadonly"> <el-row class="detail-row-view"> <el-row class="detail-row-view supplyAddLabel"> <el-col :span="12"> <div class="label">需求名称</div> <div class="val">{{ formData.demandName }}</div> @@ -194,9 +194,45 @@ > 保存 </el-button> <el-button color="#4C34FF" :loading="submitting" :disabled="submitting" @click="handleApply">申请</el-button> <el-button color="#4C34FF" :loading="submitting" :disabled="submitting" @click="handleApply" >申请</el-button> </template> <!-- 申请弹框 --> <el-dialog class="gd-dialog" v-model="showApplyDialog" title="申请" @closed="handleApplyDialogClosed" width="500px" destroy-on-close :close-on-click-modal="false" > <el-form class="gd-dialog-form" ref="applyFormRef" :model="applyFormData" :rules="applyRules"> <el-row> <el-col :span="24"> <el-form-item label="申请对象部门" prop="applyTargetDeptId"> <el-tree-select class="gd-select" popper-class="gd-tree-select-popper" v-model="applyFormData.applyTargetDeptId" node-key="id" :data="deptTree" :props="treeProps" check-strictly clearable /> </el-form-item> </el-col> </el-row> </el-form> <template #footer> <el-button color="#F2F3F5" @click="showApplyDialog = false">取消</el-button> <el-button class="" color="#4C34FF" :loading="applying" :disabled="applying" @click="handleApplySubmit"> 确认 </el-button> </template> </el-dialog> </el-dialog> </template> @@ -240,6 +276,14 @@ const dialogReadonly = computed(() => dialogMode.value === 'view') const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' }) // 申请弹框相关 const showApplyDialog = ref(false) const applyFormRef = ref(null) const applying = ref(false) const applyFormData = ref({ applyTargetDeptId: '' }) const rules = { demandName: fieldRules(true), demandType: fieldRules(true), @@ -253,6 +297,11 @@ responsibleDeptId: fieldRules(true), dataSource: fieldRules(true), demandInfo: fieldRules(true), } // 申请弹框校验规则 const applyRules = { applyTargetDeptId: fieldRules(true), } // 根据部门ID获取部门名称 function getDeptNameById(deptId, deptList) { @@ -295,19 +344,37 @@ } } // 申请提交 // 申请弹框关闭处理 function handleApplyDialogClosed() { applyFormData.value.applyTargetDeptId = '' } // 申请 async function handleApply() { const isValid = await formRef.value?.validate().catch(() => false) // 先验证主表单 const mainFormValid = await formRef.value?.validate().catch(() => false) if (!mainFormValid) return showApplyDialog.value = true } // 申请提交 async function handleApplySubmit() { const isValid = await applyFormRef.value?.validate().catch(() => false) if (!isValid) return submitting.value = true applying.value = true try { formData.value.demandStatus = '1' await gdSupplyDemandSubmitApi(formData.value) // 构建申请数据 const applyData = { ...formData.value, demandStatus: '1', applyTargetDeptId: applyFormData.value.applyTargetDeptId } await gdSupplyDemandSubmitApi(applyData) ElMessage.success('申请成功') showApplyDialog.value = false visible.value = false emit('success') } finally { submitting.value = false applying.value = false } } @@ -334,3 +401,10 @@ defineExpose({ open }) </script> <style scoped lang="scss"> .supplyAddLabel { .label { width: 120px !important; } } </style>