Просмотр исходного кода

修改高斯正算工具,新增高斯反算工具

qyx 3 недель назад
Родитель
Сommit
a96b205a44

+ 123
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/controller/CmcGaussNegativeController.java Просмотреть файл

@@ -0,0 +1,123 @@
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.CmcGaussNegative;
21
+import com.ruoyi.web.calculate.service.ICmcGaussNegativeService;
22
+import com.ruoyi.web.calculate.vo.CmcGaussNegativeTemplate;
23
+
24
+
25
+@RestController
26
+@RequestMapping("/calculate/gaussNegative")
27
+public class CmcGaussNegativeController 
28
+{
29
+    
30
+    @Autowired
31
+    private ICmcGaussNegativeService cmcGaussNegativeService;
32
+
33
+     /**
34
+     * 导入Excel数据
35
+     */
36
+    @PostMapping("/import")
37
+    public AjaxResult importExcel(@RequestParam("file") MultipartFile file)
38
+    {
39
+        try {
40
+            // 检查文件是否为空
41
+            if (file.isEmpty()) {
42
+                return AjaxResult.error("请选择要导入的文件!");
43
+            }
44
+
45
+            // 检查文件格式
46
+            String fileName = file.getOriginalFilename();
47
+            if (fileName == null || (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx"))) {
48
+                return AjaxResult.error("请上传Excel文件(.xls或.xlsx格式)!");
49
+            }
50
+
51
+            // 调用Service层解析Excel并返回数据
52
+            return cmcGaussNegativeService.importExcelData(file);
53
+
54
+        } catch (Exception e) {
55
+            e.printStackTrace();
56
+            return AjaxResult.error("导入失败:" + e.getMessage());
57
+        }
58
+    }
59
+
60
+    /**
61
+     * 导出高斯反算列表
62
+     */
63
+    @Log(title = "高斯反算", businessType = BusinessType.EXPORT)
64
+    @PostMapping("/export")
65
+    public void export(HttpServletResponse response, @RequestBody List<CmcGaussNegative> dataList)
66
+    {
67
+        if (dataList == null || dataList.isEmpty()) {
68
+            throw new RuntimeException("没有需要导出的数据");
69
+        }
70
+        
71
+        List<CmcGaussNegative> exportList = new ArrayList<>();
72
+        for (CmcGaussNegative item : dataList) {
73
+            CmcGaussNegative exportItem = new CmcGaussNegative();
74
+            exportItem.setPointNumber(item.getPointNumber());
75
+            exportItem.setCoordinateSystem(item.getCoordinateSystem());
76
+            exportItem.setLongitude(item.getLongitude());
77
+            exportItem.setLongitudePosition(item.getLongitudePosition());
78
+            exportItem.setLatitude(item.getLatitude());
79
+            exportItem.setLatitudePosition(item.getLatitudePosition());
80
+            exportItem.setZone(item.getZone());
81
+            exportItem.setBandwidth(item.getBandwidth());
82
+            exportItem.setProjectionHeight(item.getProjectionHeight());
83
+            exportItem.setGaussX(item.getGaussX());
84
+            exportItem.setGaussY(item.getGaussY());
85
+            exportList.add(exportItem);
86
+        }
87
+        
88
+        ExcelUtil<CmcGaussNegative> util = new ExcelUtil<CmcGaussNegative>(CmcGaussNegative.class);
89
+        util.exportExcel(response, exportList, "高斯反算结果");
90
+    }
91
+
92
+    /**
93
+     * 执行高斯反算(仅计算,不保存)
94
+     */
95
+    @PostMapping("/calculate")
96
+    public AjaxResult calculate(@RequestBody List<CmcGaussNegative> dataList)
97
+    {
98
+        List<CmcGaussNegative> result = cmcGaussNegativeService.calculateGaussNegative(dataList);
99
+        return AjaxResult.success(result);
100
+    }
101
+
102
+
103
+
104
+    @PostMapping("/template")
105
+    public void downloadTemplate(HttpServletResponse response) {
106
+        List<CmcGaussNegativeTemplate> templateList = new ArrayList<>();
107
+
108
+        // 添加示例数据
109
+        CmcGaussNegativeTemplate example = new CmcGaussNegativeTemplate();
110
+        example.setPointNumber("示例点1");
111
+        example.setCoordinateSystem("WGS84");
112
+        example.setGaussX(3421806.699);
113
+        example.setGaussY(34460881.36);
114
+        example.setLongitudePosition("E");
115
+        example.setLatitudePosition("N");
116
+        templateList.add(example);
117
+
118
+        ExcelUtil<CmcGaussNegativeTemplate> util = new ExcelUtil<CmcGaussNegativeTemplate>(CmcGaussNegativeTemplate.class);
119
+        util.exportExcel(response, templateList, "高斯反算模板");
120
+    }
121
+
122
+
123
+}

+ 229
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcGaussNegative.java Просмотреть файл

@@ -0,0 +1,229 @@
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
+
15
+public class CmcGaussNegative extends BaseEntity {
16
+    private static final long serialVersionUID = 1L;
17
+
18
+    /** 主键ID */
19
+    private Long id;
20
+
21
+    /** 待求点号 */
22
+    @Excel(name = "待求点")
23
+    private String pointNumber;
24
+
25
+    /** 坐标系 */
26
+    @Excel(name = "坐标系")
27
+    private String coordinateSystem;
28
+
29
+    /** 高斯坐标x */
30
+    @Excel(name = "高斯坐标x", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
31
+    private Double gaussX;
32
+
33
+    /** 高斯坐标y */
34
+    @Excel(name = "高斯坐标y", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
35
+    private Double gaussY;
36
+    
37
+    /** 带号 */
38
+    @Excel(name = "带号", cellType = ColumnType.NUMERIC)
39
+    private Integer zone;
40
+
41
+    /** 带宽 */
42
+    @Excel(name = "带宽", cellType = ColumnType.NUMERIC)
43
+    private Integer bandwidth;
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)
63
+    private double projectionHeight;
64
+
65
+
66
+    public void setId(Long id) 
67
+    {
68
+        this.id = id;
69
+    }
70
+
71
+    public Long getId() 
72
+    {
73
+        return id;
74
+    }
75
+    public void setPointNumber(String pointNumber) 
76
+    {
77
+        this.pointNumber = pointNumber;
78
+    }
79
+
80
+    public String getPointNumber() 
81
+    {
82
+        return pointNumber;
83
+    }
84
+    public void setCoordinateSystem(String coordinateSystem) 
85
+    {
86
+        this.coordinateSystem = coordinateSystem;
87
+    }
88
+
89
+    public String getCoordinateSystem() 
90
+    {
91
+        return coordinateSystem;
92
+    }
93
+     public void setLongitude(Double longitude) 
94
+    {
95
+        // 大地经度保留10位小数
96
+        if (longitude != null) {
97
+            BigDecimal bd = new BigDecimal(longitude);
98
+            this.longitude = bd.setScale(10, RoundingMode.HALF_UP).doubleValue();
99
+        } else {
100
+            this.longitude = null;
101
+        }
102
+    }
103
+
104
+    public Double getLongitude() 
105
+    {
106
+        return longitude;
107
+    }
108
+    
109
+    public void setLongitudePosition(String longitudePosition) 
110
+    {
111
+        this.longitudePosition = longitudePosition;
112
+    }
113
+
114
+    public String getLongitudePosition() 
115
+    {
116
+        return longitudePosition;
117
+    }
118
+    
119
+    public void setLatitude(Double latitude) 
120
+    {
121
+        // 大地纬度保留10位小数
122
+        if (latitude != null) {
123
+            BigDecimal bd = new BigDecimal(latitude);
124
+            this.latitude = bd.setScale(10, RoundingMode.HALF_UP).doubleValue();
125
+        } else {
126
+            this.latitude = null;
127
+        }
128
+    }
129
+
130
+    public Double getLatitude() 
131
+    {
132
+        return latitude;
133
+    }
134
+    
135
+    public void setLatitudePosition(String latitudePosition) 
136
+    {
137
+        this.latitudePosition = latitudePosition;
138
+    }
139
+
140
+    public String getLatitudePosition() 
141
+    {
142
+        return latitudePosition;
143
+    }
144
+    
145
+    public void setZone(Integer zone) 
146
+    {
147
+        this.zone = zone;
148
+    }
149
+
150
+    public Integer getZone() 
151
+    {
152
+        return zone;
153
+    }
154
+    
155
+    public void setBandwidth(Integer bandwidth) 
156
+    {
157
+        this.bandwidth = bandwidth;
158
+    }
159
+
160
+    public Integer getBandwidth() 
161
+    {
162
+        return bandwidth;
163
+    }
164
+    
165
+    public void setProjectionHeight(double projectionHeight) 
166
+    {
167
+        this.projectionHeight = projectionHeight;
168
+    }
169
+
170
+    public double getProjectionHeight() 
171
+    {
172
+        return projectionHeight;
173
+    }
174
+    
175
+    public void setGaussX(Double gaussX) 
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
+        }
184
+    }
185
+
186
+    public Double getGaussX() 
187
+    {
188
+        return gaussX;
189
+    }
190
+    
191
+    public void setGaussY(Double gaussY) 
192
+    {
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
+        }
200
+    }
201
+
202
+    public Double getGaussY() 
203
+    {
204
+        return gaussY;
205
+    }
206
+    
207
+
208
+
209
+    @Override
210
+    public String toString() {
211
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
212
+            .append("id", getId())
213
+            .append("pointNumber", getPointNumber())
214
+            .append("coordinateSystem", getCoordinateSystem())
215
+            .append("longitude", getLongitude())
216
+            .append("longitudePosition", getLongitudePosition())
217
+            .append("latitude", getLatitude())
218
+            .append("latitudePosition", getLatitudePosition())
219
+            .append("zone", getZone())
220
+            .append("bandwidth", getBandwidth())
221
+            .append("gaussX", getGaussX())
222
+            .append("gaussY", getGaussY())
223
+            .append("createTime", getCreateTime())
224
+            .append("createBy", getCreateBy())
225
+            .append("updateTime", getUpdateTime())
226
+            .append("updateBy", getUpdateBy())
227
+            .toString();
228
+    }
229
+}

