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