Prechádzať zdrojové kódy

增加创建业务场景按钮

WQQ 18 hodín pred
rodič
commit
56f3b1d308
92 zmenil súbory, kde vykonal 2397 pridanie a 59 odobranie
  1. 44 0
      RuoYi-Vue3/src/api/cesium/businessScene.js
  2. 223 43
      RuoYi-Vue3/src/components/CreateScenario.vue
  3. 88 0
      RuoYi-Vue3/src/supermap-cesium-module/config/server_config.js
  4. 342 15
      RuoYi-Vue3/src/supermap-cesium-module/views/layout/aside.vue
  5. 38 1
      RuoYi-Vue3/src/views/front/HydrologicalPlatform.vue
  6. 320 0
      RuoYi-Vue3/src/views/system/businessScene/index.vue
  7. BIN
      ruoyi-admin/db-tools/AddCameraOrientationColumns.class
  8. 47 0
      ruoyi-admin/db-tools/AddCameraOrientationColumns.java
  9. 67 0
      ruoyi-admin/db-tools/AddMissingColumns.java
  10. BIN
      ruoyi-admin/db-tools/CheckData.class
  11. 45 0
      ruoyi-admin/db-tools/CheckData.java
  12. BIN
      ruoyi-admin/db-tools/CreateBusinessSceneTable.class
  13. 100 0
      ruoyi-admin/db-tools/CreateBusinessSceneTable.java
  14. BIN
      ruoyi-admin/db-tools/ExecuteAddColumns.class
  15. 51 0
      ruoyi-admin/db-tools/ExecuteAddColumns.java
  16. BIN
      ruoyi-admin/db-tools/ExecuteBusinessSceneMenuScript.class
  17. 76 0
      ruoyi-admin/db-tools/ExecuteBusinessSceneMenuScript.java
  18. BIN
      ruoyi-admin/db-tools/InsertMenuForBusinessScene.class
  19. 98 0
      ruoyi-admin/db-tools/InsertMenuForBusinessScene.java
  20. 49 0
      ruoyi-admin/db-tools/TestApi.java
  21. 15 0
      ruoyi-admin/db-tools/add_columns.sql
  22. 112 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/BusinessSceneController.java
  23. 53 0
      ruoyi-admin/src/main/resources/sql/business_scene.sql
  24. 19 0
      ruoyi-admin/src/main/resources/sql/business_scene_menu.sql
  25. BIN
      ruoyi-admin/target/classes/com/ruoyi/RuoYiApplication.class
  26. BIN
      ruoyi-admin/target/classes/com/ruoyi/RuoYiServletInitializer.class
  27. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/cesium/CesiumMapConfigController.class
  28. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/common/CaptchaController.class
  29. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/common/CommonController.class
  30. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/monitor/CacheController.class
  31. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/monitor/ServerController.class
  32. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/monitor/SysLogininforController.class
  33. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/monitor/SysOperlogController.class
  34. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/monitor/SysUserOnlineController.class
  35. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysConfigController.class
  36. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysDeptController.class
  37. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysDictDataController.class
  38. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysDictTypeController.class
  39. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysIndexController.class
  40. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysLoginController.class
  41. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysMenuController.class
  42. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysNoticeController.class
  43. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysPostController.class
  44. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysProfileController.class
  45. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysRegisterController.class
  46. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysRoleController.class
  47. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysUserController.class
  48. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/tool/TestController.class
  49. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/tool/UserEntity.class
  50. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/watershed/WatershedModelController.class
  51. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/controller/watershed/WatershedServiceController.class
  52. BIN
      ruoyi-admin/target/classes/com/ruoyi/web/core/config/SwaggerConfig.class
  53. 279 0
      ruoyi-system/src/main/java/com/ruoyi/system/domain/BusinessScene.java
  54. 61 0
      ruoyi-system/src/main/java/com/ruoyi/system/mapper/BusinessSceneMapper.java
  55. 61 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/IBusinessSceneService.java
  56. 93 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BusinessSceneServiceImpl.java
  57. 116 0
      ruoyi-system/src/main/resources/mapper/system/BusinessSceneMapper.xml
  58. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/CesiumGeojson.class
  59. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/CesiumMapConfig.class
  60. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/SysCache.class
  61. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/SysConfig.class
  62. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/SysLogininfor.class
  63. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/SysNotice.class
  64. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/SysOperLog.class
  65. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/SysPost.class
  66. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/SysRoleDept.class
  67. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/SysRoleMenu.class
  68. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/SysUserOnline.class
  69. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/SysUserPost.class
  70. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/SysUserRole.class
  71. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/WatershedEquipment.class
  72. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/WatershedFacility.class
  73. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/WatershedService.class
  74. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/vo/MetaVo.class
  75. BIN
      ruoyi-system/target/classes/com/ruoyi/system/domain/vo/RouterVo.class
  76. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/CesiumGeojsonServiceImpl.class
  77. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/CesiumMapConfigServiceImpl.class
  78. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysConfigServiceImpl.class
  79. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysDeptServiceImpl.class
  80. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysDictDataServiceImpl.class
  81. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.class
  82. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysLogininforServiceImpl.class
  83. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysMenuServiceImpl.class
  84. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysNoticeServiceImpl.class
  85. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysOperLogServiceImpl.class
  86. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysPostServiceImpl.class
  87. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysRoleServiceImpl.class
  88. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.class
  89. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysUserServiceImpl.class
  90. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/WatershedEquipmentServiceImpl.class
  91. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/WatershedModelServiceImpl.class
  92. BIN
      ruoyi-system/target/classes/com/ruoyi/system/service/impl/WatershedServiceServiceImpl.class

