From b5d3e5db9ef39cd0bdf6b49246be6818a58d731c Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Thu, 11 Sep 2025 13:40:01 +0800
Subject: [PATCH] feat:空域录入基础配置相关处理
---
src/views/airspace/airspaceEntering.vue | 569 ++++++++++++++++++++++---------------------
src/utils/cesium/publicCesium.js | 17
src/styles/element-ui.scss | 27 ++
src/views/airspace/components/AirspaceMap.vue | 157 ++++++++++++
4 files changed, 488 insertions(+), 282 deletions(-)
diff --git a/src/styles/element-ui.scss b/src/styles/element-ui.scss
index 938aeb8..eb57fd8 100644
--- a/src/styles/element-ui.scss
+++ b/src/styles/element-ui.scss
@@ -138,4 +138,29 @@
}
}
}
-}
\ No newline at end of file
+}
+
+// ----------空域规划-----空域录入样式相关----------
+.airspace-dialog {
+ .el-dialog__header {
+ span {
+ padding-left: 16px !important;
+ display: inline-block;
+ }
+
+ .el-dialog__title {
+ font-family: 'Source Han Sans CN' !important;
+ font-weight: bold !important;
+ font-size: 16px !important;
+ color: #363636 !important;
+ }
+ }
+
+ .el-dialog__body {
+ .el-textarea__inner {
+ resize: none !important;
+ }
+ }
+}
+
+// ----------空域规划-----空域录入样式相关----------
\ No newline at end of file
diff --git a/src/utils/cesium/publicCesium.js b/src/utils/cesium/publicCesium.js
index 97b0f8a..2bdcc29 100644
--- a/src/utils/cesium/publicCesium.js
+++ b/src/utils/cesium/publicCesium.js
@@ -193,11 +193,12 @@
gl = null
this.viewer?.destroy() // 销毁Viewer实例
this.viewer = null
- var cesiumContainer = document.getElementById(this.viewerDom)
- if (cesiumContainer && removeDom) {
- cesiumContainer.remove() // 移除与地图相关的DOM元素
- this.viewerDom = null
- }
+ // var cesiumContainer = document.getElementById(this.viewerDom)
+ // if (cesiumContainer && removeDom) {
+ // cesiumContainer.remove() // 移除与地图相关的DOM元素
+ // this.viewerDom = null
+ // }
+ this.viewerDom = null
}
}
@@ -209,7 +210,7 @@
async switchContour (open) {
if (open) {
await this.boundary?.openContour()
-
+
} else {
this.boundary?.closeContour()
}
@@ -752,7 +753,7 @@
Cesium.Cartesian3.subtract(a, this.viewer?.camera.position, a),
Cesium.Cartesian3.normalize(r, r),
Cesium.Cartesian3.normalize(a, a)) : (r = c.direction,
- a = h.direction)
+ a = h.direction)
let d = Cesium.Cartesian3.dot(r, a)
, p = 0
return d < 1 && (p = Math.acos(d)),
@@ -781,7 +782,7 @@
, r = Cesium.Math.acosClamped(-e)
a > 0 && a > r && (a = r - Cesium.Math.EPSILON4),
r = Cesium.Math.acosClamped(e),
- a < 0 && -a > r && (a = -r + Cesium.Math.EPSILON4)
+ a < 0 && -a > r && (a = -r + Cesium.Math.EPSILON4)
}
return a
}
diff --git a/src/views/airspace/airspaceEntering.vue b/src/views/airspace/airspaceEntering.vue
index ea32724..e8bacb2 100644
--- a/src/views/airspace/airspaceEntering.vue
+++ b/src/views/airspace/airspaceEntering.vue
@@ -1,296 +1,319 @@
-<!--
- * @Author : yuan
- * @Date : 2025-09-11 09:23:03
- * @LastEditors : yuan
- * @LastEditTime : 2025-09-11 09:24:27
- * @FilePath : \src\views\airspace\airspaceEntering.vue
- * @Description :
- * Copyright 2025 OBKoro1, All Rights Reserved.
- * 2025-09-11 09:23:03
--->
<template>
- <div class="airspaceManage">
- <div class="search-box">
- <el-form :model="params" inline>
- <el-form-item label="类型名称:">
- <el-input v-model="params.algName" placeholder="请输入空域名称" clearable />
- </el-form-item>
- <el-form-item label="创建人:">
- <el-input v-model="params.algName" placeholder="请输入空域名称" clearable />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" @click="getList">搜索</el-button>
- <el-button @click="cancelSearch">取消</el-button>
- </el-form-item>
- </el-form>
- <div>
- <el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增类型</el-button>
- </div>
- </div>
- <div class="mange-table">
- <el-table border :data="tableList" class="custom-header">
- <el-table-column label="序号" type="index" width="60"></el-table-column>
- <el-table-column prop="model_name" label="类型名称" align="center" show-overflow-tooltip></el-table-column>
- <el-table-column prop="alg_type" label="创建时间" align="center"></el-table-column>
- <el-table-column prop="alg_type" label="创建人" align="center"></el-table-column>
- <el-table-column label="操作" width="180" align="center">
- <template #default="scope">
- <el-button icon="el-icon-view" type="text" @click="handleDetail(scope.row)">查看</el-button>
- <el-button icon="el-icon-delete" type="text" @click="handleDelete">删除</el-button>
- </template>
- </el-table-column>
- </el-table>
- </div>
- <div class="pagination">
- <el-pagination class="ztzf-pagination" popper-class="custom-pagination-dropdown" background
- :page-sizes="[10, 20, 30, 40, 50, 100]" :size="size" v-model:current-page="params.current"
- v-model:page-size="params.size" layout="total, sizes, prev, pager, next, jumper" :total="total"
- @size-change="handleSizeChange" @current-change="handleCurrentChange" />
- </div>
- </div>
- <el-dialog class="ztzf-dialog" append-to-body v-model="isShowView" title="查看" :width="pxToRem(600)"
- :close-on-click-modal="false" :destroy-on-close="true">
- <div class="content">
- <table class="view-table" border>
- <tr>
- <td class="label">空域类型</td>
- <td class="value">{{ rowView.model_name }}</td>
- <td class="label">创建时间</td>
- <td class="value">{{ rowView.alg_type }}</td>
- </tr>
- </table>
- </div>
- </el-dialog>
- <el-dialog class="ztzf-dialog" append-to-body v-model="isShowEditView" title="新增" :width="pxToRem(800)"
- :close-on-click-modal="false" :destroy-on-close="true">
- <div class="content-edit">
- <el-form ref="ruleFormRef" :model="editParams" :rules="rules" inline>
- <el-form-item label="空域名称">
- <el-input v-model="editParams.model_name" />
- </el-form-item>
- <div class="btns">
- <el-button type="primary" @click="submit(ruleFormRef)">确认</el-button>
- <el-button @click="isShowEditView = false">取消</el-button>
- </div>
- </el-form>
- </div>
- </el-dialog>
+ <basic-container>
+ <avue-crud :option="option" :table-loading="loading" :data="data" v-model:page="page" :permission="permissionList"
+ v-model="form" ref="crud" @row-update="rowUpdate" @row-save="rowSave" @row-del="rowDel" :before-open="beforeOpen"
+ @search-change="searchChange" @search-reset="searchReset" @selection-change="selectionChange"
+ @current-change="currentChange" @size-change="sizeChange" @refresh-change="refreshChange" @on-load="onLoad">
+ <template #menu-left>
+ <el-button type="primary" icon="el-icon-plus" @click="addAirspace">新增空域</el-button>
+ </template>
+
+ <template #status="{ row }">
+ <el-tag>{{ row.statusName }}</el-tag>
+ </template>
+ <template #category="{ row }">
+ <el-tag>{{ row.categoryName }}</el-tag>
+ </template>
+ </avue-crud>
+ </basic-container>
+
+ <AirspaceMap v-model:show="airspaceMapShow" />
</template>
+
<script setup>
-import { getAlgorithmManageList, algorithmManageEdit } from '@/api/airspaceManage/airspaceManage'
-import { getDictionaryByCode } from '@/api/system/dictbiz'
-
-const total = ref(0)
-const params = ref({
- current: 1,
- size: 10,
- algName: '',
- algTypeCode: '',
+import {
+ searchManagementApi,
+ listOfSpotTypesApi,
+ spotTypesCreateApi,
+ editSpotTypeApi,
+ deleteSpotTypeApi,
+} from '@/api/patchManagement/index'
+import { ref, computed, watch } from 'vue'
+import { enable, disable } from '@/api/resource/oss'
+import { useStore } from 'vuex'
+import func from '@/utils/func'
+import { useRouter } from 'vue-router'
+import AirspaceMap from '@/views/airspace/components/AirspaceMap.vue'
+import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
+const store = useStore()
+const router = useRouter()
+// ---------------- data ----------------
+const form = ref({})
+const query = ref({})
+const creatorOption = ref([])
+const loading = ref(true)
+const page = ref({
+ pageSize: 20,
+ currentPage: 1,
+ total: 0,
+ lotValue: '',
+ userName: '',
})
+const selectionList = ref([])
-let tableList = ref([])
-
-let isShowView = ref(false)
-
-let rowView = ref({})
-
-let isShowEditView = ref(false)
-
-let sfTypes = ref([])
-const ruleFormRef = ref()
-let editParams = ref({
- model_name: '',
- alg_type: '',
- qua_rate: '',
- pass_rate: '',
- event_type: '',
- remark: ''
-})
-const rules = reactive({
- qua_rate: [
- { required: true, message: '请输入最低准确率', trigger: 'blur' },
+const option = ref({
+ addBtn: false,
+ tip: false,
+ searchShow: true,
+ searchMenuSpan: 12,
+ searchMenuPosition: 'right',
+ border: true,
+ index: true,
+ indexLabel: '序号',
+ indexWidth: 60,
+ selection: true,
+ grid: false,
+ menuWidth: 180,
+ labelWidth: 100,
+ dialogWidth: 880,
+ dialogClickModal: false,
+ height: 'auto',
+ calcHeight: 20,
+ refreshBtn: false,
+ gridBtn: false,
+ searchShowBtn: false,
+ columnBtn: false,
+ column: [
{
- validator: (rule, value, callback) => {
- if (!/^\d+(\.\d+)?$/.test(value)) {
- callback(new Error('请输入有效的数字(整数或小数)'))
- } else if (parseFloat(value) < 0.4) {
- callback(new Error('最低准确率不能小于0.4'))
- } else if (parseFloat(value) >= parseFloat(editParams.value.pass_rate)) {
- callback(new Error('最低准确率必须小于最高准确率'))
- } else {
- callback()
- }
- },
- trigger: 'blur'
- }
- ],
- pass_rate: [
- { required: true, message: '请输入最低准确率', trigger: 'blur' },
+ label: '名称',
+ prop: 'patches_type',
+ search: true,
+ searchSpan: 4,
+ searchLabelWidth: 54,
+ rules: [{ required: true, message: '请输入名称', trigger: 'blur' }],
+ },
{
- validator: (rule, value, callback) => {
- if (!/^\d+(\.\d+)?$/.test(value)) {
- callback(new Error('请输入有效的数字(整数或小数)'))
- } else if (parseFloat(value) > 0.8) {
- callback(new Error('最高准确率不能大于0.8'))
- } else {
- callback()
- }
- },
- trigger: 'blur'
- }
- ],
- event_type: [
+ label: '类型',
+ prop: 'patches_type',
+ search: true,
+ searchSpan: 4,
+ searchLabelWidth: 54,
+ rules: [{ required: true, message: '请输入类型', trigger: 'blur' }],
+ },
{
- required: true,
- message: '请选择事件生成类型',
- trigger: 'change',
+ label: '高度',
+ prop: 'patches_type',
+ rules: [{ required: true, message: '请输入高度', trigger: 'blur' }],
+ },
+ {
+ label: '面积',
+ prop: 'patches_type',
+ rules: [{ required: true, message: '请输入面积', trigger: 'blur' }],
+ },
+ {
+ label: '管控时段',
+ prop: 'patches_type',
+ search: true,
+ searchSpan: 4,
+ rules: [{ required: true, message: '请输入管控时间', trigger: 'blur' }],
+ },
+ {
+ label: '创建人',
+ prop: 'patches_type',
+ rules: [{ required: true, message: '请输入创建人', trigger: 'blur' }],
+ },
+ {
+ label: '创建时间',
+ prop: 'patches_type',
+ rules: [{ required: true, message: '请输入创建时间', trigger: 'blur' }],
},
],
})
-function cancelSearch () {
- params.value = {
- algName: '',
- algTypeCode: '',
+const data = ref([])
+// 获取搜索数据
+const getsearchManagementApi = () => {
+ searchManagementApi().then(res => {
+ const creatorOptionuniqueMap = new Map()
+ res.data.data.user_names.forEach(item => {
+ const [key, value] = Object.entries(item)[0]
+ if (!creatorOptionuniqueMap.has(key)) {
+ creatorOptionuniqueMap.set(key, value)
+ }
+ })
+ creatorOption.value = Array.from(creatorOptionuniqueMap).map(([key, value]) => ({
+ label: value,
+ value: value,
+ }))
+ })
+}
+
+// ---------------- watch ----------------
+watch(
+ () => form.value.category,
+ () => {
+ const category = func.toInt(form.value.category)
+ option.value.column.filter(item => {
+ if (item.prop === 'appId') {
+ item.display = category === 4
+ }
+ })
}
- getList()
+)
+
+// ---------------- computed ----------------
+const permission = computed(() => store.getters.permission)
+const permissionList = computed(() => ({
+ addBtn: validData(permission.value.oss_add),
+ viewBtn: validData(permission.value.oss_view),
+ delBtn: validData(permission.value.oss_delete),
+ editBtn: validData(permission.value.oss_edit),
+}))
+
+const ids = computed(() => {
+ return selectionList.value.map(ele => ele.id).join(',')
+})
+
+const airspaceMapShow = ref(false)
+
+// ---------------- methods ----------------
+const addAirspace = () => {
+ form.value = {}
+ airspaceMapShow.value = true
}
-function getList () {
- getAlgorithmManageList(params.value).then(res => {
- tableList.value = res.data.data.records || []
- total.value = res.data.data.total || 0
- })
-}
-function getSFType () {
- getDictionaryByCode('WORK_ORDER_TYPE').then(res => {
- sfTypes.value = res.data.data.WORK_ORDER_TYPE || []
- })
-}
-function handleDetail (row) {
- isShowView.value = true
- rowView.value = row
-}
-function handleDelete (row) {
- console.log(row)
-}
-function handleAdd (row) {
- isShowEditView.value = true
- // editParams.value = { ...row }
-}
-
-async function submit (formValidate) {
- if (!formValidate) return
- await formValidate.validate((valid, fields) => {
- if (valid) {
- algorithmManageEdit(editParams.value).then(res => {
- isShowEditView.value = false
- getList()
- })
+const rowSave = (row, done, loadingFn) => {
+ const createParams = {
+ patches_type: row.patches_type,
+ }
+ spotTypesCreateApi(createParams).then(
+ () => {
+ onLoad(page.value)
+ ElMessage.success('操作成功!')
+ done()
+ },
+ error => {
+ console.log(error)
+ loadingFn()
}
+ )
+}
+
+const rowUpdate = (row, index, done, loadingFn) => {
+ editSpotTypeApi(row).then(
+ res => {
+ onLoad(page.value)
+ ElMessage.success('操作成功!')
+ done()
+ },
+ error => {
+ console.log(error)
+ loadingFn()
+ }
+ )
+}
+
+const rowDel = row => {
+ ElMessageBox.confirm('确定将选择数据删除?', '提示', {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: 'warning',
})
+ .then(() => deleteSpotTypeApi([row.id]))
+ .then(() => {
+ onLoad(page.value)
+ ElMessage.success('操作成功!')
+ })
+}
+
+const searchReset = () => {
+ page.value.userName = ''
+ page.value.lotValue = ''
+ page.value.currentPage = 1
+ page.value.pageSize = 20
+ onLoad(page.value)
+}
+
+const searchChange = (params, done) => {
+ page.value.currentPage = 1
+ page.value.lotValue = params.patches_type
+ page.value.userName = params.user_name
+ onLoad(page.value)
+ done()
+}
+
+const selectionChange = list => {
+ // selectionList.value = list
+}
+
+const selectionClear = () => {
+ selectionList.value = []
+ // crudRef.value.toggleSelection()
+}
+
+const handleEnable = row => {
+ ElMessageBox.confirm('是否确定启用这条配置?', '提示', {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: 'warning',
+ })
+ .then(() => enable(row.id))
+ .then(() => {
+ onLoad(page.value)
+ ElMessage.success('操作成功!')
+ // crudRef.value.toggleSelection()
+ })
+}
+
+const handleDisable = row => {
+ ElMessageBox.confirm('是否确定禁用这条配置?', '提示', {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: 'warning',
+ })
+ .then(() => disable(row.id))
+ .then(() => {
+ onLoad(page.value)
+ ElMessage.success('操作成功!')
+ // crudRef.value.toggleSelection()
+ })
+}
+
+const beforeOpen = (done, type) => {
+ // if (['edit', 'view'].includes(type)) {
+ // // getDetail(form.value.id).then(res => {
+ // // form.value = res.data.data
+ // // })
+ // }
+ done()
+}
+
+const currentChange = currentPage => {
+ page.value.currentPage = currentPage
+}
+
+const sizeChange = pageSize => {
+ page.value.pageSize = pageSize
+}
+const refreshChange = () => {
+ onLoad(page.value, query.value)
+}
+
+const onLoad = (pageParam, params = {}) => {
+ const searchparams = {
+ current: pageParam.currentPage,
+ size: pageParam.pageSize,
+ lotValue: pageParam.lotValue,
+ userName: pageParam.userName,
+ }
+ loading.value = true
+ listOfSpotTypesApi(searchparams).then(res => {
+ const resData = res.data.data
+ page.value.total = resData.total
+ data.value = resData.records
+ loading.value = false
+ selectionClear()
+ })
+}
+
+// ---------------- utils ----------------
+function validData (value) {
+ return value !== undefined && value !== null && value !== false
}
onMounted(() => {
- getList()
- getSFType()
+ getsearchManagementApi()
})
</script>
-<style lang="scss" scoped>
-.airspaceManage {
- height: 0;
- flex: 1;
- margin: 0 10px 10px 10px;
- background-color: #ffffff;
- padding: 10px 20px;
- border-radius: 5px;
- display: flex;
- flex-direction: column;
-
- .search-box {
- height: 80px;
- }
-
- :deep(.el-input) {
- .el-input__wrapper {
- width: 200px;
- }
- }
-
- // 表格
- .mange-table {
- height: 0;
- flex: 1;
- margin-top: 18px;
- overflow: auto;
- }
-
- :deep(.el-pagination) {
- display: flex;
- justify-content: right;
- }
-
- :deep(.el-pagination button) {
- background: center center no-repeat none !important;
- color: #8eb8ea !important;
- }
-
- :deep(.ztzf-select) {
- .el-select__selection {
- width: 200px;
- }
- }
-}
-
-.content {
- padding: 20px;
-
- .view-table {
- width: 100%;
- border-collapse: collapse;
- border: 1px solid #EBEEF5;
-
- tr {
- &:not(:last-child) {
- border-bottom: 1px solid #EBEEF5;
- }
-
- td {
- padding: 12px 10px;
-
- &.label {
- width: 140px;
- text-align: right;
- // color: #909399;
- // background-color: #F5F7FA;
- border-right: 1px solid #EBEEF5;
- }
-
- &.value {
- width: 180px;
- // color: #303133;
- }
- }
- }
- }
-}
-
-.content-edit {
- .el-form {
- .el-form-item {
- width: 300px;
-
- :deep(.el-form-item__label) {
- width: 120px;
- }
-
- }
-
- .btns {
- display: flex;
- justify-content: center
- }
- }
-}
-</style>
\ No newline at end of file
+<style scoped lang="scss"></style>
diff --git a/src/views/airspace/components/AirspaceMap.vue b/src/views/airspace/components/AirspaceMap.vue
new file mode 100644
index 0000000..cd2d1aa
--- /dev/null
+++ b/src/views/airspace/components/AirspaceMap.vue
@@ -0,0 +1,157 @@
+<template>
+ <el-dialog class="airspace-dialog" :title="props.title" v-model="dialogShow" width="60%" align-center
+ @close="handleClose" :close-on-click-modal="false" :close-on-press-escape="false">
+ <div class="custom-container">
+ <div class="form-container">
+ <avue-form ref="formEle" :option="option" v-model="form"></avue-form>
+ </div>
+ <div class="map-container">
+ <div id="AirspaceMap" class="ztzf-cesium"></div>
+ </div>
+ </div>
+ </el-dialog>
+</template>
+
+<script setup>
+import * as Cesium from 'cesium'
+import { PublicCesium } from '@/utils/cesium/publicCesium'
+
+const props = defineProps({
+ title: {
+ type: String,
+ default: '新增空域',
+ },
+})
+
+const dialogShow = defineModel('show')
+
+const formEle = ref(null)
+const form = ref({})
+const option = ref({
+ submitBtn: false,
+ emptyBtn: false,
+ column: [
+ {
+ label: '名称',
+ prop: 'input',
+ type: 'input',
+ rules: [
+ {
+ required: true,
+ message: '请输入名称',
+ trigger: 'blur'
+ }
+ ]
+ },
+
+ {
+ label: '高度',
+ prop: 'input',
+ type: 'input',
+ rules: [
+ {
+ required: true,
+ message: '请输入高度',
+ trigger: 'blur'
+ }
+ ]
+ },
+
+ {
+ label: '类型',
+ prop: 'select',
+ type: 'select',
+ dicData: [
+ {
+ label: '字典1',
+ value: 0,
+ },
+ {
+ label: '字典2',
+ value: 1,
+ },
+ ],
+ rules: [
+ {
+ required: true,
+ message: '请选择类型',
+ trigger: 'blur'
+ }
+ ]
+ },
+ {
+ label: '管控时段',
+ prop: 'daterange',
+ type: 'daterange',
+ format: 'YYYY-MM-DD',
+ valueFormat: 'YYYY-MM-DD',
+ startPlaceholder: '开始日期',
+ endPlaceholder: '结束日期',
+ rules: [
+ {
+ required: true,
+ message: '请选择管控时段',
+ trigger: 'blur'
+ }
+ ]
+ },
+
+ {
+ label: '备注',
+ prop: 'input',
+ type: 'textarea',
+ span: 24,
+ rows: 1,
+ minRows: 1,
+ maxRows: 1,
+ placeholder: '请输入备注',
+ },
+ ],
+})
+
+let publicCesiumInstance = null
+let viewer = null
+// 地图
+const initMap = () => {
+ if (!document.getElementById('AirspaceMap')) {
+ return
+ }
+ publicCesiumInstance = new PublicCesium({
+ dom: 'AirspaceMap',
+ flatMode: false,
+ terrain: true,
+ layerMode: 4,
+ contour: false,
+ })
+ viewer = publicCesiumInstance.getViewer()
+}
+
+watch(dialogShow, async (show) => {
+ if (show) {
+ await nextTick()
+ initMap()
+ }
+})
+
+const handleClose = () => {
+ publicCesiumInstance?.viewerDestroy()
+ publicCesiumInstance = null
+ viewer = null
+ form.value = {}
+ formEle.value.resetForm()
+ dialogShow.value = false
+}
+</script>
+
+<style scoped lang="scss">
+.custom-container {
+ .map-container {
+ height: 440px;
+
+ #AirspaceMap {
+ width: 100%;
+ height: 100%;
+ }
+ }
+}
+</style>
--
Gitblit v1.9.3