Jelajahi Sumber

1.上传模型预览及加载进场景2.加载自定义服务3.坐标拾取功能4.底图初始状态加载

WQQ 1 bulan lalu
induk
melakukan
8e26d2e1bf
100 mengubah file dengan 3000 tambahan dan 340 penghapusan
  1. TEMPAT SAMPAH
      CreateCesiumMapConfigTable.class
  2. 59 0
      CreateCesiumMapConfigTable.java
  3. 4 0
      META-INF/MANIFEST.MF
  4. 15 0
      RuoYi-Vue3/public/img/componentsImg/pick-coordinate.svg
  5. 18 0
      RuoYi-Vue3/src/api/cesium/mapConfig.js
  6. 49 0
      RuoYi-Vue3/src/api/watershed/service.js
  7. 2 0
      RuoYi-Vue3/src/supermap-cesium-module/components/components.js
  8. 48 14
      RuoYi-Vue3/src/supermap-cesium-module/components/custom-service/custom-service.vue
  9. 33 12
      RuoYi-Vue3/src/supermap-cesium-module/components/layer/custom-service/custom-service.vue
  10. 7 0
      RuoYi-Vue3/src/supermap-cesium-module/components/scene/pick-coordinate/index.js
  11. 314 0
      RuoYi-Vue3/src/supermap-cesium-module/components/scene/pick-coordinate/pick-coordinate.vue
  12. 7 18
      RuoYi-Vue3/src/supermap-cesium-module/components/viewer/viewer.js
  13. 1 1
      RuoYi-Vue3/src/supermap-cesium-module/config/server_config.js
  14. 18 13
      RuoYi-Vue3/src/supermap-cesium-module/config/views_config.js
  15. 11 0
      RuoYi-Vue3/src/supermap-cesium-module/js/common/camera.js
  16. 26 10
      RuoYi-Vue3/src/supermap-cesium-module/js/common/layerManagement.js
  17. 783 80
      RuoYi-Vue3/src/supermap-cesium-module/views/layout/aside.vue
  18. 78 106
      RuoYi-Vue3/src/views/front/ModelManagement.vue
  19. 802 57
      RuoYi-Vue3/src/views/front/content/ShuiliGongcheng.vue
  20. TEMPAT SAMPAH
      add_loaded_custom_services.sql
  21. 1 0
      add_loaded_custom_services_dm.sql
  22. 9 0
      check_service_table.sql
  23. 1 0
      classpath.txt
  24. 30 0
      create_service_table.sql
  25. TEMPAT SAMPAH
      ruoyi-admin/CheckCesiumMapConfigDetail.class
  26. 49 0
      ruoyi-admin/CheckCesiumMapConfigDetail.java
  27. TEMPAT SAMPAH
      ruoyi-admin/CleanCesiumMapConfigData.class
  28. 83 0
      ruoyi-admin/CleanCesiumMapConfigData.java
  29. TEMPAT SAMPAH
      ruoyi-admin/QueryCesiumMapConfigData.class
  30. 56 0
      ruoyi-admin/QueryCesiumMapConfigData.java
  31. 6 0
      ruoyi-admin/pom.xml
  32. 155 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/cesium/CesiumMapConfigController.java
  33. 21 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
  34. 121 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/watershed/WatershedServiceController.java
  35. 1 1
      ruoyi-admin/src/main/resources/application-druid.yml
  36. 2 1
      ruoyi-admin/src/main/resources/application.yml
  37. 22 0
      ruoyi-admin/src/main/resources/sql/cesium_map_config.sql
  38. 27 0
      ruoyi-admin/src/main/resources/sql/cesium_map_config_comments.sql
  39. 30 0
      ruoyi-admin/src/main/resources/sql/create_service_table.sql
  40. 1 1
      ruoyi-admin/target/classes/application-druid.yml
  41. 2 1
      ruoyi-admin/target/classes/application.yml
  42. TEMPAT SAMPAH
      ruoyi-admin/target/classes/com/ruoyi/web/controller/cesium/CesiumMapConfigController.class
  43. TEMPAT SAMPAH
      ruoyi-admin/target/classes/com/ruoyi/web/controller/common/CommonController.class
  44. TEMPAT SAMPAH
      ruoyi-admin/target/classes/com/ruoyi/web/controller/watershed/WatershedModelController.class
  45. TEMPAT SAMPAH
      ruoyi-admin/target/classes/com/ruoyi/web/controller/watershed/WatershedServiceController.class
  46. 22 0
      ruoyi-admin/target/classes/sql/cesium_map_config.sql
  47. 27 0
      ruoyi-admin/target/classes/sql/cesium_map_config_comments.sql
  48. 30 0
      ruoyi-admin/target/classes/sql/create_service_table.sql
  49. 2 0
      ruoyi-admin/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
  50. 27 25
      ruoyi-admin/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
  51. TEMPAT SAMPAH
      ruoyi-admin/target/ruoyi-admin.jar
  52. TEMPAT SAMPAH
      ruoyi-admin/target/ruoyi-admin.jar.original
  53. 0 0
      ruoyi-admin/uploads/models/2026/02/03/北斗_20260203110406A001.glb
  54. TEMPAT SAMPAH
      ruoyi-admin/uploads/models/2026/02/03/北斗_20260203110431A002.glb
  55. 0 0
      ruoyi-admin/uploads/models/2026/02/03/救生器材箱_20260203110641A006.glb
  56. 0 0
      ruoyi-admin/uploads/models/2026/02/03/断面桩_20260203110545A004.glb
  57. 0 0
      ruoyi-admin/uploads/models/2026/02/03/氨氮仪器_20260203110605A005.glb
  58. TEMPAT SAMPAH
      ruoyi-admin/uploads/models/2026/02/03/称重式雨量筒_20260203110507A003.glb
  59. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/annotation/Excel$ColumnType.class
  60. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/annotation/Excel$Type.class
  61. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/annotation/Excel.class
  62. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/config/RuoYiConfig.class
  63. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.class
  64. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/constant/CacheConstants.class
  65. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/constant/Constants.class
  66. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/constant/GenConstants.class
  67. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/constant/HttpStatus.class
  68. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/constant/ScheduleConstants$Status.class
  69. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/constant/ScheduleConstants.class
  70. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/constant/UserConstants.class
  71. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/controller/BaseController$1.class
  72. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/controller/BaseController.class
  73. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/domain/AjaxResult.class
  74. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/domain/BaseEntity.class
  75. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/domain/R.class
  76. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/domain/TreeEntity.class
  77. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/domain/TreeSelect.class
  78. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/domain/entity/SysDept.class
  79. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/domain/entity/SysDictData.class
  80. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/domain/entity/SysDictType.class
  81. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/domain/entity/SysMenu.class
  82. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/domain/entity/SysRole.class
  83. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/domain/entity/SysUser.class
  84. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/domain/model/LoginBody.class
  85. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/domain/model/LoginUser.class
  86. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/domain/model/RegisterBody.class
  87. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/page/PageDomain.class
  88. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/page/TableDataInfo.class
  89. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/page/TableSupport.class
  90. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/redis/RedisCache.class
  91. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/text/CharsetKit.class
  92. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/text/Convert.class
  93. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/core/text/StrFormatter.class
  94. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/enums/BusinessStatus.class
  95. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/enums/BusinessType.class
  96. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/enums/DataSourceType.class
  97. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/enums/DesensitizedType.class
  98. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/enums/HttpMethod.class
  99. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/enums/LimitType.class
  100. TEMPAT SAMPAH
      ruoyi-common/target/classes/com/ruoyi/common/enums/OperatorType.class

TEMPAT SAMPAH
CreateCesiumMapConfigTable.class


+ 59 - 0
CreateCesiumMapConfigTable.java

@@ -0,0 +1,59 @@
+import java.sql.*;
+
+public class CreateCesiumMapConfigTable {
+    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 sql = "CREATE TABLE WATERSHED.CESIUM_MAP_CONFIG (" +
+                "config_id BIGINT IDENTITY(1,1) PRIMARY KEY," +
+                "user_id BIGINT NOT NULL," +
+                "config_name VARCHAR(100) DEFAULT '默认配置'," +
+                "base_layer_type VARCHAR(50)," +
+                "base_layer_name VARCHAR(100)," +
+                "base_layer_url VARCHAR(500)," +
+                "terrain_layer_type VARCHAR(50)," +
+                "terrain_layer_name VARCHAR(100)," +
+                "terrain_layer_url VARCHAR(500)," +
+                "web_services CLOB," +
+                "loaded_models CLOB," +
+                "is_default INT DEFAULT 0," +
+                "create_by VARCHAR(64) DEFAULT ''," +
+                "create_time TIMESTAMP," +
+                "update_by VARCHAR(64) DEFAULT ''," +
+                "update_time TIMESTAMP," +
+                "remark VARCHAR(500)" +
+                ")";
+            
+            try {
+                stmt.execute(sql);
+                System.out.println("表 CESIUM_MAP_CONFIG 创建成功!");
+            } catch (SQLException e) {
+                if (e.getErrorCode() == -2626) {
+                    System.out.println("表 CESIUM_MAP_CONFIG 已存在,跳过创建。");
+                } else {
+                    throw e;
+                }
+            }
+            
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (stmt != null) stmt.close();
+                if (conn != null) conn.close();
+            } catch (SQLException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}

+ 4 - 0
META-INF/MANIFEST.MF

@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+Created-By: Maven JAR Plugin 3.4.1
+Build-Jdk-Spec: 17
+

+ 15 - 0
RuoYi-Vue3/public/img/componentsImg/pick-coordinate.svg

@@ -0,0 +1,15 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
+  <defs>
+    <linearGradient id="bgGrad" x1="0%" y1="0%" x2="100%" y2="100%">
+      <stop offset="0%" style="stop-color:#409eff;stop-opacity:1" />
+      <stop offset="100%" style="stop-color:#67c23a;stop-opacity:1" />
+    </linearGradient>
+  </defs>
+  <rect width="64" height="64" rx="8" fill="url(#bgGrad)"/>
+  <circle cx="32" cy="32" r="12" fill="none" stroke="white" stroke-width="2"/>
+  <line x1="32" y1="8" x2="32" y2="20" stroke="white" stroke-width="2" stroke-linecap="round"/>
+  <line x1="32" y1="44" x2="32" y2="56" stroke="white" stroke-width="2" stroke-linecap="round"/>
+  <line x1="8" y1="32" x2="20" y2="32" stroke="white" stroke-width="2" stroke-linecap="round"/>
+  <line x1="44" y1="32" x2="56" y2="32" stroke="white" stroke-width="2" stroke-linecap="round"/>
+  <circle cx="32" cy="32" r="4" fill="#ffd700"/>
+</svg>