+ 44 - 0
RuoYi-Vue3/src/api/cesium/businessScene.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询业务场景列表
+export function listBusinessScene(query) {
+  return request({
+    url: '/system/businessScene/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询业务场景详细
+export function getBusinessScene(sceneId) {
+  return request({
+    url: '/system/businessScene/' + sceneId,
+    method: 'get'
+  })
+}
+
+// 新增业务场景
+export function addBusinessScene(data) {
+  return request({
+    url: '/system/businessScene',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改业务场景
+export function updateBusinessScene(data) {
+  return request({
+    url: '/system/businessScene',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除业务场景
+export function delBusinessScene(sceneIds) {
+  return request({
+    url: '/system/businessScene/' + sceneIds,
+    method: 'delete'
+  })
+}

+ 223 - 43
RuoYi-Vue3/src/components/CreateScenario.vue

@@ -19,19 +19,19 @@
           <div class="form-item">
             <label class="form-label">场景名称</label>
             <input 
-              v-model="scenarioName" 
+              v-model="form.sceneName" 
               class="form-input"
               placeholder="请输入场景名称"
             />
           </div>
           
           <div class="form-item">
-            <label class="form-label">场景中心点</label>
+            <label class="form-label">第三视角相机位置</label>
             <div class="coordinate-container">
               <div class="coordinate-item">
                 <label>经度:</label>
                 <input 
-                  v-model="scenarioCenterPoint.longitude" 
+                  v-model="thirdPersonPos.longitude" 
                   class="coordinate-input"
                   placeholder="经度"
                 />
@@ -39,7 +39,7 @@
               <div class="coordinate-item">
                 <label>纬度:</label>
                 <input 
-                  v-model="scenarioCenterPoint.latitude" 
+                  v-model="thirdPersonPos.latitude" 
                   class="coordinate-input"
                   placeholder="纬度"
                 />
@@ -47,19 +47,75 @@
               <div class="coordinate-item">
                 <label>高度:</label>
                 <input 
-                  v-model.number="scenarioCenterPoint.height" 
+                  v-model.number="thirdPersonPos.height" 
                   class="coordinate-input"
                   placeholder="高度(米)"
                 />
               </div>
-              <button 
-                class="use-current-btn"
-                @click="useCurrentViewAsCenter"
-              >
-                <span class="location-icon">📍</span> 使用当前视图位置
-              </button>
             </div>
           </div>
+
+          <div class="form-item">
+            <label class="form-label">相机朝向</label>
+            <div class="coordinate-container">
+              <div class="coordinate-item">
+                <label>朝向角:</label>
+                <input 
+                  v-model.number="cameraOrientation.heading" 
+                  class="coordinate-input"
+                  placeholder="Heading"
+                />
+              </div>
+              <div class="coordinate-item">
+                <label>俯仰角:</label>
+                <input 
+                  v-model.number="cameraOrientation.pitch" 
+                  class="coordinate-input"
+                  placeholder="Pitch"
+                />
+              </div>
+              <div class="coordinate-item">
+                <label>翻滚角:</label>
+                <input 
+                  v-model.number="cameraOrientation.roll" 
+                  class="coordinate-input"
+                  placeholder="Roll"
+                />
+              </div>
+            </div>
+          </div>
+
+          <div class="form-item">
+            <button 
+              class="use-current-btn full-width"
+              @click="useCurrentViewAsCenter"
+            >
+              <span class="location-icon">📍</span> 使用当前视图位置和相机状态
+            </button>
+          </div>
+
+          <div class="form-item">
+            <label class="form-label">场景状态</label>
+            <div class="status-radio-group">
+              <label class="status-radio">
+                <input type="radio" v-model="form.status" value="0" />
+                <span>正常</span>
+              </label>
+              <label class="status-radio">
+                <input type="radio" v-model="form.status" value="1" />
+                <span>维护中</span>
+              </label>
+            </div>
+          </div>
+
+          <div class="form-item">
+            <label class="form-label">备注</label>
+            <textarea 
+              v-model="form.remark" 
+              class="form-textarea"
+              placeholder="请输入备注信息"
+            ></textarea>
+          </div>
         </div>
         
         <div class="dialog-footer">
@@ -74,6 +130,7 @@
 <script setup>
 import { ref, reactive, watch, onMounted } from 'vue'
 import { ElMessage } from 'element-plus'
+import { addBusinessScene } from '@/api/cesium/businessScene'
 
 let Cesium = null
 onMounted(() => {
@@ -91,14 +148,24 @@ const props = defineProps({
 
 const emit = defineEmits(['update:modelValue', 'confirm'])
 
-const scenarioName = ref('')
+const form = reactive({
+  sceneName: '',
+  status: '0',
+  remark: ''
+})
 
-const scenarioCenterPoint = reactive({
+const thirdPersonPos = reactive({
   longitude: '',
   latitude: '',
   height: 500
 })
 
+const cameraOrientation = reactive({
+  heading: 0,
+  pitch: 0,
+  roll: 0
+})
+
 watch(() => props.modelValue, (newVal) => {
   if (newVal) {
     initData()
@@ -106,42 +173,94 @@ watch(() => props.modelValue, (newVal) => {
 })
 
 const initData = () => {
-  scenarioName.value = ''
-  scenarioCenterPoint.longitude = ''
-  scenarioCenterPoint.latitude = ''
-  scenarioCenterPoint.height = 500
+  form.sceneName = ''
+  form.status = '0'
+  form.remark = ''
+  thirdPersonPos.longitude = ''
+  thirdPersonPos.latitude = ''
+  thirdPersonPos.height = 500
+  cameraOrientation.heading = 0
+  cameraOrientation.pitch = 0
+  cameraOrientation.roll = 0
   
   if (window.viewer && window.viewer.camera && Cesium) {
     const position = window.viewer.camera.positionCartographic
     if (position) {
-      scenarioCenterPoint.longitude = Cesium.Math.toDegrees(position.longitude).toFixed(6)
-      scenarioCenterPoint.latitude = Cesium.Math.toDegrees(position.latitude).toFixed(6)
-      scenarioCenterPoint.height = Math.round(position.height)
+      thirdPersonPos.longitude = Cesium.Math.toDegrees(position.longitude).toFixed(6)
+      thirdPersonPos.latitude = Cesium.Math.toDegrees(position.latitude).toFixed(6)
+      thirdPersonPos.height = Math.round(position.height)
+      
+      const camera = window.viewer.camera
+      const orientation = camera.orientation
+      if (orientation) {
+        cameraOrientation.heading = Number(Cesium.Math.toDegrees(orientation.heading || 0).toFixed(4))
+        cameraOrientation.pitch = Number(Cesium.Math.toDegrees(orientation.pitch || 0).toFixed(4))
+        cameraOrientation.roll = Number(Cesium.Math.toDegrees(orientation.roll || 0).toFixed(4))
+      }
     }
   }
 }
 
-const handleConfirm = () => {
-  if (!scenarioName.value || !scenarioName.value.trim()) {
+const handleConfirm = async () => {
+  if (!form.sceneName || !form.sceneName.trim()) {
     ElMessage.warning('请输入场景名称')
     return
   }
-  if (!scenarioCenterPoint.longitude || !scenarioCenterPoint.latitude) {
-    ElMessage.warning('请设置场景中心点坐标')
+  if (!thirdPersonPos.longitude || !thirdPersonPos.latitude) {
+    ElMessage.warning('请设置相机位置坐标')
     return
   }
+
+  // 直接从当前相机获取精确的状态(位置、方向、上向量)
+  let cameraPosition = null
+  let cameraDirection = null
+  let cameraUp = null
   
-  const scenarioData = {
-    name: scenarioName.value,
-    centerPoint: {
-      longitude: parseFloat(scenarioCenterPoint.longitude),
-      latitude: parseFloat(scenarioCenterPoint.latitude),
-      height: scenarioCenterPoint.height
-    }
+  if (window.viewer && window.viewer.camera && Cesium) {
+    cameraPosition = window.viewer.camera.position.clone()
+    cameraDirection = window.viewer.camera.direction.clone()
+    cameraUp = window.viewer.camera.up.clone()
+    console.log('保存时相机位置:', cameraPosition)
+    console.log('保存时相机方向:', cameraDirection)
+    console.log('保存时相机上向量:', cameraUp)
   }
-  
-  emit('confirm', scenarioData)
+
+  // 如果能直接获取相机位置,使用精确的笛卡尔坐标;否则从表单转换
+  let posArray = null
+  if (cameraPosition) {
+    posArray = [cameraPosition.x, cameraPosition.y, cameraPosition.z]
+  } else {
+    const cartesian = Cesium && Cesium.Cartesian3.fromDegrees(
+      parseFloat(thirdPersonPos.longitude),
+      parseFloat(thirdPersonPos.latitude),
+      thirdPersonPos.height
+    )
+    posArray = cartesian ? [cartesian.x, cartesian.y, cartesian.z] : null
+  }
+
+  // 构建方向向量和上向量数组
+  const dirArray = cameraDirection ? [cameraDirection.x, cameraDirection.y, cameraDirection.z] : null
+  const upArray = cameraUp ? [cameraUp.x, cameraUp.y, cameraUp.z] : null
+
+  // 使用数组格式存储相机位置,便于 Cesium.Cartesian3.fromArray 解析
+  const sceneData = {
+    sceneName: form.sceneName,
+    thirdPersonCameraPos: posArray ? JSON.stringify(posArray) : undefined,
+    thirdPersonCameraTarget: posArray ? JSON.stringify([posArray[0], posArray[1], 0]) : undefined,
+    thirdPersonCameraHeading: Cesium ? Cesium.Math.toRadians(cameraOrientation.heading) : 0,
+    thirdPersonCameraPitch: Cesium ? Cesium.Math.toRadians(cameraOrientation.pitch) : 0,
+    thirdPersonCameraRoll: Cesium ? Cesium.Math.toRadians(cameraOrientation.roll) : 0,
+    // 保存方向向量和上向量用于精确恢复相机状态
+    thirdPersonCameraDirection: dirArray ? JSON.stringify(dirArray) : undefined,
+    thirdPersonCameraUp: upArray ? JSON.stringify(upArray) : undefined,
+    status: form.status,
+    remark: form.remark || undefined
+  }
+
+  // 只发出confirm事件,由父组件处理保存逻辑
+  emit('confirm', sceneData)
   emit('update:modelValue', false)
+  ElMessage.success('场景创建成功')
 }
 
 const handleClose = () => {
@@ -150,13 +269,28 @@ const handleClose = () => {
 
 const useCurrentViewAsCenter = () => {
   if (window.viewer && window.viewer.camera && Cesium) {
-    const position = window.viewer.camera.positionCartographic
-    if (position) {
-      scenarioCenterPoint.longitude = Cesium.Math.toDegrees(position.longitude).toFixed(6)
-      scenarioCenterPoint.latitude = Cesium.Math.toDegrees(position.latitude).toFixed(6)
-      scenarioCenterPoint.height = Math.round(position.height)
-      ElMessage.success('已使用当前视图位置')
+    const camera = window.viewer.camera
+    
+    // 直接获取相机的笛卡尔位置(最精确)
+    const position = camera.position
+    console.log('相机位置(笛卡尔):', position)
+    
+    // 将笛卡尔坐标转换为经纬度高度显示给用户
+    const cartographic = Cesium.Cartographic.fromCartesian(position)
+    if (cartographic) {
+      thirdPersonPos.longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6)
+      thirdPersonPos.latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(6)
+      thirdPersonPos.height = Math.round(cartographic.height)
     }
+    
+    // 使用相机的 HPR 属性获取朝向(这些是弧度值)
+    cameraOrientation.heading = Number(Cesium.Math.toDegrees(camera.heading).toFixed(4))
+    cameraOrientation.pitch = Number(Cesium.Math.toDegrees(camera.pitch).toFixed(4))
+    cameraOrientation.roll = Number(Cesium.Math.toDegrees(camera.roll).toFixed(4))
+    
+    console.log('获取到的相机朝向(弧度):', camera.heading, camera.pitch, camera.roll)
+    console.log('获取到的相机朝向(角度):', cameraOrientation.heading, cameraOrientation.pitch, cameraOrientation.roll)
+    ElMessage.success('已使用当前视图位置和相机状态')
   }
 }
 </script>
@@ -174,7 +308,9 @@ const useCurrentViewAsCenter = () => {
 
 .create-scenario-dialog {
   position: absolute;
-  width: 320px;
+  width: 380px;
+  max-height: 80vh;
+  overflow-y: auto;
   background-color: #fff;
   border-radius: 4px;
   box-shadow: 2px 2px 12px rgba(0, 0, 0, 0.15);
@@ -261,6 +397,24 @@ const useCurrentViewAsCenter = () => {
   color: #c0c4cc;
 }
 
+.form-textarea {
+  width: 100%;
+  height: 60px;
+  padding: 8px 12px;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  font-size: 14px;
+  color: #606266;
+  box-sizing: border-box;
+  outline: none;
+  transition: border-color 0.2s;
+  resize: vertical;
+}
+
+.form-textarea:focus {
+  border-color: #409eff;
+}
+
 .coordinate-container {
   display: flex;
   flex-direction: column;
@@ -274,13 +428,13 @@ const useCurrentViewAsCenter = () => {
 }
 
 .coordinate-item label {
-  width: 40px;
+  width: 50px;
   font-size: 14px;
   color: #606266;
 }
 
 .coordinate-input {
-  width: 150px;
+  width: 180px;
   height: 28px;
   padding: 0 10px;
   border: 1px solid #dcdfe6;
@@ -296,6 +450,24 @@ const useCurrentViewAsCenter = () => {
   border-color: #409eff;
 }
 
+.status-radio-group {
+  display: flex;
+  gap: 20px;
+}
+
+.status-radio {
+  display: flex;
+  align-items: center;
+  gap: 6px;
+  font-size: 14px;
+  color: #606266;
+  cursor: pointer;
+}
+
+.status-radio input {
+  cursor: pointer;
+}
+
 .use-current-btn {
   align-self: flex-start;
   padding: 6px 12px;
@@ -310,6 +482,14 @@ const useCurrentViewAsCenter = () => {
   gap: 4px;
 }
 
+.use-current-btn.full-width {
+  width: 100%;
+  justify-content: center;
+  padding: 8px 12px;
+  background-color: #ecf5ff;
+  border-radius: 4px;
+}
+
 .use-current-btn:hover {
   color: #67c23a;
 }
@@ -356,4 +536,4 @@ const useCurrentViewAsCenter = () => {
 .btn-confirm:hover {
   background-color: #67b8ff;
 }
-</style>
+</style>

+ 88 - 0
RuoYi-Vue3/src/supermap-cesium-module/config/server_config.js

@@ -48,6 +48,94 @@ export default [
         layers: [{ type: "MVT", layerName: "流域" }],
         state: 0,
       },
+      {
+        type: "MVT",
+        thumbnail: "/img/componentsImg/mvt.png",
+        proxiedUrl: "",
+        name: "行政区域",
+        layers: [{ type: "MVT", layerName: "行政区域" }],
+        state: 0,
+      },
+      {
+        type: "MVT",
+        thumbnail: "/img/componentsImg/mvt.png",
+        proxiedUrl: "",
+        name: "居民点",
+        layers: [{ type: "MVT", layerName: "居民点" }],
+        state: 0,
+      },
+      {
+        type: "MVT",
+        thumbnail: "/img/componentsImg/mvt.png",
+        proxiedUrl: "",
+        name: "桥梁",
+        layers: [{ type: "MVT", layerName: "桥梁" }],
+        state: 0,
+      },
+      {
+        type: "MVT",
+        thumbnail: "/img/componentsImg/mvt.png",
+        proxiedUrl: "",
+        name: "道路",
+        layers: [{ type: "MVT", layerName: "道路" }],
+        state: 0,
+      },
+      {
+        type: "MVT",
+        thumbnail: "/img/componentsImg/mvt.png",
+        proxiedUrl: "",
+        name: "植被",
+        layers: [{ type: "MVT", layerName: "植被" }],
+        state: 0,
+      },
+      {
+        type: "MVT",
+        thumbnail: "/img/componentsImg/mvt.png",
+        proxiedUrl: "",
+        name: "湖泊",
+        layers: [{ type: "MVT", layerName: "湖泊" }],
+        state: 0,
+      },
+      {
+        type: "MVT",
+        thumbnail: "/img/componentsImg/mvt.png",
+        proxiedUrl: "",
+        name: "侵蚀沟",
+        layers: [{ type: "MVT", layerName: "侵蚀沟" }],
+        state: 0,
+      },
+      {
+        type: "MVT",
+        thumbnail: "/img/componentsImg/mvt.png",
+        proxiedUrl: "",
+        name: "地下湖",
+        layers: [{ type: "MVT", layerName: "地下湖" }],
+        state: 0,
+      },
+      {
+        type: "MVT",
+        thumbnail: "/img/componentsImg/mvt.png",
+        proxiedUrl: "",
+        name: "地下河",
+        layers: [{ type: "MVT", layerName: "地下河" }],
+        state: 0,
+      },
+      {
+        type: "MVT",
+        thumbnail: "/img/componentsImg/mvt.png",
+        proxiedUrl: "",
+        name: "水资源分区",
+        layers: [{ type: "MVT", layerName: "水资源分区" }],
+        state: 0,
+      },
+      {
+        type: "MVT",
+        thumbnail: "/img/componentsImg/mvt.png",
+        proxiedUrl: "",
+        name: "土地利用",
+        layers: [{ type: "MVT", layerName: "土地利用" }],
+        state: 0,
+      },
     ],
   },
   {

+ 342 - 15
RuoYi-Vue3/src/supermap-cesium-module/views/layout/aside.vue

@@ -30,7 +30,35 @@
           </template>
           <el-sub-menu v-for="(data,index) in server_config" :key="data.id" :index="data.id" popper-append-to-body="false">
             <template #title>{{data.name}}</template>
-            <div class="box" :index="index">
+            
+            <!-- 基础地理实体使用文字列表方式 -->
+            <template v-if="data.id === 'vectorData'">
+              <el-menu-item 
+                v-for="(data2, idx) in data.children" 
+                :key="data2.name" 
+                :index="data.id + '-' + idx"
+                @dblclick="addDatas(data.id, data2)"
+                class="vector-data-item"
+              >
+                <span class="vector-data-name" :class="{ 'vector-data-loaded': data2.state !== 0 }">{{ data2.name }}</span>
+                <el-popconfirm
+                  v-if="data2.state !== 0"
+                  title="确定卸载吗?"
+                  confirmButtonText="确认"
+                  cancelButtonText="取消"
+                  @confirm="DeleteDates(data.id, data2)"
+                >
+                  <template #reference>
+                    <el-icon class="delete-vector-data-icon" title="卸载">
+                      <CircleClose />
+                    </el-icon>
+                  </template>
+                </el-popconfirm>
+              </el-menu-item>
+            </template>
+            
+            <!-- 其他数据服务使用图片方式 -->
+            <div v-else class="box" :index="index">
               <div
                 class="imgbox"
                 v-for="data2 in data.children"
@@ -202,18 +230,24 @@
             <i class="iconfont iconxingcheng iconfont2"></i>
             <span>业务场景</span>
           </template>
-          <el-menu-item index="business-scenario-1" @click="loadBusinessScenario('flood-control')">
-            <span>防洪排涝</span>
-          </el-menu-item>
-          <el-menu-item index="business-scenario-2" @click="loadBusinessScenario('water-resource')">
-            <span>水资源管理</span>
-          </el-menu-item>
-          <el-menu-item index="business-scenario-3" @click="loadBusinessScenario('project-supervision')">
-            <span>水利工程监管</span>
-          </el-menu-item>
-          <el-menu-item index="business-scenario-4" @click="loadBusinessScenario('eco-environment')">
-            <span>生态环境保护</span>
-          </el-menu-item>
+          <template v-for="scene in businessScenes" :key="scene.sceneId">
+            <el-menu-item 
+              :index="'business-scenario-' + scene.sceneId"
+            >
+              <template #default>
+                <div style="display: flex; align-items: center; width: 100%;">
+                  <span 
+                    style="flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"
+                    @click="loadBusinessScenarioFromDB(scene)"
+                  >{{ scene.sceneName }}</span>
+                  <span 
+                    style="margin-left: 8px; font-size: 14px; cursor: pointer; color: #999;"
+                    @click.stop="showDeleteConfirm(scene)"
+                  >✕</span>
+                </div>
+              </template>
+            </el-menu-item>
+          </template>
           <el-menu-item index="business-scenario-create" @click="handleCreateScenario" class="no-active-style">
             <el-icon @click.stop="handleCreateScenario" class="square-plus-icon"><Plus /></el-icon>
             <span>创建场景</span>
@@ -309,11 +343,12 @@ import loadingBar from "../../components/loading.vue";  //加载动画
 import TyphoonVisualization from "../../components/typhoon-visualization/typhoon-visualization.vue";  //台风可视化组件
 import CesiumThreeFusion from "@/components/ThreeCesiumIntegration/CesiumThreeFusion.vue";  //Three.js与Cesium融合组件
 import ThreeModelViewer from "@/components/ThreeModelViewer/ModelViewer.vue";  //模型查看器组件
-import { CircleClose, Plus, CirclePlus, Setting } from '@element-plus/icons-vue';  //删除图标
+import { CircleClose, Plus, CirclePlus, Setting, Delete } from '@element-plus/icons-vue';  //删除图标
 import { listModel, getModel } from '@/api/watershed/model';  //模型API
 import { getDefaultMapConfig, saveMapConfig } from '@/api/cesium/mapConfig';  //地图配置API
 import serviceApi from '@/api/watershed/service';  //自定义服务API
-import { ElMessage } from 'element-plus';
+import { listBusinessScene, addBusinessScene, delBusinessScene } from '@/api/cesium/businessScene';  //业务场景API
+import { ElMessage, ElMessageBox } from 'element-plus';
 import { getToken } from '@/utils/auth'
 import axios from 'axios'
 import { onMounted, watch, computed } from 'vue'
@@ -368,6 +403,7 @@ export default {
       typhoonDataUrl: '',  //台风数据URL
       loadedTyphoonId: null,  //已加载的台风ID
       showModelDialog: false,  //是否显示模型弹框
+      businessScenes: [],  //业务场景列表(从数据库读取)
       // MVT属性弹窗相关
       mvtPopupVisible: false,  //弹窗是否可见
       mvtPopupPosition: { x: 0, y: 0 },  //弹窗位置
@@ -984,6 +1020,216 @@ export default {
       this.$emit('open-create-scenario')
     },
 
+    // 从数据库刷新业务场景列表
+    refreshBusinessScenes() {
+      console.log('从数据库加载业务场景列表...')
+      listBusinessScene({}).then(response => {
+        if (response.code === 200) {
+          this.businessScenes = response.rows || []
+          console.log('业务场景列表加载成功:', this.businessScenes)
+        } else {
+          console.error('加载业务场景列表失败:', response.msg)
+          ElMessage.error('加载业务场景列表失败')
+        }
+      }).catch(error => {
+        console.error('加载业务场景列表出错:', error)
+        ElMessage.error('加载业务场景列表出错')
+      })
+    },
+
+    // 显示删除确认对话框
+    showDeleteConfirm(scene) {
+      console.log('显示删除确认:', scene)
+      ElMessageBox.confirm(
+        '确定要删除场景 "' + scene.sceneName + '" 吗?',
+        '提示',
+        {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        }
+      ).then(() => {
+        this.handleDeleteBusinessScene(scene.sceneId)
+      }).catch(() => {
+        ElMessage.info('已取消删除')
+      })
+    },
+
+    // 删除业务场景
+    handleDeleteBusinessScene(sceneId) {
+      console.log('删除业务场景:', sceneId)
+      delBusinessScene(sceneId).then(response => {
+        if (response.code === 200) {
+          ElMessage.success('业务场景删除成功')
+          // 刷新场景列表
+          this.refreshBusinessScenes()
+        } else {
+          ElMessage.error('删除业务场景失败: ' + response.msg)
+        }
+      }).catch(error => {
+        console.error('删除业务场景出错:', error)
+        ElMessage.error('删除业务场景出错')
+      })
+    },
+
+    // 从数据库加载业务场景
+    loadBusinessScenarioFromDB(scene) {
+      console.log('从数据库加载业务场景:', scene)
+      
+      if (!window.viewer) {
+        ElMessage.error('Cesium viewer 未初始化')
+        return
+      }
+      
+      if (!window.Cesium) {
+        ElMessage.error('Cesium 库未加载')
+        return
+      }
+
+      try {
+        // 加载第三人称相机位置(视口跳转)
+        if (scene.thirdPersonCameraPos && scene.thirdPersonCameraTarget) {
+          console.log('thirdPersonCameraPos:', scene.thirdPersonCameraPos)
+          console.log('thirdPersonCameraTarget:', scene.thirdPersonCameraTarget)
+          
+          const cameraPos = JSON.parse(scene.thirdPersonCameraPos)
+          const cameraTarget = JSON.parse(scene.thirdPersonCameraTarget)
+          console.log('解析后的相机位置:', cameraPos, '类型:', Array.isArray(cameraPos))
+          console.log('解析后的目标位置:', cameraTarget, '类型:', Array.isArray(cameraTarget))
+          
+          // 检查数组长度是否正确
+          if (!Array.isArray(cameraPos) || cameraPos.length !== 3) {
+            console.error('相机位置格式不正确:', cameraPos)
+            ElMessage.error('相机位置数据格式错误')
+            return
+          }
+          
+          if (!Array.isArray(cameraTarget) || cameraTarget.length !== 3) {
+            console.error('目标位置格式不正确:', cameraTarget)
+            ElMessage.error('目标位置数据格式错误')
+            return
+          }
+          
+          // 使用 Cesium 的 flyTo 方法跳转到指定视角
+          const Cesium = window.Cesium
+          console.log('Cesium.Cartesian3:', Cesium.Cartesian3)
+          
+          const posCartesian = Cesium.Cartesian3.fromArray(cameraPos)
+          console.log('posCartesian:', posCartesian)
+          
+          const targetCartesian = Cesium.Cartesian3.fromArray(cameraTarget)
+          console.log('targetCartesian:', targetCartesian)
+          
+          if (!posCartesian || !targetCartesian) {
+            console.error('Cartesian3.fromArray 返回 undefined')
+            ElMessage.error('坐标转换失败')
+            return
+          }
+          
+          const direction = Cesium.Cartesian3.subtract(
+            posCartesian,
+            targetCartesian,
+            new Cesium.Cartesian3()
+          )
+          console.log('direction before normalize:', direction)
+          
+          Cesium.Cartesian3.normalize(direction, direction)
+          console.log('direction after normalize:', direction)
+          
+          // 优先使用方向向量和上向量精确恢复相机状态
+          if (scene.thirdPersonCameraDirection && scene.thirdPersonCameraUp) {
+            try {
+              const directionArray = JSON.parse(scene.thirdPersonCameraDirection)
+              const upArray = JSON.parse(scene.thirdPersonCameraUp)
+              
+              if (directionArray && directionArray.length === 3 && upArray && upArray.length === 3) {
+                const direction = new Cesium.Cartesian3(
+                  directionArray[0],
+                  directionArray[1],
+                  directionArray[2]
+                )
+                const up = new Cesium.Cartesian3(
+                  upArray[0],
+                  upArray[1],
+                  upArray[2]
+                )
+                
+                console.log('使用方向向量和上向量恢复相机状态')
+                console.log('方向向量:', direction)
+                console.log('上向量:', up)
+                
+                // 使用 setView 方法精确恢复相机状态
+                window.viewer.camera.setView({
+                  destination: posCartesian,
+                  orientation: {
+                    direction: direction,
+                    up: up
+                  }
+                })
+                console.log('使用方向向量和上向量恢复相机完成')
+                return  // 使用方向向量恢复后继续后续逻辑
+              }
+            } catch (e) {
+              console.error('解析方向向量或上向量失败:', e)
+            }
+          }
+          
+          // 如果没有方向向量,使用 HPR 角度(数据库中已存储为弧度值)
+          const heading = scene.thirdPersonCameraHeading || 0
+          const pitch = scene.thirdPersonCameraPitch || Cesium.Math.toRadians(-90)  // 默认俯视90度
+          const roll = scene.thirdPersonCameraRoll || 0
+          console.log('保存的相机朝向(弧度):', heading, pitch, roll)
+          console.log('保存的相机朝向(角度):', Cesium.Math.toDegrees(heading), Cesium.Math.toDegrees(pitch), Cesium.Math.toDegrees(roll))
+          
+          // 使用 setView 方法设置相机位置和朝向
+          // 注意:数据库中保存的已经是弧度值,不需要再转换
+          window.viewer.camera.setView({
+            destination: posCartesian,
+            orientation: {
+              heading: heading,
+              pitch: pitch,
+              roll: roll
+            }
+          })
+          console.log('使用HPR角度恢复相机完成')
+        }
+
+        // 加载第一人称相机设置
+        if (scene.firstPersonCameraPos && scene.firstPersonCameraTarget) {
+          const firstPersonPos = JSON.parse(scene.firstPersonCameraPos)
+          const firstPersonTarget = JSON.parse(scene.firstPersonCameraTarget)
+          // 可以根据需要应用第一人称相机设置
+          console.log('第一人称相机位置:', firstPersonPos, firstPersonTarget)
+        }
+
+        // 加载模型
+        if (scene.loadedModels) {
+          const models = JSON.parse(scene.loadedModels)
+          console.log('需要加载的模型:', models)
+          // 可以根据需要加载模型
+        }
+
+        // 加载数据服务
+        if (scene.dataServices) {
+          const services = JSON.parse(scene.dataServices)
+          console.log('需要加载的数据服务:', services)
+          // 可以根据需要加载数据服务
+        }
+
+        // 加载POI点
+        if (scene.poiPoints) {
+          const poiPoints = JSON.parse(scene.poiPoints)
+          console.log('需要加载的POI点:', poiPoints)
+          // 可以根据需要加载POI点
+        }
+
+        ElMessage.success(`已加载业务场景:${scene.sceneName}`)
+      } catch (error) {
+        console.error('加载业务场景失败:', error)
+        ElMessage.error('加载业务场景失败')
+      }
+    },
+
 
 
     // 区分地质体组件(需销毁)和其他组件
@@ -1292,6 +1538,12 @@ export default {
         return;
       }
 
+      // 检查URL是否为空
+      if (!obj.proxiedUrl || obj.proxiedUrl.trim() === '') {
+        ElMessage.warning(`${obj.name} 暂无数据`);
+        return;
+      }
+
       if (obj.state === 0) {
         // 根据数据类型选择加载方式
         if (obj.type === 'MVT') {
@@ -2491,6 +2743,8 @@ export default {
       this.fetchModels();
       // 从数据库加载自定义服务
       this.fetchCustomServices();
+      // 从数据库加载业务场景列表
+      this.refreshBusinessScenes();
     });
     
     // 延迟初始化全局点击处理器,等待 viewer 准备好
@@ -2501,6 +2755,16 @@ export default {
         this.initGlobalClickHandler();
       }
     }, 3000);
+
+    // 监听创建场景成功事件,刷新业务场景列表
+    this.refreshScenesHandler = () => {
+      this.refreshBusinessScenes()
+    }
+    document.addEventListener('refreshBusinessScenes', this.refreshScenesHandler)
+  },
+  beforeUnmount() {
+    // 移除事件监听
+    document.removeEventListener('refreshBusinessScenes', this.refreshScenesHandler)
   }
 };
 </script>
@@ -2852,6 +3116,41 @@ export default {
   background-color: transparent !important;
 }
 
+/* 基础地理实体菜单项样式 */
+.vector-data-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding-left: 50px !important;
+}
+
+.vector-data-item.is-active {
+  background-color: transparent !important;
+}
+
+.vector-data-item .vector-data-name {
+  flex: 1;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.vector-data-item .vector-data-name.vector-data-loaded {
+  color: #409eff;
+  font-weight: 500;
+}
+
+.vector-data-item .delete-vector-data-icon {
+  margin-left: 8px;
+  cursor: pointer;
+  color: #909399;
+  transition: color 0.3s;
+}
+
+.vector-data-item .delete-vector-data-icon:hover {
+  color: #f56c6c;
+}
+
 /* 模型菜单项样式 */
 .model-menu-item {
   display: flex;
@@ -3028,6 +3327,34 @@ export default {
   margin-left: 10px;
 }
 
+/* 场景名称 */
+.scene-name {
+  flex: 1;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+/* 删除图标 */
+.delete-icon {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  width: 24px;
+  height: 24px;
+  font-size: 16px;
+  margin-left: 8px;
+  cursor: pointer;
+  opacity: 0.6;
+  transition: opacity 0.2s;
+  flex-shrink: 0;
+}
+
+.delete-icon:hover {
+  opacity: 1;
+  color: #f56c6c;
+}
+
 // ########### 关键修复:折叠状态下 二级弹框保留原位置 + 三级强制弹出 ###########
 // 1. 折叠状态二级弹框:强制保留原有正确位置,不做任何改动
 :deep(.el-menu--collapse .el-sub-menu > .el-sub-menu__popper) {

+ 38 - 1
RuoYi-Vue3/src/views/front/HydrologicalPlatform.vue

@@ -29,6 +29,7 @@ import PageHeader from './PageHeader.vue'
 import layout from '@/supermap-cesium-module/views/layout/index.vue'
 import CreateScenario from '@/components/CreateScenario.vue'
 import { ElMessage } from 'element-plus'
+import { addBusinessScene } from '@/api/cesium/businessScene'
 
 // 创建业务场景弹窗相关
 const showCreateScenarioDialog = ref(false)
@@ -36,7 +37,43 @@ const showCreateScenarioDialog = ref(false)
 // 处理创建场景确认
 const handleCreateScenarioConfirm = (scenarioData) => {
   console.log('创建业务场景:', scenarioData)
-  ElMessage.success(`已创建业务场景:${scenarioData.name}`)
+  
+  // 构建保存到数据库的数据结构(CreateScenario组件已处理好数据格式)
+  const businessSceneData = {
+    sceneName: scenarioData.sceneName,
+    thirdPersonCameraPos: scenarioData.thirdPersonCameraPos,
+    thirdPersonCameraTarget: scenarioData.thirdPersonCameraTarget,
+    thirdPersonCameraHeading: scenarioData.thirdPersonCameraHeading,
+    thirdPersonCameraPitch: scenarioData.thirdPersonCameraPitch,
+    thirdPersonCameraRoll: scenarioData.thirdPersonCameraRoll,
+    // 添加方向向量和上向量字段
+    thirdPersonCameraDirection: scenarioData.thirdPersonCameraDirection,
+    thirdPersonCameraUp: scenarioData.thirdPersonCameraUp,
+    firstPersonCameraPos: JSON.stringify([0, 0, 0]),
+    firstPersonCameraTarget: JSON.stringify([0, 0, 0]),
+    firstPersonCameraHeading: 0,
+    firstPersonCameraPitch: 0,
+    firstPersonCameraRoll: 0,
+    loadedModels: JSON.stringify([]),
+    dataServices: JSON.stringify([]),
+    poiPoints: JSON.stringify([]),
+    remark: scenarioData.remark || '',
+    status: scenarioData.status || '0'
+  }
+
+  // 调用后端API保存到数据库
+  addBusinessScene(businessSceneData).then(response => {
+    if (response.code === 200) {
+      ElMessage.success(`业务场景 "${scenarioData.sceneName}" 已成功保存到数据库`)
+      // 刷新侧边栏的业务场景列表
+      document.dispatchEvent(new Event('refreshBusinessScenes'))
+    } else {
+      ElMessage.error('保存业务场景失败: ' + response.msg)
+    }
+  }).catch(error => {
+    console.error('保存业务场景出错:', error)
+    ElMessage.error('保存业务场景出错')
+  })
 }
 </script>
 

+ 320 - 0
RuoYi-Vue3/src/views/system/businessScene/index.vue

@@ -0,0 +1,320 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="场景名称" prop="sceneName">
+        <el-input
+          v-model="queryParams.sceneName"
+          placeholder="请输入场景名称"
+          clearable
+          style="width: 240px"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="场景状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="场景状态" clearable style="width: 240px">
+          <el-option label="正常" value="0" />
+          <el-option label="维护中" value="1" />
+          <el-option label="已删除" value="2" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['system:businessScene:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:businessScene:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:businessScene:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+          v-hasPermi="['system:businessScene:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="businessSceneList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="场景ID" align="center" prop="sceneId" />
+      <el-table-column label="场景名称" align="center" prop="sceneName" :show-overflow-tooltip="true" />
+      <el-table-column label="场景状态" align="center" prop="status">
+        <template #default="scope">
+          <el-tag :type="scope.row.status === '0' ? 'success' : scope.row.status === '1' ? 'warning' : 'danger'">
+            {{ scope.row.status === '0' ? '正常' : scope.row.status === '1' ? '维护中' : '已删除' }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:businessScene:edit']" >修改</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:businessScene:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改业务场景对话框 -->
+    <el-dialog :title="title" v-model="open" width="600px" append-to-body>
+      <el-form ref="businessSceneRef" :model="form" :rules="rules" label-width="120px">
+        <el-form-item label="场景名称" prop="sceneName">
+          <el-input v-model="form.sceneName" placeholder="请输入场景名称" />
+        </el-form-item>
+        
+        <el-divider content-position="left">第三视角相机设置</el-divider>
+        <el-form-item label="相机位置" prop="thirdPersonCameraPos">
+          <el-input v-model="form.thirdPersonCameraPos" placeholder='{"x":0,"y":0,"z":0}' />
+        </el-form-item>
+        <el-form-item label="目标位置" prop="thirdPersonCameraTarget">
+          <el-input v-model="form.thirdPersonCameraTarget" placeholder='{"x":0,"y":0,"z":0}' />
+        </el-form-item>
+        <el-form-item label="朝向角(弧度)" prop="thirdPersonCameraHeading">
+          <el-input v-model="form.thirdPersonCameraHeading" type="number" step="0.01" placeholder="0.0" />
+        </el-form-item>
+        <el-form-item label="俯仰角(弧度)" prop="thirdPersonCameraPitch">
+          <el-input v-model="form.thirdPersonCameraPitch" type="number" step="0.01" placeholder="0.0" />
+        </el-form-item>
+        <el-form-item label="翻滚角(弧度)" prop="thirdPersonCameraRoll">
+          <el-input v-model="form.thirdPersonCameraRoll" type="number" step="0.01" placeholder="0.0" />
+        </el-form-item>
+        
+        <el-divider content-position="left">第一人称相机设置</el-divider>
+        <el-form-item label="相机位置" prop="firstPersonCameraPos">
+          <el-input v-model="form.firstPersonCameraPos" placeholder='{"x":0,"y":0,"z":0}' />
+        </el-form-item>
+        <el-form-item label="目标位置" prop="firstPersonCameraTarget">
+          <el-input v-model="form.firstPersonCameraTarget" placeholder='{"x":0,"y":0,"z":0}' />
+        </el-form-item>
+        <el-form-item label="朝向角(弧度)" prop="firstPersonCameraHeading">
+          <el-input v-model="form.firstPersonCameraHeading" type="number" step="0.01" placeholder="0.0" />
+        </el-form-item>
+        <el-form-item label="俯仰角(弧度)" prop="firstPersonCameraPitch">
+          <el-input v-model="form.firstPersonCameraPitch" type="number" step="0.01" placeholder="0.0" />
+        </el-form-item>
+        <el-form-item label="翻滚角(弧度)" prop="firstPersonCameraRoll">
+          <el-input v-model="form.firstPersonCameraRoll" type="number" step="0.01" placeholder="0.0" />
+        </el-form-item>
+        
+        <el-divider content-position="left">场景内容</el-divider>
+        <el-form-item label="加载模型" prop="loadedModels">
+          <el-input v-model="form.loadedModels" type="textarea" :rows="3" placeholder='[{"id":"","name":"","path":""}]' />
+        </el-form-item>
+        <el-form-item label="数据服务" prop="dataServices">
+          <el-input v-model="form.dataServices" type="textarea" :rows="3" placeholder='[{"id":"","name":"","url":""}]' />
+        </el-form-item>
+        <el-form-item label="POI点" prop="poiPoints">
+          <el-input v-model="form.poiPoints" type="textarea" :rows="3" placeholder='[{"id":"","name":"","position":{},"icon":""}]' />
+        </el-form-item>
+        
+        <el-form-item label="场景状态" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio label="0">正常</el-radio>
+            <el-radio label="1">维护中</el-radio>
+            <el-radio label="2">已删除</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="BusinessScene">
+import { listBusinessScene, getBusinessScene, delBusinessScene, addBusinessScene, updateBusinessScene } from "@/api/cesium/businessScene"
+
+const { proxy } = getCurrentInstance()
+
+const businessSceneList = ref([])
+const open = ref(false)
+const loading = ref(true)
+const showSearch = ref(true)
+const ids = ref([])
+const single = ref(true)
+const multiple = ref(true)
+const total = ref(0)
+const title = ref("")
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    sceneName: undefined,
+    status: undefined
+  },
+  rules: {
+    sceneName: [{ required: true, message: "场景名称不能为空", trigger: "blur" }]
+  }
+})
+
+const { queryParams, form, rules } = toRefs(data)
+
+/** 查询业务场景列表 */
+function getList() {
+  loading.value = true
+  listBusinessScene(queryParams.value).then(response => {
+    businessSceneList.value = response.rows
+    total.value = response.total
+    loading.value = false
+  })
+}
+
+/** 取消按钮 */
+function cancel() {
+  open.value = false
+  reset()
+}
+
+/** 表单重置 */
+function reset() {
+  form.value = {
+    sceneId: undefined,
+    sceneName: undefined,
+    thirdPersonCameraPos: undefined,
+    thirdPersonCameraTarget: undefined,
+    thirdPersonCameraHeading: undefined,
+    thirdPersonCameraPitch: undefined,
+    thirdPersonCameraRoll: undefined,
+    firstPersonCameraPos: undefined,
+    firstPersonCameraTarget: undefined,
+    firstPersonCameraHeading: undefined,
+    firstPersonCameraPitch: undefined,
+    firstPersonCameraRoll: undefined,
+    loadedModels: undefined,
+    dataServices: undefined,
+    poiPoints: undefined,
+    status: "0",
+    remark: undefined
+  }
+  proxy.resetForm("businessSceneRef")
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  queryParams.value.pageNum = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+  proxy.resetForm("queryRef")
+  handleQuery()
+}
+
+/** 多选框选中数据 */
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.sceneId)
+  single.value = selection.length != 1
+  multiple.value = !selection.length
+}
+
+/** 新增按钮操作 */
+function handleAdd() {
+  reset()
+  open.value = true
+  title.value = "新增业务场景"
+}
+
+/** 修改按钮操作 */
+function handleUpdate(row) {
+  reset()
+  const sceneId = row.sceneId || ids.value
+  getBusinessScene(sceneId).then(response => {
+    form.value = response.data
+    open.value = true
+    title.value = "修改业务场景"
+  })
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.$refs["businessSceneRef"].validate(valid => {
+    if (valid) {
+      if (form.value.sceneId != undefined) {
+        updateBusinessScene(form.value).then(response => {
+          proxy.$modal.msgSuccess("修改成功")
+          open.value = false
+          getList()
+        })
+      } else {
+        addBusinessScene(form.value).then(response => {
+          proxy.$modal.msgSuccess("新增成功")
+          open.value = false
+          getList()
+        })
+      }
+    }
+  })
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  const sceneIds = row.sceneId || ids.value
+  proxy.$modal.confirm('是否确认删除场景ID为"' + sceneIds + '"的数据项?').then(function () {
+    return delBusinessScene(sceneIds)
+  }).then(() => {
+    getList()
+    proxy.$modal.msgSuccess("删除成功")
+  }).catch(() => {})
+}
+
+/** 导出按钮操作 */
+function handleExport() {
+  proxy.download("system/businessScene/export", {
+    ...queryParams.value
+  }, `business_scene_${new Date().getTime()}.xlsx`)
+}
+
+getList()
+</script>

BIN
ruoyi-admin/db-tools/AddCameraOrientationColumns.class


+ 47 - 0
ruoyi-admin/db-tools/AddCameraOrientationColumns.java

@@ -0,0 +1,47 @@
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+public class AddCameraOrientationColumns {
+    public static void main(String[] args) {
+        String url = "jdbc:dm://192.168.0.145:30236?charSet=utf8";
+        String username = "WATERSHED";
+        String password = "WaterShed./1224";
+
+        try (Connection conn = DriverManager.getConnection(url, username, password);
+             Statement stmt = conn.createStatement()) {
+
+            // 添加第三人称相机朝向字段
+            String addHeadingSql = "ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_HEADING DECIMAL(10,6)";
+            String addPitchSql = "ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_PITCH DECIMAL(10,6)";
+            String addRollSql = "ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_ROLL DECIMAL(10,6)";
+
+            try {
+                stmt.execute(addHeadingSql);
+                System.out.println("成功添加 THIRD_PERSON_CAMERA_HEADING 字段");
+            } catch (SQLException e) {
+                System.out.println("THIRD_PERSON_CAMERA_HEADING 字段已存在,跳过");
+            }
+
+            try {
+                stmt.execute(addPitchSql);
+                System.out.println("成功添加 THIRD_PERSON_CAMERA_PITCH 字段");
+            } catch (SQLException e) {
+                System.out.println("THIRD_PERSON_CAMERA_PITCH 字段已存在,跳过");
+            }
+
+            try {
+                stmt.execute(addRollSql);
+                System.out.println("成功添加 THIRD_PERSON_CAMERA_ROLL 字段");
+            } catch (SQLException e) {
+                System.out.println("THIRD_PERSON_CAMERA_ROLL 字段已存在,跳过");
+            }
+
+            System.out.println("所有字段添加完成!");
+
+        } catch (SQLException e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 67 - 0
ruoyi-admin/db-tools/AddMissingColumns.java

@@ -0,0 +1,67 @@
+import java.sql.*;
+
+public class AddMissingColumns {
+    public static void main(String[] args) {
+        String url = "jdbc:dm://192.168.0.145:30236?charset=utf8";
+        String username = "WATERSHED";
+        String password = "WaterShed./1224";
+        
+        Connection conn = null;
+        Statement stmt = null;
+        
+        try {
+            Class.forName("dm.jdbc.driver.DmDriver");
+            conn = DriverManager.getConnection(url, username, password);
+            stmt = conn.createStatement();
+            
+            // 添加第三视角相机朝向字段
+            String[] addColumnSqls = {
+                "ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_HEADING DECIMAL(10,6)",
+                "ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_PITCH DECIMAL(10,6)",
+                "ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_ROLL DECIMAL(10,6)",
+                "ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_DIRECTION VARCHAR(200)",
+                "ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_UP VARCHAR(200)"
+            };
+            
+            for (String sql : addColumnSqls) {
+                try {
+                    stmt.execute(sql);
+                    System.out.println("成功执行: " + sql);
+                } catch (SQLException e) {
+                    System.out.println("执行失败(可能已存在): " + sql);
+                    System.out.println("错误信息: " + e.getMessage());
+                }
+            }
+            
+            // 添加字段注释
+            String[] columnComments = {
+                "COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_HEADING IS '第三视角相机朝向角(弧度)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_PITCH IS '第三视角相机俯仰角(弧度)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_ROLL IS '第三视角相机翻滚角(弧度)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_DIRECTION IS '第三视角相机方向向量(JSON格式)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_UP IS '第三视角相机上向量(JSON格式)'"
+            };
+            
+            for (String comment : columnComments) {
+                try {
+                    stmt.execute(comment);
+                    System.out.println("成功添加注释: " + comment);
+                } catch (SQLException e) {
+                    System.out.println("添加注释失败: " + comment);
+                }
+            }
+            
+            System.out.println("所有字段添加完成!");
+            
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (stmt != null) stmt.close();
+                if (conn != null) conn.close();
+            } catch (SQLException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}

BIN
ruoyi-admin/db-tools/CheckData.class


+ 45 - 0
ruoyi-admin/db-tools/CheckData.java

@@ -0,0 +1,45 @@
+import java.sql.*;
+
+public class CheckData {
+    public static void main(String[] args) {
+        String url = "jdbc:dm://192.168.0.145:30236?charset=utf8";
+        String username = "WATERSHED";
+        String password = "WaterShed./1224";
+        
+        Connection conn = null;
+        Statement stmt = null;
+        ResultSet rs = null;
+        
+        try {
+            Class.forName("dm.jdbc.driver.DmDriver");
+            conn = DriverManager.getConnection(url, username, password);
+            stmt = conn.createStatement();
+            
+            System.out.println("Connected to database successfully!");
+            
+            String sql = "SELECT SCENE_ID, SCENE_NAME, THIRD_PERSON_CAMERA_HEADING, THIRD_PERSON_CAMERA_PITCH, THIRD_PERSON_CAMERA_ROLL, THIRD_PERSON_CAMERA_DIRECTION, THIRD_PERSON_CAMERA_UP FROM BUSINESS_SCENE ORDER BY SCENE_ID DESC";
+            rs = stmt.executeQuery(sql);
+            
+            while (rs.next()) {
+                System.out.println("\n=== Scene ID: " + rs.getLong("SCENE_ID") + " ===");
+                System.out.println("Scene Name: " + rs.getString("SCENE_NAME"));
+                System.out.println("Heading: " + rs.getDouble("THIRD_PERSON_CAMERA_HEADING"));
+                System.out.println("Pitch: " + rs.getDouble("THIRD_PERSON_CAMERA_PITCH"));
+                System.out.println("Roll: " + rs.getDouble("THIRD_PERSON_CAMERA_ROLL"));
+                System.out.println("Direction: " + rs.getString("THIRD_PERSON_CAMERA_DIRECTION"));
+                System.out.println("Up: " + rs.getString("THIRD_PERSON_CAMERA_UP"));
+            }
+            
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (rs != null) rs.close();
+                if (stmt != null) stmt.close();
+                if (conn != null) conn.close();
+            } catch (SQLException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}

BIN
ruoyi-admin/db-tools/CreateBusinessSceneTable.class


+ 100 - 0
ruoyi-admin/db-tools/CreateBusinessSceneTable.java

@@ -0,0 +1,100 @@
+import java.sql.*;
+
+public class CreateBusinessSceneTable {
+    public static void main(String[] args) {
+        String url = "jdbc:dm://192.168.0.145:30236?charset=utf8";
+        String username = "WATERSHED";
+        String password = "WaterShed./1224";
+        
+        Connection conn = null;
+        Statement stmt = null;
+        
+        try {
+            Class.forName("dm.jdbc.driver.DmDriver");
+            conn = DriverManager.getConnection(url, username, password);
+            stmt = conn.createStatement();
+            
+            String dropSql = "DROP TABLE IF EXISTS BUSINESS_SCENE";
+            stmt.execute(dropSql);
+            System.out.println("已删除旧表(如果存在)");
+            
+            String createSql = "CREATE TABLE BUSINESS_SCENE (" +
+                "SCENE_ID BIGINT NOT NULL IDENTITY(1,1), " +
+                "SCENE_NAME VARCHAR(100) NOT NULL, " +
+                "THIRD_PERSON_CAMERA_POS VARCHAR(200), " +
+                "THIRD_PERSON_CAMERA_TARGET VARCHAR(200), " +
+                "THIRD_PERSON_CAMERA_HEADING DECIMAL(10,6), " +
+                "THIRD_PERSON_CAMERA_PITCH DECIMAL(10,6), " +
+                "THIRD_PERSON_CAMERA_ROLL DECIMAL(10,6), " +
+                "THIRD_PERSON_CAMERA_DIRECTION VARCHAR(200), " +
+                "THIRD_PERSON_CAMERA_UP VARCHAR(200), " +
+                "FIRST_PERSON_CAMERA_POS VARCHAR(200), " +
+                "FIRST_PERSON_CAMERA_TARGET VARCHAR(200), " +
+                "FIRST_PERSON_CAMERA_HEADING DECIMAL(10,6), " +
+                "FIRST_PERSON_CAMERA_PITCH DECIMAL(10,6), " +
+                "FIRST_PERSON_CAMERA_ROLL DECIMAL(10,6), " +
+                "LOADED_MODELS CLOB, " +
+                "DATA_SERVICES CLOB, " +
+                "POI_POINTS CLOB, " +
+                "STATUS CHAR(1) NOT NULL DEFAULT '0', " +
+                "CREATE_BY VARCHAR(64) DEFAULT '', " +
+                "CREATE_TIME DATETIME, " +
+                "UPDATE_BY VARCHAR(64) DEFAULT '', " +
+                "UPDATE_TIME DATETIME, " +
+                "REMARK VARCHAR(500) DEFAULT NULL, " +
+                "PRIMARY KEY (SCENE_ID)" +
+                ")";
+            
+            stmt.execute(createSql);
+            System.out.println("表 BUSINESS_SCENE 创建成功!");
+            
+            String constraintSql = "ALTER TABLE BUSINESS_SCENE ADD CONSTRAINT business_scene_check_1 CHECK (STATUS IN ('0','1','2'))";
+            stmt.execute(constraintSql);
+            System.out.println("约束 business_scene_check_1 添加成功!");
+            
+            String tableComment = "COMMENT ON TABLE BUSINESS_SCENE IS '业务场景表'";
+            stmt.execute(tableComment);
+            
+            String[] columnComments = {
+                "COMMENT ON COLUMN BUSINESS_SCENE.SCENE_ID IS '场景ID'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.SCENE_NAME IS '场景名称'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_POS IS '第三视角相机位置(JSON格式)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_TARGET IS '第三视角相机目标位置(JSON格式)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_HEADING IS '第三视角相机朝向角(弧度)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_PITCH IS '第三视角相机俯仰角(弧度)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_ROLL IS '第三视角相机翻滚角(弧度)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_DIRECTION IS '第三视角相机方向向量(JSON格式)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_UP IS '第三视角相机上向量(JSON格式)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.FIRST_PERSON_CAMERA_POS IS '第一人称相机位置(JSON格式)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.FIRST_PERSON_CAMERA_TARGET IS '第一人称相机目标位置(JSON格式)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.FIRST_PERSON_CAMERA_HEADING IS '第一人称相机朝向角(弧度)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.FIRST_PERSON_CAMERA_PITCH IS '第一人称相机俯仰角(弧度)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.FIRST_PERSON_CAMERA_ROLL IS '第一人称相机翻滚角(弧度)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.LOADED_MODELS IS '场景中加载的模型列表(JSON数组)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.DATA_SERVICES IS '场景关联的数据服务列表(JSON数组)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.POI_POINTS IS 'POI点列表(JSON数组)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.STATUS IS '场景状态(0正常 1维护中 2已删除)'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.CREATE_BY IS '创建者'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.CREATE_TIME IS '创建时间'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.UPDATE_BY IS '更新者'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.UPDATE_TIME IS '更新时间'",
+                "COMMENT ON COLUMN BUSINESS_SCENE.REMARK IS '备注'"
+            };
+            
+            for (String comment : columnComments) {
+                stmt.execute(comment);
+            }
+            System.out.println("表注释和列注释添加成功!");
+            
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (stmt != null) stmt.close();
+                if (conn != null) conn.close();
+            } catch (SQLException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}

BIN
ruoyi-admin/db-tools/ExecuteAddColumns.class


+ 51 - 0
ruoyi-admin/db-tools/ExecuteAddColumns.java

@@ -0,0 +1,51 @@
+import java.sql.*;
+
+public class ExecuteAddColumns {
+    public static void main(String[] args) {
+        String url = "jdbc:dm://192.168.0.145:30236?charset=utf8";
+        String username = "WATERSHED";
+        String password = "WaterShed./1224";
+        
+        Connection conn = null;
+        Statement stmt = null;
+        
+        try {
+            Class.forName("dm.jdbc.driver.DmDriver");
+            conn = DriverManager.getConnection(url, username, password);
+            stmt = conn.createStatement();
+            
+            System.out.println("Connected to database successfully!");
+            
+            // 添加字段
+            String[] addColumnSqls = {
+                "ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_HEADING DECIMAL(10,6)",
+                "ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_PITCH DECIMAL(10,6)",
+                "ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_ROLL DECIMAL(10,6)",
+                "ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_DIRECTION VARCHAR(200)",
+                "ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_UP VARCHAR(200)"
+            };
+            
+            for (String sql : addColumnSqls) {
+                try {
+                    stmt.execute(sql);
+                    System.out.println("Success: " + sql);
+                } catch (SQLException e) {
+                    System.out.println("Skip (may already exist): " + sql);
+                    System.out.println("Error: " + e.getMessage());
+                }
+            }
+            
+            System.out.println("\nAll columns added successfully!");
+            
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (stmt != null) stmt.close();
+                if (conn != null) conn.close();
+            } catch (SQLException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}

BIN
ruoyi-admin/db-tools/ExecuteBusinessSceneMenuScript.class


+ 76 - 0
ruoyi-admin/db-tools/ExecuteBusinessSceneMenuScript.java

@@ -0,0 +1,76 @@
+import java.sql.*;
+
+public class ExecuteBusinessSceneMenuScript {
+    public static void main(String[] args) {
+        String url = "jdbc:dm://192.168.0.145:30236?charset=utf8";
+        String username = "WATERSHED";
+        String password = "WaterShed./1224";
+        
+        Connection conn = null;
+        Statement stmt = null;
+        
+        try {
+            Class.forName("dm.jdbc.driver.DmDriver");
+            conn = DriverManager.getConnection(url, username, password);
+            stmt = conn.createStatement();
+            
+            // 1. 添加业务场景管理子菜单
+            String menuSql = "INSERT INTO sys_menu VALUES (2027, '业务场景', 1, 10, 'businessScene', 'system/businessScene/index', '', 1, 0, 'C', '0', '0', 'system:businessScene:list', 'scene', 'admin', sysdate, '', NULL, '业务场景管理菜单')";
+            executeSql(stmt, menuSql, "业务场景管理菜单");
+            
+            // 2. 添加按钮权限
+            String[] buttonSqls = {
+                "INSERT INTO sys_menu VALUES (2028, '业务场景查询', 2027, 1, '', '', '', 1, 0, 'F', '0', '0', 'system:businessScene:query', '#', 'admin', sysdate, '', NULL, '')",
+                "INSERT INTO sys_menu VALUES (2029, '业务场景新增', 2027, 2, '', '', '', 1, 0, 'F', '0', '0', 'system:businessScene:add', '#', 'admin', sysdate, '', NULL, '')",
+                "INSERT INTO sys_menu VALUES (2030, '业务场景修改', 2027, 3, '', '', '', 1, 0, 'F', '0', '0', 'system:businessScene:edit', '#', 'admin', sysdate, '', NULL, '')",
+                "INSERT INTO sys_menu VALUES (2031, '业务场景删除', 2027, 4, '', '', '', 1, 0, 'F', '0', '0', 'system:businessScene:remove', '#', 'admin', sysdate, '', NULL, '')",
+                "INSERT INTO sys_menu VALUES (2032, '业务场景导出', 2027, 5, '', '', '', 1, 0, 'F', '0', '0', 'system:businessScene:export', '#', 'admin', sysdate, '', NULL, '')"
+            };
+            
+            String[] buttonNames = {"查询", "新增", "修改", "删除", "导出"};
+            for (int i = 0; i < buttonSqls.length; i++) {
+                executeSql(stmt, buttonSqls[i], "业务场景" + buttonNames[i] + "按钮");
+            }
+            
+            // 3. 给管理员角色分配权限
+            String[] roleMenuSqls = {
+                "INSERT INTO sys_role_menu VALUES (1, 2027)",
+                "INSERT INTO sys_role_menu VALUES (1, 2028)",
+                "INSERT INTO sys_role_menu VALUES (1, 2029)",
+                "INSERT INTO sys_role_menu VALUES (1, 2030)",
+                "INSERT INTO sys_role_menu VALUES (1, 2031)",
+                "INSERT INTO sys_role_menu VALUES (1, 2032)"
+            };
+            
+            executeSql(stmt, roleMenuSqls[0], "管理员角色分配业务场景菜单权限");
+            for (int i = 1; i < roleMenuSqls.length; i++) {
+                executeSql(stmt, roleMenuSqls[i], "管理员角色分配业务场景" + buttonNames[i-1] + "权限");
+            }
+            
+            System.out.println("\n业务场景管理菜单配置完成!");
+            
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (stmt != null) stmt.close();
+                if (conn != null) conn.close();
+            } catch (SQLException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+    
+    private static void executeSql(Statement stmt, String sql, String desc) {
+        try {
+            stmt.execute(sql);
+            System.out.println(desc + " - 成功");
+        } catch (SQLException e) {
+            if (e.getErrorCode() == -2626) {
+                System.out.println(desc + " - 已存在,跳过");
+            } else {
+                System.out.println(desc + " - 失败: " + e.getMessage());
+            }
+        }
+    }
+}

BIN
ruoyi-admin/db-tools/InsertMenuForBusinessScene.class


+ 98 - 0
ruoyi-admin/db-tools/InsertMenuForBusinessScene.java

@@ -0,0 +1,98 @@
+import java.sql.*;
+
+public class InsertMenuForBusinessScene {
+    public static void main(String[] args) {
+        String url = "jdbc:dm://192.168.0.145:30236?charset=utf8";
+        String username = "WATERSHED";
+        String password = "WaterShed./1224";
+        
+        Connection conn = null;
+        
+        try {
+            Class.forName("dm.jdbc.driver.DmDriver");
+            conn = DriverManager.getConnection(url, username, password);
+            
+            // 1. 添加业务场景管理子菜单
+            String menuSql = "INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) " +
+                            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, sysdate, ?, ?, ?)";
+            
+            // 业务场景管理菜单
+            insertMenu(conn, menuSql, 2027, "业务场景", 1, 10, "businessScene", "system/businessScene/index", "", 1, 0, "C", "0", "0", "system:businessScene:list", "scene", "admin", "", null, "业务场景管理菜单");
+            
+            // 按钮权限
+            insertMenu(conn, menuSql, 2028, "业务场景查询", 2027, 1, "", "", "", 1, 0, "F", "0", "0", "system:businessScene:query", "#", "admin", "", null, "");
+            insertMenu(conn, menuSql, 2029, "业务场景新增", 2027, 2, "", "", "", 1, 0, "F", "0", "0", "system:businessScene:add", "#", "admin", "", null, "");
+            insertMenu(conn, menuSql, 2030, "业务场景修改", 2027, 3, "", "", "", 1, 0, "F", "0", "0", "system:businessScene:edit", "#", "admin", "", null, "");
+            insertMenu(conn, menuSql, 2031, "业务场景删除", 2027, 4, "", "", "", 1, 0, "F", "0", "0", "system:businessScene:remove", "#", "admin", "", null, "");
+            insertMenu(conn, menuSql, 2032, "业务场景导出", 2027, 5, "", "", "", 1, 0, "F", "0", "0", "system:businessScene:export", "#", "admin", "", null, "");
+            
+            // 2. 给管理员角色分配权限
+            String roleMenuSql = "INSERT INTO sys_role_menu (role_id, menu_id) VALUES (?, ?)";
+            int[] menuIds = {2027, 2028, 2029, 2030, 2031, 2032};
+            for (int menuId : menuIds) {
+                insertRoleMenu(conn, roleMenuSql, 1, menuId);
+            }
+            
+            System.out.println("\n业务场景管理菜单配置完成!");
+            
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (conn != null) conn.close();
+            } catch (SQLException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+    
+    private static void insertMenu(Connection conn, String sql, int menuId, String menuName, int parentId, int orderNum,
+                                   String path, String component, String query, int isFrame, int isCache,
+                                   String menuType, String visible, String status, String perms, String icon,
+                                   String createBy, String updateBy, String updateTime, String remark) {
+        try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
+            pstmt.setInt(1, menuId);
+            pstmt.setString(2, menuName);
+            pstmt.setInt(3, parentId);
+            pstmt.setInt(4, orderNum);
+            pstmt.setString(5, path);
+            pstmt.setString(6, component);
+            pstmt.setString(7, query);
+            pstmt.setInt(8, isFrame);
+            pstmt.setInt(9, isCache);
+            pstmt.setString(10, menuType);
+            pstmt.setString(11, visible);
+            pstmt.setString(12, status);
+            pstmt.setString(13, perms);
+            pstmt.setString(14, icon);
+            pstmt.setString(15, createBy);
+            pstmt.setString(16, updateBy);
+            pstmt.setString(17, updateTime);
+            pstmt.setString(18, remark);
+            
+            pstmt.executeUpdate();
+            System.out.println("菜单[" + menuName + "] - 成功");
+        } catch (SQLException e) {
+            if (e.getErrorCode() == -2626) {
+                System.out.println("菜单[" + menuName + "] - 已存在,跳过");
+            } else {
+                System.out.println("菜单[" + menuName + "] - 失败: " + e.getMessage());
+            }
+        }
+    }
+    
+    private static void insertRoleMenu(Connection conn, String sql, int roleId, int menuId) {
+        try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
+            pstmt.setInt(1, roleId);
+            pstmt.setInt(2, menuId);
+            pstmt.executeUpdate();
+            System.out.println("角色权限(role=" + roleId + ", menu=" + menuId + ") - 成功");
+        } catch (SQLException e) {
+            if (e.getErrorCode() == -2626) {
+                System.out.println("角色权限(role=" + roleId + ", menu=" + menuId + ") - 已存在,跳过");
+            } else {
+                System.out.println("角色权限(role=" + roleId + ", menu=" + menuId + ") - 失败: " + e.getMessage());
+            }
+        }
+    }
+}

+ 49 - 0
ruoyi-admin/db-tools/TestApi.java

@@ -0,0 +1,49 @@
+import java.io.*;
+import java.net.*;
+
+public class TestApi {
+    public static void main(String[] args) {
+        try {
+            URL url = new URL("http://localhost:8448/system/businessScene");
+            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+            conn.setRequestMethod("POST");
+            conn.setRequestProperty("Content-Type", "application/json");
+            conn.setRequestProperty("Authorization", "Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImNyZWF0ZWQiOjE3MTg1NDkzODAxNzYsImV4cCI6MTcxODU1Mjk4MH0.SP8Jv6X8n4YJ6K5YJ6K5YJ6K5YJ6K5YJ6K5YJ6K5YJ6K5YJ6K5YJ6K5YJ6K5YJ6K5YJ6K5YJ6K5Y");
+            conn.setDoOutput(true);
+            
+            String jsonInputString = "{" +
+                "\"sceneName\": \"TestScene\"," +
+                "\"thirdPersonCameraPos\": \"[-2794881.16,5012908.69,2782554.46]\"," +
+                "\"thirdPersonCameraTarget\": \"[-2794881.16,5012908.69,0]\"," +
+                "\"thirdPersonCameraHeading\": 0.8474376369888388," +
+                "\"thirdPersonCameraPitch\": -0.47481682300505734," +
+                "\"thirdPersonCameraRoll\": 6.2831853071795845," +
+                "\"thirdPersonCameraDirection\": \"[-0.25689388313349093,-0.9082555319630337,0.3302687110023337]\"," +
+                "\"thirdPersonCameraUp\": \"[-0.6247398838094573,0.4168025198968015,0.660284587875124]\"," +
+                "\"status\": \"0\"," +
+                "\"remark\": \"Test\"" +
+            "}";
+            
+            try (OutputStream os = conn.getOutputStream()) {
+                byte[] input = jsonInputString.getBytes("utf-8");
+                os.write(input, 0, input.length);
+            }
+            
+            int code = conn.getResponseCode();
+            System.out.println("Response code: " + code);
+            
+            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
+            StringBuilder response = new StringBuilder();
+            String responseLine = null;
+            while ((responseLine = br.readLine()) != null) {
+                response.append(responseLine.trim());
+            }
+            System.out.println("Response body: " + response.toString());
+            
+            conn.disconnect();
+            
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 15 - 0
ruoyi-admin/db-tools/add_columns.sql

@@ -0,0 +1,15 @@
+-- 为 BUSINESS_SCENE 表添加缺失的第三人称相机朝向字段
+ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_HEADING DECIMAL(10,6);
+ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_PITCH DECIMAL(10,6);
+ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_ROLL DECIMAL(10,6);
+ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_DIRECTION VARCHAR(200);
+ALTER TABLE BUSINESS_SCENE ADD COLUMN THIRD_PERSON_CAMERA_UP VARCHAR(200);
+
+-- 添加字段注释
+COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_HEADING IS '第三视角相机朝向角(弧度)';
+COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_PITCH IS '第三视角相机俯仰角(弧度)';
+COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_ROLL IS '第三视角相机翻滚角(弧度)';
+COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_DIRECTION IS '第三视角相机方向向量(JSON格式)';
+COMMENT ON COLUMN BUSINESS_SCENE.THIRD_PERSON_CAMERA_UP IS '第三视角相机上向量(JSON格式)';
+
+SELECT '所有字段添加完成' AS result;

+ 112 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/BusinessSceneController.java

@@ -0,0 +1,112 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.system.domain.BusinessScene;
+import com.ruoyi.system.service.IBusinessSceneService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 业务场景Controller
+ * 
+ * @author ruoyi
+ * @date 2026-06-16
+ */
+@RestController
+@RequestMapping("/system/businessScene")
+public class BusinessSceneController extends BaseController
+{
+    @Autowired
+    private IBusinessSceneService businessSceneService;
+
+    /**
+     * 查询业务场景列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:businessScene:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(BusinessScene businessScene)
+    {
+        startPage();
+        List<BusinessScene> list = businessSceneService.selectBusinessSceneList(businessScene);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出业务场景列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:businessScene:export')")
+    @Log(title = "业务场景", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(BusinessScene businessScene)
+    {
+        List<BusinessScene> list = businessSceneService.selectBusinessSceneList(businessScene);
+        ExcelUtil<BusinessScene> util = new ExcelUtil<BusinessScene>(BusinessScene.class);
+        return util.exportExcel(list, "业务场景数据");
+    }
+
+    /**
+     * 获取业务场景详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:businessScene:query')")
+    @GetMapping(value = "/{sceneId}")
+    public AjaxResult getInfo(@PathVariable("sceneId") Long sceneId)
+    {
+        return AjaxResult.success(businessSceneService.selectBusinessSceneById(sceneId));
+    }
+
+    /**
+     * 新增业务场景
+     */
+    @PreAuthorize("@ss.hasPermi('system:businessScene:add')")
+    @Log(title = "业务场景", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody BusinessScene businessScene)
+    {
+        System.out.println("=== Received BusinessScene data ===");
+        System.out.println("SceneName: " + businessScene.getSceneName());
+        System.out.println("thirdPersonCameraPos: " + businessScene.getThirdPersonCameraPos());
+        System.out.println("thirdPersonCameraTarget: " + businessScene.getThirdPersonCameraTarget());
+        System.out.println("thirdPersonCameraHeading: " + businessScene.getThirdPersonCameraHeading());
+        System.out.println("thirdPersonCameraPitch: " + businessScene.getThirdPersonCameraPitch());
+        System.out.println("thirdPersonCameraRoll: " + businessScene.getThirdPersonCameraRoll());
+        System.out.println("thirdPersonCameraDirection: " + businessScene.getThirdPersonCameraDirection());
+        System.out.println("thirdPersonCameraUp: " + businessScene.getThirdPersonCameraUp());
+        return toAjax(businessSceneService.insertBusinessScene(businessScene));
+    }
+
+    /**
+     * 修改业务场景
+     */
+    @PreAuthorize("@ss.hasPermi('system:businessScene:edit')")
+    @Log(title = "业务场景", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody BusinessScene businessScene)
+    {
+        return toAjax(businessSceneService.updateBusinessScene(businessScene));
+    }
+
+    /**
+     * 删除业务场景
+     */
+    @PreAuthorize("@ss.hasPermi('system:businessScene:remove')")
+    @Log(title = "业务场景", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{sceneIds}")
+    public AjaxResult remove(@PathVariable Long[] sceneIds)
+    {
+        return toAjax(businessSceneService.deleteBusinessSceneByIds(sceneIds));
+    }
+}

+ 53 - 0
ruoyi-admin/src/main/resources/sql/business_scene.sql

@@ -0,0 +1,53 @@
+-- ----------------------------
+-- Table structure for BUSINESS_SCENE
+-- ----------------------------
+DROP TABLE IF EXISTS "BUSINESS_SCENE";
+CREATE TABLE "BUSINESS_SCENE" (
+  "SCENE_ID" BIGINT NOT NULL IDENTITY(1,1),
+  "SCENE_NAME" VARCHAR(100) NOT NULL,
+  "THIRD_PERSON_CAMERA_POS" VARCHAR(200),
+  "THIRD_PERSON_CAMERA_TARGET" VARCHAR(200),
+  "FIRST_PERSON_CAMERA_POS" VARCHAR(200),
+  "FIRST_PERSON_CAMERA_TARGET" VARCHAR(200),
+  "FIRST_PERSON_CAMERA_HEADING" DECIMAL(10,6),
+  "FIRST_PERSON_CAMERA_PITCH" DECIMAL(10,6),
+  "FIRST_PERSON_CAMERA_ROLL" DECIMAL(10,6),
+  "LOADED_MODELS" CLOB,
+  "DATA_SERVICES" CLOB,
+  "POI_POINTS" CLOB,
+  "STATUS" CHAR(1) NOT NULL DEFAULT '0',
+  "CREATE_BY" VARCHAR(64) DEFAULT '',
+  "CREATE_TIME" DATETIME,
+  "UPDATE_BY" VARCHAR(64) DEFAULT '',
+  "UPDATE_TIME" DATETIME,
+  "REMARK" VARCHAR(500) DEFAULT NULL,
+  PRIMARY KEY ("SCENE_ID")
+);
+
+-- ----------------------------
+-- Checks for BUSINESS_SCENE
+-- ----------------------------
+ALTER TABLE "BUSINESS_SCENE" ADD CONSTRAINT "business_scene_check_1" CHECK ("STATUS" IN ('0','1','2'));
+
+-- ----------------------------
+-- Comments for BUSINESS_SCENE
+-- ----------------------------
+COMMENT ON TABLE "BUSINESS_SCENE" IS '业务场景表';
+COMMENT ON COLUMN "BUSINESS_SCENE"."SCENE_ID" IS '场景ID';
+COMMENT ON COLUMN "BUSINESS_SCENE"."SCENE_NAME" IS '场景名称';
+COMMENT ON COLUMN "BUSINESS_SCENE"."THIRD_PERSON_CAMERA_POS" IS '第三视角相机位置(JSON格式)';
+COMMENT ON COLUMN "BUSINESS_SCENE"."THIRD_PERSON_CAMERA_TARGET" IS '第三视角相机目标位置(JSON格式)';
+COMMENT ON COLUMN "BUSINESS_SCENE"."FIRST_PERSON_CAMERA_POS" IS '第一人称相机位置(JSON格式)';
+COMMENT ON COLUMN "BUSINESS_SCENE"."FIRST_PERSON_CAMERA_TARGET" IS '第一人称相机目标位置(JSON格式)';
+COMMENT ON COLUMN "BUSINESS_SCENE"."FIRST_PERSON_CAMERA_HEADING" IS '第一人称相机朝向角(弧度)';
+COMMENT ON COLUMN "BUSINESS_SCENE"."FIRST_PERSON_CAMERA_PITCH" IS '第一人称相机俯仰角(弧度)';
+COMMENT ON COLUMN "BUSINESS_SCENE"."FIRST_PERSON_CAMERA_ROLL" IS '第一人称相机翻滚角(弧度)';
+COMMENT ON COLUMN "BUSINESS_SCENE"."LOADED_MODELS" IS '场景中加载的模型列表(JSON数组)';
+COMMENT ON COLUMN "BUSINESS_SCENE"."DATA_SERVICES" IS '场景关联的数据服务列表(JSON数组)';
+COMMENT ON COLUMN "BUSINESS_SCENE"."POI_POINTS" IS 'POI点列表(JSON数组)';
+COMMENT ON COLUMN "BUSINESS_SCENE"."STATUS" IS '场景状态(0正常 1维护中 2已删除)';
+COMMENT ON COLUMN "BUSINESS_SCENE"."CREATE_BY" IS '创建者';
+COMMENT ON COLUMN "BUSINESS_SCENE"."CREATE_TIME" IS '创建时间';
+COMMENT ON COLUMN "BUSINESS_SCENE"."UPDATE_BY" IS '更新者';
+COMMENT ON COLUMN "BUSINESS_SCENE"."UPDATE_TIME" IS '更新时间';
+COMMENT ON COLUMN "BUSINESS_SCENE"."REMARK" IS '备注';

+ 19 - 0
ruoyi-admin/src/main/resources/sql/business_scene_menu.sql

@@ -0,0 +1,19 @@
+-- 业务场景管理菜单配置
+
+-- 1. 添加业务场景管理子菜单(系统管理下)
+INSERT INTO "sys_menu" VALUES (2027, '业务场景', 1, 10, 'businessScene', 'system/businessScene/index', '', 1, 0, 'C', '0', '0', 'system:businessScene:list', 'scene', 'admin', sysdate, '', NULL, '业务场景管理菜单');
+
+-- 2. 业务场景管理按钮权限
+INSERT INTO "sys_menu" VALUES (2028, '业务场景查询', 2027, 1, '', '', '', 1, 0, 'F', '0', '0', 'system:businessScene:query', '#', 'admin', sysdate, '', NULL, '');
+INSERT INTO "sys_menu" VALUES (2029, '业务场景新增', 2027, 2, '', '', '', 1, 0, 'F', '0', '0', 'system:businessScene:add', '#', 'admin', sysdate, '', NULL, '');
+INSERT INTO "sys_menu" VALUES (2030, '业务场景修改', 2027, 3, '', '', '', 1, 0, 'F', '0', '0', 'system:businessScene:edit', '#', 'admin', sysdate, '', NULL, '');
+INSERT INTO "sys_menu" VALUES (2031, '业务场景删除', 2027, 4, '', '', '', 1, 0, 'F', '0', '0', 'system:businessScene:remove', '#', 'admin', sysdate, '', NULL, '');
+INSERT INTO "sys_menu" VALUES (2032, '业务场景导出', 2027, 5, '', '', '', 1, 0, 'F', '0', '0', 'system:businessScene:export', '#', 'admin', sysdate, '', NULL, '');
+
+-- 3. 给管理员角色分配业务场景管理权限
+INSERT INTO "sys_role_menu" VALUES (1, 2027);
+INSERT INTO "sys_role_menu" VALUES (1, 2028);
+INSERT INTO "sys_role_menu" VALUES (1, 2029);
+INSERT INTO "sys_role_menu" VALUES (1, 2030);
+INSERT INTO "sys_role_menu" VALUES (1, 2031);
+INSERT INTO "sys_role_menu" VALUES (1, 2032);

BIN
ruoyi-admin/target/classes/com/ruoyi/RuoYiApplication.class


BIN
ruoyi-admin/target/classes/com/ruoyi/RuoYiServletInitializer.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/cesium/CesiumMapConfigController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/common/CaptchaController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/common/CommonController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/monitor/CacheController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/monitor/ServerController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/monitor/SysLogininforController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/monitor/SysOperlogController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/monitor/SysUserOnlineController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysConfigController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysDeptController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysDictDataController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysDictTypeController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysIndexController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysLoginController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysMenuController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysNoticeController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysPostController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysProfileController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysRegisterController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysRoleController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/system/SysUserController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/tool/TestController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/tool/UserEntity.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/watershed/WatershedModelController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/controller/watershed/WatershedServiceController.class


BIN
ruoyi-admin/target/classes/com/ruoyi/web/core/config/SwaggerConfig.class


+ 279 - 0
ruoyi-system/src/main/java/com/ruoyi/system/domain/BusinessScene.java

@@ -0,0 +1,279 @@
+package com.ruoyi.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * 业务场景对象 business_scene
+ * 
+ * @author ruoyi
+ * @date 2026-06-16
+ */
+public class BusinessScene extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 场景ID */
+    private Long sceneId;
+
+    /** 场景名称 */
+    @Excel(name = "场景名称")
+    private String sceneName;
+
+    /** 第三视角相机位置 */
+    private String thirdPersonCameraPos;
+
+    /** 第三视角相机目标位置 */
+    private String thirdPersonCameraTarget;
+
+    /** 第三视角相机朝向角 */
+    @JsonProperty("thirdPersonCameraHeading")
+    private Double thirdPersonCameraHeading;
+
+    /** 第三视角相机俯仰角 */
+    @JsonProperty("thirdPersonCameraPitch")
+    private Double thirdPersonCameraPitch;
+
+    /** 第三视角相机翻滚角 */
+    @JsonProperty("thirdPersonCameraRoll")
+    private Double thirdPersonCameraRoll;
+
+    /** 第三视角相机方向向量 */
+    @JsonProperty("thirdPersonCameraDirection")
+    private String thirdPersonCameraDirection;
+
+    /** 第三视角相机上向量 */
+    @JsonProperty("thirdPersonCameraUp")
+    private String thirdPersonCameraUp;
+
+    /** 第一人称相机位置 */
+    private String firstPersonCameraPos;
+
+    /** 第一人称相机目标位置 */
+    private String firstPersonCameraTarget;
+
+    /** 第一人称相机朝向角 */
+    private Double firstPersonCameraHeading;
+
+    /** 第一人称相机俯仰角 */
+    private Double firstPersonCameraPitch;
+
+    /** 第一人称相机翻滚角 */
+    private Double firstPersonCameraRoll;
+
+    /** 场景中加载的模型列表 */
+    private String loadedModels;
+
+    /** 场景关联的数据服务列表 */
+    private String dataServices;
+
+    /** POI点列表 */
+    private String poiPoints;
+
+    /** 场景状态(0正常 1维护中 2已删除) */
+    @Excel(name = "场景状态", readConverterExp = "0=正常,1=维护中,2=已删除")
+    private String status;
+
+    /** 备注 */
+    @Excel(name = "备注")
+    private String remark;
+
+    public void setSceneId(Long sceneId) 
+    {
+        this.sceneId = sceneId;
+    }
+
+    public Long getSceneId() 
+    {
+        return sceneId;
+    }
+    public void setSceneName(String sceneName) 
+    {
+        this.sceneName = sceneName;
+    }
+
+    public String getSceneName() 
+    {
+        return sceneName;
+    }
+    public void setThirdPersonCameraPos(String thirdPersonCameraPos) 
+    {
+        this.thirdPersonCameraPos = thirdPersonCameraPos;
+    }
+
+    public String getThirdPersonCameraPos() 
+    {
+        return thirdPersonCameraPos;
+    }
+    public void setThirdPersonCameraTarget(String thirdPersonCameraTarget) 
+    {
+        this.thirdPersonCameraTarget = thirdPersonCameraTarget;
+    }
+
+    public String getThirdPersonCameraTarget() 
+    {
+        return thirdPersonCameraTarget;
+    }
+    public void setThirdPersonCameraHeading(Double thirdPersonCameraHeading) 
+    {
+        this.thirdPersonCameraHeading = thirdPersonCameraHeading;
+    }
+
+    public Double getThirdPersonCameraHeading() 
+    {
+        return thirdPersonCameraHeading;
+    }
+    public void setThirdPersonCameraPitch(Double thirdPersonCameraPitch) 
+    {
+        this.thirdPersonCameraPitch = thirdPersonCameraPitch;
+    }
+
+    public Double getThirdPersonCameraPitch() 
+    {
+        return thirdPersonCameraPitch;
+    }
+    public void setThirdPersonCameraRoll(Double thirdPersonCameraRoll) 
+    {
+        this.thirdPersonCameraRoll = thirdPersonCameraRoll;
+    }
+
+    public Double getThirdPersonCameraRoll() 
+    {
+        return thirdPersonCameraRoll;
+    }
+    public void setThirdPersonCameraDirection(String thirdPersonCameraDirection) 
+    {
+        this.thirdPersonCameraDirection = thirdPersonCameraDirection;
+    }
+
+    public String getThirdPersonCameraDirection() 
+    {
+        return thirdPersonCameraDirection;
+    }
+    public void setThirdPersonCameraUp(String thirdPersonCameraUp) 
+    {
+        this.thirdPersonCameraUp = thirdPersonCameraUp;
+    }
+
+    public String getThirdPersonCameraUp() 
+    {
+        return thirdPersonCameraUp;
+    }
+    public void setFirstPersonCameraPos(String firstPersonCameraPos) 
+    {
+        this.firstPersonCameraPos = firstPersonCameraPos;
+    }
+
+    public String getFirstPersonCameraPos() 
+    {
+        return firstPersonCameraPos;
+    }
+    public void setFirstPersonCameraTarget(String firstPersonCameraTarget) 
+    {
+        this.firstPersonCameraTarget = firstPersonCameraTarget;
+    }
+
+    public String getFirstPersonCameraTarget() 
+    {
+        return firstPersonCameraTarget;
+    }
+    public void setFirstPersonCameraHeading(Double firstPersonCameraHeading) 
+    {
+        this.firstPersonCameraHeading = firstPersonCameraHeading;
+    }
+
+    public Double getFirstPersonCameraHeading() 
+    {
+        return firstPersonCameraHeading;
+    }
+    public void setFirstPersonCameraPitch(Double firstPersonCameraPitch) 
+    {
+        this.firstPersonCameraPitch = firstPersonCameraPitch;
+    }
+
+    public Double getFirstPersonCameraPitch() 
+    {
+        return firstPersonCameraPitch;
+    }
+    public void setFirstPersonCameraRoll(Double firstPersonCameraRoll) 
+    {
+        this.firstPersonCameraRoll = firstPersonCameraRoll;
+    }
+
+    public Double getFirstPersonCameraRoll() 
+    {
+        return firstPersonCameraRoll;
+    }
+    public void setLoadedModels(String loadedModels) 
+    {
+        this.loadedModels = loadedModels;
+    }
+
+    public String getLoadedModels() 
+    {
+        return loadedModels;
+    }
+    public void setDataServices(String dataServices) 
+    {
+        this.dataServices = dataServices;
+    }
+
+    public String getDataServices() 
+    {
+        return dataServices;
+    }
+    public void setPoiPoints(String poiPoints) 
+    {
+        this.poiPoints = poiPoints;
+    }
+
+    public String getPoiPoints() 
+    {
+        return poiPoints;
+    }
+    public void setStatus(String status) 
+    {
+        this.status = status;
+    }
+
+    public String getStatus() 
+    {
+        return status;
+    }
+    public void setRemark(String remark) 
+    {
+        this.remark = remark;
+    }
+
+    public String getRemark() 
+    {
+        return remark;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("sceneId", getSceneId())
+            .append("sceneName", getSceneName())
+            .append("thirdPersonCameraPos", getThirdPersonCameraPos())
+            .append("thirdPersonCameraTarget", getThirdPersonCameraTarget())
+            .append("firstPersonCameraPos", getFirstPersonCameraPos())
+            .append("firstPersonCameraTarget", getFirstPersonCameraTarget())
+            .append("firstPersonCameraHeading", getFirstPersonCameraHeading())
+            .append("firstPersonCameraPitch", getFirstPersonCameraPitch())
+            .append("firstPersonCameraRoll", getFirstPersonCameraRoll())
+            .append("loadedModels", getLoadedModels())
+            .append("dataServices", getDataServices())
+            .append("poiPoints", getPoiPoints())
+            .append("status", getStatus())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
+}

+ 61 - 0
ruoyi-system/src/main/java/com/ruoyi/system/mapper/BusinessSceneMapper.java

@@ -0,0 +1,61 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.system.domain.BusinessScene;
+
+/**
+ * 业务场景Mapper接口
+ * 
+ * @author ruoyi
+ * @date 2026-06-16
+ */
+public interface BusinessSceneMapper 
+{
+    /**
+     * 查询业务场景
+     * 
+     * @param sceneId 业务场景主键
+     * @return 业务场景
+     */
+    public BusinessScene selectBusinessSceneById(Long sceneId);
+
+    /**
+     * 查询业务场景列表
+     * 
+     * @param businessScene 业务场景
+     * @return 业务场景集合
+     */
+    public List<BusinessScene> selectBusinessSceneList(BusinessScene businessScene);
+
+    /**
+     * 新增业务场景
+     * 
+     * @param businessScene 业务场景
+     * @return 结果
+     */
+    public int insertBusinessScene(BusinessScene businessScene);
+
+    /**
+     * 修改业务场景
+     * 
+     * @param businessScene 业务场景
+     * @return 结果
+     */
+    public int updateBusinessScene(BusinessScene businessScene);
+
+    /**
+     * 删除业务场景
+     * 
+     * @param sceneId 业务场景主键
+     * @return 结果
+     */
+    public int deleteBusinessSceneById(Long sceneId);
+
+    /**
+     * 批量删除业务场景
+     * 
+     * @param sceneIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteBusinessSceneByIds(Long[] sceneIds);
+}

+ 61 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/IBusinessSceneService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.system.service;
+
+import java.util.List;
+import com.ruoyi.system.domain.BusinessScene;
+
+/**
+ * 业务场景Service接口
+ * 
+ * @author ruoyi
+ * @date 2026-06-16
+ */
+public interface IBusinessSceneService 
+{
+    /**
+     * 查询业务场景
+     * 
+     * @param sceneId 业务场景主键
+     * @return 业务场景
+     */
+    public BusinessScene selectBusinessSceneById(Long sceneId);
+
+    /**
+     * 查询业务场景列表
+     * 
+     * @param businessScene 业务场景
+     * @return 业务场景集合
+     */
+    public List<BusinessScene> selectBusinessSceneList(BusinessScene businessScene);
+
+    /**
+     * 新增业务场景
+     * 
+     * @param businessScene 业务场景
+     * @return 结果
+     */
+    public int insertBusinessScene(BusinessScene businessScene);
+
+    /**
+     * 修改业务场景
+     * 
+     * @param businessScene 业务场景
+     * @return 结果
+     */
+    public int updateBusinessScene(BusinessScene businessScene);
+
+    /**
+     * 批量删除业务场景
+     * 
+     * @param sceneIds 需要删除的业务场景主键集合
+     * @return 结果
+     */
+    public int deleteBusinessSceneByIds(Long[] sceneIds);
+
+    /**
+     * 删除业务场景信息
+     * 
+     * @param sceneId 业务场景主键
+     * @return 结果
+     */
+    public int deleteBusinessSceneById(Long sceneId);
+}

+ 93 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BusinessSceneServiceImpl.java

@@ -0,0 +1,93 @@
+package com.ruoyi.system.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.system.mapper.BusinessSceneMapper;
+import com.ruoyi.system.domain.BusinessScene;
+import com.ruoyi.system.service.IBusinessSceneService;
+
+/**
+ * 业务场景Service业务层处理
+ * 
+ * @author ruoyi
+ * @date 2026-06-16
+ */
+@Service
+public class BusinessSceneServiceImpl implements IBusinessSceneService 
+{
+    @Autowired
+    private BusinessSceneMapper businessSceneMapper;
+
+    /**
+     * 查询业务场景
+     * 
+     * @param sceneId 业务场景主键
+     * @return 业务场景
+     */
+    @Override
+    public BusinessScene selectBusinessSceneById(Long sceneId) 
+    {
+        return businessSceneMapper.selectBusinessSceneById(sceneId);
+    }
+
+    /**
+     * 查询业务场景列表
+     * 
+     * @param businessScene 业务场景
+     * @return 业务场景
+     */
+    @Override
+    public List<BusinessScene> selectBusinessSceneList(BusinessScene businessScene) 
+    {
+        return businessSceneMapper.selectBusinessSceneList(businessScene);
+    }
+
+    /**
+     * 新增业务场景
+     * 
+     * @param businessScene 业务场景
+     * @return 结果
+     */
+    @Override
+    public int insertBusinessScene(BusinessScene businessScene) 
+    {
+        return businessSceneMapper.insertBusinessScene(businessScene);
+    }
+
+    /**
+     * 修改业务场景
+     * 
+     * @param businessScene 业务场景
+     * @return 结果
+     */
+    @Override
+    public int updateBusinessScene(BusinessScene businessScene) 
+    {
+        return businessSceneMapper.updateBusinessScene(businessScene);
+    }
+
+    /**
+     * 删除业务场景
+     * 
+     * @param sceneId 业务场景主键
+     * @return 结果
+     */
+    @Override
+    public int deleteBusinessSceneById(Long sceneId) 
+    {
+        return businessSceneMapper.deleteBusinessSceneById(sceneId);
+    }
+
+    /**
+     * 批量删除业务场景
+     * 
+     * @param sceneIds 需要删除的业务场景主键集合
+     * @return 结果
+     */
+    @Override
+    public int deleteBusinessSceneByIds(Long[] sceneIds) 
+    {
+        return businessSceneMapper.deleteBusinessSceneByIds(sceneIds);
+    }
+}

+ 116 - 0
ruoyi-system/src/main/resources/mapper/system/BusinessSceneMapper.xml

@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.BusinessSceneMapper">
+
+    <resultMap type="BusinessScene" id="BusinessSceneResult">
+        <id     property="sceneId"                        column="scene_id"                 />
+        <result property="sceneName"                      column="scene_name"               />
+        <result property="thirdPersonCameraPos"           column="third_person_camera_pos"  />
+        <result property="thirdPersonCameraTarget"        column="third_person_camera_target"/>
+        <result property="thirdPersonCameraHeading"       column="third_person_camera_heading"/>
+        <result property="thirdPersonCameraPitch"         column="third_person_camera_pitch"/>
+        <result property="thirdPersonCameraRoll"          column="third_person_camera_roll"/>
+        <result property="thirdPersonCameraDirection"     column="third_person_camera_direction"/>
+        <result property="thirdPersonCameraUp"            column="third_person_camera_up"/>
+        <result property="firstPersonCameraPos"           column="first_person_camera_pos"  />
+        <result property="firstPersonCameraTarget"        column="first_person_camera_target"/>
+        <result property="firstPersonCameraHeading"       column="first_person_camera_heading"/>
+        <result property="firstPersonCameraPitch"         column="first_person_camera_pitch"/>
+        <result property="firstPersonCameraRoll"          column="first_person_camera_roll"/>
+        <result property="loadedModels"                   column="loaded_models"            />
+        <result property="dataServices"                   column="data_services"            />
+        <result property="poiPoints"                      column="poi_points"               />
+        <result property="status"                         column="status"                   />
+        <result property="createBy"                       column="create_by"                />
+        <result property="createTime"                     column="create_time"              />
+        <result property="updateBy"                       column="update_by"                />
+        <result property="updateTime"                     column="update_time"              />
+        <result property="remark"                         column="remark"                   />
+    </resultMap>
+
+    <sql id="selectBusinessSceneVo">
+        select scene_id, scene_name, third_person_camera_pos, third_person_camera_target,
+               third_person_camera_heading, third_person_camera_pitch, third_person_camera_roll,
+               third_person_camera_direction, third_person_camera_up,
+               first_person_camera_pos, first_person_camera_target, first_person_camera_heading, 
+               first_person_camera_pitch, first_person_camera_roll, loaded_models, 
+               data_services, poi_points, status, create_by, create_time, update_by, update_time, remark 
+        from business_scene
+    </sql>
+
+    <select id="selectBusinessSceneById" parameterType="Long" resultMap="BusinessSceneResult">
+        <include refid="selectBusinessSceneVo"/>
+        where scene_id = #{sceneId}
+    </select>
+
+    <select id="selectBusinessSceneList" parameterType="BusinessScene" resultMap="BusinessSceneResult">
+        <include refid="selectBusinessSceneVo"/>
+        <where>
+            <if test="sceneName != null and sceneName != ''">
+                and scene_name like concat('%', #{sceneName}, '%')
+            </if>
+            <if test="status != null and status != ''">
+                and status = #{status}
+            </if>
+        </where>
+    </select>
+
+    <insert id="insertBusinessScene" parameterType="BusinessScene" useGeneratedKeys="true" keyProperty="sceneId">
+        insert into business_scene (
+            scene_name, third_person_camera_pos, third_person_camera_target,
+            third_person_camera_heading, third_person_camera_pitch, third_person_camera_roll,
+            third_person_camera_direction, third_person_camera_up,
+            first_person_camera_pos, first_person_camera_target, first_person_camera_heading,
+            first_person_camera_pitch, first_person_camera_roll, loaded_models,
+            data_services, poi_points, status, create_by, create_time, update_by, update_time, remark
+        ) values (
+            #{sceneName}, #{thirdPersonCameraPos}, #{thirdPersonCameraTarget},
+            #{thirdPersonCameraHeading}, #{thirdPersonCameraPitch}, #{thirdPersonCameraRoll},
+            #{thirdPersonCameraDirection}, #{thirdPersonCameraUp},
+            #{firstPersonCameraPos}, #{firstPersonCameraTarget}, #{firstPersonCameraHeading},
+            #{firstPersonCameraPitch}, #{firstPersonCameraRoll}, #{loadedModels},
+            #{dataServices}, #{poiPoints}, #{status}, #{createBy}, #{createTime}, #{updateBy}, #{updateTime}, #{remark}
+        )
+    </insert>
+
+    <update id="updateBusinessScene" parameterType="BusinessScene">
+        update business_scene
+        <set>
+            <if test="sceneName != null">scene_name = #{sceneName},</if>
+            <if test="thirdPersonCameraPos != null">third_person_camera_pos = #{thirdPersonCameraPos},</if>
+            <if test="thirdPersonCameraTarget != null">third_person_camera_target = #{thirdPersonCameraTarget},</if>
+            <if test="thirdPersonCameraHeading != null">third_person_camera_heading = #{thirdPersonCameraHeading},</if>
+            <if test="thirdPersonCameraPitch != null">third_person_camera_pitch = #{thirdPersonCameraPitch},</if>
+            <if test="thirdPersonCameraRoll != null">third_person_camera_roll = #{thirdPersonCameraRoll},</if>
+            <if test="thirdPersonCameraDirection != null">third_person_camera_direction = #{thirdPersonCameraDirection},</if>
+            <if test="thirdPersonCameraUp != null">third_person_camera_up = #{thirdPersonCameraUp},</if>
+            <if test="firstPersonCameraPos != null">first_person_camera_pos = #{firstPersonCameraPos},</if>
+            <if test="firstPersonCameraTarget != null">first_person_camera_target = #{firstPersonCameraTarget},</if>
+            <if test="firstPersonCameraHeading != null">first_person_camera_heading = #{firstPersonCameraHeading},</if>
+            <if test="firstPersonCameraPitch != null">first_person_camera_pitch = #{firstPersonCameraPitch},</if>
+            <if test="firstPersonCameraRoll != null">first_person_camera_roll = #{firstPersonCameraRoll},</if>
+            <if test="loadedModels != null">loaded_models = #{loadedModels},</if>
+            <if test="dataServices != null">data_services = #{dataServices},</if>
+            <if test="poiPoints != null">poi_points = #{poiPoints},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="remark != null">remark = #{remark},</if>
+        </set>
+        where scene_id = #{sceneId}
+    </update>
+
+    <delete id="deleteBusinessSceneById" parameterType="Long">
+        delete from business_scene where scene_id = #{sceneId}
+    </delete>
+
+    <delete id="deleteBusinessSceneByIds" parameterType="Long">
+        delete from business_scene where scene_id in 
+        <foreach collection="array" item="sceneId" open="(" separator="," close=")">
+            #{sceneId}
+        </foreach>
+    </delete>
+
+</mapper>

BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/CesiumGeojson.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/CesiumMapConfig.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/SysCache.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/SysConfig.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/SysLogininfor.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/SysNotice.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/SysOperLog.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/SysPost.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/SysRoleDept.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/SysRoleMenu.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/SysUserOnline.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/SysUserPost.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/SysUserRole.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/WatershedEquipment.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/WatershedFacility.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/WatershedService.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/vo/MetaVo.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/domain/vo/RouterVo.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/CesiumGeojsonServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/CesiumMapConfigServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysConfigServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysDeptServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysDictDataServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysLogininforServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysMenuServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysNoticeServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysOperLogServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysPostServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysRoleServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/SysUserServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/WatershedEquipmentServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/WatershedModelServiceImpl.class


BIN
ruoyi-system/target/classes/com/ruoyi/system/service/impl/WatershedServiceServiceImpl.class