+ 9
- 9
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/domain/CmcGaussPositive.java Просмотреть файл

@@ -12,7 +12,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
12 12
 /**
13 13
  * 高斯正算对象 cmc_gauss_positive
14 14
  * 
15
- * @author ruoyi
15
+ * @author qyx
16 16
  * @date 2026-04-21
17 17
  */
18 18
 public class CmcGaussPositive extends BaseEntity
@@ -31,7 +31,7 @@ public class CmcGaussPositive extends BaseEntity
31 31
     private String coordinateSystem;
32 32
 
33 33
     /** 大地经度 */
34
-    @Excel(name = "大地经度" , cellType = ColumnType.NUMERIC)
34
+    @Excel(name = "大地经度" , cellType = ColumnType.NUMERIC,numberFormat = "0.000000000")
35 35
     private Double longitude;
36 36
 
37 37
     /** 经度位置 */
@@ -39,7 +39,7 @@ public class CmcGaussPositive extends BaseEntity
39 39
     private String longitudePosition;
40 40
 
41 41
     /** 大地纬度 */
42
-    @Excel(name = "大地纬度", cellType = ColumnType.NUMERIC)
42
+    @Excel(name = "大地纬度", cellType = ColumnType.NUMERIC, numberFormat = "0.000000000")
43 43
     private Double latitude;