+ 18 - 0
RuoYi-Vue3/src/api/cesium/mapConfig.js

@@ -0,0 +1,18 @@
+import request from '@/utils/request'
+
+// 获取默认地图配置
+export function getDefaultMapConfig() {
+  return request({
+    url: '/cesium/mapConfig/default',
+    method: 'get'
+  })
+}
+
+// 保存地图配置
+export function saveMapConfig(data) {
+  return request({
+    url: '/cesium/mapConfig',
+    method: 'post',
+    data: data
+  })
+}

+ 49 - 0
RuoYi-Vue3/src/api/watershed/service.js

@@ -0,0 +1,49 @@
+import request from '@/utils/request'
+
+// 自定义服务相关API
+const serviceApi = {
+  // 获取服务列表
+  getServiceList: (params) => {
+    return request({
+      url: '/watershed/service/list',
+      method: 'get',
+      params
+    })
+  },
+
+  // 获取服务详情
+  getServiceById: (id) => {
+    return request({
+      url: `/watershed/service/${id}`,
+      method: 'get'
+    })
+  },
+
+  // 新增服务
+  addService: (data) => {
+    return request({
+      url: '/watershed/service',
+      method: 'post',
+      data
+    })
+  },
+
+  // 更新服务
+  updateService: (data) => {
+    return request({
+      url: '/watershed/service',
+      method: 'put',
+      data
+    })
+  },
+
+  // 删除服务
+  deleteService: (ids) => {
+    return request({
+      url: `/watershed/service/${ids}`,
+      method: 'delete'
+    })
+  }
+}
+
+export default serviceApi

+ 2 - 0
RuoYi-Vue3/src/supermap-cesium-module/components/components.js

@@ -49,6 +49,7 @@ import draw from "./draw/draw-line-surface/index.js"
 import symbol from "./draw/add-point-symbol/index.js"
 import light from "./scene/light/index.js"
 import projection from "./scene/projection-image/index.js"
+import pickCoordinate from "./scene/pick-coordinate/index.js"
 import scanEffect from "./special-effects/scan-effect/index.js"
 import geologicalBody from "./model/geological-body/index.js"
 import volume from "./scene/volume-render/index.js"
