54 changed files with 941 additions and 168 deletions
@ -0,0 +1,26 @@ |
|||
package com.jiagutech.ams.utils; |
|||
|
|||
import java.nio.ByteBuffer; |
|||
import java.util.Base64; |
|||
import java.util.UUID; |
|||
|
|||
public class TraceIdUtil { |
|||
private static final ThreadLocal<String> TRACE_ID = new InheritableThreadLocal<>(); |
|||
|
|||
public static void setTraceId(String traceId) { |
|||
TRACE_ID.set(traceId); |
|||
} |
|||
|
|||
public static String getTraceId() { |
|||
return TRACE_ID.get(); |
|||
} |
|||
|
|||
public static void clear() { |
|||
TRACE_ID.remove(); |
|||
} |
|||
|
|||
public static String generateTraceId() { |
|||
UUID uuid = UUID.randomUUID(); |
|||
return Long.toHexString(uuid.getMostSignificantBits()); |
|||
} |
|||
} |
@ -1,4 +1,4 @@ |
|||
package com.jiagutech.ams.model; |
|||
package com.jiagutech.ams.model.mapping; |
|||
|
|||
import com.jiagutech.ams.model.dto.DeviceDTO; |
|||
import com.jiagutech.ams.model.response.DeviceInfo; |
@ -1,4 +1,4 @@ |
|||
package com.jiagutech.ams.model; |
|||
package com.jiagutech.ams.model.mapping; |
|||
|
|||
import com.jiagutech.ams.model.dto.JobDTO; |
|||
import com.jiagutech.ams.model.request.JobCreateRequest; |
@ -1,5 +1,6 @@ |
|||
package com.jiagutech.ams.model; |
|||
package com.jiagutech.ams.model.mapping; |
|||
|
|||
import com.jiagutech.ams.model.UavSortie; |
|||
import com.jiagutech.ams.model.dto.SortieDTO; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.Mapping; |
@ -1,5 +1,6 @@ |
|||
package com.jiagutech.ams.model; |
|||
package com.jiagutech.ams.model.mapping; |
|||
|
|||
import com.jiagutech.ams.model.TrackImageVO; |
|||
import com.jiagutech.ams.model.request.MachImage; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.factory.Mappers; |
@ -1,5 +1,9 @@ |
|||
package com.jiagutech.ams.model; |
|||
package com.jiagutech.ams.model.mapping; |
|||
|
|||
import com.jiagutech.ams.model.Locus; |
|||
import com.jiagutech.ams.model.TrackImageVO; |
|||
import com.jiagutech.ams.model.TrackItem; |
|||
import com.jiagutech.ams.model.ZhongNongTrack; |
|||
import com.jiagutech.ams.model.dto.TrackImageDTO; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.Mapping; |
@ -0,0 +1,15 @@ |
|||
package com.jiagutech.ams.model.request; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
@Schema(name = "设备列表请求条件") |
|||
public class DeviceRequest { |
|||
@Schema(description = "区域编码") |
|||
private Long regionCode; |
|||
@Schema(description = "合作社ID") |
|||
private Integer deptId; |
|||
@Schema(description = "设备车牌") |
|||
private String licensePlate; |
|||
} |
@ -0,0 +1,39 @@ |
|||
package com.jiagutech.ams.model.request; |
|||
|
|||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; |
|||
import com.jiagutech.ams.utils.StringToLongDeserializer; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Data |
|||
@Schema(name = "切分作业请求") |
|||
public class JobSegmentRequest { |
|||
|
|||
@Schema(description = "原始作业ID", example = "123456789") |
|||
@JsonDeserialize(using = StringToLongDeserializer.class) |
|||
private long originalJobId; |
|||
@Schema(description = "切分作业内容") |
|||
private List<JobSegment> segments; |
|||
|
|||
@Data |
|||
@Schema(name = "切分作业内容") |
|||
public static class JobSegment { |
|||
@Schema(description = "作业开始时间", example = "123456789") |
|||
private Long startTime; |
|||
@Schema(description = "作业结束时间", example = "123456789") |
|||
private Long endTime; |
|||
|
|||
|
|||
@Schema(description = "操作员ID", example = "123456789") |
|||
@JsonDeserialize(using = StringToLongDeserializer.class) |
|||
private long operatorId; |
|||
|
|||
@Schema(description = "农户ID", example = "123456789") |
|||
@JsonDeserialize(using = StringToLongDeserializer.class) |
|||
private long farmerId; |
|||
// @Schema(description = "地块面积", example = "123456789")
|
|||
// private Float area;
|
|||
} |
|||
} |
@ -0,0 +1,12 @@ |
|||
package com.jiagutech.ams.model.response; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
public class ChartItem { |
|||
private Long code; |
|||
private String name; |
|||
private Integer count; |
|||
} |
@ -0,0 +1,13 @@ |
|||
package com.jiagutech.ams.model.response; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
public class ChartMultiItem { |
|||
private Long code; |
|||
private String name; |
|||
private Integer count; |
|||
private Float value; |
|||
} |
@ -0,0 +1,131 @@ |
|||
package com.jiagutech.ams.utils; |
|||
|
|||
import com.jiagutech.ams.model.TrackItem; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.locationtech.jts.geom.Coordinate; |
|||
import org.locationtech.jts.geom.GeometryFactory; |
|||
import org.locationtech.jts.geom.Point; |
|||
import org.locationtech.proj4j.BasicCoordinateTransform; |
|||
import org.locationtech.proj4j.CRSFactory; |
|||
import org.locationtech.proj4j.CoordinateReferenceSystem; |
|||
import org.locationtech.proj4j.ProjCoordinate; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.math.RoundingMode; |
|||
import java.util.ArrayList; |
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
|
|||
@Slf4j |
|||
public class Pro4jUtil { |
|||
|
|||
|
|||
/** |
|||
* 计算地理多边形的面积 |
|||
* |
|||
* @param polygonLatLon 多边形顶点的经纬度数组,格式:{{纬度1, 经度1}, {纬度2, 经度2}, ...} |
|||
* @param targetEPSG 平面投影的 EPSG 编号,例如 "EPSG:32633" 表示 UTM Zone 33N |
|||
* @return 多边形面积,单位为平方米 |
|||
*/ |
|||
public static double calculatePolygonArea(double[][] polygonLatLon, String sourceEPSG, String targetEPSG) { |
|||
// 1. 初始化投影系统
|
|||
CRSFactory crsFactory = new CRSFactory(); |
|||
CoordinateReferenceSystem sourceCRS = crsFactory.createFromName(sourceEPSG); |
|||
CoordinateReferenceSystem targetCRS = crsFactory.createFromName(targetEPSG); // 平面投影
|
|||
log.info("sourceCRS: {}, targetCRS: {}", sourceCRS, targetCRS); |
|||
// 2. 初始化坐标转换器
|
|||
BasicCoordinateTransform transform = new BasicCoordinateTransform(sourceCRS, targetCRS); |
|||
|
|||
// 3. 转换多边形的经纬度为平面坐标
|
|||
ProjCoordinate srcCoord = new ProjCoordinate(); |
|||
ProjCoordinate destCoord = new ProjCoordinate(); |
|||
double[][] polygonXY = new double[polygonLatLon.length][2]; |
|||
|
|||
for (int i = 0; i < polygonLatLon.length; i++) { |
|||
srcCoord.x = polygonLatLon[i][1]; // 经度
|
|||
srcCoord.y = polygonLatLon[i][0]; // 纬度
|
|||
transform.transform(srcCoord, destCoord); |
|||
polygonXY[i][0] = destCoord.x; |
|||
polygonXY[i][1] = destCoord.y; |
|||
} |
|||
// 4. 确保多边形闭合
|
|||
if (!Arrays.equals(polygonXY[0], polygonXY[polygonXY.length - 1])) { |
|||
polygonXY = Arrays.copyOf(polygonXY, polygonXY.length + 1); |
|||
polygonXY[polygonXY.length - 1] = polygonXY[0]; |
|||
} |
|||
|
|||
// 4. 计算多边形面积
|
|||
return calculateAreaFromXY(polygonXY); |
|||
} |
|||
|
|||
/** |
|||
* 使用 Shoelace 公式计算平面多边形的面积 |
|||
* |
|||
* @param polygonXY 多边形顶点的平面坐标数组,格式:{{x1, y1}, {x2, y2}, ...} |
|||
* @return 多边形面积,单位与坐标单位一致 |
|||
*/ |
|||
private static double calculateAreaFromXY(double[][] polygonXY) { |
|||
double area = 0.0; |
|||
int n = polygonXY.length; |
|||
|
|||
for (int i = 0; i < n - 1; i++) { |
|||
area += polygonXY[i][0] * polygonXY[i + 1][1] - polygonXY[i + 1][0] * polygonXY[i][1]; |
|||
} |
|||
area = Math.abs(area) / 2.0; |
|||
return area; |
|||
} |
|||
|
|||
public static float calculateAreaByCGCS2000(List<TrackItem> trackItemList) { |
|||
|
|||
double[][] polygonLatLon = new double[trackItemList.size()][2]; |
|||
for (int i = 0; i < trackItemList.size(); i++) { |
|||
polygonLatLon[i][0] = trackItemList.get(i).getLat(); |
|||
polygonLatLon[i][1] = trackItemList.get(i).getLng(); |
|||
} |
|||
double area = calculatePolygonArea(polygonLatLon, "EPSG:4490", "EPSG:4543"); |
|||
area = area * 0.0015; |
|||
|
|||
BigDecimal b = new BigDecimal(area); |
|||
return b.setScale(2, RoundingMode.HALF_UP).floatValue(); |
|||
|
|||
} |
|||
|
|||
public static double haversineDistance(double lat1, double lon1, double lat2, double lon2) { |
|||
GeometryFactory geometryFactory = new GeometryFactory(); |
|||
|
|||
Coordinate coord1 = fromLatLngToPoint(lat1, lon1); |
|||
Coordinate coord2 = fromLatLngToPoint(lat2, lon2); |
|||
|
|||
Point point1 = geometryFactory.createPoint(coord1); |
|||
Point point2 = geometryFactory.createPoint(coord2); |
|||
|
|||
return point1.distance(point2); |
|||
} |
|||
|
|||
private static final double DEG_TO_RAD = Math.PI / 180; |
|||
|
|||
public static Coordinate fromLatLngToPoint(double lat, double lng) { |
|||
double x = lng * 20037508.34 / 180; |
|||
double y = Math.log(Math.tan((90 + lat) * DEG_TO_RAD / 2)) / DEG_TO_RAD; |
|||
y = y * 20037508.34 / 180; |
|||
return new Coordinate(x, y); |
|||
} |
|||
|
|||
public static List<TrackItem> removeStationaryPoints(List<TrackItem> points, double threshold) { |
|||
List<TrackItem> filteredPoints = new ArrayList<>(); |
|||
filteredPoints.add(points.get(0)); |
|||
|
|||
for (int i = 1; i < points.size(); i++) { |
|||
TrackItem previousPoint = points.get(i - 1); |
|||
TrackItem currentPoint = points.get(i); |
|||
|
|||
double distance = haversineDistance(previousPoint.getLat(), previousPoint.getLng(), currentPoint.getLat(), currentPoint.getLng()); |
|||
|
|||
if (distance >= threshold) { |
|||
filteredPoints.add(currentPoint); |
|||
} |
|||
} |
|||
|
|||
return filteredPoints; |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
package com.jiagutech.ams.model.request; |
|||
|
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class DeptAddRequest { |
|||
|
|||
/** |
|||
* 合作社名称 |
|||
*/ |
|||
private String deptName; |
|||
/** |
|||
* 合作社负责人ID |
|||
*/ |
|||
private String managerName ; |
|||
|
|||
private String managerPhone; |
|||
|
|||
private String managerPassword; |
|||
|
|||
} |
@ -0,0 +1,17 @@ |
|||
package com.jiagutech.ams.model.request; |
|||
|
|||
import jakarta.validation.constraints.Pattern; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class FarmerAddRequest { |
|||
|
|||
private String nickName; |
|||
@Pattern(regexp = "^1[34578]\\d{9}$", message = "手机号码格式不正确") |
|||
private String phone; |
|||
|
|||
private String identityCardNum; |
|||
|
|||
private Long regionCode; |
|||
|
|||
} |
@ -1,42 +0,0 @@ |
|||
package com.jiagutech.ams.service; |
|||
|
|||
import cn.dev33.satoken.stp.StpUtil; |
|||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import com.jiagutech.ams.constant.UserConstants; |
|||
import com.jiagutech.ams.mapper.DeptMapper; |
|||
import com.jiagutech.ams.model.DeptItem; |
|||
import com.jiagutech.ams.model.LoginUser; |
|||
import com.jiagutech.ams.model.common.PageRequest; |
|||
import com.jiagutech.ams.model.common.PageResult; |
|||
import com.jiagutech.ams.model.request.DeptPageRequest; |
|||
import com.jiagutech.ams.utils.LoginUtil; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
/** |
|||
* @ClassName DeptServcieImpl |
|||
* @author: zhangyeguang |
|||
* @create: 2024-09-02 17:35 |
|||
* @Version 1.0 |
|||
* @description: |
|||
**/ |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
public class DeptServcieImpl implements DeptService { |
|||
private final DeptMapper deptMapper; |
|||
@Override |
|||
public PageResult<DeptItem> selectPage(PageRequest<DeptPageRequest> pageRequest) { |
|||
|
|||
DeptPageRequest requestParam = pageRequest.getRequest(); |
|||
Page<DeptItem> page = new Page(pageRequest.getPageNum(), pageRequest.getPageSize()); |
|||
LoginUser loginUser = LoginUtil.getLoginUser(); |
|||
|
|||
Page<DeptItem> result = deptMapper.deptPage(page,requestParam!=null ?requestParam.getDeptName():null, loginUser.getRegionPath()); |
|||
return PageResult.of((int) result.getTotal(), (int) result.getSize(), (int) result.getCurrent(), result.getRecords()); |
|||
|
|||
} |
|||
|
|||
|
|||
|
|||
} |
@ -0,0 +1,75 @@ |
|||
package com.jiagutech.ams.service; |
|||
|
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import com.jiagutech.ams.mapper.DeptMapper; |
|||
import com.jiagutech.ams.mapper.UserDeptMapper; |
|||
import com.jiagutech.ams.mapper.UserMapper; |
|||
import com.jiagutech.ams.model.DeptItem; |
|||
import com.jiagutech.ams.model.LoginUser; |
|||
import com.jiagutech.ams.model.common.PageRequest; |
|||
import com.jiagutech.ams.model.common.PageResult; |
|||
import com.jiagutech.ams.model.dto.DeptDTO; |
|||
import com.jiagutech.ams.model.dto.UserDTO; |
|||
import com.jiagutech.ams.model.dto.UserDeptDTO; |
|||
import com.jiagutech.ams.model.request.DeptAddRequest; |
|||
import com.jiagutech.ams.model.request.DeptPageRequest; |
|||
import com.jiagutech.ams.utils.LoginUtil; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.transaction.annotation.Transactional; |
|||
|
|||
/** |
|||
* @author zhangyeguang |
|||
* @version 1.0 |
|||
* @ClassName DeptServcieImpl |
|||
* @create: 2024-09-02 17:35 |
|||
* @description: |
|||
**/ |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
public class DeptServiceImpl implements DeptService { |
|||
private final DeptMapper deptMapper; |
|||
private final UserDeptMapper userDeptMapper; |
|||
private final UserMapper userMapper; |
|||
|
|||
@Override |
|||
public PageResult<DeptItem> selectPage(PageRequest<DeptPageRequest> pageRequest) { |
|||
|
|||
DeptPageRequest requestParam = pageRequest.getRequest(); |
|||
Page<DeptItem> page = new Page(pageRequest.getPageNum(), pageRequest.getPageSize()); |
|||
LoginUser loginUser = LoginUtil.getLoginUser(); |
|||
|
|||
Page<DeptItem> result = deptMapper.deptPage(page, requestParam != null ? requestParam.getDeptName() : null, loginUser.getRegionPath()); |
|||
return PageResult.of((int) result.getTotal(), (int) result.getSize(), (int) result.getCurrent(), result.getRecords()); |
|||
|
|||
} |
|||
|
|||
@Override |
|||
@Transactional |
|||
public Boolean add(DeptAddRequest deptAddRequest) { |
|||
LoginUser loginUser = LoginUtil.getLoginUser(); |
|||
assert loginUser != null; |
|||
|
|||
DeptDTO deptDTO = new DeptDTO().setName(deptAddRequest.getDeptName()) |
|||
.setRegionCode(loginUser.getRegionCode()) |
|||
.setRegionPath(loginUser.getRegionPath()); |
|||
int row = deptMapper.insert(deptDTO); |
|||
if (row > 0) { |
|||
UserDTO userDTO = new UserDTO(); |
|||
userDTO.setPassword(deptAddRequest.getManagerPassword()); |
|||
userDTO.setNickName(deptAddRequest.getManagerName()); |
|||
userDTO.setPhone(deptAddRequest.getManagerPhone()); |
|||
int insert = userMapper.insert(userDTO); |
|||
if (insert > 0) { |
|||
UserDeptDTO userDeptDTO = new UserDeptDTO(); |
|||
userDeptDTO.setDeptId(deptDTO.getId()); |
|||
userDeptDTO.setUserId(userDTO.getId()); |
|||
userDeptMapper.insert(userDeptDTO); |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,46 @@ |
|||
package com.jiagutech.ams.config; |
|||
|
|||
import com.jiagutech.ams.utils.TraceIdUtil; |
|||
import jakarta.servlet.http.HttpServletRequest; |
|||
import jakarta.servlet.http.HttpServletResponse; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.jetbrains.annotations.NotNull; |
|||
import org.slf4j.MDC; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.util.StopWatch; |
|||
import org.springframework.web.servlet.HandlerInterceptor; |
|||
import org.springframework.web.servlet.ModelAndView; |
|||
|
|||
@Slf4j |
|||
@Component |
|||
public class CommonInterceptor implements HandlerInterceptor { |
|||
|
|||
|
|||
@Override |
|||
public boolean preHandle(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception { |
|||
StopWatch stopWatch = new StopWatch(); |
|||
stopWatch.start(); |
|||
request.setAttribute("stopWatch", stopWatch); |
|||
String traceId = TraceIdUtil.generateTraceId(); |
|||
TraceIdUtil.setTraceId(traceId); |
|||
|
|||
// 将 traceId 放入 MDC,供日志打印
|
|||
MDC.put("traceId", traceId); |
|||
return true; |
|||
} |
|||
|
|||
@Override |
|||
public void postHandle(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, ModelAndView modelAndView) throws Exception { |
|||
StopWatch stopWatch = (StopWatch) request.getAttribute("stopWatch"); |
|||
stopWatch.stop(); |
|||
log.info("path={}处理完成,耗时={}ms", request.getRequestURI(), stopWatch.getTotalTimeMillis()); |
|||
TraceIdUtil.clear(); |
|||
MDC.remove("traceId"); |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public void afterCompletion(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, Exception ex) throws Exception { |
|||
HandlerInterceptor.super.afterCompletion(request, response, handler, ex); |
|||
} |
|||
} |
@ -1,16 +1,21 @@ |
|||
package com.jiagutech.ams.config; |
|||
|
|||
import cn.dev33.satoken.interceptor.SaInterceptor; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; |
|||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
|||
|
|||
@Configuration |
|||
public class SaTokenConfigure implements WebMvcConfigurer { |
|||
// 注册 Sa-Token 拦截器,打开注解式鉴权功能
|
|||
@Autowired |
|||
private CommonInterceptor commonInterceptor; |
|||
|
|||
// 注册 Sa-Token 拦截器,打开注解式鉴权功能
|
|||
@Override |
|||
public void addInterceptors(InterceptorRegistry registry) { |
|||
// 注册 Sa-Token 拦截器,打开注解式鉴权功能
|
|||
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**"); |
|||
registry.addInterceptor(new SaInterceptor()).order(10).addPathPatterns("/**"); |
|||
registry.addInterceptor(commonInterceptor).order(-999).addPathPatterns("/**"); |
|||
} |
|||
} |
|||
|
Loading…
Reference in new issue