44 44
 
45 45
     /** 纬度位置 */
@@ -56,18 +56,18 @@ public class CmcGaussPositive extends BaseEntity
56 56
 
57 57
     /** 带宽 */
58 58
     @Excel(name = "投影面高程", cellType = ColumnType.NUMERIC)
59
-    private Integer projectionHeight;
59
+    private double projectionHeight;
60 60
 
61 61
     /** 高斯坐标x */
62
-    @Excel(name = "高斯坐标x", cellType = ColumnType.NUMERIC)
62
+    @Excel(name = "高斯坐标x", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
63 63
     private Double gaussX;
64 64
 
65 65
     /** 高斯坐标y */
66
-    @Excel(name = "高斯坐标y", cellType = ColumnType.NUMERIC)
66
+    @Excel(name = "高斯坐标y", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
67 67
     private Double gaussY;
68 68
 
69 69
     /** 子午线收敛角γ */
70
-    @Excel(name = "子午线收敛角γ", cellType = ColumnType.NUMERIC)
70
+    @Excel(name = "子午线收敛角γ", cellType = ColumnType.NUMERIC, numberFormat = "0.0000000")
71 71
     private Double meridianConvergence;
72 72
 
73 73
     public void setId(Long id) 
@@ -169,12 +169,12 @@ public class CmcGaussPositive extends BaseEntity
169 169
         return bandwidth;
170 170
     }
171 171
     
172
-    public void setProjectionHeight(Integer projectionHeight) 
172
+    public void setProjectionHeight(double projectionHeight) 
173 173
     {
174 174
         this.projectionHeight = projectionHeight;
175 175
     }
176 176
 
177
-    public Integer getProjectionHeight() 
177
+    public double getProjectionHeight() 
178 178
     {
179 179
         return projectionHeight;
180 180
     }

+ 32
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/ICmcGaussNegativeService.java Просмотреть файл

@@ -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.CmcGaussNegative;
9
+
10
+/**
11
+ * 高斯反算服务接口
12
+ * 
13
+ * @author qyx
14
+ * @date 2026-04-21
15
+ */
16
+public interface ICmcGaussNegativeService {
17
+    /**
18
+     * 导入Excel数据
19
+     * 
20
+     * @param file Excel文件
21
+     * @return 导入结果
22
+     */
23
+     public AjaxResult importExcelData(MultipartFile file);
24
+    
25
+    /**
26
+     * 执行高斯反算
27
+     * 
28
+     * @param cmcGaussPositive 高斯反算参数
29
+     * @return 计算结果
30
+     */
31
+    public List<CmcGaussNegative> calculateGaussNegative(List<CmcGaussNegative> dataList);
32
+}

+ 2
- 2
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/ICmcGaussPositiveService.java Просмотреть файл

@@ -10,9 +10,9 @@ import com.ruoyi.common.core.domain.AjaxResult;
10 10
 import com.ruoyi.web.calculate.domain.CmcGaussPositive;
11 11
 
12 12
 /**
13
- * 高斯算服务接口
13
+ * 高斯算服务接口
14 14
  * 
15
- * @author ruoyi
15
+ * @author qyx
16 16
  * @date 2026-04-21
17 17
  */
18 18
 public interface ICmcGaussPositiveService 

+ 321
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcGaussNegativeServiceImpl.java Просмотреть файл

@@ -0,0 +1,321 @@
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.CmcGaussNegative;
21
+import com.ruoyi.web.calculate.service.ICmcGaussNegativeService;
22
+
23
+/**
24
+ * 高斯反算服务实现
25
+ * 
26
+ * @author ruoyi
27
+ * @date 2026-04-21
28
+ */
29
+@Service
30
+public class CmcGaussNegativeServiceImpl implements ICmcGaussNegativeService {
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<CmcGaussNegative> util = new ExcelUtil<CmcGaussNegative>(CmcGaussNegative.class);
58
+            List<CmcGaussNegative> 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
+                CmcGaussNegative 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("longitudePosition", item.getLongitudePosition());
81
+                    rowMap.put("latitudePosition", item.getLatitudePosition());
82
+                    rowMap.put("projectionHeight", item.getProjectionHeight());
83
+                    rowMap.put("rowNum", i + 2); // Excel中的行号
84
+
85
+                    validData.add(rowMap);
86
+                    successCount++;
87
+
88
+                } catch (Exception e) {
89
+                    errorMsg.append(String.format("第%d行数据验证失败:%s;", i + 2, e.getMessage()));
90
+                }
91
+            }
92
+
93
+            // 构建返回结果
94
+            Map<String, Object> result = new HashMap<>();
95
+            result.put("total", dataList.size());
96
+            result.put("validCount", successCount);
97
+            result.put("data", validData);
98
+
99
+            if (successCount == 0) {
100
+                return AjaxResult.error("没有有效数据!" + errorMsg.toString());
101
+            }
102
+
103
+            String message = String.format("导入成功!共解析%d条数据,有效数据%d条", dataList.size(), successCount);
104
+            if (errorMsg.length() > 0) {
105
+                message += ";部分数据验证失败:" + errorMsg.toString();
106
+                return AjaxResult.success(message, result);
107
+            }
108
+
109
+            return AjaxResult.success(message, result);
110
+
111
+        } catch (Exception e) {
112
+            e.printStackTrace();
113
+            return AjaxResult.error("导入失败:" + e.getMessage());
114
+        }
115
+    }
116
+
117
+    /**
118
+     * 执行高斯反算
119
+     */
120
+    @Override
121
+    public List<CmcGaussNegative> calculateGaussNegative(List<CmcGaussNegative> dataList) {
122
+        List<CmcGaussNegative> resultList = new ArrayList<>();
123
+        for (CmcGaussNegative item : dataList) {
124
+            try {
125
+                CmcGaussNegative result = calculateGaussNegativeSingle(item);
126
+                resultList.add(result);
127
+            } catch (Exception e) {
128
+                e.printStackTrace();
129
+                // 计算失败时,返回带有错误信息的对象
130
+                CmcGaussNegative errorResult = new CmcGaussNegative();
131
+                errorResult.setPointNumber(item.getPointNumber());
132
+                errorResult.setLatitude(-1.0);
133
+                errorResult.setLongitude(-1.0);
134
+                resultList.add(errorResult);
135
+            }
136
+        }
137
+
138
+        return resultList;
139
+    }
140
+
141
+    /**
142
+     * 单条高斯正算
143
+     */
144
+    private CmcGaussNegative calculateGaussNegativeSingle(CmcGaussNegative cmcGaussNegative) {
145
+        try {
146
+            initEllipsoidParams(cmcGaussNegative.getCoordinateSystem());
147
+            
148
+            double gaussX = cmcGaussNegative.getGaussX(); // 经度(度)
149
+            double gaussY = cmcGaussNegative.getGaussY(); // 经度(度)
150
+            String longitudePosition = cmcGaussNegative.getLongitudePosition(); // 经度位置(东/西)
151
+            String latitudePosition = cmcGaussNegative.getLatitudePosition(); // 纬度位置(北/南)
152
+            double projectionHeight = cmcGaussNegative.getProjectionHeight(); // 投影面高程
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;
156
+
157
+            double x = latitudePosition.equals("S") ? 10000000 - gaussX : gaussX;
158
+            double y = gaussY > 1.0E+7 ? gaussY - (int) Math.floor(gaussY / 1.0E+6) * 1.0E+6 - 500000 : gaussY - 500000;
159
+
160
+            double bf = calculateBf(x, projectionHeight);
161
+            double tf = Math.tan(bf);
162
+            double ep2 = 1 / Math.pow(1 - F, 2) - 1;
163
+            double etaf2 = ep2 * Math.pow(Math.cos(bf), 2);
164
+            double Vf = Math.sqrt(1 + etaf2);
165
+            double c = (A + projectionHeight) / (1 - F);
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;
180
+            // 最终纬度 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));
196
+
197
+            //大地经度和大地纬度
198
+            double longitude = convertDecimalDegrees(L);
199
+            double latitude = convertDecimalDegrees(B);
200
+
201
+            cmcGaussNegative.setLongitude(longitude);
202
+            cmcGaussNegative.setLatitude(latitude);
203
+            cmcGaussNegative.setZone(zone);
204
+            cmcGaussNegative.setBandwidth(bandwidth);
205
+           
206
+        } catch (Exception e) {
207
+            e.printStackTrace();
208
+        }
209
+        return cmcGaussNegative;
210
+    }
211
+
212
+    // 选择椭球体参数
213
+    private void initEllipsoidParams(String coordinateSystem) {
214
+        String F_str;
215
+        if ("CGCS2000".equalsIgnoreCase(coordinateSystem) || "国家2000".equalsIgnoreCase(coordinateSystem)
216
+                || "2000".equalsIgnoreCase(coordinateSystem)) {
217
+            A = A_CGCS2000;
218
+            F_str = F_CGCS2000;
219
+        } else if ("1954".equalsIgnoreCase(coordinateSystem) || "北京54".equalsIgnoreCase(coordinateSystem)
220
+                || "Beijing54".equalsIgnoreCase(coordinateSystem)
221
+                || "54".equalsIgnoreCase(coordinateSystem)) {
222
+            A = A_BJ54;
223
+            F_str = F_BJ54;
224
+        } else if ("1980".equalsIgnoreCase(coordinateSystem) || "西安80".equalsIgnoreCase(coordinateSystem)
225
+                || "Xian80".equalsIgnoreCase(coordinateSystem)
226
+                || "80".equalsIgnoreCase(coordinateSystem)) {
227
+            A = A_XA80;
228
+            F_str = F_XA80;
229
+        } else {
230
+            A = A_WGS84;
231
+            F_str = F_WGS84;
232
+        }
233
+        BigDecimal one = BigDecimal.ONE;
234
+        BigDecimal divisor = new BigDecimal(F_str);
235
+        BigDecimal db_F = one.divide(divisor, 20, RoundingMode.HALF_UP);
236
+
237
+        // 计算 2 * F
238
+        BigDecimal two = new BigDecimal("2");
239
+        BigDecimal twoF = two.multiply(db_F);
240
+
241
+        // 计算 F * F
242
+        BigDecimal F_squared = db_F.multiply(db_F);
243
+
244
+        // 计算 e2 = 2*F - F*F
245
+        BigDecimal e2 = twoF.subtract(F_squared);
246
+        E2 = e2.doubleValue();
247
+        F = db_F.doubleValue();
248
+    }
249
+
250
+    // 计算bf
251
+    private double calculateBf(double x, double projectionHeight) {
252
+        double e2 = E2;
253
+        double e4 = E2 * E2;
254
+        double e6 = e4 * E2;
255
+        double e8 = e6 * E2;
256
+        double e10 = e8 * E2;
257
+        double d = A + projectionHeight;
258
+        // 计算子午线弧长系数
259
+        double a0 = (d - d * e2) * (1
260
+                + 3.0 / 4.0 * e2
261
+                + 45.0 / 64.0 * e4
262
+                + 175.0 / 256.0 * e6
263
+                + 11025.0 / 16384.0 * e8
264
+                + 43659.0 / 65536.0 * e10);
265
+
266
+        double a2 = (d - d * e2) * (3.0 / 4.0 * e2
267
+                + 45.0 / 64.0 * e4
268
+                + 175.0 / 256.0 * e6
269
+                + 11025.0 / 16384.0 * e8
270
+                + 43659.0 / 65536.0 * e10);
271
+
272
+        double a4 = (d - d * e2) * (15.0 / 32.0 * e4
273
+                + 175.0 / 384.0 * e6
274
+                + 3675.0 / 8192.0 * e8
275
+                + 14553.0 / 32768.0 * e10);
276
+
277
+        double a6 = (d - d * e2) * (35.0 / 96.0 * e6
278
+                + 735.0 / 2048.0 * e8
279
+                + 14553.0 / 40960.0 * e10);
280
+
281
+        double a8 = (d - d * e2) * (315.0 / 1024.0 * e8
282
+                + 6237.0 / 20480.0 * e10);
283
+
284
+        double b = x / a0;
285
+        double sinB = Math.sin(b);
286
+        double cosB = Math.cos(b);
287
+        double f = -(a2 * sinB + a4 * Math.pow(sinB, 3) + a6 * Math.pow(sinB, 5) + a8 * Math.pow(sinB, 7)) * cosB;
288
+
289
+        for (int i = 0; i < 9; i++) {
290
+            b = (x - f) / a0;
291
+            sinB = Math.sin(b);
292
+            cosB = Math.cos(b);
293
+            f = -(a2 * sinB + a4 * Math.pow(sinB, 3) + a6 * Math.pow(sinB, 5) + a8 * Math.pow(sinB, 7)) * cosB;
294
+            i++;
295
+        }
296
+        return b;
297
+    }
298
+
299
+    /**
300
+     * 将十进制度数数值转换为度分秒格式(
301
+     * 
302
+     * @param decimalDegrees 十进制度数数值
303
+     * @return 转换后的值
304
+     */
305
+    private static double convertDecimalDegrees(double decimalDegrees) {
306
+
307
+        final double PRECISION = 1.2e-12; // 修正值
308
+        final double SEC_PRECISION = 1e-11; // 秒的修正值
309
+
310
+        // 提取度
311
+        double degrees = Math.floor(decimalDegrees + PRECISION);
312
+        // 提取分
313
+        double minutesRaw = 60 * (decimalDegrees - degrees);
314
+        double minutes = Math.floor(minutesRaw + PRECISION) / 100;
315
+        // 提取秒(高精度)
316
+        double secondsRaw = (decimalDegrees * 60 - Math.floor(decimalDegrees * 60 + PRECISION)) * 60;
317
+        double seconds = Math.floor((secondsRaw + SEC_PRECISION) * 1000000) / 10000000000.0;
318
+        
319
+        return degrees + minutes + seconds;
320
+    }
321
+}

