rmy 1 неделю назад
Родитель
Сommit
f8ad87329a

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

@@ -0,0 +1,142 @@
1
+package com.ruoyi.web.calculate.controller;
2
+
3
+import java.util.ArrayList;
4
+import java.util.List;
5
+import java.util.Map;
6
+
7
+import javax.servlet.http.HttpServletResponse;
8
+
9
+import org.springframework.beans.factory.annotation.Autowired;
10
+import org.springframework.web.bind.annotation.PostMapping;
11
+import org.springframework.web.bind.annotation.RequestBody;
12
+import org.springframework.web.bind.annotation.RequestMapping;
13
+import org.springframework.web.bind.annotation.RequestParam;
14
+import org.springframework.web.bind.annotation.RestController;
15
+import org.springframework.web.multipart.MultipartFile;
16
+
17
+import com.ruoyi.common.annotation.Log;
18
+import com.ruoyi.common.core.domain.AjaxResult;
19
+import com.ruoyi.common.enums.BusinessType;
20
+import com.ruoyi.common.utils.poi.ExcelUtil;
21
+import com.ruoyi.web.calculate.domain.CmcEleDifSideLandDir;
22
+import com.ruoyi.web.calculate.service.ICmcEleDifSideLandDirService;
23
+import com.ruoyi.web.calculate.vo.CmcEleDifSideLandDirTemplate;
24
+
25
+/**
26
+ * 计算请求VO
27
+ */
28
+class CalculateRequest {
29
+    private Map<String, Map<String, Integer>> columnMappings;
30
+    private List<CmcEleDifSideLandDir> data;
31
+    
32
+    public Map<String, Map<String, Integer>> getColumnMappings() {
33
+        return columnMappings;
34
+    }
35
+    
36
+    public void setColumnMappings(Map<String, Map<String, Integer>> columnMappings) {
37
+        this.columnMappings = columnMappings;
38
+    }
39
+    
40
+    public List<CmcEleDifSideLandDir> getData() {
41
+        return data;
42
+    }
43
+    
44
+    public void setData(List<CmcEleDifSideLandDir> data) {
45
+        this.data = data;
46
+    }
47
+}
48
+
49
+/**
50
+ * 高差边长方向值Controller
51
+ * 
52
+ * @author R
53
+ * @date 2026-06-15
54
+ */
55
+@RestController
56
+@RequestMapping("/calculate/eleDifSideLandDir")
57
+public class CmcEleDifSideLandDirController {
58
+
59
+    @Autowired
60
+    private ICmcEleDifSideLandDirService cmcEleDifSideLandDirService;
61
+
62
+    /**
63
+     * 导入Excel数据(支持多个工作表)
64
+     * 
65
+     * @param file Excel文件
66
+     * @param sheetNames 工作表名称列表(可选,为空时读取所有工作表)
67
+     * @param columnMappings 列映射配置(可选)
68
+     */
69
+    @PostMapping("/import")
70
+    public AjaxResult importExcel(@RequestParam("file") MultipartFile file,
71
+            @RequestParam(value = "sheetNames", required = false) List<String> sheetNames,
72
+            @RequestParam(value = "columnMappings", required = false) String columnMappings) {
73
+        try {
74
+            // 检查文件是否为空
75
+            if (file.isEmpty()) {
76
+                return AjaxResult.error("请选择要导入的文件!");
77
+            }
78
+
79
+            // 检查文件格式
80
+            String fileName = file.getOriginalFilename();
81
+            if (fileName == null || (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx"))) {
82
+                return AjaxResult.error("请上传Excel文件(.xls或.xlsx格式)!");
83
+            }
84
+
85
+            // 调用Service层解析Excel并返回数据
86
+            return cmcEleDifSideLandDirService.importExcelData(file, sheetNames, columnMappings);
87
+
88
+        } catch (Exception e) {
89
+            e.printStackTrace();
90
+            return AjaxResult.error("导入失败:" + e.getMessage());
91
+        }
92
+    }
93
+
94
+    /**
95
+     * 导出高差边长方向值计算结果列表
96
+     */
97
+    @Log(title = "高差边长方向值", businessType = BusinessType.EXPORT)
98
+    @PostMapping("/export")
99
+    public void export(HttpServletResponse response, @RequestBody List<CmcEleDifSideLandDir> dataList) {
100
+        if (dataList == null || dataList.isEmpty()) {
101
+            throw new RuntimeException("没有需要导出的数据");
102
+        }
103
+
104
+        List<CmcEleDifSideLandDir> exportList = new ArrayList<>();
105
+        for (CmcEleDifSideLandDir item : dataList) {
106
+            CmcEleDifSideLandDir exportItem = new CmcEleDifSideLandDir();
107
+            // 测站序号
108
+            exportItem.setStationPN(item.getStationPN());
109
+            // 方向序号
110
+            exportItem.setDirectionPN(item.getDirectionPN());
111
+            // 测站坐标
112
+            exportItem.setSPX(item.getSPX());
113
+            exportItem.setSPY(item.getSPY());
114
+            exportItem.setSPZ(item.getSPZ());
115
+            // 方向坐标
116
+            exportItem.setDPX(item.getDPX());
117
+            exportItem.setDPY(item.getDPY());
118
+            exportItem.setDPZ(item.getDPZ());
119
+            // 方位角
120
+            exportItem.setAzimuthAngle(item.getAzimuthAngle());
121
+            exportList.add(exportItem);
122
+        }
123
+
124
+        ExcelUtil<CmcEleDifSideLandDir> util = new ExcelUtil<CmcEleDifSideLandDir>(CmcEleDifSideLandDir.class);
125
+        util.exportExcel(response, exportList, "高差边长方向值计算结果");
126
+    }
127
+
128
+    /**
129
+     * 执行高差边长方向值计算(仅计算,不保存)
130
+     */
131
+    @PostMapping("/calculate")
132
+    public AjaxResult calculate(@RequestBody CalculateRequest request) {
133
+        List<CmcEleDifSideLandDir> dataList = request.getData();
134
+        Map<String, Map<String, Integer>> columnMappings = request.getColumnMappings();
135
+        
136
+        // 第一步:匹配测站和方向坐标
137
+        List<CmcEleDifSideLandDir> matchedList = cmcEleDifSideLandDirService.calculateEleDifSideLandDir(dataList, columnMappings);
138
+        // 第二步:计算方位角和角度差
139
+        List<CmcEleDifSideLandDir> result = cmcEleDifSideLandDirService.calculateAzimuthAngle(matchedList);
140
+        return AjaxResult.success(result);
141
+    }
142
+}

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

@@ -0,0 +1,298 @@
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 CmcEleDifSideLandDir extends BaseEntity {
15
+    private static final long serialVersionUID = 1L;
16
+
17
+    /** 主键ID */
18
+    private Long id;
19
+
20
+    /** 待求点号 */
21
+    private String pointNumber;
22
+
23
+    /** 坐标系 */
24
+    private String pointName;
25
+
26
+    /** 控制网点坐标x */
27
+    private Double cpX;
28
+
29
+    /** 控制网点坐标y */
30
+    private Double cpY;
31
+
32
+    /** 控制网点坐标z */
33
+    private Double cpZ;
34
+
35
+    /** 测站序号 */
36
+    @Excel(name = "测站序号", cellType = ColumnType.NUMERIC)
37
+    private Integer stationPN;
38
+
39
+    /** 方向序号 */
40
+    @Excel(name = "方向序号", cellType = ColumnType.NUMERIC)
41
+    private Integer directionPN;
42
+
43
+    /** 测站坐标x */
44
+    @Excel(name = "测站坐标x", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
45
+    private Double spX;
46
+
47
+    /** 测站坐标y */
48
+    @Excel(name = "测站坐标y", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
49
+    private Double spY;
50
+
51
+    /** 测站坐标z */
52
+    @Excel(name = "测站坐标z", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
53
+    private Double spZ;
54
+
55
+    /** 方向坐标x */
56
+    @Excel(name = "方向坐标x", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
57
+    private Double dpX;
58
+
59
+    /** 方向坐标y */
60
+    @Excel(name = "方向坐标y", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
61
+    private Double dpY;
62
+
63
+    /** 方向坐标z */
64
+    @Excel(name = "方向坐标z", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
65
+    private Double dpZ;
66
+
67
+    /** 测站点名 */
68
+    @Excel(name = "测站点名")
69
+    private String stationPointName;
70
+
71
+    /** 方向点名 */
72
+    @Excel(name = "方向点名")
73
+    private String directionPointName;
74
+
75
+    /** 高差 */
76
+    @Excel(name = "高差", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
77
+    private Double heightDiff;
78
+
79
+    /** 边长 */
80
+    @Excel(name = "边长", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
81
+    private Double edgeLength;
82
+
83
+    /** 方位角 */
84
+    @Excel(name = "方位角", cellType = ColumnType.NUMERIC)
85
+    private double azimuthAngle;
86
+
87
+    /** 天顶距 */
88
+    @Excel(name = "天顶距", cellType = ColumnType.NUMERIC)
89
+    private double topDistance;
90
+
91
+    /** 原始方位角(未复用前计算的值) */
92
+    @Excel(name = "原始方位角", cellType = ColumnType.NUMERIC)
93
+    private double originalAzimuthAngle;
94
+
95
+    /** 角度差(原始方位角 - 复用后的方位角) */
96
+    @Excel(name = "角度差", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
97
+    private Double angleDifference;
98
+
99
+    public void setId(Long id) {
100
+        this.id = id;
101
+    }
102
+
103
+    public Long getId() {
104
+        return id;
105
+    }
106
+
107
+    public void setPointNumber(String pointNumber) {
108
+        this.pointNumber = pointNumber;
109
+    }
110
+
111
+    public String getPointNumber() {
112
+        return pointNumber;
113
+    }
114
+
115
+    public void setPointName(String pointName) {
116
+        this.pointName = pointName;
117
+    }
118
+
119
+    public String getPointName() {
120
+        return pointName;
121
+    }
122
+
123
+    public void setCPX(Double cpX) {
124
+        this.cpX = cpX;
125
+    }
126
+
127
+    public Double getCPX() {
128
+        return cpX;
129
+    }
130
+
131
+    public void setCPY(Double cpY) {
132
+        this.cpY = cpY;
133
+    }
134
+
135
+    public Double getCPY() {
136
+        return cpY;
137
+    }
138
+
139
+    public void setCPZ(Double cpZ) {
140
+        this.cpZ = cpZ;
141
+    }
142
+
143
+    public Double getCPZ() {
144
+        return cpZ;
145
+    }
146
+
147
+    public void setStationPN(Integer stationPN) {
148
+        this.stationPN = stationPN;
149
+    }
150
+
151
+    public Integer getStationPN() {
152
+        return stationPN;
153
+    }
154
+
155
+    public void setDirectionPN(Integer directionPN) {
156
+        this.directionPN = directionPN;
157
+    }
158
+
159
+    public Integer getDirectionPN() {
160
+        return directionPN;
161
+    }
162
+
163
+    public void setSPX(Double spX) {
164
+        this.spX = spX;
165
+    }
166
+
167
+    public Double getSPX() {
168
+        return spX;
169
+    }
170
+
171
+    public void setSPY(Double spY) {
172
+        this.spY = spY;
173
+    }
174
+
175
+    public Double getSPY() {
176
+        return spY;
177
+    }
178
+
179
+    public void setSPZ(Double spZ) {
180
+        this.spZ = spZ;
181
+    }
182
+
183
+    public Double getSPZ() {
184
+        return spZ;
185
+    }
186
+
187
+    public void setDPX(Double dpX) {
188
+        this.dpX = dpX;
189
+    }
190
+
191
+    public Double getDPX() {
192
+        return dpX;
193
+    }
194
+
195
+    public void setDPY(Double dpY) {
196
+        this.dpY = dpY;
197
+    }
198
+
199
+    public Double getDPY() {
200
+        return dpY;
201
+    }
202
+
203
+    public void setDPZ(Double dpZ) {
204
+        this.dpZ = dpZ;
205
+    }
206
+
207
+    public Double getDPZ() {
208
+        return dpZ;
209
+    }
210
+
211
+    public void setStationPointName(String stationPointName) {
212
+        this.stationPointName = stationPointName;
213
+    }
214
+
215
+    public String getStationPointName() {
216
+        return stationPointName;
217
+    }
218
+
219
+    public void setDirectionPointName(String directionPointName) {
220
+        this.directionPointName = directionPointName;
221
+    }
222
+
223
+    public String getDirectionPointName() {
224
+        return directionPointName;
225
+    }
226
+
227
+    public void setHeightDiff(Double heightDiff) {
228
+        this.heightDiff = heightDiff;
229
+    }
230
+
231
+    public Double getHeightDiff() {
232
+        return heightDiff;
233
+    }
234
+
235
+    public void setEdgeLength(Double edgeLength) {
236
+        this.edgeLength = edgeLength;
237
+    }
238
+
239
+    public Double getEdgeLength() {
240
+        return edgeLength;
241
+    }
242
+
243
+    public void setAzimuthAngle(double azimuthAngle) {
244
+        this.azimuthAngle = azimuthAngle;
245
+    }
246
+
247
+    public double getAzimuthAngle() {
248
+        return azimuthAngle;
249
+    }
250
+
251
+    public void setTopDistance(double topDistance) {
252
+        this.topDistance = topDistance;
253
+    }
254
+
255
+    public double getTopDistance() {
256
+        return topDistance;
257
+    }
258
+
259
+    public void setOriginalAzimuthAngle(double originalAzimuthAngle) {
260
+        this.originalAzimuthAngle = originalAzimuthAngle;
261
+    }
262
+
263
+    public double getOriginalAzimuthAngle() {
264
+        return originalAzimuthAngle;
265
+    }
266
+
267
+    public void setAngleDifference(Double angleDifference) {
268
+        this.angleDifference = angleDifference;
269
+    }
270
+
271
+    public Double getAngleDifference() {
272
+        return angleDifference;
273
+    }
274
+    @Override
275
+    public String toString() {
276
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
277
+                .append("id", getId())
278
+                .append("pointNumber", getPointNumber())
279
+                .append("pointName", getPointName())
280
+                .append("cpX", getCPX())
281
+                .append("cpY", getCPY())
282
+                .append("cpZ", getCPZ())
283
+                .append("stationPN", getStationPN())
284
+                .append("directionPN", getDirectionPN())
285
+                .append("spX", getSPX())
286
+                .append("spY", getSPY())
287
+                .append("spZ", getSPZ())
288
+                .append("dpX", getDPX())
289
+                .append("dpY", getDPY())
290
+                .append("dpZ", getDPZ())
291
+                .append("heightDiff", getHeightDiff())
292
+                .append("edgeLength", getEdgeLength())
293
+                .append("azimuthAngle", getAzimuthAngle())
294
+                .append("topDistance", getTopDistance())
295
+                .toString();
296
+    }
297
+}
298
+

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

@@ -0,0 +1,69 @@
1
+package com.ruoyi.web.calculate.service;
2
+
3
+import java.util.List;
4
+import java.util.Map;
5
+
6
+import org.springframework.web.multipart.MultipartFile;
7
+
8
+import com.ruoyi.common.core.domain.AjaxResult;
9
+import com.ruoyi.web.calculate.domain.CmcEleDifSideLandDir;
10
+
11
+/**
12
+ * 高差边长方向值接口
13
+ * 
14
+ * @author R
15
+ * @date 2026-06-12
16
+ */
17
+public interface ICmcEleDifSideLandDirService {
18
+    /**
19
+     * 导入Excel数据(支持多个工作表)
20
+     * 
21
+     * @param file Excel文件
22
+     * @param sheetNames 工作表名称列表(可选,为空时读取所有工作表)
23
+     * @return 导入结果
24
+     */
25
+    public AjaxResult importExcelData(MultipartFile file, List<String> sheetNames);
26
+    
27
+    /**
28
+     * 导入Excel数据(支持多个工作表和列映射)
29
+     * 
30
+     * @param file Excel文件
31
+     * @param sheetNames 工作表名称列表(可选,为空时读取所有工作表)
32
+     * @param columnMappings 列映射配置(JSON字符串)
33
+     * @return 导入结果
34
+     */
35
+    public AjaxResult importExcelData(MultipartFile file, List<String> sheetNames, String columnMappings);
36
+
37
+    /**
38
+     * 执行高差边长方向值计算
39
+     * 
40
+     * @param dataList 数据列表
41
+     * @return 计算结果
42
+     */
43
+    public List<CmcEleDifSideLandDir> calculateEleDifSideLandDir(List<CmcEleDifSideLandDir> dataList);
44
+    
45
+    /**
46
+     * 执行高差边长方向值计算(带列映射)
47
+     * 
48
+     * @param dataList 数据列表
49
+     * @param columnMappings 列映射配置
50
+     * @return 计算结果
51
+     */
52
+    public List<CmcEleDifSideLandDir> calculateEleDifSideLandDir(List<CmcEleDifSideLandDir> dataList, Map<String, Map<String, Integer>> columnMappings);
53
+
54
+    /**
55
+     * 计算方位角
56
+     * 
57
+     * @param resultList 包含测站坐标和方向坐标的结果列表
58
+     * @return 计算方位角后的结果列表
59
+     */
60
+    public List<CmcEleDifSideLandDir> calculateAzimuthAngle(List<CmcEleDifSideLandDir> resultList);
61
+
62
+    /**
63
+     * 获取Excel文件的所有工作表名称
64
+     * 
65
+     * @param file Excel文件
66
+     * @return 工作表名称列表
67
+     */
68
+    public List<String> getSheetNames(MultipartFile file);
69
+}

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

@@ -0,0 +1,746 @@
1
+package com.ruoyi.web.calculate.service.impl;
2
+
3
+import java.io.InputStream;
4
+import java.math.BigDecimal;
5
+import java.math.RoundingMode;
6
+import java.util.ArrayList;
7
+import java.util.HashMap;
8
+import java.util.List;
9
+import java.util.Map;
10
+
11
+import com.fasterxml.jackson.core.type.TypeReference;
12
+import com.fasterxml.jackson.databind.ObjectMapper;
13
+
14
+import javax.servlet.http.HttpServletResponse;
15
+
16
+import org.apache.poi.ss.usermodel.Sheet;
17
+import org.apache.poi.ss.usermodel.Workbook;
18
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
19
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
20
+import org.springframework.beans.factory.annotation.Autowired;
21
+import org.springframework.stereotype.Service;
22
+import org.springframework.transaction.annotation.Transactional;
23
+import org.springframework.web.multipart.MultipartFile;
24
+
25
+import com.ruoyi.common.core.domain.AjaxResult;
26
+import com.ruoyi.common.utils.poi.ExcelUtil;
27
+// import com.ruoyi.web.calculate.mapper.CmcGaussPositiveMapper;
28
+import com.ruoyi.web.calculate.domain.CmcEleDifSideLandDir;
29
+import com.ruoyi.web.calculate.service.ICmcEleDifSideLandDirService;
30
+
31
+/**
32
+ * 高差边长方向值服务实现
33
+ * 
34
+ * @author R
35
+ * @date 2026-06-12
36
+ */
37
+@Service
38
+public class CmcEleDifSideLandDirServiceImpl implements ICmcEleDifSideLandDirService {
39
+    /**
40
+     * 导入Excel数据(支持多个工作表)
41
+     */
42
+    @Override
43
+    @Transactional(rollbackFor = Exception.class)
44
+    public AjaxResult importExcelData(MultipartFile file, List<String> sheetNames) {
45
+        return importExcelData(file, sheetNames, null);
46
+    }
47
+    
48
+    /**
49
+     * 导入Excel数据(支持多个工作表和列映射)
50
+     */
51
+    @Override
52
+    @Transactional(rollbackFor = Exception.class)
53
+    public AjaxResult importExcelData(MultipartFile file, List<String> sheetNames, String columnMappingsJson) {
54
+        // 解析列映射配置
55
+        Map<String, Map<String, Integer>> columnMappings = null;
56
+        if (columnMappingsJson != null && !columnMappingsJson.isEmpty()) {
57
+            try {
58
+                ObjectMapper mapper = new ObjectMapper();
59
+                columnMappings = mapper.readValue(columnMappingsJson, 
60
+                    new TypeReference<Map<String, Map<String, Integer>>>() {});
61
+            } catch (Exception e) {
62
+                // 解析失败,使用默认映射
63
+            }
64
+        }
65
+        try {
66
+            // 存储每个工作表的数据
67
+            List<Map<String, Object>> sheetDataList = new ArrayList<>();
68
+            
69
+            // 合并所有工作表的数据用于计算
70
+            List<CmcEleDifSideLandDir> allDataList = new ArrayList<>();
71
+            
72
+            List<String> targetSheetNames;
73
+            
74
+            // 判断是否指定了工作表
75
+            if (sheetNames != null && !sheetNames.isEmpty()) {
76
+                targetSheetNames = sheetNames;
77
+            } else {
78
+                // 如果未指定,读取所有工作表
79
+                targetSheetNames = getSheetNames(file);
80
+            }
81
+            
82
+            // 获取当前工作表的列映射
83
+            Map<String, Integer> currentMapping = null;
84
+            
85
+            // 读取指定的多个工作表
86
+            for (String sheetName : targetSheetNames) {
87
+                // 获取当前工作表的列映射配置
88
+                if (columnMappings != null && columnMappings.containsKey(sheetName)) {
89
+                    currentMapping = columnMappings.get(sheetName);
90
+                } else {
91
+                    currentMapping = null;
92
+                }
93
+                
94
+                List<CmcEleDifSideLandDir> sheetData = importExcelFromSheet(file, sheetName, currentMapping);
95
+                List<String> headers = readSheetHeaders(file, sheetName);
96
+                List<List<Object>> rawData = readRawSheetData(file, sheetName);
97
+                if (sheetData != null && !sheetData.isEmpty()) {
98
+                    // 按工作表分组存储
99
+                    Map<String, Object> sheetInfo = new HashMap<>();
100
+                    sheetInfo.put("sheetName", sheetName);
101
+                    sheetInfo.put("headers", headers);
102
+                    sheetInfo.put("rawData", rawData);
103
+                    sheetInfo.put("data", convertToMapList(sheetData));
104
+                    sheetDataList.add(sheetInfo);
105
+                    
106
+                    // 添加到合并列表用于后续计算
107
+                    allDataList.addAll(sheetData);
108
+                }
109
+            }
110
+
111
+            // 检查是否有数据
112
+            if (allDataList == null || allDataList.isEmpty()) {
113
+                return AjaxResult.error("Excel文件中没有数据!");
114
+            }
115
+
116
+            // 将数据分为两组:点信息组 和 方向信息组
117
+            // 第一组:ipointNumber, pointName, cpX, cpY, cpZ(点的基本信息)
118
+            // 第二组:stationPN, directionPN(测站和方向信息)
119
+            
120
+            List<Map<String, Object>> pointDataList = new ArrayList<>();  // 点信息组
121
+            List<Map<String, Object>> directionDataList = new ArrayList<>();  // 方向信息组
122
+            
123
+            int pointCount = 0;
124
+            int directionCount = 0;
125
+            StringBuilder errorMsg = new StringBuilder();
126
+
127
+            for (int i = 0; i < allDataList.size(); i++) {
128
+                CmcEleDifSideLandDir item = allDataList.get(i);
129
+
130
+                try {
131
+                    // 判断是点信息还是方向信息
132
+                    boolean hasPointInfo = item.getPointNumber() != null && !item.getPointNumber().isEmpty();
133
+                    boolean hasDirectionInfo = item.getStationPN() != null && item.getDirectionPN() != null;
134
+                    
135
+                    // 如果有点号,作为点信息处理
136
+                    if (hasPointInfo) {
137
+                        Map<String, Object> pointMap = new HashMap<>();
138
+                        pointMap.put("pointNumber", item.getPointNumber());
139
+                        pointMap.put("pointName", item.getPointName());
140
+                        pointMap.put("cpX", item.getCPX());
141
+                        pointMap.put("cpY", item.getCPY());
142
+                        pointMap.put("cpZ", item.getCPZ());
143
+                        pointMap.put("rowNum", i + 2); // Excel中的行号
144
+                        pointDataList.add(pointMap);
145
+                        pointCount++;
146
+                    }
147
+                    
148
+                    // 如果有测站和方向序号,作为方向信息处理
149
+                    if (hasDirectionInfo) {
150
+                        Map<String, Object> directionMap = new HashMap<>();
151
+                        directionMap.put("pointNumber", item.getPointNumber()); // 关联的点号(可能为空)
152
+                        directionMap.put("stationPN", item.getStationPN());
153
+                        directionMap.put("directionPN", item.getDirectionPN());
154
+                        directionMap.put("rowNum", i + 2); // Excel中的行号
155
+                        directionDataList.add(directionMap);
156
+                        directionCount++;
157
+                    }
158
+                    
159
+                } catch (Exception e) {
160
+                    errorMsg.append(String.format("第%d行数据验证失败:%s;", i + 2, e.getMessage()));
161
+                }
162
+            }
163
+
164
+            // 构建返回结果
165
+            Map<String, Object> result = new HashMap<>();
166
+            result.put("total", allDataList.size());
167
+            result.put("pointCount", pointCount);
168
+            result.put("directionCount", directionCount);
169
+            result.put("pointData", pointDataList);
170
+            result.put("directionData", directionDataList);
171
+            // 添加按工作表分组的数据
172
+            result.put("sheetData", sheetDataList);
173
+
174
+            if (pointCount == 0 && directionCount == 0) {
175
+                return AjaxResult.error("没有有效数据!" + errorMsg.toString());
176
+            }
177
+
178
+            String message = String.format("导入成功!共解析%d条数据,其中点信息%d条,方向信息%d条", 
179
+                    allDataList.size(), pointCount, directionCount);
180
+            if (errorMsg.length() > 0) {
181
+                message += ";部分数据验证失败:" + errorMsg.toString();
182
+                return AjaxResult.success(message, result);
183
+            }
184
+
185
+            return AjaxResult.success(message, result);
186
+
187
+        } catch (Exception e) {
188
+            e.printStackTrace();
189
+            return AjaxResult.error("导入失败:" + e.getMessage());
190
+        }
191
+    }
192
+    
193
+    /**
194
+     * 将实体列表转换为Map列表
195
+     */
196
+    private List<Map<String, Object>> convertToMapList(List<CmcEleDifSideLandDir> dataList) {
197
+        List<Map<String, Object>> result = new ArrayList<>();
198
+        for (CmcEleDifSideLandDir item : dataList) {
199
+            Map<String, Object> map = new HashMap<>();
200
+            map.put("pointNumber", item.getPointNumber());
201
+            map.put("pointName", item.getPointName());
202
+            map.put("cpX", item.getCPX());
203
+            map.put("cpY", item.getCPY());
204
+            map.put("cpZ", item.getCPZ());
205
+            map.put("stationPN", item.getStationPN());
206
+            map.put("directionPN", item.getDirectionPN());
207
+            result.add(map);
208
+        }
209
+        return result;
210
+    }
211
+
212
+    /**
213
+     * 读取工作表的表头信息
214
+     * 
215
+     * @param file Excel文件
216
+     * @param sheetName 工作表名称
217
+     * @return 表头列表
218
+     */
219
+    private List<String> readSheetHeaders(MultipartFile file, String sheetName) {
220
+        List<String> headers = new ArrayList<>();
221
+        
222
+        try (InputStream inputStream = file.getInputStream();
223
+             Workbook workbook = createWorkbook(inputStream, file.getOriginalFilename())) {
224
+            // 查找指定名称的工作表
225
+            Sheet sheet = workbook.getSheet(sheetName);
226
+            
227
+            if (sheet == null) {
228
+                // 如果按名称找不到,尝试按索引查找
229
+                try {
230
+                    int sheetIndex = Integer.parseInt(sheetName);
231
+                    sheet = workbook.getSheetAt(sheetIndex);
232
+                } catch (NumberFormatException e) {
233
+                    return headers;
234
+                }
235
+            }
236
+            
237
+            if (sheet == null) {
238
+                return headers;
239
+            }
240
+            
241
+            // 读取第一行作为表头
242
+            org.apache.poi.ss.usermodel.Row headerRow = sheet.getRow(0);
243
+            if (headerRow != null) {
244
+                int lastCellNum = headerRow.getLastCellNum();
245
+                for (int i = 0; i < lastCellNum; i++) {
246
+                    headers.add(getCellStringValue(headerRow.getCell(i)));
247
+                }
248
+            }
249
+            
250
+        } catch (Exception e) {
251
+            e.printStackTrace();
252
+        }
253
+        
254
+        return headers;
255
+    }
256
+    
257
+    /**
258
+     * 读取工作表的原始数据(从第二行开始)
259
+     * 
260
+     * @param file Excel文件
261
+     * @param sheetName 工作表名称
262
+     * @return 原始数据列表
263
+     */
264
+    private List<List<Object>> readRawSheetData(MultipartFile file, String sheetName) {
265
+        List<List<Object>> rawData = new ArrayList<>();
266
+        
267
+        try (InputStream inputStream = file.getInputStream();
268
+             Workbook workbook = createWorkbook(inputStream, file.getOriginalFilename())) {
269
+            // 查找指定名称的工作表
270
+            Sheet sheet = workbook.getSheet(sheetName);
271
+            
272
+            if (sheet == null) {
273
+                // 如果按名称找不到,尝试按索引查找
274
+                try {
275
+                    int sheetIndex = Integer.parseInt(sheetName);
276
+                    sheet = workbook.getSheetAt(sheetIndex);
277
+                } catch (NumberFormatException e) {
278
+                    return rawData;
279
+                }
280
+            }
281
+            
282
+            if (sheet == null) {
283
+                return rawData;
284
+            }
285
+            
286
+            // 获取表头列数
287
+            org.apache.poi.ss.usermodel.Row headerRow = sheet.getRow(0);
288
+            int colCount = headerRow != null ? headerRow.getLastCellNum() : 10;
289
+            
290
+            // 从第二行开始读取数据
291
+            int lastRowNum = sheet.getLastRowNum();
292
+            for (int i = 1; i <= lastRowNum; i++) {
293
+                org.apache.poi.ss.usermodel.Row row = sheet.getRow(i);
294
+                if (row == null) continue;
295
+                
296
+                List<Object> rowData = new ArrayList<>();
297
+                for (int j = 0; j < colCount; j++) {
298
+                    rowData.add(getCellStringValue(row.getCell(j)));
299
+                }
300
+                
301
+                // 跳过空行
302
+                boolean hasData = false;
303
+                for (Object obj : rowData) {
304
+                    if (obj != null && !"".equals(obj.toString().trim())) {
305
+                        hasData = true;
306
+                        break;
307
+                    }
308
+                }
309
+                if (hasData) {
310
+                    rawData.add(rowData);
311
+                }
312
+            }
313
+            
314
+        } catch (Exception e) {
315
+            e.printStackTrace();
316
+        }
317
+        
318
+        return rawData;
319
+    }
320
+    
321
+    /**
322
+     * 从指定工作表读取Excel数据
323
+     * 
324
+     * @param file Excel文件
325
+     * @param sheetName 工作表名称
326
+     * @return 数据列表
327
+     */
328
+    private List<CmcEleDifSideLandDir> importExcelFromSheet(MultipartFile file, String sheetName) {
329
+        return importExcelFromSheet(file, sheetName, null);
330
+    }
331
+    
332
+    /**
333
+     * 从指定工作表读取Excel数据(支持列映射)
334
+     * 
335
+     * @param file Excel文件
336
+     * @param sheetName 工作表名称
337
+     * @param columnMapping 列映射配置(字段名 -> 列索引),为空则使用默认映射
338
+     * @return 数据列表
339
+     */
340
+    private List<CmcEleDifSideLandDir> importExcelFromSheet(MultipartFile file, String sheetName, Map<String, Integer> columnMapping) {
341
+        List<CmcEleDifSideLandDir> dataList = new ArrayList<>();
342
+        
343
+        try (InputStream inputStream = file.getInputStream();
344
+             Workbook workbook = createWorkbook(inputStream, file.getOriginalFilename())) {
345
+            // 查找指定名称的工作表
346
+            Sheet sheet = workbook.getSheet(sheetName);
347
+            
348
+            if (sheet == null) {
349
+                // 如果按名称找不到,尝试按索引查找
350
+                try {
351
+                    int sheetIndex = Integer.parseInt(sheetName);
352
+                    sheet = workbook.getSheetAt(sheetIndex);
353
+                } catch (NumberFormatException e) {
354
+                    // 不是数字索引,返回空列表
355
+                    return dataList;
356
+                }
357
+            }
358
+            
359
+            if (sheet == null) {
360
+                return dataList;
361
+            }
362
+            
363
+            // 直接使用POI解析Sheet数据
364
+            int lastRowNum = sheet.getLastRowNum();
365
+            // 从第二行开始读取(跳过表头)
366
+            for (int i = 1; i <= lastRowNum; i++) {
367
+                org.apache.poi.ss.usermodel.Row row = sheet.getRow(i);
368
+                if (row == null) {
369
+                    continue;
370
+                }
371
+                
372
+                CmcEleDifSideLandDir item = new CmcEleDifSideLandDir();
373
+                
374
+                if (columnMapping != null && !columnMapping.isEmpty()) {
375
+                    // 使用自定义列映射
376
+                    int colIndex = columnMapping.getOrDefault("pointNumber", -1);
377
+                    if (colIndex >= 0) {
378
+                        item.setPointNumber(getCellStringValue(row.getCell(colIndex)));
379
+                    }
380
+                    
381
+                    colIndex = columnMapping.getOrDefault("pointName", -1);
382
+                    if (colIndex >= 0) {
383
+                        item.setPointName(getCellStringValue(row.getCell(colIndex)));
384
+                    }
385
+                    
386
+                    colIndex = columnMapping.getOrDefault("cpX", -1);
387
+                    if (colIndex >= 0) {
388
+                        item.setCPX(getCellDoubleValue(row.getCell(colIndex)));
389
+                    }
390
+                    
391
+                    colIndex = columnMapping.getOrDefault("cpY", -1);
392
+                    if (colIndex >= 0) {
393
+                        item.setCPY(getCellDoubleValue(row.getCell(colIndex)));
394
+                    }
395
+                    
396
+                    colIndex = columnMapping.getOrDefault("cpZ", -1);
397
+                    if (colIndex >= 0) {
398
+                        item.setCPZ(getCellDoubleValue(row.getCell(colIndex)));
399
+                    }
400
+                    
401
+                    colIndex = columnMapping.getOrDefault("stationPN", -1);
402
+                    if (colIndex >= 0) {
403
+                        item.setStationPN(getCellIntegerValue(row.getCell(colIndex)));
404
+                    }
405
+                    
406
+                    colIndex = columnMapping.getOrDefault("directionPN", -1);
407
+                    if (colIndex >= 0) {
408
+                        item.setDirectionPN(getCellIntegerValue(row.getCell(colIndex)));
409
+                    }
410
+                } else {
411
+                    // 使用默认列映射:ipointNumber, pointName, cpX, cpY, cpZ, stationPN, directionPN
412
+                    item.setPointNumber(getCellStringValue(row.getCell(0)));
413
+                    item.setPointName(getCellStringValue(row.getCell(1)));
414
+                    item.setCPX(getCellDoubleValue(row.getCell(2)));
415
+                    item.setCPY(getCellDoubleValue(row.getCell(3)));
416
+                    item.setCPZ(getCellDoubleValue(row.getCell(4)));
417
+                    item.setStationPN(getCellIntegerValue(row.getCell(5)));
418
+                    item.setDirectionPN(getCellIntegerValue(row.getCell(6)));
419
+                }
420
+                
421
+                dataList.add(item);
422
+            }
423
+            
424
+        } catch (Exception e) {
425
+            e.printStackTrace();
426
+        }
427
+        
428
+        return dataList;
429
+    }
430
+    
431
+    /**
432
+     * 获取单元格的字符串值
433
+     */
434
+    private String getCellStringValue(org.apache.poi.ss.usermodel.Cell cell) {
435
+        if (cell == null) {
436
+            return null;
437
+        }
438
+        switch (cell.getCellType()) {
439
+            case STRING:
440
+                return cell.getStringCellValue();
441
+            case NUMERIC:
442
+                // 数字类型转字符串,避免科学计数法
443
+                double numValue = cell.getNumericCellValue();
444
+                if (numValue == Math.floor(numValue)) {
445
+                    return String.valueOf((long) numValue);
446
+                }
447
+                return String.valueOf(numValue);
448
+            case BOOLEAN:
449
+                return String.valueOf(cell.getBooleanCellValue());
450
+            case FORMULA:
451
+                try {
452
+                    return cell.getStringCellValue();
453
+                } catch (Exception e) {
454
+                    return String.valueOf(cell.getNumericCellValue());
455
+                }
456
+            default:
457
+                return null;
458
+        }
459
+    }
460
+    
461
+    /**
462
+     * 获取单元格的Double值
463
+     */
464
+    private Double getCellDoubleValue(org.apache.poi.ss.usermodel.Cell cell) {
465
+        if (cell == null) {
466
+            return null;
467
+        }
468
+        switch (cell.getCellType()) {
469
+            case NUMERIC:
470
+                return cell.getNumericCellValue();
471
+            case STRING:
472
+                try {
473
+                    return Double.parseDouble(cell.getStringCellValue().trim());
474
+                } catch (NumberFormatException e) {
475
+                    return null;
476
+                }
477
+            default:
478
+                return null;
479
+        }
480
+    }
481
+    
482
+    /**
483
+     * 获取单元格的Integer值
484
+     */
485
+    private Integer getCellIntegerValue(org.apache.poi.ss.usermodel.Cell cell) {
486
+        if (cell == null) {
487
+            return null;
488
+        }
489
+        switch (cell.getCellType()) {
490
+            case NUMERIC:
491
+                return (int) cell.getNumericCellValue();
492
+            case STRING:
493
+                try {
494
+                    return Integer.parseInt(cell.getStringCellValue().trim());
495
+                } catch (NumberFormatException e) {
496
+                    return null;
497
+                }
498
+            default:
499
+                return null;
500
+        }
501
+    }
502
+
503
+    /**
504
+     * 根据文件类型创建Workbook
505
+     */
506
+    private Workbook createWorkbook(InputStream inputStream, String fileName) throws Exception {
507
+        if (fileName != null && fileName.endsWith(".xlsx")) {
508
+            return new XSSFWorkbook(inputStream);
509
+        } else {
510
+            return new HSSFWorkbook(inputStream);
511
+        }
512
+    }
513
+
514
+    /**
515
+     * 获取Excel文件的所有工作表名称
516
+     * 
517
+     * @param file Excel文件
518
+     * @return 工作表名称列表
519
+     */
520
+    @Override
521
+    public List<String> getSheetNames(MultipartFile file) {
522
+        List<String> sheetNames = new ArrayList<>();
523
+        
524
+        try (InputStream inputStream = file.getInputStream();
525
+             Workbook workbook = createWorkbook(inputStream, file.getOriginalFilename())) {
526
+            int numberOfSheets = workbook.getNumberOfSheets();
527
+            for (int i = 0; i < numberOfSheets; i++) {
528
+                sheetNames.add(workbook.getSheetName(i));
529
+            }
530
+        } catch (Exception e) {
531
+            e.printStackTrace();
532
+        }
533
+        
534
+        return sheetNames;
535
+    }
536
+
537
+    /**
538
+     * 执行高差边长方向值计算
539
+     */
540
+    @Override
541
+    public List<CmcEleDifSideLandDir> calculateEleDifSideLandDir(List<CmcEleDifSideLandDir> dataList) {
542
+        return calculateEleDifSideLandDir(dataList, null);
543
+    }
544
+    
545
+    /**
546
+     * 执行高差边长方向值计算(带列映射)
547
+     */
548
+    @Override
549
+    public List<CmcEleDifSideLandDir> calculateEleDifSideLandDir(List<CmcEleDifSideLandDir> dataList, Map<String, Map<String, Integer>> columnMappings) {
550
+        // 列映射参数在计算阶段不需要使用,因为数据已经在导入阶段按映射解析好了
551
+        // 这里保留方法签名以兼容接口
552
+        List<CmcEleDifSideLandDir> resultList = new ArrayList<>();
553
+        
554
+        // 第一组:控制网点信息,key 是序号(ipointNumber作为序号)
555
+        // 假设 ipointNumber 是整数序号,用于匹配 stationPN 和 directionPN
556
+        Map<Integer, CmcEleDifSideLandDir> controlPointMap = new HashMap<>();
557
+        
558
+        // 第二组:测站和方向序号对
559
+        List<Map<String, Integer>> stationDirectionList = new ArrayList<>();
560
+        
561
+        for (CmcEleDifSideLandDir item : dataList) {
562
+            try {
563
+                String pointNumber = item.getPointNumber();
564
+                Integer stationPN = item.getStationPN();
565
+                Integer directionPN = item.getDirectionPN();
566
+                
567
+                // 处理第一组:控制网点信息
568
+                // 检查是否有有效的坐标信息(cpX/cpY/cpZ)
569
+                boolean hasCoordinates = item.getCPX() != null || item.getCPY() != null || item.getCPZ() != null;
570
+                
571
+                // 优先使用 pointNumber 作为序号,如果不是数字则尝试使用其他字段
572
+                Integer seqNumber = null;
573
+                if (pointNumber != null && !pointNumber.isEmpty()) {
574
+                    try {
575
+                        seqNumber = Integer.parseInt(pointNumber.trim());
576
+                    } catch (NumberFormatException e) {
577
+                        // 如果点号不是数字格式,尝试使用stationPN作为备选序号
578
+                        if (stationPN != null) {
579
+                            seqNumber = stationPN;
580
+                        } else if (directionPN != null) {
581
+                            seqNumber = directionPN;
582
+                        }
583
+                    }
584
+                } else if (stationPN != null) {
585
+                    // 如果没有pointNumber,使用stationPN作为序号
586
+                    seqNumber = stationPN;
587
+                } else if (directionPN != null) {
588
+                    // 如果没有pointNumber和stationPN,使用directionPN作为序号
589
+                    seqNumber = directionPN;
590
+                }
591
+                
592
+                // 如果有序号且有坐标信息,添加到控制点映射
593
+                if (seqNumber != null && hasCoordinates) {
594
+                    if (!controlPointMap.containsKey(seqNumber)) {
595
+                        CmcEleDifSideLandDir pointData = new CmcEleDifSideLandDir();
596
+                        pointData.setPointNumber(item.getPointNumber());
597
+                        pointData.setPointName(item.getPointName());
598
+                        pointData.setCPX(item.getCPX());
599
+                        pointData.setCPY(item.getCPY());
600
+                        pointData.setCPZ(item.getCPZ());
601
+                        controlPointMap.put(seqNumber, pointData);
602
+                    }
603
+                }
604
+                
605
+                // 处理第二组:测站和方向序号(独立处理,不依赖pointNumber)
606
+                if (stationPN != null && directionPN != null) {
607
+                    Map<String, Integer> stationDir = new HashMap<>();
608
+                    stationDir.put("stationPN", stationPN);
609
+                    stationDir.put("directionPN", directionPN);
610
+                    stationDirectionList.add(stationDir);
611
+                }
612
+                
613
+            } catch (Exception e) {
614
+                e.printStackTrace();
615
+            }
616
+        }
617
+        
618
+        // 根据 stationPN 和 directionPN 匹配控制网点坐标
619
+        for (Map<String, Integer> stationDir : stationDirectionList) {
620
+            Integer stationPN = stationDir.get("stationPN");
621
+            Integer directionPN = stationDir.get("directionPN");
622
+            
623
+            CmcEleDifSideLandDir result = new CmcEleDifSideLandDir();
624
+            
625
+            // 设置序号(始终设置,即使匹配失败)
626
+            result.setStationPN(stationPN);
627
+            result.setDirectionPN(directionPN);
628
+            
629
+            // 根据 stationPN 查找测站控制网点坐标
630
+            CmcEleDifSideLandDir stationPoint = controlPointMap.get(stationPN);
631
+            if (stationPoint != null) {
632
+                // 将测站控制网点坐标设置为测站坐标
633
+                result.setSPX(stationPoint.getCPX());
634
+                result.setSPY(stationPoint.getCPY());
635
+                result.setSPZ(stationPoint.getCPZ());
636
+                result.setStationPointName(stationPoint.getPointName());
637
+            }
638
+            
639
+            // 根据 directionPN 查找方向控制网点坐标
640
+            CmcEleDifSideLandDir directionPoint = controlPointMap.get(directionPN);
641
+            if (directionPoint != null) {
642
+                // 将方向控制网点坐标设置为方向坐标
643
+                result.setDPX(directionPoint.getCPX());
644
+                result.setDPY(directionPoint.getCPY());
645
+                result.setDPZ(directionPoint.getCPZ());
646
+                result.setDirectionPointName(directionPoint.getPointName());
647
+            }
648
+            
649
+            // 只要有一个匹配成功就添加到结果(允许部分匹配)
650
+            if (stationPoint != null || directionPoint != null) {
651
+                resultList.add(result);
652
+            }
653
+        }
654
+        
655
+        return resultList;
656
+    }
657
+    
658
+    /**
659
+     * 计算方位角
660
+     * 使用 ATAN2(方向y-测站y, 方向x-测站x) 并转换为度
661
+     * 同一测站号的所有记录使用第一个计算出的方位角值
662
+     * 同时计算角度差:原始方位角 - 复用后的方位角
663
+     * 
664
+     * @param resultList 包含测站坐标和方向坐标的结果列表
665
+     * @return 计算方位角后的结果列表
666
+     */
667
+    public List<CmcEleDifSideLandDir> calculateAzimuthAngle(List<CmcEleDifSideLandDir> resultList) {
668
+        // 缓存每个测站号对应的第一个方位角值
669
+        Map<Integer, Double> stationAzimuthMap = new HashMap<>();
670
+        
671
+        for (CmcEleDifSideLandDir item : resultList) {
672
+            try {
673
+                Integer stationPN = item.getStationPN();
674
+                
675
+                // 如果测站号为空,跳过
676
+                if (stationPN == null) {
677
+                    continue;
678
+                }
679
+                
680
+                Double spX = item.getSPX();
681
+                Double spY = item.getSPY();
682
+                Double dpX = item.getDPX();
683
+                Double dpY = item.getDPY();
684
+                
685
+                // 计算原始方位角
686
+                Double originalAzimuth = null;
687
+                if (spX != null && spY != null && dpX != null && dpY != null) {
688
+                    // 计算坐标差
689
+                    double deltaX = dpX - spX;
690
+                    double deltaY = dpY - spY;
691
+                    
692
+                    // 计算 ATAN2(Δy, Δx),结果为弧度
693
+                    double azimuthRadians = Math.atan2(deltaY, deltaX);
694
+                    
695
+                    // 转换为度
696
+                    originalAzimuth = Math.toDegrees(azimuthRadians);
697
+                    
698
+                    // 方位角标准化到 0-360 度范围
699
+                    if (originalAzimuth < 0) {
700
+                        originalAzimuth += 360.0;
701
+                    }
702
+                    
703
+                    // 保存原始方位角
704
+                    item.setOriginalAzimuthAngle(originalAzimuth);
705
+                }
706
+                
707
+                // 检查该测站号是否已经有缓存的方位角值
708
+                if (stationAzimuthMap.containsKey(stationPN)) {
709
+                    // 使用缓存的第一个方位角值
710
+                    double reusedAzimuth = stationAzimuthMap.get(stationPN);
711
+                    
712
+                    // 计算角度差:原始方位角 - 复用后的方位角
713
+                    double angleDiff = 0.0;
714
+                    if (originalAzimuth != null) {
715
+                        angleDiff = originalAzimuth - reusedAzimuth;
716
+                        
717
+                        // 如果角度差小于0,则+360,反之保持原样
718
+                        if (angleDiff < 0) {
719
+                            angleDiff += 360.0;
720
+                        }
721
+                        
722
+                        item.setAngleDifference(angleDiff);
723
+                    }
724
+                    
725
+                    // 设置方位角为角度差(直接使用十进制度数)
726
+                    item.setAzimuthAngle(angleDiff);
727
+                } else {
728
+                    // 使用自己计算的方位角作为复用值
729
+                    if (originalAzimuth != null) {
730
+                        // 缓存该测站号的第一个方位角值
731
+                        stationAzimuthMap.put(stationPN, originalAzimuth);
732
+                        
733
+                        // 角度差为 0(自己与自己相同)
734
+                        item.setAngleDifference(0.0);
735
+                        
736
+                        // 第一个方向的方位角(角度差)为0
737
+                        item.setAzimuthAngle(0.0);
738
+                    }
739
+                }
740
+            } catch (Exception e) {
741
+                e.printStackTrace();
742
+            }
743
+        }
744
+        return resultList;
745
+    }
746
+}

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

@@ -0,0 +1,105 @@
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 CmcEleDifSideLandDirTemplate {
10
+    /** 主键ID */
11
+    private Long id;
12
+
13
+    /** 待求点号 */
14
+    @Excel(name = "序号")
15
+    private String pointNumber;
16
+
17
+    /** 坐标系 */
18
+    @Excel(name = "点名")
19
+    private String pointName;
20
+
21
+    /** 控制网点坐标x */
22
+    @Excel(name = "控制网点坐标x", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
23
+    private Double cpX;
24
+
25
+    /** 控制网点坐标y */
26
+    @Excel(name = "控制网点坐标y", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
27
+    private Double cpY;
28
+
29
+    /** 控制网点坐标z */
30
+    @Excel(name = "控制网点坐标z", cellType = ColumnType.NUMERIC, numberFormat = "0.0000")
31
+    private Double cpZ;
32
+
33
+    /** 测站序号 */
34
+    @Excel(name = "测站序号", cellType = ColumnType.NUMERIC)
35
+    private Integer stationPN;
36
+
37
+    /** 方向序号 */
38
+    @Excel(name = "方向序号", cellType = ColumnType.NUMERIC)
39
+    private Integer directionPN;
40
+
41
+    public void setId(Long id) {
42
+        this.id = id;
43
+    }
44
+
45
+    public Long getId() {
46
+        return id;
47
+    }
48
+
49
+    public void setPointNumber(String pointNumber) {
50
+        this.pointNumber = pointNumber;
51
+    }
52
+
53
+    public String getPointNumber() {
54
+        return pointNumber;
55
+    }
56
+
57
+    public void setPointName(String pointName) {
58
+        this.pointName = pointName;
59
+    }
60
+
61
+    public String getPointName() {
62
+        return pointName;
63
+    }
64
+
65
+    public void setCPX(Double cpX) {
66
+        this.cpX = cpX;
67
+    }
68
+
69
+    public Double getCPX() {
70
+        return cpX;
71
+    }
72
+
73
+    public void setCPY(Double cpY) {
74
+        this.cpY = cpY;
75
+    }
76
+
77
+    public Double getCPY() {
78
+        return cpY;
79
+    }
80
+
81
+    public void setCPZ(Double cpZ) {
82
+        this.cpZ = cpZ;
83
+    }
84
+
85
+    public Double getCPZ() {
86
+        return cpZ;
87
+    }
88
+
89
+    public void setStationPN(Integer stationPN) {
90
+        this.stationPN = stationPN;
91
+    }
92
+
93
+    public Integer getStationPN() {
94
+        return stationPN;
95
+    }
96
+
97
+    public void setDirectionPN(Integer directionPN) {
98
+        this.directionPN = directionPN;
99
+    }
100
+
101
+    public Integer getDirectionPN() {
102
+        return directionPN;
103
+    }
104
+}
105
+

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

@@ -0,0 +1,63 @@
1
+import request from '@/utils/request'
2
+
3
+/**
4
+ * 高差边长方向值计算
5
+ */
6
+export function calculate(data) {
7
+    return request({
8
+        url: `/calculate/eleDifSideLandDir/calculate`,
9
+        method: 'post',
10
+        data: data
11
+    })
12
+}
13
+
14
+/**
15
+ * 导入Excel数据
16
+ */
17
+export function importExcel(data) {
18
+    return request({
19
+        url: `/calculate/eleDifSideLandDir/import`,
20
+        method: 'post',
21
+        data: data,
22
+        headers: {
23
+            'Content-Type': 'multipart/form-data'
24
+        }
25
+    })
26
+}
27
+
28
+/**
29
+ * 导出计算结果
30
+ */
31
+export function exportExcel(data) {
32
+    return request({
33
+        url: `/calculate/eleDifSideLandDir/export`,
34
+        method: 'post',
35
+        data: data,
36
+        responseType: 'blob'
37
+    })
38
+}
39
+
40
+/**
41
+ * 下载导入模板
42
+ */
43
+export function downloadTemplate() {
44
+    return request({
45
+        url: '/calculate/eleDifSideLandDir/template',
46
+        method: 'get',
47
+        responseType: 'blob'
48
+    })
49
+}
50
+
51
+/**
52
+ * 获取工作表名称
53
+ */
54
+export function getSheetNames(data) {
55
+    return request({
56
+        url: '/calculate/eleDifSideLandDir/sheetNames',
57
+        method: 'post',
58
+        data: data,
59
+        headers: {
60
+            'Content-Type': 'multipart/form-data'
61
+        }
62
+    })
63
+}

+ 998
- 0
oa-ui/src/views/calculate/tools/eledifsidelanddir.vue
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


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