优化方阵、光伏板、光伏板点方法逻辑和性能
This commit is contained in:
@ -3,6 +3,7 @@ package org.dromara;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
/**
|
||||
@ -10,8 +11,9 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@EnableAsync
|
||||
@SpringBootApplication
|
||||
@EnableAsync
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
|
||||
public class DromaraApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@ -1,14 +1,12 @@
|
||||
package org.dromara.facility.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 设施-光伏板对象 fac_photovoltaic_panel
|
||||
@ -65,15 +63,4 @@ public class FacPhotovoltaicPanel extends BaseEntity {
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 删除时间
|
||||
*/
|
||||
private Date deletedAt;
|
||||
|
||||
/**
|
||||
* 是否删除(0正常 1删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private Long isDelete;
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,12 @@
|
||||
package org.dromara.facility.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 设施-光伏板立柱对象 fac_photovoltaic_panel_column
|
||||
@ -65,15 +63,4 @@ public class FacPhotovoltaicPanelColumn extends BaseEntity {
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 删除时间
|
||||
*/
|
||||
private Date deletedAt;
|
||||
|
||||
/**
|
||||
* 是否删除(0正常 1删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private Long isDelete;
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,12 @@
|
||||
package org.dromara.facility.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 设施-光伏板桩点对象 fac_photovoltaic_panel_point
|
||||
@ -65,15 +63,4 @@ public class FacPhotovoltaicPanelPoint extends BaseEntity {
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 删除时间
|
||||
*/
|
||||
private Date deletedAt;
|
||||
|
||||
/**
|
||||
* 是否删除(0正常 1删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private Long isDelete;
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,12 @@
|
||||
package org.dromara.facility.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 设施-光伏板支架对象 fac_photovoltaic_panel_support
|
||||
@ -65,15 +63,4 @@ public class FacPhotovoltaicPanelSupport extends BaseEntity {
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 删除时间
|
||||
*/
|
||||
private Date deletedAt;
|
||||
|
||||
/**
|
||||
* 是否删除(0正常 1删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private Long isDelete;
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
package org.dromara.facility.service;
|
||||
|
||||
import org.dromara.facility.domain.FacPhotovoltaicPanelColumn;
|
||||
import org.dromara.facility.domain.FacPhotovoltaicPanelPoint;
|
||||
import org.dromara.facility.domain.FacPhotovoltaicPanelSupport;
|
||||
import org.dromara.facility.domain.req.photovoltaicpanelparts.PhotovoltaicPanelPartsCreateByGeoJsonReq;
|
||||
import org.dromara.facility.domain.req.photovoltaicpanelparts.PhotovoltaicPanelPartsCreateReq;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设施-光伏板(桩点、立柱、支架)Service接口
|
||||
@ -21,6 +25,28 @@ public interface IFacPhotovoltaicPanelPartsService {
|
||||
*/
|
||||
Boolean insertPartsByGeoJson(PhotovoltaicPanelPartsCreateByGeoJsonReq geoJson);
|
||||
|
||||
/**
|
||||
* 批量新增设施-光伏板(桩点、立柱、支架)内部方法
|
||||
*
|
||||
* @param pointList 桩点列表
|
||||
* @param columnList 立柱列表
|
||||
* @param supportList 支架列表
|
||||
*/
|
||||
void batchInsertPartsInner(List<FacPhotovoltaicPanelPoint> pointList,
|
||||
List<FacPhotovoltaicPanelColumn> columnList,
|
||||
List<FacPhotovoltaicPanelSupport> supportList);
|
||||
|
||||
/**
|
||||
* 批量删除设施-光伏板(桩点、立柱、支架)内部方法
|
||||
*
|
||||
* @param pointList 桩点列表
|
||||
* @param columnList 立柱列表
|
||||
* @param supportList 支架列表
|
||||
*/
|
||||
void batchDeletePartsInner(List<FacPhotovoltaicPanelPoint> pointList,
|
||||
List<FacPhotovoltaicPanelColumn> columnList,
|
||||
List<FacPhotovoltaicPanelSupport> supportList);
|
||||
|
||||
/**
|
||||
* 批量新增设施-光伏板(桩点、立柱、支架)
|
||||
*
|
||||
|
@ -154,6 +154,9 @@ public class FacMatrixServiceImpl extends ServiceImpl<FacMatrixMapper, FacMatrix
|
||||
if (projectService.getById(projectId) == null) {
|
||||
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
// 获取当下项目下方阵信息
|
||||
List<FacMatrix> oldMatrixList = this.lambdaQuery()
|
||||
.eq(FacMatrix::getProjectId, projectId).list();
|
||||
List<FacMatrix> matrixList = new ArrayList<>();
|
||||
List<Feature> locationFeatures = geoJson.getLocationGeoJson().getFeatures();
|
||||
List<FeatureByPoint> nameFeatures = geoJson.getNameGeoJson().getFeatures();
|
||||
@ -183,6 +186,12 @@ public class FacMatrixServiceImpl extends ServiceImpl<FacMatrixMapper, FacMatrix
|
||||
matrix.setMatrixName(name);
|
||||
matrixList.add(matrix);
|
||||
}
|
||||
if (CollUtil.isEmpty(oldMatrixList)) {
|
||||
boolean result = this.removeBatchByIds(oldMatrixList);
|
||||
if (!result) {
|
||||
throw new ServiceException("数据库操作失败", HttpStatus.ERROR);
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(matrixList)) {
|
||||
boolean result = this.saveBatch(matrixList);
|
||||
if (!result) {
|
||||
|
@ -4,9 +4,11 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.constant.HttpStatus;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.facility.domain.FacPhotovoltaicPanel;
|
||||
import org.dromara.facility.domain.FacPhotovoltaicPanelColumn;
|
||||
import org.dromara.facility.domain.FacPhotovoltaicPanelPoint;
|
||||
@ -17,18 +19,29 @@ import org.dromara.facility.domain.req.photovoltaicpanelparts.PhotovoltaicPanelP
|
||||
import org.dromara.facility.service.*;
|
||||
import org.dromara.project.service.IBusProjectService;
|
||||
import org.dromara.utils.GeoJsonUtils;
|
||||
import org.springframework.aop.framework.AopContext;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author lcj
|
||||
* @date 2025/4/21 15:53
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPanelPartsService {
|
||||
|
||||
@ -57,7 +70,6 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean insertPartsByGeoJson(PhotovoltaicPanelPartsCreateByGeoJsonReq geoJson) {
|
||||
Long projectId = geoJson.getProjectId();
|
||||
if (projectService.getById(projectId) == null) {
|
||||
@ -70,12 +82,39 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
|
||||
throw new ServiceException("项目下未创建光伏板", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
List<FeatureByPoint> features = geoJson.getPointGeoJson().getFeatures();
|
||||
// 获取数据库中所有点的列表
|
||||
List<FacPhotovoltaicPanelPoint> oldPointList = photovoltaicPanelPointService.lambdaQuery()
|
||||
.eq(FacPhotovoltaicPanelPoint::getProjectId, projectId).list();
|
||||
Map<String, FacPhotovoltaicPanelPoint> oldPointMap = oldPointList.stream()
|
||||
.collect(Collectors.toMap(
|
||||
FacPhotovoltaicPanelPoint::getName,
|
||||
Function.identity(),
|
||||
(existing, replacement) -> existing // 如果有重复,保留第一个
|
||||
));
|
||||
List<FacPhotovoltaicPanelColumn> oldColumnList = photovoltaicPanelColumnService.lambdaQuery()
|
||||
.eq(FacPhotovoltaicPanelColumn::getProjectId, projectId).list();
|
||||
Map<String, FacPhotovoltaicPanelColumn> oldColumnMap = oldColumnList.stream()
|
||||
.collect(Collectors.toMap(
|
||||
FacPhotovoltaicPanelColumn::getName,
|
||||
Function.identity(),
|
||||
(existing, replacement) -> existing // 如果有重复,保留第一个
|
||||
));
|
||||
List<FacPhotovoltaicPanelSupport> oldSupportList = photovoltaicPanelSupportService.lambdaQuery()
|
||||
.eq(FacPhotovoltaicPanelSupport::getProjectId, projectId).list();
|
||||
Map<String, FacPhotovoltaicPanelSupport> oldSupportMap = oldSupportList.stream()
|
||||
.collect(Collectors.toMap(
|
||||
FacPhotovoltaicPanelSupport::getName,
|
||||
Function.identity(),
|
||||
(existing, replacement) -> existing // 如果有重复,保留第一个
|
||||
));
|
||||
// 获取所有点列表
|
||||
List<List<Double>> pointList = new ArrayList<>
|
||||
List<List<Double>> pointPositionList = new ArrayList<>
|
||||
(features.stream().map(featureByPoint -> featureByPoint.getGeometry().getCoordinates()).toList());
|
||||
List<FacPhotovoltaicPanelPoint> photovoltaicPanelPointList = new ArrayList<>();
|
||||
List<FacPhotovoltaicPanelColumn> photovoltaicPanelColumnList = new ArrayList<>();
|
||||
List<FacPhotovoltaicPanelSupport> photovoltaicPanelSupportList = new ArrayList<>();
|
||||
List<FacPhotovoltaicPanelPoint> pointList = new ArrayList<>();
|
||||
List<FacPhotovoltaicPanelColumn> columnList = new ArrayList<>();
|
||||
List<FacPhotovoltaicPanelSupport> supportList = new ArrayList<>();
|
||||
// 获取当前登录用户
|
||||
Long userId = LoginHelper.getUserId();
|
||||
// 遍历所有光伏板,找到所有匹配的点
|
||||
for (FacPhotovoltaicPanel photovoltaicPanel : photovoltaicPanelList) {
|
||||
String positions = photovoltaicPanel.getPositions();
|
||||
@ -85,9 +124,10 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
|
||||
positionList.add(JSONUtil.toList(s, Double.class));
|
||||
}
|
||||
// 获取点在面内的点
|
||||
List<List<Double>> pointInPlaneList = GeoJsonUtils.getPointInPlaneList(positionList, pointList);
|
||||
List<List<Double>> pointInPlaneList = GeoJsonUtils.getPointInPlaneList(positionList, pointPositionList);
|
||||
// 删除点在面内的点
|
||||
pointList.removeAll(pointInPlaneList);
|
||||
pointPositionList.removeAll(pointInPlaneList);
|
||||
// 判断点在面内的点是否为空
|
||||
if (CollUtil.isNotEmpty(pointInPlaneList)) {
|
||||
int i = 1;
|
||||
// 遍历点在面内的点,添加实体信息
|
||||
@ -101,45 +141,181 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
|
||||
photovoltaicPanelPoint.setMatrixId(matrixId);
|
||||
photovoltaicPanelPoint.setName(name);
|
||||
photovoltaicPanelPoint.setPositions(jsonStr);
|
||||
photovoltaicPanelPointList.add(photovoltaicPanelPoint);
|
||||
photovoltaicPanelPoint.setCreateBy(userId);
|
||||
photovoltaicPanelPoint.setUpdateBy(userId);
|
||||
if (CollUtil.isNotEmpty(oldPointMap) && oldPointMap.containsKey(name)) {
|
||||
FacPhotovoltaicPanelPoint oldPoint = oldPointMap.get(name);
|
||||
photovoltaicPanelPoint.setFinishType(oldPoint.getFinishType());
|
||||
photovoltaicPanelPoint.setStatus(oldPoint.getStatus());
|
||||
}
|
||||
pointList.add(photovoltaicPanelPoint);
|
||||
FacPhotovoltaicPanelColumn photovoltaicPanelColumn = new FacPhotovoltaicPanelColumn();
|
||||
photovoltaicPanelColumn.setProjectId(projectId);
|
||||
photovoltaicPanelColumn.setMatrixId(matrixId);
|
||||
photovoltaicPanelColumn.setName(name);
|
||||
photovoltaicPanelColumn.setPositions(jsonStr);
|
||||
photovoltaicPanelColumnList.add(photovoltaicPanelColumn);
|
||||
photovoltaicPanelColumn.setCreateBy(userId);
|
||||
photovoltaicPanelColumn.setUpdateBy(userId);
|
||||
if (CollUtil.isNotEmpty(oldColumnMap) && oldColumnMap.containsKey(name)) {
|
||||
FacPhotovoltaicPanelColumn oldColumn = oldColumnMap.get(name);
|
||||
photovoltaicPanelColumn.setFinishType(oldColumn.getFinishType());
|
||||
photovoltaicPanelColumn.setStatus(oldColumn.getStatus());
|
||||
}
|
||||
columnList.add(photovoltaicPanelColumn);
|
||||
FacPhotovoltaicPanelSupport photovoltaicPanelSupport = new FacPhotovoltaicPanelSupport();
|
||||
photovoltaicPanelSupport.setProjectId(projectId);
|
||||
photovoltaicPanelSupport.setMatrixId(matrixId);
|
||||
photovoltaicPanelSupport.setName(name);
|
||||
photovoltaicPanelSupport.setPositions(jsonStr);
|
||||
photovoltaicPanelSupportList.add(photovoltaicPanelSupport);
|
||||
photovoltaicPanelSupport.setCreateBy(userId);
|
||||
photovoltaicPanelSupport.setUpdateBy(userId);
|
||||
if (CollUtil.isNotEmpty(oldSupportMap) && oldSupportMap.containsKey(name)) {
|
||||
FacPhotovoltaicPanelSupport oldSupport = oldSupportMap.get(name);
|
||||
photovoltaicPanelSupport.setFinishType(oldSupport.getFinishType());
|
||||
photovoltaicPanelSupport.setStatus(oldSupport.getStatus());
|
||||
}
|
||||
supportList.add(photovoltaicPanelSupport);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 批量新增
|
||||
if (CollUtil.isNotEmpty(photovoltaicPanelPointList)) {
|
||||
boolean result = photovoltaicPanelPointService.saveBatch(photovoltaicPanelPointList);
|
||||
if (!result) {
|
||||
throw new ServiceException("批量新增光伏板桩点失败,数据库异常", HttpStatus.ERROR);
|
||||
}
|
||||
// 自定义线程池(IO 密集型线程池)
|
||||
ThreadPoolExecutor customExecutor = new ThreadPoolExecutor(
|
||||
20, // 核心线程数
|
||||
50, // 最大线程数
|
||||
60L, // 线程空闲存活时间
|
||||
TimeUnit.SECONDS, // 存活时间单位
|
||||
new LinkedBlockingQueue<>(10000), // 阻塞队列容量
|
||||
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:由调用线程处理任务
|
||||
);
|
||||
// 分批处理,避免长事务,假设每次处理 1000 条数据
|
||||
int batchSize = 1000;
|
||||
// 保存所有批次任务
|
||||
List<CompletableFuture<Void>> deleteFutures = new ArrayList<>();
|
||||
int deleteSize = oldPointList.size();
|
||||
for (int i = 0; i < deleteSize; i += batchSize) {
|
||||
int endIndex = Math.min(i + batchSize, deleteSize);
|
||||
List<FacPhotovoltaicPanelPoint> batchPointList = oldPointList.subList(i, endIndex);
|
||||
List<FacPhotovoltaicPanelColumn> batchColumnList = oldColumnList.subList(i, endIndex);
|
||||
List<FacPhotovoltaicPanelSupport> batchSupportList = oldSupportList.subList(i, endIndex);
|
||||
// 使用事务处理每批数据
|
||||
// 获取代理
|
||||
FacPhotovoltaicPanelPartsServiceImpl photovoltaicPanelPartsService = (FacPhotovoltaicPanelPartsServiceImpl) AopContext.currentProxy();
|
||||
// 异步处理每批数据,将任务添加到异步任务列表
|
||||
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> photovoltaicPanelPartsService.batchDeletePartsInner(batchPointList, batchColumnList, batchSupportList), customExecutor);
|
||||
deleteFutures.add(future);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(photovoltaicPanelColumnList)) {
|
||||
boolean result = photovoltaicPanelColumnService.saveBatch(photovoltaicPanelColumnList);
|
||||
if (!result) {
|
||||
throw new ServiceException("批量新增光伏板立柱失败,数据库异常", HttpStatus.ERROR);
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(photovoltaicPanelSupportList)) {
|
||||
boolean result = photovoltaicPanelSupportService.saveBatch(photovoltaicPanelSupportList);
|
||||
if (!result) {
|
||||
throw new ServiceException("批量新增光伏板支架失败,数据库异常", HttpStatus.ERROR);
|
||||
}
|
||||
// 等待所有批次完成操作
|
||||
CompletableFuture.allOf(deleteFutures.toArray(new CompletableFuture[0])).join();
|
||||
// 保存所有批次任务
|
||||
List<CompletableFuture<Void>> insertFutures = new ArrayList<>();
|
||||
int totalSize = pointList.size();
|
||||
for (int i = 0; i < totalSize; i += batchSize) {
|
||||
int endIndex = Math.min(i + batchSize, totalSize);
|
||||
List<FacPhotovoltaicPanelPoint> batchPointList = pointList.subList(i, endIndex);
|
||||
List<FacPhotovoltaicPanelColumn> batchColumnList = columnList.subList(i, endIndex);
|
||||
List<FacPhotovoltaicPanelSupport> batchSupportList = supportList.subList(i, endIndex);
|
||||
// 使用事务处理每批数据
|
||||
// 获取代理
|
||||
FacPhotovoltaicPanelPartsServiceImpl photovoltaicPanelPartsService = (FacPhotovoltaicPanelPartsServiceImpl) AopContext.currentProxy();
|
||||
// 异步处理每批数据,将任务添加到异步任务列表
|
||||
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> photovoltaicPanelPartsService.batchInsertPartsInner(batchPointList, batchColumnList, batchSupportList), customExecutor);
|
||||
insertFutures.add(future);
|
||||
}
|
||||
// 等待所有批次完成操作
|
||||
CompletableFuture.allOf(insertFutures.toArray(new CompletableFuture[0])).join();
|
||||
// 关闭线程池
|
||||
customExecutor.shutdown();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量新增设施-光伏板(桩点、立柱、支架)内部方法
|
||||
*
|
||||
* @param pointList 桩点列表
|
||||
* @param columnList 立柱列表
|
||||
* @param supportList 支架列表
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchInsertPartsInner(List<FacPhotovoltaicPanelPoint> pointList,
|
||||
List<FacPhotovoltaicPanelColumn> columnList,
|
||||
List<FacPhotovoltaicPanelSupport> supportList) {
|
||||
try {
|
||||
if (CollUtil.isNotEmpty(pointList)) {
|
||||
boolean result = photovoltaicPanelPointService.saveBatch(pointList);
|
||||
if (!result) {
|
||||
throw new ServiceException("批量新增光伏板桩点失败,数据库异常", HttpStatus.ERROR);
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(columnList)) {
|
||||
boolean result = photovoltaicPanelColumnService.saveBatch(columnList);
|
||||
if (!result) {
|
||||
throw new ServiceException("批量新增光伏板立柱失败,数据库异常", HttpStatus.ERROR);
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(supportList)) {
|
||||
boolean result = photovoltaicPanelSupportService.saveBatch(supportList);
|
||||
if (!result) {
|
||||
throw new ServiceException("批量新增光伏板支架失败,数据库异常", HttpStatus.ERROR);
|
||||
}
|
||||
}
|
||||
} catch (DataIntegrityViolationException e) {
|
||||
log.error("数据库唯一键冲突或违反其他完整性约束, 错误信息: {}", e.getMessage());
|
||||
throw new ServiceException("数据已存在,无法重复添加");
|
||||
} catch (DataAccessException e) {
|
||||
log.error("数据库连接问题、事务问题等导致操作失败, 错误信息: {}", e.getMessage());
|
||||
throw new ServiceException("数据库操作失败");
|
||||
} catch (Exception e) {
|
||||
// 捕获其他异常,做通用处理
|
||||
log.error("批量添加光伏板点时发生未知错误,错误信息: {}", e.getMessage());
|
||||
throw new ServiceException("批量添加光伏板点失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除设施-光伏板(桩点、立柱、支架)内部方法
|
||||
*
|
||||
* @param pointList 桩点列表
|
||||
* @param columnList 立柱列表
|
||||
* @param supportList 支架列表
|
||||
*/
|
||||
@Override
|
||||
public void batchDeletePartsInner(List<FacPhotovoltaicPanelPoint> pointList,
|
||||
List<FacPhotovoltaicPanelColumn> columnList,
|
||||
List<FacPhotovoltaicPanelSupport> supportList) {
|
||||
try {
|
||||
if (CollUtil.isNotEmpty(pointList)) {
|
||||
boolean result = photovoltaicPanelPointService.removeBatchByIds(pointList);
|
||||
if (!result) {
|
||||
throw new ServiceException("数据库操作失败", HttpStatus.ERROR);
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(columnList)) {
|
||||
boolean result = photovoltaicPanelColumnService.removeBatchByIds(columnList);
|
||||
if (!result) {
|
||||
throw new ServiceException("数据库操作失败", HttpStatus.ERROR);
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(supportList)) {
|
||||
boolean result = photovoltaicPanelSupportService.removeBatchByIds(supportList);
|
||||
if (!result) {
|
||||
throw new ServiceException("数据库操作失败", HttpStatus.ERROR);
|
||||
}
|
||||
}
|
||||
} catch (DataIntegrityViolationException e) {
|
||||
log.error("数据库唯一键冲突或违反其他完整性约束: {}", e.getMessage());
|
||||
throw new ServiceException("数据已存在,无法重复添加");
|
||||
} catch (DataAccessException e) {
|
||||
log.error("数据库连接问题、事务问题等导致操作失败: {}", e.getMessage());
|
||||
throw new ServiceException("数据库操作失败");
|
||||
} catch (Exception e) {
|
||||
// 捕获其他异常,做通用处理
|
||||
log.error("批量删除光伏板点时发生未知错误,错误信息: {}", e.getMessage());
|
||||
throw new ServiceException("批量添加光伏板点失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量新增设施-光伏板(桩点、立柱、支架)
|
||||
*
|
||||
|
@ -13,7 +13,6 @@ import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.facility.domain.FacMatrix;
|
||||
import org.dromara.facility.domain.FacPhotovoltaicPanel;
|
||||
import org.dromara.facility.domain.req.geojson.FeatureByPlane;
|
||||
import org.dromara.facility.domain.req.geojson.FeatureByPoint;
|
||||
@ -37,6 +36,9 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 设施-光伏板Service业务层处理
|
||||
@ -146,11 +148,22 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
|
||||
if (projectService.getById(projectId) == null) {
|
||||
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
List<FacMatrix> matrixList = matrixService.lambdaQuery()
|
||||
// todo 获取项目下方阵信息
|
||||
/* List<FacMatrix> matrixList = matrixService.lambdaQuery()
|
||||
.eq(FacMatrix::getProjectId, projectId).list();
|
||||
if (CollUtil.isEmpty(matrixList)) {
|
||||
throw new ServiceException("项目下无方阵数据,请先创建方阵消息后再添加光伏板信息", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}*/
|
||||
// 获取当下项目下光伏板的信息
|
||||
List<FacPhotovoltaicPanel> oldPhotovoltaicPanelList = this.lambdaQuery()
|
||||
.eq(FacPhotovoltaicPanel::getProjectId, projectId).list();
|
||||
Map<String, FacPhotovoltaicPanel> photovoltaicPanelMap = oldPhotovoltaicPanelList.stream()
|
||||
.collect(Collectors.toMap(
|
||||
FacPhotovoltaicPanel::getName,
|
||||
Function.identity(),
|
||||
(existing, replacement) -> existing // 如果有重复,保留第一个
|
||||
));
|
||||
// 获取数据库中光伏板信息
|
||||
List<FacPhotovoltaicPanel> photovoltaicPanelList = new ArrayList<>();
|
||||
List<FeatureByPlane> locationFeatures = geoJson.getLocationGeoJson().getFeatures();
|
||||
List<FeatureByPoint> nameFeatures = geoJson.getNameGeoJson().getFeatures();
|
||||
@ -158,8 +171,8 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
|
||||
FacPhotovoltaicPanel photovoltaicPanel = new FacPhotovoltaicPanel();
|
||||
GeometryByPlane geometry = locationFeature.getGeometry();
|
||||
List<List<Double>> coordinates = geometry.getCoordinates().get(0);
|
||||
// 判断光伏板在哪个方阵里
|
||||
Long matrixId = null;
|
||||
// todo 判断光伏板在哪个方阵里
|
||||
/* Long matrixId = null;
|
||||
for (FacMatrix matrix : matrixList) {
|
||||
String positions = matrix.getPositions();
|
||||
List<List<Double>> positionList = new ArrayList<>();
|
||||
@ -176,7 +189,8 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
|
||||
if (matrixId == null) {
|
||||
continue;
|
||||
}
|
||||
photovoltaicPanel.setMatrixId(matrixId);
|
||||
photovoltaicPanel.setMatrixId(matrixId);*/
|
||||
photovoltaicPanel.setMatrixId(1L);
|
||||
// 获取光伏板名称
|
||||
String name = null;
|
||||
for (FeatureByPoint nameFeature : nameFeatures) {
|
||||
@ -193,12 +207,28 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
|
||||
photovoltaicPanel.setName(name);
|
||||
photovoltaicPanel.setProjectId(projectId);
|
||||
photovoltaicPanel.setPositions(JSONUtil.toJsonStr(coordinates));
|
||||
// 如果有同名光伏板,则获取该光伏板的完成状态
|
||||
if (CollUtil.isNotEmpty(photovoltaicPanelMap) && photovoltaicPanelMap.containsKey(name)) {
|
||||
FacPhotovoltaicPanel oldPhotovoltaicPanel = photovoltaicPanelMap.get(name);
|
||||
photovoltaicPanel.setFinishType(oldPhotovoltaicPanel.getFinishType());
|
||||
photovoltaicPanel.setStatus(oldPhotovoltaicPanel.getStatus());
|
||||
}
|
||||
photovoltaicPanelList.add(photovoltaicPanel);
|
||||
}
|
||||
// 操作数据库,批量保存
|
||||
boolean save = this.saveBatch(photovoltaicPanelList);
|
||||
if (!save) {
|
||||
throw new ServiceException("新增光伏板失败,数据库异常", HttpStatus.ERROR);
|
||||
// 操作数据库
|
||||
// 删除旧数据
|
||||
if (CollUtil.isNotEmpty(oldPhotovoltaicPanelList)) {
|
||||
boolean result = this.removeBatchByIds(oldPhotovoltaicPanelList);
|
||||
if (!result) {
|
||||
throw new ServiceException("数据库操作失败", HttpStatus.ERROR);
|
||||
}
|
||||
}
|
||||
// 批量保存
|
||||
if (CollUtil.isNotEmpty(photovoltaicPanelList)) {
|
||||
boolean save = this.saveBatch(photovoltaicPanelList);
|
||||
if (!save) {
|
||||
throw new ServiceException("新增光伏板失败,数据库异常", HttpStatus.ERROR);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -101,8 +101,8 @@ public class BusProjectFileController extends BaseController {
|
||||
*/
|
||||
@Log(title = "项目文件存储", businessType = BusinessType.IMPORT)
|
||||
@PostMapping("/upload/dxf")
|
||||
public R<Void> uploadDxf2Json(@RequestParam("file") MultipartFile file, ProjectFileUploadDxfReq req) {
|
||||
return toAjax(busProjectFileService.uploadDxf2Json(file, req));
|
||||
public R<Long> uploadDxf2Json(@RequestParam("file") MultipartFile file, ProjectFileUploadDxfReq req) {
|
||||
return R.ok(busProjectFileService.uploadDxf2Json(file, req));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,11 +25,6 @@ public class ProjectFileUpdateReq implements Serializable {
|
||||
*/
|
||||
private Long projectId;
|
||||
|
||||
/**
|
||||
* 文件类型
|
||||
*/
|
||||
private String fileType;
|
||||
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
|
@ -81,7 +81,7 @@ public interface IBusProjectFileService extends IService<BusProjectFile> {
|
||||
* @param req 请求
|
||||
* @return 主键
|
||||
*/
|
||||
Boolean uploadDxf2Json(MultipartFile file, ProjectFileUploadDxfReq req);
|
||||
Long uploadDxf2Json(MultipartFile file, ProjectFileUploadDxfReq req);
|
||||
|
||||
/**
|
||||
* 获取项目文件存储视图对象
|
||||
|
@ -3,6 +3,7 @@ package org.dromara.project.service.impl;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.crypto.digest.MD5;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
@ -64,7 +65,7 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
|
||||
@Resource
|
||||
private ScheduledExecutorService scheduledExecutorService;
|
||||
|
||||
private static final ConcurrentHashMap<Long, Boolean> USER_TASK_RUNNING = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<String, Boolean> USER_TASK_RUNNING = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 查询项目文件存储
|
||||
@ -118,7 +119,7 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
|
||||
BusProjectFile projectFile = new BusProjectFile();
|
||||
BeanUtils.copyProperties(req, projectFile);
|
||||
// 数据校验
|
||||
validEntityBeforeSave(projectFile, false);
|
||||
validEntityBeforeSave(projectFile);
|
||||
// 判断是否存在
|
||||
BusProjectFile oldProjectFile = this.getById(projectFile.getId());
|
||||
if (oldProjectFile == null) {
|
||||
@ -135,15 +136,13 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(BusProjectFile entity, Boolean create) {
|
||||
private void validEntityBeforeSave(BusProjectFile entity) {
|
||||
// TODO 做一些数据校验,如唯一约束
|
||||
Long projectId = entity.getProjectId();
|
||||
if (create) {
|
||||
if (projectId == null) {
|
||||
throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
if (projectId == null) {
|
||||
throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
if (projectId != null && projectService.getById(projectId) == null) {
|
||||
if (projectService.getById(projectId) == null) {
|
||||
throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
@ -157,8 +156,12 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
List<BusProjectFile> projectFileList = this.listByIds(ids);
|
||||
if (isValid) {
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
List<Long> projectId = projectFileList.stream().map(BusProjectFile::getProjectId).toList();
|
||||
projectService.validAuth(projectId, userId);
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
@ -175,6 +178,15 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
|
||||
if (projectFile == null) {
|
||||
throw new ServiceException("对应项目文件存储信息不存在", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
Long userId = LoginHelper.getUserId();
|
||||
// 获取当前登录用户key值
|
||||
String string = String.valueOf(userId + projectFile.getProjectId());
|
||||
String md5 = MD5.create().digestHex16(string);
|
||||
// 判断当前用户是否已经有一个正在处理的任务
|
||||
Boolean alreadyRunning = USER_TASK_RUNNING.get(md5);
|
||||
if (alreadyRunning != null && alreadyRunning) {
|
||||
throw new ServiceException("正在转换,请稍后重试", HttpStatus.CONFLICT);
|
||||
}
|
||||
String filePath = projectFile.getFilePath();
|
||||
String suffix = FileUtil.getSuffix(FileUtil.getName(filePath));
|
||||
if (!suffix.equals(DesignMapFileConstant.JSONFileSuffix)) {
|
||||
@ -201,10 +213,13 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean uploadDxf2Json(MultipartFile file, ProjectFileUploadDxfReq req) {
|
||||
public Long uploadDxf2Json(MultipartFile file, ProjectFileUploadDxfReq req) {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
// 获取当前登录用户key值
|
||||
String string = String.valueOf(userId + req.getProjectId());
|
||||
String md5 = MD5.create().digestHex16(string);
|
||||
// 判断当前用户是否已经有一个正在处理的任务
|
||||
Boolean alreadyRunning = USER_TASK_RUNNING.putIfAbsent(userId, true);
|
||||
Boolean alreadyRunning = USER_TASK_RUNNING.putIfAbsent(md5, true);
|
||||
if (alreadyRunning != null && alreadyRunning) {
|
||||
throw new ServiceException("当前有一个正在处理的转换任务,请等待完成后再上传", HttpStatus.CONFLICT);
|
||||
}
|
||||
@ -228,10 +243,11 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
|
||||
String projectRoot = System.getProperty("user.dir");
|
||||
String bashPath = DesignMapFileConstant.getDxfProjectPath(projectId);
|
||||
String filePath = projectRoot + File.separator + bashPath;
|
||||
String uuid = IdUtil.fastSimpleUUID();
|
||||
if (!FileUtil.exist(filePath)) {
|
||||
FileUtil.mkdir(filePath);
|
||||
}
|
||||
String inputDXFPath = filePath + File.separator + fileName;
|
||||
String inputDXFPath = filePath + File.separator + uuid + "." + suffix;
|
||||
try {
|
||||
// 保存文件
|
||||
File savedFile = new File(inputDXFPath);
|
||||
@ -240,7 +256,6 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
|
||||
throw new ServiceException("dxf 文件保存失败");
|
||||
}
|
||||
// 构造 JSON 输出路径
|
||||
String uuid = IdUtil.fastSimpleUUID();
|
||||
String outputJSONPath = filePath + File.separator + uuid + "." + DesignMapFileConstant.JSONFileSuffix;
|
||||
// 获取 dxf2json.exe 路径
|
||||
String exePath = projectRoot + File.separator + DesignMapFileConstant.DXF_BASE_PATH + File.separator + "main.exe";
|
||||
@ -249,50 +264,66 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
|
||||
BusProjectFile oldProjectFile = this.lambdaQuery()
|
||||
.eq(BusProjectFile::getProjectId, projectId)
|
||||
.one();
|
||||
Long projectFileId;
|
||||
String dxfFilePath = bashPath + File.separator + uuid + "." + suffix;
|
||||
if (oldProjectFile != null) {
|
||||
// 删除之前的文件
|
||||
try {
|
||||
FileUtil.del(projectRoot + File.separator + oldProjectFile.getFilePath());
|
||||
FileUtil.del(projectRoot + File.separator + oldProjectFile.getRemark());
|
||||
} catch (Exception e) {
|
||||
log.error("删除项目文件失败", e);
|
||||
}
|
||||
projectFileId = oldProjectFile.getId();
|
||||
BusProjectFile projectFile = new BusProjectFile();
|
||||
projectFile.setId(projectFileId);
|
||||
projectFile.setFileName(fileName);
|
||||
projectFile.setRemark(dxfFilePath);
|
||||
boolean result = this.updateById(projectFile);
|
||||
if (!result) {
|
||||
throw new ServiceException("数据库更新异常");
|
||||
}
|
||||
} else {
|
||||
BusProjectFile projectFile = new BusProjectFile();
|
||||
projectFile.setProjectId(projectId);
|
||||
projectFile.setFileName(fileName);
|
||||
projectFile.setRemark(dxfFilePath);
|
||||
boolean save = this.save(projectFile);
|
||||
if (!save) {
|
||||
throw new ServiceException("数据库插入异常");
|
||||
}
|
||||
projectFileId = projectFile.getId();
|
||||
}
|
||||
SseMessageDto messageDto = new SseMessageDto();
|
||||
messageDto.setMessage("DXF 文件上传成功,正在转换中......");
|
||||
messageDto.setUserIds(List.of(userId));
|
||||
SseMessageUtils.publishMessage(messageDto);
|
||||
scheduledExecutorService.execute(() -> {
|
||||
try {
|
||||
// 构造命令行参数
|
||||
Dxf2JsonUtils.dxf2json(exePath, inputDXFPath, outputJSONPath, sourceEPSG, targetEPSG);
|
||||
String jsonFilePath = bashPath + File.separator + uuid + "." + DesignMapFileConstant.JSONFileSuffix;
|
||||
String jsonFileName = FileUtil.getPrefix(fileName) + "." + DesignMapFileConstant.JSONFileSuffix;
|
||||
// 修改数据库信息
|
||||
BusProjectFile projectFile = new BusProjectFile();
|
||||
if (oldProjectFile != null) {
|
||||
projectFile.setId(oldProjectFile.getId());
|
||||
projectFile.setFileName(jsonFileName);
|
||||
projectFile.setFilePath(jsonFilePath);
|
||||
boolean update = this.updateById(projectFile);
|
||||
if (!update) throw new ServiceException("数据库修改异常");
|
||||
} else {
|
||||
projectFile.setProjectId(projectId);
|
||||
projectFile.setFileName(jsonFileName);
|
||||
projectFile.setFilePath(jsonFilePath);
|
||||
boolean save = this.save(projectFile);
|
||||
if (!save) throw new ServiceException("数据库新增异常");
|
||||
}
|
||||
SseMessageDto dto = new SseMessageDto();
|
||||
dto.setMessage("DXF 文件转换成 GeoJSON 成功");
|
||||
dto.setUserIds(List.of(userId));
|
||||
SseMessageUtils.publishMessage(dto);
|
||||
projectFile.setId(projectFileId);
|
||||
projectFile.setFilePath(jsonFilePath);
|
||||
projectFile.setFileName(jsonFileName);
|
||||
projectFile.setFileType(DesignMapFileConstant.JSONFileSuffix);
|
||||
boolean update = this.updateById(projectFile);
|
||||
if (!update) throw new ServiceException("数据库修改异常");
|
||||
messageDto.setMessage("DXF 文件转换成 GeoJSON 成功");
|
||||
SseMessageUtils.publishMessage(messageDto);
|
||||
} catch (Exception e) {
|
||||
log.error("DXF 转换失败", e);
|
||||
SseMessageDto dto = new SseMessageDto();
|
||||
dto.setMessage("DXF 文件转换失败,请联系管理员处理");
|
||||
dto.setUserIds(List.of(userId));
|
||||
SseMessageUtils.publishMessage(dto);
|
||||
messageDto.setMessage("DXF 文件转换失败,请联系管理员处理");
|
||||
SseMessageUtils.publishMessage(messageDto);
|
||||
} finally {
|
||||
// 无论成功或失败都释放状态
|
||||
USER_TASK_RUNNING.remove(userId);
|
||||
USER_TASK_RUNNING.remove(md5);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
return projectFileId;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,14 +59,6 @@ public class Dxf2JsonUtils {
|
||||
reader.close();
|
||||
} catch (IOException | InterruptedException e) {
|
||||
log.error("执行 dxf 转 json 命令行时出错", e);
|
||||
}finally {
|
||||
// 删除dxf文件
|
||||
if (inputDXFFile.exists()) {
|
||||
boolean delete = inputDXFFile.delete();
|
||||
if (!delete) {
|
||||
log.error("dxf文件删除失败,路径:{}", inputDXFPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user