+ 24
- 24
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/service/impl/CmcGaussPositiveServiceImpl.java Просмотреть файл

@@ -30,19 +30,18 @@ import com.ruoyi.web.calculate.service.ICmcGaussPositiveService;
30 30
 public class CmcGaussPositiveServiceImpl implements ICmcGaussPositiveService 
31 31
 {
32 32
     @Autowired
33
-    // private CmcGaussPositiveMapper cmcGaussPositiveMapper;
34
-
33
+    //扁率直接计算精度不够,在后面的椭球参数选择中用BigDecimal计算,下面的F是分母
35 34
     private static final double A_WGS84 = 6378137.0;
36
-    private static final double F_WGS84 = 1 / 298.257223563;
35
+    private static final String F_WGS84 = "298.257223563";
37 36
 
38 37
     private static final double A_CGCS2000 = 6378137.0;
39
-    private static final double F_CGCS2000 = 1 / 298.257222101;
38
+    private static final String F_CGCS2000 = "298.257222101";
40 39
 
41 40
     private static final double A_BJ54 = 6378245.0;
42
-    private static final double F_BJ54 = 1 / 298.3;
41
+    private static final String F_BJ54 = "298.3";
43 42
 
44 43
     private static final double A_XA80 = 6378140.0;
45
-    private static final double F_XA80 = 1 / 298.257;
44
+    private static final String F_XA80 = "298.257";
46 45
 
47 46
     private static double A;
48 47
     private static double F;
@@ -160,7 +159,7 @@ public class CmcGaussPositiveServiceImpl implements ICmcGaussPositiveService
160 159
             double latitude = cmcGaussPositive.getLatitude(); // 纬度(度)
161 160
             Integer zone = cmcGaussPositive.getZone(); // 带号
162 161
             int bandwidth = cmcGaussPositive.getBandwidth(); // 带宽
163
-            int projectionHeight = cmcGaussPositive.getProjectionHeight(); // 投影面高程
162
+            double projectionHeight = cmcGaussPositive.getProjectionHeight(); // 投影面高程
164 163
 
165 164
             // 计算中央经线
166 165
             double centralMeridian;
@@ -188,7 +187,6 @@ public class CmcGaussPositiveServiceImpl implements ICmcGaussPositiveService
188 187
             double N = (A + projectionHeight) / ((1 - F) * Math.sqrt(1 + eta2));
189 188
             // 计算子午线弧长
190 189
             double X = calculateMeridianArc(B, projectionHeight);
191
-
192 190
             // 计算Y坐标的系数
193 191
             double t = Math.tan(B);
194 192
             double t2 = t * t;
@@ -219,8 +217,7 @@ public class CmcGaussPositiveServiceImpl implements ICmcGaussPositiveService
219 217
             }
