Sfoglia il codice sorgente

完成接口编目和说明,基本功能

DESKTOP-6LTVLN7\Liumouren 1 mese fa
parent
commit
5fc315c38a
3 ha cambiato i file con 256 aggiunte e 82 eliminazioni
  1. 246 68
      src/components/skszk/controlPanel.vue
  2. 2 10
      src/router/index.js
  3. 8 4
      src/utils/request.js

+ 246 - 68
src/components/skszk/controlPanel.vue

@@ -31,8 +31,16 @@
         </div>
       </div>
       <el-divider></el-divider>
-      <div>
-        参数个数:{{
+      <div
+        v-if="
+          SceneValue &&
+          SceneRule[SceneValue] &&
+          (SceneRule[SceneValue].elementTypes.includes('point') ||
+            SceneRule[SceneValue].elementTypes.includes('polyline') ||
+            SceneRule[SceneValue].elementTypes.includes('polygon'))
+        "
+      >
+        元素个数:{{
           SceneValue && SceneRule[SceneValue] ? SceneRule[SceneValue].numberOf : ""
         }}
       </div>
@@ -52,7 +60,67 @@
       <!-- 元素文本渲染和操作区域 -->
       <el-tabs tab-position="left" style="height: calc(100vh - 250px)" class="demo-tabs">
         <el-tab-pane label="入参">
+          <div
+            v-if="
+              SceneValue &&
+              SceneRule[SceneValue] &&
+              SceneRule[SceneValue].elementTypes.includes('file')
+            "
+          >
+            <el-upload
+              v-model:file-list="fileList"
+              class="upload-demo"
+              action=""
+              :limit="1"
+              :on-change="handleFileChange"
+              :on-exceed="handleExceed"
+              :on-remove="uploadRemove"
+              :auto-upload="false"
+            >
+              <el-button type="primary">上传文件</el-button>
+            </el-upload>
+          </div>
+          <div v-if="SceneValue && SceneRule[SceneValue]">
+            <div
+              v-for="item in SceneRule[SceneValue].elementTypes"
+              :key="item"
+              style="margin-top: 0.5rem"
+            >
+              <div
+                v-if="SceneValue && SceneRule[SceneValue] && SceneRule[SceneValue][item]"
+              >
+                {{ item }}:<el-select
+                  v-if="SceneRule[SceneValue][item]"
+                  v-model="params[item]"
+                  :placeholder="'请选择' + item"
+                  style="width: 240px"
+                >
+                  <el-option
+                    v-for="item in SceneRule[SceneValue][item]"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </el-select>
+              </div>
+              <div v-if="['lon', 'lat', 'filePath', 'EPSILON'].includes(item)">
+                {{ item }}:
+                <el-input
+                  v-model="params[item]"
+                  style="width: 240px"
+                  :placeholder="'请输入' + item"
+                />
+              </div>
+            </div>
+          </div>
           <json-viewer
+            v-if="
+              SceneValue &&
+              SceneRule[SceneValue] &&
+              (SceneRule[SceneValue].elementTypes.includes('point') ||
+                SceneRule[SceneValue].elementTypes.includes('polyline') ||
+                SceneRule[SceneValue].elementTypes.includes('polygon'))
+            "
             :value="jsonData"
             :editable="true"
             :preview-mode="false"
@@ -66,8 +134,19 @@
           />
         </el-tab-pane>
         <el-tab-pane label="返回">
+          <div
+            v-if="backData.message || backData.error"
+            :style="{
+              backgroundColor: backData.code === 200 ? '#67C23A' : '#F56C6C',
+              color: '#fff',
+              padding: '5px 10px',
+              fontSize: '14px',
+            }"
+          >
+            {{ backData.message || backData.error }}
+          </div>
           <json-viewer
-            :value="backData"
+            :value="backData.content"
             :editable="true"
             :preview-mode="false"
             style="
@@ -80,7 +159,16 @@
       </el-tabs>
     </div>
     <!-- 绘制工具栏 -->
-    <div class="toolbar">
+    <div
+      class="toolbar"
+      v-if="
+        SceneValue &&
+        SceneRule[SceneValue] &&
+        (SceneRule[SceneValue].elementTypes.includes('point') ||
+          SceneRule[SceneValue].elementTypes.includes('polyline') ||
+          SceneRule[SceneValue].elementTypes.includes('polygon'))
+      "
+    >
       <div
         class="tool-item"
         @click="activateDraw('point')"
@@ -129,6 +217,17 @@ export default {
   },
   data() {
     return {
+      currentFile: null, // 当前选中的文件
+      fileList: [],
+      // 其他参数
+      params: {
+        unit: "",
+        outFileType: "",
+        outPrj: "",
+        inPrj: "",
+        lon: "",
+        lat: "",
+      },
       // 请求参数
       jsonData: {},
       // 返回参数
@@ -294,7 +393,7 @@ export default {
           functionalDefinition:
             "计算两个点要素之间的最短空间距离,单位支持米、千米。操作逻辑为:用户通过接口输入两点经纬度坐标,或在系统内部地图上点击选择两点,系统基于坐标系参数计算欧氏距离。例如:计算青浦区某学校与社区卫生服务中心的直线距离,用于公共服务覆盖半径评估;计算两个监测点位的直线距离,用于监测设备信号覆盖范围判断。",
           // 元素类型
-          elementTypes: ["point", "point"],
+          elementTypes: ["point", "point", "unit"],
           // 单位
           unit: [
             {
@@ -315,7 +414,7 @@ export default {
           // 功能描述
           functionalDefinition: "计算点和线要素之间的最短空间距离,单位支持米、千米",
           // 元素类型
-          elementTypes: ["point", "polyline"],
+          elementTypes: ["point", "polyline", "unit"],
           // 单位
           unit: [
             {
@@ -336,7 +435,7 @@ export default {
           // 功能描述
           functionalDefinition: "计算点和面要素之间的最短空间距离,单位支持米、千米",
           // 元素类型
-          elementTypes: ["point", "polygon"],
+          elementTypes: ["point", "polygon", "unit"],
           // 单位
           unit: [
             {
@@ -357,7 +456,7 @@ export default {
           // 功能描述
           functionalDefinition: "计算两个面要素之间的最短空间距离,单位支持米、千米",
           // 元素类型
-          elementTypes: ["polygon", "polygon"],
+          elementTypes: ["polygon", "polygon", "unit"],
           // 单位
           unit: [
             {
@@ -378,7 +477,7 @@ export default {
           // 功能描述
           functionalDefinition: "计算多条线段组成的折线总长度,单位支持米、千米",
           // 元素类型
-          elementTypes: ["polyline"],
+          elementTypes: ["polyline", "unit"],
           // 单位
           unit: [
             {
@@ -400,7 +499,7 @@ export default {
           functionalDefinition:
             "计算面要素在二维平面上的投影面积,单位支持平方米、公顷、平方千米切换",
           // 元素类型
-          elementTypes: ["polygon"],
+          elementTypes: ["polygon", "unit"],
           // 单位
           unit: [
             {
@@ -426,7 +525,7 @@ export default {
           functionalDefinition:
             "结合 DEM 高程数据,计算面要素在三维地形上的实际曲面面积(考虑地形起伏),精度依赖 DEM 数据分辨率。,单位支持平方米、公顷、平方千米切换",
           // 元素类型
-          elementTypes: ["polygon"],
+          elementTypes: ["polygon", "unit"],
           // 单位
           unit: [
             {
@@ -529,7 +628,7 @@ export default {
           functionalDefinition:
             "判断两个面要素是否 “边界接触但不重叠”,且距离小于等于自定义阈值(默认 1 米,可通过接口参数调整),核心用于 “相邻区域联动” 场景",
           // 元素类型
-          elementTypes: ["polygon", "polygon"],
+          elementTypes: ["polygon", "polygon", "EPSILON"],
           // 元素个数
           numberOf: 2,
           // 后台接口路径
@@ -540,7 +639,7 @@ export default {
           functionalDefinition:
             "判断一个要素(含点、线、面)是否完全位于另一个面要素内部,且无任何部分超出,核心用于 “归属界定” 场景",
           // 元素类型
-          elementTypes: ["point", "polyline", "polygon"],
+          elementTypes: ["point", "polyline", "polygon", "EPSILON"],
           // 元素个数
           numberOf: 2,
           // 后台接口路径
@@ -551,7 +650,7 @@ export default {
           functionalDefinition:
             "判断两个要素(点与线、点与面、线与线、线与面、面与面)是否存在空间重叠(含部分重叠),核心用于 “交叉影响” 场景",
           // 元素类型
-          elementTypes: ["point", "polyline", "polygon"],
+          elementTypes: ["point", "polyline", "polygon", "EPSILON"],
           // 元素个数
           numberOf: 2,
           // 后台接口路径
@@ -562,7 +661,7 @@ export default {
           functionalDefinition:
             "判断两个要素(点、线、面)之间无任何空间接触(含边界接触),且最小距离大于自定义阈值(默认 10 米,可通过接口参数调整),核心用于 “无关联排除” 场景",
           // 元素类型
-          elementTypes: ["point", "polyline", "polygon"],
+          elementTypes: ["point", "polyline", "polygon", "EPSILON"],
           // 元素个数
           numberOf: 2,
           // 后台接口路径
@@ -573,7 +672,7 @@ export default {
           functionalDefinition:
             "以一个核心要素(点、线、面)为中心,按自定义半径(如 500 米、1 千米)划定范围,查询范围内所有目标要素(如设施、地块、道路),核心用于 “资源覆盖范围” 场景。​",
           // 元素类型
-          elementTypes: ["point", "polyline", "polygon"],
+          elementTypes: ["point", "polyline", "polygon", "EPSILON"],
           // 元素个数
           numberOf: 2,
           // 后台接口路径
@@ -595,7 +694,7 @@ export default {
           functionalDefinition:
             "坐标转换是基于青浦区三维数字底板的坐标系统(SH2000投影坐标系),将空间要素的坐标在不同坐标系之间进行转换的功能,包括地理坐标系(如 WGS84、上海 2000 等)和投影坐标系(如高斯 - 克吕格投影、UTM 投影等)",
           // 元素类型
-          elementTypes: ["lon", "lat"],
+          elementTypes: ["lon", "lat", "inPrj", "outPrj"],
           inPrj: [
             {
               value: "WGS84",
@@ -662,7 +761,7 @@ export default {
           // 功能描述
           functionalDefinition: "转换文件下载",
           // 元素类型
-          elementTypes: [],
+          elementTypes: ["filePath"],
           // 元素个数
           numberOf: 0,
           // 后台接口路径
@@ -693,12 +792,29 @@ export default {
     }
   },
   methods: {
+    handleExceed(file) {
+      this.$message({
+        message: "最多只能上传一个文件",
+        type: "warning",
+      });
+    },
+    handleFileChange(file, fileList) {
+      this.currentFile = file; // 注意:Element UI Plus 无需 .raw
+    },
+    uploadRemove() {
+      this.currentFile = null;
+    },
     handleJsonInput(value) {
       this.jsonData = JSON.parse(value);
     },
     handleChange(emit) {
+      this.params.unit = "";
+      this.currentFile = null;
+      // 清除所有地图中的元素
+      this.clearAll();
+      this.jsonData = {};
+      this.backData = {};
       this.SceneValue = emit[emit.length - 1];
-      console.log(emit, this.SceneValue);
     },
     // 初始化绘制处理器
     initDrawHandler() {
@@ -710,23 +826,18 @@ export default {
     activateDraw(type) {
       // 取消镂空绘制模式
       this.isDrawingHole = false;
-
       // 如果已经是当前激活的工具,则取消激活
       if (this.currentTool === type) {
         this.deactivateDraw();
         return;
       }
-
       // 先取消之前的绘制模式
       this.deactivateDraw();
-
       // 设置当前工具
       this.currentTool = type;
       this.drawingMode = type;
-
       // 重置当前绘制状态
       this.resetDrawingState();
-
       switch (type) {
         case "point":
           this.drawPoint();
@@ -747,6 +858,7 @@ export default {
       // 移除临时预览实体
       if (this.tempEntity) {
         viewer.entities.remove(this.tempEntity);
+        viewer.scene.requestRender();
         this.tempEntity = null;
       }
     },
@@ -759,7 +871,6 @@ export default {
         this.handler.removeInputAction(SkyScenery.ScreenSpaceEventType.MOUSE_MOVE);
         this.handler.removeInputAction(SkyScenery.ScreenSpaceEventType.RIGHT_CLICK);
       }
-
       // 重置状态
       this.resetDrawingState();
       this.currentTool = null;
@@ -773,12 +884,10 @@ export default {
       this.handler.setInputAction(function (event) {
         const ray = viewer.camera.getPickRay(event.position);
         const position = viewer.scene.globe.pick(ray, viewer.scene);
-
         if (position) {
           const cartographic = SkyScenery.Cartographic.fromCartesian(position);
           const longitude = SkyScenery.Math.toDegrees(cartographic.longitude);
           const latitude = SkyScenery.Math.toDegrees(cartographic.latitude);
-
           // 创建点实体(实时渲染)
           const entity = viewer.entities.add({
             position: position,
@@ -790,20 +899,16 @@ export default {
               outlineWidth: 2,
             },
           });
-
+          viewer.scene.requestRender();
           that.drawnEntities.push(entity);
-
           // 转换为geometry格式并保存
           const geometry = {
             type: "Point",
             coordinates: [longitude, latitude],
           };
           that.geometries.push(geometry);
-
+          that.changeGeometries();
           console.log("绘制了点:", geometry);
-
-          // 检查是否绘制了两个元素
-          that.checkAndSendGeometries();
         }
       }, SkyScenery.ScreenSpaceEventType.LEFT_CLICK);
     },
@@ -811,7 +916,6 @@ export default {
     // 绘制线
     drawPolyline() {
       const that = this;
-
       // 鼠标移动时更新临时线(实时渲染预览)
       this.handler.setInputAction(function (event) {
         if (that.currentPositions.length > 0) {
@@ -831,6 +935,7 @@ export default {
                   width: 3,
                 },
               });
+              viewer.scene.requestRender();
             } else {
               that.tempEntity.polyline.positions = tempPositions;
             }
@@ -862,6 +967,7 @@ export default {
                 width: 3,
               },
             });
+            viewer.scene.requestRender();
           }
         }
       }, SkyScenery.ScreenSpaceEventType.LEFT_CLICK);
@@ -889,6 +995,7 @@ export default {
           }
 
           that.drawnEntities.push(that.currentEntity);
+          viewer.scene.requestRender();
 
           // 转换为geometry格式并保存
           const coordinates = [];
@@ -905,12 +1012,8 @@ export default {
             coordinates: coordinates,
           };
           that.geometries.push(geometry);
-
+          that.changeGeometries();
           console.log("绘制了线:", geometry);
-
-          // 检查是否绘制了两个元素
-          that.checkAndSendGeometries();
-
           // 取消当前绘制模式
           that.deactivateDraw();
         }
@@ -949,6 +1052,7 @@ export default {
                   outlineWidth: 2,
                 },
               });
+              viewer.scene.requestRender();
             } else {
               that.tempEntity.polygon.hierarchy = new SkyScenery.PolygonHierarchy(
                 tempPositions
@@ -999,6 +1103,7 @@ export default {
                 outlineWidth: 2,
               },
             });
+            viewer.scene.requestRender();
           }
         }
       }, SkyScenery.ScreenSpaceEventType.LEFT_CLICK);
@@ -1007,10 +1112,6 @@ export default {
       this.handler.setInputAction(function () {
         if (that.currentPositions.length > 2) {
           that.finalizePolygonDrawing();
-
-          // 检查是否绘制了两个元素
-          that.checkAndSendGeometries();
-
           // 取消当前绘制模式
           that.deactivateDraw();
         }
@@ -1044,6 +1145,7 @@ export default {
           outlineWidth: 2,
         },
       });
+      viewer.scene.requestRender();
 
       this.drawnEntities.push(this.currentEntity);
 
@@ -1073,7 +1175,7 @@ export default {
       // 保存实体和几何对象的关联
       this.currentEntity.geometryRef = geometry;
       this.geometries.push(geometry);
-
+      this.changeGeometries();
       console.log("绘制了面:", geometry);
     },
 
@@ -1156,6 +1258,7 @@ export default {
                   outlineWidth: 2,
                 },
               });
+              viewer.scene.requestRender();
             } else {
               that.tempEntity.polygon.hierarchy = new SkyScenery.PolygonHierarchy(
                 tempPositions
@@ -1198,6 +1301,7 @@ export default {
       // 移除临时预览实体
       if (this.tempEntity) {
         viewer.entities.remove(this.tempEntity);
+        viewer.scene.requestRender();
         this.tempEntity = null;
       }
 
@@ -1274,7 +1378,6 @@ export default {
           return new SkyScenery.PolygonHierarchy(holePositions);
         });
       }
-
       return hierarchy;
     },
 
@@ -1284,18 +1387,9 @@ export default {
       const distance = SkyScenery.Cartesian3.distance(position, firstPosition);
       return distance < tolerance;
     },
-
-    // 检查是否绘制了两个元素,如果是则调用后台接口
-    checkAndSendGeometries() {
-      if (this.geometries.length >= 2) {
-        console.log("已绘制两个或更多几何元素,准备发送到后台");
-        this.sendGeometriesToBackend();
-      }
-    },
-    // 发送几何数据到后台接口
-    sendGeometriesToBackend() {
-      // 这里使用axios发送请求,需要确保项目中已安装并导入axios
-      const geometriesToSend = this.geometries.slice(0, 2); // 只取前两个几何元素
+    changeGeometries() {
+      let requestData = {};
+      const geometriesToSend = this.geometries;
       let FeatureCollectionFeatures = [];
       geometriesToSend.forEach((item) => {
         FeatureCollectionFeatures.push({
@@ -1308,23 +1402,107 @@ export default {
         });
       });
       // 构造请求数据
-      const requestData = {
+      requestData = {
         type: "FeatureCollection",
         features: FeatureCollectionFeatures,
         timestamp: new Date().getTime(),
       };
-
-      console.log("发送到后台的数据:", requestData);
+      if (
+        this.SceneValue &&
+        this.SceneRule[this.SceneValue] &&
+        this.SceneRule[this.SceneValue].elementTypes &&
+        this.SceneRule[this.SceneValue].elementTypes.includes("unit") &&
+        this.params.unit
+      ) {
+        requestData.unit = this.params.unit;
+      }
+      if (
+        this.SceneValue &&
+        this.SceneRule[this.SceneValue] &&
+        this.SceneRule[this.SceneValue].elementTypes &&
+        this.SceneRule[this.SceneValue].elementTypes.includes("EPSILON") &&
+        this.params.EPSILON
+      ) {
+        requestData.EPSILON = this.params.EPSILON;
+      }
       this.jsonData = requestData;
+      return requestData;
+    },
+    // 发送几何数据到后台接口
+    sendGeometriesToBackend() {
+      // 这里使用axios发送请求,需要确保项目中已安装并导入axios
+      let requestData;
+      let requestUrl = this.SceneRule[this.SceneValue].apiUrl;
+      if (
+        this.SceneRule[this.SceneValue].elementTypes.includes("point") ||
+        this.SceneRule[this.SceneValue].elementTypes.includes("polyline") ||
+        this.SceneRule[this.SceneValue].elementTypes.includes("polygon")
+      ) {
+        requestData = this.changeGeometries();
+      } else {
+        requestData = new FormData();
+        this.SceneRule[this.SceneValue].elementTypes.forEach((key) => {
+          if (key == "file") {
+            if (!this.currentFile) {
+              return this.$message({
+                message: "请选择文件",
+                type: "error",
+              });
+            }
+            requestData.append("file", this.currentFile.raw);
+          } else {
+            requestData.append(key, this.params[key]);
+          }
+        });
+      }
+      let that = this;
       // 实际项目中使用以下代码发送请求
       skszk
-        .topology(this.SceneRule[this.SceneValue].apiUrl, requestData)
+        .topology(requestUrl, requestData)
         .then((res) => {
-          this.backData = res;
-          this.$message({
-            message: res.message,
-            type: "success",
-          });
+          if (requestUrl.indexOf("downloadFile") == -1) {
+            that.backData = res;
+            if (res.code && res.code == 200) {
+              that.$message({
+                message: res.message,
+                type: "success",
+              });
+            } else {
+              that.$message({
+                message: res.content,
+                type: "error",
+              });
+            }
+          } else {
+            const blob = res; // 响应体是 Blob 类型
+            if (!blob) {
+              that.$message.error("下载失败:文件流为空");
+              reject("文件流为空");
+              return;
+            }
+            let _downloadFile = that.params.filePath + "";
+            let fileName = _downloadFile.substring(
+              _downloadFile.indexOf("down_files") + 11
+            );
+            // D:\work\backCode\one_map_portal_server\down_files\0378b1c2e92a4c36ab447f552c0c7888.xlsx
+            // 替换原代码中创建 url 的逻辑,先加校验
+            console.log("blob 类型:", Object.prototype.toString.call(blob)); // 正常应输出 [object Blob]
+            console.log("blob 大小:", blob.size); // 正常应大于 0
+
+            if (!(blob instanceof Blob) || blob.size === 0) {
+              this.$message.error("文件流解析失败,无法生成下载链接");
+              return;
+            }
+            const url = window.URL.createObjectURL(blob); // 将 Blob 转为临时 URL
+            const link = document.createElement("a");
+            link.href = url;
+            link.download = fileName; // 设置下载文件名
+            link.style.display = "none";
+            document.body.appendChild(link);
+            link.click(); // 触发点击下载
+            document.body.removeChild(link);
+            window.URL.revokeObjectURL(url); // 销毁临时 URL,避免内存泄漏
+          }
         })
         .catch((error) => {
           console.error("后台接口调用失败:", error);
@@ -1337,11 +1515,11 @@ export default {
       this.drawnEntities.forEach((entity) => {
         viewer.entities.remove(entity);
       });
-
+      viewer.scene.requestRender();
       // 清空数组
       this.drawnEntities = [];
       this.geometries = [];
-
+      this.changeGeometries();
       // 取消当前绘制模式
       this.deactivateDraw();
 

+ 2 - 10
src/router/index.js

@@ -36,16 +36,8 @@ const routes = [
     path: '/skszk',
     name: 'skszk',
     component: function () {
-      return import('../views/Skszk.vue')
-    },
-    children: [ // 子路由配置开始
-      {
-        path: 'example',
-        component: function () {
-          return import('../views/skszk/Example.vue')
-        },
-      }
-    ], // 子路由配置结束
+      return import('../views/skszk/Example.vue')
+    }
   },
   // 时空门户
   {

+ 8 - 4
src/utils/request.js

@@ -145,17 +145,21 @@ function postform(url, data) {
 }
 function postBody(url, data) {
   return new Promise((resolve, reject) => {
-    service({
+    let params = {
       method: 'POST',
       url,
       data: data,
       headers: {
         'Content-Type': 'application/json;'
       }
-    }).then(res => {
-      resolve(res.data)
+    };
+    if (url.indexOf('downloadFile') != -1) {
+      params.responseType = 'blob';
+    }
+    service(params).then(res => {
+      resolve(res.data);
     }).catch(err => {
-      reject(err)
+      reject(err);
     })
   })
 }