@@ -93,6 +94,7 @@ const components = [
     symbol,
     light,
     projection,
+    pickCoordinate,
     scanEffect,
     geologicalBody,
     volume,

+ 48 - 14
RuoYi-Vue3/src/supermap-cesium-module/components/custom-service/custom-service.vue

@@ -1,5 +1,5 @@
 <template>
-  <div id="CustomService-panel" class="sm-panel" v-drag>
+  <div id="CustomService-panel" class="sm-panel" v-drag :style="panelStyle">
     <div class="sm-function-module-sub-section" style="margin:0" v-stopdrag>
       <div class="sm-half-L">
         <label style="width:40%">打开图层</label>
@@ -57,7 +57,7 @@
 <script>
 import layerManagement from "../../js/common/layerManagement.js";
 import tool from "../../js/tool/tool.js";
-import { watch, ref, reactive, toRefs, onBeforeUnmount, onMounted } from "vue";
+import { watch, ref, reactive, toRefs, onBeforeUnmount, onMounted, getCurrentInstance } from "vue";
 export default {
   name: "Sm3dCustomService",
   props: {
@@ -74,6 +74,16 @@ export default {
     }
   },
   setup(props) {
+    onMounted(() => {
+      setTimeout(() => {
+        const panel = document.getElementById('CustomService-panel');
+        if (panel) {
+          panel.style.left = '35%';
+          panel.style.top = '25%';
+        }
+      }, 50);
+    });
+    
     // 设置默认值数据
     let state = reactive({
       layersType: "SCENE",
@@ -132,38 +142,61 @@ export default {
         return;
       };
       getLayerName(state.layerName);
-      switch (state.layersType) {
+      
+      const currentURL = state.layerURL;
+      const currentToken = state.token;
+      const currentTokenRequired = state.isAddToken;
+      const currentLayerName = state.layerName;
+      const currentLayersType = state.layersType;
+      
+      const serviceInfo = {
+        url: currentURL,
+        token: currentToken,
+        tokenRequired: currentTokenRequired
+      };
+      
+      console.log('addLayer - serviceInfo:', serviceInfo);
+      console.log('addLayer - currentURL:', currentURL);
+      
+      switch (currentLayersType) {
         case "SCENE":
           if (check()) {
             let options = {};
-            if (state.isAddToken) options.SceneToken = state.token;
-            layerManagement.addScene(state.layerURL, options, addCallback);
+            if (currentTokenRequired) options.SceneToken = currentToken;
+            console.log('SCENE回调前serviceInfo:', serviceInfo);
+            layerManagement.addScene(currentURL, options, (layers) => {
+              console.log('SCENE回调中serviceInfo:', serviceInfo);
+              addCallback(layers, "SCENE", serviceInfo);
+            });
           }
           break;
         case "S3M":
           if (check()) {
             let scps = [
-              { url: state.layerURL, options: { name: state.layerName } }
+              { url: currentURL, options: { name: currentLayerName } }
             ];
-            layerManagement.addS3mLayers(scps, addCallback);
+            layerManagement.addS3mLayers(scps, (layers) => {
+              addCallback(layers, "S3M", serviceInfo);
+            });
           }
           break;
         case "IMG":
           if (check()) {
-           let layer = layerManagement.addImageLayer(state.layerURL);
-            addCallback(layer, "IMG");
+            let layer = layerManagement.addImageLayer(currentURL);
+            addCallback(layer, "IMG", serviceInfo);
           }
           break;
         case "TERRAIN":
           if (check()) {
-            let terrainProvider = layerManagement.addTerrainLayer(state.layerURL, state.isSct);
-            addCallback(terrainProvider, "TERRAIN");
+            let terrainProvider = layerManagement.addTerrainLayer(currentURL, state.isSct);
+            addCallback(terrainProvider, "TERRAIN", serviceInfo);
           }
           break;
-           case "MVT":
+        case "MVT":
           if (check()) {
-            let mvtlayer = layerManagement.addMvtLayer(state.layerURL, state.layerName);
-            addCallback(mvtlayer, "MVT");
+            layerManagement.addMvtLayer(currentURL, currentLayerName, (mvtlayer) => {
+              addCallback(mvtlayer, "MVT", serviceInfo);
+            });
           }
           break;
       }
@@ -184,6 +217,7 @@ export default {
 
     return {
       ...toRefs(state),
+      panelStyle,
       addLayer,
       clear
     };

+ 33 - 12
RuoYi-Vue3/src/supermap-cesium-module/components/layer/custom-service/custom-service.vue

@@ -132,38 +132,59 @@ export default {
         return;
       };
       getLayerName(state.layerName);
-      switch (state.layersType) {
+      
+      const currentURL = state.layerURL;
+      const currentToken = state.token;
+      const currentTokenRequired = state.isAddToken;
+      const currentLayerName = state.layerName;
+      const currentLayersType = state.layersType;
+      
+      const serviceInfo = {
+        url: currentURL,
+        token: currentToken,
+        tokenRequired: currentTokenRequired
+      };
+      
+      console.log('addLayer - serviceInfo:', serviceInfo);
+      
+      switch (currentLayersType) {
         case "SCENE":
           if (check()) {
             let options = {};
-            if (state.isAddToken) options.SceneToken = token;
-            layerManagement.addScene(state.layerURL, options, addCallback);
+            if (currentTokenRequired) options.SceneToken = currentToken;
+            layerManagement.addScene(currentURL, options, (layers) => {
+              console.log('SCENE回调中serviceInfo:', serviceInfo);
+              addCallback(layers, "SCENE", serviceInfo);
+            });
           }
           break;
         case "S3M":
           if (check()) {
             let scps = [
-              { url: state.layerURL, options: { name: state.layerName } }
+              { url: currentURL, options: { name: currentLayerName } }
             ];
-            layerManagement.addS3mLayers(scps, addCallback);
+            layerManagement.addS3mLayers(scps, (layers) => {
+              addCallback(layers, "S3M", serviceInfo);
+            });
           }
           break;
         case "IMG":
           if (check()) {
-           let layer = layerManagement.addImageLayer(state.layerURL);
-            addCallback(layer, "IMG");
+            let layer = layerManagement.addImageLayer(currentURL);
+            addCallback(layer, "IMG", serviceInfo);
           }
           break;
         case "TERRAIN":
           if (check()) {
-            layerManagement.addTerrainLayer(state.layerURL, state.isSct);
-            addCallback(viewer.terrainProvider, "TERRAIN");
+            let terrainProvider = layerManagement.addTerrainLayer(currentURL, state.isSct);
+            addCallback(terrainProvider, "TERRAIN", serviceInfo);
           }
           break;
-           case "MVT":
+        case "MVT":
           if (check()) {
-            let mvtlayer = layerManagement.addMvtLayer(state.layerURL, state.layerName);
-            addCallback(mvtlayer, "MVT");
+            layerManagement.addMvtLayer(currentURL, currentLayerName, (mvtlayer) => {
+              addCallback(mvtlayer, "MVT", serviceInfo);
+            });
           }
           break;
       }

+ 7 - 0
RuoYi-Vue3/src/supermap-cesium-module/components/scene/pick-coordinate/index.js

@@ -0,0 +1,7 @@
+import pickCoordinate from './pick-coordinate.vue'
+
+pickCoordinate.install = function (app) {
+  app.component(pickCoordinate.name, pickCoordinate);
+};
+
+export default pickCoordinate;

+ 314 - 0
RuoYi-Vue3/src/supermap-cesium-module/components/scene/pick-coordinate/pick-coordinate.vue

@@ -0,0 +1,314 @@
+<template>
+  <div id="pick-coordinate-panel" class="sm-panel" v-drag>
+    <div class="sm-function-module-sub-section" style="margin:0" v-stopdrag>
+      <div class="sm-half-L">
+        <label>状态:</label>
+        <span :class="{ active: isPicking }">{{ isPicking ? '拾取中...' : '已停止' }}</span>
+      </div>
+      <div class="sm-half-L" v-if="lastPosition">
+        <label>经度:</label>
+        <span class="coord-value">{{ lastPosition.longitude }}</span>
+      </div>
+      <div class="sm-half-L" v-if="lastPosition">
+        <label>纬度:</label>
+        <span class="coord-value">{{ lastPosition.latitude }}</span>
+      </div>
+      <div class="sm-half-L" v-if="lastPosition">
+        <label>高度:</label>
+        <span class="coord-value">{{ lastPosition.height }} m</span>
+      </div>
+      <div class="sm-half-L flex-between">
+        <el-button 
+          :type="isPicking ? 'danger' : 'primary'" 
+          size="small" 
+          @click="togglePicking"
+          class="pick-btn"
+        >
+          {{ isPicking ? '停止拾取' : '开始拾取' }}
+        </el-button>
+        <el-button 
+          size="small" 
+          @click="copyCoordinate" 
+          :disabled="!lastPosition"
+        >
+          复制
+        </el-button>
+        <el-button 
+          size="small" 
+          @click="clearPosition"
+        >
+          清空
+        </el-button>
+      </div>
+      <div class="history-section" v-if="positionHistory.length > 0">
+        <label>历史记录</label>
+        <div class="history-list">
+          <div 
+            class="history-item" 
+            v-for="(pos, index) in positionHistory" 
+            :key="index"
+            @click="copyHistoryCoordinate(pos)"
+          >
+            <span class="history-index">{{ index + 1 }}.</span>
+            <span class="history-coord">{{ pos.longitude }}, {{ pos.latitude }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { ElMessage } from 'element-plus'
+
+export default {
+  name: 'Sm3dPickCoordinate',
+  data() {
+    return {
+      isPicking: false,
+      handler: null,
+      lastPosition: null,
+      positionHistory: []
+    }
+  },
+  mounted() {
+    this.initHandler()
+    this.startPicking()
+  },
+  beforeUnmount() {
+    this.destroyPick()
+  },
+  methods: {
+    initHandler() {
+      if (!this.handler) {
+        this.handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
+      }
+    },
+    startPicking() {
+      this.initHandler()
+      
+      this.handler.setInputAction((movement) => {
+        if (typeof viewer === 'undefined' || !viewer || !viewer.scene) {
+          return
+        }
+        
+        let cartesian = viewer.scene.pickPosition(movement.position)
+        
+        if (!cartesian) {
+          const ray = viewer.camera.getPickRay(movement.position)
+          cartesian = viewer.scene.globe.pick(ray, viewer.scene)
+        }
+        
+        if (cartesian) {
+          const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
+          if (cartographic) {
+            const longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6)
+            const latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(6)
+            const height = cartographic.height.toFixed(2)
+            this.updatePosition(longitude, latitude, height, cartesian)
+          }
+        } else {
+          const cartesian2 = viewer.camera.pickEllipsoid(
+            movement.position,
+            viewer.scene.globe.ellipsoid
+          )
+          if (cartesian2) {
+            const cartographic = Cesium.Cartographic.fromCartesian(cartesian2)
+            if (cartographic) {
+              const longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6)
+              const latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(6)
+              let height = cartographic.height
+              if (Math.abs(height) < 0.01) {
+                const terrainHeight = viewer.scene.globe.getHeight(cartographic)
+                height = terrainHeight || 0
+              }
+              this.updatePosition(longitude, latitude, height.toFixed(2), cartesian2)
+            }
+          }
+        }
+      }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
+      
+      this.isPicking = true
+    },
+    updatePosition(longitude, latitude, height, cartesian) {
+      this.lastPosition = {
+        longitude,
+        latitude,
+        height
+      }
+      
+      if (this.positionHistory.length >= 10) {
+        this.positionHistory.shift()
+      }
+      this.positionHistory.push({ ...this.lastPosition })
+      
+      if (typeof viewer !== 'undefined' && viewer && viewer.entities) {
+        viewer.entities.removeById('pick-point-marker')
+        viewer.entities.add({
+          id: 'pick-point-marker',
+          position: cartesian,
+          point: {
+            pixelSize: 10,
+            color: Cesium.Color.YELLOW.withAlpha(0.8),
+            outlineColor: Cesium.Color.RED,
+            outlineWidth: 2
+          },
+          label: {
+            text: `${longitude}, ${latitude}`,
+            font: '12px sans-serif',
+            fillColor: Cesium.Color.WHITE,
+            outlineColor: Cesium.Color.BLACK,
+            outlineWidth: 2,
+            pixelOffset: new Cesium.Cartesian2(0, -20)
+          }
+        })
+      }
+    },
+    stopPicking() {
+      if (this.handler) {
+        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
+      }
+      this.isPicking = false
+    },
+    togglePicking() {
+      if (this.isPicking) {
+        this.stopPicking()
+      } else {
+        this.startPicking()
+      }
+    },
+    copyCoordinate() {
+      if (this.lastPosition) {
+        const coord = `${this.lastPosition.longitude}, ${this.lastPosition.latitude}, ${this.lastPosition.height}`
+        navigator.clipboard.writeText(coord).then(() => {
+          ElMessage.success('坐标已复制到剪贴板')
+        }).catch(() => {
+          ElMessage.error('复制失败')
+        })
+      }
+    },
+    copyHistoryCoordinate(pos) {
+      const coord = `${pos.longitude}, ${pos.latitude}, ${pos.height}`
+      navigator.clipboard.writeText(coord).then(() => {
+        ElMessage.success('坐标已复制到剪贴板')
+      }).catch(() => {
+        ElMessage.error('复制失败')
+      })
+    },
+    clearPosition() {
+      this.lastPosition = null
+      this.positionHistory = []
+      if (typeof viewer !== 'undefined' && viewer && viewer.entities) {
+        viewer.entities.removeById('pick-point-marker')
+      }
+    },
+    destroyPick() {
+      this.stopPicking()
+      if (this.handler) {
+        this.handler.destroy()
+        this.handler = null
+      }
+      if (typeof viewer !== 'undefined' && viewer && viewer.entities) {
+        viewer.entities.removeById('pick-point-marker')
+      }
+      this.$emit('delete')
+    }
+  }
+}
+</script>
+
+<style scoped>
+.sm-half-L {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+  margin-bottom: 8px;
+}
+
+.sm-half-L label {
+  width: auto;
+  margin-right: 10px;
+}
+
+.sm-half-L span {
+  font-family: monospace;
+  color: #303133;
+}
+
+.sm-half-L span.active {
+  color: #67c23a;
+  font-weight: 500;
+}
+
+.coord-value {
+  background: #f5f7fa;
+  padding: 2px 8px;
+  border-radius: 4px;
+  font-size: 12px;
+}
+
+.flex-between {
+  display: flex;
+  justify-content: space-between;
+  gap: 8px;
+}
+
+.flex-between .el-button {
+  flex: 1;
+}
+
+.pick-btn {
+  color: #fff !important;
+}
+
+.pick-btn:hover {
+  color: #fff !important;
+}
+
+.history-section {
+  width: 100%;
+  border-top: 1px solid #ebeef5;
+  padding-top: 10px;
+  margin-top: 5px;
+}
+
+.history-section > label {
+  width: 100%;
+  font-weight: 500;
+  color: #606266;
+  margin-bottom: 8px;
+}
+
+.history-list {
+  max-height: 150px;
+  overflow-y: auto;
+}
+
+.history-item {
+  display: flex;
+  align-items: center;
+  padding: 4px 8px;
+  margin-bottom: 4px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  cursor: pointer;
+  transition: background 0.2s;
+}
+
+.history-item:hover {
+  background: #e6f1fc;
+}
+
+.history-index {
+  color: #909399;
+  margin-right: 8px;
+  font-size: 12px;
+}
+
+.history-coord {
+  font-family: monospace;
+  color: #303133;
+  font-size: 12px;
+}
+</style>

+ 7 - 18
RuoYi-Vue3/src/supermap-cesium-module/components/viewer/viewer.js

@@ -90,24 +90,13 @@ function initViewer(props, callback) {
   }
 
   function openingAnimation() {
-    viewer.camera.flyTo({
-      destination: new Cesium.Cartesian3(
-        6788287.844465209,
-        -41980756.10214644,
-        29619220.04004376
-      ),
-      duration: 0,
-      complete: function () {
-        viewer.camera.flyTo({
-          destination: new Cesium.Cartesian3.fromDegrees(
-            110.60396458865515,
-            34.54408834959379,
-            30644793.325518917
-          ),
-          duration: 5,
-        });
-
-      },
+    viewer.camera.setView({
+      destination: Cesium.Cartesian3.fromDegrees(117.5, 26.0, 500000),
+      orientation: {
+        heading: 0.0,
+        pitch: Cesium.Math.toRadians(-45),
+        roll: 0.0
+      }
     });
   }
 

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

@@ -90,7 +90,7 @@ export default [
                 thumbnail: '/img/baseLayer/Bing.png',
                 title: 'BingMap',
                 type: 'BINGMAP',
-                state: 1
+                state: 0
             },
             {
                 proxiedUrl: 'https://[subdomain].tianditu.gov.cn/img_w/wmts',

+ 18 - 13
RuoYi-Vue3/src/supermap-cesium-module/config/views_config.js

@@ -203,6 +203,11 @@ export default [
                 imgSrc: "/img/componentsImg/volume.png",
                 name: "带时序的体元栅格的可视化表达",
             },
+            {
+                component: "Sm3dPickCoordinate",
+                imgSrc: "/img/componentsImg/pick-coordinate.svg",
+                name: "拾取坐标"
+            },
         ]
     },
     {
@@ -240,17 +245,17 @@ export default [
             
         ]
     },
-    {
-        id: "model",
-        icon: "iconfont iconmoxing",  //图标
-        name: "模型",
-        children: [
-            {
-                component: "Sm3dGeologicalBody",  //组件名称
-                imgSrc: "/img/componentsImg/geological.png",  
-                name: "地质体",
-                destroy:true   //不使用就立即销毁
-            },
-        ]
-    }
+    // {
+    //     id: "model",
+    //     icon: "iconfont iconmoxing",  //图标
+    //     name: "模型",
+    //     children: [
+    //         {
+    //             component: "Sm3dGeologicalBody",  //组件名称
+    //             imgSrc: "/img/componentsImg/geological.png",  
+    //             name: "地质体",
+    //             destroy:true   //不使用就立即销毁
+    //         },
+    //     ]
+    // }
 ]

+ 11 - 0
RuoYi-Vue3/src/supermap-cesium-module/js/common/camera.js

@@ -29,6 +29,17 @@ const flyByCameraParam = function (cameraParam) {
 const flyByLayerName = function (type, id_name) {
     if (!type || !id_name) return;
     switch (type) {
+        case "SCENE":
+            let sceneLayer = viewer.scene.layers.find(id_name);
+            if (sceneLayer) {
+                viewer.flyTo(sceneLayer, {duration: 0});
+            } else {
+                const layers = viewer.scene.layers.layerQueue;
+                if (layers && layers.length > 0) {
+                    viewer.flyTo(layers[0], {duration: 0});
+                }
+            }
+            break;
         case "S3M":
             let layer = viewer.scene.layers.find(id_name);
             viewer.flyTo(layer,{duration: 0,})

+ 26 - 10
RuoYi-Vue3/src/supermap-cesium-module/js/common/layerManagement.js

@@ -30,7 +30,7 @@ function addScene(url, options, callback) {  //无返回值options:{SceneToken,a
         Cesium.Credential.CREDENTIAL = new Cesium.Credential(options.SceneToken);
     }
     let flag = true;
-    if (options && options.autoSetView) {
+    if (options && options.autoSetView !== undefined) {
         flag = options.autoSetView
     }
     if (checkURL(url)) {
@@ -50,16 +50,19 @@ function addScene(url, options, callback) {  //无返回值options:{SceneToken,a
 // 添加地形
 function addTerrainLayer(LayerURL, isSct) {
     try {
-        viewer.terrainProvider = new Cesium.CesiumTerrainProvider({
+        const terrainProvider = new Cesium.CesiumTerrainProvider({
             url: LayerURL,
             isSct: isSct, //地形服务源自SuperMap iServer发布时需设置isSct为true
         });
+        viewer.terrainProvider = terrainProvider;
+        return terrainProvider;
     } catch (e) {
         let widget = viewer.cesiumWidget;
         if (widget._showRenderLoopErrors) {
             let title = "渲染时发生错误,已停止渲染。";
             widget.showErrorPanel(title, undefined, e);
         }
+        return null;
     }
 };
 
@@ -127,7 +130,7 @@ function promiseWhen(promiseArray, callback, type) {
             console.log("layers:",layers)
             storeDate.layers = viewer.scene.layers.layerQueue;
             actions.setChangeLayers();
-            callback(layers[0],type);
+            callback(layers, type);
             storeDate.layers.forEach((s3mlayer) => {
                 if (!s3mlayer.visibleDistanceMax || s3mlayer.visibleDistanceMax > 12000) {
                     s3mlayer.visibleDistanceMax = 12000   //设置模型最可见距离
@@ -159,10 +162,24 @@ function checkURL(url) {
 //   删除图层
 function layersDelete(type, id_name, callback) {
     switch (type) {
+        case "SCENE":
+            console.log('开始删除SCENE图层, id_name:', id_name);
+            if (viewer.scene.layers && viewer.scene.layers.layerQueue) {
+                const layers = viewer.scene.layers.layerQueue;
+                console.log('场景中的图层数量:', layers.length);
+                for (let i = layers.length - 1; i >= 0; i--) {
+                    const layer = layers[i];
+                    console.log('删除图层:', i, layer.name);
+                    viewer.scene.layers.remove(layer);
+                }
+            }
+            actions.setChangeLayers();
+            if (callback) callback();
+            break;
         case "S3M":
             viewer.scene.layers.remove(id_name);
-            actions.setChangeLayers();   //图层改变全局响应触发
-            callback();
+            actions.setChangeLayers();
+            if (callback) callback();
             break;
         case "IMG":
             let img_layer;
@@ -179,22 +196,21 @@ function layersDelete(type, id_name, callback) {
             if (img_layer) {
                 viewer.imageryLayers.remove(img_layer);
                 actions.setChangeLayers();
-                callback();
+                if (callback) callback();
             }
-
             break;
         case "TERRAIN":
             viewer.terrainProvider = new Cesium.EllipsoidTerrainProvider();
             actions.setChangeLayers();
-            callback()
+            if (callback) callback();
             break;
         case "MVT":
             viewer.scene.removeVectorTilesMap(id_name);
             actions.setChangeLayers();
-            callback()
+            if (callback) callback();
             break;
         default:
-            null;
+            if (callback) callback();
     }
 }
 

File diff ditekan karena terlalu besar
+ 783 - 80
RuoYi-Vue3/src/supermap-cesium-module/views/layout/aside.vue


+ 78 - 106
RuoYi-Vue3/src/views/front/ModelManagement.vue

@@ -10,113 +10,72 @@
       <el-menu-item-group>
         <template #title><span style="font-size: 1.45rem; font-weight: 600; color: #303133;">模型分类</span></template>
         
-        <!-- 1. 水利工程实体 (核心工程类) -->
+        <!-- 水利工程模型 -->
         <el-sub-menu index="1">
           <template #title>
-            <el-icon><Menu /></el-icon>
-            <span>水利工程实体</span>
+            <div @click.stop="handleMenuSelect('1')" style="cursor: pointer; width: 100%; display: flex; align-items: center;">
+              <el-icon><Menu /></el-icon>
+              <span>水利工程模型</span>
+            </div>
           </template>
+          
+          <!-- 1. 水利工程实体 -->
           <el-sub-menu index="1-1">
-            <template #title>水库工程</template>
-            <el-menu-item index="1-1-1">大坝</el-menu-item>
-            <el-menu-item index="1-1-2">溢洪道</el-menu-item>
-            <el-menu-item index="1-1-3">泄洪洞/输水洞</el-menu-item>
-            <el-menu-item index="1-1-4">水电站厂房</el-menu-item>
+            <template #title>水利工程实体</template>
+            <el-menu-item index="1-1-1">水库工程</el-menu-item>
+            <el-menu-item index="1-1-2">水闸工程</el-menu-item>
+            <el-menu-item index="1-1-3">泵站工程</el-menu-item>
+            <el-menu-item index="1-1-4">灌区工程</el-menu-item>
+            <el-menu-item index="1-1-5">堤防与护岸工程</el-menu-item>
           </el-sub-menu>
+          
+          <!-- 2. 水系与水利设施 -->
           <el-sub-menu index="1-2">
-            <template #title>水闸工程</template>
-            <el-menu-item index="1-2-1">节制闸</el-menu-item>
-            <el-menu-item index="1-2-2">分洪闸</el-menu-item>
-            <el-menu-item index="1-2-3">进水闸/取水口</el-menu-item>
-            <el-menu-item index="1-2-4">船闸</el-menu-item>
+            <template #title>水系水利设施</template>
+            <el-menu-item index="1-2-1">河流</el-menu-item>
+            <el-menu-item index="1-2-2">湖泊与水库水面</el-menu-item>
+            <el-menu-item index="1-2-3">渠道与输水管道</el-menu-item>
+            <el-menu-item index="1-2-4">河口与海岸带</el-menu-item>
           </el-sub-menu>
+          
+          <!-- 3. 地理与环境要素 -->
           <el-sub-menu index="1-3">
-            <template #title>泵站工程</template>
-            <el-menu-item index="1-3-1">泵站主厂房</el-menu-item>
-            <el-menu-item index="1-3-2">进出水建筑物</el-menu-item>
+            <template #title>地理环境要素</template>
+            <el-menu-item index="1-3-1">地形地貌</el-menu-item>
+            <el-menu-item index="1-3-2">行政区划</el-menu-item>
+            <el-menu-item index="1-3-3">重要地物</el-menu-item>
           </el-sub-menu>
+          
+          <!-- 4. 自然景观与生态 -->
           <el-sub-menu index="1-4">
-            <template #title>灌区工程</template>
-            <el-menu-item index="1-4-1">渡槽</el-menu-item>
-            <el-menu-item index="1-4-2">倒虹吸</el-menu-item>
-            <el-menu-item index="1-4-3">渠系建筑物 (分水闸、涵洞等)</el-menu-item>
+            <template #title>自然生态景观</template>
+            <el-menu-item index="1-4-1">湖泊湿地</el-menu-item>
+            <el-menu-item index="1-4-2">森林公园</el-menu-item>
+            <el-menu-item index="1-4-3">地质公园</el-menu-item>
+            <el-menu-item index="1-4-4">海岸带景观</el-menu-item>
           </el-sub-menu>
+          
+          <!-- 5. 模型集与项目 -->
           <el-sub-menu index="1-5">
-            <template #title>堤防与护岸工程</template>
-            <el-menu-item index="1-5-1">防洪堤</el-menu-item>
-            <el-menu-item index="1-5-2">护岸/护坡</el-menu-item>
+            <template #title>模型集与项目</template>
+            <el-menu-item index="1-5-1">待分类模型</el-menu-item>
+            <el-menu-item index="1-5-2">XX市防洪排涝工程</el-menu-item>
           </el-sub-menu>
         </el-sub-menu>
         
-        <!-- 2. 水系与水利设施 (线性与面状水系) -->
+        <!-- 自定义服务 -->
         <el-sub-menu index="2">
           <template #title>
-            <el-icon><Menu /></el-icon>
-            <span>水系水利设施</span>
+            <div @click.stop="handleMenuSelect('2')" style="cursor: pointer; width: 100%; display: flex; align-items: center;">
+              <el-icon><Menu /></el-icon>
+              <span>自定义服务</span>
+            </div>
           </template>
-          <el-sub-menu index="2-1">
-            <template #title>河流</template>
-            <el-menu-item index="2-1-1">河道</el-menu-item>
-            <el-menu-item index="2-1-2">滩地/湿地</el-menu-item>
-          </el-sub-menu>
-          <el-menu-item index="2-2">湖泊与水库水面</el-menu-item>
-          <el-sub-menu index="2-3">
-            <template #title>渠道与输水管道</template>
-            <el-menu-item index="2-3-1">灌溉渠道</el-menu-item>
-            <el-menu-item index="2-3-2">城市供排水管网 (可选)</el-menu-item>
-          </el-sub-menu>
-          <el-sub-menu index="2-4">
-            <template #title>河口与海岸带</template>
-            <el-menu-item index="2-4-1">河口</el-menu-item>
-            <el-menu-item index="2-4-2">海堤/防波堤</el-menu-item>
-          </el-sub-menu>
-        </el-sub-menu>
-        
-        <!-- 3. 地理与环境要素 (基础地理与背景) -->
-        <el-sub-menu index="3">
-          <template #title>
-            <el-icon><Menu /></el-icon>
-            <span>地理环境要素</span>
-          </template>
-          <el-sub-menu index="3-1">
-            <template #title>地形地貌</template>
-            <el-menu-item index="3-1-1">数字高程模型 (DEM)</el-menu-item>
-            <el-menu-item index="3-1-2">地形晕渲图</el-menu-item>
-          </el-sub-menu>
-          <el-sub-menu index="3-2">
-            <template #title>行政区划</template>
-            <el-menu-item index="3-2-1">省级边界</el-menu-item>
-            <el-menu-item index="3-2-2">市级边界</el-menu-item>
-            <el-menu-item index="3-2-3">县级边界</el-menu-item>
-          </el-sub-menu>
-          <el-sub-menu index="3-3">
-            <template #title>重要地物</template>
-            <el-menu-item index="3-3-1">城镇/村庄模型</el-menu-item>
-            <el-menu-item index="3-3-2">交通设施 (桥梁、道路)</el-menu-item>
-            <el-menu-item index="3-3-3">植被覆盖</el-menu-item>
-          </el-sub-menu>
-        </el-sub-menu>
-        
-        <!-- 4. 自然景观与生态 (自然与生态类) -->
-        <el-sub-menu index="4">
-          <template #title>
-            <el-icon><Menu /></el-icon>
-            <span>自然生态景观</span>
-          </template>
-          <el-menu-item index="4-1">湖泊湿地</el-menu-item>
-          <el-menu-item index="4-2">森林公园</el-menu-item>
-          <el-menu-item index="4-3">地质公园</el-menu-item>
-          <el-menu-item index="4-4">海岸带景观</el-menu-item>
-        </el-sub-menu>
-        
-        <!-- 5. 模型集与项目 (管理与组织类) -->
-        <el-sub-menu index="5">
-          <template #title>
-            <el-icon><Menu /></el-icon>
-            <span>模型集与项目</span>
-          </template>
-          <el-menu-item index="5-1">待分类模型</el-menu-item>
-          <el-menu-item index="5-2">XX市防洪排涝工程</el-menu-item>
+          <el-menu-item index="2-1">场景</el-menu-item>
+          <el-menu-item index="2-2">S3M</el-menu-item>
+          <el-menu-item index="2-3">影像</el-menu-item>
+          <el-menu-item index="2-4">地形</el-menu-item>
+          <el-menu-item index="2-5">矢量瓦片</el-menu-item>
         </el-sub-menu>
       </el-menu-item-group>
     </el-menu>
@@ -125,7 +84,7 @@
   <!-- 右侧内容区域 -->
       <section class="right-content">
         <!-- 面包屑导航已移除 -->
-        <component :is="activeComponent" />
+        <ShuiliGongcheng :selected-category="selectedCategory" />
       </section>
 </main>
     <!-- 页面底部 -->
@@ -151,15 +110,17 @@ const JidianShebeiRaw = markRaw(JidianShebei)
 const ShuiliSheshiRaw = markRaw(ShuiliSheshi)
 
 const activeMenu = ref('1')
-const activeMenuName = ref('水利工程')
+const activeMenuName = ref('水利工程模型')
+const selectedCategory = ref(null)
 const activeComponent = ref(ShuiliGongchengRaw)
 
 const handleOpen = (key, keyPath) => {
   console.log('Menu opened:', key, keyPath)
   if (key === '1') {
     activeMenu.value = key
-    activeMenuName.value = '水利工程'
+    activeMenuName.value = '水利工程模型'
     activeComponent.value = ShuiliGongchengRaw
+    selectedCategory.value = null
     console.log('Set active component to ShuiliGongcheng')
   }
 }
@@ -173,27 +134,38 @@ const handleMenuSelect = (key) => {
   activeMenu.value = key
   
   // 根据选择的菜单项更新活动菜单名称和组件
-  if (key.startsWith('1')) {
-    activeMenuName.value = '水利工程实体'
-    activeComponent.value = ShuiliGongchengRaw
-  } else if (key.startsWith('2')) {
-    activeMenuName.value = '水系与水利设施'
-    activeComponent.value = ShuiliSheshiRaw
-  } else if (key.startsWith('3')) {
-    activeMenuName.value = '地理与环境要素'
+  if (key.startsWith('2')) {
+    // 自定义服务及其子菜单
+    activeMenuName.value = '自定义服务'
     activeComponent.value = ShuiliGongchengRaw
-  } else if (key.startsWith('4')) {
-    activeMenuName.value = '自然景观与生态'
-    activeComponent.value = ShuiliSheshiRaw
-  } else if (key.startsWith('5')) {
-    activeMenuName.value = '模型集与项目'
+    selectedCategory.value = key
+  } else if (key.startsWith('1')) {
+    // 水利工程模型及其子菜单
+    if (key === '1') {
+      activeMenuName.value = '水利工程模型'
+      selectedCategory.value = null
+    } else if (key.startsWith('1-1')) {
+      activeMenuName.value = '水利工程实体'
+    } else if (key.startsWith('1-2')) {
+      activeMenuName.value = '水系水利设施'
+    } else if (key.startsWith('1-3')) {
+      activeMenuName.value = '地理环境要素'
+    } else if (key.startsWith('1-4')) {
+      activeMenuName.value = '自然生态景观'
+    } else if (key.startsWith('1-5')) {
+      activeMenuName.value = '模型集与项目'
+    }
     activeComponent.value = ShuiliGongchengRaw
+    // 设置选中的分类,用于筛选模型
+    selectedCategory.value = key
   } else {
-    activeMenuName.value = '水利工程'
+    activeMenuName.value = '水利工程模型'
     activeComponent.value = ShuiliGongchengRaw
+    selectedCategory.value = null
   }
   
   console.log('Active component:', activeComponent.value)
+  console.log('Selected category:', selectedCategory.value)
 }
 
 

File diff ditekan karena terlalu besar
+ 802 - 57
RuoYi-Vue3/src/views/front/content/ShuiliGongcheng.vue


TEMPAT SAMPAH
add_loaded_custom_services.sql


+ 1 - 0
add_loaded_custom_services_dm.sql

@@ -0,0 +1 @@
+ALTER TABLE CESIUM_MAP_CONFIG ADD loaded_custom_services TEXT;

+ 9 - 0
check_service_table.sql

@@ -0,0 +1,9 @@
+-- 检查WATERSHED_SERVICE表的结构
+SELECT column_name, data_type, data_length, char_length, collation_name
+FROM user_tab_columns
+WHERE table_name = 'WATERSHED_SERVICE';
+
+-- 检查数据库的字符集设置
+SELECT parameter, value
+FROM nls_database_parameters
+WHERE parameter IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');

+ 1 - 0
classpath.txt

@@ -0,0 +1 @@
+D:\Web\PlatformModel\ruoyi-admin\lib\yauaa-7.32.0.jar

+ 30 - 0
create_service_table.sql

@@ -0,0 +1,30 @@
+-- ----------------------------
+-- Table structure for watershed_service
+-- ----------------------------
+DROP TABLE IF EXISTS "WATERSHED_SERVICE";
+CREATE TABLE "WATERSHED_SERVICE" (
+  "id" BIGINT NOT NULL IDENTITY(1,1),
+  "name" VARCHAR(100) NOT NULL,
+  "type" VARCHAR(50) NOT NULL,
+  "url" VARCHAR(255) NOT NULL,
+  "token_required" INT DEFAULT 0,
+  "token" VARCHAR(255),
+  "status" VARCHAR(20) NOT NULL DEFAULT 'NORMAL',
+  "created_at" DATETIME,
+  "updated_at" DATETIME,
+  PRIMARY KEY ("id")
+);
+
+-- ----------------------------
+-- Comments for WATERSHED_SERVICE
+-- ----------------------------
+COMMENT ON TABLE "WATERSHED_SERVICE" IS '自定义服务表';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."id" IS '服务ID';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."name" IS '服务名称';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."type" IS '服务类型';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."url" IS '服务URL';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."token_required" IS '是否需要token';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."token" IS '服务token';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."status" IS '服务状态';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."created_at" IS '创建时间';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."updated_at" IS '更新时间';

TEMPAT SAMPAH
ruoyi-admin/CheckCesiumMapConfigDetail.class


+ 49 - 0
ruoyi-admin/CheckCesiumMapConfigDetail.java

@@ -0,0 +1,49 @@
+import java.sql.*;
+
+public class CheckCesiumMapConfigDetail {
+    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 {
+            Class.forName("dm.jdbc.driver.DmDriver");
+            Connection conn = DriverManager.getConnection(url, username, password);
+            Statement stmt = conn.createStatement();
+
+            System.out.println("=== 查询地图配置详细信息 ===");
+            ResultSet rs = stmt.executeQuery(
+                "SELECT config_id, user_id, config_name, base_layer_type, base_layer_name, " +
+                "base_layer_url, terrain_layer_type, terrain_layer_name, terrain_layer_url, " +
+                "web_services, loaded_models, is_default, create_time, update_time " +
+                "FROM WATERSHED.CESIUM_MAP_CONFIG ORDER BY update_time DESC"
+            );
+            
+            while (rs.next()) {
+                System.out.println("\n========================================");
+                System.out.println("配置ID: " + rs.getLong("config_id"));
+                System.out.println("用户ID: " + rs.getLong("user_id"));
+                System.out.println("配置名称: " + rs.getString("config_name"));
+                System.out.println("底图类型: " + rs.getString("base_layer_type"));
+                System.out.println("底图名称: " + rs.getString("base_layer_name"));
+                System.out.println("底图URL: " + rs.getString("base_layer_url"));
+                System.out.println("地形类型: " + rs.getString("terrain_layer_type"));
+                System.out.println("地形名称: " + rs.getString("terrain_layer_name"));
+                System.out.println("地形URL: " + rs.getString("terrain_layer_url"));
+                System.out.println("Web服务配置: " + rs.getString("web_services"));
+                System.out.println("已加载模型配置: " + rs.getString("loaded_models"));
+                System.out.println("是否默认: " + rs.getInt("is_default"));
+                System.out.println("创建时间: " + rs.getTimestamp("create_time"));
+                System.out.println("更新时间: " + rs.getTimestamp("update_time"));
+                System.out.println("========================================");
+            }
+
+            rs.close();
+            stmt.close();
+            conn.close();
+            
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

TEMPAT SAMPAH
ruoyi-admin/CleanCesiumMapConfigData.class


+ 83 - 0
ruoyi-admin/CleanCesiumMapConfigData.java

@@ -0,0 +1,83 @@
+import java.sql.*;
+
+public class CleanCesiumMapConfigData {
+    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 {
+            Class.forName("dm.jdbc.driver.DmDriver");
+            Connection conn = DriverManager.getConnection(url, username, password);
+            Statement stmt = conn.createStatement();
+
+            System.out.println("=== 清理前的数据统计 ===");
+            ResultSet rs1 = stmt.executeQuery("SELECT user_id, COUNT(*) as count FROM WATERSHED.CESIUM_MAP_CONFIG GROUP BY user_id");
+            while (rs1.next()) {
+                System.out.println("用户ID: " + rs1.getLong("user_id") + ", 配置数量: " + rs1.getInt("count"));
+            }
+
+            System.out.println("\n=== 开始清理重复配置 ===");
+            
+            ResultSet rs2 = stmt.executeQuery(
+                "SELECT user_id FROM WATERSHED.CESIUM_MAP_CONFIG GROUP BY user_id HAVING COUNT(*) > 1"
+            );
+            
+            int totalDeleted = 0;
+            while (rs2.next()) {
+                Long userId = rs2.getLong("user_id");
+                
+                System.out.println("\n处理用户ID: " + userId);
+                
+                ResultSet rs3 = stmt.executeQuery(
+                    "SELECT config_id, is_default, update_time FROM WATERSHED.CESIUM_MAP_CONFIG " +
+                    "WHERE user_id = " + userId + " ORDER BY update_time DESC"
+                );
+                
+                java.util.List<Long> idsToDelete = new java.util.ArrayList<>();
+                boolean hasDefault = false;
+                
+                while (rs3.next()) {
+                    Long configId = rs3.getLong("config_id");
+                    int isDefault = rs3.getInt("is_default");
+                    
+                    if (isDefault == 1) {
+                        System.out.println("  保留默认配置: ID=" + configId);
+                        hasDefault = true;
+                    } else {
+                        idsToDelete.add(configId);
+                    }
+                }
+                rs3.close();
+                
+                for (Long configId : idsToDelete) {
+                    int deleteResult = stmt.executeUpdate(
+                        "DELETE FROM WATERSHED.CESIUM_MAP_CONFIG WHERE config_id = " + configId
+                    );
+                    if (deleteResult > 0) {
+                        System.out.println("  删除重复配置: ID=" + configId);
+                        totalDeleted++;
+                    }
+                }
+            }
+            rs2.close();
+
+            System.out.println("\n=== 清理后的数据统计 ===");
+            ResultSet rs4 = stmt.executeQuery("SELECT user_id, COUNT(*) as count FROM WATERSHED.CESIUM_MAP_CONFIG GROUP BY user_id");
+            while (rs4.next()) {
+                System.out.println("用户ID: " + rs4.getLong("user_id") + ", 配置数量: " + rs4.getInt("count"));
+            }
+
+            System.out.println("\n=== 清理完成 ===");
+            System.out.println("总共删除了 " + totalDeleted + " 条重复配置");
+
+            rs1.close();
+            rs4.close();
+            stmt.close();
+            conn.close();
+            
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

TEMPAT SAMPAH
ruoyi-admin/QueryCesiumMapConfigData.class


+ 56 - 0
ruoyi-admin/QueryCesiumMapConfigData.java

@@ -0,0 +1,56 @@
+import java.sql.*;
+
+public class QueryCesiumMapConfigData {
+    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 {
+            Class.forName("dm.jdbc.driver.DmDriver");
+            Connection conn = DriverManager.getConnection(url, username, password);
+            Statement stmt = conn.createStatement();
+
+            System.out.println("=== 查询所有配置数据 ===");
+            ResultSet rs = stmt.executeQuery("SELECT config_id, user_id, config_name, is_default, create_time, update_time FROM WATERSHED.CESIUM_MAP_CONFIG ORDER BY user_id, update_time DESC");
+            
+            while (rs.next()) {
+                System.out.println("ID: " + rs.getLong("config_id") + 
+                    ", 用户ID: " + rs.getLong("user_id") + 
+                    ", 配置名称: " + rs.getString("config_name") + 
+                    ", 是否默认: " + rs.getInt("is_default") + 
+                    ", 创建时间: " + rs.getTimestamp("create_time") + 
+                    ", 更新时间: " + rs.getTimestamp("update_time"));
+            }
+
+            System.out.println("\n=== 统计每个用户的配置数量 ===");
+            ResultSet rs2 = stmt.executeQuery("SELECT user_id, COUNT(*) as count FROM WATERSHED.CESIUM_MAP_CONFIG GROUP BY user_id");
+            
+            while (rs2.next()) {
+                System.out.println("用户ID: " + rs2.getLong("user_id") + ", 配置数量: " + rs2.getInt("count"));
+            }
+
+            System.out.println("\n=== 查找重复配置(同一用户有多条) ===");
+            ResultSet rs3 = stmt.executeQuery("SELECT user_id, COUNT(*) as count FROM WATERSHED.CESIUM_MAP_CONFIG GROUP BY user_id HAVING COUNT(*) > 1");
+            
+            boolean hasDuplicates = false;
+            while (rs3.next()) {
+                hasDuplicates = true;
+                System.out.println("用户ID: " + rs3.getLong("user_id") + ", 重复数量: " + rs3.getInt("count"));
+            }
+            
+            if (!hasDuplicates) {
+                System.out.println("没有发现重复配置");
+            }
+
+            rs.close();
+            rs2.close();
+            rs3.close();
+            stmt.close();
+            conn.close();
+            
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 6 - 0
ruoyi-admin/pom.xml

@@ -80,6 +80,12 @@
             <artifactId>ruoyi-framework</artifactId>
         </dependency>
 
+        <!-- 系统模块-->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-system</artifactId>
+        </dependency>
+
         <!-- 定时任务-->
         <dependency>
             <groupId>com.ruoyi</groupId>

+ 155 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/cesium/CesiumMapConfigController.java

@@ -0,0 +1,155 @@
+package com.ruoyi.web.controller.cesium;
+
+import java.util.List;
+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.common.utils.SecurityUtils;
+import com.ruoyi.system.domain.CesiumMapConfig;
+import com.ruoyi.system.service.ICesiumMapConfigService;
+
+@RestController
+@RequestMapping("/cesium/mapConfig")
+public class CesiumMapConfigController extends BaseController
+{
+    @Autowired
+    private ICesiumMapConfigService cesiumMapConfigService;
+
+    @GetMapping("/default")
+    public AjaxResult getDefaultConfig()
+    {
+        try {
+            Long userId = SecurityUtils.getUserId();
+            CesiumMapConfig config = cesiumMapConfigService.selectDefaultConfigByUserId(userId);
+            return AjaxResult.success(config);
+        } catch (Exception e) {
+            logger.error("获取默认地图配置失败", e);
+            return AjaxResult.error("获取默认地图配置失败: " + e.getMessage());
+        }
+    }
+
+    @GetMapping("/list")
+    public AjaxResult list(CesiumMapConfig cesiumMapConfig)
+    {
+        try {
+            Long userId = SecurityUtils.getUserId();
+            cesiumMapConfig.setUserId(userId);
+            List<CesiumMapConfig> list = cesiumMapConfigService.selectCesiumMapConfigList(cesiumMapConfig);
+            return AjaxResult.success(list);
+        } catch (Exception e) {
+            logger.error("查询地图配置列表失败", e);
+            return AjaxResult.error("查询地图配置列表失败: " + e.getMessage());
+        }
+    }
+
+    @GetMapping("/{configId}")
+    public AjaxResult getInfo(@PathVariable("configId") Long configId)
+    {
+        try {
+            CesiumMapConfig config = cesiumMapConfigService.selectCesiumMapConfigById(configId);
+            return AjaxResult.success(config);
+        } catch (Exception e) {
+            logger.error("获取地图配置详情失败", e);
+            return AjaxResult.error("获取地图配置详情失败: " + e.getMessage());
+        }
+    }
+
+    @PostMapping
+    @Log(title = "地图配置", businessType = BusinessType.UPDATE)
+    public AjaxResult save(@RequestBody CesiumMapConfig cesiumMapConfig)
+    {
+        try {
+            System.out.println("========== Controller 接收到的数据 ==========");
+            System.out.println("terrainLayerType: " + cesiumMapConfig.getTerrainLayerType());
+            System.out.println("terrainLayerName: " + cesiumMapConfig.getTerrainLayerName());
+            System.out.println("terrainLayerUrl: " + cesiumMapConfig.getTerrainLayerUrl());
+            
+            Long userId = SecurityUtils.getUserId();
+            cesiumMapConfig.setUserId(userId);
+            if (cesiumMapConfig.getConfigName() == null || cesiumMapConfig.getConfigName().isEmpty()) {
+                cesiumMapConfig.setConfigName("默认配置");
+            }
+            
+            // 将空字符串转换为 null
+            if (cesiumMapConfig.getBaseLayerType() != null && cesiumMapConfig.getBaseLayerType().isEmpty()) {
+                cesiumMapConfig.setBaseLayerType(null);
+            }
+            if (cesiumMapConfig.getBaseLayerName() != null && cesiumMapConfig.getBaseLayerName().isEmpty()) {
+                cesiumMapConfig.setBaseLayerName(null);
+            }
+            if (cesiumMapConfig.getBaseLayerUrl() != null && cesiumMapConfig.getBaseLayerUrl().isEmpty()) {
+                cesiumMapConfig.setBaseLayerUrl(null);
+            }
+            if (cesiumMapConfig.getTerrainLayerType() != null && cesiumMapConfig.getTerrainLayerType().isEmpty()) {
+                cesiumMapConfig.setTerrainLayerType(null);
+                System.out.println("terrainLayerType 已设置为 null");
+            }
+            if (cesiumMapConfig.getTerrainLayerName() != null && cesiumMapConfig.getTerrainLayerName().isEmpty()) {
+                cesiumMapConfig.setTerrainLayerName(null);
+                System.out.println("terrainLayerName 已设置为 null");
+            }
+            if (cesiumMapConfig.getTerrainLayerUrl() != null && cesiumMapConfig.getTerrainLayerUrl().isEmpty()) {
+                cesiumMapConfig.setTerrainLayerUrl(null);
+                System.out.println("terrainLayerUrl 已设置为 null");
+            }
+            
+            System.out.println("转换后 terrainLayerType: " + cesiumMapConfig.getTerrainLayerType());
+            System.out.println("转换后 terrainLayerName: " + cesiumMapConfig.getTerrainLayerName());
+            System.out.println("转换后 terrainLayerUrl: " + cesiumMapConfig.getTerrainLayerUrl());
+            
+            cesiumMapConfig.setIsDefault(1);
+            cesiumMapConfig.setUpdateBy(SecurityUtils.getUsername());
+            
+            CesiumMapConfig existingConfig = cesiumMapConfigService.selectDefaultConfigByUserId(userId);
+            int result;
+            if (existingConfig != null) {
+                cesiumMapConfig.setConfigId(existingConfig.getConfigId());
+                result = cesiumMapConfigService.updateCesiumMapConfig(cesiumMapConfig);
+            } else {
+                cesiumMapConfig.setCreateBy(SecurityUtils.getUsername());
+                result = cesiumMapConfigService.insertCesiumMapConfig(cesiumMapConfig);
+            }
+            return toAjax(result);
+        } catch (Exception e) {
+            logger.error("保存地图配置失败", e);
+            return AjaxResult.error("保存地图配置失败: " + e.getMessage());
+        }
+    }
+
+    @PutMapping
+    @Log(title = "地图配置", businessType = BusinessType.UPDATE)
+    public AjaxResult edit(@RequestBody CesiumMapConfig cesiumMapConfig)
+    {
+        try {
+            cesiumMapConfig.setUpdateBy(SecurityUtils.getUsername());
+            int result = cesiumMapConfigService.updateCesiumMapConfig(cesiumMapConfig);
+            return toAjax(result);
+        } catch (Exception e) {
+            logger.error("修改地图配置失败", e);
+            return AjaxResult.error("修改地图配置失败: " + e.getMessage());
+        }
+    }
+
+    @DeleteMapping("/{configIds}")
+    @Log(title = "地图配置", businessType = BusinessType.DELETE)
+    public AjaxResult remove(@PathVariable Long[] configIds)
+    {
+        try {
+            int result = cesiumMapConfigService.deleteCesiumMapConfigByIds(configIds);
+            return toAjax(result);
+        } catch (Exception e) {
+            logger.error("删除地图配置失败", e);
+            return AjaxResult.error("删除地图配置失败: " + e.getMessage());
+        }
+    }
+}

+ 21 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java

@@ -140,23 +140,44 @@ public class CommonController
     {
         try
         {
+            log.info("========== 开始下载资源文件 ==========");
+            log.info("请求的资源路径: {}", resource);
+            
             if (!FileUtils.checkAllowDownload(resource))
             {
                 throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
             }
             // 本地资源路径
             String localPath = RuoYiConfig.getProfile();
+            log.info("本地资源路径: {}", localPath);
             // 数据库资源地址
             String downloadPath = localPath + FileUtils.stripPrefix(resource);
+            log.info("最终下载路径: {}", downloadPath);
+            
+            java.io.File file = new java.io.File(downloadPath);
+            log.info("文件是否存在: {}", file.exists());
+            log.info("文件是否可读: {}", file.canRead());
+            log.info("文件大小: {} bytes", file.length());
+            
+            if (!file.exists()) {
+                log.error("文件不存在: {}", downloadPath);
+                throw new Exception("文件不存在: " + downloadPath);
+            }
+            
             // 下载名称
             String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
+            log.info("下载文件名: {}", downloadName);
+            
             response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
             FileUtils.setAttachmentResponseHeader(response, downloadName);
             FileUtils.writeBytes(downloadPath, response.getOutputStream());
+            
+            log.info("文件下载完成");
         }
         catch (Exception e)
         {
             log.error("下载文件失败", e);
+            throw e;
         }
     }
 }

+ 121 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/watershed/WatershedServiceController.java

@@ -0,0 +1,121 @@
+package com.ruoyi.web.controller.watershed;
+
+import java.util.List;
+import java.util.Map;
+import javax.servlet.http.HttpServletResponse;
+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.WatershedService;
+import com.ruoyi.system.service.IWatershedService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 自定义服务Controller
+ * 
+ * @author ruoyi
+ * @date 2026-02-03
+ */
+@RestController
+@RequestMapping("/watershed/service")
+public class WatershedServiceController extends BaseController
+{
+    @Autowired
+    private IWatershedService watershedServiceService;
+
+    /**
+     * 查询自定义服务列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(WatershedService watershedService)
+    {
+        startPage();
+        List<WatershedService> list = watershedServiceService.selectWatershedServiceList(watershedService);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出自定义服务列表
+     */
+    @Log(title = "自定义服务", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, WatershedService watershedService)
+    {
+        List<WatershedService> list = watershedServiceService.selectWatershedServiceList(watershedService);
+        ExcelUtil<WatershedService> util = new ExcelUtil<WatershedService>(WatershedService.class);
+        util.exportExcel(response, list, "自定义服务数据");
+    }
+
+    /**
+     * 获取自定义服务详细信息
+     */
+    @GetMapping(value = "/{serviceId}")
+    public AjaxResult getInfo(@PathVariable("serviceId") Long serviceId)
+    {
+        return success(watershedServiceService.selectWatershedServiceByServiceId(serviceId));
+    }
+
+    /**
+     * 新增自定义服务
+     */
+    @Log(title = "自定义服务", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody Map<String, Object> requestBody)
+    {
+        System.out.println("接收到新增服务请求:");
+        System.out.println("请求体: " + requestBody);
+        
+        // 创建WatershedService对象
+        WatershedService watershedService = new WatershedService();
+        watershedService.setServiceName((String) requestBody.get("name"));
+        watershedService.setServiceType((String) requestBody.get("type"));
+        watershedService.setServiceUrl((String) requestBody.get("url"));
+        watershedService.setTokenRequired((Integer) requestBody.get("tokenRequired"));
+        watershedService.setServiceToken((String) requestBody.get("token"));
+        watershedService.setStatus((String) requestBody.get("status"));
+        
+        System.out.println("服务名称: " + watershedService.getServiceName());
+        System.out.println("服务类型: " + watershedService.getServiceType());
+        System.out.println("服务URL: " + watershedService.getServiceUrl());
+        System.out.println("是否需要token: " + watershedService.getTokenRequired());
+        System.out.println("服务token: " + watershedService.getServiceToken());
+        System.out.println("服务状态: " + watershedService.getStatus());
+        
+        int result = watershedServiceService.insertWatershedService(watershedService);
+        System.out.println("服务保存结果: " + result);
+        
+        return toAjax(result);
+    }
+
+    /**
+     * 修改自定义服务
+     */
+    @Log(title = "自定义服务", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody WatershedService watershedService)
+    {
+        return toAjax(watershedServiceService.updateWatershedService(watershedService));
+    }
+
+    /**
+     * 删除自定义服务
+     */
+    @Log(title = "自定义服务", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{serviceIds}")
+    public AjaxResult remove(@PathVariable Long[] serviceIds)
+    {
+        return toAjax(watershedServiceService.deleteWatershedServiceByServiceIds(serviceIds));
+    }
+}

+ 1 - 1
ruoyi-admin/src/main/resources/application-druid.yml

@@ -6,7 +6,7 @@ spring:
         druid:
             # 主库数据源
             master:
-                url: jdbc:dm://192.168.0.145:30236?charset=utf8
+                url: jdbc:dm://192.168.0.145:30236?charSet=utf8
                 username: WATERSHED
                 password: WaterShed./1224
                 # 初始化脚本

+ 2 - 1
ruoyi-admin/src/main/resources/application.yml

@@ -7,7 +7,8 @@ ruoyi:
   # 版权年份
   copyrightYear: 2025
   # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
-  profile: ruoyi-admin/uploads/models
+  # 相对路径示例(相对于项目根目录)
+  profile: uploads/models
   # 获取ip地址开关
   addressEnabled: false
   # 验证码类型 math 数字计算 char 字符验证

+ 22 - 0
ruoyi-admin/src/main/resources/sql/cesium_map_config.sql

@@ -0,0 +1,22 @@
+-- ----------------------------
+-- Table structure for cesium_map_config
+-- ----------------------------
+CREATE TABLE WATERSHED.CESIUM_MAP_CONFIG (
+  config_id BIGINT IDENTITY(1,1) PRIMARY KEY,
+  user_id BIGINT NOT NULL,
+  config_name VARCHAR(100) DEFAULT '默认配置',
+  base_layer_type VARCHAR(50),
+  base_layer_name VARCHAR(100),
+  base_layer_url VARCHAR(500),
+  terrain_layer_type VARCHAR(50),
+  terrain_layer_name VARCHAR(100),
+  terrain_layer_url VARCHAR(500),
+  web_services CLOB,
+  loaded_models CLOB,
+  is_default INT DEFAULT 0,
+  create_by VARCHAR(64) DEFAULT '',
+  create_time TIMESTAMP,
+  update_by VARCHAR(64) DEFAULT '',
+  update_time TIMESTAMP,
+  remark VARCHAR(500)
+);

+ 27 - 0
ruoyi-admin/src/main/resources/sql/cesium_map_config_comments.sql

@@ -0,0 +1,27 @@
+-- ----------------------------
+-- Comments for CESIUM_MAP_CONFIG
+-- ----------------------------
+COMMENT ON TABLE WATERSHED.CESIUM_MAP_CONFIG IS '地图配置表';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.config_id IS '配置ID';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.user_id IS '用户ID';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.config_name IS '配置名称';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.base_layer_type IS '底图类型';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.base_layer_name IS '底图名称';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.base_layer_url IS '底图URL';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.terrain_layer_type IS '地形类型';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.terrain_layer_name IS '地形名称';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.terrain_layer_url IS '地形URL';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.web_services IS '公共服务配置(JSON格式)';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.loaded_models IS '已加载模型配置(JSON格式)';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.is_default IS '是否默认配置(0否 1是)';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.create_by IS '创建者';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.create_time IS '创建时间';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.update_by IS '更新者';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.update_time IS '更新时间';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.remark IS '备注';
+
+-- ----------------------------
+-- Indexes for CESIUM_MAP_CONFIG
+-- ----------------------------
+CREATE INDEX idx_user_id ON WATERSHED.CESIUM_MAP_CONFIG(user_id);
+CREATE INDEX idx_is_default ON WATERSHED.CESIUM_MAP_CONFIG(is_default);

+ 30 - 0
ruoyi-admin/src/main/resources/sql/create_service_table.sql

@@ -0,0 +1,30 @@
+-- ----------------------------
+-- Table structure for watershed_service
+-- ----------------------------
+DROP TABLE IF EXISTS "WATERSHED_SERVICE";
+CREATE TABLE "WATERSHED_SERVICE" (
+  "id" BIGINT NOT NULL IDENTITY(1,1),
+  "name" VARCHAR(100) NOT NULL,
+  "type" VARCHAR(50) NOT NULL,
+  "url" VARCHAR(255) NOT NULL,
+  "token_required" INT DEFAULT 0,
+  "token" VARCHAR(255),
+  "status" VARCHAR(20) NOT NULL DEFAULT 'NORMAL',
+  "created_at" DATETIME,
+  "updated_at" DATETIME,
+  PRIMARY KEY ("id")
+);
+
+-- ----------------------------
+-- Comments for WATERSHED_SERVICE
+-- ----------------------------
+COMMENT ON TABLE "WATERSHED_SERVICE" IS '自定义服务表';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."id" IS '服务ID';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."name" IS '服务名称';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."type" IS '服务类型';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."url" IS '服务URL';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."token_required" IS '是否需要token';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."token" IS '服务token';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."status" IS '服务状态';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."created_at" IS '创建时间';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."updated_at" IS '更新时间';

+ 1 - 1
ruoyi-admin/target/classes/application-druid.yml

@@ -6,7 +6,7 @@ spring:
         druid:
             # 主库数据源
             master:
-                url: jdbc:dm://192.168.0.145:30236?charset=utf8
+                url: jdbc:dm://192.168.0.145:30236?charSet=utf8
                 username: WATERSHED
                 password: WaterShed./1224
                 # 初始化脚本

+ 2 - 1
ruoyi-admin/target/classes/application.yml

@@ -7,7 +7,8 @@ ruoyi:
   # 版权年份
   copyrightYear: 2025
   # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
-  profile: ruoyi-admin/uploads/models
+  # 相对路径示例(相对于项目根目录)
+  profile: uploads/models
   # 获取ip地址开关
   addressEnabled: false
   # 验证码类型 math 数字计算 char 字符验证

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


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


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


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


+ 22 - 0
ruoyi-admin/target/classes/sql/cesium_map_config.sql

@@ -0,0 +1,22 @@
+-- ----------------------------
+-- Table structure for cesium_map_config
+-- ----------------------------
+CREATE TABLE WATERSHED.CESIUM_MAP_CONFIG (
+  config_id BIGINT IDENTITY(1,1) PRIMARY KEY,
+  user_id BIGINT NOT NULL,
+  config_name VARCHAR(100) DEFAULT '默认配置',
+  base_layer_type VARCHAR(50),
+  base_layer_name VARCHAR(100),
+  base_layer_url VARCHAR(500),
+  terrain_layer_type VARCHAR(50),
+  terrain_layer_name VARCHAR(100),
+  terrain_layer_url VARCHAR(500),
+  web_services CLOB,
+  loaded_models CLOB,
+  is_default INT DEFAULT 0,
+  create_by VARCHAR(64) DEFAULT '',
+  create_time TIMESTAMP,
+  update_by VARCHAR(64) DEFAULT '',
+  update_time TIMESTAMP,
+  remark VARCHAR(500)
+);

+ 27 - 0
ruoyi-admin/target/classes/sql/cesium_map_config_comments.sql

@@ -0,0 +1,27 @@
+-- ----------------------------
+-- Comments for CESIUM_MAP_CONFIG
+-- ----------------------------
+COMMENT ON TABLE WATERSHED.CESIUM_MAP_CONFIG IS '地图配置表';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.config_id IS '配置ID';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.user_id IS '用户ID';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.config_name IS '配置名称';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.base_layer_type IS '底图类型';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.base_layer_name IS '底图名称';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.base_layer_url IS '底图URL';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.terrain_layer_type IS '地形类型';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.terrain_layer_name IS '地形名称';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.terrain_layer_url IS '地形URL';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.web_services IS '公共服务配置(JSON格式)';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.loaded_models IS '已加载模型配置(JSON格式)';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.is_default IS '是否默认配置(0否 1是)';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.create_by IS '创建者';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.create_time IS '创建时间';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.update_by IS '更新者';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.update_time IS '更新时间';
+COMMENT ON COLUMN WATERSHED.CESIUM_MAP_CONFIG.remark IS '备注';
+
+-- ----------------------------
+-- Indexes for CESIUM_MAP_CONFIG
+-- ----------------------------
+CREATE INDEX idx_user_id ON WATERSHED.CESIUM_MAP_CONFIG(user_id);
+CREATE INDEX idx_is_default ON WATERSHED.CESIUM_MAP_CONFIG(is_default);

+ 30 - 0
ruoyi-admin/target/classes/sql/create_service_table.sql

@@ -0,0 +1,30 @@
+-- ----------------------------
+-- Table structure for watershed_service
+-- ----------------------------
+DROP TABLE IF EXISTS "WATERSHED_SERVICE";
+CREATE TABLE "WATERSHED_SERVICE" (
+  "id" BIGINT NOT NULL IDENTITY(1,1),
+  "name" VARCHAR(100) NOT NULL,
+  "type" VARCHAR(50) NOT NULL,
+  "url" VARCHAR(255) NOT NULL,
+  "token_required" INT DEFAULT 0,
+  "token" VARCHAR(255),
+  "status" VARCHAR(20) NOT NULL DEFAULT 'NORMAL',
+  "created_at" DATETIME,
+  "updated_at" DATETIME,
+  PRIMARY KEY ("id")
+);
+
+-- ----------------------------
+-- Comments for WATERSHED_SERVICE
+-- ----------------------------
+COMMENT ON TABLE "WATERSHED_SERVICE" IS '自定义服务表';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."id" IS '服务ID';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."name" IS '服务名称';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."type" IS '服务类型';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."url" IS '服务URL';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."token_required" IS '是否需要token';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."token" IS '服务token';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."status" IS '服务状态';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."created_at" IS '创建时间';
+COMMENT ON COLUMN "WATERSHED_SERVICE"."updated_at" IS '更新时间';

+ 2 - 0
ruoyi-admin/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst

@@ -1,4 +1,5 @@
 com\ruoyi\RuoYiServletInitializer.class
+com\ruoyi\web\controller\watershed\WatershedServiceController.class
 com\ruoyi\web\controller\common\CaptchaController.class
 com\ruoyi\web\controller\system\SysDictDataController.class
 com\ruoyi\web\controller\monitor\SysOperlogController.class
@@ -16,6 +17,7 @@ com\ruoyi\web\controller\system\SysLoginController.class
 com\ruoyi\web\controller\monitor\CacheController.class
 com\ruoyi\web\controller\system\SysNoticeController.class
 com\ruoyi\web\controller\system\SysDictTypeController.class
+com\ruoyi\web\controller\cesium\CesiumMapConfigController.class
 com\ruoyi\web\controller\system\SysProfileController.class
 com\ruoyi\web\controller\system\SysDeptController.class
 com\ruoyi\web\controller\system\SysConfigController.class

+ 27 - 25
ruoyi-admin/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst

@@ -1,25 +1,27 @@
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\common\CommonController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysConfigController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\tool\TestController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysNoticeController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysProfileController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\monitor\SysUserOnlineController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\common\CaptchaController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysLoginController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\watershed\WatershedModelController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysDeptController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysRoleController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\monitor\CacheController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysDictDataController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysRegisterController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysPostController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\monitor\SysLogininforController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysIndexController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\RuoYiServletInitializer.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\monitor\SysOperlogController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysUserController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysMenuController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\monitor\ServerController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\RuoYiApplication.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysDictTypeController.java
-D:\VUEobject\FujianModelPlatform\ruoyi-admin\src\main\java\com\ruoyi\web\core\config\SwaggerConfig.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\watershed\WatershedServiceController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\common\CaptchaController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\common\CommonController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysRoleController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysMenuController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\monitor\ServerController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\monitor\SysUserOnlineController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysProfileController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\monitor\CacheController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysIndexController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysDictDataController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysRegisterController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\RuoYiApplication.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysUserController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\core\config\SwaggerConfig.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysNoticeController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\cesium\CesiumMapConfigController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\monitor\SysOperlogController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\watershed\WatershedModelController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\monitor\SysLogininforController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysDeptController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysLoginController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysConfigController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysDictTypeController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\RuoYiServletInitializer.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\tool\TestController.java
+D:\Web\PlatformModel\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysPostController.java

TEMPAT SAMPAH
ruoyi-admin/target/ruoyi-admin.jar


TEMPAT SAMPAH
ruoyi-admin/target/ruoyi-admin.jar.original


+ 0 - 0
ruoyi-admin/target/ruoyi-admin/uploads/models/2026/01/22/北斗_20260122153214A003.glb → ruoyi-admin/uploads/models/2026/02/03/北斗_20260203110406A001.glb


TEMPAT SAMPAH
ruoyi-admin/uploads/models/2026/02/03/北斗_20260203110431A002.glb


+ 0 - 0
ruoyi-admin/target/ruoyi-admin/uploads/models/2026/01/22/救生器材箱_20260122165132A004.glb → ruoyi-admin/uploads/models/2026/02/03/救生器材箱_20260203110641A006.glb


+ 0 - 0
ruoyi-admin/target/ruoyi-admin/uploads/models/2026/01/22/断面桩_20260122165734A005.glb → ruoyi-admin/uploads/models/2026/02/03/断面桩_20260203110545A004.glb


+ 0 - 0
ruoyi-admin/target/ruoyi-admin/uploads/models/2026/01/22/氨氮仪器_20260122170557A009.glb → ruoyi-admin/uploads/models/2026/02/03/氨氮仪器_20260203110605A005.glb


TEMPAT SAMPAH
ruoyi-admin/uploads/models/2026/02/03/称重式雨量筒_20260203110507A003.glb


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/annotation/Excel$ColumnType.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/annotation/Excel$Type.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/annotation/Excel.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/config/RuoYiConfig.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/constant/CacheConstants.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/constant/Constants.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/constant/GenConstants.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/constant/HttpStatus.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/constant/ScheduleConstants$Status.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/constant/ScheduleConstants.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/constant/UserConstants.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/controller/BaseController$1.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/controller/BaseController.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/domain/AjaxResult.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/domain/BaseEntity.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/domain/R.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/domain/TreeEntity.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/domain/TreeSelect.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/domain/entity/SysDept.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/domain/entity/SysDictData.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/domain/entity/SysDictType.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/domain/entity/SysMenu.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/domain/entity/SysRole.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/domain/entity/SysUser.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/domain/model/LoginBody.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/domain/model/LoginUser.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/domain/model/RegisterBody.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/page/PageDomain.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/page/TableDataInfo.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/page/TableSupport.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/redis/RedisCache.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/text/CharsetKit.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/text/Convert.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/core/text/StrFormatter.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/enums/BusinessStatus.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/enums/BusinessType.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/enums/DataSourceType.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/enums/DesensitizedType.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/enums/HttpMethod.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/enums/LimitType.class


TEMPAT SAMPAH
ruoyi-common/target/classes/com/ruoyi/common/enums/OperatorType.class


Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini