Selaa lähdekoodia

计算工具:新增各种坐标系高斯正算分类下的所有子工具

qyx 1 päivä sitten
vanhempi
commit
d53b312f6b
53 muutettua tiedostoa jossa 8413 lisäystä ja 110 poistoa
  1. 122
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcGaussBandChangeController.java
  2. 1
    1
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcGaussNegativeController.java
  3. 2
    2
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcGaussPositiveController.java
  4. 130
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcGeodeticToSpatialController.java
  5. 128
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcSpatialToGeodeticContoller.java
  6. 118
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcUTMBandChangeContorller.java
  7. 126
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcUTMNegativeController.java
  8. 130
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcUTMPositiveController.java
  9. 207
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcGaussBandChange.java
  10. 8
    20
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcGaussNegative.java
  11. 8
    20
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcGaussPositive.java
  12. 227
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcGeodeticToSpatial.java
  13. 228
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcSpatialToGeodetic.java
  14. 181
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcUTMBandChange.java
  15. 201
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcUTMNegative.java
  16. 222
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcUTMPositive.java
  17. 32
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/ICmcGaussBandChangeService.java
  18. 32
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/ICmcGeodeticToSpatialService.java
  19. 32
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/ICmcSpatialToGeodeticService.java
  20. 32
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/ICmcUTMBandChangeService.java
  21. 35
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/ICmcUTMNegativeService.java
  22. 36
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/ICmcUTMPositiveService.java
  23. 392
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcGaussBandChangeServiceImpl.java
  24. 46
    31
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcGaussNegativeServiceImpl.java
  25. 4
    4
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcGaussPositiveServiceImpl.java
  26. 234
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcGeodeticToSpatialServiceImpl.java
  27. 227
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcSpatialToGeodeticServiceImpl.java
  28. 400
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcUTMBandChangeServicelmpl.java
  29. 340
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcUTMNegativeServiceImpl.java
  30. 336
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcUTMPositiveServiceImpl.java
  31. 125
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcGaussBandChangeTemplate.java
  32. 3
    2
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcGaussNegativeTemplate.java
  33. 10
    9
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcGaussPositiveTemplate.java
  34. 88
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcGeodeticToSpatialTemplate.java
  35. 66
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcSpatialToGeodeticTemplate.java
  36. 101
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcUTMBandChangeTemplate.java
  37. 98
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcUTMNegativeTemplate.java
  38. 109
    0
      oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcUTMPositiveTemplate.java
  39. 42
    0
      oa-ui/src/api/calculate/gaussbandchange.js
  40. 41
    0
      oa-ui/src/api/calculate/geodetictospatial.js
  41. 41
    0
      oa-ui/src/api/calculate/spatialtogeodetic.js
  42. 42
    0
      oa-ui/src/api/calculate/utmbandchange.js
  43. 42
    0
      oa-ui/src/api/calculate/utmnegative.js
  44. 42
    0
      oa-ui/src/api/calculate/utmpositive.js
  45. 88
    10
      oa-ui/src/views/calculate/index.vue
  46. 579
    0
      oa-ui/src/views/calculate/tools/gaussbandchange.vue
  47. 5
    5
      oa-ui/src/views/calculate/tools/gaussnegative.vue
  48. 6
    6
      oa-ui/src/views/calculate/tools/gausspositive.vue
  49. 505
    0
      oa-ui/src/views/calculate/tools/geodetictospatial.vue
  50. 499
    0
      oa-ui/src/views/calculate/tools/spatialtogeodetic.vue
  51. 561
    0
      oa-ui/src/views/calculate/tools/utmbandchange.vue
  52. 548
    0
      oa-ui/src/views/calculate/tools/utmnegative.vue
  53. 555
    0
      oa-ui/src/views/calculate/tools/utmpositive.vue

+ 122
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcGaussBandChangeController.java Näytä tiedosto

@@ -0,0 +1,122 @@
1
+package com.ruoyi.web.calculate.controller;
2
+
3
+import java.util.ArrayList;
4
+import java.util.List;
5
+
6
+import javax.servlet.http.HttpServletResponse;
7
+
8
+import org.springframework.beans.factory.annotation.Autowired;
9
+import org.springframework.web.bind.annotation.PostMapping;
10
+import org.springframework.web.bind.annotation.RequestBody;
11
+import org.springframework.web.bind.annotation.RequestMapping;
12
+import org.springframework.web.bind.annotation.RequestParam;
13
+import org.springframework.web.bind.annotation.RestController;
14
+import org.springframework.web.multipart.MultipartFile;
15
+
16
+import com.ruoyi.common.annotation.Log;
17
+import com.ruoyi.common.core.domain.AjaxResult;
18
+import com.ruoyi.common.enums.BusinessType;
19
+import com.ruoyi.common.utils.poi.ExcelUtil;
20
+import com.ruoyi.web.calculate.domain.CmcGaussBandChange;
21
+import com.ruoyi.web.calculate.service.ICmcGaussBandChangeService;
22
+import com.ruoyi.web.calculate.vo.CmcGaussBandChangeTemplate;
23
+
24
+@RestController
25
+@RequestMapping("/calculate/gaussBandChange")
26
+public class CmcGaussBandChangeController {
27
+
28
+    @Autowired
29
+    private ICmcGaussBandChangeService cmcGaussBandChangeService;
30
+
31
+    /**
32
+     * 导入Excel数据
33
+     */
34
+    @PostMapping("/import")
35
+    public AjaxResult importExcel(@RequestParam("file") MultipartFile file) {
36
+        try {
37
+            // 检查文件是否为空
38
+            if (file.isEmpty()) {
39
+                return AjaxResult.error("请选择要导入的文件!");
40
+            }
41
+
42
+            // 检查文件格式
43
+            String fileName = file.getOriginalFilename();
44
+            if (fileName == null || (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx"))) {
45
+                return AjaxResult.error("请上传Excel文件(.xls或.xlsx格式)!");
46
+            }
47
+
48
+            // 调用Service层解析Excel并返回数据
49
+            return cmcGaussBandChangeService.importExcelData(file);
50
+
51
+        } catch (Exception e) {
52
+            e.printStackTrace();
53
+            return AjaxResult.error("导入失败:" + e.getMessage());
54
+        }
55
+    }
56
+
57
+    /**
58
+     * 导出高斯反算列表
59
+     */
60
+    @Log(title = "高斯换带", businessType = BusinessType.EXPORT)
61
+    @PostMapping("/export")
62
+    public void export(HttpServletResponse response, @RequestBody List<CmcGaussBandChange> dataList) {
63
+        if (dataList == null || dataList.isEmpty()) {
64
+            throw new RuntimeException("没有需要导出的数据");
65
+        }
66
+
67
+        List<CmcGaussBandChange> exportList = new ArrayList<>();
68
+        for (CmcGaussBandChange item : dataList) {
69
+            CmcGaussBandChange exportItem = new CmcGaussBandChange();
70
+            exportItem.setPointNumber(item.getPointNumber());
71
+            exportItem.setCoordinateSystem(item.getCoordinateSystem());
72
+            exportItem.setGaussX(item.getGaussX());
73
+            exportItem.setGaussY(item.getGaussY());
74
+            exportItem.setBand(item.getBand());
75
+            exportItem.setBandwidth(item.getBandwidth());
76
+            exportItem.setNewBand(item.getNewBand());
77
+            exportItem.setNewBandwidth(item.getNewBandwidth());
78
+            exportItem.setLongitudePosition(item.getLongitudePosition());
79
+            exportItem.setLatitudePosition(item.getLatitudePosition());
80
+            exportItem.setNewGaussX(item.getNewGaussX());
81
+            exportItem.setNewGaussY(item.getNewGaussY());
82
+            exportItem.setProjectionHeight(item.getProjectionHeight());
83
+            exportList.add(exportItem);
84
+        }
85
+
86
+        ExcelUtil<CmcGaussBandChange> util = new ExcelUtil<CmcGaussBandChange>(CmcGaussBandChange.class);
87
+        util.exportExcel(response, exportList, "高斯换带结果");
88
+    }
89
+
90
+    /**
91
+     * 执行高斯换带(仅计算,不保存)
92
+     */
93
+    @PostMapping("/calculate")
94
+    public AjaxResult calculate(@RequestBody List<CmcGaussBandChange> dataList) {
95
+        List<CmcGaussBandChange> result = cmcGaussBandChangeService.calculateGaussBandChange(dataList);
96
+        return AjaxResult.success(result);
97
+    }
98
+
99
+    @PostMapping("/template")
100
+    public void downloadTemplate(HttpServletResponse response) {
101
+        List<CmcGaussBandChangeTemplate> templateList = new ArrayList<>();
102
+
103
+        // 添加示例数据
104
+        CmcGaussBandChangeTemplate example = new CmcGaussBandChangeTemplate();
105
+        example.setPointNumber("示例点1");
106
+        example.setCoordinateSystem("WGS84");
107
+        example.setGaussX(3421806.699);
108
+        example.setGaussY(34460881.36);
109
+        example.setBand(1);
110
+        example.setBandwidth(3);
111
+        example.setNewBand(2);
112
+        example.setNewBandwidth(6);
113
+        example.setLongitudePosition("E");
114
+        example.setLatitudePosition("N");
115
+        templateList.add(example);
116
+
117
+        ExcelUtil<CmcGaussBandChangeTemplate> util = new ExcelUtil<CmcGaussBandChangeTemplate>(
118
+                CmcGaussBandChangeTemplate.class);
119
+        util.exportExcel(response, templateList, "高斯换带模板");
120
+    }
121
+
122
+}

+ 1
- 1
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcGaussNegativeController.java Näytä tiedosto

@@ -77,7 +77,7 @@ public class CmcGaussNegativeController
77 77
             exportItem.setLongitudePosition(item.getLongitudePosition());
78 78
             exportItem.setLatitude(item.getLatitude());
79 79
             exportItem.setLatitudePosition(item.getLatitudePosition());
80
-            exportItem.setZone(item.getZone());
80
+            exportItem.setBand(item.getBand());
81 81
             exportItem.setBandwidth(item.getBandwidth());
82 82
             exportItem.setProjectionHeight(item.getProjectionHeight());
83 83
             exportItem.setGaussX(item.getGaussX());

+ 2
- 2
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcGaussPositiveController.java Näytä tiedosto

@@ -86,7 +86,7 @@ public class CmcGaussPositiveController extends BaseController
86 86
             exportItem.setLongitudePosition(item.getLongitudePosition());
87 87
             exportItem.setLatitude(item.getLatitude());
88 88
             exportItem.setLatitudePosition(item.getLatitudePosition());
89
-            exportItem.setZone(item.getZone());
89
+            exportItem.setBand(item.getBand());
90 90
             exportItem.setBandwidth(item.getBandwidth());
91 91
             exportItem.setProjectionHeight(item.getProjectionHeight());
92 92
             exportItem.setGaussX(item.getGaussX());
@@ -121,7 +121,7 @@ public class CmcGaussPositiveController extends BaseController
121 121
         example.setLongitudePosition("E");
122 122
         example.setLatitude(29.29315636);
123 123
         example.setLatitudePosition("N");
124
-        example.setZone(35);
124
+        example.setBand(35);
125 125
         example.setBandwidth(3);
126 126
         templateList.add(example);
127 127
 

+ 130
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcGeodeticToSpatialController.java Näytä tiedosto

@@ -0,0 +1,130 @@
1
+package com.ruoyi.web.calculate.controller;
2
+
3
+import java.util.ArrayList;
4
+import java.util.List;
5
+import javax.servlet.http.HttpServletResponse;
6
+
7
+import org.springframework.beans.factory.annotation.Autowired;
8
+import org.springframework.web.bind.annotation.GetMapping;
9
+import org.springframework.web.bind.annotation.PostMapping;
10
+import org.springframework.web.bind.annotation.PutMapping;
11
+import org.springframework.web.bind.annotation.DeleteMapping;
12
+import org.springframework.web.bind.annotation.PathVariable;
13
+import org.springframework.web.bind.annotation.RequestBody;
14
+import org.springframework.web.bind.annotation.RequestMapping;
15
+import org.springframework.web.bind.annotation.RequestParam;
16
+import org.springframework.web.bind.annotation.RestController;
17
+import org.springframework.web.multipart.MultipartFile;
18
+
19
+import com.ruoyi.common.annotation.Log;
20
+import com.ruoyi.common.core.controller.BaseController;
21
+import com.ruoyi.common.core.domain.AjaxResult;
22
+import com.ruoyi.common.enums.BusinessType;
23
+import com.ruoyi.web.calculate.domain.CmcGeodeticToSpatial;
24
+import com.ruoyi.web.calculate.service.ICmcGeodeticToSpatialService;
25
+import com.ruoyi.web.calculate.vo.CmcGeodeticToSpatialTemplate;
26
+import com.ruoyi.common.utils.poi.ExcelUtil;
27
+import com.ruoyi.common.core.page.TableDataInfo;
28
+
29
+/**
30
+ * 大地坐标转空间直角坐标 Controller
31
+ * 
32
+ * @author ruoyi
33
+ * @date 2026-06-09
34
+ */
35
+@RestController
36
+@RequestMapping("/calculate/geodeticToSpatial")
37
+public class CmcGeodeticToSpatialController extends BaseController
38
+{
39
+    @Autowired
40
+    private ICmcGeodeticToSpatialService cmcGeodeticToSpatialService;
41
+
42
+    /**
43
+     * 导入 Excel 数据
44
+     */
45
+    @PostMapping("/import")
46
+    public AjaxResult importExcel(@RequestParam("file") MultipartFile file)
47
+    {
48
+        try {
49
+            // 检查文件是否为空
50
+            if (file.isEmpty()) {
51
+                return AjaxResult.error("请选择要导入的文件!");
52
+            }
53
+
54
+            // 检查文件格式
55
+            String fileName = file.getOriginalFilename();
56
+            if (fileName == null || (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx"))) {
57
+                return AjaxResult.error("请上传 Excel 文件(.xls 或.xlsx 格式)!");
58
+            }
59
+
60
+            // 调用 Service 层解析 Excel 并返回数据
61
+            return cmcGeodeticToSpatialService.importExcelData(file);
62
+
63
+        } catch (Exception e) {
64
+            e.printStackTrace();
65
+            return AjaxResult.error("导入失败:" + e.getMessage());
66
+        }
67
+    }
68
+
69
+    /**
70
+     * 导出大地坐标转空间坐标列表
71
+     */
72
+    @Log(title = "大地坐标转空间坐标", businessType = BusinessType.EXPORT)
73
+    @PostMapping("/export")
74
+    public void export(HttpServletResponse response, @RequestBody List<CmcGeodeticToSpatial> dataList)
75
+    {
76
+        if (dataList == null || dataList.isEmpty()) {
77
+            throw new RuntimeException("没有需要导出的数据");
78
+        }
79
+        
80
+        List<CmcGeodeticToSpatial> exportList = new ArrayList<>();
81
+        for (CmcGeodeticToSpatial item : dataList) {
82
+            CmcGeodeticToSpatial exportItem = new CmcGeodeticToSpatial();
83
+            exportItem.setPointNumber(item.getPointNumber());
84
+            exportItem.setCoordinateSystem(item.getCoordinateSystem());
85
+            exportItem.setLongitude(item.getLongitude());
86
+            exportItem.setLongitudePosition(item.getLongitudePosition());
87
+            exportItem.setLatitude(item.getLatitude());
88
+            exportItem.setLatitudePosition(item.getLatitudePosition());
89
+            exportItem.setHeight(item.getHeight());
90
+            exportItem.setSpatialX(item.getSpatialX());
91
+            exportItem.setSpatialY(item.getSpatialY());
92
+            exportItem.setSpatialZ(item.getSpatialZ());
93
+            exportItem.setProjectionHeight(item.getProjectionHeight());
94
+            exportList.add(exportItem);
95
+        }
96
+        
97
+        ExcelUtil<CmcGeodeticToSpatial> util = new ExcelUtil<CmcGeodeticToSpatial>(CmcGeodeticToSpatial.class);
98
+        util.exportExcel(response, exportList, "大地坐标转空间坐标结果");
99
+    }
100
+
101
+    /**
102
+     * 执行大地坐标转空间直角坐标(仅计算,不保存)
103
+     */
104
+    @PostMapping("/calculate")
105
+    public AjaxResult calculate(@RequestBody List<CmcGeodeticToSpatial> dataList)
106
+    {
107
+        List<CmcGeodeticToSpatial> result = cmcGeodeticToSpatialService.calculateGeodeticToSpatial(dataList);
108
+        return success(result);
109
+    }
110
+
111
+    @PostMapping("/template")
112
+    public void downloadTemplate(HttpServletResponse response) {
113
+        List<CmcGeodeticToSpatialTemplate> templateList = new ArrayList<>();
114
+
115
+        // 添加示例数据
116
+        CmcGeodeticToSpatialTemplate example = new CmcGeodeticToSpatialTemplate();
117
+        example.setPointNumber("示例点 1");
118
+        example.setCoordinateSystem("WGS84");
119
+        example.setLongitude(103.3734281951);
120
+        example.setLongitudePosition("E");
121
+        example.setLatitude(29.29315636);
122
+        example.setLatitudePosition("N");
123
+        example.setHeight(500.0);
124
+        templateList.add(example);
125
+
126
+        ExcelUtil<CmcGeodeticToSpatialTemplate> util = new ExcelUtil<CmcGeodeticToSpatialTemplate>(CmcGeodeticToSpatialTemplate.class);
127
+        util.exportExcel(response, templateList, "大地坐标转空间坐标模板");
128
+    }
129
+
130
+}

+ 128
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcSpatialToGeodeticContoller.java Näytä tiedosto

@@ -0,0 +1,128 @@
1
+package com.ruoyi.web.calculate.controller;
2
+
3
+import java.util.ArrayList;
4
+import java.util.List;
5
+import javax.servlet.http.HttpServletResponse;
6
+
7
+import org.springframework.beans.factory.annotation.Autowired;
8
+import org.springframework.web.bind.annotation.GetMapping;
9
+import org.springframework.web.bind.annotation.PostMapping;
10
+import org.springframework.web.bind.annotation.PutMapping;
11
+import org.springframework.web.bind.annotation.DeleteMapping;
12
+import org.springframework.web.bind.annotation.PathVariable;
13
+import org.springframework.web.bind.annotation.RequestBody;
14
+import org.springframework.web.bind.annotation.RequestMapping;
15
+import org.springframework.web.bind.annotation.RequestParam;
16
+import org.springframework.web.bind.annotation.RestController;
17
+import org.springframework.web.multipart.MultipartFile;
18
+
19
+import com.ruoyi.common.annotation.Log;
20
+import com.ruoyi.common.core.controller.BaseController;
21
+import com.ruoyi.common.core.domain.AjaxResult;
22
+import com.ruoyi.common.enums.BusinessType;
23
+import com.ruoyi.web.calculate.domain.CmcSpatialToGeodetic;
24
+import com.ruoyi.web.calculate.service.ICmcSpatialToGeodeticService;
25
+import com.ruoyi.web.calculate.vo.CmcSpatialToGeodeticTemplate;
26
+import com.ruoyi.common.utils.poi.ExcelUtil;
27
+import com.ruoyi.common.core.page.TableDataInfo;
28
+
29
+/**
30
+ * 空间直角坐标转大地坐标 Controller
31
+ * 
32
+ * @author ruoyi
33
+ * @date 2026-06-10
34
+ */
35
+@RestController
36
+@RequestMapping("/calculate/spatialToGeodetic")
37
+public class CmcSpatialToGeodeticContoller extends BaseController
38
+{
39
+    @Autowired
40
+    private ICmcSpatialToGeodeticService cmcSpatialToGeodeticService;
41
+
42
+    /**
43
+     * 导入 Excel 数据
44
+     */
45
+    @PostMapping("/import")
46
+    public AjaxResult importExcel(@RequestParam("file") MultipartFile file)
47
+    {
48
+        try {
49
+            // 检查文件是否为空
50
+            if (file.isEmpty()) {
51
+                return AjaxResult.error("请选择要导入的文件!");
52
+            }
53
+
54
+            // 检查文件格式
55
+            String fileName = file.getOriginalFilename();
56
+            if (fileName == null || (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx"))) {
57
+                return AjaxResult.error("请上传 Excel 文件(.xls 或.xlsx 格式)!");
58
+            }
59
+
60
+            // 调用 Service 层解析 Excel 并返回数据
61
+            return cmcSpatialToGeodeticService.importExcelData(file);
62
+
63
+        } catch (Exception e) {
64
+            e.printStackTrace();
65
+            return AjaxResult.error("导入失败:" + e.getMessage());
66
+        }
67
+    }
68
+
69
+    /**
70
+     * 导出空间直角坐标转大地坐标列表
71
+     */
72
+    @Log(title = "空间直角坐标转大地坐标", businessType = BusinessType.EXPORT)
73
+    @PostMapping("/export")
74
+    public void export(HttpServletResponse response, @RequestBody List<CmcSpatialToGeodetic> dataList)
75
+    {
76
+        if (dataList == null || dataList.isEmpty()) {
77
+            throw new RuntimeException("没有需要导出的数据");
78
+        }
79
+        
80
+        List<CmcSpatialToGeodetic> exportList = new ArrayList<>();
81
+        for (CmcSpatialToGeodetic item : dataList) {
82
+            CmcSpatialToGeodetic exportItem = new CmcSpatialToGeodetic();
83
+            exportItem.setPointNumber(item.getPointNumber());
84
+            exportItem.setCoordinateSystem(item.getCoordinateSystem());
85
+            exportItem.setSpatialX(item.getSpatialX());
86
+            exportItem.setSpatialY(item.getSpatialY());
87
+            exportItem.setSpatialZ(item.getSpatialZ());
88
+            exportItem.setLongitude(item.getLongitude());
89
+            exportItem.setLongitudePosition(item.getLongitudePosition());
90
+            exportItem.setLatitude(item.getLatitude());
91
+            exportItem.setLatitudePosition(item.getLatitudePosition());
92
+            exportItem.setHeight(item.getHeight());
93
+            exportItem.setProjectionHeight(item.getProjectionHeight());
94
+            exportList.add(exportItem);
95
+        }
96
+        
97
+        ExcelUtil<CmcSpatialToGeodetic> util = new ExcelUtil<CmcSpatialToGeodetic>(CmcSpatialToGeodetic.class);
98
+        util.exportExcel(response, exportList, "空间转大地结果");
99
+    }
100
+
101
+    /**
102
+     * 执行空间坐标转大地坐标(仅计算,不保存)
103
+     */
104
+    @PostMapping("/calculate")
105
+    public AjaxResult calculate(@RequestBody List<CmcSpatialToGeodetic> dataList)
106
+    {
107
+        List<CmcSpatialToGeodetic> result = cmcSpatialToGeodeticService.calculateSpatialToGeodetic(dataList);
108
+        return success(result);
109
+    }
110
+
111
+    @PostMapping("/template")
112
+    public void downloadTemplate(HttpServletResponse response) {
113
+        List<CmcSpatialToGeodeticTemplate> templateList = new ArrayList<>();
114
+
115
+        // 添加示例数据
116
+        CmcSpatialToGeodeticTemplate example = new CmcSpatialToGeodeticTemplate();
117
+        example.setPointNumber("示例点 1");
118
+        example.setCoordinateSystem("WGS84");
119
+        example.setSpatialX(-2267767.268);
120
+        example.setSpatialY(4895887.566);
121
+        example.setSpatialZ(3279474.822);
122
+        templateList.add(example);
123
+
124
+        ExcelUtil<CmcSpatialToGeodeticTemplate> util = new ExcelUtil<CmcSpatialToGeodeticTemplate>(CmcSpatialToGeodeticTemplate.class);
125
+        util.exportExcel(response, templateList, "空间转大地模板");
126
+    }
127
+
128
+}

+ 118
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcUTMBandChangeContorller.java Näytä tiedosto

@@ -0,0 +1,118 @@
1
+package com.ruoyi.web.calculate.controller;
2
+
3
+import java.util.ArrayList;
4
+import java.util.List;
5
+
6
+import javax.servlet.http.HttpServletResponse;
7
+
8
+import org.springframework.beans.factory.annotation.Autowired;
9
+import org.springframework.web.bind.annotation.PostMapping;
10
+import org.springframework.web.bind.annotation.RequestBody;
11
+import org.springframework.web.bind.annotation.RequestMapping;
12
+import org.springframework.web.bind.annotation.RequestParam;
13
+import org.springframework.web.bind.annotation.RestController;
14
+import org.springframework.web.multipart.MultipartFile;
15
+
16
+import com.ruoyi.common.annotation.Log;
17
+import com.ruoyi.common.core.domain.AjaxResult;
18
+import com.ruoyi.common.enums.BusinessType;
19
+import com.ruoyi.common.utils.poi.ExcelUtil;
20
+import com.ruoyi.web.calculate.domain.CmcUTMBandChange;
21
+import com.ruoyi.web.calculate.service.ICmcUTMBandChangeService;
22
+import com.ruoyi.web.calculate.vo.CmcUTMBandChangeTemplate;
23
+
24
+@RestController
25
+@RequestMapping("/calculate/utmBandChange")
26
+public class CmcUTMBandChangeContorller {
27
+
28
+    @Autowired
29
+    private ICmcUTMBandChangeService cmcUTMBandChangeService;
30
+
31
+    /**
32
+     * 导入Excel数据
33
+     */
34
+    @PostMapping("/import")
35
+    public AjaxResult importExcel(@RequestParam("file") MultipartFile file) {
36
+        try {
37
+            // 检查文件是否为空
38
+            if (file.isEmpty()) {
39
+                return AjaxResult.error("请选择要导入的文件!");
40
+            }
41
+
42
+            // 检查文件格式
43
+            String fileName = file.getOriginalFilename();
44
+            if (fileName == null || (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx"))) {
45
+                return AjaxResult.error("请上传Excel文件(.xls或.xlsx格式)!");
46
+            }
47
+
48
+            // 调用Service层解析Excel并返回数据
49
+            return cmcUTMBandChangeService.importExcelData(file);
50
+
51
+        } catch (Exception e) {
52
+            e.printStackTrace();
53
+            return AjaxResult.error("导入失败:" + e.getMessage());
54
+        }
55
+    }
56
+
57
+    /**
58
+     * 导出UTM换带列表
59
+     */
60
+    @Log(title = "UTM换带", businessType = BusinessType.EXPORT)
61
+    @PostMapping("/export")
62
+    public void export(HttpServletResponse response, @RequestBody List<CmcUTMBandChange> dataList) {
63
+        if (dataList == null || dataList.isEmpty()) {
64
+            throw new RuntimeException("没有需要导出的数据");
65
+        }
66
+
67
+        List<CmcUTMBandChange> exportList = new ArrayList<>();
68
+        for (CmcUTMBandChange item : dataList) {
69
+            CmcUTMBandChange exportItem = new CmcUTMBandChange();
70
+            exportItem.setPointNumber(item.getPointNumber());
71
+            exportItem.setCoordinateSystem(item.getCoordinateSystem());
72
+            exportItem.setUtmX(item.getUtmX());
73
+            exportItem.setUtmY(item.getUtmY());
74
+            exportItem.setBand(item.getBand());
75
+            exportItem.setNewBand(item.getNewBand());
76
+            exportItem.setLongitudePosition(item.getLongitudePosition());
77
+            exportItem.setLatitudePosition(item.getLatitudePosition());
78
+            exportItem.setNewUtmX(item.getNewUtmX());
79
+            exportItem.setNewUtmY(item.getNewUtmY());
80
+            exportItem.setProjectionHeight(item.getProjectionHeight());
81
+            exportList.add(exportItem);
82
+        }
83
+
84
+        ExcelUtil<CmcUTMBandChange> util = new ExcelUtil<CmcUTMBandChange>(CmcUTMBandChange.class);
85
+        util.exportExcel(response, exportList, "UTM换带结果");
86
+    }
87
+
88
+    /**
89
+     * 执行UTM换带(仅计算,不保存)
90
+     */
91
+    @PostMapping("/calculate")
92
+    public AjaxResult calculate(@RequestBody List<CmcUTMBandChange> dataList) {
93
+        List<CmcUTMBandChange> result = cmcUTMBandChangeService.calculateUTMBandChange(dataList);
94
+        return AjaxResult.success(result);
95
+    }
96
+
97
+    @PostMapping("/template")
98
+    public void downloadTemplate(HttpServletResponse response) {
99
+        List<CmcUTMBandChangeTemplate> templateList = new ArrayList<>();
100
+
101
+        // 添加示例数据
102
+        CmcUTMBandChangeTemplate example = new CmcUTMBandChangeTemplate();
103
+        example.setPointNumber("示例点1");
104
+        example.setCoordinateSystem("WGS84");
105
+        example.setUtmX(3421806.699);
106
+        example.setUtmY(4460881.36);
107
+        example.setBand(49);
108
+        example.setNewBand(50);
109
+        example.setLongitudePosition("E");
110
+        example.setLatitudePosition("N");
111
+        templateList.add(example);
112
+
113
+        ExcelUtil<CmcUTMBandChangeTemplate> util = new ExcelUtil<CmcUTMBandChangeTemplate>(
114
+                CmcUTMBandChangeTemplate.class);
115
+        util.exportExcel(response, templateList, "UTM换带模板");
116
+    }
117
+
118
+}

+ 126
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcUTMNegativeController.java Näytä tiedosto

@@ -0,0 +1,126 @@
1
+package com.ruoyi.web.calculate.controller;
2
+
3
+import java.util.ArrayList;
4
+import java.util.List;
5
+import javax.servlet.http.HttpServletResponse;
6
+
7
+import org.springframework.beans.factory.annotation.Autowired;
8
+import org.springframework.web.bind.annotation.GetMapping;
9
+import org.springframework.web.bind.annotation.PostMapping;
10
+import org.springframework.web.bind.annotation.RequestBody;
11
+import org.springframework.web.bind.annotation.RequestMapping;
12
+import org.springframework.web.bind.annotation.RequestParam;
13
+import org.springframework.web.bind.annotation.RestController;
14
+import org.springframework.web.multipart.MultipartFile;
15
+
16
+import com.ruoyi.common.annotation.Log;
17
+import com.ruoyi.common.core.controller.BaseController;
18
+import com.ruoyi.common.core.domain.AjaxResult;
19
+import com.ruoyi.common.enums.BusinessType;
20
+import com.ruoyi.web.calculate.domain.CmcUTMNegative;
21
+import com.ruoyi.web.calculate.service.ICmcUTMNegativeService;
22
+import com.ruoyi.web.calculate.vo.CmcUTMNegativeTemplate;
23
+import com.ruoyi.common.utils.poi.ExcelUtil;
24
+
25
+/**
26
+ * UTM反算Controller
27
+ * 
28
+ * @author qyx
29
+ * @date 2026-04-21
30
+ */
31
+@RestController
32
+@RequestMapping("/calculate/utmNegative")
33
+public class CmcUTMNegativeController extends BaseController
34
+{
35
+    @Autowired
36
+    private ICmcUTMNegativeService cmcUTMNagativeService;
37
+
38
+     /**
39
+     * 导入Excel数据
40
+     */
41
+    @PostMapping("/import")
42
+    public AjaxResult importExcel(@RequestParam("file") MultipartFile file)
43
+    {
44
+        try {
45
+            // 检查文件是否为空
46
+            if (file.isEmpty()) {
47
+                return AjaxResult.error("请选择要导入的文件!");
48
+            }
49
+
50
+            // 检查文件格式
51
+            String fileName = file.getOriginalFilename();
52
+            if (fileName == null || (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx"))) {
53
+                return AjaxResult.error("请上传Excel文件(.xls或.xlsx格式)!");
54
+            }
55
+
56
+            // 调用Service层解析Excel并返回数据
57
+            return cmcUTMNagativeService.importExcelData(file);
58
+
59
+        } catch (Exception e) {
60
+            e.printStackTrace();
61
+            return AjaxResult.error("导入失败:" + e.getMessage());
62
+        }
63
+    }
64
+
65
+    /**
66
+     * 导出UTM反算列表
67
+     */
68
+    @Log(title = "UTM反算", businessType = BusinessType.EXPORT)
69
+    @PostMapping("/export")
70
+    public void export(HttpServletResponse response, @RequestBody List<CmcUTMNegative> dataList)
71
+    {
72
+        if (dataList == null || dataList.isEmpty()) {
73
+            throw new RuntimeException("没有需要导出的数据");
74
+        }
75
+        
76
+        List<CmcUTMNegative> exportList = new ArrayList<>();
77
+        for (CmcUTMNegative item : dataList) {
78
+            CmcUTMNegative exportItem = new CmcUTMNegative();
79
+            exportItem.setPointNumber(item.getPointNumber());
80
+            exportItem.setCoordinateSystem(item.getCoordinateSystem());
81
+            exportItem.setUtmX(item.getUtmX());
82
+            exportItem.setUtmY(item.getUtmY());
83
+            exportItem.setBand(item.getBand());
84
+            exportItem.setProjectionHeight(item.getProjectionHeight());
85
+            exportItem.setLongitude(item.getLongitude());
86
+            exportItem.setLongitudePosition(item.getLongitudePosition());
87
+            exportItem.setLatitude(item.getLatitude());
88
+            exportItem.setLatitudePosition(item.getLatitudePosition());
89
+            exportList.add(exportItem);
90
+        }
91
+        
92
+        ExcelUtil<CmcUTMNegative> util = new ExcelUtil<CmcUTMNegative>(CmcUTMNegative.class);
93
+        util.exportExcel(response, exportList, "UTM反算结果");
94
+    }
95
+
96
+    /**
97
+     * 执行UTM反算(仅计算,不保存)
98
+     */
99
+    @PostMapping("/calculate")
100
+    public AjaxResult calculate(@RequestBody List<CmcUTMNegative> dataList)
101
+    {
102
+        List<CmcUTMNegative> result = cmcUTMNagativeService.calculateUTMNagative(dataList);
103
+        return success(result);
104
+    }
105
+
106
+    @PostMapping("/template")
107
+    public void downloadTemplate(HttpServletResponse response) {
108
+        List<CmcUTMNegativeTemplate> templateList = new ArrayList<>();
109
+
110
+        // 添加示例数据
111
+        CmcUTMNegativeTemplate example = new CmcUTMNegativeTemplate();
112
+        example.setPointNumber("示例点1");
113
+        example.setCoordinateSystem("WGS84");
114
+        example.setUtmX(500000.1234);
115
+        example.setUtmY(3248765.4321);
116
+        example.setBand(48);
117
+        example.setLongitudePosition("东");
118
+        example.setLatitudePosition("北");
119
+        
120
+        templateList.add(example); // 示例数据
121
+        
122
+        ExcelUtil<CmcUTMNegativeTemplate> util = new ExcelUtil<CmcUTMNegativeTemplate>(CmcUTMNegativeTemplate.class);
123
+        util.exportExcel(response, templateList, "UTM反算模板");
124
+    }
125
+
126
+}

+ 130
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcUTMPositiveController.java Näytä tiedosto

@@ -0,0 +1,130 @@
1
+package com.ruoyi.web.calculate.controller;
2
+
3
+import java.util.ArrayList;
4
+import java.util.List;
5
+import javax.servlet.http.HttpServletResponse;
6
+
7
+import org.springframework.beans.factory.annotation.Autowired;
8
+import org.springframework.web.bind.annotation.GetMapping;
9
+import org.springframework.web.bind.annotation.PostMapping;
10
+import org.springframework.web.bind.annotation.PutMapping;
11
+import org.springframework.web.bind.annotation.DeleteMapping;
12
+import org.springframework.web.bind.annotation.PathVariable;
13
+import org.springframework.web.bind.annotation.RequestBody;
14
+import org.springframework.web.bind.annotation.RequestMapping;
15
+import org.springframework.web.bind.annotation.RequestParam;
16
+import org.springframework.web.bind.annotation.RestController;
17
+import org.springframework.web.multipart.MultipartFile;
18
+
19
+import com.ruoyi.common.annotation.Log;
20
+import com.ruoyi.common.core.controller.BaseController;
21
+import com.ruoyi.common.core.domain.AjaxResult;
22
+import com.ruoyi.common.enums.BusinessType;
23
+import com.ruoyi.web.calculate.domain.CmcUTMPositive;
24
+import com.ruoyi.web.calculate.service.ICmcUTMPositiveService;
25
+import com.ruoyi.web.calculate.vo.CmcUTMPositiveTemplate;
26
+import com.ruoyi.common.utils.poi.ExcelUtil;
27
+import com.ruoyi.common.core.page.TableDataInfo;
28
+
29
+/**
30
+ * UTM正算Controller
31
+ * 
32
+ * @author ruoyi
33
+ * @date 2026-04-21
34
+ */
35
+@RestController
36
+@RequestMapping("/calculate/utmPositive")
37
+public class CmcUTMPositiveController extends BaseController
38
+{
39
+    @Autowired
40
+    private ICmcUTMPositiveService cmcUTMPositiveService;
41
+
42
+     /**
43
+     * 导入Excel数据
44
+     */
45
+    @PostMapping("/import")
46
+    public AjaxResult importExcel(@RequestParam("file") MultipartFile file)
47
+    {
48
+        try {
49
+            // 检查文件是否为空
50
+            if (file.isEmpty()) {
51
+                return AjaxResult.error("请选择要导入的文件!");
52
+            }
53
+
54
+            // 检查文件格式
55
+            String fileName = file.getOriginalFilename();
56
+            if (fileName == null || (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx"))) {
57
+                return AjaxResult.error("请上传Excel文件(.xls或.xlsx格式)!");
58
+            }
59
+
60
+            // 调用Service层解析Excel并返回数据
61
+            return cmcUTMPositiveService.importExcelData(file);
62
+
63
+        } catch (Exception e) {
64
+            e.printStackTrace();
65
+            return AjaxResult.error("导入失败:" + e.getMessage());
66
+        }
67
+    }
68
+
69
+    /**
70
+     * 导出UTM正算列表
71
+     */
72
+    @Log(title = "UTM正算", businessType = BusinessType.EXPORT)
73
+    @PostMapping("/export")
74
+    public void export(HttpServletResponse response, @RequestBody List<CmcUTMPositive> dataList)
75
+    {
76
+        if (dataList == null || dataList.isEmpty()) {
77
+            throw new RuntimeException("没有需要导出的数据");
78
+        }
79
+        
80
+        List<CmcUTMPositive> exportList = new ArrayList<>();
81
+        for (CmcUTMPositive item : dataList) {
82
+            CmcUTMPositive exportItem = new CmcUTMPositive();
83
+            exportItem.setPointNumber(item.getPointNumber());
84
+            exportItem.setCoordinateSystem(item.getCoordinateSystem());
85
+            exportItem.setLongitude(item.getLongitude());
86
+            exportItem.setLongitudePosition(item.getLongitudePosition());
87
+            exportItem.setLatitude(item.getLatitude());
88
+            exportItem.setLatitudePosition(item.getLatitudePosition());
89
+            exportItem.setBand(item.getBand());
90
+            exportItem.setProjectionHeight(item.getProjectionHeight());
91
+            exportItem.setUtmX(item.getUtmX());
92
+            exportItem.setUtmY(item.getUtmY());
93
+            exportItem.setMeridianConvergence(item.getMeridianConvergence());
94
+            exportList.add(exportItem);
95
+        }
96
+        
97
+        ExcelUtil<CmcUTMPositive> util = new ExcelUtil<CmcUTMPositive>(CmcUTMPositive.class);
98
+        util.exportExcel(response, exportList, "UTM正算结果");
99
+    }
100
+
101
+    /**
102
+     * 执行UTM正算(仅计算,不保存)
103
+     */
104
+    @PostMapping("/calculate")
105
+    public AjaxResult calculate(@RequestBody List<CmcUTMPositive> dataList)
106
+    {
107
+        List<CmcUTMPositive> result = cmcUTMPositiveService.calculateUTMPositive(dataList);
108
+        return success(result);
109
+    }
110
+
111
+    @PostMapping("/template")
112
+    public void downloadTemplate(HttpServletResponse response) {
113
+        List<CmcUTMPositiveTemplate> templateList = new ArrayList<>();
114
+
115
+        // 添加示例数据
116
+        CmcUTMPositiveTemplate example = new CmcUTMPositiveTemplate();
117
+        example.setPointNumber("示例点1");
118
+        example.setCoordinateSystem("WGS84");
119
+        example.setLongitude(103.3734281951);
120
+        example.setLongitudePosition("E");
121
+        example.setLatitude(29.29315636);
122
+        example.setLatitudePosition("N");
123
+        example.setBand(48);
124
+        templateList.add(example);
125
+
126
+        ExcelUtil<CmcUTMPositiveTemplate> util = new ExcelUtil<CmcUTMPositiveTemplate>(CmcUTMPositiveTemplate.class);
127
+        util.exportExcel(response, templateList, "UTM正算模板");
128
+    }
129
+
130
+}

+ 207
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcGaussBandChange.java Näytä tiedosto

@@ -0,0 +1,207 @@
1
+package com.ruoyi.web.calculate.domain;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+
6
+import org.apache.commons.lang3.builder.ToStringBuilder;
7
+import org.apache.commons.lang3.builder.ToStringStyle;
8
+import org.springframework.format.annotation.NumberFormat;
9
+
10
+import com.ruoyi.common.annotation.Excel;
11
+import com.ruoyi.common.annotation.Excel.ColumnType;
12
+import com.ruoyi.common.core.domain.BaseEntity;
13
+
14
+public class CmcGaussBandChange extends BaseEntity {
15
+    private static final long serialVersionUID = 1L;
16
+
17
+    /** 主键ID */
18
+    private Long id;
19
+
20
+    /** 待求点号 */
21
+    @Excel(name = "待求点")
22
+    private String pointNumber;
23
+
24
+    /** 坐标系 */
25
+    @Excel(name = "坐标系")
26
+    private String coordinateSystem;
27
+
28
+    /** 高斯坐标x */
29
+    @Excel(name = "高斯坐标x", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
30
+    private Double gaussX;
31
+
32
+    /** 高斯坐标y */
33
+    @Excel(name = "高斯坐标y", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
34
+    private Double gaussY;
35
+
36
+    /** 带号 */
37
+    @Excel(name = "带号", cellType = ColumnType.NUMERIC)
38
+    private double band;
39
+
40
+    /** 带宽 */
41
+    @Excel(name = "带宽", cellType = ColumnType.NUMERIC)
42
+    private Integer bandwidth;
43
+
44
+    /** 新带号 */
45
+    @Excel(name = "新带号", cellType = ColumnType.NUMERIC)
46
+    private double newBand;
47
+
48
+    /** 新带宽 */
49
+    @Excel(name = "新带宽", cellType = ColumnType.NUMERIC)
50
+    private Integer newBandwidth;
51
+
52
+    /** 经度位置 */
53
+    @Excel(name = "经度位置")
54
+    private String longitudePosition;
55
+
56
+    /** 纬度位置 */
57
+    @Excel(name = "纬度位置")
58
+    private String latitudePosition;
59
+
60
+    /** 高斯坐标x */
61
+    @Excel(name = "新高斯坐标x", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
62
+    private Double newGaussX;
63
+
64
+    /** 高斯坐标y */
65
+    @Excel(name = "新高斯坐标y", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
66
+    private Double newGaussY;
67
+
68
+    /** 带宽 */
69
+    @Excel(name = "投影面高程", cellType = ColumnType.NUMERIC)
70
+    private double projectionHeight;
71
+
72
+    public void setId(Long id) {
73
+        this.id = id;
74
+    }
75
+
76
+    public Long getId() {
77
+        return id;
78
+    }
79
+
80
+    public void setPointNumber(String pointNumber) {
81
+        this.pointNumber = pointNumber;
82
+    }
83
+
84
+    public String getPointNumber() {
85
+        return pointNumber;
86
+    }
87
+
88
+    public void setCoordinateSystem(String coordinateSystem) {
89
+        this.coordinateSystem = coordinateSystem;
90
+    }
91
+
92
+    public String getCoordinateSystem() {
93
+        return coordinateSystem;
94
+    }
95
+
96
+    public void setLongitudePosition(String longitudePosition) {
97
+        this.longitudePosition = longitudePosition;
98
+    }
99
+
100
+    public String getLongitudePosition() {
101
+        return longitudePosition;
102
+    }
103
+
104
+    public void setLatitudePosition(String latitudePosition) {
105
+        this.latitudePosition = latitudePosition;
106
+    }
107
+
108
+    public String getLatitudePosition() {
109
+        return latitudePosition;
110
+    }
111
+
112
+    public void setBand(double band) {
113
+        this.band = band;
114
+    }
115
+
116
+    public double getBand() {
117
+        return band;
118
+    }
119
+    
120
+    public void setNewBand(double newBand) {
121
+        this.newBand = newBand;
122
+    }
123
+
124
+    public double getNewBand() {
125
+        return newBand;
126
+    }
127
+
128
+    public void setNewBandwidth(Integer newBandwidth) {
129
+        this.newBandwidth = newBandwidth;
130
+    }
131
+
132
+    public Integer getNewBandwidth() {
133
+        return newBandwidth;
134
+    }
135
+
136
+    public Integer getBandwidth() {
137
+        return bandwidth;
138
+    }
139
+
140
+    public void setBandwidth(Integer bandwidth) {
141
+        this.bandwidth = bandwidth;
142
+    }
143
+    public void setProjectionHeight(double projectionHeight) {
144
+        this.projectionHeight = projectionHeight;
145
+    }
146
+
147
+    public double getProjectionHeight() {
148
+        return projectionHeight;
149
+    }
150
+
151
+    public void setGaussX(Double gaussX) {
152
+        this.gaussX = gaussX;
153
+    }
154
+
155
+    public Double getGaussX() {
156
+        return gaussX;
157
+    }
158
+
159
+    public void setGaussY(Double gaussY) {
160
+        this.gaussY = gaussY;
161
+    }
162
+
163
+    public Double getGaussY() {
164
+        return gaussY;
165
+    }
166
+
167
+    public void setNewGaussX(Double newGaussX) {
168
+        this.newGaussX = newGaussX;
169
+    }
170
+
171
+    public Double getNewGaussX() {
172
+        return newGaussX;
173
+    }
174
+
175
+    public void setNewGaussY(Double newGaussY) {
176
+        this.newGaussY = newGaussY;
177
+    }
178
+
179
+    public Double getNewGaussY() {
180
+        return newGaussY;
181
+    }
182
+
183
+    @Override
184
+    public String toString() {
185
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
186
+                .append("id", getId())
187
+                .append("pointNumber", getPointNumber())
188
+                .append("coordinateSystem", getCoordinateSystem())
189
+                .append("longitudePosition", getLongitudePosition())
190
+                .append("latitudePosition", getLatitudePosition())
191
+                .append("band", getBand())
192
+                .append("bandwidth", getBandwidth())
193
+                .append("gaussX", getGaussX())
194
+                .append("gaussY", getGaussY())
195
+                .append("newBand", getNewBand())
196
+                .append("newBandwidth", getNewBandwidth())
197
+                .append("projectionHeight", getProjectionHeight())
198
+                .append("newGaussX", getNewGaussX())
199
+                .append("newGaussY", getNewGaussY())
200
+                .append("createTime", getCreateTime())
201
+                .append("createBy", getCreateBy())
202
+                .append("updateTime", getUpdateTime())
203
+                .append("updateBy", getUpdateBy())
204
+                .toString();
205
+    }
206
+}
207
+

+ 8
- 20
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcGaussNegative.java Näytä tiedosto

@@ -36,7 +36,7 @@ public class CmcGaussNegative extends BaseEntity {
36 36
     
37 37
     /** 带号 */
38 38
     @Excel(name = "带号", cellType = ColumnType.NUMERIC)
39
-    private Integer zone;
39
+    private Integer band;
40 40
 
41 41
     /** 带宽 */
42 42
     @Excel(name = "带宽", cellType = ColumnType.NUMERIC)
@@ -142,14 +142,14 @@ public class CmcGaussNegative extends BaseEntity {
142 142
         return latitudePosition;
143 143
     }
144 144
     
145
-    public void setZone(Integer zone) 
145
+    public void setBand(Integer band) 
146 146
     {
147
-        this.zone = zone;
147
+        this.band = band;
148 148
     }
149 149
 
150
-    public Integer getZone() 
150
+    public Integer getBand() 
151 151
     {
152
-        return zone;
152
+        return band;
153 153
     }
154 154
     
155 155
     public void setBandwidth(Integer bandwidth) 
@@ -174,13 +174,7 @@ public class CmcGaussNegative extends BaseEntity {
174 174
     
175 175
     public void setGaussX(Double gaussX) 
176 176
     {
177
-        // 高斯X坐标保留4位小数
178
-        if (gaussX != null) {
179
-            BigDecimal bd = new BigDecimal(gaussX);
180
-            this.gaussX = bd.setScale(4, RoundingMode.HALF_UP).doubleValue();
181
-        } else {
182
-            this.gaussX = null;
183
-        }
177
+        this.gaussX = gaussX;
184 178
     }
185 179
 
186 180
     public Double getGaussX() 
@@ -190,13 +184,7 @@ public class CmcGaussNegative extends BaseEntity {
190 184
     
191 185
     public void setGaussY(Double gaussY) 
192 186
     {
193
-        // 高斯Y坐标保留4位小数
194
-        if (gaussY != null) {
195
-            BigDecimal bd = new BigDecimal(gaussY);
196
-            this.gaussY = bd.setScale(4, RoundingMode.HALF_UP).doubleValue();
197
-        } else {
198
-            this.gaussY = null;
199
-        }
187
+        this.gaussY = gaussY;
200 188
     }
201 189
 
202 190
     public Double getGaussY() 
@@ -216,7 +204,7 @@ public class CmcGaussNegative extends BaseEntity {
216 204
             .append("longitudePosition", getLongitudePosition())
217 205
             .append("latitude", getLatitude())
218 206
             .append("latitudePosition", getLatitudePosition())
219
-            .append("zone", getZone())
207
+            .append("band", getBand())
220 208
             .append("bandwidth", getBandwidth())
221 209
             .append("gaussX", getGaussX())
222 210
             .append("gaussY", getGaussY())

+ 8
- 20
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcGaussPositive.java Näytä tiedosto

@@ -48,7 +48,7 @@ public class CmcGaussPositive extends BaseEntity
48 48
 
49 49
     /** 带号 */
50 50
     @Excel(name = "带号", cellType = ColumnType.NUMERIC)
51
-    private Integer zone;
51
+    private Integer band;
52 52
 
53 53
     /** 带宽 */
54 54
     @Excel(name = "带宽", cellType = ColumnType.NUMERIC)
@@ -149,14 +149,14 @@ public class CmcGaussPositive extends BaseEntity
149 149
         return latitudePosition;
150 150
     }
151 151
     
152
-    public void setZone(Integer zone) 
152
+    public void setBand(Integer band) 
153 153
     {
154
-        this.zone = zone;
154
+        this.band = band;
155 155
     }
156 156
 
157
-    public Integer getZone() 
157
+    public Integer getBand() 
158 158
     {
159
-        return zone;
159
+        return band;
160 160
     }
161 161
     
162 162
     public void setBandwidth(Integer bandwidth) 
@@ -181,13 +181,7 @@ public class CmcGaussPositive extends BaseEntity
181 181
     
182 182
     public void setGaussX(Double gaussX) 
183 183
     {
184
-        // 高斯X坐标保留4位小数
185
-        if (gaussX != null) {
186
-            BigDecimal bd = new BigDecimal(gaussX);
187
-            this.gaussX = bd.setScale(4, RoundingMode.HALF_UP).doubleValue();
188
-        } else {
189
-            this.gaussX = null;
190
-        }
184
+        this.gaussX = gaussX;
191 185
     }
192 186
 
193 187
     public Double getGaussX() 
@@ -197,13 +191,7 @@ public class CmcGaussPositive extends BaseEntity
197 191
     
198 192
     public void setGaussY(Double gaussY) 
199 193
     {
200
-        // 高斯Y坐标保留4位小数
201
-        if (gaussY != null) {
202
-            BigDecimal bd = new BigDecimal(gaussY);
203
-            this.gaussY = bd.setScale(4, RoundingMode.HALF_UP).doubleValue();
204
-        } else {
205
-            this.gaussY = null;
206
-        }
194
+        this.gaussY = gaussY;
207 195
     }
208 196
 
209 197
     public Double getGaussY() 
@@ -238,7 +226,7 @@ public class CmcGaussPositive extends BaseEntity
238 226
             .append("longitudePosition", getLongitudePosition())
239 227
             .append("latitude", getLatitude())
240 228
             .append("latitudePosition", getLatitudePosition())
241
-            .append("zone", getZone())
229
+            .append("band", getBand())
242 230
             .append("bandwidth", getBandwidth())
243 231
             .append("gaussX", getGaussX())
244 232
             .append("gaussY", getGaussY())

+ 227
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcGeodeticToSpatial.java Näytä tiedosto

@@ -0,0 +1,227 @@
1
+package com.ruoyi.web.calculate.domain;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+
6
+import org.apache.commons.lang3.builder.ToStringBuilder;
7
+import org.apache.commons.lang3.builder.ToStringStyle;
8
+import com.ruoyi.common.annotation.Excel;
9
+import com.ruoyi.common.annotation.Excel.ColumnType;
10
+import com.ruoyi.common.core.domain.BaseEntity;
11
+
12
+/**
13
+ * 同坐标系中大地坐标转空间坐标
14
+ * 
15
+ * @author qyx
16
+ * @date 2026-06-09
17
+ */
18
+public class CmcGeodeticToSpatial extends BaseEntity
19
+{
20
+    private static final long serialVersionUID = 1L;
21
+
22
+    /** 主键ID */
23
+    private Long id;
24
+
25
+    /** 待求点号 */
26
+    @Excel(name = "待求点")
27
+    private String pointNumber;
28
+
29
+    /** 坐标系 */
30
+    @Excel(name = "坐标系")
31
+    private String coordinateSystem;
32
+
33
+    /** 大地经度 */
34
+    @Excel(name = "大地经度" , cellType = ColumnType.NUMERIC,numberFormat = "0.000000000")
35
+    private Double longitude;
36
+
37
+    /** 经度位置 */
38
+    @Excel(name = "经度位置")
39
+    private String longitudePosition;
40
+
41
+    /** 大地纬度 */
42
+    @Excel(name = "大地纬度", cellType = ColumnType.NUMERIC, numberFormat = "0.000000000")
43
+    private Double latitude;
44
+
45
+    /** 纬度位置 */
46
+    @Excel(name = "纬度位置")
47
+    private String latitudePosition;
48
+
49
+    /** 大地高 */
50
+    @Excel(name = "大地高", cellType = ColumnType.NUMERIC, numberFormat = "0.000")
51
+    private Double height;
52
+
53
+    /** 空间直角坐标X */
54
+    @Excel(name = "空间直角坐标X", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
55
+    private Double spatialX;
56
+
57
+    /** 空间直角坐标Y */
58
+    @Excel(name = "空间直角坐标Y", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
59
+    private Double spatialY;
60
+
61
+    /** 空间直角坐标Z */
62
+    @Excel(name = "空间直角坐标Z", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
63
+    private Double spatialZ;
64
+
65
+    @Excel(name = "投影面高程", cellType = ColumnType.NUMERIC)
66
+    private double projectionHeight;
67
+
68
+    public void setId(Long id) 
69
+    {
70
+        this.id = id;
71
+    }
72
+
73
+    public Long getId() 
74
+    {
75
+        return id;
76
+    }
77
+    
78
+    public void setPointNumber(String pointNumber) 
79
+    {
80
+        this.pointNumber = pointNumber;
81
+    }
82
+
83
+    public String getPointNumber() 
84
+    {
85
+        return pointNumber;
86
+    }
87
+    
88
+    public void setCoordinateSystem(String coordinateSystem) 
89
+    {
90
+        this.coordinateSystem = coordinateSystem;
91
+    }
92
+
93
+    public String getCoordinateSystem() 
94
+    {
95
+        return coordinateSystem;
96
+    }
97
+    
98
+    public void setLongitude(Double longitude) 
99
+    {
100
+        // 大地经度保留10位小数
101
+        if (longitude != null) {
102
+            BigDecimal bd = new BigDecimal(longitude);
103
+            this.longitude = bd.setScale(10, RoundingMode.HALF_UP).doubleValue();
104
+        } else {
105
+            this.longitude = null;
106
+        }
107
+    }
108
+
109
+    public Double getLongitude() 
110
+    {
111
+        return longitude;
112
+    }
113
+    
114
+    public void setLongitudePosition(String longitudePosition) 
115
+    {
116
+        this.longitudePosition = longitudePosition;
117
+    }
118
+
119
+    public String getLongitudePosition() 
120
+    {
121
+        return longitudePosition;
122
+    }
123
+    
124
+    public void setLatitude(Double latitude) 
125
+    {
126
+        // 大地纬度保留10位小数
127
+        if (latitude != null) {
128
+            BigDecimal bd = new BigDecimal(latitude);
129
+            this.latitude = bd.setScale(10, RoundingMode.HALF_UP).doubleValue();
130
+        } else {
131
+            this.latitude = null;
132
+        }
133
+    }
134
+
135
+    public Double getLatitude() 
136
+    {
137
+        return latitude;
138
+    }
139
+    
140
+    public void setLatitudePosition(String latitudePosition) 
141
+    {
142
+        this.latitudePosition = latitudePosition;
143
+    }
144
+
145
+    public String getLatitudePosition() 
146
+    {
147
+        return latitudePosition;
148
+    }
149
+    
150
+    public void setHeight(Double height) 
151
+    {
152
+        // 大地高保留3位小数
153
+        if (height != null) {
154
+            BigDecimal bd = new BigDecimal(height);
155
+            this.height = bd.setScale(3, RoundingMode.HALF_UP).doubleValue();
156
+        } else {
157
+            this.height = null;
158
+        }
159
+    }
160
+
161
+    public Double getHeight() 
162
+    {
163
+        return height;
164
+    }
165
+    
166
+    public void setSpatialX(Double spatialX) 
167
+    {
168
+        this.spatialX = spatialX;
169
+    }
170
+
171
+    public Double getSpatialX() 
172
+    {
173
+        return spatialX;
174
+    }
175
+    
176
+    public void setSpatialY(Double spatialY) 
177
+    {
178
+        this.spatialY = spatialY;
179
+    }
180
+
181
+    public Double getSpatialY() 
182
+    {
183
+        return spatialY;
184
+    }
185
+    
186
+    public void setSpatialZ(Double spatialZ) 
187
+    {
188
+        this.spatialZ = spatialZ;
189
+    }
190
+
191
+    public Double getSpatialZ() 
192
+    {
193
+        return spatialZ;
194
+    }
195
+    
196
+    public void setProjectionHeight(double projectionHeight) 
197
+    {
198
+        this.projectionHeight = projectionHeight;
199
+    }
200
+
201
+    public double getProjectionHeight() 
202
+    {
203
+        return projectionHeight;
204
+    }
205
+
206
+    @Override
207
+    public String toString() {
208
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
209
+            .append("id", getId())
210
+            .append("pointNumber", getPointNumber())
211
+            .append("coordinateSystem", getCoordinateSystem())
212
+            .append("longitude", getLongitude())
213
+            .append("longitudePosition", getLongitudePosition())
214
+            .append("latitude", getLatitude())
215
+            .append("latitudePosition", getLatitudePosition())
216
+            .append("height", getHeight())
217
+            .append("spatialX", getSpatialX())
218
+            .append("spatialY", getSpatialY())
219
+            .append("spatialZ", getSpatialZ())
220
+            .append("projectionHeight", getProjectionHeight())
221
+            .append("createTime", getCreateTime())
222
+            .append("createBy", getCreateBy())
223
+            .append("updateTime", getUpdateTime())
224
+            .append("updateBy", getUpdateBy())
225
+            .toString();
226
+    }
227
+}

+ 228
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcSpatialToGeodetic.java Näytä tiedosto

@@ -0,0 +1,228 @@
1
+package com.ruoyi.web.calculate.domain;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+
6
+import org.apache.commons.lang3.builder.ToStringBuilder;
7
+import org.apache.commons.lang3.builder.ToStringStyle;
8
+import com.ruoyi.common.annotation.Excel;
9
+import com.ruoyi.common.annotation.Excel.ColumnType;
10
+import com.ruoyi.common.core.domain.BaseEntity;
11
+
12
+/**
13
+ * 同坐标系中空间坐标转大地坐标
14
+ * 
15
+ * @author qyx
16
+ * @date 2026-06-10
17
+ */
18
+public class CmcSpatialToGeodetic extends BaseEntity
19
+{
20
+    private static final long serialVersionUID = 1L;
21
+
22
+    /** 主键ID */
23
+    private Long id;
24
+
25
+    /** 待求点号 */
26
+    @Excel(name = "待求点")
27
+    private String pointNumber;
28
+
29
+    /** 坐标系 */
30
+    @Excel(name = "坐标系")
31
+    private String coordinateSystem;
32
+
33
+    /** 空间直角坐标X */
34
+    @Excel(name = "空间坐标X", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
35
+    private Double spatialX;
36
+
37
+    /** 空间直角坐标Y */
38
+    @Excel(name = "空间坐标Y", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
39
+    private Double spatialY;
40
+
41
+    /** 空间直角坐标Z */
42
+    @Excel(name = "空间坐标Z", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
43
+    private Double spatialZ;
44
+
45
+    /** 大地经度 */
46
+    @Excel(name = "大地经度" , cellType = ColumnType.NUMERIC,numberFormat = "0.000000000")
47
+    private Double longitude;
48
+
49
+    /** 经度位置 */
50
+    @Excel(name = "经度位置")
51
+    private String longitudePosition;
52
+
53
+    /** 大地纬度 */
54
+    @Excel(name = "大地纬度", cellType = ColumnType.NUMERIC, numberFormat = "0.000000000")
55
+    private Double latitude;
56
+
57
+    /** 纬度位置 */
58
+    @Excel(name = "纬度位置")
59
+    private String latitudePosition;
60
+
61
+    /** 大地高 */
62
+    @Excel(name = "大地高", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
63
+    private Double height;
64
+
65
+    /** 投影面高程 */
66
+    @Excel(name = "投影面高程", cellType = ColumnType.NUMERIC)
67
+    private double projectionHeight;
68
+
69
+    public void setId(Long id) 
70
+    {
71
+        this.id = id;
72
+    }
73
+
74
+    public Long getId() 
75
+    {
76
+        return id;
77
+    }
78
+    
79
+    public void setPointNumber(String pointNumber) 
80
+    {
81
+        this.pointNumber = pointNumber;
82
+    }
83
+
84
+    public String getPointNumber() 
85
+    {
86
+        return pointNumber;
87
+    }
88
+    
89
+    public void setCoordinateSystem(String coordinateSystem) 
90
+    {
91
+        this.coordinateSystem = coordinateSystem;
92
+    }
93
+
94
+    public String getCoordinateSystem() 
95
+    {
96
+        return coordinateSystem;
97
+    }
98
+    
99
+    public void setSpatialX(Double spatialX) 
100
+    {
101
+        this.spatialX = spatialX;
102
+    }
103
+
104
+    public Double getSpatialX() 
105
+    {
106
+        return spatialX;
107
+    }
108
+    
109
+    public void setSpatialY(Double spatialY) 
110
+    {
111
+        this.spatialY = spatialY;
112
+    }
113
+
114
+    public Double getSpatialY() 
115
+    {
116
+        return spatialY;
117
+    }
118
+    
119
+    public void setSpatialZ(Double spatialZ) 
120
+    {
121
+        this.spatialZ = spatialZ;
122
+    }
123
+
124
+    public Double getSpatialZ() 
125
+    {
126
+        return spatialZ;
127
+    }
128
+    
129
+    public void setLongitude(Double longitude) 
130
+    {
131
+        // 大地经度保留10位小数
132
+        if (longitude != null) {
133
+            BigDecimal bd = new BigDecimal(longitude);
134
+            this.longitude = bd.setScale(10, RoundingMode.HALF_UP).doubleValue();
135
+        } else {
136
+            this.longitude = null;
137
+        }
138
+    }
139
+
140
+    public Double getLongitude() 
141
+    {
142
+        return longitude;
143
+    }
144
+    
145
+    public void setLongitudePosition(String longitudePosition) 
146
+    {
147
+        this.longitudePosition = longitudePosition;
148
+    }
149
+
150
+    public String getLongitudePosition() 
151
+    {
152
+        return longitudePosition;
153
+    }
154
+    
155
+    public void setLatitude(Double latitude) 
156
+    {
157
+        // 大地纬度保留10位小数
158
+        if (latitude != null) {
159
+            BigDecimal bd = new BigDecimal(latitude);
160
+            this.latitude = bd.setScale(10, RoundingMode.HALF_UP).doubleValue();
161
+        } else {
162
+            this.latitude = null;
163
+        }
164
+    }
165
+
166
+    public Double getLatitude() 
167
+    {
168
+        return latitude;
169
+    }
170
+    
171
+    public void setLatitudePosition(String latitudePosition) 
172
+    {
173
+        this.latitudePosition = latitudePosition;
174
+    }
175
+
176
+    public String getLatitudePosition() 
177
+    {
178
+        return latitudePosition;
179
+    }
180
+    
181
+    public void setHeight(Double height) 
182
+    {
183
+        // 大地高保留3位小数
184
+        if (height != null) {
185
+            BigDecimal bd = new BigDecimal(height);
186
+            this.height = bd.setScale(6, RoundingMode.HALF_UP).doubleValue();
187
+        } else {
188
+            this.height = null;
189
+        }
190
+    }
191
+
192
+    public Double getHeight() 
193
+    {
194
+        return height;
195
+    }
196
+    
197
+    public void setProjectionHeight(double projectionHeight) 
198
+    {
199
+        this.projectionHeight = projectionHeight;
200
+    }
201
+
202
+    public double getProjectionHeight() 
203
+    {
204
+        return projectionHeight;
205
+    }
206
+
207
+    @Override
208
+    public String toString() {
209
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
210
+            .append("id", getId())
211
+            .append("pointNumber", getPointNumber())
212
+            .append("coordinateSystem", getCoordinateSystem())
213
+            .append("spatialX", getSpatialX())
214
+            .append("spatialY", getSpatialY())
215
+            .append("spatialZ", getSpatialZ())
216
+            .append("longitude", getLongitude())
217
+            .append("longitudePosition", getLongitudePosition())
218
+            .append("latitude", getLatitude())
219
+            .append("latitudePosition", getLatitudePosition())
220
+            .append("height", getHeight())
221
+            .append("projectionHeight", getProjectionHeight())
222
+            .append("createTime", getCreateTime())
223
+            .append("createBy", getCreateBy())
224
+            .append("updateTime", getUpdateTime())
225
+            .append("updateBy", getUpdateBy())
226
+            .toString();
227
+    }
228
+}

+ 181
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcUTMBandChange.java Näytä tiedosto

@@ -0,0 +1,181 @@
1
+package com.ruoyi.web.calculate.domain;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+
6
+import org.apache.commons.lang3.builder.ToStringBuilder;
7
+import org.apache.commons.lang3.builder.ToStringStyle;
8
+import org.springframework.format.annotation.NumberFormat;
9
+
10
+import com.ruoyi.common.annotation.Excel;
11
+import com.ruoyi.common.annotation.Excel.ColumnType;
12
+import com.ruoyi.common.core.domain.BaseEntity;
13
+
14
+public class CmcUTMBandChange extends BaseEntity {
15
+    private static final long serialVersionUID = 1L;
16
+
17
+    /** 主键ID */
18
+    private Long id;
19
+
20
+    /** 待求点号 */
21
+    @Excel(name = "待求点")
22
+    private String pointNumber;
23
+
24
+    /** 坐标系 */
25
+    @Excel(name = "坐标系")
26
+    private String coordinateSystem;
27
+
28
+    /** UTM坐标x */
29
+    @Excel(name = "UTM坐标x", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
30
+    private Double utmX;
31
+
32
+    /** UTM坐标y */
33
+    @Excel(name = "UTM坐标y", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
34
+    private Double utmY;
35
+
36
+    /** 带号 */
37
+    @Excel(name = "带号", cellType = ColumnType.NUMERIC)
38
+    private double band;
39
+
40
+    /** 新带号 */
41
+    @Excel(name = "新带号", cellType = ColumnType.NUMERIC)
42
+    private double newBand;
43
+
44
+    /** 经度位置 */
45
+    @Excel(name = "经度位置")
46
+    private String longitudePosition;
47
+
48
+    /** 纬度位置 */
49
+    @Excel(name = "纬度位置")
50
+    private String latitudePosition;
51
+
52
+    /** 新UTM坐标x */
53
+    @Excel(name = "新UTM坐标x", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
54
+    private Double newUtmX;
55
+
56
+    /** 新UTM坐标y */
57
+    @Excel(name = "新UTM坐标y", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
58
+    private Double newUtmY;
59
+
60
+    /** 投影面高程 */
61
+    @Excel(name = "投影面高程", cellType = ColumnType.NUMERIC)
62
+    private double projectionHeight;
63
+
64
+    public void setId(Long id) {
65
+        this.id = id;
66
+    }
67
+
68
+    public Long getId() {
69
+        return id;
70
+    }
71
+
72
+    public void setPointNumber(String pointNumber) {
73
+        this.pointNumber = pointNumber;
74
+    }
75
+
76
+    public String getPointNumber() {
77
+        return pointNumber;
78
+    }
79
+
80
+    public void setCoordinateSystem(String coordinateSystem) {
81
+        this.coordinateSystem = coordinateSystem;
82
+    }
83
+
84
+    public String getCoordinateSystem() {
85
+        return coordinateSystem;
86
+    }
87
+
88
+    public void setLongitudePosition(String longitudePosition) {
89
+        this.longitudePosition = longitudePosition;
90
+    }
91
+
92
+    public String getLongitudePosition() {
93
+        return longitudePosition;
94
+    }
95
+
96
+    public void setLatitudePosition(String latitudePosition) {
97
+        this.latitudePosition = latitudePosition;
98
+    }
99
+
100
+    public String getLatitudePosition() {
101
+        return latitudePosition;
102
+    }
103
+
104
+    public void setBand(double band) {
105
+        this.band = band;
106
+    }
107
+
108
+    public double getBand() {
109
+        return band;
110
+    }
111
+    
112
+    public void setNewBand(double newBand) {
113
+        this.newBand = newBand;
114
+    }
115
+
116
+    public double getNewBand() {
117
+        return newBand;
118
+    }
119
+
120
+    public void setProjectionHeight(double projectionHeight) {
121
+        this.projectionHeight = projectionHeight;
122
+    }
123
+
124
+    public double getProjectionHeight() {
125
+        return projectionHeight;
126
+    }
127
+
128
+    public void setUtmX(Double utmX) {
129
+        this.utmX = utmX;
130
+    }
131
+
132
+    public Double getUtmX() {
133
+        return utmX;
134
+    }
135
+
136
+    public void setUtmY(Double utmY) {
137
+        this.utmY = utmY;
138
+    }
139
+
140
+    public Double getUtmY() {
141
+        return utmY;
142
+    }
143
+
144
+    public void setNewUtmX(Double newUtmX) {
145
+        this.newUtmX = newUtmX;
146
+    }
147
+
148
+    public Double getNewUtmX() {
149
+        return newUtmX;
150
+    }
151
+
152
+    public void setNewUtmY(Double newUtmY) {
153
+        this.newUtmY = newUtmY;
154
+    }
155
+
156
+    public Double getNewUtmY() {
157
+        return newUtmY;
158
+    }
159
+
160
+    @Override
161
+    public String toString() {
162
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
163
+                .append("id", getId())
164
+                .append("pointNumber", getPointNumber())
165
+                .append("coordinateSystem", getCoordinateSystem())
166
+                .append("longitudePosition", getLongitudePosition())
167
+                .append("latitudePosition", getLatitudePosition())
168
+                .append("band", getBand())
169
+                .append("utmX", getUtmX())
170
+                .append("utmY", getUtmY())
171
+                .append("newBand", getNewBand())
172
+                .append("projectionHeight", getProjectionHeight())
173
+                .append("newUtmX", getNewUtmX())
174
+                .append("newUtmY", getNewUtmY())
175
+                .append("createTime", getCreateTime())
176
+                .append("createBy", getCreateBy())
177
+                .append("updateTime", getUpdateTime())
178
+                .append("updateBy", getUpdateBy())
179
+                .toString();
180
+    }
181
+}

+ 201
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcUTMNegative.java Näytä tiedosto

@@ -0,0 +1,201 @@
1
+package com.ruoyi.web.calculate.domain;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+
6
+import org.apache.commons.lang3.builder.ToStringBuilder;
7
+import org.apache.commons.lang3.builder.ToStringStyle;
8
+import com.ruoyi.common.annotation.Excel;
9
+import com.ruoyi.common.annotation.Excel.ColumnType;
10
+import com.ruoyi.common.core.domain.BaseEntity;
11
+
12
+/**
13
+ * UTM反算对象 cmc_utm_nagative
14
+ * 
15
+ * @author qyx
16
+ * @date 2026-04-21
17
+ */
18
+public class CmcUTMNegative extends BaseEntity
19
+{
20
+    private static final long serialVersionUID = 1L;
21
+
22
+    /** 主键ID */
23
+    private Long id;
24
+
25
+    /** 待求点号 */
26
+    @Excel(name = "待求点")
27
+    private String pointNumber;
28
+
29
+    /** 坐标系 */
30
+    @Excel(name = "坐标系")
31
+    private String coordinateSystem;
32
+
33
+    /** utm坐标x */
34
+    @Excel(name = "UTM坐标x", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
35
+    private Double utmX;
36
+
37
+    /** utm坐标y */
38
+    @Excel(name = "UTM坐标y", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
39
+    private Double utmY;
40
+
41
+    /** 带号 */
42
+    @Excel(name = "带号", cellType = ColumnType.NUMERIC)
43
+    private Integer band;
44
+
45
+    /** 投影面高程 */
46
+    @Excel(name = "投影面高程", cellType = ColumnType.NUMERIC)
47
+    private double projectionHeight;
48
+
49
+    /** 大地经度 */
50
+    @Excel(name = "大地经度" , cellType = ColumnType.NUMERIC,numberFormat = "0.000000000")
51
+    private Double longitude;
52
+
53
+    /** 经度位置 */
54
+    @Excel(name = "经度位置")
55
+    private String longitudePosition;
56
+
57
+    /** 大地纬度 */
58
+    @Excel(name = "大地纬度", cellType = ColumnType.NUMERIC, numberFormat = "0.000000000")
59
+    private Double latitude;
60
+
61
+    /** 纬度位置 */
62
+    @Excel(name = "纬度位置")
63
+    private String latitudePosition;
64
+
65
+    public void setId(Long id) 
66
+    {
67
+        this.id = id;
68
+    }
69
+
70
+    public Long getId() 
71
+    {
72
+        return id;
73
+    }
74
+    public void setPointNumber(String pointNumber) 
75
+    {
76
+        this.pointNumber = pointNumber;
77
+    }
78
+
79
+    public String getPointNumber() 
80
+    {
81
+        return pointNumber;
82
+    }
83
+    public void setCoordinateSystem(String coordinateSystem) 
84
+    {
85
+        this.coordinateSystem = coordinateSystem;
86
+    }
87
+
88
+    public String getCoordinateSystem() 
89
+    {
90
+        return coordinateSystem;
91
+    }
92
+    public void setUtmX(Double utmX) 
93
+    {
94
+        this.utmX = utmX;
95
+    }
96
+
97
+    public Double getUtmX() 
98
+    {
99
+        return utmX;
100
+    }
101
+    
102
+    public void setUtmY(Double utmY) 
103
+    {
104
+        this.utmY = utmY;
105
+    }
106
+
107
+    public Double getUtmY() 
108
+    {
109
+        return utmY;
110
+    }
111
+    
112
+    public void setBand(Integer band) 
113
+    {
114
+        this.band = band;
115
+    }
116
+
117
+    public Integer getBand() 
118
+    {
119
+        return band;
120
+    }
121
+    
122
+    public void setProjectionHeight(double projectionHeight) 
123
+    {
124
+        this.projectionHeight = projectionHeight;
125
+    }
126
+
127
+    public double getProjectionHeight() 
128
+    {
129
+        return projectionHeight;
130
+    }
131
+    
132
+    public void setLongitude(Double longitude) 
133
+    {
134
+        if (longitude != null) {
135
+            BigDecimal bd = new BigDecimal(longitude);
136
+            this.longitude = bd.setScale(10, RoundingMode.HALF_UP).doubleValue();
137
+        } else {
138
+            this.longitude = null;
139
+        }
140
+    }
141
+
142
+    public Double getLongitude() 
143
+    {
144
+        return longitude;
145
+    }
146
+    
147
+    public void setLongitudePosition(String longitudePosition) 
148
+    {
149
+        this.longitudePosition = longitudePosition;
150
+    }
151
+
152
+    public String getLongitudePosition() 
153
+    {
154
+        return longitudePosition;
155
+    }
156
+    
157
+    public void setLatitude(Double latitude) 
158
+    {
159
+        if (latitude != null) {
160
+            BigDecimal bd = new BigDecimal(latitude);
161
+            this.latitude = bd.setScale(10, RoundingMode.HALF_UP).doubleValue();
162
+        } else {
163
+            this.latitude = null;
164
+        }
165
+    }
166
+
167
+    public Double getLatitude() 
168
+    {
169
+        return latitude;
170
+    }
171
+    
172
+    public void setLatitudePosition(String latitudePosition) 
173
+    {
174
+        this.latitudePosition = latitudePosition;
175
+    }
176
+
177
+    public String getLatitudePosition() 
178
+    {
179
+        return latitudePosition;
180
+    }
181
+
182
+    @Override
183
+    public String toString() {
184
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
185
+            .append("id", getId())
186
+            .append("pointNumber", getPointNumber())
187
+            .append("coordinateSystem", getCoordinateSystem())
188
+            .append("utmX", getUtmX())
189
+            .append("utmY", getUtmY())
190
+            .append("band", getBand())
191
+            .append("longitude", getLongitude())
192
+            .append("longitudePosition", getLongitudePosition())
193
+            .append("latitude", getLatitude())
194
+            .append("latitudePosition", getLatitudePosition())
195
+            .append("createTime", getCreateTime())
196
+            .append("createBy", getCreateBy())
197
+            .append("updateTime", getUpdateTime())
198
+            .append("updateBy", getUpdateBy())
199
+            .toString();
200
+    }
201
+}

+ 222
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcUTMPositive.java Näytä tiedosto

@@ -0,0 +1,222 @@
1
+package com.ruoyi.web.calculate.domain;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+
6
+import org.apache.commons.lang3.builder.ToStringBuilder;
7
+import org.apache.commons.lang3.builder.ToStringStyle;
8
+import com.ruoyi.common.annotation.Excel;
9
+import com.ruoyi.common.annotation.Excel.ColumnType;
10
+import com.ruoyi.common.core.domain.BaseEntity;
11
+
12
+/**
13
+ * UTM正算对象 cmc_utm_positive
14
+ * 
15
+ * @author qyx
16
+ * @date 2026-04-21
17
+ */
18
+public class CmcUTMPositive extends BaseEntity
19
+{
20
+    private static final long serialVersionUID = 1L;
21
+
22
+    /** 主键ID */
23
+    private Long id;
24
+
25
+    /** 待求点号 */
26
+    @Excel(name = "待求点")
27
+    private String pointNumber;
28
+
29
+    /** 坐标系 */
30
+    @Excel(name = "坐标系")
31
+    private String coordinateSystem;
32
+
33
+    /** 大地经度 */
34
+    @Excel(name = "大地经度" , cellType = ColumnType.NUMERIC,numberFormat = "0.000000000")
35
+    private Double longitude;
36
+
37
+    /** 经度位置 */
38
+    @Excel(name = "经度位置")
39
+    private String longitudePosition;
40
+
41
+    /** 大地纬度 */
42
+    @Excel(name = "大地纬度", cellType = ColumnType.NUMERIC, numberFormat = "0.000000000")
43
+    private Double latitude;
44
+
45
+    /** 纬度位置 */
46
+    @Excel(name = "纬度位置")
47
+    private String latitudePosition;
48
+
49
+    /** 带号 */
50
+    @Excel(name = "带号", cellType = ColumnType.NUMERIC)
51
+    private Integer band;
52
+
53
+    /** 投影面高程 */
54
+    @Excel(name = "投影面高程", cellType = ColumnType.NUMERIC)
55
+    private double projectionHeight;
56
+
57
+    /** UTM坐标x */
58
+    @Excel(name = "UTM坐标x", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
59
+    private Double utmX;
60
+
61
+    /** UTM坐标y */
62
+    @Excel(name = "UTM坐标y", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
63
+    private Double utmY;
64
+
65
+    /** 子午线收敛角γ */
66
+    @Excel(name = "子午线收敛角γ", cellType = ColumnType.NUMERIC, numberFormat = "0.0000000")
67
+    private Double meridianConvergence;
68
+
69
+    public void setId(Long id) 
70
+    {
71
+        this.id = id;
72
+    }
73
+
74
+    public Long getId() 
75
+    {
76
+        return id;
77
+    }
78
+    public void setPointNumber(String pointNumber) 
79
+    {
80
+        this.pointNumber = pointNumber;
81
+    }
82
+
83
+    public String getPointNumber() 
84
+    {
85
+        return pointNumber;
86
+    }
87
+    public void setCoordinateSystem(String coordinateSystem) 
88
+    {
89
+        this.coordinateSystem = coordinateSystem;
90
+    }
91
+
92
+    public String getCoordinateSystem() 
93
+    {
94
+        return coordinateSystem;
95
+    }
96
+     public void setLongitude(Double longitude) 
97
+    {
98
+        if (longitude != null) {
99
+            BigDecimal bd = new BigDecimal(longitude);
100
+            this.longitude = bd.setScale(10, RoundingMode.HALF_UP).doubleValue();
101
+        } else {
102
+            this.longitude = null;
103
+        }
104
+    }
105
+
106
+    public Double getLongitude() 
107
+    {
108
+        return longitude;
109
+    }
110
+    
111
+    public void setLongitudePosition(String longitudePosition) 
112
+    {
113
+        this.longitudePosition = longitudePosition;
114
+    }
115
+
116
+    public String getLongitudePosition() 
117
+    {
118
+        return longitudePosition;
119
+    }
120
+    
121
+    public void setLatitude(Double latitude) 
122
+    {
123
+        if (latitude != null) {
124
+            BigDecimal bd = new BigDecimal(latitude);
125
+            this.latitude = bd.setScale(10, RoundingMode.HALF_UP).doubleValue();
126
+        } else {
127
+            this.latitude = null;
128
+        }
129
+    }
130
+
131
+    public Double getLatitude() 
132
+    {
133
+        return latitude;
134
+    }
135
+    
136
+    public void setLatitudePosition(String latitudePosition) 
137
+    {
138
+        this.latitudePosition = latitudePosition;
139
+    }
140
+
141
+    public String getLatitudePosition() 
142
+    {
143
+        return latitudePosition;
144
+    }
145
+    
146
+    public void setBand(Integer band) 
147
+    {
148
+        this.band = band;
149
+    }
150
+
151
+    public Integer getBand() 
152
+    {
153
+        return band;
154
+    }
155
+    
156
+    public void setProjectionHeight(double projectionHeight) 
157
+    {
158
+        this.projectionHeight = projectionHeight;
159
+    }
160
+
161
+    public double getProjectionHeight() 
162
+    {
163
+        return projectionHeight;
164
+    }
165
+    
166
+    public void setUtmX(Double utmX) 
167
+    {
168
+        this.utmX = utmX;
169
+    }
170
+
171
+    public Double getUtmX() 
172
+    {
173
+        return utmX;
174
+    }
175
+    
176
+    public void setUtmY(Double utmY) 
177
+    {
178
+        this.utmY = utmY;
179
+    }
180
+
181
+    public Double getUtmY() 
182
+    {
183
+        return utmY;
184
+    }
185
+    
186
+    public void setMeridianConvergence(Double meridianConvergence) 
187
+    {
188
+        if (meridianConvergence != null) {
189
+            BigDecimal bd = new BigDecimal(meridianConvergence);
190
+            this.meridianConvergence = bd.setScale(7, RoundingMode.HALF_UP).doubleValue();
191
+        } else {
192
+            this.meridianConvergence = null;
193
+        }
194
+    }
195
+
196
+    public Double getMeridianConvergence() 
197
+    {
198
+        return meridianConvergence;
199
+    }
200
+
201
+
202
+    @Override
203
+    public String toString() {
204
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
205
+            .append("id", getId())
206
+            .append("pointNumber", getPointNumber())
207
+            .append("coordinateSystem", getCoordinateSystem())
208
+            .append("longitude", getLongitude())
209
+            .append("longitudePosition", getLongitudePosition())
210
+            .append("latitude", getLatitude())
211
+            .append("latitudePosition", getLatitudePosition())
212
+            .append("band", getBand())
213
+            .append("utmX", getUtmX())
214
+            .append("utmY", getUtmY())
215
+            .append("meridianConvergence", getMeridianConvergence())
216
+            .append("createTime", getCreateTime())
217
+            .append("createBy", getCreateBy())
218
+            .append("updateTime", getUpdateTime())
219
+            .append("updateBy", getUpdateBy())
220
+            .toString();
221
+    }
222
+}

+ 32
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/ICmcGaussBandChangeService.java Näytä tiedosto

@@ -0,0 +1,32 @@
1
+package com.ruoyi.web.calculate.service;
2
+
3
+import java.util.List;
4
+
5
+import org.springframework.web.multipart.MultipartFile;
6
+
7
+import com.ruoyi.common.core.domain.AjaxResult;
8
+import com.ruoyi.web.calculate.domain.CmcGaussBandChange;
9
+
10
+/**
11
+ * 高斯换带接口
12
+ * 
13
+ * @author qyx
14
+ * @date 2026-04-21
15
+ */
16
+public interface ICmcGaussBandChangeService {
17
+    /**
18
+     * 导入Excel数据
19
+     * 
20
+     * @param file Excel文件
21
+     * @return 导入结果
22
+     */
23
+    public AjaxResult importExcelData(MultipartFile file);
24
+
25
+    /**
26
+     * 执行高斯反算
27
+     * 
28
+     * @param cmcGaussBandChange 高斯反算参数
29
+     * @return 计算结果
30
+     */
31
+    public List<CmcGaussBandChange> calculateGaussBandChange(List<CmcGaussBandChange> dataList);
32
+}

+ 32
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/ICmcGeodeticToSpatialService.java Näytä tiedosto

@@ -0,0 +1,32 @@
1
+package com.ruoyi.web.calculate.service;
2
+
3
+import java.util.List;
4
+
5
+import org.springframework.web.multipart.MultipartFile;
6
+
7
+import com.ruoyi.common.core.domain.AjaxResult;
8
+import com.ruoyi.web.calculate.domain.CmcGeodeticToSpatial;
9
+
10
+/**
11
+ * 同坐标系中大地坐标转空间坐标服务接口
12
+ * 
13
+ * @author qyx
14
+ * @date 2026-06-09
15
+ */
16
+public interface ICmcGeodeticToSpatialService {
17
+    /**
18
+     * 导入Excel数据
19
+     * 
20
+     * @param file Excel文件
21
+     * @return 导入结果
22
+     */
23
+    public AjaxResult importExcelData(MultipartFile file);
24
+
25
+    /**
26
+     * 执行大地坐标转空间坐标计算
27
+     * 
28
+     * @param dataList 计算参数列表
29
+     * @return 计算结果
30
+     */
31
+    public List<CmcGeodeticToSpatial> calculateGeodeticToSpatial(List<CmcGeodeticToSpatial> dataList);
32
+}

+ 32
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/ICmcSpatialToGeodeticService.java Näytä tiedosto

@@ -0,0 +1,32 @@
1
+package com.ruoyi.web.calculate.service;
2
+
3
+import java.util.List;
4
+
5
+import org.springframework.web.multipart.MultipartFile;
6
+
7
+import com.ruoyi.common.core.domain.AjaxResult;
8
+import com.ruoyi.web.calculate.domain.CmcSpatialToGeodetic;
9
+
10
+/**
11
+ * 空间直角坐标转大地坐标服务接口
12
+ * 
13
+ * @author qyx
14
+ * @date 2026-06-10
15
+ */
16
+public interface ICmcSpatialToGeodeticService {
17
+    /**
18
+     * 导入Excel数据
19
+     * 
20
+     * @param file Excel文件
21
+     * @return 导入结果
22
+     */
23
+    public AjaxResult importExcelData(MultipartFile file);
24
+
25
+    /**
26
+     * 执行空间直角坐标转大地坐标计算
27
+     * 
28
+     * @param dataList 计算参数列表
29
+     * @return 计算结果
30
+     */
31
+    public List<CmcSpatialToGeodetic> calculateSpatialToGeodetic(List<CmcSpatialToGeodetic> dataList);
32
+}

+ 32
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/ICmcUTMBandChangeService.java Näytä tiedosto

@@ -0,0 +1,32 @@
1
+package com.ruoyi.web.calculate.service;
2
+
3
+import java.util.List;
4
+
5
+import org.springframework.web.multipart.MultipartFile;
6
+
7
+import com.ruoyi.common.core.domain.AjaxResult;
8
+import com.ruoyi.web.calculate.domain.CmcUTMBandChange;
9
+
10
+/**
11
+ * UTM换带接口
12
+ * 
13
+ * @author qyx
14
+ * @date 2026-06-05
15
+ */
16
+public interface ICmcUTMBandChangeService {
17
+    /**
18
+     * 导入Excel数据
19
+     * 
20
+     * @param file Excel文件
21
+     * @return 导入结果
22
+     */
23
+    public AjaxResult importExcelData(MultipartFile file);
24
+
25
+    /**
26
+     * 执行UTM换带计算
27
+     * 
28
+     * @param dataList UTM换带参数列表
29
+     * @return 计算结果
30
+     */
31
+    public List<CmcUTMBandChange> calculateUTMBandChange(List<CmcUTMBandChange> dataList);
32
+}

+ 35
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/ICmcUTMNegativeService.java Näytä tiedosto

@@ -0,0 +1,35 @@
1
+package com.ruoyi.web.calculate.service;
2
+
3
+import java.util.List;
4
+
5
+import javax.servlet.http.HttpServletResponse;
6
+
7
+import org.springframework.web.multipart.MultipartFile;
8
+
9
+import com.ruoyi.common.core.domain.AjaxResult;
10
+import com.ruoyi.web.calculate.domain.CmcUTMNegative;
11
+
12
+/**
13
+ * UTM反算Service接口
14
+ * 
15
+ * @author qyx
16
+ * @date 2026-04-21
17
+ */
18
+public interface ICmcUTMNegativeService 
19
+{
20
+    /**
21
+     * 导入Excel数据
22
+     * 
23
+     * @param file Excel文件
24
+     * @return 结果
25
+     */
26
+    public AjaxResult importExcelData(MultipartFile file);
27
+
28
+    /**
29
+     * 执行UTM反算
30
+     * 
31
+     * @param dataList 数据列表
32
+     * @return 计算结果列表
33
+     */
34
+    public List<CmcUTMNegative> calculateUTMNagative(List<CmcUTMNegative> dataList);
35
+}

+ 36
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/ICmcUTMPositiveService.java Näytä tiedosto

@@ -0,0 +1,36 @@
1
+package com.ruoyi.web.calculate.service;
2
+
3
+import java.util.List;
4
+
5
+import javax.servlet.http.HttpServletResponse;
6
+
7
+import org.springframework.web.multipart.MultipartFile;
8
+
9
+import com.ruoyi.common.core.domain.AjaxResult;
10
+import com.ruoyi.web.calculate.domain.CmcUTMPositive;
11
+
12
+/**
13
+ * UTM正算服务接口
14
+ * 
15
+ * @author qyx
16
+ * @date 2026-04-21
17
+ */
18
+public interface ICmcUTMPositiveService 
19
+{
20
+     /**
21
+     * 导入Excel数据
22
+     * 
23
+     * @param file Excel文件
24
+     * @return 导入结果
25
+     */
26
+     public AjaxResult importExcelData(MultipartFile file);
27
+    
28
+    /**
29
+     * 执行UTM正算
30
+     * 
31
+     * @param cmcUTMPositive UTM正算参数
32
+     * @return 计算结果
33
+     */
34
+    public List<CmcUTMPositive> calculateUTMPositive(List<CmcUTMPositive> dataList);
35
+
36
+}

+ 392
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcGaussBandChangeServiceImpl.java Näytä tiedosto

@@ -0,0 +1,392 @@
1
+package com.ruoyi.web.calculate.service.impl;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+import java.util.ArrayList;
6
+import java.util.HashMap;
7
+import java.util.List;
8
+import java.util.Map;
9
+
10
+import javax.servlet.http.HttpServletResponse;
11
+
12
+import org.springframework.beans.factory.annotation.Autowired;
13
+import org.springframework.stereotype.Service;
14
+import org.springframework.transaction.annotation.Transactional;
15
+import org.springframework.web.multipart.MultipartFile;
16
+
17
+import com.ruoyi.common.core.domain.AjaxResult;
18
+import com.ruoyi.common.utils.poi.ExcelUtil;
19
+// import com.ruoyi.web.calculate.mapper.CmcGaussPositiveMapper;
20
+import com.ruoyi.web.calculate.domain.CmcGaussBandChange;
21
+import com.ruoyi.web.calculate.service.ICmcGaussBandChangeService;
22
+
23
+/**
24
+ * 高斯换带服务实现
25
+ * 
26
+ * @author ruoyi
27
+ * @date 2026-04-21
28
+ */
29
+@Service
30
+public class CmcGaussBandChangeServiceImpl implements ICmcGaussBandChangeService {
31
+    @Autowired
32
+    // 扁率直接计算精度不够,在后面的椭球参数选择中用BigDecimal计算,下面的F是分母
33
+    private static final double A_WGS84 = 6378137.0;
34
+    private static final String F_WGS84 = "298.257223563";
35
+
36
+    private static final double A_CGCS2000 = 6378137.0;
37
+    private static final String F_CGCS2000 = "298.257222101";
38
+
39
+    private static final double A_BJ54 = 6378245.0;
40
+    private static final String F_BJ54 = "298.3";
41
+
42
+    private static final double A_XA80 = 6378140.0;
43
+    private static final String F_XA80 = "298.257";
44
+
45
+    private static double A;
46
+    private static double F;
47
+    private static double E2;
48
+
49
+    /**
50
+     * 导入Excel数据
51
+     */
52
+    @Override
53
+    @Transactional(rollbackFor = Exception.class)
54
+    public AjaxResult importExcelData(MultipartFile file) {
55
+        try {
56
+            // 使用若依的ExcelUtil工具类
57
+            ExcelUtil<CmcGaussBandChange> util = new ExcelUtil<CmcGaussBandChange>(CmcGaussBandChange.class);
58
+            List<CmcGaussBandChange> dataList = util.importExcel(file.getInputStream());
59
+
60
+            // 检查是否有数据
61
+            if (dataList == null || dataList.isEmpty()) {
62
+                return AjaxResult.error("Excel文件中没有数据!");
63
+            }
64
+
65
+            // 验证数据并转换为前端需要的格式
66
+            List<Map<String, Object>> validData = new ArrayList<>();
67
+            int successCount = 0;
68
+            StringBuilder errorMsg = new StringBuilder();
69
+
70
+            for (int i = 0; i < dataList.size(); i++) {
71
+                CmcGaussBandChange item = dataList.get(i);
72
+
73
+                try {
74
+                    // 转换为前端需要的Map格式
75
+                    Map<String, Object> rowMap = new HashMap<>();
76
+                    rowMap.put("pointNumber", item.getPointNumber());
77
+                    rowMap.put("coordinateSystem", item.getCoordinateSystem());
78
+                    rowMap.put("gaussX", item.getGaussX());
79
+                    rowMap.put("gaussY", item.getGaussY());
80
+                    rowMap.put("band", item.getBand());
81
+                    rowMap.put("bandWidth", item.getBandwidth());
82
+                    rowMap.put("newBand", item.getNewBand());
83
+                    rowMap.put("newBandWidth", item.getNewBandwidth());
84
+                    rowMap.put("longitudePosition", item.getLongitudePosition());
85
+                    rowMap.put("latitudePosition", item.getLatitudePosition());
86
+                    rowMap.put("projectionHeight", item.getProjectionHeight());
87
+                    rowMap.put("rowNum", i + 2); // Excel中的行号
88
+
89
+                    validData.add(rowMap);
90
+                    successCount++;
91
+
92
+                } catch (Exception e) {
93
+                    errorMsg.append(String.format("第%d行数据验证失败:%s;", i + 2, e.getMessage()));
94
+                }
95
+            }
96
+
97
+            // 构建返回结果
98
+            Map<String, Object> result = new HashMap<>();
99
+            result.put("total", dataList.size());
100
+            result.put("validCount", successCount);
101
+            result.put("data", validData);
102
+
103
+            if (successCount == 0) {
104
+                return AjaxResult.error("没有有效数据!" + errorMsg.toString());
105
+            }
106
+
107
+            String message = String.format("导入成功!共解析%d条数据,有效数据%d条", dataList.size(), successCount);
108
+            if (errorMsg.length() > 0) {
109
+                message += ";部分数据验证失败:" + errorMsg.toString();
110
+                return AjaxResult.success(message, result);
111
+            }
112
+
113
+            return AjaxResult.success(message, result);
114
+
115
+        } catch (Exception e) {
116
+            e.printStackTrace();
117
+            return AjaxResult.error("导入失败:" + e.getMessage());
118
+        }
119
+    }
120
+
121
+    /**
122
+     * 执行高斯反算
123
+     */
124
+    @Override
125
+    public List<CmcGaussBandChange> calculateGaussBandChange(List<CmcGaussBandChange> dataList) {
126
+        List<CmcGaussBandChange> resultList = new ArrayList<>();
127
+        for (CmcGaussBandChange item : dataList) {
128
+            try {
129
+                CmcGaussBandChange result = calculateGaussBandChangeSingle(item);
130
+                resultList.add(result);
131
+            } catch (Exception e) {
132
+                e.printStackTrace();
133
+                // 计算失败时,返回带有错误信息的对象
134
+                CmcGaussBandChange errorResult = new CmcGaussBandChange();
135
+                errorResult.setPointNumber(item.getPointNumber());
136
+                errorResult.setNewGaussX(-1.0);
137
+                errorResult.setNewGaussY(-1.0);
138
+                resultList.add(errorResult);
139
+            }
140
+        }
141
+
142
+        return resultList;
143
+    }
144
+
145
+    /**
146
+     * 单条高斯换带计算
147
+     */
148
+    private CmcGaussBandChange calculateGaussBandChangeSingle(CmcGaussBandChange cmcGaussBandChange) {
149
+        try {
150
+            initEllipsoidParams(cmcGaussBandChange.getCoordinateSystem());
151
+            // 以大地坐标(纬度B,经度L)为桥梁,通过连续应用高斯反算和正算公式来实现换带。
152
+            double gaussX = cmcGaussBandChange.getGaussX(); // 经度(度)
153
+            double gaussY = cmcGaussBandChange.getGaussY(); // 经度(度)
154
+            String longitudePosition = cmcGaussBandChange.getLongitudePosition(); // 经度位置(东/西)
155
+            String latitudePosition = cmcGaussBandChange.getLatitudePosition(); // 纬度位置(北/南)
156
+            double projectionHeight = cmcGaussBandChange.getProjectionHeight(); // 投影面高程
157
+            double band = cmcGaussBandChange.getBand();
158
+            int bandwidth = cmcGaussBandChange.getBandwidth();
159
+            double newband = cmcGaussBandChange.getNewBand();
160
+            int newbandwidth = cmcGaussBandChange.getNewBandwidth();
161
+
162
+            double x = latitudePosition.equals("S") ? 10000000 - gaussX : gaussX;
163
+            double y = gaussY > 1.0E+7 ? gaussY - (int) Math.floor(gaussY / 1.0E+6) * 1.0E+6 - 500000 : gaussY - 500000;
164
+
165
+            double bf = calculateBf(x, projectionHeight);
166
+            double tf = Math.tan(bf);
167
+            double ep2 = 1 / Math.pow(1 - F, 2) - 1;
168
+            double etaf2 = ep2 * Math.pow(Math.cos(bf), 2);
169
+            double Vf = Math.sqrt(1 + etaf2);
170
+            double c = (A + projectionHeight) / (1 - F);
171
+            double n = y * Vf / c;
172
+
173
+            // 大地纬度 B
174
+            double B = calculateB(bf, tf, etaf2, n);
175
+            // 大地经度L
176
+            double L = calculateL(bf, tf, etaf2, n, longitudePosition, bandwidth, band);
177
+            
178
+            double b = B /180 * Math.PI;
179
+            double l = "W".equals(longitudePosition)
180
+                    ? (newbandwidth == 6 ? (newband * newbandwidth - 3 - L) / 180 * Math.PI : (newband * newbandwidth - L)/180*Math.PI)
181
+                    : (newbandwidth == 6 ? (L - newband * newbandwidth + 3) / 180 * Math.PI
182
+                            : (L - newband * newbandwidth) / 180 * Math.PI);
183
+                            
184
+            // 将大地坐标代入目标带,投影计算新的平面坐标。
185
+            double m = Math.cos(b) * l;
186
+            double eta2 = ep2 * Math.cos(b) * Math.cos(b);
187
+
188
+            // 计算卯酉圈曲率半径
189
+            double N = (A + projectionHeight) / ((1 - F) * Math.sqrt(1 + eta2));
190
+            // 计算子午线弧长
191
+            double X = calculateMeridianArc(b, projectionHeight);
192
+            // 计算Y坐标的系数
193
+            double t = Math.tan(b);
194
+            double t2 = t * t;
195
+            double t4 = t2 * t2;
196
+            double m2 = m * m;
197
+            double m4 = m2 * m2;
198
+
199
+            // 计算X坐标
200
+            double xnow = X + N * Math.cos(b) * Math.cos(b) * t * l * l / 2 +
201
+                    N * Math.pow(Math.cos(b), 4) * t * (5 - t * t + 9 * eta2 + 4 * eta2 * eta2) * Math.pow(l, 4) / 24 +
202
+                    N * Math.pow(Math.cos(b), 6) * t * (61 - 58 * t2 + t4 + 270 * eta2 - 330 * eta2 * t2)
203
+                            * Math.pow(l, 6) / 720;
204
+            // l
205
+            double term1 = m;
206
+            // l³
207
+            double term3 = (1 - t2 + eta2) * m2 * m / 6;
208
+            // l⁵
209
+            double term5 = (5 - 18 * t2 + t4 + 14 * eta2 - 58 * eta2 * t2) * m4 * m / 120;
210
+            // 计算y坐标
211
+            double ynow = N * (term1 + term3 + term5)+500000;
212
+
213
+            cmcGaussBandChange.setNewGaussX(xnow);
214
+            cmcGaussBandChange.setNewGaussY(ynow);
215
+        } catch (Exception e) {
216
+            e.printStackTrace();
217
+        }
218
+        return cmcGaussBandChange;
219
+    }
220
+
221
+    // 选择椭球体参数
222
+    private void initEllipsoidParams(String coordinateSystem) {
223
+        String F_str;
224
+        if ("CGCS2000".equalsIgnoreCase(coordinateSystem) || "国家2000".equalsIgnoreCase(coordinateSystem)
225
+                || "2000".equalsIgnoreCase(coordinateSystem)) {
226
+            A = A_CGCS2000;
227
+            F_str = F_CGCS2000;
228
+        } else if ("1954".equalsIgnoreCase(coordinateSystem) || "北京54".equalsIgnoreCase(coordinateSystem)
229
+                || "Beijing54".equalsIgnoreCase(coordinateSystem)
230
+                || "54".equalsIgnoreCase(coordinateSystem)) {
231
+            A = A_BJ54;
232
+            F_str = F_BJ54;
233
+        } else if ("1980".equalsIgnoreCase(coordinateSystem) || "西安80".equalsIgnoreCase(coordinateSystem)
234
+                || "Xian80".equalsIgnoreCase(coordinateSystem)
235
+                || "80".equalsIgnoreCase(coordinateSystem)) {
236
+            A = A_XA80;
237
+            F_str = F_XA80;
238
+        } else {
239
+            A = A_WGS84;
240
+            F_str = F_WGS84;
241
+        }
242
+        BigDecimal one = BigDecimal.ONE;
243
+        BigDecimal divisor = new BigDecimal(F_str);
244
+        BigDecimal db_F = one.divide(divisor, 20, RoundingMode.HALF_UP);
245
+
246
+        // 计算 2 * F
247
+        BigDecimal two = new BigDecimal("2");
248
+        BigDecimal twoF = two.multiply(db_F);
249
+
250
+        // 计算 F * F
251
+        BigDecimal F_squared = db_F.multiply(db_F);
252
+
253
+        // 计算 e2 = 2*F - F*F
254
+        BigDecimal e2 = twoF.subtract(F_squared);
255
+        E2 = e2.doubleValue();
256
+        F = db_F.doubleValue();
257
+    }
258
+
259
+    // 计算bf
260
+    private double calculateBf(double x, double projectionHeight) {
261
+        double e2 = E2;
262
+        double e4 = E2 * E2;
263
+        double e6 = e4 * E2;
264
+        double e8 = e6 * E2;
265
+        double e10 = e8 * E2;
266
+        double d = A + projectionHeight;
267
+        // 计算子午线弧长系数
268
+        double a0 = (d - d * e2) * (1
269
+                + 3.0 / 4.0 * e2
270
+                + 45.0 / 64.0 * e4
271
+                + 175.0 / 256.0 * e6
272
+                + 11025.0 / 16384.0 * e8
273
+                + 43659.0 / 65536.0 * e10);
274
+
275
+        double a2 = (d - d * e2) * (3.0 / 4.0 * e2
276
+                + 45.0 / 64.0 * e4
277
+                + 175.0 / 256.0 * e6
278
+                + 11025.0 / 16384.0 * e8
279
+                + 43659.0 / 65536.0 * e10);
280
+
281
+        double a4 = (d - d * e2) * (15.0 / 32.0 * e4
282
+                + 175.0 / 384.0 * e6
283
+                + 3675.0 / 8192.0 * e8
284
+                + 14553.0 / 32768.0 * e10);
285
+
286
+        double a6 = (d - d * e2) * (35.0 / 96.0 * e6
287
+                + 735.0 / 2048.0 * e8
288
+                + 14553.0 / 40960.0 * e10);
289
+
290
+        double a8 = (d - d * e2) * (315.0 / 1024.0 * e8
291
+                + 6237.0 / 20480.0 * e10);
292
+
293
+        double b = x / a0;
294
+        double sinB = Math.sin(b);
295
+        double cosB = Math.cos(b);
296
+        double f = -(a2 * sinB + a4 * Math.pow(sinB, 3) + a6 * Math.pow(sinB, 5) + a8 * Math.pow(sinB, 7)) * cosB;
297
+
298
+        for (int i = 0; i < 9; i++) {
299
+            b = (x - f) / a0;
300
+            sinB = Math.sin(b);
301
+            cosB = Math.cos(b);
302
+            f = -(a2 * sinB + a4 * Math.pow(sinB, 3) + a6 * Math.pow(sinB, 5) + a8 * Math.pow(sinB, 7)) * cosB;
303
+            i++;
304
+        }
305
+        return b;
306
+    }
307
+
308
+    // 计算B
309
+    private double calculateB(double bf, double tf, double etaf2, double n) {
310
+        double n2 = n * n;
311
+        double n4 = n2 * n2;
312
+        double n6 = n4 * n2;
313
+        // 计算底点纬度对应的值
314
+        double term1 = bf * 180 / Math.PI; // 转为度
315
+        // 计算括号内的各项
316
+        double bracket = 90 * n2
317
+                - 7.5 * (5 + 3 * tf * tf + etaf2 - 9 * etaf2 * tf * tf) * n4
318
+                + 0.25 * (61 + 90 * tf * tf + 45 * tf * tf * tf * tf) * n6;
319
+        // 计算第二项
320
+        double term2 = (1 + etaf2) / Math.PI * tf * bracket;
321
+        // 最终纬度 B
322
+        double B = term1 - term2;
323
+        return B;
324
+    }
325
+
326
+    // 计算l
327
+    private double calculateL(double bf, double tf, double etaf2, double n, String longitudePosition,
328
+            double bandwidth, double band) {
329
+        double n2 = n * n;
330
+        double n3 = n2 * n;
331
+        double n5 = n3 * n2;
332
+        double tf2 = tf * tf;
333
+        double tf4 = tf2 * tf2;
334
+        // 括号内计算
335
+        double bracket2 = 180 * n
336
+                - 30 * (1 + 2 * tf2 + etaf2) * n3
337
+                + 1.5 * (5 + 28 * tf2 + 24 * tf4) * n5;
338
+        double l = 1 / Math.PI / Math.cos(bf) * bracket2;
339
+
340
+        double L = "W".equals(longitudePosition)
341
+                ? (bandwidth == 6 ? (band * bandwidth - 3 - l) : (band * bandwidth - l))
342
+                : (bandwidth == 6 ? (l + band * bandwidth - 3) : (l + band * bandwidth));
343
+        return L;
344
+    }
345
+
346
+    /**
347
+     * 计算子午线弧长
348
+     */
349
+    private double calculateMeridianArc(double B, double projectionHeight) {
350
+        double e2 = E2;
351
+        double e4 = E2 * E2;
352
+        double e6 = e4 * E2;
353
+        double e8 = e6 * E2;
354
+        double e10 = e8 * E2;
355
+        double d = A + projectionHeight;
356
+        // 计算子午线弧长系数
357
+        double a0 = (d - d * e2) * (1
358
+                + 3.0 / 4.0 * e2
359
+                + 45.0 / 64.0 * e4
360
+                + 175.0 / 256.0 * e6
361
+                + 11025.0 / 16384.0 * e8
362
+                + 43659.0 / 65536.0 * e10);
363
+
364
+        double a2 = (d - d * e2) * (3.0 / 4.0 * e2
365
+                + 45.0 / 64.0 * e4
366
+                + 175.0 / 256.0 * e6
367
+                + 11025.0 / 16384.0 * e8
368
+                + 43659.0 / 65536.0 * e10);
369
+
370
+        double a4 = (d - d * e2) * (15.0 / 32.0 * e4
371
+                + 175.0 / 384.0 * e6
372
+                + 3675.0 / 8192.0 * e8
373
+                + 14553.0 / 32768.0 * e10);
374
+
375
+        double a6 = (d - d * e2) * (35.0 / 96.0 * e6
376
+                + 735.0 / 2048.0 * e8
377
+                + 14553.0 / 40960.0 * e10);
378
+
379
+        double a8 = (d - d * e2) * (315.0 / 1024.0 * e8
380
+                + 6237.0 / 20480.0 * e10);
381
+
382
+        double a10 = (d - d * e2) * (693.0 / 2560.0) * e10;
383
+
384
+        // 计算子午线弧长
385
+        double sinB = Math.sin(B);
386
+        double cosB = Math.cos(B);
387
+
388
+        double X = a0 * B - (a2 * sinB + a4 * Math.pow(sinB, 3) + a6 * Math.pow(sinB, 5) + a8 * Math.pow(sinB, 7)
389
+                + a10 * Math.pow(sinB, 9)) * cosB;
390
+        return X;
391
+    }
392
+}

+ 46
- 31
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcGaussNegativeServiceImpl.java Näytä tiedosto

@@ -151,8 +151,8 @@ public class CmcGaussNegativeServiceImpl implements ICmcGaussNegativeService {
151 151
             String latitudePosition = cmcGaussNegative.getLatitudePosition(); // 纬度位置(北/南)
152 152
             double projectionHeight = cmcGaussNegative.getProjectionHeight(); // 投影面高程
153 153
             String yStr = String.valueOf(Math.abs((long) gaussY));
154
-            int zone = Integer.parseInt(yStr.substring(0, 2));
155
-            int bandwidth = zone > 30 ? 3 : 6;
154
+            int band = Integer.parseInt(yStr.substring(0, 2));
155
+            int bandwidth = band > 30 ? 3 : 6;
156 156
 
157 157
             double x = latitudePosition.equals("S") ? 10000000 - gaussX : gaussX;
158 158
             double y = gaussY > 1.0E+7 ? gaussY - (int) Math.floor(gaussY / 1.0E+6) * 1.0E+6 - 500000 : gaussY - 500000;
@@ -164,35 +164,12 @@ public class CmcGaussNegativeServiceImpl implements ICmcGaussNegativeService {
164 164
             double Vf = Math.sqrt(1 + etaf2);
165 165
             double c = (A + projectionHeight) / (1 - F);
166 166
             double n = y * Vf / c;
167
-           
168
-            double n2 = n * n;
169
-            double n4 = n2 * n2;
170
-            double n6 = n4 * n2;
171
-            //计算B
172
-            // 计算底点纬度对应的值
173
-            double term1 = bf * 180 / Math.PI; // 转为度
174
-            // 计算括号内的各项
175
-            double bracket = 90 * n2
176
-                    - 7.5 * (5 + 3 * tf * tf + etaf2 - 9 * etaf2 * tf * tf) * n4
177
-                    + 0.25 * (61 + 90 * tf * tf + 45 * tf * tf * tf * tf) * n6;
178
-            // 计算第二项
179
-            double term2 = (1 + etaf2) / Math.PI * tf * bracket;
167
+            
180 168
             // 最终纬度 B
181
-            double B = term1 - term2;
182
-            //计算l
183
-            double n3 = n2 * n;
184
-            double n5 = n3 * n2;
185
-            double tf2 = tf * tf;
186
-            double tf4 = tf2 * tf2;
187
-            // 括号内计算
188
-            double bracket2 = 180 * n
189
-                    - 30 * (1 + 2 * tf2 + etaf2) * n3
190
-                    + 1.5 * (5 + 28 * tf2 + 24 * tf4) * n5;
191
-            double l = 1 / Math.PI / Math.cos(bf) * bracket2;
192
-
193
-            double L = "W".equals(longitudePosition)
194
-                    ? (bandwidth == 6 ? (zone * bandwidth - 3 - l) : (zone * bandwidth - l))
195
-                    : (bandwidth == 6 ? (l + zone * bandwidth - 3) : (l + zone * bandwidth));
169
+            double B = calculateB(bf, tf, etaf2, n);
170
+
171
+            //计算L
172
+            double L = calculateL(bf, tf, etaf2, n, longitudePosition, bandwidth, band);
196 173
 
197 174
             //大地经度和大地纬度
198 175
             double longitude = convertDecimalDegrees(L);
@@ -200,7 +177,7 @@ public class CmcGaussNegativeServiceImpl implements ICmcGaussNegativeService {
200 177
 
201 178
             cmcGaussNegative.setLongitude(longitude);
202 179
             cmcGaussNegative.setLatitude(latitude);
203
-            cmcGaussNegative.setZone(zone);
180
+            cmcGaussNegative.setBand(band);
204 181
             cmcGaussNegative.setBandwidth(bandwidth);
205 182
            
206 183
         } catch (Exception e) {
@@ -296,6 +273,43 @@ public class CmcGaussNegativeServiceImpl implements ICmcGaussNegativeService {
296 273
         return b;
297 274
     }
298 275
 
276
+    //计算B
277
+    private double calculateB(double bf, double tf, double etaf2, double n) {        double n2 = n * n;
278
+        double n4 = n2 * n2;
279
+        double n6 = n4 * n2;
280
+        // 计算底点纬度对应的值
281
+        double term1 = bf * 180 / Math.PI; // 转为度
282
+        // 计算括号内的各项
283
+        double bracket = 90 * n2
284
+                - 7.5 * (5 + 3 * tf * tf + etaf2 - 9 * etaf2 * tf * tf) * n4
285
+                + 0.25 * (61 + 90 * tf * tf + 45 * tf * tf * tf * tf) * n6;
286
+        // 计算第二项
287
+        double term2 = (1 + etaf2) / Math.PI * tf * bracket;
288
+        // 最终纬度 B
289
+        double B = term1 - term2;
290
+        return B;
291
+    }
292
+
293
+    //计算l
294
+    private double calculateL(double bf, double tf, double etaf2, double n, String longitudePosition,
295
+                 double bandwidth, double band) {
296
+        double n2 = n * n;
297
+        double n3 = n2 * n;
298
+        double n5 = n3 * n2;
299
+        double tf2 = tf * tf;
300
+        double tf4 = tf2 * tf2;
301
+        // 括号内计算
302
+        double bracket2 = 180 * n
303
+                - 30 * (1 + 2 * tf2 + etaf2) * n3
304
+                + 1.5 * (5 + 28 * tf2 + 24 * tf4) * n5;
305
+        double l = 1 / Math.PI / Math.cos(bf) * bracket2;
306
+
307
+        double L = "W".equals(longitudePosition)
308
+                ? (bandwidth == 6 ? (band * bandwidth - 3 - l) : (band * bandwidth - l))
309
+                : (bandwidth == 6 ? (l + band * bandwidth - 3) : (l + band * bandwidth));
310
+        return L;
311
+    }
312
+
299 313
     /**
300 314
      * 将十进制度数数值转换为度分秒格式(
301 315
      * 
@@ -319,3 +333,4 @@ public class CmcGaussNegativeServiceImpl implements ICmcGaussNegativeService {
319 333
         return degrees + minutes + seconds;
320 334
     }
321 335
 }
336
+

+ 4
- 4
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcGaussPositiveServiceImpl.java Näytä tiedosto

@@ -82,7 +82,7 @@ public class CmcGaussPositiveServiceImpl implements ICmcGaussPositiveService
82 82
                     rowMap.put("longitudePosition", item.getLongitudePosition());
83 83
                     rowMap.put("latitude", item.getLatitude());
84 84
                     rowMap.put("latitudePosition", item.getLatitudePosition());
85
-                    rowMap.put("zone", item.getZone());
85
+                    rowMap.put("band", item.getBand());
86 86
                     rowMap.put("bandwidth", item.getBandwidth());
87 87
                     rowMap.put("projectionHeight", item.getProjectionHeight());
88 88
                     rowMap.put("rowNum", i + 2); // Excel中的行号
@@ -157,16 +157,16 @@ public class CmcGaussPositiveServiceImpl implements ICmcGaussPositiveService
157 157
             String longitudePosition = cmcGaussPositive.getLongitudePosition(); // 经度位置(东/西)
158 158
             String latitudePosition = cmcGaussPositive.getLatitudePosition(); // 纬度位置(北/南)
159 159
             double latitude = cmcGaussPositive.getLatitude(); // 纬度(度)
160
-            Integer zone = cmcGaussPositive.getZone(); // 带号
160
+            Integer band = cmcGaussPositive.getBand(); // 带号
161 161
             int bandwidth = cmcGaussPositive.getBandwidth(); // 带宽
162 162
             double projectionHeight = cmcGaussPositive.getProjectionHeight(); // 投影面高程
163 163
 
164 164
             // 计算中央经线
165 165
             double centralMeridian;
166 166
             if (bandwidth == 6) {
167
-                centralMeridian = zone * 6 - 3;
167
+                centralMeridian = band * 6 - 3;
168 168
             } else { // 3度带
169
-                centralMeridian = zone * 3;
169
+                centralMeridian = band * 3;
170 170
             }
171 171
             // 转换为弧度
172 172
             double B = convertDecimalDegrees(latitude) * Math.PI / 180;

+ 234
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcGeodeticToSpatialServiceImpl.java Näytä tiedosto

@@ -0,0 +1,234 @@
1
+package com.ruoyi.web.calculate.service.impl;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+import java.util.ArrayList;
6
+import java.util.HashMap;
7
+import java.util.List;
8
+import java.util.Map;
9
+
10
+import javax.servlet.http.HttpServletResponse;
11
+
12
+import org.springframework.beans.factory.annotation.Autowired;
13
+import org.springframework.stereotype.Service;
14
+import org.springframework.transaction.annotation.Transactional;
15
+import org.springframework.web.multipart.MultipartFile;
16
+
17
+import com.ruoyi.common.core.domain.AjaxResult;
18
+import com.ruoyi.common.utils.poi.ExcelUtil;
19
+import com.ruoyi.web.calculate.domain.CmcGeodeticToSpatial;
20
+import com.ruoyi.web.calculate.service.ICmcGeodeticToSpatialService;
21
+
22
+/**
23
+ * 大地坐标转空间直角坐标服务实现
24
+ * 
25
+ * @author ruoyi
26
+ * @date 2026-06-09
27
+ */
28
+@Service
29
+public class CmcGeodeticToSpatialServiceImpl implements ICmcGeodeticToSpatialService {
30
+    @Autowired
31
+    // 扁率直接计算精度不够,在后面的椭球参数选择中用BigDecimal计算,下面的F是分母
32
+    private static final double A_WGS84 = 6378137.0;
33
+    private static final String F_WGS84 = "298.257223563";
34
+
35
+    private static final double A_CGCS2000 = 6378137.0;
36
+    private static final String F_CGCS2000 = "298.257222101";
37
+
38
+    private static final double A_BJ54 = 6378245.0;
39
+    private static final String F_BJ54 = "298.3";
40
+
41
+    private static final double A_XA80 = 6378140.0;
42
+    private static final String F_XA80 = "298.257";
43
+
44
+    private static double A;
45
+    private static double F;
46
+    private static double E2;
47
+
48
+    /**
49
+     * 导入Excel数据
50
+     */
51
+    @Override
52
+    @Transactional(rollbackFor = Exception.class)
53
+    public AjaxResult importExcelData(MultipartFile file) {
54
+        try {
55
+            // 使用若依的ExcelUtil工具类
56
+            ExcelUtil<CmcGeodeticToSpatial> util = new ExcelUtil<CmcGeodeticToSpatial>(CmcGeodeticToSpatial.class);
57
+            List<CmcGeodeticToSpatial> dataList = util.importExcel(file.getInputStream());
58
+
59
+            // 检查是否有数据
60
+            if (dataList == null || dataList.isEmpty()) {
61
+                return AjaxResult.error("Excel文件中没有数据!");
62
+            }
63
+
64
+            // 验证数据并转换为前端需要的格式
65
+            List<Map<String, Object>> validData = new ArrayList<>();
66
+            int successCount = 0;
67
+            StringBuilder errorMsg = new StringBuilder();
68
+
69
+            for (int i = 0; i < dataList.size(); i++) {
70
+                CmcGeodeticToSpatial item = dataList.get(i);
71
+
72
+                try {
73
+                    // 转换为前端需要的Map格式
74
+                    Map<String, Object> rowMap = new HashMap<>();
75
+                    rowMap.put("pointNumber", item.getPointNumber());
76
+                    rowMap.put("coordinateSystem", item.getCoordinateSystem());
77
+                    rowMap.put("longitude", item.getLongitude());
78
+                    rowMap.put("longitudePosition", item.getLongitudePosition());
79
+                    rowMap.put("latitude", item.getLatitude());
80
+                    rowMap.put("latitudePosition", item.getLatitudePosition());
81
+                    rowMap.put("height", item.getHeight());
82
+                    rowMap.put("rowNum", i + 2); // Excel中的行号
83
+
84
+                    validData.add(rowMap);
85
+                    successCount++;
86
+
87
+                } catch (Exception e) {
88
+                    errorMsg.append(String.format("第%d行数据验证失败:%s;", i + 2, e.getMessage()));
89
+                }
90
+            }
91
+
92
+            // 构建返回结果
93
+            Map<String, Object> result = new HashMap<>();
94
+            result.put("total", dataList.size());
95
+            result.put("validCount", successCount);
96
+            result.put("data", validData);
97
+
98
+            if (successCount == 0) {
99
+                return AjaxResult.error("没有有效数据!" + errorMsg.toString());
100
+            }
101
+
102
+            String message = String.format("导入成功!共解析%d条数据,有效数据%d条", dataList.size(), successCount);
103
+            if (errorMsg.length() > 0) {
104
+                message += ";部分数据验证失败:" + errorMsg.toString();
105
+                return AjaxResult.success(message, result);
106
+            }
107
+
108
+            return AjaxResult.success(message, result);
109
+
110
+        } catch (Exception e) {
111
+            e.printStackTrace();
112
+            return AjaxResult.error("导入失败:" + e.getMessage());
113
+        }
114
+    }
115
+
116
+    /**
117
+     * 执行大地坐标转空间直角坐标计算
118
+     */
119
+    @Override
120
+    public List<CmcGeodeticToSpatial> calculateGeodeticToSpatial(List<CmcGeodeticToSpatial> dataList) {
121
+        List<CmcGeodeticToSpatial> resultList = new ArrayList<>();
122
+        for (CmcGeodeticToSpatial item : dataList) {
123
+            try {
124
+                CmcGeodeticToSpatial result = calculateGeodeticToSpatialSingle(item);
125
+                resultList.add(result);
126
+            } catch (Exception e) {
127
+                e.printStackTrace();
128
+                // 计算失败时,返回带有错误信息的对象
129
+                CmcGeodeticToSpatial errorResult = new CmcGeodeticToSpatial();
130
+                errorResult.setPointNumber(item.getPointNumber());
131
+                errorResult.setSpatialX(-1.0);
132
+                errorResult.setSpatialY(-1.0);
133
+                errorResult.setSpatialZ(-1.0);
134
+                resultList.add(errorResult);
135
+            }
136
+        }
137
+
138
+        return resultList;
139
+    }
140
+
141
+    /**
142
+     * 单条大地坐标转空间直角坐标计算
143
+     */
144
+    private CmcGeodeticToSpatial calculateGeodeticToSpatialSingle(CmcGeodeticToSpatial cmcGeodeticToSpatial) {
145
+
146
+        // 获取输入值
147
+        String coordinateSystem = cmcGeodeticToSpatial.getCoordinateSystem(); // 坐标系
148
+        double longitude = cmcGeodeticToSpatial.getLongitude(); // 大地经度(度)
149
+        String longitudePosition = cmcGeodeticToSpatial.getLongitudePosition(); // 经度位置 E/W
150
+        double latitude = cmcGeodeticToSpatial.getLatitude(); // 大地纬度(度)
151
+        String latitudePosition = cmcGeodeticToSpatial.getLatitudePosition(); // 纬度位置 N/S
152
+        double projectionHeight = cmcGeodeticToSpatial.getProjectionHeight(); // 投影高
153
+        double height = cmcGeodeticToSpatial.getHeight(); // 大地高
154
+        double j = 1.5e-12;
155
+
156
+        // 初始化椭球参数
157
+        initEllipsoidParams(coordinateSystem);
158
+
159
+        double a = A + projectionHeight;
160
+        // 将角度转换为弧度
161
+        double B = latitudePosition.equals("N") ? calculateRadianValue(latitude, j)
162
+                : -calculateRadianValue(latitude, j); // 纬度弧度
163
+        double L = longitudePosition.equals("E") ? calculateRadianValue(longitude, j)
164
+                : -calculateRadianValue(longitude, j);// 经度弧度
165
+
166
+        // 计算卯酉圈曲率半径 N = a / sqrt(1 - e² * sin²(B))
167
+        double sinB = Math.sin(B);
168
+        double cosB = Math.cos(B);
169
+        double sinL = Math.sin(L);
170
+        double cosL = Math.cos(L);
171
+
172
+        double N = a / Math.sqrt(1 - E2 * sinB * sinB);
173
+
174
+        // 计算空间直角坐标
175
+        double X = (N + height) * cosB * cosL;
176
+        double Y = (N + height) * cosB * sinL;
177
+        double Z = (N * (1 - E2) + height) * sinB;
178
+
179
+        // 设置计算结果
180
+        cmcGeodeticToSpatial.setSpatialX(X);
181
+        cmcGeodeticToSpatial.setSpatialY(Y);
182
+        cmcGeodeticToSpatial.setSpatialZ(Z);
183
+
184
+        return cmcGeodeticToSpatial;
185
+    }
186
+
187
+    // 选择椭球体参数
188
+    private void initEllipsoidParams(String coordinateSystem) {
189
+        String F_str;
190
+        if ("CGCS2000".equalsIgnoreCase(coordinateSystem) || "国家2000".equalsIgnoreCase(coordinateSystem)
191
+                || "2000".equalsIgnoreCase(coordinateSystem)) {
192
+            A = A_CGCS2000;
193
+            F_str = F_CGCS2000;
194
+        } else if ("1954".equalsIgnoreCase(coordinateSystem) || "北京54".equalsIgnoreCase(coordinateSystem)
195
+                || "Beijing54".equalsIgnoreCase(coordinateSystem)
196
+                || "54".equalsIgnoreCase(coordinateSystem)) {
197
+            A = A_BJ54;
198
+            F_str = F_BJ54;
199
+        } else if ("1980".equalsIgnoreCase(coordinateSystem) || "西安80".equalsIgnoreCase(coordinateSystem)
200
+                || "Xian80".equalsIgnoreCase(coordinateSystem)
201
+                || "80".equalsIgnoreCase(coordinateSystem)) {
202
+            A = A_XA80;
203
+            F_str = F_XA80;
204
+        } else {
205
+            A = A_WGS84;
206
+            F_str = F_WGS84;
207
+        }
208
+        BigDecimal one = BigDecimal.ONE;
209
+        BigDecimal divisor = new BigDecimal(F_str);
210
+        BigDecimal db_F = one.divide(divisor, 20, RoundingMode.HALF_UP);
211
+
212
+        // 计算 2 * F
213
+        BigDecimal two = new BigDecimal("2");
214
+        BigDecimal twoF = two.multiply(db_F);
215
+
216
+        // 计算 F * F
217
+        BigDecimal F_squared = db_F.multiply(db_F);
218
+
219
+        // 计算 e2 = 2*F - F*F
220
+        BigDecimal e2 = twoF.subtract(F_squared);
221
+        E2 = e2.doubleValue();
222
+        F = db_F.doubleValue();
223
+    }
224
+
225
+    private double calculateRadianValue (double degree, double j) {
226
+        // 计算基础值(度 + 分/60 + 秒/3600)
227
+        double baseValue = Math.floor(degree + j) // 度(整数部分)
228
+                + (Math.floor((degree + j) * 100) % 100) / 60.0 // 分(取两位)/60
229
+                + (Math.floor((degree + j) * Math.pow(10, 10)) % Math.pow(10, 8)) / Math.pow(10, 6) / 3600.0; // 秒
230
+        // 度转弧度
231
+        double radianValue = baseValue / 180.0 * Math.PI;
232
+        return radianValue;
233
+    }
234
+}

+ 227
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcSpatialToGeodeticServiceImpl.java Näytä tiedosto

@@ -0,0 +1,227 @@
1
+package com.ruoyi.web.calculate.service.impl;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+import java.util.ArrayList;
6
+import java.util.HashMap;
7
+import java.util.List;
8
+import java.util.Map;
9
+
10
+import javax.servlet.http.HttpServletResponse;
11
+
12
+import org.springframework.beans.factory.annotation.Autowired;
13
+import org.springframework.stereotype.Service;
14
+import org.springframework.transaction.annotation.Transactional;
15
+import org.springframework.web.multipart.MultipartFile;
16
+
17
+import com.ruoyi.common.core.domain.AjaxResult;
18
+import com.ruoyi.common.utils.poi.ExcelUtil;
19
+import com.ruoyi.web.calculate.domain.CmcSpatialToGeodetic;
20
+import com.ruoyi.web.calculate.service.ICmcSpatialToGeodeticService;
21
+
22
+/**
23
+ * 空间直角坐标转大地坐标服务实现
24
+ * 
25
+ * @author ruoyi
26
+ * @date 2026-06-10
27
+ */
28
+@Service
29
+public class CmcSpatialToGeodeticServiceImpl implements ICmcSpatialToGeodeticService {
30
+    @Autowired
31
+    // 扁率直接计算精度不够,在后面的椭球参数选择中用BigDecimal计算,下面的F是分母
32
+    private static final double A_WGS84 = 6378137.0;
33
+    private static final String F_WGS84 = "298.257223563";
34
+
35
+    private static final double A_CGCS2000 = 6378137.0;
36
+    private static final String F_CGCS2000 = "298.257222101";
37
+
38
+    private static final double A_BJ54 = 6378245.0;
39
+    private static final String F_BJ54 = "298.3";
40
+
41
+    private static final double A_XA80 = 6378140.0;
42
+    private static final String F_XA80 = "298.257";
43
+
44
+    private static double A;
45
+    private static double F;
46
+    private static double E2;
47
+
48
+    /**
49
+     * 导入Excel数据
50
+     */
51
+    @Override
52
+    @Transactional(rollbackFor = Exception.class)
53
+    public AjaxResult importExcelData(MultipartFile file) {
54
+        try {
55
+            // 使用若依的ExcelUtil工具类
56
+            ExcelUtil<CmcSpatialToGeodetic> util = new ExcelUtil<CmcSpatialToGeodetic>(CmcSpatialToGeodetic.class);
57
+            List<CmcSpatialToGeodetic> dataList = util.importExcel(file.getInputStream());
58
+
59
+            // 检查是否有数据
60
+            if (dataList == null || dataList.isEmpty()) {
61
+                return AjaxResult.error("Excel文件中没有数据!");
62
+            }
63
+
64
+            // 验证数据并转换为前端需要的格式
65
+            List<Map<String, Object>> validData = new ArrayList<>();
66
+            int successCount = 0;
67
+            StringBuilder errorMsg = new StringBuilder();
68
+
69
+            for (int i = 0; i < dataList.size(); i++) {
70
+                CmcSpatialToGeodetic item = dataList.get(i);
71
+
72
+                try {
73
+                    // 转换为前端需要的Map格式
74
+                    Map<String, Object> rowMap = new HashMap<>();
75
+                    rowMap.put("pointNumber", item.getPointNumber());
76
+                    rowMap.put("coordinateSystem", item.getCoordinateSystem());
77
+                    rowMap.put("spatialX", item.getSpatialX());
78
+                    rowMap.put("spatialY", item.getSpatialY());
79
+                    rowMap.put("spatialZ", item.getSpatialZ());
80
+                    rowMap.put("rowNum", i + 2); // Excel中的行号
81
+
82
+                    validData.add(rowMap);
83
+                    successCount++;
84
+
85
+                } catch (Exception e) {
86
+                    errorMsg.append(String.format("第%d行数据验证失败:%s;", i + 2, e.getMessage()));
87
+                }
88
+            }
89
+
90
+            // 构建返回结果
91
+            Map<String, Object> result = new HashMap<>();
92
+            result.put("total", dataList.size());
93
+            result.put("validCount", successCount);
94
+            result.put("data", validData);
95
+
96
+            if (successCount == 0) {
97
+                return AjaxResult.error("没有有效数据!" + errorMsg.toString());
98
+            }
99
+
100
+            String message = String.format("导入成功!共解析%d条数据,有效数据%d条", dataList.size(), successCount);
101
+            if (errorMsg.length() > 0) {
102
+                message += ";部分数据验证失败:" + errorMsg.toString();
103
+                return AjaxResult.success(message, result);
104
+            }
105
+
106
+            return AjaxResult.success(message, result);
107
+
108
+        } catch (Exception e) {
109
+            e.printStackTrace();
110
+            return AjaxResult.error("导入失败:" + e.getMessage());
111
+        }
112
+    }
113
+
114
+    /**
115
+     * 执行空间直角坐标转大地坐标计算
116
+     */
117
+    @Override
118
+    public List<CmcSpatialToGeodetic> calculateSpatialToGeodetic(List<CmcSpatialToGeodetic> dataList) {
119
+        List<CmcSpatialToGeodetic> resultList = new ArrayList<>();
120
+        for (CmcSpatialToGeodetic item : dataList) {
121
+            try {
122
+                CmcSpatialToGeodetic result = calculateSpatialToGeodeticSingle(item);
123
+                resultList.add(result);
124
+            } catch (Exception e) {
125
+                e.printStackTrace();
126
+                // 计算失败时,返回带有错误信息的对象
127
+                CmcSpatialToGeodetic errorResult = new CmcSpatialToGeodetic();
128
+                errorResult.setPointNumber(item.getPointNumber());
129
+                errorResult.setLongitude(-1.0);
130
+                errorResult.setLatitude(-1.0);
131
+                errorResult.setHeight(-1.0);
132
+                resultList.add(errorResult);
133
+            }
134
+        }
135
+
136
+        return resultList;
137
+    }
138
+
139
+    /**
140
+     * 单条空间直角坐标转大地坐标计算(待实现)
141
+     */
142
+    private CmcSpatialToGeodetic calculateSpatialToGeodeticSingle(CmcSpatialToGeodetic cmcSpatialToGeodetic) {
143
+        // 获取输入值
144
+        String coordinateSystem = cmcSpatialToGeodetic.getCoordinateSystem(); // 坐标系
145
+        double spatialX = cmcSpatialToGeodetic.getSpatialX(); // 空间坐标X
146
+        Double spatialY = cmcSpatialToGeodetic.getSpatialY(); // 空间坐标Y
147
+        double spatialZ = cmcSpatialToGeodetic.getSpatialZ(); // 空间坐标Z
148
+        double projectionHeight = cmcSpatialToGeodetic.getProjectionHeight(); // 投影高
149
+        double j = 1.5e-12;
150
+
151
+        initEllipsoidParams(coordinateSystem);
152
+
153
+        double a = A + projectionHeight;
154
+        double L = Math.acos(spatialX / Math.sqrt(spatialX * spatialX + spatialY * spatialY));
155
+        double L_degree = Math.toDegrees(L);
156
+        double t = spatialZ * E2;
157
+        double b = Math.asin(
158
+                (spatialZ + t) / Math.sqrt(Math.pow(spatialX, 2) + Math.pow(spatialY, 2) + Math.pow(spatialZ + t, 2)));
159
+
160
+        //循环计算
161
+        double N=0;
162
+        for (int i = 0; i < 8; i++) {
163
+            N = a / Math.sqrt(1 - E2 * Math.pow(Math.sin(b), 2));
164
+            t = E2 * N * Math.sin(b);
165
+            b = Math.asin((spatialZ + t)
166
+                    / Math.sqrt(Math.pow(spatialX, 2) + Math.pow(spatialY, 2) + Math.pow(spatialZ + t, 2)));
167
+        }
168
+
169
+        double B = Math.toDegrees(b);
170
+
171
+        double longitude = Math.floor(L_degree + j) + 
172
+                           Math.floor((L_degree - Math.floor(L_degree + j)) * 60 + j) / 100.0 + 
173
+                           Math.floor(((L_degree * 60 - Math.floor(L_degree * 60)) * 60 + Math.pow(10, -11)) * Math.pow(10, 6))
174
+                        / Math.pow(10, 10);
175
+        double latitude = Math.floor(B + j) + 
176
+                           Math.floor((B - Math.floor(B + j)) * 60 + j) / 100.0 + 
177
+                           Math.floor(((B * 60 - Math.floor(B * 60)) * 60 + Math.pow(10, -11)) * Math.pow(10, 6))
178
+                        / Math.pow(10, 10);
179
+        String longitudePosition = spatialY < 0 ? "W" : "E";
180
+        String latitudePosition = spatialX < 0 ? "S" : "N";
181
+        double height = Math.sqrt(Math.pow(spatialX, 2) + Math.pow(spatialY, 2) + Math.pow(spatialZ + t, 2)) - N;
182
+        cmcSpatialToGeodetic.setLongitude(longitude);
183
+        cmcSpatialToGeodetic.setLatitude(latitude);
184
+        cmcSpatialToGeodetic.setLongitudePosition(longitudePosition);
185
+        cmcSpatialToGeodetic.setLatitudePosition(latitudePosition);
186
+        cmcSpatialToGeodetic.setHeight(height);
187
+        return cmcSpatialToGeodetic;
188
+    }
189
+
190
+    // 选择椭球体参数
191
+    private void initEllipsoidParams(String coordinateSystem) {
192
+        String F_str;
193
+        if ("CGCS2000".equalsIgnoreCase(coordinateSystem) || "国家2000".equalsIgnoreCase(coordinateSystem)
194
+                || "2000".equalsIgnoreCase(coordinateSystem)) {
195
+            A = A_CGCS2000;
196
+            F_str = F_CGCS2000;
197
+        } else if ("1954".equalsIgnoreCase(coordinateSystem) || "北京54".equalsIgnoreCase(coordinateSystem)
198
+                || "Beijing54".equalsIgnoreCase(coordinateSystem)
199
+                || "54".equalsIgnoreCase(coordinateSystem)) {
200
+            A = A_BJ54;
201
+            F_str = F_BJ54;
202
+        } else if ("1980".equalsIgnoreCase(coordinateSystem) || "西安80".equalsIgnoreCase(coordinateSystem)
203
+                || "Xian80".equalsIgnoreCase(coordinateSystem)
204
+                || "80".equalsIgnoreCase(coordinateSystem)) {
205
+            A = A_XA80;
206
+            F_str = F_XA80;
207
+        } else {
208
+            A = A_WGS84;
209
+            F_str = F_WGS84;
210
+        }
211
+        BigDecimal one = BigDecimal.ONE;
212
+        BigDecimal divisor = new BigDecimal(F_str);
213
+        BigDecimal db_F = one.divide(divisor, 20, RoundingMode.HALF_UP);
214
+
215
+        // 计算 2 * F
216
+        BigDecimal two = new BigDecimal("2");
217
+        BigDecimal twoF = two.multiply(db_F);
218
+
219
+        // 计算 F * F
220
+        BigDecimal F_squared = db_F.multiply(db_F);
221
+
222
+        // 计算 e2 = 2*F - F*F
223
+        BigDecimal e2 = twoF.subtract(F_squared);
224
+        E2 = e2.doubleValue();
225
+        F = db_F.doubleValue();
226
+    }
227
+}

+ 400
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcUTMBandChangeServicelmpl.java Näytä tiedosto

@@ -0,0 +1,400 @@
1
+package com.ruoyi.web.calculate.service.impl;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+import java.util.ArrayList;
6
+import java.util.HashMap;
7
+import java.util.List;
8
+import java.util.Map;
9
+
10
+import javax.servlet.http.HttpServletResponse;
11
+
12
+import org.springframework.beans.factory.annotation.Autowired;
13
+import org.springframework.stereotype.Service;
14
+import org.springframework.transaction.annotation.Transactional;
15
+import org.springframework.web.multipart.MultipartFile;
16
+
17
+import com.ruoyi.common.core.domain.AjaxResult;
18
+import com.ruoyi.common.utils.poi.ExcelUtil;
19
+import com.ruoyi.web.calculate.domain.CmcUTMBandChange;
20
+import com.ruoyi.web.calculate.service.ICmcUTMBandChangeService;
21
+
22
+/**
23
+ * UTM换带服务实现
24
+ * 
25
+ * @author ruoyi
26
+ * @date 2026-06-05
27
+ */
28
+@Service
29
+public class CmcUTMBandChangeServicelmpl implements ICmcUTMBandChangeService {
30
+    @Autowired
31
+    // 扁率直接计算精度不够,在后面的椭球参数选择中用BigDecimal计算,下面的F是分母
32
+    private static final double A_WGS84 = 6378137.0;
33
+    private static final String F_WGS84 = "298.257223563";
34
+
35
+    private static final double A_CGCS2000 = 6378137.0;
36
+    private static final String F_CGCS2000 = "298.257222101";
37
+
38
+    private static final double A_BJ54 = 6378245.0;
39
+    private static final String F_BJ54 = "298.3";
40
+
41
+    private static final double A_XA80 = 6378140.0;
42
+    private static final String F_XA80 = "298.257";
43
+
44
+    private static double A;
45
+    private static double F;
46
+    private static double E2;
47
+
48
+    /**
49
+     * 导入Excel数据
50
+     */
51
+    @Override
52
+    @Transactional(rollbackFor = Exception.class)
53
+    public AjaxResult importExcelData(MultipartFile file) {
54
+        try {
55
+            // 使用若依的ExcelUtil工具类
56
+            ExcelUtil<CmcUTMBandChange> util = new ExcelUtil<CmcUTMBandChange>(CmcUTMBandChange.class);
57
+            List<CmcUTMBandChange> dataList = util.importExcel(file.getInputStream());
58
+
59
+            // 检查是否有数据
60
+            if (dataList == null || dataList.isEmpty()) {
61
+                return AjaxResult.error("Excel文件中没有数据!");
62
+            }
63
+
64
+            // 验证数据并转换为前端需要的格式
65
+            List<Map<String, Object>> validData = new ArrayList<>();
66
+            int successCount = 0;
67
+            StringBuilder errorMsg = new StringBuilder();
68
+
69
+            for (int i = 0; i < dataList.size(); i++) {
70
+                CmcUTMBandChange item = dataList.get(i);
71
+
72
+                try {
73
+                    // 转换为前端需要的Map格式
74
+                    Map<String, Object> rowMap = new HashMap<>();
75
+                    rowMap.put("pointNumber", item.getPointNumber());
76
+                    rowMap.put("coordinateSystem", item.getCoordinateSystem());
77
+                    rowMap.put("utmX", item.getUtmX());
78
+                    rowMap.put("utmY", item.getUtmY());
79
+                    rowMap.put("band", item.getBand());
80
+                    rowMap.put("newBand", item.getNewBand());
81
+                    rowMap.put("longitudePosition", item.getLongitudePosition());
82
+                    rowMap.put("latitudePosition", item.getLatitudePosition());
83
+                    rowMap.put("projectionHeight", item.getProjectionHeight());
84
+                    rowMap.put("rowNum", i + 2); // Excel中的行号
85
+
86
+                    validData.add(rowMap);
87
+                    successCount++;
88
+
89
+                } catch (Exception e) {
90
+                    errorMsg.append(String.format("第%d行数据验证失败:%s;", i + 2, e.getMessage()));
91
+                }
92
+            }
93
+
94
+            // 构建返回结果
95
+            Map<String, Object> result = new HashMap<>();
96
+            result.put("total", dataList.size());
97
+            result.put("validCount", successCount);
98
+            result.put("data", validData);
99
+
100
+            if (successCount == 0) {
101
+                return AjaxResult.error("没有有效数据!" + errorMsg.toString());
102
+            }
103
+
104
+            String message = String.format("导入成功!共解析%d条数据,有效数据%d条", dataList.size(), successCount);
105
+            if (errorMsg.length() > 0) {
106
+                message += ";部分数据验证失败:" + errorMsg.toString();
107
+                return AjaxResult.success(message, result);
108
+            }
109
+
110
+            return AjaxResult.success(message, result);
111
+
112
+        } catch (Exception e) {
113
+            e.printStackTrace();
114
+            return AjaxResult.error("导入失败:" + e.getMessage());
115
+        }
116
+    }
117
+
118
+    /**
119
+     * 执行UTM换带计算
120
+     */
121
+    @Override
122
+    public List<CmcUTMBandChange> calculateUTMBandChange(List<CmcUTMBandChange> dataList) {
123
+        List<CmcUTMBandChange> resultList = new ArrayList<>();
124
+        for (CmcUTMBandChange item : dataList) {
125
+            try {
126
+                CmcUTMBandChange result = calculateUTMBandChangeSingle(item);
127
+                resultList.add(result);
128
+            } catch (Exception e) {
129
+                e.printStackTrace();
130
+                // 计算失败时,返回带有错误信息的对象
131
+                CmcUTMBandChange errorResult = new CmcUTMBandChange();
132
+                errorResult.setPointNumber(item.getPointNumber());
133
+                errorResult.setNewUtmX(-1.0);
134
+                errorResult.setNewUtmY(-1.0);
135
+                resultList.add(errorResult);
136
+            }
137
+        }
138
+
139
+        return resultList;
140
+    }
141
+
142
+    /**
143
+     * 单条UTM换带计算
144
+     */
145
+    private CmcUTMBandChange calculateUTMBandChangeSingle(CmcUTMBandChange cmcUTMBandChange) {
146
+        try {
147
+            initEllipsoidParams(cmcUTMBandChange.getCoordinateSystem());
148
+            // 以大地坐标(纬度B,经度L)为桥梁,通过连续应用UTM反算和正算公式来实现换带。
149
+            double utmX = cmcUTMBandChange.getUtmX(); // UTM X坐标
150
+            double utmY = cmcUTMBandChange.getUtmY(); // UTM Y坐标
151
+            String longitudePosition = cmcUTMBandChange.getLongitudePosition(); // 经度位置(东/西)
152
+            String latitudePosition = cmcUTMBandChange.getLatitudePosition(); // 纬度位置(北/南)
153
+            double projectionHeight = cmcUTMBandChange.getProjectionHeight(); // 投影面高程
154
+            double band = cmcUTMBandChange.getBand();
155
+            double newband = cmcUTMBandChange.getNewBand();
156
+            
157
+            // UTM带宽固定为6度
158
+            int bandwidth = 6;
159
+
160
+            // UTM坐标处理:南半球X坐标需要特殊处理
161
+            // 处理x坐标(南半球特殊处理)
162
+            double x = latitudePosition.equals("S") ? (10000000 - utmX) / 0.9996 : utmX / 0.9996;
163
+
164
+            // 处理y坐标(减去东偏500000)
165
+            double y0 = utmY > 1.0E+7 ? (utmY - (int) Math.floor(utmY / 1.0E+6) * 1.0E+6 - 500000) / 0.9996 + 500000
166
+                    : (utmY - 500000)
167
+                            / 0.9996 + 500000;
168
+            double y = y0 > 1.0E+7 ? y0 - (int) Math.floor(y0 / 1.0E+6) * 1.0E+6 - 500000 : y0 - 500000;
169
+            
170
+            // 反算:UTM平面坐标 -> 大地坐标
171
+            double bf = calculateBf(x, projectionHeight);
172
+            double tf = Math.tan(bf);
173
+            double ep2 = 1 / Math.pow(1 - F, 2) - 1;
174
+            double etaf2 = ep2 * Math.pow(Math.cos(bf), 2);
175
+            double Vf = Math.sqrt(1 + etaf2);
176
+            double c = (A + projectionHeight) / (1 - F);
177
+            double n = y * Vf / c;
178
+            // 大地纬度 B
179
+            double B = calculateB(bf, tf, etaf2, n);
180
+
181
+            // 大地经度L
182
+            double L = calculateL(bf, tf, etaf2, n, longitudePosition, bandwidth, band);
183
+            
184
+            // 将大地坐标转换为弧度
185
+            double b = B / 180 * Math.PI;
186
+            double l = "E".equals(longitudePosition)
187
+                    ? (L-(newband-30) * 6 + 3)/180*Math.PI
188
+                    : ((30-newband) * 6 + 3 - L)/180*Math.PI;
189
+              
190
+            // 将大地坐标代入目标带,投影计算新的平面坐标。
191
+            double m = Math.cos(b) * l;
192
+            double cosb2 = Math.pow(Math.cos(b), 2);
193
+            double eta2 = new BigDecimal(ep2).multiply(new BigDecimal(cosb2)).doubleValue();
194
+            // 计算卯酉圈曲率半径
195
+            double N = (A + projectionHeight) / (1 - F) / Math.sqrt(1 + eta2);
196
+            // 计算子午线弧长
197
+            double X = calculateMeridianArc(b, projectionHeight);
198
+
199
+            // 计算Y坐标的系数
200
+            double t = Math.tan(b);
201
+            double t2 = t * t;
202
+            double t4 = t2 * t2;
203
+            double m2 = m * m;
204
+            double m4 = m2 * m2;
205
+
206
+            // 计算X坐标(UTM正算公式)
207
+            double xnow = X + N * Math.cos(b) * Math.cos(b) * t * l * l / 2 +
208
+                    N * Math.pow(Math.cos(b), 4) * t * (5 - t * t + 9 * eta2 + 4 * eta2 * eta2) * Math.pow(l, 4) / 24 +
209
+                    N * Math.pow(Math.cos(b), 6) * t * (61 - 58 * t2 + t4 + 270 * eta2 - 330 * eta2 * t2)
210
+                            * Math.pow(l, 6) / 720;
211
+            
212
+            // 计算Y坐标的各项
213
+            double term1 = m;
214
+            double term3 = (1 - t2 + eta2) * m2 * m / 6;
215
+            double term5 = (5 - 18 * t2 + t4 + 14 * eta2 - 58 * eta2 * t2) * m4 * m / 120;
216
+            
217
+            // 计算y坐标(加上500,000米东偏移)
218
+            double ynow = 0.9996 * (N * (term1 + term3 + term5)) + 500000;
219
+            
220
+            // 设置结果(南半球需要特殊处理)
221
+            cmcUTMBandChange.setNewUtmX(latitudePosition.equals("S") ? 10000000 - 0.9996 *xnow : 0.9996 * xnow);
222
+            cmcUTMBandChange.setNewUtmY(ynow);
223
+        } catch (Exception e) {
224
+            e.printStackTrace();
225
+        }
226
+        return cmcUTMBandChange;
227
+    }
228
+
229
+    // 选择椭球体参数
230
+    private void initEllipsoidParams(String coordinateSystem) {
231
+        String F_str;
232
+        if ("CGCS2000".equalsIgnoreCase(coordinateSystem) || "国家2000".equalsIgnoreCase(coordinateSystem)
233
+                || "2000".equalsIgnoreCase(coordinateSystem)) {
234
+            A = A_CGCS2000;
235
+            F_str = F_CGCS2000;
236
+        } else if ("1954".equalsIgnoreCase(coordinateSystem) || "北京54".equalsIgnoreCase(coordinateSystem)
237
+                || "Beijing54".equalsIgnoreCase(coordinateSystem)
238
+                || "54".equalsIgnoreCase(coordinateSystem)) {
239
+            A = A_BJ54;
240
+            F_str = F_BJ54;
241
+        } else if ("1980".equalsIgnoreCase(coordinateSystem) || "西安80".equalsIgnoreCase(coordinateSystem)
242
+                || "Xian80".equalsIgnoreCase(coordinateSystem)
243
+                || "80".equalsIgnoreCase(coordinateSystem)) {
244
+            A = A_XA80;
245
+            F_str = F_XA80;
246
+        } else {
247
+            A = A_WGS84;
248
+            F_str = F_WGS84;
249
+        }
250
+        BigDecimal one = BigDecimal.ONE;
251
+        BigDecimal divisor = new BigDecimal(F_str);
252
+        BigDecimal db_F = one.divide(divisor, 20, RoundingMode.HALF_UP);
253
+
254
+        // 计算 2 * F
255
+        BigDecimal two = new BigDecimal("2");
256
+        BigDecimal twoF = two.multiply(db_F);
257
+
258
+        // 计算 F * F
259
+        BigDecimal F_squared = db_F.multiply(db_F);
260
+
261
+        // 计算 e2 = 2*F - F*F
262
+        BigDecimal e2 = twoF.subtract(F_squared);
263
+        E2 = e2.doubleValue();
264
+        F = db_F.doubleValue();
265
+    }
266
+
267
+    // 计算bf
268
+    private double calculateBf(double x, double projectionHeight) {
269
+        double e2 = E2;
270
+        double e4 = E2 * E2;
271
+        double e6 = e4 * E2;
272
+        double e8 = e6 * E2;
273
+        double e10 = e8 * E2;
274
+        double d = A + projectionHeight;
275
+        // 计算子午线弧长系数
276
+        double a0 = (d - d * e2) * (1
277
+                + 3.0 / 4.0 * e2
278
+                + 45.0 / 64.0 * e4
279
+                + 175.0 / 256.0 * e6
280
+                + 11025.0 / 16384.0 * e8
281
+                + 43659.0 / 65536.0 * e10);
282
+
283
+        double a2 = (d - d * e2) * (3.0 / 4.0 * e2
284
+                + 45.0 / 64.0 * e4
285
+                + 175.0 / 256.0 * e6
286
+                + 11025.0 / 16384.0 * e8
287
+                + 43659.0 / 65536.0 * e10);
288
+
289
+        double a4 = (d - d * e2) * (15.0 / 32.0 * e4
290
+                + 175.0 / 384.0 * e6
291
+                + 3675.0 / 8192.0 * e8
292
+                + 14553.0 / 32768.0 * e10);
293
+
294
+        double a6 = (d - d * e2) * (35.0 / 96.0 * e6
295
+                + 735.0 / 2048.0 * e8
296
+                + 14553.0 / 40960.0 * e10);
297
+
298
+        double a8 = (d - d * e2) * (315.0 / 1024.0 * e8
299
+                + 6237.0 / 20480.0 * e10);
300
+
301
+        double b = x / a0;
302
+        double sinB = Math.sin(b);
303
+        double cosB = Math.cos(b);
304
+        double f = -(a2 * sinB + a4 * Math.pow(sinB, 3) + a6 * Math.pow(sinB, 5) + a8 * Math.pow(sinB, 7)) * cosB;
305
+
306
+        for (int i = 0; i < 9; i++) {
307
+            b = (x - f) / a0;
308
+            sinB = Math.sin(b);
309
+            cosB = Math.cos(b);
310
+            f = -(a2 * sinB + a4 * Math.pow(sinB, 3) + a6 * Math.pow(sinB, 5) + a8 * Math.pow(sinB, 7)) * cosB;
311
+            i++;
312
+        }
313
+        return b;
314
+    }
315
+
316
+    // 计算B
317
+    private double calculateB(double bf, double tf, double etaf2, double n) {
318
+        double n2 = n * n;
319
+        double n4 = n2 * n2;
320
+        double n6 = n4 * n2;
321
+        // 计算底点纬度对应的值
322
+        double term1 = bf * 180 / Math.PI; // 转为度
323
+        // 计算括号内的各项
324
+        double bracket = 90 * n2
325
+                - 7.5 * (5 + 3 * tf * tf + etaf2 - 9 * etaf2 * tf * tf) * n4
326
+                + 0.25 * (61 + 90 * tf * tf + 45 * tf * tf * tf * tf) * n6;
327
+        // 计算第二项
328
+        double term2 = (1 + etaf2) / Math.PI * tf * bracket;
329
+        // 最终纬度 B
330
+        double B = term1 - term2;
331
+        return B;
332
+    }
333
+
334
+    // 计算l
335
+    private double calculateL(double bf, double tf, double etaf2, double n, String longitudePosition,
336
+            double bandwidth, double band) {
337
+        double n2 = n * n;
338
+        double n3 = n2 * n;
339
+        double n5 = n3 * n2;
340
+        double tf2 = tf * tf;
341
+        double tf4 = tf2 * tf2;
342
+        // 括号内计算
343
+        double bracket2 = 180 * n
344
+                - 30 * (1 + 2 * tf2 + etaf2) * n3
345
+                + 1.5 * (5 + 28 * tf2 + 24 * tf4) * n5;
346
+        double l = 1 / Math.PI / Math.cos(bf) * bracket2;
347
+
348
+        double L = "W".equals(longitudePosition)
349
+                ? (30 - band) * 6 + 3 - l
350
+                : l + (band - 30) * 6 - 3;
351
+        return L;
352
+    }
353
+
354
+    /**
355
+     * 计算子午线弧长
356
+     */
357
+    private double calculateMeridianArc(double B, double projectionHeight) {
358
+        double e2 = E2;
359
+        double e4 = E2 * E2;
360
+        double e6 = e4 * E2;
361
+        double e8 = e6 * E2;
362
+        double e10 = e8 * E2;
363
+        double d = A + projectionHeight;
364
+        // 计算子午线弧长系数
365
+        double a0 = (d - d * e2) * (1
366
+                + 3.0 / 4.0 * e2
367
+                + 45.0 / 64.0 * e4
368
+                + 175.0 / 256.0 * e6
369
+                + 11025.0 / 16384.0 * e8
370
+                + 43659.0 / 65536.0 * e10);
371
+
372
+        double a2 = (d - d * e2) * (3.0 / 4.0 * e2
373
+                + 45.0 / 64.0 * e4
374
+                + 175.0 / 256.0 * e6
375
+                + 11025.0 / 16384.0 * e8
376
+                + 43659.0 / 65536.0 * e10);
377
+
378
+        double a4 = (d - d * e2) * (15.0 / 32.0 * e4
379
+                + 175.0 / 384.0 * e6
380
+                + 3675.0 / 8192.0 * e8
381
+                + 14553.0 / 32768.0 * e10);
382
+
383
+        double a6 = (d - d * e2) * (35.0 / 96.0 * e6
384
+                + 735.0 / 2048.0 * e8
385
+                + 14553.0 / 40960.0 * e10);
386
+
387
+        double a8 = (d - d * e2) * (315.0 / 1024.0 * e8
388
+                + 6237.0 / 20480.0 * e10);
389
+
390
+        double a10 = (d - d * e2) * (693.0 / 2560.0) * e10;
391
+
392
+        // 计算子午线弧长
393
+        double sinB = Math.sin(B);
394
+        double cosB = Math.cos(B);
395
+
396
+        double X = a0 * B - (a2 * sinB + a4 * Math.pow(sinB, 3) + a6 * Math.pow(sinB, 5) + a8 * Math.pow(sinB, 7)
397
+                + a10 * Math.pow(sinB, 9)) * cosB;
398
+        return X;
399
+    }
400
+}

+ 340
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcUTMNegativeServiceImpl.java Näytä tiedosto

@@ -0,0 +1,340 @@
1
+package com.ruoyi.web.calculate.service.impl;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+import java.util.ArrayList;
6
+import java.util.HashMap;
7
+import java.util.List;
8
+import java.util.Map;
9
+
10
+import org.springframework.beans.factory.annotation.Autowired;
11
+import org.springframework.stereotype.Service;
12
+import org.springframework.transaction.annotation.Transactional;
13
+import org.springframework.web.multipart.MultipartFile;
14
+
15
+import com.ruoyi.common.core.domain.AjaxResult;
16
+import com.ruoyi.common.utils.poi.ExcelUtil;
17
+import com.ruoyi.web.calculate.domain.CmcUTMNegative;
18
+import com.ruoyi.web.calculate.service.ICmcUTMNegativeService;
19
+
20
+/**
21
+ * UTM反算服务实现
22
+ * 
23
+ * @author qyx
24
+ * @date 2026-04-21
25
+ */
26
+@Service
27
+public class CmcUTMNegativeServiceImpl implements ICmcUTMNegativeService 
28
+{
29
+    @Autowired
30
+    //扁率直接计算精度不够,在后面的椭球参数选择中用BigDecimal计算,下面的F是分母
31
+    private static final double A_WGS84 = 6378137.0;
32
+    private static final String F_WGS84 = "298.257223563";
33
+
34
+    private static final double A_CGCS2000 = 6378137.0;
35
+    private static final String F_CGCS2000 = "298.257222101";
36
+
37
+    private static final double A_BJ54 = 6378245.0;
38
+    private static final String F_BJ54 = "298.3";
39
+
40
+    private static final double A_XA80 = 6378140.0;
41
+    private static final String F_XA80 = "298.257";
42
+
43
+    private static double A;
44
+    private static double F;
45
+    private static double E2;
46
+
47
+    private static final double K0 = 0.9996; // UTM比例因子
48
+
49
+    /**
50
+     * 导入Excel数据
51
+     */
52
+    @Override
53
+    @Transactional(rollbackFor = Exception.class)
54
+    public AjaxResult importExcelData(MultipartFile file)
55
+    {
56
+        try {
57
+            // 使用若依的ExcelUtil工具类
58
+            ExcelUtil<CmcUTMNegative> util = new ExcelUtil<CmcUTMNegative>(CmcUTMNegative.class);
59
+            List<CmcUTMNegative> dataList = util.importExcel(file.getInputStream());
60
+
61
+            // 检查是否有数据
62
+            if (dataList == null || dataList.isEmpty()) {
63
+                return AjaxResult.error("Excel文件中没有数据!");
64
+            }
65
+
66
+            // 验证数据并转换为前端需要的格式
67
+            List<Map<String, Object>> validData = new ArrayList<>();
68
+            int successCount = 0;
69
+            StringBuilder errorMsg = new StringBuilder();
70
+
71
+            for (int i = 0; i < dataList.size(); i++) {
72
+                CmcUTMNegative item = dataList.get(i);
73
+
74
+                try {
75
+                    // 转换为前端需要的Map格式
76
+                    Map<String, Object> rowMap = new HashMap<>();
77
+                    rowMap.put("pointNumber", item.getPointNumber());
78
+                    rowMap.put("coordinateSystem", item.getCoordinateSystem());
79
+                    rowMap.put("utmX", item.getUtmX());
80
+                    rowMap.put("utmY", item.getUtmY());
81
+                    rowMap.put("band", item.getBand());
82
+                    rowMap.put("projectionHeight", item.getProjectionHeight());
83
+                    rowMap.put("longitudePosition", item.getLongitudePosition());
84
+                    rowMap.put("latitudePosition", item.getLatitudePosition());
85
+                    rowMap.put("rowNum", i + 2); // Excel中的行号
86
+
87
+                    validData.add(rowMap); 
88
+                    successCount++;
89
+
90
+                } catch (Exception e) {
91
+                    errorMsg.append(String.format("第%d行数据验证失败:%s;", i + 2, e.getMessage()));
92
+                }
93
+            }
94
+
95
+            // 构建返回结果
96
+            Map<String, Object> result = new HashMap<>();
97
+            result.put("total", dataList.size());
98
+            result.put("validCount", successCount);
99
+            result.put("data", validData);
100
+
101
+            if (successCount == 0) {
102
+                return AjaxResult.error("没有有效数据!" + errorMsg.toString());
103
+            }
104
+
105
+            String message = String.format("导入成功!共解析%d条数据,有效数据%d条", dataList.size(), successCount);
106
+            if (errorMsg.length() > 0) {
107
+                message += ";部分数据验证失败:" + errorMsg.toString();
108
+                return AjaxResult.success(message, result);
109
+            }
110
+
111
+            return AjaxResult.success(message, result);
112
+
113
+        } catch (Exception e) {
114
+            e.printStackTrace();
115
+            return AjaxResult.error("导入失败:" + e.getMessage());
116
+        }
117
+    }
118
+
119
+    /**
120
+     * 执行UTM反算
121
+     */
122
+    @Override
123
+    public List<CmcUTMNegative> calculateUTMNagative(List<CmcUTMNegative> dataList)
124
+    {
125
+        List<CmcUTMNegative> resultList = new ArrayList<>();
126
+        for (CmcUTMNegative item : dataList) {
127
+            try {
128
+                CmcUTMNegative result = calculateUTMNagativeSingle(item);
129
+                resultList.add(result);
130
+            } catch (Exception e) {
131
+                e.printStackTrace();
132
+                // 计算失败时,返回带有错误信息的对象
133
+                CmcUTMNegative errorResult = new CmcUTMNegative();
134
+                errorResult.setPointNumber(item.getPointNumber());
135
+                errorResult.setLongitude(-1.0);
136
+                errorResult.setLatitude(-1.0);
137
+                resultList.add(errorResult);
138
+            }
139
+        }
140
+
141
+        return resultList;
142
+    }
143
+    
144
+    /**
145
+     * 单条UTM反算(算法与高斯反算相同)
146
+     */
147
+    private CmcUTMNegative calculateUTMNagativeSingle(CmcUTMNegative cmcUTMNagative) {
148
+        try {
149
+            initEllipsoidParams(cmcUTMNagative.getCoordinateSystem());
150
+            
151
+            double utmX = cmcUTMNagative.getUtmX();
152
+            double utmY = cmcUTMNagative.getUtmY();
153
+            Integer band = cmcUTMNagative.getBand();
154
+            String longitudePosition = cmcUTMNagative.getLongitudePosition();
155
+            String latitudePosition = cmcUTMNagative.getLatitudePosition();
156
+            double projectionHeight = cmcUTMNagative.getProjectionHeight();
157
+            
158
+            // UTM使用固定6度带
159
+            int bandwidth = 6;
160
+
161
+            // 处理x坐标(南半球特殊处理)
162
+            double x = latitudePosition.equals("S") ? (10000000 - utmX)/0.9996: utmX/0.9996;
163
+            
164
+            // 处理y坐标(减去东偏500000)
165
+            double y0 = utmY > 1.0E+7 ? (utmY - (int) Math.floor(utmY / 1.0E+6) * 1.0E+6 - 500000) / 0.9996 + 500000 : (utmY - 500000)
166
+                    / 0.9996 + 500000;
167
+            double y= y0 > 1.0E+7 ? y0 - (int) Math.floor(y0 / 1.0E+6) * 1.0E+6 - 500000 : y0 - 500000;
168
+
169
+            // 计算bf
170
+            double bf = calculateBf(x, projectionHeight);
171
+            double tf = Math.tan(bf);
172
+            double ep2 = 1 / Math.pow(1 - F, 2) - 1;
173
+            double etaf2 = ep2 * Math.pow(Math.cos(bf), 2);
174
+            double Vf = Math.sqrt(1 + etaf2);
175
+            double c = (A + projectionHeight) / (1 - F);
176
+            double n = y * Vf / c;
177
+
178
+            // 计算最终纬度 B
179
+            double B = calculateB(bf, tf, etaf2, n);
180
+            // 计算经度 L
181
+            double L = calculateL(bf, tf, etaf2, n, longitudePosition, bandwidth, band);
182
+            // 大地经度和大地纬度
183
+            double longitude = convertDecimalDegrees(L);
184
+            double latitude = convertDecimalDegrees(B);
185
+
186
+            cmcUTMNagative.setLongitude(longitude);
187
+            cmcUTMNagative.setLatitude(latitude);
188
+            cmcUTMNagative.setBand(band);
189
+            
190
+        } catch (Exception e) {
191
+            e.printStackTrace();
192
+        }
193
+        return cmcUTMNagative;
194
+    }
195
+    
196
+    // 计算bf
197
+    private double calculateBf(double x, double projectionHeight) {
198
+        double e2 = E2;
199
+        double e4 = E2 * E2;
200
+        double e6 = e4 * E2;
201
+        double e8 = e6 * E2;
202
+        double e10 = e8 * E2;
203
+        double d = A + projectionHeight;
204
+        // 计算子午线弧长系数
205
+        double a0 = (d - d * e2) * (1
206
+                + 3.0 / 4.0 * e2
207
+                + 45.0 / 64.0 * e4
208
+                + 175.0 / 256.0 * e6
209
+                + 11025.0 / 16384.0 * e8
210
+                + 43659.0 / 65536.0 * e10);
211
+
212
+        double a2 = (d - d * e2) * (3.0 / 4.0 * e2
213
+                + 45.0 / 64.0 * e4
214
+                + 175.0 / 256.0 * e6
215
+                + 11025.0 / 16384.0 * e8
216
+                + 43659.0 / 65536.0 * e10);
217
+
218
+        double a4 = (d - d * e2) * (15.0 / 32.0 * e4
219
+                + 175.0 / 384.0 * e6
220
+                + 3675.0 / 8192.0 * e8
221
+                + 14553.0 / 32768.0 * e10);
222
+
223
+        double a6 = (d - d * e2) * (35.0 / 96.0 * e6
224
+                + 735.0 / 2048.0 * e8
225
+                + 14553.0 / 40960.0 * e10);
226
+
227
+        double a8 = (d - d * e2) * (315.0 / 1024.0 * e8
228
+                + 6237.0 / 20480.0 * e10);
229
+
230
+        double b = x / a0;
231
+        double sinB = Math.sin(b);
232
+        double cosB = Math.cos(b);
233
+        double f = -(a2 * sinB + a4 * Math.pow(sinB, 3) + a6 * Math.pow(sinB, 5) + a8 * Math.pow(sinB, 7)) * cosB;
234
+
235
+        for (int i = 0; i < 9; i++) {
236
+            b = (x - f) / a0;
237
+            sinB = Math.sin(b);
238
+            cosB = Math.cos(b);
239
+            f = -(a2 * sinB + a4 * Math.pow(sinB, 3) + a6 * Math.pow(sinB, 5) + a8 * Math.pow(sinB, 7)) * cosB;
240
+            i++;
241
+        }
242
+        return b;
243
+    }
244
+
245
+    //计算B
246
+    private double calculateB(double bf, double tf, double etaf2, double n) {        
247
+        double n2 = n * n;
248
+        double n4 = n2 * n2;
249
+        double n6 = n4 * n2;
250
+        // 计算底点纬度对应的值
251
+        double term1 = bf * 180 / Math.PI; // 转为度
252
+        // 计算括号内的各项
253
+        double bracket = 90 * n2
254
+                - 7.5 * (5 + 3 * tf * tf + etaf2 - 9 * etaf2 * tf * tf) * n4
255
+                + 0.25 * (61 + 90 * tf * tf + 45 * tf * tf * tf * tf) * n6;
256
+        // 计算第二项
257
+        double term2 = (1 + etaf2) / Math.PI * tf * bracket;
258
+        // 最终纬度 B
259
+        double B = term1 - term2;
260
+        return B;
261
+    }
262
+
263
+    //计算L
264
+    private double calculateL(double bf, double tf, double etaf2, double n, String longitudePosition,
265
+                 double bandwidth, double band) {
266
+        double n2 = n * n;
267
+        double n3 = n2 * n;
268
+        double n5 = n3 * n2;
269
+        double tf2 = tf * tf;
270
+        double tf4 = tf2 * tf2;
271
+        // 括号内计算
272
+        double bracket2 = 180 * n
273
+                - 30 * (1 + 2 * tf2 + etaf2) * n3
274
+                + 1.5 * (5 + 28 * tf2 + 24 * tf4) * n5;
275
+        double l = 1 / Math.PI / Math.cos(bf) * bracket2;
276
+
277
+        double L = "W".equals(longitudePosition)
278
+                ? (30 - band) * 6 + 3 - l
279
+                : l + (band - 30) * 6 - 3;
280
+        return L;
281
+    }
282
+
283
+    /**
284
+     * 将十进制度数数值转换为度分秒格式
285
+     * 
286
+     * @param decimalDegrees 十进制度数数值
287
+     * @return 转换后的值
288
+     */
289
+    private static double convertDecimalDegrees(double decimalDegrees) {
290
+
291
+        final double PRECISION = 1.2e-12; // 修正值
292
+        final double SEC_PRECISION = 1e-11; // 秒的修正值
293
+
294
+        // 提取度
295
+        double degrees = Math.floor(decimalDegrees + PRECISION);
296
+        // 提取分
297
+        double minutesRaw = 60 * (decimalDegrees - degrees);
298
+        double minutes = Math.floor(minutesRaw + PRECISION) / 100;
299
+        // 提取秒(高精度)
300
+        double secondsRaw = (decimalDegrees * 60 - Math.floor(decimalDegrees * 60 + PRECISION)) * 60;
301
+        double seconds = Math.floor((secondsRaw + SEC_PRECISION) * 1000000) / 10000000000.0;
302
+        
303
+        return degrees + minutes + seconds;
304
+    }
305
+    
306
+    //选择椭球体参数
307
+    private void initEllipsoidParams(String coordinateSystem) {
308
+        String F_str;
309
+        if ("CGCS2000".equalsIgnoreCase(coordinateSystem) || "国家2000".equalsIgnoreCase(coordinateSystem) || "2000".equalsIgnoreCase(coordinateSystem)) {
310
+            A = A_CGCS2000;
311
+            F_str = F_CGCS2000;
312
+        } else if ("1954".equalsIgnoreCase(coordinateSystem) || "北京54".equalsIgnoreCase(coordinateSystem) || "Beijing54".equalsIgnoreCase(coordinateSystem)
313
+                || "54".equalsIgnoreCase(coordinateSystem)) {
314
+            A = A_BJ54;
315
+            F_str = F_BJ54;
316
+        } else if ("1980".equalsIgnoreCase(coordinateSystem) || "西安80".equalsIgnoreCase(coordinateSystem) || "Xian80".equalsIgnoreCase(coordinateSystem)
317
+                || "80".equalsIgnoreCase(coordinateSystem)) {
318
+            A = A_XA80;
319
+            F_str = F_XA80;
320
+        } else {
321
+            A = A_WGS84;
322
+            F_str = F_WGS84;
323
+        }
324
+        BigDecimal one = BigDecimal.ONE;
325
+        BigDecimal divisor = new BigDecimal(F_str);
326
+        BigDecimal db_F = one.divide(divisor, 20, RoundingMode.HALF_UP);
327
+
328
+        // 计算 2 * F
329
+        BigDecimal two = new BigDecimal("2");
330
+        BigDecimal twoF = two.multiply(db_F);
331
+
332
+        // 计算 F * F
333
+        BigDecimal F_squared = db_F.multiply(db_F);
334
+
335
+        // 计算 e2 = 2*F - F*F
336
+        BigDecimal e2 = twoF.subtract(F_squared);
337
+        E2 = e2.doubleValue();
338
+        F = db_F.doubleValue();
339
+    }
340
+}

+ 336
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcUTMPositiveServiceImpl.java Näytä tiedosto

@@ -0,0 +1,336 @@
1
+package com.ruoyi.web.calculate.service.impl;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+import java.util.ArrayList;
6
+import java.util.HashMap;
7
+import java.util.List;
8
+import java.util.Map;
9
+
10
+import javax.servlet.http.HttpServletResponse;
11
+
12
+import org.springframework.beans.factory.annotation.Autowired;
13
+import org.springframework.stereotype.Service;
14
+import org.springframework.transaction.annotation.Transactional;
15
+import org.springframework.web.multipart.MultipartFile;
16
+
17
+import com.ruoyi.common.core.domain.AjaxResult;
18
+import com.ruoyi.common.utils.poi.ExcelUtil;
19
+import com.ruoyi.web.calculate.domain.CmcUTMPositive;
20
+import com.ruoyi.web.calculate.service.ICmcUTMPositiveService;
21
+
22
+/**
23
+ * UTM正算服务实现
24
+ * 
25
+ * @author ruoyi
26
+ * @date 2026-04-21
27
+ */
28
+@Service
29
+public class CmcUTMPositiveServiceImpl implements ICmcUTMPositiveService 
30
+{
31
+    @Autowired
32
+    //扁率直接计算精度不够,在后面的椭球参数选择中用BigDecimal计算,下面的F是分母
33
+    private static final double A_WGS84 = 6378137.0;
34
+    private static final String F_WGS84 = "298.257223563";
35
+
36
+    private static final double A_CGCS2000 = 6378137.0;
37
+    private static final String F_CGCS2000 = "298.257222101";
38
+
39
+    private static final double A_BJ54 = 6378245.0;
40
+    private static final String F_BJ54 = "298.3";
41
+
42
+    private static final double A_XA80 = 6378140.0;
43
+    private static final String F_XA80 = "298.257";
44
+
45
+    private static double A;
46
+    private static double F;
47
+    private static double E2;
48
+
49
+
50
+    /**
51
+     * 导入Excel数据
52
+     */
53
+    @Override
54
+    @Transactional(rollbackFor = Exception.class)
55
+    public AjaxResult importExcelData(MultipartFile file)
56
+    {
57
+        try {
58
+            // 使用若依的ExcelUtil工具类
59
+            ExcelUtil<CmcUTMPositive> util = new ExcelUtil<CmcUTMPositive>(CmcUTMPositive.class);
60
+            List<CmcUTMPositive> dataList = util.importExcel(file.getInputStream());
61
+
62
+            // 检查是否有数据
63
+            if (dataList == null || dataList.isEmpty()) {
64
+                return AjaxResult.error("Excel文件中没有数据!");
65
+            }
66
+
67
+            // 验证数据并转换为前端需要的格式
68
+            List<Map<String, Object>> validData = new ArrayList<>();
69
+            int successCount = 0;
70
+            StringBuilder errorMsg = new StringBuilder();
71
+
72
+            for (int i = 0; i < dataList.size(); i++) {
73
+                CmcUTMPositive item = dataList.get(i);
74
+
75
+                try {
76
+                    // 转换为前端需要的Map格式
77
+                    Map<String, Object> rowMap = new HashMap<>();
78
+                    rowMap.put("pointNumber", item.getPointNumber());
79
+                    rowMap.put("coordinateSystem", item.getCoordinateSystem());
80
+                    rowMap.put("longitude", item.getLongitude());
81
+                    rowMap.put("longitudePosition", item.getLongitudePosition());
82
+                    rowMap.put("latitude", item.getLatitude());
83
+                    rowMap.put("latitudePosition", item.getLatitudePosition());
84
+                    rowMap.put("band", item.getBand());
85
+                    rowMap.put("projectionHeight", item.getProjectionHeight());
86
+                    rowMap.put("rowNum", i + 2); // Excel中的行号
87
+
88
+                    validData.add(rowMap);
89
+                    successCount++;
90
+
91
+                } catch (Exception e) {
92
+                    errorMsg.append(String.format("第%d行数据验证失败:%s;", i + 2, e.getMessage()));
93
+                }
94
+            }
95
+
96
+            // 构建返回结果
97
+            Map<String, Object> result = new HashMap<>();
98
+            result.put("total", dataList.size());
99
+            result.put("validCount", successCount);
100
+            result.put("data", validData);
101
+
102
+            if (successCount == 0) {
103
+                return AjaxResult.error("没有有效数据!" + errorMsg.toString());
104
+            }
105
+
106
+            String message = String.format("导入成功!共解析%d条数据,有效数据%d条", dataList.size(), successCount);
107
+            if (errorMsg.length() > 0) {
108
+                message += ";部分数据验证失败:" + errorMsg.toString();
109
+                return AjaxResult.success(message, result);
110
+            }
111
+
112
+            return AjaxResult.success(message, result);
113
+
114
+        } catch (Exception e) {
115
+            e.printStackTrace();
116
+            return AjaxResult.error("导入失败:" + e.getMessage());
117
+        }
118
+    }
119
+
120
+    /**
121
+     * 执行UTM正算
122
+     */
123
+    @Override
124
+    public List<CmcUTMPositive> calculateUTMPositive(List<CmcUTMPositive> dataList)
125
+    {
126
+        List<CmcUTMPositive> resultList = new ArrayList<>();
127
+        for (CmcUTMPositive item : dataList) {
128
+            try {
129
+                CmcUTMPositive result = calculateUTMPositiveSingle(item);
130
+                resultList.add(result);
131
+            } catch (Exception e) {
132
+                e.printStackTrace();
133
+                // 计算失败时,返回带有错误信息的对象
134
+                CmcUTMPositive errorResult = new CmcUTMPositive();
135
+                errorResult.setPointNumber(item.getPointNumber());
136
+                errorResult.setUtmX(-1.0);
137
+                errorResult.setUtmY(-1.0);
138
+                errorResult.setMeridianConvergence(-1.0);
139
+                resultList.add(errorResult);
140
+            }
141
+        }
142
+
143
+        return resultList;
144
+    }
145
+    
146
+    /**
147
+     * 单条UTM正算
148
+     */
149
+    private CmcUTMPositive calculateUTMPositiveSingle(CmcUTMPositive cmcUTMPositive)
150
+    {
151
+        try {
152
+            initEllipsoidParams(cmcUTMPositive.getCoordinateSystem());
153
+
154
+            double longitude = cmcUTMPositive.getLongitude(); // 经度(度)
155
+            String longitudePosition = cmcUTMPositive.getLongitudePosition(); // 经度位置(东/西)
156
+            String latitudePosition = cmcUTMPositive.getLatitudePosition(); // 纬度位置(北/南)
157
+            double latitude = cmcUTMPositive.getLatitude(); // 纬度(度)
158
+            Integer band = cmcUTMPositive.getBand(); // 带号
159
+            double projectionHeight = cmcUTMPositive.getProjectionHeight(); // 投影面高程
160
+
161
+            // 转换为弧度
162
+            double B = convertDecimalDegrees(latitude) * Math.PI / 180;
163
+            double L = convertDecimalDegrees(longitude);
164
+           
165
+            // 计算经差
166
+            double l = ((30-band)*6+3-L) * Math.PI / 180;
167
+            // 处理西经情况
168
+            if ("东".equals(longitudePosition) || "E".equalsIgnoreCase(longitudePosition)) {
169
+                l = (L-(band-30)*6+3) * Math.PI / 180;
170
+            }
171
+            double m = Math.cos(B) * l;
172
+            double ep2 = 1 / Math.pow(1 - F, 2) - 1;
173
+            double eta2 = ep2 * Math.cos(B) * Math.cos(B);
174
+
175
+            // 计算卯酉圈曲率半径
176
+            double N = (A + projectionHeight) / ((1 - F) * Math.sqrt(1 + eta2));
177
+            // 计算子午线弧长
178
+            double X = calculateMeridianArc(B, projectionHeight);
179
+            // 计算Y坐标的系数
180
+            double t = Math.tan(B);
181
+            double t2 = t * t;
182
+            double t4 = t2 * t2;
183
+            double m2 = m * m;
184
+            double m4 = m2 * m2;
185
+
186
+            // 计算X坐标
187
+            double x = X + N * Math.cos(B) * Math.cos(B) * t * l * l / 2 +
188
+                    N * Math.pow(Math.cos(B), 4) * t * (5 - t * t + 9 * eta2 + 4 * eta2 * eta2) * Math.pow(l, 4) / 24 +
189
+                    N * Math.pow(Math.cos(B), 6) * t * (61 - 58 * t2 + t4 + 270 * eta2 - 330 * eta2 * t2)
190
+                            * Math.pow(l, 6) / 720;
191
+            // l 
192
+            double term1 = m;
193
+            //  l³ 
194
+            double term3 = (1 - t2 + eta2) * m2 * m / 6;
195
+            //  l⁵ 
196
+            double term5 = (5 - 18 * t2 + t4 + 14 * eta2 - 58 * eta2 * t2) * m4 * m / 120;
197
+            //计算y坐标
198
+            double y = N * (term1 + term3 + term5);
199
+
200
+            // 计算子午线收敛角
201
+            double meridianConvergence = t * (m + (1 + 3 * eta2 + 2 * eta2 * eta2) * m2 * m / 3 + (2 - t2) * m4 * m * 12 / 180);
202
+            meridianConvergence = Math.toDegrees(meridianConvergence);
203
+            meridianConvergence = decimalToDMS(meridianConvergence);
204
+            x= latitudePosition.equals("N") || latitudePosition.equals("北") ? 0.9996 * x :10000000 - 0.9996 * x ;
205
+            // 加入东偏
206
+            y = 500000 + 0.9996 * y;
207
+            
208
+            cmcUTMPositive.setUtmX(x);
209
+            cmcUTMPositive.setUtmY(y);
210
+            cmcUTMPositive.setMeridianConvergence(meridianConvergence);
211
+        } catch (Exception e) {
212
+            e.printStackTrace();
213
+        }
214
+        return cmcUTMPositive;
215
+    }
216
+    
217
+    //选择椭球体参数
218
+    private void initEllipsoidParams(String coordinateSystem) {
219
+        String F_str;
220
+        if ("CGCS2000".equalsIgnoreCase(coordinateSystem) || "国家2000".equalsIgnoreCase(coordinateSystem) || "2000".equalsIgnoreCase(coordinateSystem)) {
221
+            A = A_CGCS2000;
222
+            F_str = F_CGCS2000;
223
+        } else if ("1954".equalsIgnoreCase(coordinateSystem) || "北京54".equalsIgnoreCase(coordinateSystem) || "Beijing54".equalsIgnoreCase(coordinateSystem)
224
+                || "54".equalsIgnoreCase(coordinateSystem)) {
225
+            A = A_BJ54;
226
+            F_str = F_BJ54;
227
+        } else if ("1980".equalsIgnoreCase(coordinateSystem) || "西安80".equalsIgnoreCase(coordinateSystem) || "Xian80".equalsIgnoreCase(coordinateSystem)
228
+                || "80".equalsIgnoreCase(coordinateSystem)) {
229
+            A = A_XA80;
230
+            F_str = F_XA80;
231
+        } else {
232
+            A = A_WGS84;
233
+            F_str = F_WGS84;
234
+        }
235
+        BigDecimal one = BigDecimal.ONE;
236
+        BigDecimal divisor = new BigDecimal(F_str);
237
+        BigDecimal db_F = one.divide(divisor, 20, RoundingMode.HALF_UP);
238
+
239
+        // 计算 2 * F
240
+        BigDecimal two = new BigDecimal("2");
241
+        BigDecimal twoF = two.multiply(db_F);
242
+
243
+        // 计算 F * F
244
+        BigDecimal F_squared = db_F.multiply(db_F);
245
+
246
+        // 计算 e2 = 2*F - F*F
247
+        BigDecimal e2 = twoF.subtract(F_squared);
248
+        E2 = e2.doubleValue();
249
+        F = db_F.doubleValue();
250
+    }
251
+
252
+    /**
253
+     * 计算子午线弧长
254
+     */
255
+    private double calculateMeridianArc(double B, double projectionHeight) {
256
+        double e2 = E2;
257
+        double e4 = E2 * E2;
258
+        double e6 = e4 * E2;
259
+        double e8 = e6 * E2;
260
+        double e10 = e8 * E2;
261
+        double d = A + projectionHeight;
262
+        // 计算子午线弧长系数
263
+        double a0 = (d - d * e2) * (1
264
+                + 3.0 / 4.0 * e2
265
+                + 45.0 / 64.0 * e4
266
+                + 175.0 / 256.0 * e6
267
+                + 11025.0 / 16384.0 * e8
268
+                + 43659.0 / 65536.0 * e10);
269
+
270
+        double a2 = (d - d * e2) * (3.0 / 4.0 * e2
271
+                + 45.0 / 64.0 * e4
272
+                + 175.0 / 256.0 * e6
273
+                + 11025.0 / 16384.0 * e8
274
+                + 43659.0 / 65536.0 * e10);
275
+
276
+        double a4 = (d - d * e2) * (15.0 / 32.0 * e4
277
+                + 175.0 / 384.0 * e6
278
+                + 3675.0 / 8192.0 * e8
279
+                + 14553.0 / 32768.0 * e10);
280
+
281
+        double a6 = (d - d * e2) * (35.0 / 96.0 * e6
282
+                + 735.0 / 2048.0 * e8
283
+                + 14553.0 / 40960.0 * e10);
284
+
285
+        double a8 = (d - d * e2) * (315.0 / 1024.0 * e8
286
+                + 6237.0 / 20480.0 * e10);
287
+
288
+        double a10 = (d - d * e2) * (693.0/2560.0)* e10;
289
+
290
+        // 计算子午线弧长
291
+        double sinB = Math.sin(B);
292
+        double cosB = Math.cos(B);
293
+
294
+        double X = a0 * B - (a2 * sinB + a4 * Math.pow(sinB, 3) + a6 * Math.pow(sinB, 5) + a8 * Math.pow(sinB, 7)
295
+                + a10 * Math.pow(sinB, 9)) * cosB;
296
+        return X;
297
+    }
298
+    
299
+    /**
300
+     * 将十进制度数转换为特定格式(
301
+     * @param decimalDegrees 十进制度数
302
+     * @return 转换后的值
303
+     */
304
+    public static double convertDecimalDegrees(double decimalDegrees) {
305
+        // 度的整数部分
306
+        double degrees = Math.floor(decimalDegrees + 1.0E-12);
307
+
308
+        // 分的计算
309
+        double minutes = Math.floor(100 * (decimalDegrees - degrees) + 1.0E-12) / 60;
310
+
311
+        // 秒的计算
312
+        double seconds = (decimalDegrees * 100 - Math.floor(decimalDegrees * 100 + 1.0E-12)) / 36;
313
+
314
+        return degrees + minutes + seconds;
315
+    }
316
+    
317
+    /**
318
+     * 将十进制度数转换为度分秒格式数值(DD.MMSSssss)
319
+     * 
320
+     * @param decimalDegrees 十进制度数(如 103.373428195)
321
+     */
322
+    public static double decimalToDMS(double decimalDegrees) {
323
+        // 1. 提取度
324
+        double degrees = Math.floor(decimalDegrees + 1.0E-12);
325
+
326
+        // 2. 提取分
327
+        double minutesRaw = 60 * (decimalDegrees - degrees);
328
+        double minutes = Math.floor(minutesRaw + 1.0E-12) / 100;
329
+
330
+        // 3. 提取秒
331
+        double secondsRaw = 60 * (60 * decimalDegrees - Math.floor(60 * decimalDegrees + 1.0E-12))+ 1.0E-12;
332
+        double seconds = secondsRaw / 10000;
333
+
334
+        return degrees + minutes + seconds;
335
+    }
336
+}

+ 125
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcGaussBandChangeTemplate.java Näytä tiedosto

@@ -0,0 +1,125 @@
1
+package com.ruoyi.web.calculate.vo;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+
6
+import com.ruoyi.common.annotation.Excel;
7
+import com.ruoyi.common.annotation.Excel.ColumnType;
8
+
9
+public class CmcGaussBandChangeTemplate {
10
+
11
+    @Excel(name = "待求点")
12
+    private String pointNumber;
13
+
14
+    @Excel(name = "坐标系")
15
+    private String coordinateSystem;
16
+
17
+    @Excel(name = "高斯坐标x", cellType = ColumnType.NUMERIC)
18
+    private Double gaussX;
19
+
20
+    @Excel(name = "高斯坐标y", cellType = ColumnType.NUMERIC)
21
+    private Double gaussY;
22
+
23
+     /** 带号 */
24
+    @Excel(name = "带号", cellType = ColumnType.NUMERIC)
25
+    private Integer band;
26
+
27
+    /** 带宽 */
28
+    @Excel(name = "带宽", cellType = ColumnType.NUMERIC)
29
+    private Integer bandwidth;
30
+
31
+    /** 新带号 */
32
+    @Excel(name = "新带号", cellType = ColumnType.NUMERIC)
33
+    private Integer newBand;
34
+
35
+    /** 新带宽 */
36
+    @Excel(name = "新带宽", cellType = ColumnType.NUMERIC)
37
+    private Integer newBandwidth;
38
+
39
+    @Excel(name = "经度位置")
40
+    private String longitudePosition;
41
+
42
+    @Excel(name = "纬度位置")
43
+    private String latitudePosition;
44
+
45
+    public void setPointNumber(String pointNumber) {
46
+        this.pointNumber = pointNumber;
47
+    }
48
+
49
+    public String getPointNumber() {
50
+        return pointNumber;
51
+    }
52
+
53
+    public void setCoordinateSystem(String coordinateSystem) {
54
+        this.coordinateSystem = coordinateSystem;
55
+    }
56
+
57
+    public String getCoordinateSystem() {
58
+        return coordinateSystem;
59
+    }
60
+
61
+    public void setGaussX(Double gaussX) {
62
+        this.gaussX = gaussX;
63
+    }
64
+
65
+    public Double getGaussX() {
66
+        return gaussX;
67
+    }
68
+
69
+    public void setGaussY(Double gaussY) {
70
+        this.gaussY = gaussY;
71
+    }
72
+
73
+    public Double getGaussY() {
74
+        return gaussY;
75
+    }
76
+
77
+    public void setBand(Integer band) {
78
+        this.band = band;
79
+    }
80
+
81
+    public Integer getBand() {
82
+        return band;
83
+    }
84
+    
85
+    public void setBandwidth(Integer bandwidth) {
86
+        this.bandwidth = bandwidth;
87
+    }
88
+
89
+    public Integer getBandwidth() {
90
+        return bandwidth;
91
+    }
92
+    
93
+    public void setNewBand(Integer newBand) {
94
+        this.newBand = newBand;
95
+    }
96
+
97
+    public Integer getNewBand() {
98
+        return newBand;
99
+    }
100
+    
101
+    public void setNewBandwidth(Integer newBandwidth) {
102
+        this.newBandwidth = newBandwidth;
103
+    }
104
+
105
+    public Integer getNewBandwidth() {
106
+        return newBandwidth;
107
+    }
108
+
109
+    public void setLongitudePosition(String longitudePosition) {
110
+        this.longitudePosition = longitudePosition;
111
+    }
112
+
113
+    public String getLongitudePosition() {
114
+        return longitudePosition;
115
+    }
116
+
117
+    public void setLatitudePosition(String latitudePosition) {
118
+        this.latitudePosition = latitudePosition;
119
+    }
120
+
121
+    public String getLatitudePosition() {
122
+        return latitudePosition;
123
+    }
124
+
125
+}

+ 3
- 2
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcGaussNegativeTemplate.java Näytä tiedosto

@@ -4,6 +4,7 @@ import java.math.BigDecimal;
4 4
 import java.math.RoundingMode;
5 5
 
6 6
 import com.ruoyi.common.annotation.Excel;
7
+import com.ruoyi.common.annotation.Excel.ColumnType;
7 8
 
8 9
 public class CmcGaussNegativeTemplate {
9 10
 
@@ -13,10 +14,10 @@ public class CmcGaussNegativeTemplate {
13 14
     @Excel(name = "坐标系")
14 15
     private String coordinateSystem;
15 16
 
16
-    @Excel(name = "高斯坐标x")
17
+    @Excel(name = "高斯坐标x", cellType = ColumnType.NUMERIC)
17 18
     private Double gaussX;
18 19
 
19
-    @Excel(name = "高斯坐标y")
20
+    @Excel(name = "高斯坐标y", cellType = ColumnType.NUMERIC)
20 21
     private Double gaussY;
21 22
 
22 23
     @Excel(name = "经度位置")

+ 10
- 9
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcGaussPositiveTemplate.java Näytä tiedosto

@@ -4,6 +4,7 @@ import java.math.BigDecimal;
4 4
 import java.math.RoundingMode;
5 5
 
6 6
 import com.ruoyi.common.annotation.Excel;
7
+import com.ruoyi.common.annotation.Excel.ColumnType;
7 8
 
8 9
 public class CmcGaussPositiveTemplate {
9 10
 
@@ -13,22 +14,22 @@ public class CmcGaussPositiveTemplate {
13 14
     @Excel(name = "坐标系")
14 15
     private String coordinateSystem;
15 16
 
16
-    @Excel(name = "大地经度")
17
+    @Excel(name = "大地经度", cellType = ColumnType.NUMERIC)
17 18
     private Double longitude;
18 19
 
19 20
     @Excel(name = "经度位置")
20 21
     private String longitudePosition;
21 22
 
22
-    @Excel(name = "大地纬度")
23
+    @Excel(name = "大地纬度", cellType = ColumnType.NUMERIC)
23 24
     private Double latitude;
24 25
 
25 26
     @Excel(name = "纬度位置")
26 27
     private String latitudePosition;
27 28
 
28
-    @Excel(name = "带号")
29
-    private Integer zone;
29
+    @Excel(name = "带号", cellType = ColumnType.NUMERIC)
30
+    private Integer band;
30 31
 
31
-    @Excel(name = "带宽")
32
+    @Excel(name = "带宽", cellType = ColumnType.NUMERIC)
32 33
     private Integer bandwidth;
33 34
 
34 35
     public void setPointNumber(String pointNumber) 
@@ -101,14 +102,14 @@ public class CmcGaussPositiveTemplate {
101 102
         return latitudePosition;
102 103
     }
103 104
     
104
-    public void setZone(Integer zone) 
105
+    public void setBand(Integer band) 
105 106
     {
106
-        this.zone = zone;
107
+        this.band = band;
107 108
     }
108 109
 
109
-    public Integer getZone() 
110
+    public Integer getBand() 
110 111
     {
111
-        return zone;
112
+        return band;
112 113
     }
113 114
     
114 115
     public void setBandwidth(Integer bandwidth) 

+ 88
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcGeodeticToSpatialTemplate.java Näytä tiedosto

@@ -0,0 +1,88 @@
1
+package com.ruoyi.web.calculate.vo;
2
+
3
+import com.ruoyi.common.annotation.Excel;
4
+import com.ruoyi.common.annotation.Excel.ColumnType;
5
+
6
+/**
7
+ * 大地坐标转空间直角坐标模板
8
+ */
9
+public class CmcGeodeticToSpatialTemplate {
10
+
11
+    @Excel(name = "待求点")
12
+    private String pointNumber;
13
+
14
+    @Excel(name = "坐标系")
15
+    private String coordinateSystem;
16
+
17
+    @Excel(name = "大地经度", cellType = ColumnType.NUMERIC)
18
+    private Double longitude;
19
+
20
+    @Excel(name = "经度位置")
21
+    private String longitudePosition;
22
+
23
+    @Excel(name = "大地纬度", cellType = ColumnType.NUMERIC)
24
+    private Double latitude;
25
+
26
+    @Excel(name = "纬度位置")
27
+    private String latitudePosition;
28
+
29
+    @Excel(name = "大地高", cellType = ColumnType.NUMERIC)
30
+    private Double height;
31
+
32
+    public void setPointNumber(String pointNumber) {
33
+        this.pointNumber = pointNumber;
34
+    }
35
+
36
+    public String getPointNumber() {
37
+        return pointNumber;
38
+    }
39
+
40
+    public void setCoordinateSystem(String coordinateSystem) {
41
+        this.coordinateSystem = coordinateSystem;
42
+    }
43
+
44
+    public String getCoordinateSystem() {
45
+        return coordinateSystem;
46
+    }
47
+
48
+    public void setLongitude(Double longitude) {
49
+        this.longitude = longitude;
50
+    }
51
+
52
+    public Double getLongitude() {
53
+        return longitude;
54
+    }
55
+
56
+    public void setLongitudePosition(String longitudePosition) {
57
+        this.longitudePosition = longitudePosition;
58
+    }
59
+
60
+    public String getLongitudePosition() {
61
+        return longitudePosition;
62
+    }
63
+
64
+    public void setLatitude(Double latitude) {
65
+        this.latitude = latitude;
66
+    }
67
+
68
+    public Double getLatitude() {
69
+        return latitude;
70
+    }
71
+
72
+    public void setLatitudePosition(String latitudePosition) {
73
+        this.latitudePosition = latitudePosition;
74
+    }
75
+
76
+    public String getLatitudePosition() {
77
+        return latitudePosition;
78
+    }
79
+
80
+    public void setHeight(Double height) {
81
+        this.height = height;
82
+    }
83
+
84
+    public Double getHeight() {
85
+        return height;
86
+    }
87
+
88
+}

+ 66
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcSpatialToGeodeticTemplate.java Näytä tiedosto

@@ -0,0 +1,66 @@
1
+package com.ruoyi.web.calculate.vo;
2
+
3
+import com.ruoyi.common.annotation.Excel;
4
+import com.ruoyi.common.annotation.Excel.ColumnType;
5
+
6
+/**
7
+ * 空间直角坐标转大地坐标模板
8
+ */
9
+public class CmcSpatialToGeodeticTemplate {
10
+
11
+    @Excel(name = "待求点")
12
+    private String pointNumber;
13
+
14
+    @Excel(name = "坐标系")
15
+    private String coordinateSystem;
16
+
17
+    @Excel(name = "空间坐标X", cellType = ColumnType.NUMERIC)
18
+    private Double spatialX;
19
+
20
+    @Excel(name = "空间坐标Y", cellType = ColumnType.NUMERIC)
21
+    private Double spatialY;
22
+
23
+    @Excel(name = "空间坐标Z", cellType = ColumnType.NUMERIC)
24
+    private Double spatialZ;
25
+
26
+    public void setPointNumber(String pointNumber) {
27
+        this.pointNumber = pointNumber;
28
+    }
29
+
30
+    public String getPointNumber() {
31
+        return pointNumber;
32
+    }
33
+
34
+    public void setCoordinateSystem(String coordinateSystem) {
35
+        this.coordinateSystem = coordinateSystem;
36
+    }
37
+
38
+    public String getCoordinateSystem() {
39
+        return coordinateSystem;
40
+    }
41
+
42
+    public void setSpatialX(Double spatialX) {
43
+        this.spatialX = spatialX;
44
+    }
45
+
46
+    public Double getSpatialX() {
47
+        return spatialX;
48
+    }
49
+
50
+    public void setSpatialY(Double spatialY) {
51
+        this.spatialY = spatialY;
52
+    }
53
+
54
+    public Double getSpatialY() {
55
+        return spatialY;
56
+    }
57
+
58
+    public void setSpatialZ(Double spatialZ) {
59
+        this.spatialZ = spatialZ;
60
+    }
61
+
62
+    public Double getSpatialZ() {
63
+        return spatialZ;
64
+    }
65
+
66
+}

+ 101
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcUTMBandChangeTemplate.java Näytä tiedosto

@@ -0,0 +1,101 @@
1
+package com.ruoyi.web.calculate.vo;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+
6
+import com.ruoyi.common.annotation.Excel;
7
+import com.ruoyi.common.annotation.Excel.ColumnType;
8
+
9
+public class CmcUTMBandChangeTemplate {
10
+
11
+    @Excel(name = "待求点")
12
+    private String pointNumber;
13
+
14
+    @Excel(name = "坐标系")
15
+    private String coordinateSystem;
16
+
17
+    @Excel(name = "UTM坐标x", cellType = ColumnType.NUMERIC)
18
+    private Double utmX;
19
+
20
+    @Excel(name = "UTM坐标y", cellType = ColumnType.NUMERIC)
21
+    private Double utmY;
22
+
23
+    /** 带号 */
24
+    @Excel(name = "带号", cellType = ColumnType.NUMERIC)
25
+    private Integer band;
26
+
27
+    /** 新带号 */
28
+    @Excel(name = "新带号", cellType = ColumnType.NUMERIC)
29
+    private Integer newBand;
30
+
31
+    @Excel(name = "经度位置")
32
+    private String longitudePosition;
33
+
34
+    @Excel(name = "纬度位置")
35
+    private String latitudePosition;
36
+
37
+    public void setPointNumber(String pointNumber) {
38
+        this.pointNumber = pointNumber;
39
+    }
40
+
41
+    public String getPointNumber() {
42
+        return pointNumber;
43
+    }
44
+
45
+    public void setCoordinateSystem(String coordinateSystem) {
46
+        this.coordinateSystem = coordinateSystem;
47
+    }
48
+
49
+    public String getCoordinateSystem() {
50
+        return coordinateSystem;
51
+    }
52
+
53
+    public void setUtmX(Double utmX) {
54
+        this.utmX = utmX;
55
+    }
56
+
57
+    public Double getUtmX() {
58
+        return utmX;
59
+    }
60
+
61
+    public void setUtmY(Double utmY) {
62
+        this.utmY = utmY;
63
+    }
64
+
65
+    public Double getUtmY() {
66
+        return utmY;
67
+    }
68
+
69
+    public void setBand(Integer band) {
70
+        this.band = band;
71
+    }
72
+
73
+    public Integer getBand() {
74
+        return band;
75
+    }
76
+    
77
+    public void setNewBand(Integer newBand) {
78
+        this.newBand = newBand;
79
+    }
80
+
81
+    public Integer getNewBand() {
82
+        return newBand;
83
+    }
84
+
85
+    public void setLongitudePosition(String longitudePosition) {
86
+        this.longitudePosition = longitudePosition;
87
+    }
88
+
89
+    public String getLongitudePosition() {
90
+        return longitudePosition;
91
+    }
92
+
93
+    public void setLatitudePosition(String latitudePosition) {
94
+        this.latitudePosition = latitudePosition;
95
+    }
96
+
97
+    public String getLatitudePosition() {
98
+        return latitudePosition;
99
+    }
100
+
101
+}

+ 98
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcUTMNegativeTemplate.java Näytä tiedosto

@@ -0,0 +1,98 @@
1
+package com.ruoyi.web.calculate.vo;
2
+
3
+import com.ruoyi.common.annotation.Excel;
4
+import com.ruoyi.common.annotation.Excel.ColumnType;
5
+
6
+public class CmcUTMNegativeTemplate {
7
+
8
+    @Excel(name = "待求点")
9
+    private String pointNumber;
10
+
11
+    @Excel(name = "坐标系")
12
+    private String coordinateSystem;
13
+
14
+    @Excel(name = "UTM坐标x", cellType = ColumnType.NUMERIC)
15
+    private Double utmX;
16
+
17
+    @Excel(name = "UTM坐标y", cellType = ColumnType.NUMERIC)
18
+    private Double utmY;
19
+
20
+    @Excel(name = "带号", cellType = ColumnType.NUMERIC)
21
+    private Integer band;
22
+
23
+    @Excel(name = "经度位置")
24
+    private String longitudePosition;
25
+
26
+    @Excel(name = "纬度位置")
27
+    private String latitudePosition;
28
+
29
+    public void setPointNumber(String pointNumber) 
30
+    {
31
+        this.pointNumber = pointNumber;
32
+    }
33
+
34
+    public String getPointNumber() 
35
+    {
36
+        return pointNumber;
37
+    }
38
+    
39
+    public void setCoordinateSystem(String coordinateSystem) 
40
+    {
41
+        this.coordinateSystem = coordinateSystem;
42
+    }
43
+
44
+    public String getCoordinateSystem() 
45
+    {
46
+        return coordinateSystem;
47
+    }
48
+    
49
+    public void setUtmX(Double utmX) 
50
+    {
51
+        this.utmX = utmX;
52
+    }
53
+
54
+    public Double getUtmX() 
55
+    {
56
+        return utmX;
57
+    }
58
+    
59
+    public void setUtmY(Double utmY) 
60
+    {
61
+        this.utmY = utmY;
62
+    }
63
+
64
+    public Double getUtmY() 
65
+    {
66
+        return utmY;
67
+    }
68
+    
69
+    public void setBand(Integer band) 
70
+    {
71
+        this.band = band;
72
+    }
73
+
74
+    public Integer getBand() 
75
+    {
76
+        return band;
77
+    }
78
+    
79
+    public void setLongitudePosition(String longitudePosition) 
80
+    {
81
+        this.longitudePosition = longitudePosition;
82
+    }
83
+
84
+    public String getLongitudePosition() 
85
+    {
86
+        return longitudePosition;
87
+    }
88
+    
89
+    public void setLatitudePosition(String latitudePosition) 
90
+    {
91
+        this.latitudePosition = latitudePosition;
92
+    }
93
+
94
+    public String getLatitudePosition() 
95
+    {
96
+        return latitudePosition;
97
+    }
98
+}

+ 109
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcUTMPositiveTemplate.java Näytä tiedosto

@@ -0,0 +1,109 @@
1
+package com.ruoyi.web.calculate.vo;
2
+
3
+import java.math.BigDecimal;
4
+import java.math.RoundingMode;
5
+
6
+import com.ruoyi.common.annotation.Excel;
7
+import com.ruoyi.common.annotation.Excel.ColumnType;
8
+
9
+public class CmcUTMPositiveTemplate {
10
+
11
+    @Excel(name = "待求点")
12
+    private String pointNumber;
13
+
14
+    @Excel(name = "坐标系")
15
+    private String coordinateSystem;
16
+
17
+    @Excel(name = "大地经度", cellType = ColumnType.NUMERIC)
18
+    private Double longitude;
19
+
20
+    @Excel(name = "经度位置")
21
+    private String longitudePosition;
22
+
23
+    @Excel(name = "大地纬度", cellType = ColumnType.NUMERIC)
24
+    private Double latitude;
25
+
26
+    @Excel(name = "纬度位置")
27
+    private String latitudePosition;
28
+
29
+    @Excel(name = "带号", cellType = ColumnType.NUMERIC)
30
+    private Integer band;
31
+
32
+    public void setPointNumber(String pointNumber) 
33
+    {
34
+        this.pointNumber = pointNumber;
35
+    }
36
+
37
+    public String getPointNumber() 
38
+    {
39
+        return pointNumber;
40
+    }
41
+    public void setCoordinateSystem(String coordinateSystem) 
42
+    {
43
+        this.coordinateSystem = coordinateSystem;
44
+    }
45
+
46
+    public String getCoordinateSystem() 
47
+    {
48
+        return coordinateSystem;
49
+    }
50
+     public void setLongitude(Double longitude) 
51
+    {
52
+        if (longitude != null) {
53
+            BigDecimal bd = new BigDecimal(longitude);
54
+            this.longitude = bd.setScale(10, RoundingMode.HALF_UP).doubleValue();
55
+        } else {
56
+            this.longitude = null;
57
+        }
58
+    }
59
+
60
+    public Double getLongitude() 
61
+    {
62
+        return longitude;
63
+    }
64
+    
65
+    public void setLongitudePosition(String longitudePosition) 
66
+    {
67
+        this.longitudePosition = longitudePosition;
68
+    }
69
+
70
+    public String getLongitudePosition() 
71
+    {
72
+        return longitudePosition;
73
+    }
74
+    
75
+    public void setLatitude(Double latitude) 
76
+    {
77
+        if (latitude != null) {
78
+            BigDecimal bd = new BigDecimal(latitude);
79
+            this.latitude = bd.setScale(10, RoundingMode.HALF_UP).doubleValue();
80
+        } else {
81
+            this.latitude = null;
82
+        }
83
+    }
84
+
85
+    public Double getLatitude() 
86
+    {
87
+        return latitude;
88
+    }
89
+    
90
+    public void setLatitudePosition(String latitudePosition) 
91
+    {
92
+        this.latitudePosition = latitudePosition;
93
+    }
94
+
95
+    public String getLatitudePosition() 
96
+    {
97
+        return latitudePosition;
98
+    }
99
+    
100
+    public void setBand(Integer band) 
101
+    {
102
+        this.band = band;
103
+    }
104
+
105
+    public Integer getBand() 
106
+    {
107
+        return band;
108
+    }
109
+}

+ 42
- 0
oa-ui/src/api/calculate/gaussbandchange.js Näytä tiedosto

@@ -0,0 +1,42 @@
1
+import request from '@/utils/request'
2
+
3
+
4
+// 执行高斯正算
5
+export function calculate(data) {
6
+    return request({
7
+        url: `/calculate/gaussBandChange/calculate`,
8
+        method: 'post',
9
+        data: data
10
+    })
11
+}
12
+
13
+// 导入Excel
14
+export function importExcel(data) {
15
+    return request({
16
+        url: `/calculate/gaussBandChange/import`,
17
+        method: 'post',
18
+        data: data,
19
+        headers: {
20
+            'Content-Type': 'multipart/form-data'
21
+        }
22
+    })
23
+}
24
+
25
+// 导出高斯换带
26
+export function exportExcel(data) {
27
+    return request({
28
+        url: `/calculate/gaussBandChange/export`,
29
+        method: 'post',
30
+        data: data,
31
+        responseType: 'blob'
32
+    })
33
+}
34
+
35
+// 下载模板
36
+export function downloadTemplate() {
37
+    return request({
38
+        url: '/calculate/gaussBandChange/template',
39
+        method: 'get',
40
+        responseType: 'blob'
41
+    })
42
+}

+ 41
- 0
oa-ui/src/api/calculate/geodetictospatial.js Näytä tiedosto

@@ -0,0 +1,41 @@
1
+import request from '@/utils/request'
2
+
3
+// 执行大地坐标转空间直角坐标
4
+export function calculate(data) {
5
+    return request({
6
+        url: `/calculate/geodeticToSpatial/calculate`,
7
+        method: 'post',
8
+        data: data
9
+    })
10
+}
11
+
12
+// 导入 Excel
13
+export function importExcel(data) {
14
+    return request({
15
+        url: `/calculate/geodeticToSpatial/import`,
16
+        method: 'post',
17
+        data: data,
18
+        headers: {
19
+            'Content-Type': 'multipart/form-data'
20
+        }
21
+    })
22
+}
23
+
24
+// 导出大地坐标转空间直角坐标
25
+export function exportExcel(data) {
26
+    return request({
27
+        url: `/calculate/geodeticToSpatial/export`,
28
+        method: 'post',
29
+        data: data,
30
+        responseType: 'blob'
31
+    })
32
+}
33
+
34
+// 下载模板
35
+export function downloadTemplate() {
36
+    return request({
37
+        url: '/calculate/geodeticToSpatial/template',
38
+        method: 'get',
39
+        responseType: 'blob'
40
+    })
41
+}

+ 41
- 0
oa-ui/src/api/calculate/spatialtogeodetic.js Näytä tiedosto

@@ -0,0 +1,41 @@
1
+import request from '@/utils/request'
2
+
3
+// 执行空间坐标转大地坐标
4
+export function calculate(data) {
5
+    return request({
6
+        url: `/calculate/spatialToGeodetic/calculate`,
7
+        method: 'post',
8
+        data: data
9
+    })
10
+}
11
+
12
+// 导入 Excel
13
+export function importExcel(data) {
14
+    return request({
15
+        url: `/calculate/spatialToGeodetic/import`,
16
+        method: 'post',
17
+        data: data,
18
+        headers: {
19
+            'Content-Type': 'multipart/form-data'
20
+        }
21
+    })
22
+}
23
+
24
+// 导出空间坐标转大地坐标
25
+export function exportExcel(data) {
26
+    return request({
27
+        url: `/calculate/spatialToGeodetic/export`,
28
+        method: 'post',
29
+        data: data,
30
+        responseType: 'blob'
31
+    })
32
+}
33
+
34
+// 下载模板
35
+export function downloadTemplate() {
36
+    return request({
37
+        url: '/calculate/spatialToGeodetic/template',
38
+        method: 'get',
39
+        responseType: 'blob'
40
+    })
41
+}

+ 42
- 0
oa-ui/src/api/calculate/utmbandchange.js Näytä tiedosto

@@ -0,0 +1,42 @@
1
+import request from '@/utils/request'
2
+
3
+
4
+// 执行UTM换带计算
5
+export function calculate(data) {
6
+    return request({
7
+        url: `/calculate/utmBandChange/calculate`,
8
+        method: 'post',
9
+        data: data
10
+    })
11
+}
12
+
13
+// 导入Excel
14
+export function importExcel(data) {
15
+    return request({
16
+        url: `/calculate/utmBandChange/import`,
17
+        method: 'post',
18
+        data: data,
19
+        headers: {
20
+            'Content-Type': 'multipart/form-data'
21
+        }
22
+    })
23
+}
24
+
25
+// 导出UTM换带
26
+export function exportExcel(data) {
27
+    return request({
28
+        url: `/calculate/utmBandChange/export`,
29
+        method: 'post',
30
+        data: data,
31
+        responseType: 'blob'
32
+    })
33
+}
34
+
35
+// 下载模板
36
+export function downloadTemplate() {
37
+    return request({
38
+        url: '/calculate/utmBandChange/template',
39
+        method: 'get',
40
+        responseType: 'blob'
41
+    })
42
+}

+ 42
- 0
oa-ui/src/api/calculate/utmnegative.js Näytä tiedosto

@@ -0,0 +1,42 @@
1
+import request from '@/utils/request'
2
+
3
+
4
+// 执行UTM反算
5
+export function calculate(data) {
6
+    return request({
7
+        url: `/calculate/utmNegative/calculate`,
8
+        method: 'post',
9
+        data: data
10
+    })
11
+}
12
+
13
+// 导入Excel
14
+export function importExcel(data) {
15
+    return request({
16
+        url: `/calculate/utmNegative/import`,
17
+        method: 'post',
18
+        data: data,
19
+        headers: {
20
+            'Content-Type': 'multipart/form-data'
21
+        }
22
+    })
23
+}
24
+
25
+// 导出UTM反算
26
+export function exportExcel(data) {
27
+    return request({
28
+        url: `/calculate/utmNegative/export`,
29
+        method: 'post',
30
+        data: data,
31
+        responseType: 'blob'
32
+    })
33
+}
34
+
35
+// 下载模板
36
+export function downloadTemplate() {
37
+    return request({
38
+        url: '/calculate/utmNegative/template',
39
+        method: 'get',
40
+        responseType: 'blob'
41
+    })
42
+}

+ 42
- 0
oa-ui/src/api/calculate/utmpositive.js Näytä tiedosto

@@ -0,0 +1,42 @@
1
+import request from '@/utils/request'
2
+
3
+
4
+// 执行UTM正算
5
+export function calculate(data) {
6
+    return request({
7
+        url: `/calculate/utmPositive/calculate`,
8
+        method: 'post',
9
+        data: data
10
+    })
11
+}
12
+
13
+// 导入Excel
14
+export function importExcel(data) {
15
+    return request({
16
+        url: `/calculate/utmPositive/import`,
17
+        method: 'post',
18
+        data: data,
19
+        headers: {
20
+            'Content-Type': 'multipart/form-data'
21
+        }
22
+    })
23
+}
24
+
25
+// 导出UTM正算
26
+export function exportExcel(data) {
27
+    return request({
28
+        url: `/calculate/utmPositive/export`,
29
+        method: 'post',
30
+        data: data,
31
+        responseType: 'blob'
32
+    })
33
+}
34
+
35
+// 下载模板
36
+export function downloadTemplate() {
37
+    return request({
38
+        url: '/calculate/utmPositive/template',
39
+        method: 'get',
40
+        responseType: 'blob'
41
+    })
42
+}

+ 88
- 10
oa-ui/src/views/calculate/index.vue Näytä tiedosto

@@ -20,14 +20,25 @@
20 20
     
21 21
     <!-- 动态组件:根据选择的工具显示对应的工具页面 -->
22 22
     <div class="tool-content">
23
-      <transition name="fade" mode="out-in">
24
-        <component 
25
-          :is="currentToolComponent" 
26
-          :key="currentToolKey"
27
-          ref="currentTool"
28
-          @tool-event="handleToolEvent"
29
-        />
30
-      </transition>
23
+      <!-- 当前工具标题 -->
24
+      <div class="tool-header">
25
+        <div class="tool-title">
26
+          <!-- <i class="el-icon-location"></i> -->
27
+          <span>{{ currentToolName }}</span>
28
+        </div>
29
+      </div>
30
+      
31
+      <!-- 工具内容区域(带内边距,不影响子组件布局) -->
32
+      <div class="tool-body">
33
+        <transition name="fade" mode="out-in">
34
+          <component 
35
+            :is="currentToolComponent" 
36
+            :key="currentToolKey"
37
+            ref="currentTool"
38
+            @tool-event="handleToolEvent"
39
+          />
40
+        </transition>
41
+      </div>
31 42
     </div>
32 43
   </div>
33 44
 </template>
@@ -36,12 +47,24 @@
36 47
 // 导入各个工具组件
37 48
 import GaussPositiveTool from './tools/gausspositive.vue'
38 49
 import GaussNegativeTool from './tools/gaussnegative.vue'
50
+import GaussBandChangeTool from './tools/gaussbandchange.vue'
51
+import UTMPositiveTool from './tools/utmpositive.vue'
52
+import UTMNegativeTool from './tools/utmnegative.vue'
53
+import UTMBandChangeTool from './tools/utmbandchange.vue'
54
+import GeodeticToSpatialTool from './tools/geodetictospatial.vue'
55
+import SpatialToGeodeticTool from './tools/spatialtogeodetic.vue'
39 56
 
40 57
 export default {
41 58
   name: 'CalculationTools',
42 59
   components: {
43 60
     GaussPositiveTool,
44 61
     GaussNegativeTool,
62
+    GaussBandChangeTool,
63
+    UTMPositiveTool,
64
+    UTMNegativeTool,
65
+    UTMBandChangeTool,
66
+    GeodeticToSpatialTool,
67
+    SpatialToGeodeticTool,
45 68
   },
46 69
   data() {
47 70
     return {
@@ -49,6 +72,8 @@ export default {
49 72
       selectedToolPath: [],
50 73
       // 当前激活的工具组件名称
51 74
       currentToolComponent: 'GaussPositiveTool',
75
+      // 当前工具名称
76
+      currentToolName: '高斯正算工具',
52 77
       // 当前工具的key(用于强制刷新组件)
53 78
       currentToolKey: 0,
54 79
       // 级联选择器的配置
@@ -73,7 +98,37 @@ export default {
73 98
               id: 'gauss-negative',
74 99
               name: '高斯反算工具',
75 100
               component: 'GaussNegativeTool'
76
-            }
101
+            },
102
+            {
103
+              id: 'gauss-band-change',
104
+              name: '高斯换带工具',
105
+              component: 'GaussBandChangeTool'
106
+            },
107
+            {
108
+              id: 'utm-positive',
109
+              name: 'UTM投影正算工具',
110
+              component: 'UTMPositiveTool'
111
+            },
112
+            {
113
+              id: 'utm-negative',
114
+              name: 'UTM投影反算工具',
115
+              component: 'UTMNegativeTool'
116
+            },
117
+            {
118
+              id: 'utm-band-change',
119
+              name: 'UTM换带工具',
120
+              component: 'UTMBandChangeTool'
121
+            },
122
+            {
123
+              id: 'geodetic-to-spatial',
124
+              name: '大地坐标转空间坐标工具',
125
+              component: 'GeodeticToSpatialTool'
126
+            },
127
+            {
128
+              id: 'spatial-to-geodetic',
129
+              name: '空间坐标转大地坐标工具',
130
+              component: 'SpatialToGeodeticTool'
131
+            },
77 132
           ]
78 133
         },
79 134
         {
@@ -98,6 +153,7 @@ export default {
98 153
         const firstTool = firstCategory.children[0]
99 154
         this.selectedToolPath = [firstCategory.id, firstTool.id]
100 155
         this.currentToolComponent = firstTool.component
156
+        this.currentToolName = firstTool.name
101 157
         // 强制刷新组件
102 158
         this.currentToolKey++
103 159
       }
@@ -127,6 +183,7 @@ export default {
127 183
         const tool = category.children.find(child => child.id === toolId)
128 184
         if (tool && tool.component) {
129 185
           this.currentToolComponent = tool.component
186
+          this.currentToolName = tool.name
130 187
           // 强制刷新组件
131 188
           this.currentToolKey++
132 189
         }
@@ -212,11 +269,32 @@ export default {
212 269
 .tool-content {
213 270
   background-color: #ffffff;
214 271
   border-radius: 12px;
215
-  padding: 24px;
216 272
   box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
217 273
   min-height: 500px;
218 274
 }
219 275
 
276
+/* 工具标题栏 */
277
+.tool-header {
278
+  border-bottom: 1px solid #e8e8e8;
279
+  padding: 16px 24px;
280
+  background-color: #fafafa;
281
+  border-radius: 12px 12px 0 0;
282
+}
283
+.tool-title {
284
+  display: flex;
285
+  align-items: center;
286
+  gap: 10px;
287
+}
288
+
289
+.tool-title i {
290
+  font-size: 18px;
291
+  color: #11a983;
292
+}
293
+/* 工具内容区域(带内边距,不影响子组件布局) */
294
+.tool-body {
295
+  padding: 20px 24px 24px;
296
+}
297
+
220 298
 /* 过渡动画 */
221 299
 .fade-enter-active,
222 300
 .fade-leave-active {

+ 579
- 0
oa-ui/src/views/calculate/tools/gaussbandchange.vue Näytä tiedosto

@@ -0,0 +1,579 @@
1
+<!-- 高斯反算工具组件 -->
2
+<template>
3
+  <div class="gauss-band-change-tool">
4
+    <!-- 操作按钮区 -->
5
+    <div class="tool-header">
6
+      <div class="card-header-buttons">
7
+        <el-button type="primary" @click="handleImport" size="small" icon="el-icon-upload">
8
+          导入Excel
9
+        </el-button>
10
+
11
+        <el-button 
12
+          type="success" 
13
+          @click="handlePreview" 
14
+          size="small" 
15
+          :disabled="!importedData || importedData.length === 0"
16
+          icon="el-icon-view">
17
+          预览数据
18
+        </el-button>
19
+        <el-button 
20
+          type="warning" 
21
+          @click="handleCalculate" 
22
+          size="small" 
23
+          :disabled="!importedData || importedData.length === 0 || calculating"
24
+          :loading="calculating"
25
+          icon="el-icon-caret-right">
26
+          {{ calculating ? '计算中...' : '执行计算' }}
27
+        </el-button>
28
+        <el-button 
29
+          type="danger" 
30
+          @click="clearAll" 
31
+          size="small" 
32
+          :disabled="(!importedData || importedData.length === 0) && calculationResults.length === 0"
33
+          plain
34
+          icon="el-icon-delete">
35
+          清空全部
36
+        </el-button>
37
+      </div>
38
+    </div>
39
+    
40
+    <!-- 投影面高程设置 -->
41
+    <div class="height-setting">
42
+      <div class="setting-label">
43
+        <span>投影面高程</span>
44
+      </div>
45
+      <div class="setting-content">
46
+        <el-input 
47
+          v-model="projectionHeight" 
48
+          size="small" 
49
+          style="width: 120px; margin-right: 10px;">
50
+        </el-input>
51
+        <span class="unit">米 (m)</span>
52
+        
53
+      </div>
54
+    </div>
55
+
56
+    <!-- 计算结果展示区 - 只显示计算结果,不包含原始数据 -->
57
+    <div v-if="calculationResults.length > 0" class="result-section">
58
+      <div class="section-header">
59
+        <span class="section-title">
60
+          <i class="el-icon-tickets"></i>
61
+          计算结果
62
+        </span>
63
+        <span class="section-info">
64
+          共 {{ calculationResults.length }} 条计算结果
65
+        </span>
66
+        <el-button type="text" size="small" @click="handleExport" icon="el-icon-download">
67
+          导出结果
68
+        </el-button>
69
+      </div>
70
+      
71
+      <el-table :data="calculationResults" style="width: 100%" border stripe>
72
+        <el-table-column prop="pointNumber" label="待求点号" width="120" align="center"></el-table-column>
73
+        <el-table-column prop="newGaussX" label="高斯坐标x(m)" width="180" align="center">
74
+          <template slot-scope="scope">
75
+            <span class="result-value">{{ formatNumber(scope.row.newGaussX,4) }}</span>
76
+          </template>
77
+        </el-table-column>
78
+        <el-table-column prop="newGaussY" label="高斯坐标y(m)" width="180" align="center">
79
+          <template slot-scope="scope">
80
+            <span class="result-value">{{ formatNumber(scope.row.newGaussY,4) }}</span>
81
+          </template>
82
+        </el-table-column>
83
+      </el-table>
84
+    </div>
85
+    
86
+    <!-- 空状态 -->
87
+    <div v-else class="empty-state">
88
+      <i class="el-icon-document"></i>
89
+      <p>暂无计算结果</p>
90
+      <p class="empty-tip">请先导入Excel数据,然后点击"执行计算"</p>
91
+    </div>
92
+    
93
+    <!-- 导入Excel对话框 -->
94
+    <el-dialog title="导入Excel" :visible.sync="importDialogVisible" width="550px" @close="resetImport">
95
+      <div class="import-tips">
96
+        <el-alert
97
+          title="Excel模板格式说明"
98
+          type="info"
99
+          :closable="false"
100
+          show-icon>
101
+          <div class="template-info">
102
+            <p>请确保Excel文件包含以下列(第一行为表头):</p>
103
+            <ul>
104
+              <li><strong>待求点</strong> - 点号</li>
105
+              <li><strong>坐标系</strong> - WGS84/CGCS2000/Beijing54/Xian80</li>
106
+              <li><strong>高斯坐标X</strong> - (m)</li>
107
+              <li><strong>高斯坐标Y</strong> - (m)</li>
108
+              <li><strong>带号</strong> - 带号数值</li>
109
+              <li><strong>带宽</strong> - 3或6</li>
110
+              <li><strong>新带号</strong> - 新带号数值</li>
111
+              <li><strong>新带宽</strong> - 3或6</li>
112
+              <li><strong>经度位置</strong> - E/W</li>
113
+              <li><strong>纬度位置</strong> - N/S</li>
114
+            </ul>
115
+          </div>
116
+        </el-alert>
117
+         <div class="template-download-wrapper">
118
+            <el-button type="primary" plain size="small" @click="handleDownloadTemplate" icon="el-icon-download">
119
+              下载Excel模板
120
+            </el-button>
121
+          </div>
122
+      </div>
123
+      <div style="text-align: center;">
124
+        <el-upload
125
+          class="upload-area"
126
+          :action="''"
127
+          :auto-upload="false"
128
+          :on-change="handleFileChange"
129
+          :show-file-list="true"
130
+          accept=".xlsx,.xls"
131
+          drag
132
+          ref="upload">
133
+          <i class="el-icon-upload"></i>
134
+          <div class="el-upload__text">将Excel文件拖到此处,或<em>点击选择</em></div>
135
+          <div class="el-upload__tip" slot="tip">
136
+            支持.xlsx和.xls格式文件
137
+          </div>
138
+        </el-upload>
139
+      </div>
140
+      
141
+      <span slot="footer" class="dialog-footer">
142
+        <el-button @click="importDialogVisible = false">取消</el-button>
143
+        <el-button type="primary" @click="submitImport" :loading="importLoading" :disabled="!importFile">
144
+          确认导入
145
+        </el-button>
146
+      </span>
147
+    </el-dialog>
148
+    
149
+    <!-- 预览数据对话框 - 显示导入的原始数据 -->
150
+    <el-dialog title="导入数据预览" :visible.sync="previewDialogVisible" width="80%">
151
+      <div class="preview-info">
152
+        <span>共 {{ importedData.length }} 条数据</span>
153
+        <span style="margin-left: 20px;">状态:{{ importedData.filter(item => item.calculated).length }} 条已计算,{{ importedData.filter(item => !item.calculated).length }} 条未计算</span>
154
+      </div>
155
+      <el-table :data="importedData" border stripe max-height="500">
156
+        <el-table-column prop="pointNumber" label="待求点号" width="120" fixed="left" align="center"></el-table-column>
157
+        <el-table-column prop="coordinateSystem" label="坐标系" width="110" align="center">
158
+          <template slot-scope="scope">
159
+            <el-tag size="small" :type="getCoordinateType(scope.row.coordinateSystem)">
160
+              {{ scope.row.coordinateSystem }}
161
+            </el-tag>
162
+          </template>
163
+        </el-table-column>
164
+        <el-table-column prop="longitude" label="高斯X坐标(m)" width="130" align="center">
165
+          <template slot-scope="scope">
166
+            {{ formatNumber(scope.row.gaussX,4) }}
167
+          </template>
168
+        </el-table-column>
169
+         <el-table-column prop="longitudePosition" label="高斯Y坐标(m)" width="130" align="center">
170
+          <template slot-scope="scope">
171
+            {{ formatNumber(scope.row.gaussY,4) }}
172
+          </template>
173
+        </el-table-column>
174
+        <el-table-column prop="band" label="带号" width="130" align="center">
175
+          <template slot-scope="scope">
176
+            {{ scope.row.band}}
177
+                   </template>
178
+        </el-table-column>
179
+        <el-table-column prop="bandWidth" label="带宽" width="130" align="center">
180
+          <template slot-scope="scope">
181
+            {{ scope.row.bandWidth}}
182
+                   </template>
183
+        </el-table-column>
184
+        <el-table-column prop="newBand" label="新带号" width="130" align="center">
185
+          <template slot-scope="scope">
186
+            {{ scope.row.newBand}}
187
+                   </template>
188
+        </el-table-column>
189
+        <el-table-column prop="newBandWidth" label="新带宽" width="130" align="center">
190
+          <template slot-scope="scope">
191
+            {{ scope.row.newBandWidth}}
192
+                   </template>
193
+        </el-table-column>
194
+        <el-table-column prop="longitudePosition" label="经度位置" width="130" align="center">
195
+          <template slot-scope="scope">
196
+            {{ scope.row.longitudePosition}}
197
+                   </template>
198
+        </el-table-column>
199
+        <el-table-column prop="latitudePosition" label="纬度位置" width="130" align="center">
200
+          <template slot-scope="scope">
201
+            {{ scope.row.latitudePosition}}
202
+                   </template>
203
+        </el-table-column>
204
+      </el-table>
205
+      <span slot="footer" class="dialog-footer">
206
+        <el-button type="primary" @click="previewDialogVisible = false">关闭</el-button>
207
+      </span>
208
+    </el-dialog>
209
+  </div>
210
+</template>
211
+
212
+<script>
213
+import { calculate, importExcel,exportExcel,downloadTemplate } from '@/api/calculate/gaussbandchange'
214
+
215
+export default {
216
+  name: 'GaussBandChangeTool',    
217
+  data() {
218
+    return {
219
+      importedData: [],        // 导入的原始数据
220
+      calculationResults: [],  // 计算结果
221
+      importDialogVisible: false,
222
+      importLoading: false,
223
+      importFile: null,
224
+      calculating: false,
225
+      previewDialogVisible: false,
226
+      projectionHeight: 0
227
+    }
228
+  },
229
+  watch: {
230
+    // 当投影面高程改变时,重新计算(如果已有数据)
231
+    projectionHeight(newVal, oldVal) {
232
+       // 清除之前的定时器
233
+      if (this.heightTimer) {
234
+        clearTimeout(this.heightTimer)
235
+      }
236
+      
237
+      // 只有已有数据时才触发计算
238
+      if (this.importedData.length > 0 && this.calculationResults.length > 0) {
239
+        // 设置新的定时器,500ms 后执行
240
+        this.heightTimer = setTimeout(() => {
241
+          this.handleCalculate()
242
+        }, 500)
243
+      }
244
+    }
245
+  },
246
+  methods: {
247
+    // 打开导入对话框 
248
+    handleImport() {
249
+      this.importDialogVisible = true
250
+    },
251
+    
252
+    // 文件选择变化
253
+    handleFileChange(file) {
254
+      this.importFile = file.raw
255
+    },
256
+    
257
+    // 提交导入
258
+    async submitImport() {
259
+      if (!this.importFile) {
260
+        this.$message.warning('请选择文件')
261
+        return
262
+      }
263
+      
264
+      this.importLoading = true
265
+      
266
+      const formData = new FormData()
267
+      formData.append('file', this.importFile)
268
+      
269
+        const response = await importExcel(formData)
270
+        
271
+        if (response.code === 200) {
272
+          const result = response.data
273
+          // 将后端返回的数据转换为前端格式
274
+          this.importedData = (result.data || []).map(item => ({
275
+            pointNumber: item.pointNumber,
276
+            coordinateSystem: item.coordinateSystem,
277
+            gaussX: item.gaussX,
278
+            gaussY: item.gaussY,
279
+            band: item.band,
280
+            bandWidth: item.bandWidth,
281
+            newBand: item.newBand,
282
+            newBandWidth: item.newBandWidth,
283
+            longitudePosition: item.longitudePosition,
284
+            latitudePosition: item.latitudePosition
285
+          }))
286
+          
287
+          // 清空之前的计算结果
288
+          this.calculationResults = []
289
+          
290
+          this.$message.success(`${response.msg}`)
291
+          this.importDialogVisible = false
292
+          this.importLoading = false
293
+        } else {
294
+          this.$message.error(response.msg)
295
+        }
296
+    },
297
+    
298
+    // 预览数据 - 显示导入的原始数据
299
+    handlePreview() {
300
+      if (!this.importedData || this.importedData.length === 0) {
301
+        this.$message.warning('没有可预览的数据')
302
+        return
303
+      }
304
+      this.previewDialogVisible = true
305
+    },
306
+    
307
+    // 下载模板
308
+    handleDownloadTemplate() {
309
+       this.download('/calculate/gaussBandChange/template', {}, '高斯换带模板.xlsx')
310
+    },
311
+    
312
+    
313
+    // 执行计算
314
+    async handleCalculate() {
315
+      if (!this.importedData || this.importedData.length === 0) {
316
+        this.$message.warning('没有数据可计算')
317
+        return
318
+      }
319
+      
320
+      this.calculating = true
321
+      const results = []
322
+      let successCount = 0
323
+      let failCount = 0
324
+      
325
+      // 构建请求参数
326
+      const requestData = this.importedData.map(item => ({
327
+        pointNumber: item.pointNumber,
328
+        coordinateSystem: item.coordinateSystem,
329
+        gaussX: item.gaussX,
330
+        gaussY: item.gaussY,
331
+        band: item.band,
332
+        bandwidth: item.bandWidth,
333
+        newBand: item.newBand,
334
+        newBandwidth: item.newBandWidth,
335
+        longitudePosition: item.longitudePosition,
336
+        latitudePosition: item.latitudePosition,
337
+        projectionHeight: this.projectionHeight
338
+      }))
339
+      
340
+      const response = await calculate(requestData)
341
+      
342
+      if (response.code === 200) {
343
+        const results = response.data || []
344
+        
345
+        // 更新计算结果
346
+        this.calculationResults = results.map(item => ({
347
+          pointNumber: item.pointNumber,
348
+          coordinateSystem: item.coordinateSystem,
349
+          gaussX: item.gaussX,
350
+          gaussY: item.gaussY,
351
+          band: item.band,
352
+          bandwidth: item.bandwidth,
353
+          newBand: item.newBand,
354
+          newBandwidth: item.newBandwidth,
355
+          longitudePosition: item.longitudePosition,
356
+          latitudePosition: item.latitudePosition,
357
+          newGaussX: item.newGaussX,
358
+          newGaussY: item.newGaussY,
359
+          projectionHeight: this.projectionHeight
360
+        }))
361
+        
362
+        // 更新导入数据的计算状态
363
+        this.importedData.forEach(importItem => {
364
+          const found = results.find(r => r.pointNumber === importItem.pointNumber)
365
+          if (found && found.gaussX !== -1) {
366
+            importItem.calculated = true
367
+          }
368
+        })
369
+        
370
+        const successCount = results.filter(r => r.gaussX !== -1).length
371
+        const failCount = results.length - successCount
372
+        
373
+        this.$message.success(`计算完成,成功 ${successCount} 条${failCount > 0 ? `,失败 ${failCount} 条` : ''}`)
374
+        this.calculating = false
375
+        } else {
376
+          this.$message.error(response.msg)
377
+        }
378
+    },
379
+    
380
+    
381
+    // 导出结果
382
+    async handleExport() {
383
+      if (this.calculationResults.length === 0) {
384
+        this.$message.warning('没有结果可导出')
385
+        return
386
+      }
387
+
388
+      const response = await exportExcel(this.calculationResults)
389
+      
390
+      const blob = new Blob([response], { 
391
+        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
392
+      })
393
+      
394
+      const url = window.URL.createObjectURL(blob)
395
+      const link = document.createElement('a')
396
+      link.href = url
397
+      link.download = `高斯换带结果_${new Date().getTime()}.xlsx`
398
+      link.click()
399
+      window.URL.revokeObjectURL(url)
400
+  },
401
+    
402
+  // 清空全部
403
+  clearAll() {
404
+    if ((!this.importedData || this.importedData.length === 0) && this.calculationResults.length === 0) {
405
+      return
406
+    }
407
+    
408
+    this.$confirm('确定清空所有数据吗?此操作不可恢复!', '警告', {
409
+      confirmButtonText: '确定',
410
+      cancelButtonText: '取消',
411
+      type: 'warning'
412
+    }).then(() => {
413
+      this.importedData = []
414
+      this.calculationResults = []
415
+      this.$message.success('已清空所有数据')
416
+    }).catch(() => {})
417
+  },
418
+  
419
+  // 重置导入状态
420
+  resetImport() {
421
+    this.importFile = null
422
+    if (this.$refs.upload) {
423
+      this.$refs.upload.clearFiles()
424
+    }
425
+  },
426
+  
427
+  // 格式化数字显示
428
+  formatNumber(value, decimals) {
429
+    if (value === null || value === undefined) return '--'
430
+    return Number(value).toFixed(decimals)
431
+  },
432
+  
433
+  // 获取坐标系标签类型
434
+  getCoordinateType(system) {
435
+    const types = {
436
+      'WGS84': 'primary',
437
+      'CGCS2000': 'success',
438
+      'Beijing54': 'warning',
439
+      'Xian80': 'info'
440
+    }
441
+    return types[system] || 'info'
442
+  }
443
+  }
444
+}
445
+</script>
446
+
447
+<style scoped>
448
+.gauss-positive-tool {
449
+  width: 100%;
450
+}
451
+
452
+.tool-header {
453
+  margin-bottom: 20px;
454
+}
455
+
456
+.card-header-buttons {
457
+  display: flex;
458
+  gap: 10px;
459
+  flex-wrap: wrap;
460
+}
461
+
462
+/* 投影面高程设置样式 */
463
+.height-setting {
464
+  background: #f5f7fa;
465
+  border-radius: 8px;
466
+  padding: 12px 20px;
467
+  margin-bottom: 20px;
468
+  border: 1px solid #e4e7ed;
469
+  display: flex;
470
+  align-items: center;
471
+  gap: 20px;
472
+  flex-wrap: wrap;
473
+}
474
+
475
+.result-section {
476
+  margin-top: 10px;
477
+}
478
+
479
+.section-header {
480
+  padding: 12px 16px;
481
+  background: #f5f7fa;
482
+  border-radius: 8px 8px 0 0;
483
+  border: 1px solid #e4e7ed;
484
+  border-bottom: none;
485
+  display: flex;
486
+  justify-content: space-between;
487
+  align-items: center;
488
+}
489
+
490
+.section-title {
491
+  font-size: 14px;
492
+  font-weight: bold;
493
+  color: #303133;
494
+}
495
+
496
+.section-title i {
497
+  margin-right: 8px;
498
+  color: #11a983;
499
+}
500
+
501
+.section-info {
502
+  font-size: 12px;
503
+  color: #909399;
504
+}
505
+
506
+.result-value {
507
+  color: #409eff;
508
+  font-family: monospace;
509
+  font-weight: 500;
510
+}
511
+
512
+.empty-state {
513
+  text-align: center;
514
+  padding: 60px 20px;
515
+  background: #fff;
516
+  border-radius: 8px;
517
+  border: 1px solid #e4e7ed;
518
+  color: #909399;
519
+}
520
+
521
+.empty-state i {
522
+  font-size: 64px;
523
+  margin-bottom: 16px;
524
+}
525
+
526
+.empty-tip {
527
+  font-size: 12px;
528
+  margin-top: 12px;
529
+  color: #c0c4cc;
530
+}
531
+
532
+.import-tips {
533
+  margin-bottom: 20px;
534
+}
535
+
536
+.template-info {
537
+  margin-top: 12px;
538
+}
539
+
540
+.template-info ul {
541
+  margin: 8px 0;
542
+  padding-left: 20px;
543
+}
544
+
545
+.template-info li {
546
+  margin: 4px 0;
547
+  font-size: 13px;
548
+}
549
+
550
+.upload-area {
551
+  margin-top: 10px;
552
+}
553
+
554
+.preview-info {
555
+  margin-bottom: 15px;
556
+  padding: 10px;
557
+  background: #f5f7fa;
558
+  border-radius: 4px;
559
+  font-size: 14px;
560
+  color: #606266;
561
+}
562
+
563
+.dialog-footer {
564
+  width: 100%;
565
+  display: flex;
566
+  justify-content: flex-end;
567
+  gap: 10px;
568
+}
569
+
570
+.template-download-wrapper {
571
+  margin-top: 12px;
572
+  display: flex;
573
+  align-items: center;
574
+  justify-content: flex-end;
575
+  gap: 10px;
576
+  padding-top: 12px;
577
+  border-top: 1px dashed #e4e7ed;
578
+}
579
+</style>

+ 5
- 5
oa-ui/src/views/calculate/tools/gaussnegative.vue Näytä tiedosto

@@ -70,9 +70,9 @@
70 70
       
71 71
       <el-table :data="calculationResults" style="width: 100%" border stripe>
72 72
         <el-table-column prop="pointNumber" label="待求点号" width="120" align="center"></el-table-column>
73
-        <el-table-column prop="zone" label="带号" width="180" align="center">
73
+        <el-table-column prop="band" label="带号" width="180" align="center">
74 74
           <template slot-scope="scope">
75
-            <span class="result-value">{{ formatNumber(scope.row.zone,0) }}</span>
75
+            <span class="result-value">{{ formatNumber(scope.row.band,0) }}</span>
76 76
           </template>
77 77
         </el-table-column>
78 78
          <el-table-column prop="bandwidth" label="带宽" width="180" align="center">
@@ -159,8 +159,8 @@
159 159
         <span style="margin-left: 20px;">状态:{{ importedData.filter(item => item.calculated).length }} 条已计算,{{ importedData.filter(item => !item.calculated).length }} 条未计算</span>
160 160
       </div>
161 161
       <el-table :data="importedData" border stripe max-height="500">
162
-        <el-table-column prop="pointNumber" label="待求点号" width="120" fixed="left"></el-table-column>
163
-        <el-table-column prop="coordinateSystem" label="坐标系" width="110">
162
+        <el-table-column prop="pointNumber" label="待求点号" width="120" fixed="left" align="center"></el-table-column>
163
+        <el-table-column prop="coordinateSystem" label="坐标系" width="110" align="center">
164 164
           <template slot-scope="scope">
165 165
             <el-tag size="small" :type="getCoordinateType(scope.row.coordinateSystem)">
166 166
               {{ scope.row.coordinateSystem }}
@@ -329,7 +329,7 @@ export default {
329 329
           longitudePosition: item.longitudePosition,
330 330
           latitude: parseFloat(item.latitude),
331 331
           latitudePosition: item.latitudePosition,
332
-          zone: parseInt(item.zone),
332
+          band: parseInt(item.band),
333 333
           bandwidth: parseInt(item.bandwidth),
334 334
           projectionHeight: this.projectionHeight,
335 335
           gaussX: item.gaussX,

+ 6
- 6
oa-ui/src/views/calculate/tools/gausspositive.vue Näytä tiedosto

@@ -156,8 +156,8 @@
156 156
         <span style="margin-left: 20px;">状态:{{ importedData.filter(item => item.calculated).length }} 条已计算,{{ importedData.filter(item => !item.calculated).length }} 条未计算</span>
157 157
       </div>
158 158
       <el-table :data="importedData" border stripe max-height="500">
159
-        <el-table-column prop="pointNumber" label="待求点号" width="120" fixed="left"></el-table-column>
160
-        <el-table-column prop="coordinateSystem" label="坐标系" width="110">
159
+        <el-table-column prop="pointNumber" label="待求点号" width="120" fixed="left" align="center"></el-table-column>
160
+        <el-table-column prop="coordinateSystem" label="坐标系" width="110" align="center">
161 161
           <template slot-scope="scope">
162 162
             <el-tag size="small" :type="getCoordinateType(scope.row.coordinateSystem)">
163 163
               {{ scope.row.coordinateSystem }}
@@ -184,7 +184,7 @@
184 184
             {{ scope.row.latitudePosition}}
185 185
                    </template>
186 186
         </el-table-column>
187
-        <el-table-column prop="zone" label="带号" width="80" align="center"></el-table-column>
187
+        <el-table-column prop="band" label="带号" width="80" align="center"></el-table-column>
188 188
         <el-table-column prop="bandwidth" label="带宽" width="80" align="center">
189 189
           <template slot-scope="scope">
190 190
             {{ scope.row.bandwidth }}
@@ -269,7 +269,7 @@ export default {
269 269
             longitudePosition: item.longitudePosition,
270 270
             latitude: item.latitude,
271 271
             latitudePosition: item.latitudePosition,
272
-            zone: item.zone,
272
+            band: item.band,
273 273
             bandwidth: item.bandwidth
274 274
           }))
275 275
           
@@ -319,7 +319,7 @@ export default {
319 319
         longitudePosition: item.longitudePosition,
320 320
         latitude: parseFloat(item.latitude),
321 321
         latitudePosition: item.latitudePosition,
322
-        zone: parseInt(item.zone),
322
+        band: parseInt(item.band),
323 323
         bandwidth: parseInt(item.bandwidth),
324 324
         projectionHeight: this.projectionHeight
325 325
       }))
@@ -337,7 +337,7 @@ export default {
337 337
           longitudePosition: item.longitudePosition,
338 338
           latitude: parseFloat(item.latitude),
339 339
           latitudePosition: item.latitudePosition,
340
-          zone: parseInt(item.zone),
340
+          band: parseInt(item.band),
341 341
           bandwidth: parseInt(item.bandwidth),
342 342
           projectionHeight: this.projectionHeight,
343 343
           gaussX: item.gaussX,

+ 505
- 0
oa-ui/src/views/calculate/tools/geodetictospatial.vue Näytä tiedosto

@@ -0,0 +1,505 @@
1
+<!-- 大地坐标转空间直角坐标工具组件 -->
2
+<template>
3
+  <div class="geodetic-to-spatial-tool">
4
+    <!-- 操作按钮区 -->
5
+    <div class="tool-header">
6
+      <div class="card-header-buttons">
7
+        <el-button type="primary" @click="handleImport" size="small" icon="el-icon-upload">
8
+          导入 Excel
9
+        </el-button>
10
+
11
+        <el-button 
12
+          type="success" 
13
+          @click="handlePreview" 
14
+          size="small" 
15
+          :disabled="!importedData || importedData.length === 0"
16
+          icon="el-icon-view">
17
+          预览数据
18
+        </el-button>
19
+        <el-button 
20
+          type="warning" 
21
+          @click="handleCalculate" 
22
+          size="small" 
23
+          :disabled="!importedData || importedData.length === 0 || calculating"
24
+          :loading="calculating"
25
+          icon="el-icon-caret-right">
26
+          {{ calculating ? '计算中...' : '执行计算' }}
27
+        </el-button>
28
+        <el-button 
29
+          type="danger" 
30
+          @click="clearAll" 
31
+          size="small" 
32
+          :disabled="(!importedData || importedData.length === 0) && calculationResults.length === 0"
33
+          plain
34
+          icon="el-icon-delete">
35
+          清空全部
36
+        </el-button>
37
+      </div>
38
+    </div>
39
+
40
+    <!-- 计算结果展示区 -->
41
+    <div v-if="calculationResults.length > 0" class="result-section">
42
+      <div class="section-header">
43
+        <span class="section-title">
44
+          <i class="el-icon-tickets"></i>
45
+          计算结果
46
+        </span>
47
+        <span class="section-info">
48
+          共 {{ calculationResults.length }} 条计算结果
49
+        </span>
50
+        <el-button type="text" size="small" @click="handleExport" icon="el-icon-download">
51
+          导出结果
52
+        </el-button>
53
+      </div>
54
+      
55
+      <el-table :data="calculationResults" style="width: 100%" border stripe>
56
+        <el-table-column prop="pointNumber" label="待求点号" width="120" align="center"></el-table-column>
57
+        <el-table-column prop="spatialX" label="空间直角坐标 X(m)" width="200" align="center">
58
+          <template slot-scope="scope">
59
+            <span class="result-value">{{ formatNumber(scope.row.spatialX, 4) }}</span>
60
+          </template>
61
+        </el-table-column>
62
+        <el-table-column prop="spatialY" label="空间直角坐标 Y(m)" width="200" align="center">
63
+          <template slot-scope="scope">
64
+            <span class="result-value">{{ formatNumber(scope.row.spatialY, 4) }}</span>
65
+          </template>
66
+        </el-table-column>
67
+        <el-table-column prop="spatialZ" label="空间直角坐标 Z(m)" width="200" align="center">
68
+          <template slot-scope="scope">
69
+            <span class="result-value">{{ formatNumber(scope.row.spatialZ, 4) }}</span>
70
+          </template>
71
+        </el-table-column>
72
+      </el-table>
73
+    </div>
74
+    
75
+    <!-- 空状态 -->
76
+    <div v-else class="empty-state">
77
+      <i class="el-icon-document"></i>
78
+      <p>暂无计算结果</p>
79
+      <p class="empty-tip">请先导入 Excel 数据,然后点击"执行计算"</p>
80
+    </div>
81
+    
82
+    <!-- 导入 Excel 对话框 -->
83
+    <el-dialog title="导入 Excel" :visible.sync="importDialogVisible" width="550px" @close="resetImport">
84
+      <div class="import-tips">
85
+        <el-alert
86
+          title="Excel 模板格式说明"
87
+          type="info"
88
+          :closable="false"
89
+          show-icon>
90
+          <div class="template-info">
91
+            <p>请确保 Excel 文件包含以下列(第一行为表头):</p>
92
+            <ul>
93
+              <li><strong>待求点</strong> - 点号</li>
94
+              <li><strong>坐标系</strong> - WGS84/CGCS2000/Beijing54/Xian80</li>
95
+              <li><strong>大地经度</strong> - 经度数值 (°)</li>
96
+              <li><strong>经度位置</strong> - E/W</li>
97
+              <li><strong>大地纬度</strong> - 纬度数值 (°)</li>
98
+              <li><strong>纬度位置</strong> - N/S</li>
99
+              <li><strong>大地高</strong> - 高程数值 (m)</li>
100
+            </ul>
101
+          </div>
102
+        </el-alert>
103
+         <div class="template-download-wrapper">
104
+            <el-button type="primary" plain size="small" @click="handleDownloadTemplate" icon="el-icon-download">
105
+              下载 Excel 模板
106
+            </el-button>
107
+          </div>
108
+      </div>
109
+      <div style="text-align: center;">
110
+        <el-upload
111
+          class="upload-area"
112
+          :action="''"
113
+          :auto-upload="false"
114
+          :on-change="handleFileChange"
115
+          :show-file-list="true"
116
+          accept=".xlsx,.xls"
117
+          drag
118
+          ref="upload">
119
+          <i class="el-icon-upload"></i>
120
+          <div class="el-upload__text">将 Excel 文件拖到此处,或<em>点击选择</em></div>
121
+          <div class="el-upload__tip" slot="tip">
122
+            支持.xlsx 和.xls 格式文件
123
+          </div>
124
+        </el-upload>
125
+      </div>
126
+      
127
+      <span slot="footer" class="dialog-footer">
128
+        <el-button @click="importDialogVisible = false">取消</el-button>
129
+        <el-button type="primary" @click="submitImport" :loading="importLoading" :disabled="!importFile">
130
+          确认导入
131
+        </el-button>
132
+      </span>
133
+    </el-dialog>
134
+    
135
+    <!-- 预览数据对话框 -->
136
+    <el-dialog title="导入数据预览" :visible.sync="previewDialogVisible" width="80%">
137
+      <div class="preview-info">
138
+        <span>共 {{ importedData.length }} 条数据</span>
139
+        <span style="margin-left: 20px;">状态:{{ importedData.filter(item => item.calculated).length }} 条已计算,{{ importedData.filter(item => !item.calculated).length }} 条未计算</span>
140
+      </div>
141
+      <el-table :data="importedData" border stripe max-height="500">
142
+        <el-table-column prop="pointNumber" label="待求点号" width="120" fixed="left" align="center"></el-table-column>
143
+        <el-table-column prop="coordinateSystem" label="坐标系" width="110" align="center">
144
+          <template slot-scope="scope">
145
+            <el-tag size="small" :type="getCoordinateType(scope.row.coordinateSystem)">
146
+              {{ scope.row.coordinateSystem }}
147
+            </el-tag>
148
+          </template>
149
+        </el-table-column>
150
+        <el-table-column prop="longitude" label="大地经度" width="130" align="center">
151
+          <template slot-scope="scope">
152
+            {{ scope.row.longitude }}
153
+          </template>
154
+        </el-table-column>
155
+         <el-table-column prop="longitudePosition" label="经度位置" width="100" align="center">
156
+          <template slot-scope="scope">
157
+            {{ scope.row.longitudePosition}}
158
+          </template>
159
+        </el-table-column>
160
+        <el-table-column prop="latitude" label="大地纬度" width="130" align="center">
161
+          <template slot-scope="scope">
162
+            {{ scope.row.latitude }}
163
+          </template>
164
+        </el-table-column>
165
+         <el-table-column prop="latitudePosition" label="纬度位置" width="100" align="center">
166
+          <template slot-scope="scope">
167
+            {{ scope.row.latitudePosition}}
168
+          </template>
169
+        </el-table-column>
170
+        <el-table-column prop="height" label="大地高 (m)" width="100" align="center">
171
+          <template slot-scope="scope">
172
+            {{ formatNumber(scope.row.height, 4) }}
173
+          </template>
174
+        </el-table-column>
175
+      </el-table>
176
+      <span slot="footer" class="dialog-footer">
177
+        <el-button type="primary" @click="previewDialogVisible = false">关闭</el-button>
178
+      </span>
179
+    </el-dialog>
180
+  </div>
181
+</template>
182
+
183
+<script>
184
+import { calculate, importExcel, exportExcel, downloadTemplate } from '@/api/calculate/geodetictospatial'
185
+
186
+export default {
187
+  name: 'GeodeticToSpatialTool',
188
+  data() {
189
+    return {
190
+      importedData: [],        // 导入的原始数据
191
+      calculationResults: [],  // 计算结果
192
+      importDialogVisible: false,
193
+      importLoading: false,
194
+      importFile: null,
195
+      calculating: false,
196
+      previewDialogVisible: false,
197
+    }
198
+  },
199
+  methods: {
200
+    // 打开导入对话框 
201
+    handleImport() {
202
+      this.importDialogVisible = true
203
+    },
204
+    
205
+    // 文件选择变化
206
+    handleFileChange(file) {
207
+      this.importFile = file.raw
208
+    },
209
+    
210
+    // 提交导入
211
+    async submitImport() {
212
+      if (!this.importFile) {
213
+        this.$message.warning('请选择文件')
214
+        return
215
+      }
216
+      
217
+      this.importLoading = true
218
+      
219
+      const formData = new FormData()
220
+      formData.append('file', this.importFile)
221
+      
222
+      const response = await importExcel(formData)
223
+      
224
+      if (response.code === 200) {
225
+        const result = response.data
226
+        
227
+        // 将后端返回的数据转换为前端格式
228
+        this.importedData = (result.data || []).map(item => ({
229
+          pointNumber: item.pointNumber,
230
+          coordinateSystem: item.coordinateSystem,
231
+          longitude: item.longitude,
232
+          longitudePosition: item.longitudePosition,
233
+          latitude: item.latitude,
234
+          latitudePosition: item.latitudePosition,
235
+          height: item.height
236
+        }))
237
+        
238
+        // 清空之前的计算结果
239
+        this.calculationResults = []
240
+        
241
+        this.$message.success(`${response.msg}`)
242
+        this.importDialogVisible = false
243
+        this.importLoading = false
244
+      } else {
245
+        this.$message.error(response.msg)
246
+      }
247
+    },
248
+    
249
+    // 预览数据 - 显示导入的原始数据
250
+    handlePreview() {
251
+      if (!this.importedData || this.importedData.length === 0) {
252
+        this.$message.warning('没有可预览的数据')
253
+        return
254
+      }
255
+      this.previewDialogVisible = true
256
+    },
257
+    
258
+    // 下载模板
259
+    handleDownloadTemplate() {
260
+      this.download('/calculate/geodeticToSpatial/template', {}, '大地转空间模板.xlsx')
261
+    },
262
+    
263
+    // 执行计算
264
+    async handleCalculate() {
265
+      if (!this.importedData || this.importedData.length === 0) {
266
+        this.$message.warning('没有数据可计算')
267
+        return
268
+      }
269
+      
270
+      this.calculating = true
271
+      
272
+      // 构建请求参数
273
+      const requestData = this.importedData.map(item => ({
274
+        pointNumber: item.pointNumber,
275
+        coordinateSystem: item.coordinateSystem,
276
+        longitude: parseFloat(item.longitude),
277
+        longitudePosition: item.longitudePosition,
278
+        latitude: parseFloat(item.latitude),
279
+        latitudePosition: item.latitudePosition,
280
+        height: parseFloat(item.height) || 0
281
+      }))
282
+      
283
+      const response = await calculate(requestData)
284
+      
285
+      if (response.code === 200) {
286
+        const results = response.data || []
287
+        
288
+        // 更新计算结果
289
+        this.calculationResults = results.map(item => ({
290
+          pointNumber: item.pointNumber,
291
+          coordinateSystem: item.coordinateSystem,
292
+          longitude: item.longitude,
293
+          longitudePosition: item.longitudePosition,
294
+          latitude: item.latitude,
295
+          latitudePosition: item.latitudePosition,
296
+          height: item.height,
297
+          spatialX: item.spatialX,
298
+          spatialY: item.spatialY,
299
+          spatialZ: item.spatialZ
300
+        }))
301
+        
302
+        // 更新导入数据的计算状态
303
+        this.importedData.forEach(importItem => {
304
+          const found = results.find(r => r.pointNumber === importItem.pointNumber)
305
+          if (found && found.spatialX !== -1) {
306
+            importItem.calculated = true
307
+          }
308
+        })
309
+        
310
+        const successCount = results.filter(r => r.spatialX !== -1).length
311
+        const failCount = results.length - successCount
312
+        
313
+        this.$message.success(`计算完成,成功 ${successCount} 条${failCount > 0 ? `,失败 ${failCount} 条` : ''}`)
314
+        this.calculating = false
315
+      } else {
316
+        this.$message.error(response.msg)
317
+      }
318
+    },
319
+    
320
+    // 导出结果
321
+    async handleExport() {
322
+      if (this.calculationResults.length === 0) {
323
+        this.$message.warning('没有结果可导出')
324
+        return
325
+      }
326
+      
327
+      const response = await exportExcel(this.calculationResults)
328
+      
329
+      const blob = new Blob([response], { 
330
+        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
331
+      })
332
+      
333
+      const url = window.URL.createObjectURL(blob)
334
+      const link = document.createElement('a')
335
+      link.href = url
336
+      link.download = `大地转空间结果_${new Date().getTime()}.xlsx`
337
+      link.click()
338
+      window.URL.revokeObjectURL(url)
339
+    },
340
+    
341
+    // 清空全部
342
+    clearAll() {
343
+      if ((!this.importedData || this.importedData.length === 0) && this.calculationResults.length === 0) {
344
+        return
345
+      }
346
+      
347
+      this.$confirm('确定清空所有数据吗?此操作不可恢复!', '警告', {
348
+        confirmButtonText: '确定',
349
+        cancelButtonText: '取消',
350
+        type: 'warning'
351
+      }).then(() => {
352
+        this.importedData = []
353
+        this.calculationResults = []
354
+        this.$message.success('已清空所有数据')
355
+      }).catch(() => {})
356
+    },
357
+    
358
+    // 重置导入状态
359
+    resetImport() {
360
+      this.importFile = null
361
+      if (this.$refs.upload) {
362
+        this.$refs.upload.clearFiles()
363
+      }
364
+    },
365
+    
366
+    // 格式化数字显示
367
+    formatNumber(value, decimals = 3) {
368
+      if (value === null || value === undefined) return '--'
369
+      return Number(value).toFixed(decimals)
370
+    },
371
+    
372
+    // 获取坐标系标签类型
373
+    getCoordinateType(system) {
374
+      const types = {
375
+        'WGS84': 'primary',
376
+        'CGCS2000': 'success',
377
+        'Beijing54': 'warning',
378
+        'Xian80': 'info'
379
+      }
380
+      return types[system] || 'info'
381
+    }
382
+  }
383
+}
384
+</script>
385
+
386
+<style scoped>
387
+.geodetic-to-spatial-tool {
388
+  width: 100%;
389
+}
390
+
391
+.tool-header {
392
+  margin-bottom: 20px;
393
+}
394
+
395
+.card-header-buttons {
396
+  display: flex;
397
+  gap: 10px;
398
+  flex-wrap: wrap;
399
+}
400
+
401
+.result-section {
402
+  margin-top: 10px;
403
+}
404
+
405
+.section-header {
406
+  padding: 12px 16px;
407
+  background: #f5f7fa;
408
+  border-radius: 8px 8px 0 0;
409
+  border: 1px solid #e4e7ed;
410
+  border-bottom: none;
411
+  display: flex;
412
+  justify-content: space-between;
413
+  align-items: center;
414
+}
415
+
416
+.section-title {
417
+  font-size: 14px;
418
+  font-weight: bold;
419
+  color: #303133;
420
+}
421
+
422
+.section-title i {
423
+  margin-right: 8px;
424
+  color: #11a983;
425
+}
426
+
427
+.section-info {
428
+  font-size: 12px;
429
+  color: #909399;
430
+}
431
+
432
+.result-value {
433
+  color: #409eff;
434
+  font-family: monospace;
435
+  font-weight: 500;
436
+}
437
+
438
+.empty-state {
439
+  text-align: center;
440
+  padding: 60px 20px;
441
+  background: #fff;
442
+  border-radius: 8px;
443
+  border: 1px solid #e4e7ed;
444
+  color: #909399;
445
+}
446
+
447
+.empty-state i {
448
+  font-size: 64px;
449
+  margin-bottom: 16px;
450
+}
451
+
452
+.empty-tip {
453
+  font-size: 12px;
454
+  margin-top: 12px;
455
+  color: #c0c4cc;
456
+}
457
+
458
+.import-tips {
459
+  margin-bottom: 20px;
460
+}
461
+
462
+.template-info {
463
+  margin-top: 12px;
464
+}
465
+
466
+.template-info ul {
467
+  margin: 8px 0;
468
+  padding-left: 20px;
469
+}
470
+
471
+.template-info li {
472
+  margin: 4px 0;
473
+  font-size: 13px;
474
+}
475
+
476
+.upload-area {
477
+  margin-top: 10px;
478
+}
479
+
480
+.preview-info {
481
+  margin-bottom: 15px;
482
+  padding: 10px;
483
+  background: #f5f7fa;
484
+  border-radius: 4px;
485
+  font-size: 14px;
486
+  color: #606266;
487
+}
488
+
489
+.dialog-footer {
490
+  width: 100%;
491
+  display: flex;
492
+  justify-content: flex-end;
493
+  gap: 10px;
494
+}
495
+
496
+.template-download-wrapper {
497
+  margin-top: 12px;
498
+  display: flex;
499
+  align-items: center;
500
+  justify-content: flex-end;
501
+  gap: 10px;
502
+  padding-top: 12px;
503
+  border-top: 1px dashed #e4e7ed;
504
+}
505
+</style>

+ 499
- 0
oa-ui/src/views/calculate/tools/spatialtogeodetic.vue Näytä tiedosto

@@ -0,0 +1,499 @@
1
+<!-- 空间直角坐标转大地坐标工具组件 -->
2
+<template>
3
+  <div class="spatial-to-geodetic-tool">
4
+    <!-- 操作按钮区 -->
5
+    <div class="tool-header">
6
+      <div class="card-header-buttons">
7
+        <el-button type="primary" @click="handleImport" size="small" icon="el-icon-upload">
8
+          导入 Excel
9
+        </el-button>
10
+
11
+        <el-button 
12
+          type="success" 
13
+          @click="handlePreview" 
14
+          size="small" 
15
+          :disabled="!importedData || importedData.length === 0"
16
+          icon="el-icon-view">
17
+          预览数据
18
+        </el-button>
19
+        <el-button 
20
+          type="warning" 
21
+          @click="handleCalculate" 
22
+          size="small" 
23
+          :disabled="!importedData || importedData.length === 0 || calculating"
24
+          :loading="calculating"
25
+          icon="el-icon-caret-right">
26
+          {{ calculating ? '计算中...' : '执行计算' }}
27
+        </el-button>
28
+        <el-button 
29
+          type="danger" 
30
+          @click="clearAll" 
31
+          size="small" 
32
+          :disabled="(!importedData || importedData.length === 0) && calculationResults.length === 0"
33
+          plain
34
+          icon="el-icon-delete">
35
+          清空全部
36
+        </el-button>
37
+      </div>
38
+    </div>
39
+
40
+    <!-- 计算结果展示区 -->
41
+    <div v-if="calculationResults.length > 0" class="result-section">
42
+      <div class="section-header">
43
+        <span class="section-title">
44
+          <i class="el-icon-tickets"></i>
45
+          计算结果
46
+        </span>
47
+        <span class="section-info">
48
+          共 {{ calculationResults.length }} 条计算结果
49
+        </span>
50
+        <el-button type="text" size="small" @click="handleExport" icon="el-icon-download">
51
+          导出结果
52
+        </el-button>
53
+      </div>
54
+      
55
+      <el-table :data="calculationResults" style="width: 100%" border stripe>
56
+        <el-table-column prop="pointNumber" label="待求点号" width="120" align="center"></el-table-column>
57
+        <el-table-column prop="longitude" label="大地经度(°)" width="180" align="center">
58
+          <template slot-scope="scope">
59
+            <span class="result-value">{{ formatNumber(scope.row.longitude, 9) }}</span>
60
+          </template>
61
+        </el-table-column>
62
+        <el-table-column prop="longitudePosition" label="经度位置" width="100" align="center">
63
+          <template slot-scope="scope">
64
+            <el-tag size="small" type="primary">{{ scope.row.longitudePosition }}</el-tag>
65
+          </template>
66
+        </el-table-column>
67
+        <el-table-column prop="latitude" label="大地纬度(°)" width="180" align="center">
68
+          <template slot-scope="scope">
69
+            <span class="result-value">{{ formatNumber(scope.row.latitude, 9) }}</span>
70
+          </template>
71
+        </el-table-column>
72
+        <el-table-column prop="latitudePosition" label="纬度位置" width="100" align="center">
73
+          <template slot-scope="scope">
74
+            <el-tag size="small" type="success">{{ scope.row.latitudePosition }}</el-tag>
75
+          </template>
76
+        </el-table-column>
77
+        <el-table-column prop="height" label="大地高(m)" width="120" align="center">
78
+          <template slot-scope="scope">
79
+            <span class="result-value">{{ formatNumber(scope.row.height, 4) }}</span>
80
+          </template>
81
+        </el-table-column>
82
+      </el-table>
83
+    </div>
84
+    
85
+    <!-- 空状态 -->
86
+    <div v-else class="empty-state">
87
+      <i class="el-icon-document"></i>
88
+      <p>暂无计算结果</p>
89
+      <p class="empty-tip">请先导入 Excel 数据,然后点击"执行计算"</p>
90
+    </div>
91
+    
92
+    <!-- 导入 Excel 对话框 -->
93
+    <el-dialog title="导入 Excel" :visible.sync="importDialogVisible" width="550px" @close="resetImport">
94
+      <div class="import-tips">
95
+        <el-alert
96
+          title="Excel 模板格式说明"
97
+          type="info"
98
+          :closable="false"
99
+          show-icon>
100
+          <div class="template-info">
101
+            <p>请确保 Excel 文件包含以下列(第一行为表头):</p>
102
+            <ul>
103
+              <li><strong>待求点</strong> - 点号</li>
104
+              <li><strong>坐标系</strong> - WGS84/CGCS2000/Beijing54/Xian80</li>
105
+              <li><strong>空间直角坐标X</strong> - X坐标值 (m)</li>
106
+              <li><strong>空间直角坐标Y</strong> - Y坐标值 (m)</li>
107
+              <li><strong>空间直角坐标Z</strong> - Z坐标值 (m)</li>
108
+            </ul>
109
+          </div>
110
+        </el-alert>
111
+         <div class="template-download-wrapper">
112
+            <el-button type="primary" plain size="small" @click="handleDownloadTemplate" icon="el-icon-download">
113
+              下载 Excel 模板
114
+            </el-button>
115
+          </div>
116
+      </div>
117
+      <div style="text-align: center;">
118
+        <el-upload
119
+          class="upload-area"
120
+          :action="''"
121
+          :auto-upload="false"
122
+          :on-change="handleFileChange"
123
+          :show-file-list="true"
124
+          accept=".xlsx,.xls"
125
+          drag
126
+          ref="upload">
127
+          <i class="el-icon-upload"></i>
128
+          <div class="el-upload__text">将 Excel 文件拖到此处,或<em>点击选择</em></div>
129
+          <div class="el-upload__tip" slot="tip">
130
+            支持.xlsx 和.xls 格式文件
131
+          </div>
132
+        </el-upload>
133
+      </div>
134
+      
135
+      <span slot="footer" class="dialog-footer">
136
+        <el-button @click="importDialogVisible = false">取消</el-button>
137
+        <el-button type="primary" @click="submitImport" :loading="importLoading" :disabled="!importFile">
138
+          确认导入
139
+        </el-button>
140
+      </span>
141
+    </el-dialog>
142
+    
143
+    <!-- 预览数据对话框 -->
144
+    <el-dialog title="导入数据预览" :visible.sync="previewDialogVisible" width="80%">
145
+      <div class="preview-info">
146
+        <span>共 {{ importedData.length }} 条数据</span>
147
+        <span style="margin-left: 20px;">状态:{{ importedData.filter(item => item.calculated).length }} 条已计算,{{ importedData.filter(item => !item.calculated).length }} 条未计算</span>
148
+      </div>
149
+      <el-table :data="importedData" border stripe max-height="500">
150
+        <el-table-column prop="pointNumber" label="待求点号" width="120" fixed="left" align="center"></el-table-column>
151
+        <el-table-column prop="coordinateSystem" label="坐标系" width="110" align="center">
152
+          <template slot-scope="scope">
153
+            <el-tag size="small" :type="getCoordinateType(scope.row.coordinateSystem)">
154
+              {{ scope.row.coordinateSystem }}
155
+            </el-tag>
156
+          </template>
157
+        </el-table-column>
158
+        <el-table-column prop="spatialX" label="空间X坐标" width="150" align="center">
159
+          <template slot-scope="scope">
160
+            {{ formatNumber(scope.row.spatialX, 4) }}
161
+          </template>
162
+        </el-table-column>
163
+        <el-table-column prop="spatialY" label="空间Y坐标" width="150" align="center">
164
+          <template slot-scope="scope">
165
+            {{ formatNumber(scope.row.spatialY, 4) }}
166
+          </template>
167
+        </el-table-column>
168
+        <el-table-column prop="spatialZ" label="空间Z坐标" width="150" align="center">
169
+          <template slot-scope="scope">
170
+            {{ formatNumber(scope.row.spatialZ, 4) }}
171
+          </template>
172
+        </el-table-column>
173
+      </el-table>
174
+      <span slot="footer" class="dialog-footer">
175
+        <el-button type="primary" @click="previewDialogVisible = false">关闭</el-button>
176
+      </span>
177
+    </el-dialog>
178
+  </div>
179
+</template>
180
+
181
+<script>
182
+import { calculate, importExcel, exportExcel, downloadTemplate } from '@/api/calculate/spatialtogeodetic'
183
+
184
+export default {
185
+  name: 'SpatialToGeodeticTool',
186
+  data() {
187
+    return {
188
+      importedData: [],        // 导入的原始数据
189
+      calculationResults: [],  // 计算结果
190
+      importDialogVisible: false,
191
+      importLoading: false,
192
+      importFile: null,
193
+      calculating: false,
194
+      previewDialogVisible: false,
195
+    }
196
+  },
197
+  methods: {
198
+    // 打开导入对话框 
199
+    handleImport() {
200
+      this.importDialogVisible = true
201
+    },
202
+    
203
+    // 文件选择变化
204
+    handleFileChange(file) {
205
+      this.importFile = file.raw
206
+    },
207
+    
208
+    // 提交导入
209
+    async submitImport() {
210
+      if (!this.importFile) {
211
+        this.$message.warning('请选择文件')
212
+        return
213
+      }
214
+      
215
+      this.importLoading = true
216
+      
217
+      const formData = new FormData()
218
+      formData.append('file', this.importFile)
219
+      
220
+      const response = await importExcel(formData)
221
+      
222
+      if (response.code === 200) {
223
+        const result = response.data
224
+        
225
+        // 将后端返回的数据转换为前端格式
226
+        this.importedData = (result.data || []).map(item => ({
227
+          pointNumber: item.pointNumber,
228
+          coordinateSystem: item.coordinateSystem,
229
+          spatialX: item.spatialX,
230
+          spatialY: item.spatialY,
231
+          spatialZ: item.spatialZ
232
+        }))
233
+        
234
+        // 清空之前的计算结果
235
+        this.calculationResults = []
236
+        
237
+        this.$message.success(`${response.msg}`)
238
+        this.importDialogVisible = false
239
+        this.importLoading = false
240
+      } else {
241
+        this.$message.error(response.msg)
242
+      }
243
+    },
244
+    
245
+    // 预览数据 - 显示导入的原始数据
246
+    handlePreview() {
247
+      if (!this.importedData || this.importedData.length === 0) {
248
+        this.$message.warning('没有可预览的数据')
249
+        return
250
+      }
251
+      this.previewDialogVisible = true
252
+    },
253
+    
254
+    // 下载模板
255
+    handleDownloadTemplate() {
256
+      this.download('/calculate/spatialToGeodetic/template', {}, '空间转大地模板.xlsx')
257
+    },
258
+    
259
+    // 执行计算
260
+    async handleCalculate() {
261
+      if (!this.importedData || this.importedData.length === 0) {
262
+        this.$message.warning('没有数据可计算')
263
+        return
264
+      }
265
+      
266
+      this.calculating = true
267
+      
268
+      // 构建请求参数
269
+      const requestData = this.importedData.map(item => ({
270
+        pointNumber: item.pointNumber,
271
+        coordinateSystem: item.coordinateSystem,
272
+        spatialX: parseFloat(item.spatialX),
273
+        spatialY: parseFloat(item.spatialY),
274
+        spatialZ: parseFloat(item.spatialZ)
275
+      }))
276
+      
277
+      const response = await calculate(requestData)
278
+      
279
+      if (response.code === 200) {
280
+        const results = response.data || []
281
+        
282
+        // 更新计算结果
283
+        this.calculationResults = results.map(item => ({
284
+          pointNumber: item.pointNumber,
285
+          coordinateSystem: item.coordinateSystem,
286
+          spatialX: item.spatialX,
287
+          spatialY: item.spatialY,
288
+          spatialZ: item.spatialZ,
289
+          longitude: item.longitude,
290
+          longitudePosition: item.longitudePosition,
291
+          latitude: item.latitude,
292
+          latitudePosition: item.latitudePosition,
293
+          height: item.height
294
+        }))
295
+        
296
+        // 更新导入数据的计算状态
297
+        this.importedData.forEach(importItem => {
298
+          const found = results.find(r => r.pointNumber === importItem.pointNumber)
299
+          if (found && found.longitude !== -1) {
300
+            importItem.calculated = true
301
+          }
302
+        })
303
+        
304
+        const successCount = results.filter(r => r.longitude !== -1).length
305
+        const failCount = results.length - successCount
306
+        
307
+        this.$message.success(`计算完成,成功 ${successCount} 条${failCount > 0 ? `,失败 ${failCount} 条` : ''}`)
308
+        this.calculating = false
309
+      } else {
310
+        this.$message.error(response.msg)
311
+      }
312
+    },
313
+    
314
+    // 导出结果
315
+    async handleExport() {
316
+      if (this.calculationResults.length === 0) {
317
+        this.$message.warning('没有结果可导出')
318
+        return
319
+      }
320
+      
321
+      const response = await exportExcel(this.calculationResults)
322
+      
323
+      const blob = new Blob([response], { 
324
+        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
325
+      })
326
+      
327
+      const url = window.URL.createObjectURL(blob)
328
+      const link = document.createElement('a')
329
+      link.href = url
330
+      link.download = `空间转大地结果_${new Date().getTime()}.xlsx`
331
+      link.click()
332
+      window.URL.revokeObjectURL(url)
333
+    },
334
+    
335
+    // 清空全部
336
+    clearAll() {
337
+      if ((!this.importedData || this.importedData.length === 0) && this.calculationResults.length === 0) {
338
+        return
339
+      }
340
+      
341
+      this.$confirm('确定清空所有数据吗?此操作不可恢复!', '警告', {
342
+        confirmButtonText: '确定',
343
+        cancelButtonText: '取消',
344
+        type: 'warning'
345
+      }).then(() => {
346
+        this.importedData = []
347
+        this.calculationResults = []
348
+        this.$message.success('已清空所有数据')
349
+      }).catch(() => {})
350
+    },
351
+    
352
+    // 重置导入状态
353
+    resetImport() {
354
+      this.importFile = null
355
+      if (this.$refs.upload) {
356
+        this.$refs.upload.clearFiles()
357
+      }
358
+    },
359
+    
360
+    // 格式化数字显示
361
+    formatNumber(value, decimals = 3) {
362
+      if (value === null || value === undefined) return '--'
363
+      return Number(value).toFixed(decimals)
364
+    },
365
+    
366
+    // 获取坐标系标签类型
367
+    getCoordinateType(system) {
368
+      const types = {
369
+        'WGS84': 'primary',
370
+        'CGCS2000': 'success',
371
+        'Beijing54': 'warning',
372
+        'Xian80': 'info'
373
+      }
374
+      return types[system] || 'info'
375
+    }
376
+  }
377
+}
378
+</script>
379
+
380
+<style scoped>
381
+.spatial-to-geodetic-tool {
382
+  width: 100%;
383
+}
384
+
385
+.tool-header {
386
+  margin-bottom: 20px;
387
+}
388
+
389
+.card-header-buttons {
390
+  display: flex;
391
+  gap: 10px;
392
+  flex-wrap: wrap;
393
+}
394
+
395
+.result-section {
396
+  margin-top: 10px;
397
+}
398
+
399
+.section-header {
400
+  padding: 12px 16px;
401
+  background: #f5f7fa;
402
+  border-radius: 8px 8px 0 0;
403
+  border: 1px solid #e4e7ed;
404
+  border-bottom: none;
405
+  display: flex;
406
+  justify-content: space-between;
407
+  align-items: center;
408
+}
409
+
410
+.section-title {
411
+  font-size: 14px;
412
+  font-weight: bold;
413
+  color: #303133;
414
+}
415
+
416
+.section-title i {
417
+  margin-right: 8px;
418
+  color: #11a983;
419
+}
420
+
421
+.section-info {
422
+  font-size: 12px;
423
+  color: #909399;
424
+}
425
+
426
+.result-value {
427
+  color: #409eff;
428
+  font-family: monospace;
429
+  font-weight: 500;
430
+}
431
+
432
+.empty-state {
433
+  text-align: center;
434
+  padding: 60px 20px;
435
+  background: #fff;
436
+  border-radius: 8px;
437
+  border: 1px solid #e4e7ed;
438
+  color: #909399;
439
+}
440
+
441
+.empty-state i {
442
+  font-size: 64px;
443
+  margin-bottom: 16px;
444
+}
445
+
446
+.empty-tip {
447
+  font-size: 12px;
448
+  margin-top: 12px;
449
+  color: #c0c4cc;
450
+}
451
+
452
+.import-tips {
453
+  margin-bottom: 20px;
454
+}
455
+
456
+.template-info {
457
+  margin-top: 12px;
458
+}
459
+
460
+.template-info ul {
461
+  margin: 8px 0;
462
+  padding-left: 20px;
463
+}
464
+
465
+.template-info li {
466
+  margin: 4px 0;
467
+  font-size: 13px;
468
+}
469
+
470
+.upload-area {
471
+  margin-top: 10px;
472
+}
473
+
474
+.preview-info {
475
+  margin-bottom: 15px;
476
+  padding: 10px;
477
+  background: #f5f7fa;
478
+  border-radius: 4px;
479
+  font-size: 14px;
480
+  color: #606266;
481
+}
482
+
483
+.dialog-footer {
484
+  width: 100%;
485
+  display: flex;
486
+  justify-content: flex-end;
487
+  gap: 10px;
488
+}
489
+
490
+.template-download-wrapper {
491
+  margin-top: 12px;
492
+  display: flex;
493
+  align-items: center;
494
+  justify-content: flex-end;
495
+  gap: 10px;
496
+  padding-top: 12px;
497
+  border-top: 1px dashed #e4e7ed;
498
+}
499
+</style>

+ 561
- 0
oa-ui/src/views/calculate/tools/utmbandchange.vue Näytä tiedosto

@@ -0,0 +1,561 @@
1
+<!-- UTM换带工具组件 -->
2
+<template>
3
+  <div class="utm-band-change-tool">
4
+    <!-- 操作按钮区 -->
5
+    <div class="tool-header">
6
+      <div class="card-header-buttons">
7
+        <el-button type="primary" @click="handleImport" size="small" icon="el-icon-upload">
8
+          导入Excel
9
+        </el-button>
10
+
11
+        <el-button 
12
+          type="success" 
13
+          @click="handlePreview" 
14
+          size="small" 
15
+          :disabled="!importedData || importedData.length === 0"
16
+          icon="el-icon-view">
17
+          预览数据
18
+        </el-button>
19
+        <el-button 
20
+          type="warning" 
21
+          @click="handleCalculate" 
22
+          size="small" 
23
+          :disabled="!importedData || importedData.length === 0 || calculating"
24
+          :loading="calculating"
25
+          icon="el-icon-caret-right">
26
+          {{ calculating ? '计算中...' : '执行计算' }}
27
+        </el-button>
28
+        <el-button 
29
+          type="danger" 
30
+          @click="clearAll" 
31
+          size="small" 
32
+          :disabled="(!importedData || importedData.length === 0) && calculationResults.length === 0"
33
+          plain
34
+          icon="el-icon-delete">
35
+          清空全部
36
+        </el-button>
37
+      </div>
38
+    </div>
39
+    
40
+    <!-- 投影面高程设置 -->
41
+    <div class="height-setting">
42
+      <div class="setting-label">
43
+        <span>投影面高程</span>
44
+      </div>
45
+      <div class="setting-content">
46
+        <el-input 
47
+          v-model="projectionHeight" 
48
+          size="small" 
49
+          style="width: 120px; margin-right: 10px;">
50
+        </el-input>
51
+        <span class="unit">米 (m)</span>
52
+        
53
+      </div>
54
+    </div>
55
+
56
+    <!-- 计算结果展示区 - 只显示计算结果,不包含原始数据 -->
57
+    <div v-if="calculationResults.length > 0" class="result-section">
58
+      <div class="section-header">
59
+        <span class="section-title">
60
+          <i class="el-icon-tickets"></i>
61
+          计算结果
62
+        </span>
63
+        <span class="section-info">
64
+          共 {{ calculationResults.length }} 条计算结果
65
+        </span>
66
+        <el-button type="text" size="small" @click="handleExport" icon="el-icon-download">
67
+          导出结果
68
+        </el-button>
69
+      </div>
70
+      
71
+      <el-table :data="calculationResults" style="width: 100%" border stripe>
72
+        <el-table-column prop="pointNumber" label="待求点号" width="120" align="center"></el-table-column>
73
+        <el-table-column prop="newUtmX" label="UTM坐标x(m)" width="180" align="center">
74
+          <template slot-scope="scope">
75
+            <span class="result-value">{{ formatNumber(scope.row.newUtmX,4) }}</span>
76
+          </template>
77
+        </el-table-column>
78
+        <el-table-column prop="newUtmY" label="UTM坐标y(m)" width="180" align="center">
79
+          <template slot-scope="scope">
80
+            <span class="result-value">{{ formatNumber(scope.row.newUtmY,4) }}</span>
81
+          </template>
82
+        </el-table-column>
83
+      </el-table>
84
+    </div>
85
+    
86
+    <!-- 空状态 -->
87
+    <div v-else class="empty-state">
88
+      <i class="el-icon-document"></i>
89
+      <p>暂无计算结果</p>
90
+      <p class="empty-tip">请先导入Excel数据,然后点击"执行计算"</p>
91
+    </div>
92
+    
93
+    <!-- 导入Excel对话框 -->
94
+    <el-dialog title="导入Excel" :visible.sync="importDialogVisible" width="550px" @close="resetImport">
95
+      <div class="import-tips">
96
+        <el-alert
97
+          title="Excel模板格式说明"
98
+          type="info"
99
+          :closable="false"
100
+          show-icon>
101
+          <div class="template-info">
102
+            <p>请确保Excel文件包含以下列(第一行为表头):</p>
103
+            <ul>
104
+              <li><strong>待求点</strong> - 点号</li>
105
+              <li><strong>坐标系</strong> - WGS84/CGCS2000/Beijing54/Xian80</li>
106
+              <li><strong>UTM坐标X</strong> - (m)</li>
107
+              <li><strong>UTM坐标Y</strong> - (m)</li>
108
+              <li><strong>带号</strong> - 带号数值</li>
109
+              <li><strong>新带号</strong> - 新带号数值</li>
110
+              <li><strong>经度位置</strong> - E/W</li>
111
+              <li><strong>纬度位置</strong> - N/S</li>
112
+            </ul>
113
+          </div>
114
+        </el-alert>
115
+         <div class="template-download-wrapper">
116
+            <el-button type="primary" plain size="small" @click="handleDownloadTemplate" icon="el-icon-download">
117
+              下载Excel模板
118
+            </el-button>
119
+          </div>
120
+      </div>
121
+      <div style="text-align: center;">
122
+        <el-upload
123
+          class="upload-area"
124
+          :action="''"
125
+          :auto-upload="false"
126
+          :on-change="handleFileChange"
127
+          :show-file-list="true"
128
+          accept=".xlsx,.xls"
129
+          drag
130
+          ref="upload">
131
+          <i class="el-icon-upload"></i>
132
+          <div class="el-upload__text">将Excel文件拖到此处,或<em>点击选择</em></div>
133
+          <div class="el-upload__tip" slot="tip">
134
+            支持.xlsx和.xls格式文件
135
+          </div>
136
+        </el-upload>
137
+      </div>
138
+      
139
+      <span slot="footer" class="dialog-footer">
140
+        <el-button @click="importDialogVisible = false">取消</el-button>
141
+        <el-button type="primary" @click="submitImport" :loading="importLoading" :disabled="!importFile">
142
+          确认导入
143
+        </el-button>
144
+      </span>
145
+    </el-dialog>
146
+    
147
+    <!-- 预览数据对话框 - 显示导入的原始数据 -->
148
+    <el-dialog title="导入数据预览" :visible.sync="previewDialogVisible" width="80%">
149
+      <div class="preview-info">
150
+        <span>共 {{ importedData.length }} 条数据</span>
151
+        <span style="margin-left: 20px;">状态:{{ importedData.filter(item => item.calculated).length }} 条已计算,{{ importedData.filter(item => !item.calculated).length }} 条未计算</span>
152
+      </div>
153
+      <el-table :data="importedData" border stripe max-height="500">
154
+        <el-table-column prop="pointNumber" label="待求点号" width="120" fixed="left" align="center"></el-table-column>
155
+        <el-table-column prop="coordinateSystem" label="坐标系" width="110" align="center">
156
+          <template slot-scope="scope">
157
+            <el-tag size="small" :type="getCoordinateType(scope.row.coordinateSystem)">
158
+              {{ scope.row.coordinateSystem }}
159
+            </el-tag>
160
+          </template>
161
+        </el-table-column>
162
+        <el-table-column prop="utmX" label="UTM X坐标(m)" width="130" align="center">
163
+          <template slot-scope="scope">
164
+            {{ formatNumber(scope.row.utmX,4) }}
165
+          </template>
166
+        </el-table-column>
167
+         <el-table-column prop="utmY" label="UTM Y坐标(m)" width="130" align="center">
168
+          <template slot-scope="scope">
169
+            {{ formatNumber(scope.row.utmY,4) }}
170
+          </template>
171
+        </el-table-column>
172
+        <el-table-column prop="band" label="带号" width="130" align="center">
173
+          <template slot-scope="scope">
174
+            {{ scope.row.band}}
175
+                   </template>
176
+        </el-table-column>
177
+        <el-table-column prop="newBand" label="新带号" width="130" align="center">
178
+          <template slot-scope="scope">
179
+            {{ scope.row.newBand}}
180
+                   </template>
181
+        </el-table-column>
182
+        <el-table-column prop="longitudePosition" label="经度位置" width="130" align="center">
183
+          <template slot-scope="scope">
184
+            {{ scope.row.longitudePosition}}
185
+                   </template>
186
+        </el-table-column>
187
+        <el-table-column prop="latitudePosition" label="纬度位置" width="130" align="center">
188
+          <template slot-scope="scope">
189
+            {{ scope.row.latitudePosition}}
190
+                   </template>
191
+        </el-table-column>
192
+      </el-table>
193
+      <span slot="footer" class="dialog-footer">
194
+        <el-button type="primary" @click="previewDialogVisible = false">关闭</el-button>
195
+      </span>
196
+    </el-dialog>
197
+  </div>
198
+</template>
199
+
200
+<script>
201
+import { calculate, importExcel,exportExcel,downloadTemplate } from '@/api/calculate/utmbandchange'
202
+
203
+export default {
204
+  name: 'UTMBandChangeTool',    
205
+  data() {
206
+    return {
207
+      importedData: [],        // 导入的原始数据
208
+      calculationResults: [],  // 计算结果
209
+      importDialogVisible: false,
210
+      importLoading: false,
211
+      importFile: null,
212
+      calculating: false,
213
+      previewDialogVisible: false,
214
+      projectionHeight: 0
215
+    }
216
+  },
217
+  watch: {
218
+    // 当投影面高程改变时,重新计算(如果已有数据)
219
+    projectionHeight(newVal, oldVal) {
220
+       // 清除之前的定时器
221
+      if (this.heightTimer) {
222
+        clearTimeout(this.heightTimer)
223
+      }
224
+      
225
+      // 只有已有数据时才触发计算
226
+      if (this.importedData.length > 0 && this.calculationResults.length > 0) {
227
+        // 设置新的定时器,500ms 后执行
228
+        this.heightTimer = setTimeout(() => {
229
+          this.handleCalculate()
230
+        }, 500)
231
+      }
232
+    }
233
+  },
234
+  methods: {
235
+    // 打开导入对话框 
236
+    handleImport() {
237
+      this.importDialogVisible = true
238
+    },
239
+    
240
+    // 文件选择变化
241
+    handleFileChange(file) {
242
+      this.importFile = file.raw
243
+    },
244
+    
245
+    // 提交导入
246
+    async submitImport() {
247
+      if (!this.importFile) {
248
+        this.$message.warning('请选择文件')
249
+        return
250
+      }
251
+      
252
+      this.importLoading = true
253
+      
254
+      const formData = new FormData()
255
+      formData.append('file', this.importFile)
256
+      
257
+        const response = await importExcel(formData)
258
+        
259
+        if (response.code === 200) {
260
+          const result = response.data
261
+          // 将后端返回的数据转换为前端格式
262
+          this.importedData = (result.data || []).map(item => ({
263
+            pointNumber: item.pointNumber,
264
+            coordinateSystem: item.coordinateSystem,
265
+            utmX: item.utmX,
266
+            utmY: item.utmY,
267
+            band: item.band,
268
+            newBand: item.newBand,
269
+            longitudePosition: item.longitudePosition,
270
+            latitudePosition: item.latitudePosition
271
+          }))
272
+          
273
+          // 清空之前的计算结果
274
+          this.calculationResults = []
275
+          
276
+          this.$message.success(`${response.msg}`)
277
+          this.importDialogVisible = false
278
+          this.importLoading = false
279
+        } else {
280
+          this.$message.error(response.msg)
281
+        }
282
+    },
283
+    
284
+    // 预览数据 - 显示导入的原始数据
285
+    handlePreview() {
286
+      if (!this.importedData || this.importedData.length === 0) {
287
+        this.$message.warning('没有可预览的数据')
288
+        return
289
+      }
290
+      this.previewDialogVisible = true
291
+    },
292
+    
293
+    // 下载模板
294
+    handleDownloadTemplate() {
295
+       this.download('/calculate/utmBandChange/template', {}, 'UTM换带模板.xlsx')
296
+    },
297
+    
298
+    
299
+    // 执行计算
300
+    async handleCalculate() {
301
+      if (!this.importedData || this.importedData.length === 0) {
302
+        this.$message.warning('没有数据可计算')
303
+        return
304
+      }
305
+      
306
+      this.calculating = true
307
+      const results = []
308
+      let successCount = 0
309
+      let failCount = 0
310
+      
311
+      // 构建请求参数
312
+      const requestData = this.importedData.map(item => ({
313
+        pointNumber: item.pointNumber,
314
+        coordinateSystem: item.coordinateSystem,
315
+        utmX: item.utmX,
316
+        utmY: item.utmY,
317
+        band: item.band,
318
+        newBand: item.newBand,
319
+        longitudePosition: item.longitudePosition,
320
+        latitudePosition: item.latitudePosition,
321
+        projectionHeight: this.projectionHeight
322
+      }))
323
+      
324
+      const response = await calculate(requestData)
325
+      
326
+      if (response.code === 200) {
327
+        const results = response.data || []
328
+        
329
+        // 更新计算结果
330
+        this.calculationResults = results.map(item => ({
331
+          pointNumber: item.pointNumber,
332
+          coordinateSystem: item.coordinateSystem,
333
+          utmX: item.utmX,
334
+          utmY: item.utmY,
335
+          band: item.band,
336
+          newBand: item.newBand,
337
+          longitudePosition: item.longitudePosition,
338
+          latitudePosition: item.latitudePosition,
339
+          newUtmX: item.newUtmX,
340
+          newUtmY: item.newUtmY,
341
+          projectionHeight: this.projectionHeight
342
+        }))
343
+        
344
+        // 更新导入数据的计算状态
345
+        this.importedData.forEach(importItem => {
346
+          const found = results.find(r => r.pointNumber === importItem.pointNumber)
347
+          if (found && found.utmX !== -1) {
348
+            importItem.calculated = true
349
+          }
350
+        })
351
+        
352
+        const successCount = results.filter(r => r.utmX !== -1).length
353
+        const failCount = results.length - successCount
354
+        
355
+        this.$message.success(`计算完成,成功 ${successCount} 条${failCount > 0 ? `,失败 ${failCount} 条` : ''}`)
356
+        this.calculating = false
357
+        } else {
358
+          this.$message.error(response.msg)
359
+        }
360
+    },
361
+    
362
+    
363
+    // 导出结果
364
+    async handleExport() {
365
+      if (this.calculationResults.length === 0) {
366
+        this.$message.warning('没有结果可导出')
367
+        return
368
+      }
369
+
370
+      const response = await exportExcel(this.calculationResults)
371
+      
372
+      const blob = new Blob([response], { 
373
+        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
374
+      })
375
+      
376
+      const url = window.URL.createObjectURL(blob)
377
+      const link = document.createElement('a')
378
+      link.href = url
379
+      link.download = `UTM换带结果_${new Date().getTime()}.xlsx`
380
+      link.click()
381
+      window.URL.revokeObjectURL(url)
382
+  },
383
+    
384
+  // 清空全部
385
+  clearAll() {
386
+    if ((!this.importedData || this.importedData.length === 0) && this.calculationResults.length === 0) {
387
+      return
388
+    }
389
+    
390
+    this.$confirm('确定清空所有数据吗?此操作不可恢复!', '警告', {
391
+      confirmButtonText: '确定',
392
+      cancelButtonText: '取消',
393
+      type: 'warning'
394
+    }).then(() => {
395
+      this.importedData = []
396
+      this.calculationResults = []
397
+      this.$message.success('已清空所有数据')
398
+    }).catch(() => {})
399
+  },
400
+  
401
+  // 重置导入状态
402
+  resetImport() {
403
+    this.importFile = null
404
+    if (this.$refs.upload) {
405
+      this.$refs.upload.clearFiles()
406
+    }
407
+  },
408
+  
409
+  // 格式化数字显示
410
+  formatNumber(value, decimals) {
411
+    if (value === null || value === undefined) return '--'
412
+    return Number(value).toFixed(decimals)
413
+  },
414
+  
415
+  // 获取坐标系标签类型
416
+  getCoordinateType(system) {
417
+    const types = {
418
+      'WGS84': 'primary',
419
+      'CGCS2000': 'success',
420
+      'Beijing54': 'warning',
421
+      'Xian80': 'info'
422
+    }
423
+    return types[system] || 'info'
424
+  }
425
+  }
426
+}
427
+</script>
428
+
429
+<style scoped>
430
+.utm-band-change-tool {
431
+  width: 100%;
432
+}
433
+
434
+.tool-header {
435
+  margin-bottom: 20px;
436
+}
437
+
438
+.card-header-buttons {
439
+  display: flex;
440
+  gap: 10px;
441
+  flex-wrap: wrap;
442
+}
443
+
444
+/* 投影面高程设置样式 */
445
+.height-setting {
446
+  background: #f5f7fa;
447
+  border-radius: 8px;
448
+  padding: 12px 20px;
449
+  margin-bottom: 20px;
450
+  border: 1px solid #e4e7ed;
451
+  display: flex;
452
+  align-items: center;
453
+  gap: 20px;
454
+  flex-wrap: wrap;
455
+}
456
+
457
+.result-section {
458
+  margin-top: 10px;
459
+}
460
+
461
+.section-header {
462
+  padding: 12px 16px;
463
+  background: #f5f7fa;
464
+  border-radius: 8px 8px 0 0;
465
+  border: 1px solid #e4e7ed;
466
+  border-bottom: none;
467
+  display: flex;
468
+  justify-content: space-between;
469
+  align-items: center;
470
+}
471
+
472
+.section-title {
473
+  font-size: 14px;
474
+  font-weight: bold;
475
+  color: #303133;
476
+}
477
+
478
+.section-title i {
479
+  margin-right: 8px;
480
+  color: #11a983;
481
+}
482
+
483
+.section-info {
484
+  font-size: 12px;
485
+  color: #909399;
486
+}
487
+
488
+.result-value {
489
+  color: #409eff;
490
+  font-family: monospace;
491
+  font-weight: 500;
492
+}
493
+
494
+.empty-state {
495
+  text-align: center;
496
+  padding: 60px 20px;
497
+  background: #fff;
498
+  border-radius: 8px;
499
+  border: 1px solid #e4e7ed;
500
+  color: #909399;
501
+}
502
+
503
+.empty-state i {
504
+  font-size: 64px;
505
+  margin-bottom: 16px;
506
+}
507
+
508
+.empty-tip {
509
+  font-size: 12px;
510
+  margin-top: 12px;
511
+  color: #c0c4cc;
512
+}
513
+
514
+.import-tips {
515
+  margin-bottom: 20px;
516
+}
517
+
518
+.template-info {
519
+  margin-top: 12px;
520
+}
521
+
522
+.template-info ul {
523
+  margin: 8px 0;
524
+  padding-left: 20px;
525
+}
526
+
527
+.template-info li {
528
+  margin: 4px 0;
529
+  font-size: 13px;
530
+}
531
+
532
+.upload-area {
533
+  margin-top: 10px;
534
+}
535
+
536
+.preview-info {
537
+  margin-bottom: 15px;
538
+  padding: 10px;
539
+  background: #f5f7fa;
540
+  border-radius: 4px;
541
+  font-size: 14px;
542
+  color: #606266;
543
+}
544
+
545
+.dialog-footer {
546
+  width: 100%;
547
+  display: flex;
548
+  justify-content: flex-end;
549
+  gap: 10px;
550
+}
551
+
552
+.template-download-wrapper {
553
+  margin-top: 12px;
554
+  display: flex;
555
+  align-items: center;
556
+  justify-content: flex-end;
557
+  gap: 10px;
558
+  padding-top: 12px;
559
+  border-top: 1px dashed #e4e7ed;
560
+}
561
+</style>

+ 548
- 0
oa-ui/src/views/calculate/tools/utmnegative.vue Näytä tiedosto

@@ -0,0 +1,548 @@
1
+<!-- UTM反算工具组件 -->
2
+<template>
3
+  <div class="utm-negative-tool">
4
+    <!-- 操作按钮区 -->
5
+    <div class="tool-header">
6
+      <div class="card-header-buttons">
7
+        <el-button type="primary" @click="handleImport" size="small" icon="el-icon-upload">
8
+          导入Excel
9
+        </el-button>
10
+
11
+        <el-button 
12
+          type="success" 
13
+          @click="handlePreview" 
14
+          size="small" 
15
+          :disabled="!importedData || importedData.length === 0"
16
+          icon="el-icon-view">
17
+          预览数据
18
+        </el-button>
19
+        <el-button 
20
+          type="warning" 
21
+          @click="handleCalculate" 
22
+          size="small" 
23
+          :disabled="!importedData || importedData.length === 0 || calculating"
24
+          :loading="calculating"
25
+          icon="el-icon-caret-right">
26
+          {{ calculating ? '计算中...' : '执行计算' }}
27
+        </el-button>
28
+        <el-button 
29
+          type="danger" 
30
+          @click="clearAll" 
31
+          size="small" 
32
+          :disabled="(!importedData || importedData.length === 0) && calculationResults.length === 0"
33
+          plain
34
+          icon="el-icon-delete">
35
+          清空全部
36
+        </el-button>
37
+      </div>
38
+    </div>
39
+    
40
+    <!-- 投影面高程设置 -->
41
+    <div class="height-setting">
42
+      <div class="setting-label">
43
+        <span>投影面高程</span>
44
+      </div>
45
+      <div class="setting-content">
46
+        <el-input 
47
+          v-model="projectionHeight" 
48
+          size="small" 
49
+          style="width: 120px; margin-right: 10px;">
50
+        </el-input>
51
+        <span class="unit">米 (m)</span>
52
+        
53
+      </div>
54
+    </div>
55
+
56
+    <!-- 计算结果展示区 - 只显示计算结果,不包含原始数据 -->
57
+    <div v-if="calculationResults.length > 0" class="result-section">
58
+      <div class="section-header">
59
+        <span class="section-title">
60
+          <i class="el-icon-tickets"></i>
61
+          计算结果
62
+        </span>
63
+        <span class="section-info">
64
+          共 {{ calculationResults.length }} 条计算结果
65
+        </span>
66
+        <el-button type="text" size="small" @click="handleExport" icon="el-icon-download">
67
+          导出结果
68
+        </el-button>
69
+      </div>
70
+      
71
+      <el-table :data="calculationResults" style="width: 100%" border stripe>
72
+        <el-table-column prop="pointNumber" label="待求点号" width="120" align="center"></el-table-column>
73
+        <el-table-column prop="longitude" label="大地经度(°)" width="160" align="center">
74
+          <template slot-scope="scope">
75
+            <span class="result-value">{{ formatNumber(scope.row.longitude,10) }}</span>
76
+          </template>
77
+        </el-table-column>
78
+        <el-table-column prop="latitude" label="大地纬度(°)" width="160" align="center">
79
+          <template slot-scope="scope">
80
+            <span class="result-value">{{ formatNumber(scope.row.latitude,10) }}</span>
81
+          </template>
82
+        </el-table-column>
83
+      </el-table>
84
+    </div>
85
+    
86
+    <!-- 空状态 -->
87
+    <div v-else class="empty-state">
88
+      <i class="el-icon-document"></i>
89
+      <p>暂无计算结果</p>
90
+      <p class="empty-tip">请先导入Excel数据,然后点击"执行计算"</p>
91
+    </div>
92
+    
93
+    <!-- 导入Excel对话框 -->
94
+    <el-dialog title="导入Excel" :visible.sync="importDialogVisible" width="550px" @close="resetImport">
95
+      <div class="import-tips">
96
+        <el-alert
97
+          title="Excel模板格式说明"
98
+          type="info"
99
+          :closable="false"
100
+          show-icon>
101
+          <div class="template-info">
102
+            <p>请确保Excel文件包含以下列(第一行为表头):</p>
103
+            <ul>
104
+              <li><strong>待求点</strong> - 点号</li>
105
+              <li><strong>坐标系</strong> - WGS84/CGCS2000/Beijing54/Xian80</li>
106
+              <li><strong>UTM坐标x</strong> - X坐标值(米)</li>
107
+              <li><strong>UTM坐标y</strong> - Y坐标值(米)</li>
108
+              <li><strong>带号</strong> - 带号数值(UTM使用6度带)</li>
109
+              <li><strong>经度位置</strong> - E/W(东/西)</li>
110
+              <li><strong>纬度位置</strong> - N/S(北/南)</li>
111
+            </ul>
112
+          </div>
113
+        </el-alert>
114
+         <div class="template-download-wrapper">
115
+            <el-button type="primary" plain size="small" @click="handleDownloadTemplate" icon="el-icon-download">
116
+              下载Excel模板
117
+            </el-button>
118
+          </div>
119
+      </div>
120
+      <div style="text-align: center;">
121
+        <el-upload
122
+          class="upload-area"
123
+          :action="''"
124
+          :auto-upload="false"
125
+          :on-change="handleFileChange"
126
+          :show-file-list="true"
127
+          accept=".xlsx,.xls"
128
+          drag
129
+          ref="upload">
130
+          <i class="el-icon-upload"></i>
131
+          <div class="el-upload__text">将Excel文件拖到此处,或<em>点击选择</em></div>
132
+          <div class="el-upload__tip" slot="tip">
133
+            支持.xlsx和.xls格式文件
134
+          </div>
135
+        </el-upload>
136
+      </div>
137
+      
138
+      <span slot="footer" class="dialog-footer">
139
+        <el-button @click="importDialogVisible = false">取消</el-button>
140
+        <el-button type="primary" @click="submitImport" :loading="importLoading" :disabled="!importFile">
141
+          确认导入
142
+        </el-button>
143
+      </span>
144
+    </el-dialog>
145
+    <!-- 预览数据对话框 - 显示导入的原始数据 -->
146
+    <el-dialog title="导入数据预览"  :visible.sync="previewDialogVisible" width="80%">
147
+      <div class="preview-info">
148
+        <span>共 {{ importedData.length }} 条数据</span>
149
+        <span style="margin-left: 20px;">状态:{{ importedData.filter(item => item.calculated).length }} 条已计算,{{ importedData.filter(item => !item.calculated).length }} 条未计算</span>
150
+      </div>
151
+      <el-table :data="importedData" border stripe max-height="500">
152
+        <el-table-column prop="pointNumber" label="待求点号" width="120" fixed="left" align="center"></el-table-column>
153
+        <el-table-column prop="coordinateSystem" label="坐标系" width="110" align="center">
154
+          <template slot-scope="scope">
155
+            <el-tag size="small" :type="getCoordinateType(scope.row.coordinateSystem)">
156
+              {{ scope.row.coordinateSystem }}
157
+            </el-tag>
158
+          </template>
159
+        </el-table-column>
160
+        <el-table-column prop="utmX" label="UTM坐标X(m)" width="150" align="center">
161
+          <template slot-scope="scope">
162
+            {{ formatNumber(scope.row.utmX,4) }}
163
+          </template>
164
+        </el-table-column>
165
+        <el-table-column prop="utmY" label="UTM坐标Y(m)" width="150" align="center">
166
+          <template slot-scope="scope">
167
+            {{ formatNumber(scope.row.utmY,4) }}
168
+          </template>
169
+        </el-table-column>
170
+        <el-table-column prop="band" label="带号" width="80" align="center"></el-table-column>
171
+        <el-table-column prop="longitudePosition" label="经度位置" width="100" align="center">
172
+          <template slot-scope="scope">
173
+            {{scope.row.longitudePosition}}
174
+          </template>
175
+        </el-table-column>
176
+        <el-table-column prop="latitudePosition" label="纬度位置" width="100" align="center">
177
+          <template slot-scope="scope">
178
+            {{ scope.row.latitudePosition }}
179
+          </template>
180
+        </el-table-column>
181
+      </el-table>
182
+      <span slot="footer" class="dialog-footer">
183
+        <el-button type="primary" @click="previewDialogVisible = false">关闭</el-button>
184
+      </span>
185
+    </el-dialog>
186
+ </div>
187
+</template>
188
+
189
+<script>
190
+import { calculate, importExcel,exportExcel,downloadTemplate } from '@/api/calculate/utmnegative'
191
+
192
+export default {
193
+  name: 'UTMNagativeTool',
194
+  data() {
195
+    return {
196
+      importedData: [],        // 导入的原始数据
197
+      calculationResults: [],  // 计算结果
198
+      importDialogVisible: false,
199
+      importLoading: false,
200
+      importFile: null,
201
+      calculating: false,
202
+      previewDialogVisible: false,
203
+      projectionHeight: 0,
204
+      heightTimer: null,
205
+    }
206
+  },
207
+  watch: {
208
+    // 当投影面高程改变时,重新计算(如果已有数据)
209
+    projectionHeight(newVal, oldVal) {
210
+       // 清除之前的定时器
211
+      if (this.heightTimer) {
212
+        clearTimeout(this.heightTimer)
213
+      }
214
+      
215
+      // 只有已有数据时才触发计算
216
+      if (this.importedData.length > 0 && this.calculationResults.length > 0) {
217
+        // 设置新的定时器,500ms 后执行
218
+        this.heightTimer = setTimeout(() => {
219
+          this.handleCalculate()
220
+        }, 500)
221
+      }
222
+    }
223
+  },
224
+  methods: {
225
+    // 打开导入对话框 
226
+    handleImport() {
227
+      this.importDialogVisible = true
228
+    },
229
+    
230
+    // 文件选择变化
231
+    handleFileChange(file) {
232
+      this.importFile = file.raw
233
+    },
234
+    
235
+    // 提交导入
236
+    async submitImport() {
237
+      if (!this.importFile) {
238
+        this.$message.warning('请选择文件')
239
+        return
240
+      }
241
+      
242
+      this.importLoading = true
243
+      
244
+      const formData = new FormData()
245
+      formData.append('file', this.importFile)
246
+      
247
+        const response = await importExcel(formData)
248
+        
249
+        if (response.code === 200) {
250
+          const result = response.data
251
+          
252
+          // 将后端返回的数据转换为前端格式
253
+          this.importedData = (result.data || []).map(item => ({
254
+            pointNumber: item.pointNumber,
255
+            coordinateSystem: item.coordinateSystem,
256
+            utmX: item.utmX,
257
+            utmY: item.utmY,
258
+            band: item.band,
259
+            longitudePosition: item.longitudePosition,
260
+            latitudePosition: item.latitudePosition
261
+          }))
262
+          
263
+          // 清空之前的计算结果
264
+          this.calculationResults = []
265
+          
266
+          this.$message.success(`${response.msg}`)
267
+          this.importDialogVisible = false
268
+          this.importLoading = false
269
+        } else {
270
+          this.$message.error(response.msg)
271
+        }
272
+    },
273
+    
274
+    // 预览数据 - 显示导入的原始数据
275
+    handlePreview() {
276
+      if (!this.importedData || this.importedData.length === 0) {
277
+        this.$message.warning('没有可预览的数据')
278
+        return
279
+      }
280
+      this.previewDialogVisible = true
281
+    },
282
+    
283
+    // 下载模板
284
+    handleDownloadTemplate() {
285
+       this.download('/calculate/utmNegative/template', {}, 'UTM反算模板.xlsx')
286
+    },
287
+    
288
+    
289
+    // 执行计算
290
+    async handleCalculate() {
291
+      if (!this.importedData || this.importedData.length === 0) {
292
+        this.$message.warning('没有数据可计算')
293
+        return
294
+      }
295
+      
296
+      this.calculating = true
297
+      const results = []
298
+      let successCount = 0
299
+      let failCount = 0
300
+      
301
+      // 构建请求参数
302
+      const requestData = this.importedData.map(item => ({
303
+        pointNumber: item.pointNumber,
304
+        coordinateSystem: item.coordinateSystem,
305
+        utmX: parseFloat(item.utmX),
306
+        utmY: parseFloat(item.utmY),
307
+        band: parseInt(item.band),
308
+        longitudePosition: item.longitudePosition,
309
+        latitudePosition: item.latitudePosition,
310
+        projectionHeight: this.projectionHeight
311
+      }))
312
+      
313
+      const response = await calculate(requestData)
314
+      
315
+      if (response.code === 200) {
316
+        const results = response.data || []
317
+        
318
+        // 更新计算结果
319
+        this.calculationResults = results.map(item => ({
320
+          pointNumber: item.pointNumber,
321
+          coordinateSystem: item.coordinateSystem,
322
+          utmX: item.utmX,
323
+          utmY: item.utmY,
324
+          band: parseInt(item.band),
325
+          longitude: item.longitude,
326
+          longitudePosition: item.longitudePosition,
327
+          latitude: item.latitude,
328
+          latitudePosition: item.latitudePosition
329
+        }))
330
+        
331
+        // 更新导入数据的计算状态
332
+        this.importedData.forEach(importItem => {
333
+          const found = results.find(r => r.pointNumber === importItem.pointNumber)
334
+          if (found && found.longitude !== -1) {
335
+            importItem.calculated = true
336
+          }
337
+        })
338
+        
339
+        const successCount = results.filter(r => r.longitude !== -1).length
340
+        const failCount = results.length - successCount
341
+        
342
+        this.$message.success(`计算完成,成功 ${successCount} 条${failCount > 0 ? `,失败 ${failCount} 条` : ''}`)
343
+        this.calculating = false
344
+        } else {
345
+          this.$message.error(response.msg)
346
+        }
347
+    },
348
+    
349
+    
350
+    // 导出结果
351
+    async handleExport() {
352
+      if (this.calculationResults.length === 0) {
353
+        this.$message.warning('没有结果可导出')
354
+        return
355
+      }
356
+      
357
+        const response = await exportExcel(this.calculationResults)
358
+        
359
+        const blob = new Blob([response], { 
360
+          type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
361
+        })
362
+        
363
+        const url = window.URL.createObjectURL(blob)
364
+        const link = document.createElement('a')
365
+        link.href = url
366
+        link.download = `UTM反算结果_${new Date().getTime()}.xlsx`
367
+        link.click()
368
+        window.URL.revokeObjectURL(url)
369
+  },
370
+    
371
+  // 清空全部
372
+  clearAll() {
373
+    if ((!this.importedData || this.importedData.length === 0) && this.calculationResults.length === 0) {
374
+      return
375
+    }
376
+    
377
+    this.$confirm('确定清空所有数据吗?此操作不可恢复!', '警告', {
378
+      confirmButtonText: '确定',
379
+      cancelButtonText: '取消',
380
+      type: 'warning'
381
+    }).then(() => {
382
+      this.importedData = []
383
+      this.calculationResults = []
384
+      this.$message.success('已清空所有数据')
385
+    }).catch(() => {})
386
+  },
387
+  
388
+  // 重置导入状态
389
+  resetImport() {
390
+    this.importFile = null
391
+    if (this.$refs.upload) {
392
+      this.$refs.upload.clearFiles()
393
+    }
394
+  },
395
+  
396
+  // 格式化数字显示
397
+  formatNumber(value, decimals = 3) {
398
+    if (value === null || value === undefined) return '--'
399
+    return Number(value).toFixed(decimals)
400
+  },
401
+  
402
+  // 获取坐标系标签类型
403
+  getCoordinateType(system) {
404
+    const types = {
405
+      'WGS84': 'primary',
406
+      'CGCS2000': 'success',
407
+      'Beijing54': 'warning',
408
+      'Xian80': 'info'
409
+    }
410
+    return types[system] || 'info'
411
+  }
412
+  }
413
+}
414
+</script>
415
+
416
+<style scoped>
417
+.utm-negative-tool {
418
+  width: 100%;
419
+}
420
+
421
+.tool-header {
422
+  margin-bottom: 20px;
423
+}
424
+
425
+.card-header-buttons {
426
+  display: flex;
427
+  gap: 10px;
428
+  flex-wrap: wrap;
429
+}
430
+
431
+/* 投影面高程设置样式 */
432
+.height-setting {
433
+  background: #f5f7fa;
434
+  border-radius: 8px;
435
+  padding: 12px 20px;
436
+  margin-bottom: 20px;
437
+  border: 1px solid #e4e7ed;
438
+  display: flex;
439
+  align-items: center;
440
+  gap: 20px;
441
+  flex-wrap: wrap;
442
+}
443
+
444
+.result-section {
445
+  margin-top: 10px;
446
+}
447
+
448
+.section-header {
449
+  padding: 12px 16px;
450
+  background: #f5f7fa;
451
+  border-radius: 8px 8px 0 0;
452
+  border: 1px solid #e4e7ed;
453
+  border-bottom: none;
454
+  display: flex;
455
+  justify-content: space-between;
456
+  align-items: center;
457
+}
458
+
459
+.section-title {
460
+  font-size: 14px;
461
+  font-weight: bold;
462
+  color: #303133;
463
+}
464
+
465
+.section-title i {
466
+  margin-right: 8px;
467
+  color: #11a983;
468
+}
469
+
470
+.section-info {
471
+  font-size: 12px;
472
+  color: #909399;
473
+}
474
+
475
+.result-value {
476
+  color: #409eff;
477
+  font-family: monospace;
478
+  font-weight: 500;
479
+}
480
+
481
+.empty-state {
482
+  text-align: center;
483
+  padding: 60px 20px;
484
+  background: #fff;
485
+  border-radius: 8px;
486
+  border: 1px solid #e4e7ed;
487
+  color: #909399;
488
+}
489
+
490
+.empty-state i {
491
+  font-size: 64px;
492
+  margin-bottom: 16px;
493
+}
494
+
495
+.empty-tip {
496
+  font-size: 12px;
497
+  margin-top: 12px;
498
+  color: #c0c4cc;
499
+}
500
+
501
+.import-tips {
502
+  margin-bottom: 20px;
503
+}
504
+
505
+.template-info {
506
+  margin-top: 12px;
507
+}
508
+
509
+.template-info ul {
510
+  margin: 8px 0;
511
+  padding-left: 20px;
512
+}
513
+
514
+.template-info li {
515
+  margin: 4px 0;
516
+  font-size: 13px;
517
+}
518
+
519
+.upload-area {
520
+  margin-top: 10px;
521
+}
522
+
523
+.preview-info {
524
+  margin-bottom: 15px;
525
+  padding: 10px;
526
+  background: #f5f7fa;
527
+  border-radius: 4px;
528
+  font-size: 14px;
529
+  color: #606266;
530
+}
531
+
532
+.dialog-footer {
533
+  width: 100%;
534
+  display: flex;
535
+  justify-content: flex-end;
536
+  gap: 10px;
537
+}
538
+
539
+.template-download-wrapper {
540
+  margin-top: 12px;
541
+  display: flex;
542
+  align-items: center;
543
+  justify-content: flex-end;
544
+  gap: 10px;
545
+  padding-top: 12px;
546
+  border-top: 1px dashed #e4e7ed;
547
+}
548
+</style>

+ 555
- 0
oa-ui/src/views/calculate/tools/utmpositive.vue Näytä tiedosto

@@ -0,0 +1,555 @@
1
+<!-- UTM正算工具组件 -->
2
+<template>
3
+  <div class="utm-positive-tool">
4
+    <!-- 操作按钮区 -->
5
+    <div class="tool-header">
6
+      <div class="card-header-buttons">
7
+        <el-button type="primary" @click="handleImport" size="small" icon="el-icon-upload">
8
+          导入Excel
9
+        </el-button>
10
+
11
+        <el-button 
12
+          type="success" 
13
+          @click="handlePreview" 
14
+          size="small" 
15
+          :disabled="!importedData || importedData.length === 0"
16
+          icon="el-icon-view">
17
+          预览数据
18
+        </el-button>
19
+        <el-button 
20
+          type="warning" 
21
+          @click="handleCalculate" 
22
+          size="small" 
23
+          :disabled="!importedData || importedData.length === 0 || calculating"
24
+          :loading="calculating"
25
+          icon="el-icon-caret-right">
26
+          {{ calculating ? '计算中...' : '执行计算' }}
27
+        </el-button>
28
+        <el-button 
29
+          type="danger" 
30
+          @click="clearAll" 
31
+          size="small" 
32
+          :disabled="(!importedData || importedData.length === 0) && calculationResults.length === 0"
33
+          plain
34
+          icon="el-icon-delete">
35
+          清空全部
36
+        </el-button>
37
+      </div>
38
+    </div>
39
+    
40
+    <!-- 投影面高程设置 -->
41
+    <div class="height-setting">
42
+      <div class="setting-label">
43
+        <span>投影面高程</span>
44
+      </div>
45
+      <div class="setting-content">
46
+        <el-input 
47
+          v-model="projectionHeight" 
48
+          size="small" 
49
+          style="width: 120px; margin-right: 10px;">
50
+        </el-input>
51
+        <span class="unit">米 (m)</span>
52
+        
53
+      </div>
54
+    </div>
55
+
56
+    <!-- 计算结果展示区 - 只显示计算结果,不包含原始数据 -->
57
+    <div v-if="calculationResults.length > 0" class="result-section">
58
+      <div class="section-header">
59
+        <span class="section-title">
60
+          <i class="el-icon-tickets"></i>
61
+          计算结果
62
+        </span>
63
+        <span class="section-info">
64
+          共 {{ calculationResults.length }} 条计算结果
65
+        </span>
66
+        <el-button type="text" size="small" @click="handleExport" icon="el-icon-download">
67
+          导出结果
68
+        </el-button>
69
+      </div>
70
+      
71
+      <el-table :data="calculationResults" style="width: 100%" border stripe>
72
+        <el-table-column prop="pointNumber" label="待求点号" width="120" align="center"></el-table-column>
73
+        <el-table-column prop="utmX" label="UTM 坐标X(m)" width="180" align="center">
74
+          <template slot-scope="scope">
75
+            <span class="result-value">{{ formatNumber(scope.row.utmX,4) }}</span>
76
+          </template>
77
+        </el-table-column>
78
+        <el-table-column prop="utmY" label="UTM 坐标Y(m)" width="180" align="center">
79
+          <template slot-scope="scope">
80
+            <span class="result-value">{{ formatNumber(scope.row.utmY,4) }}</span>
81
+          </template>
82
+        </el-table-column>
83
+        <el-table-column prop="meridianConvergence" label="子午线收敛角γ(°)" width="200" align="center">
84
+          <template slot-scope="scope">
85
+            <span class="result-value">{{ formatNumber(scope.row.meridianConvergence, 7) }}</span>
86
+          </template>
87
+        </el-table-column>
88
+      </el-table>
89
+    </div>
90
+    
91
+    <!-- 空状态 -->
92
+    <div v-else class="empty-state">
93
+      <i class="el-icon-document"></i>
94
+      <p>暂无计算结果</p>
95
+      <p class="empty-tip">请先导入Excel数据,然后点击"执行计算"</p>
96
+    </div>
97
+    
98
+    <!-- 导入Excel对话框 -->
99
+    <el-dialog title="导入Excel" :visible.sync="importDialogVisible" width="550px" @close="resetImport">
100
+      <div class="import-tips">
101
+        <el-alert
102
+          title="Excel模板格式说明"
103
+          type="info"
104
+          :closable="false"
105
+          show-icon>
106
+          <div class="template-info">
107
+            <p>请确保Excel文件包含以下列(第一行为表头):</p>
108
+            <ul>
109
+              <li><strong>待求点</strong> - 点号</li>
110
+              <li><strong>坐标系</strong> - WGS84/CGCS2000/Beijing54/Xian80</li>
111
+              <li><strong>大地经度</strong> - 经度数值(° ′ ″)</li>
112
+              <li><strong>经度位置</strong> - E/W</li>
113
+              <li><strong>大地纬度</strong> - 纬度数值(° ′ ″)</li>
114
+              <li><strong>纬度位置</strong> - N/S</li>
115
+              <li><strong>带号</strong> - 带号数值(UTM使用6度带)</li>
116
+            </ul>
117
+          </div>
118
+        </el-alert>
119
+         <div class="template-download-wrapper">
120
+            <el-button type="primary" plain size="small" @click="handleDownloadTemplate" icon="el-icon-download">
121
+              下载Excel模板
122
+            </el-button>
123
+          </div>
124
+      </div>
125
+      <div style="text-align: center;">
126
+        <el-upload
127
+          class="upload-area"
128
+          :action="''"
129
+          :auto-upload="false"
130
+          :on-change="handleFileChange"
131
+          :show-file-list="true"
132
+          accept=".xlsx,.xls"
133
+          drag
134
+          ref="upload">
135
+          <i class="el-icon-upload"></i>
136
+          <div class="el-upload__text">将Excel文件拖到此处,或<em>点击选择</em></div>
137
+          <div class="el-upload__tip" slot="tip">
138
+            支持.xlsx和.xls格式文件
139
+          </div>
140
+        </el-upload>
141
+      </div>
142
+      
143
+      <span slot="footer" class="dialog-footer">
144
+        <el-button @click="importDialogVisible = false">取消</el-button>
145
+        <el-button type="primary" @click="submitImport" :loading="importLoading" :disabled="!importFile">
146
+          确认导入
147
+        </el-button>
148
+      </span>
149
+    </el-dialog>
150
+    <!-- 预览数据对话框 - 显示导入的原始数据 -->
151
+    <el-dialog title="导入数据预览"  :visible.sync="previewDialogVisible" width="80%">
152
+      <div class="preview-info">
153
+        <span>共 {{ importedData.length }} 条数据</span>
154
+        <span style="margin-left: 20px;">状态:{{ importedData.filter(item => item.calculated).length }} 条已计算,{{ importedData.filter(item => !item.calculated).length }} 条未计算</span>
155
+      </div>
156
+      <el-table :data="importedData" border stripe max-height="500">
157
+        <el-table-column prop="pointNumber" label="待求点号" width="120" fixed="left" align="center"></el-table-column>
158
+        <el-table-column prop="coordinateSystem" label="坐标系" width="110" align="center">
159
+          <template slot-scope="scope">
160
+            <el-tag size="small" :type="getCoordinateType(scope.row.coordinateSystem)">
161
+              {{ scope.row.coordinateSystem }}
162
+            </el-tag>
163
+          </template>
164
+        </el-table-column>
165
+        <el-table-column prop="longitude" label="大地经度" width="130" align="center">
166
+          <template slot-scope="scope">
167
+            {{ scope.row.longitude }}
168
+          </template>
169
+        </el-table-column>
170
+         <el-table-column prop="longitudePosition" label="经度位置" width="130" align="center">
171
+          <template slot-scope="scope">
172
+            {{ scope.row.longitudePosition}}
173
+          </template>
174
+        </el-table-column>
175
+        <el-table-column prop="latitude" label="大地纬度" width="130" align="center">
176
+          <template slot-scope="scope">
177
+            {{ scope.row.latitude }}
178
+          </template>
179
+        </el-table-column>
180
+         <el-table-column prop="latitudePosition" label="纬度位置" width="130" align="center">
181
+          <template slot-scope="scope">
182
+            {{ scope.row.latitudePosition}}
183
+                   </template>
184
+        </el-table-column>
185
+        <el-table-column prop="band" label="带号" width="80" align="center"></el-table-column>
186
+      </el-table>
187
+      <span slot="footer" class="dialog-footer">
188
+        <el-button type="primary" @click="previewDialogVisible = false">关闭</el-button>
189
+      </span>
190
+    </el-dialog>
191
+ </div>
192
+</template>
193
+
194
+<script>
195
+import { calculate, importExcel,exportExcel,downloadTemplate } from '@/api/calculate/utmpositive'
196
+
197
+export default {
198
+  name: 'UTMPositiveTool',
199
+  data() {
200
+    return {
201
+      importedData: [],        // 导入的原始数据
202
+      calculationResults: [],  // 计算结果
203
+      importDialogVisible: false,
204
+      importLoading: false,
205
+      importFile: null,
206
+      calculating: false,
207
+      previewDialogVisible: false,
208
+      projectionHeight: 0,
209
+      heightTimer: null,
210
+    }
211
+  },
212
+  watch: {
213
+    // 当投影面高程改变时,重新计算(如果已有数据)
214
+    projectionHeight(newVal, oldVal) {
215
+       // 清除之前的定时器
216
+      if (this.heightTimer) {
217
+        clearTimeout(this.heightTimer)
218
+      }
219
+      
220
+      // 只有已有数据时才触发计算
221
+      if (this.importedData.length > 0 && this.calculationResults.length > 0) {
222
+        // 设置新的定时器,500ms 后执行
223
+        this.heightTimer = setTimeout(() => {
224
+          this.handleCalculate()
225
+        }, 500)
226
+      }
227
+    }
228
+  },
229
+  methods: {
230
+    // 打开导入对话框 
231
+    handleImport() {
232
+      this.importDialogVisible = true
233
+    },
234
+    
235
+    // 文件选择变化
236
+    handleFileChange(file) {
237
+      this.importFile = file.raw
238
+    },
239
+    
240
+    // 提交导入
241
+    async submitImport() {
242
+      if (!this.importFile) {
243
+        this.$message.warning('请选择文件')
244
+        return
245
+      }
246
+      
247
+      this.importLoading = true
248
+      
249
+      const formData = new FormData()
250
+      formData.append('file', this.importFile)
251
+      
252
+        const response = await importExcel(formData)
253
+        
254
+        if (response.code === 200) {
255
+          const result = response.data
256
+          
257
+          // 将后端返回的数据转换为前端格式
258
+          this.importedData = (result.data || []).map(item => ({
259
+            pointNumber: item.pointNumber,
260
+            coordinateSystem: item.coordinateSystem,
261
+            longitude: item.longitude,
262
+            longitudePosition: item.longitudePosition,
263
+            latitude: item.latitude,
264
+            latitudePosition: item.latitudePosition,
265
+            band: item.band
266
+          }))
267
+          
268
+          // 清空之前的计算结果
269
+          this.calculationResults = []
270
+          
271
+          this.$message.success(`${response.msg}`)
272
+          this.importDialogVisible = false
273
+          this.importLoading = false
274
+        } else {
275
+          this.$message.error(response.msg)
276
+        }
277
+    },
278
+    
279
+    // 预览数据 - 显示导入的原始数据
280
+    handlePreview() {
281
+      if (!this.importedData || this.importedData.length === 0) {
282
+        this.$message.warning('没有可预览的数据')
283
+        return
284
+      }
285
+      this.previewDialogVisible = true
286
+    },
287
+    
288
+    // 下载模板
289
+    handleDownloadTemplate() {
290
+       this.download('/calculate/utmPositive/template', {}, 'UTM正算模板.xlsx')
291
+    },
292
+    
293
+    
294
+    // 执行计算
295
+    async handleCalculate() {
296
+      if (!this.importedData || this.importedData.length === 0) {
297
+        this.$message.warning('没有数据可计算')
298
+        return
299
+      }
300
+      
301
+      this.calculating = true
302
+      const results = []
303
+      let successCount = 0
304
+      let failCount = 0
305
+      
306
+      // 构建请求参数
307
+      const requestData = this.importedData.map(item => ({
308
+        pointNumber: item.pointNumber,
309
+        coordinateSystem: item.coordinateSystem,
310
+        longitude: parseFloat(item.longitude),
311
+        longitudePosition: item.longitudePosition,
312
+        latitude: parseFloat(item.latitude),
313
+        latitudePosition: item.latitudePosition,
314
+        band: parseInt(item.band),
315
+        projectionHeight: this.projectionHeight
316
+      }))
317
+      
318
+      const response = await calculate(requestData)
319
+      
320
+      if (response.code === 200) {
321
+        const results = response.data || []
322
+        
323
+        // 更新计算结果
324
+        this.calculationResults = results.map(item => ({
325
+          pointNumber: item.pointNumber,
326
+          coordinateSystem: item.coordinateSystem,
327
+          longitude: parseFloat(item.longitude),
328
+          longitudePosition: item.longitudePosition,
329
+          latitude: parseFloat(item.latitude),
330
+          latitudePosition: item.latitudePosition,
331
+          band: parseInt(item.band),
332
+          projectionHeight: this.projectionHeight,
333
+          utmX: item.utmX,
334
+          utmY: item.utmY,
335
+          meridianConvergence: item.meridianConvergence
336
+        }))
337
+        
338
+        // 更新导入数据的计算状态
339
+        this.importedData.forEach(importItem => {
340
+          const found = results.find(r => r.pointNumber === importItem.pointNumber)
341
+          if (found && found.utmX !== -1) {
342
+            importItem.calculated = true
343
+          }
344
+        })
345
+        
346
+        const successCount = results.filter(r => r.utmX !== -1).length
347
+        const failCount = results.length - successCount
348
+        
349
+        this.$message.success(`计算完成,成功 ${successCount} 条${failCount > 0 ? `,失败 ${failCount} 条` : ''}`)
350
+        this.calculating = false
351
+        } else {
352
+          this.$message.error(response.msg)
353
+        }
354
+    },
355
+    
356
+    
357
+    // 导出结果
358
+    async handleExport() {
359
+      if (this.calculationResults.length === 0) {
360
+        this.$message.warning('没有结果可导出')
361
+        return
362
+      }
363
+      
364
+        const response = await exportExcel(this.calculationResults)
365
+        
366
+        const blob = new Blob([response], { 
367
+          type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
368
+        })
369
+        
370
+        const url = window.URL.createObjectURL(blob)
371
+        const link = document.createElement('a')
372
+        link.href = url
373
+        link.download = `UTM正算结果_${new Date().getTime()}.xlsx`
374
+        link.click()
375
+        window.URL.revokeObjectURL(url)
376
+  },
377
+    
378
+  // 清空全部
379
+  clearAll() {
380
+    if ((!this.importedData || this.importedData.length === 0) && this.calculationResults.length === 0) {
381
+      return
382
+    }
383
+    
384
+    this.$confirm('确定清空所有数据吗?此操作不可恢复!', '警告', {
385
+      confirmButtonText: '确定',
386
+      cancelButtonText: '取消',
387
+      type: 'warning'
388
+    }).then(() => {
389
+      this.importedData = []
390
+      this.calculationResults = []
391
+      this.$message.success('已清空所有数据')
392
+    }).catch(() => {})
393
+  },
394
+  
395
+  // 重置导入状态
396
+  resetImport() {
397
+    this.importFile = null
398
+    if (this.$refs.upload) {
399
+      this.$refs.upload.clearFiles()
400
+    }
401
+  },
402
+  
403
+  // 格式化数字显示
404
+  formatNumber(value, decimals = 3) {
405
+    if (value === null || value === undefined) return '--'
406
+    return Number(value).toFixed(decimals)
407
+  },
408
+  
409
+  // 获取坐标系标签类型
410
+  getCoordinateType(system) {
411
+    const types = {
412
+      'WGS84': 'primary',
413
+      'CGCS2000': 'success',
414
+      'Beijing54': 'warning',
415
+      'Xian80': 'info'
416
+    }
417
+    return types[system] || 'info'
418
+  }
419
+  }
420
+}
421
+</script>
422
+
423
+<style scoped>
424
+.utm-positive-tool {
425
+  width: 100%;
426
+}
427
+
428
+.tool-header {
429
+  margin-bottom: 20px;
430
+}
431
+
432
+.card-header-buttons {
433
+  display: flex;
434
+  gap: 10px;
435
+  flex-wrap: wrap;
436
+}
437
+
438
+/* 投影面高程设置样式 */
439
+.height-setting {
440
+  background: #f5f7fa;
441
+  border-radius: 8px;
442
+  padding: 12px 20px;
443
+  margin-bottom: 20px;
444
+  border: 1px solid #e4e7ed;
445
+  display: flex;
446
+  align-items: center;
447
+  gap: 20px;
448
+  flex-wrap: wrap;
449
+}
450
+
451
+.result-section {
452
+  margin-top: 10px;
453
+}
454
+
455
+.section-header {
456
+  padding: 12px 16px;
457
+  background: #f5f7fa;
458
+  border-radius: 8px 8px 0 0;
459
+  border: 1px solid #e4e7ed;
460
+  border-bottom: none;
461
+  display: flex;
462
+  justify-content: space-between;
463
+  align-items: center;
464
+}
465
+
466
+.section-title {
467
+  font-size: 14px;
468
+  font-weight: bold;
469
+  color: #303133;
470
+}
471
+
472
+.section-title i {
473
+  margin-right: 8px;
474
+  color: #11a983;
475
+}
476
+
477
+.section-info {
478
+  font-size: 12px;
479
+  color: #909399;
480
+}
481
+
482
+.result-value {
483
+  color: #409eff;
484
+  font-family: monospace;
485
+  font-weight: 500;
486
+}
487
+
488
+.empty-state {
489
+  text-align: center;
490
+  padding: 60px 20px;
491
+  background: #fff;
492
+  border-radius: 8px;
493
+  border: 1px solid #e4e7ed;
494
+  color: #909399;
495
+}
496
+
497
+.empty-state i {
498
+  font-size: 64px;
499
+  margin-bottom: 16px;
500
+}
501
+
502
+.empty-tip {
503
+  font-size: 12px;
504
+  margin-top: 12px;
505
+  color: #c0c4cc;
506
+}
507
+
508
+.import-tips {
509
+  margin-bottom: 20px;
510
+}
511
+
512
+.template-info {
513
+  margin-top: 12px;
514
+}
515
+
516
+.template-info ul {
517
+  margin: 8px 0;
518
+  padding-left: 20px;
519
+}
520
+
521
+.template-info li {
522
+  margin: 4px 0;
523
+  font-size: 13px;
524
+}
525
+
526
+.upload-area {
527
+  margin-top: 10px;
528
+}
529
+
530
+.preview-info {
531
+  margin-bottom: 15px;
532
+  padding: 10px;
533
+  background: #f5f7fa;
534
+  border-radius: 4px;
535
+  font-size: 14px;
536
+  color: #606266;
537
+}
538
+
539
+.dialog-footer {
540
+  width: 100%;
541
+  display: flex;
542
+  justify-content: flex-end;
543
+  gap: 10px;
544
+}
545
+
546
+.template-download-wrapper {
547
+  margin-top: 12px;
548
+  display: flex;
549
+  align-items: center;
550
+  justify-content: flex-end;
551
+  gap: 10px;
552
+  padding-top: 12px;
553
+  border-top: 1px dashed #e4e7ed;
554
+}
555
+</style>

Loading…
Peruuta
Tallenna