220 218
             // 加入东偏
221 219
             y = 500000 + y;
222
-            System.out.println("x = " + x + ", y = " + y+", meridianConvergence = "+meridianConvergence);
223
-            // 设置计算结果
220
+            
224 221
             cmcGaussPositive.setGaussX(x);
225 222
             cmcGaussPositive.setGaussY(y);
226 223
             cmcGaussPositive.setMeridianConvergence(meridianConvergence);
@@ -232,21 +229,24 @@ public class CmcGaussPositiveServiceImpl implements ICmcGaussPositiveService
232 229
     
233 230
     //选择椭球体参数
234 231
     private void initEllipsoidParams(String coordinateSystem) {
235
-        if ("CGCS2000".equalsIgnoreCase(coordinateSystem) || "国家2000".equalsIgnoreCase(coordinateSystem)) {
232
+        String F_str;
233
+        if ("CGCS2000".equalsIgnoreCase(coordinateSystem) || "国家2000".equalsIgnoreCase(coordinateSystem) || "2000".equalsIgnoreCase(coordinateSystem)) {
236 234
             A = A_CGCS2000;
237
-            F = F_CGCS2000;
238
-        } else if ("1954".equalsIgnoreCase(coordinateSystem) || "北京54".equalsIgnoreCase(coordinateSystem) || "Beijing54".equalsIgnoreCase(coordinateSystem)) {
235
+            F_str = F_CGCS2000;
236
+        } else if ("1954".equalsIgnoreCase(coordinateSystem) || "北京54".equalsIgnoreCase(coordinateSystem) || "Beijing54".equalsIgnoreCase(coordinateSystem)
237
+                || "54".equalsIgnoreCase(coordinateSystem)) {
239 238
             A = A_BJ54;
240
-            F = F_BJ54;
241
-        } else if ("1980".equalsIgnoreCase(coordinateSystem) || "西安80".equalsIgnoreCase(coordinateSystem) || "Xian80".equalsIgnoreCase(coordinateSystem)) {
239
+            F_str = F_BJ54;
240
+        } else if ("1980".equalsIgnoreCase(coordinateSystem) || "西安80".equalsIgnoreCase(coordinateSystem) || "Xian80".equalsIgnoreCase(coordinateSystem)
241
+                || "80".equalsIgnoreCase(coordinateSystem)) {
242 242
             A = A_XA80;
243
-            F = F_XA80;
243
+            F_str = F_XA80;
244 244
         } else {
245 245
             A = A_WGS84;
246
-            F = F_WGS84;
246
+            F_str = F_WGS84;
247 247
         }
248 248
         BigDecimal one = BigDecimal.ONE;
249
-        BigDecimal divisor = new BigDecimal("298.257222101");
249
+        BigDecimal divisor = new BigDecimal(F_str);
250 250
         BigDecimal db_F = one.divide(divisor, 20, RoundingMode.HALF_UP);
251 251
 
252 252
         // 计算 2 * F
@@ -316,13 +316,13 @@ public class CmcGaussPositiveServiceImpl implements ICmcGaussPositiveService
316 316
      */
317 317
     public static double convertDecimalDegrees(double decimalDegrees) {
318 318
         // 度的整数部分
319
-        double degrees = Math.floor(decimalDegrees);
319
+        double degrees = Math.floor(decimalDegrees + 1.0E-12);
320 320
 
321 321
         // 分的计算
322
-        double minutes = Math.floor(100 * (decimalDegrees - degrees)) / 60;
322
+        double minutes = Math.floor(100 * (decimalDegrees - degrees) + 1.0E-12) / 60;
323 323
 
324 324
         // 秒的计算
325
-        double seconds = (decimalDegrees * 100 - Math.floor(decimalDegrees * 100)) / 36;
325
+        double seconds = (decimalDegrees * 100 - Math.floor(decimalDegrees * 100 + 1.0E-12)) / 36;
326 326
 
327 327
         return degrees + minutes + seconds;
328 328
     }
@@ -334,14 +334,14 @@ public class CmcGaussPositiveServiceImpl implements ICmcGaussPositiveService
334 334
      */
335 335
     public static double decimalToDMS(double decimalDegrees) {
336 336
         // 1. 提取度
337
-        double degrees = Math.floor(decimalDegrees );
337
+        double degrees = Math.floor(decimalDegrees + 1.0E-12);
338 338
 
339 339
         // 2. 提取分
340 340
         double minutesRaw = 60 * (decimalDegrees - degrees);
341
-        double minutes = Math.floor(minutesRaw) / 100;
341
+        double minutes = Math.floor(minutesRaw + 1.0E-12) / 100;
342 342
 
343 343
         // 3. 提取秒
344
-        double secondsRaw = 60 * (60 * decimalDegrees - Math.floor(60 * decimalDegrees ));
344
+        double secondsRaw = 60 * (60 * decimalDegrees - Math.floor(60 * decimalDegrees + 1.0E-12))+ 1.0E-12;
345 345
         double seconds = secondsRaw / 10000;
346 346
 
347 347
         return degrees + minutes + seconds;

+ 75
- 0
oa-back/ruoyi-calculate/src/main/java/com/ruoyi/web/calculate/vo/CmcGaussNegativeTemplate.java Просмотреть файл

@@ -0,0 +1,75 @@
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
+
8
+public class CmcGaussNegativeTemplate {
9
+
10
+    @Excel(name = "待求点")
11
+    private String pointNumber;
12
+
13
+    @Excel(name = "坐标系")
14
+    private String coordinateSystem;
15
+
16
+    @Excel(name = "高斯坐标x")
17
+    private Double gaussX;
18
+
19
+    @Excel(name = "高斯坐标y")
20
+    private Double gaussY;
21
+
22
+    @Excel(name = "经度位置")
23
+    private String longitudePosition;
24
+
25
+    @Excel(name = "纬度位置")
26
+    private String latitudePosition;
27
+
28
+    public void setPointNumber(String pointNumber) {
29
+        this.pointNumber = pointNumber;
30
+    }
31
+
32
+    public String getPointNumber() {
33
+        return pointNumber;
34
+    }
35
+
36
+    public void setCoordinateSystem(String coordinateSystem) {
37
+        this.coordinateSystem = coordinateSystem;
38
+    }
39
+
40
+    public String getCoordinateSystem() {
41
+        return coordinateSystem;
42
+    }
43
+
44
+    public void setGaussX(Double gaussX) {
45
+        this.gaussX = gaussX;
46
+    }
47
+
48
+    public Double getGaussX() {
49
+        return gaussX;
50
+    }
51
+
52
+    public void setGaussY(Double gaussY) {
53
+        this.gaussY = gaussY;
54
+    }
55
+
56
+    public Double getGaussY() {
57
+        return gaussY;
58
+    }
59
+    public void setLongitudePosition(String longitudePosition) {
60
+        this.longitudePosition = longitudePosition;
61
+    }
62
+
63
+    public String getLongitudePosition() {
64
+        return longitudePosition;
65
+    }
66
+
67
+    public void setLatitudePosition(String latitudePosition) {
68
+        this.latitudePosition = latitudePosition;
69
+    }
70
+
71
+    public String getLatitudePosition() {
72
+        return latitudePosition;
73
+    }
74
+
75
+}

+ 5
- 0
oa-back/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java Просмотреть файл

@@ -153,6 +153,11 @@ public @interface Excel
153 153
      */
154 154
     Type type() default Type.ALL;
155 155
 
156
+    /**
157
+     * 数字格式化, 如: 0.0000
158
+     */
159
+    public String numberFormat() default "";
160
+
156 161
     public enum Type
157 162
     {
158 163
         ALL(0), EXPORT(1), IMPORT(2);

+ 24
- 4
oa-back/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java Просмотреть файл

@@ -66,6 +66,7 @@ import org.apache.poi.xssf.usermodel.XSSFPicture;
66 66
 import org.apache.poi.xssf.usermodel.XSSFShape;
67 67
 import org.apache.poi.xssf.usermodel.XSSFSheet;
68 68
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
69
+import org.apache.poi.ss.usermodel.DataFormat;
69 70
 import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
70 71
 import org.slf4j.Logger;
71 72
 import org.slf4j.LoggerFactory;
@@ -203,6 +204,11 @@ public class ExcelUtil<T>
203 204
         this.clazz = clazz;
204 205
     }
205 206
 
207
+    /**
208
+     * 缓存Excel样式
209
+     */
210
+    private Map<String, CellStyle> styleCache = new HashMap<>();
211
+
206 212
     /**
207 213
      * 隐藏Excel中列属性
208 214
      *
@@ -956,11 +962,25 @@ public class ExcelUtil<T>
956 962
         }
957 963
         else if (ColumnType.NUMERIC == attr.cellType())
958 964
         {
959
-            if (StringUtils.isNotNull(value))
960
-            {
961
-                cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value));
965
+            if (StringUtils.isNotNull(value)) {
966
+                String formatKey = attr.numberFormat();
967
+                CellStyle numberCellStyle = styleCache.get(formatKey);
968
+                if (numberCellStyle == null) {
969
+                    numberCellStyle = this.wb.createCellStyle();
970
+                    numberCellStyle.cloneStyleFrom(cell.getCellStyle());
971
+                    DataFormat dataFormat = this.wb.createDataFormat();
972
+                    numberCellStyle.setDataFormat(dataFormat.getFormat(formatKey));
973
+                    styleCache.put(formatKey, numberCellStyle);
974
+                }
975
+                cell.setCellStyle(numberCellStyle);
962 976
             }
963
-        }
977
+            if (value != null) {
978
+                cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value)
979
+                        : Convert.toInt(value));
980
+            } else {
981
+                cell.setCellValue(0); // 空指针则填写0
982
+            }
983
+        } 
964 984
         else if (ColumnType.IMAGE == attr.cellType())
965 985
         {
966 986
             ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1);

+ 42
- 0
oa-ui/src/api/calculate/gaussnegative.js Просмотреть файл

@@ -0,0 +1,42 @@
1
+import request from '@/utils/request'
2
+
3
+
4
+// 执行高斯正算
5
+export function calculate(data) {
6
+    return request({
7
+        url: `/calculate/gaussNegative/calculate`,
8
+        method: 'post',
9
+        data: data
10
+    })
11
+}
12
+
13
+// 导入Excel
14
+export function importExcel(data) {
15
+    return request({
16
+        url: `/calculate/gaussNegative/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/gaussNegative/export`,
29
+        method: 'post',
30
+        data: data,
31
+        responseType: 'blob'
32
+    })
33
+}
34
+
35
+// 下载模板
36
+export function downloadTemplate() {
37
+    return request({
38
+        url: '/calculate/gaussNegative/template',
39
+        method: 'get',
40
+        responseType: 'blob'
41
+    })
42
+}

+ 7
- 0
oa-ui/src/views/calculate/index.vue Просмотреть файл

@@ -35,11 +35,13 @@
35 35
 <script>
36 36
 // 导入各个工具组件
37 37
 import GaussPositiveTool from './tools/gausspositive.vue'
38
+import GaussNegativeTool from './tools/gaussnegative.vue'
38 39
 
39 40
 export default {
40 41
   name: 'CalculationTools',
41 42
   components: {
42 43
     GaussPositiveTool,
44
+    GaussNegativeTool,
43 45
   },
44 46
   data() {
45 47
     return {
@@ -66,6 +68,11 @@ export default {
66 68
               id: 'gauss-positive',
67 69
               name: '高斯正算工具',
68 70
               component: 'GaussPositiveTool'
71
+            },
72
+            {
73
+              id: 'gauss-negative',
74
+              name: '高斯反算工具',
75
+              component: 'GaussNegativeTool'
69 76
             }
70 77
           ]
71 78
         },

+ 558
- 0
oa-ui/src/views/calculate/tools/gaussnegative.vue Просмотреть файл

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

+ 13
- 3
oa-ui/src/views/calculate/tools/gausspositive.vue Просмотреть файл

@@ -212,19 +212,29 @@ export default {
212 212
       importFile: null,
213 213
       calculating: false,
214 214
       previewDialogVisible: false,
215
-      projectionHeight: 0
215
+      projectionHeight: 0,
216
+      heightTimer: null,
216 217
     }
217 218
   },
218 219
   watch: {
219 220
     // 当投影面高程改变时,重新计算(如果已有数据)
220 221
     projectionHeight(newVal, oldVal) {
222
+       // 清除之前的定时器
223
+      if (this.heightTimer) {
224
+        clearTimeout(this.heightTimer)
225
+      }
226
+      
227
+      // 只有已有数据时才触发计算
221 228
       if (this.importedData.length > 0 && this.calculationResults.length > 0) {
222
-        this.handleCalculate()
229
+        // 设置新的定时器,500ms 后执行
230
+        this.heightTimer = setTimeout(() => {
231
+          this.handleCalculate()
232
+        }, 500)
223 233
       }
224 234
     }
225 235
   },
226 236
   methods: {
227
-    // 打开导入对话框
237
+    // 打开导入对话框 
228 238
     handleImport() {
229 239
       this.importDialogVisible = true
230 240
     },

Загрузка…
Отмена
Сохранить