ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/DataStatisticsController.java
@@ -337,6 +337,9 @@ // 查询片区 List<TLocation> locationList = locationService.list(Wrappers.lambdaQuery(TLocation.class) .in(TLocation::getProjectId, query.getProjectId())); if (locationList.isEmpty()){ return R.ok(map); } List<String> locationTypeList = locationList.stream().map(TLocation::getLocationType).distinct().collect(Collectors.toList()); List<TLocationType> locationTypes = locationTypeService.list(Wrappers.lambdaQuery(TLocationType.class) .in(TLocationType::getId, locationTypeList)); ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TAppealController.java
@@ -161,9 +161,11 @@ appealDetailVO.setLocationIcon(byId2.getLocationIcon()); appealDetailVO.setLocationName(byId2.getLocationName()); appealDetailVO.setTaskId(byId.getId()); if (appeal.getAuditPerson()!=null){ SysUser sysUser = sysUserService.selectUserById(Long.valueOf(appeal.getAuditPerson())); if (sysUser!=null){ appealDetailVO.setAuditPersonName(sysUser.getUserName()); } } appealDetailVO.setTaskName(byId.getTaskName()); appealDetailVO.setTaskCode(byId.getTaskCode()); @@ -175,7 +177,8 @@ @ApiOperation(value = "审核申诉记录") @PostMapping(value = "/audit") public R<Boolean> audit(@RequestBody @Valid TAppealAuditDTO dto) { TTask task = taskCleanService.getById(dto.getTaskId()); TAppeal appeal = appealService.getById(dto.getId()); TTask task = taskCleanService.getById(appeal.getTaskId()); TLocation location = locationService.getById(task.getLocationId()); TNotice tNotice = new TNotice(); tNotice.setUserId(dto.getAppealPerson()); ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TInspectorController.java
@@ -1,25 +1,35 @@ package com.ruoyi.web.controller.api; import cn.afterturn.easypoi.excel.ExcelExportUtil; import cn.afterturn.easypoi.excel.entity.ExportParams; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.basic.PageInfo; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.WebUtils; import com.ruoyi.framework.web.service.TokenService; import com.ruoyi.system.model.TDept; import com.ruoyi.system.model.TLocation; import com.ruoyi.system.model.TProjectDept; import com.ruoyi.system.model.TTaskDetail; import com.ruoyi.system.query.InsepectorListQuery; import com.ruoyi.system.query.TaskListQuery; import com.ruoyi.system.service.*; import com.ruoyi.system.vo.system.InspectorListVO; import com.ruoyi.system.vo.system.TaskListVO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.apache.poi.ss.usermodel.Workbook; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URLEncoder; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -121,6 +131,103 @@ } return R.ok(inspectorService.pageList(query)); } @Log(title = "督察记录导出", businessType = BusinessType.EXPORT) @ApiOperation(value = "督察记录导出") @PostMapping(value = "/exportExcel") public void exportExcel(@RequestBody InsepectorListQuery query) { List<SysUser> sysUsers = sysUserService.selectAllList(); List<TLocation> locationList = locationService.list(); if (StringUtils.hasLength(query.getDeptName())){ List<String> projectIds = projectDeptService.lambdaQuery().like(TProjectDept::getProjectName, query.getDeptName()).list() .stream().map(TProjectDept::getId).collect(Collectors.toList()); List<String> deptIds = deptService.lambdaQuery().like(TDept::getDeptName, query.getDeptName()).list() .stream().map(TDept::getId).collect(Collectors.toList()); projectIds.addAll(deptIds); if (projectIds.isEmpty()){ projectIds.add("0") ; } if (StringUtils.hasLength(query.getPhonenumber())){ List<Long> patrolInspectorIds = sysUsers.stream().filter(sysUser -> sysUser.getPhonenumber().equals(query.getPhonenumber()) && projectIds.contains(sysUser.getDeptId()) ).map(SysUser::getUserId).collect(Collectors.toList()); if (patrolInspectorIds.isEmpty()){ patrolInspectorIds.add(0L) ; } query.setPatrolInspectorIds(patrolInspectorIds); } } if (StringUtils.hasLength(query.getPhonenumber())){ List<Long> patrolInspectorIds = sysUsers.stream().filter(sysUser -> sysUser.getPhonenumber().equals(query.getPhonenumber()) ).map(SysUser::getUserId).collect(Collectors.toList()); if (!query.getPatrolInspectorIds().isEmpty()){ // 取交集 patrolInspectorIds = patrolInspectorIds.stream().filter(query.getPatrolInspectorIds()::contains).collect(Collectors.toList()); } if (patrolInspectorIds.isEmpty()){ patrolInspectorIds.add(0L); } query.setPatrolInspectorIds(patrolInspectorIds); } if (query.getClearStatus()!=null){ List<String> collect = tTaskDetailService.lambdaQuery().eq(TTaskDetail::getClearStatus, query.getClearStatus()) .list().stream().distinct().map(TTaskDetail::getTaskId).collect(Collectors.toList()); if (collect.isEmpty()){ collect.add("-1"); } query.setTaskIds(collect); } if (query.getLocationType()!=null){ List<String> collect = locationList.stream().filter(e -> e.getLocationType().equals(query.getLocationType())).map(TLocation::getId) .collect(Collectors.toList()); if (collect.isEmpty()){ collect.add("-1"); } query.setLocationIds(collect); } if (StringUtils.hasLength(query.getLocationName())){ List<String> collect = locationList.stream().filter(e -> e.getLocationName().contains(query.getLocationName())).map(TLocation::getId) .collect(Collectors.toList()); if (collect.isEmpty()){ collect.add("-1"); query.setLocationIds(collect); }else{ collect = collect.stream().filter(query.getLocationIds()::contains).collect(Collectors.toList()); if (collect.isEmpty()){ collect.add("-1"); } query.setLocationIds(collect); } } List<InspectorListVO> inspectorListVOS = inspectorService.pageListExport(query); //1.获取excel模板 Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), InspectorListVO.class, inspectorListVOS); HttpServletResponse response = WebUtils.response(); response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); ServletOutputStream outputStream = null; try { String fileName = URLEncoder.encode("随机督察记录列表.xls", "utf-8"); response.setHeader("Content-dispodition", "attachment;filename=" + fileName); outputStream = response.getOutputStream(); workbook.write(outputStream); } catch (IOException e) { e.printStackTrace(); } finally { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } @Log(title = "批量删除督察任务", businessType = BusinessType.DELETE) @ApiOperation(value = "批量删除督察任务") @DeleteMapping(value = "/deleteByIds") ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/TTaskDetailController.java
@@ -1,6 +1,8 @@ package com.ruoyi.web.controller.api; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.domain.R; @@ -9,11 +11,16 @@ import com.ruoyi.system.dto.TTaskAuditBatchDTO; import com.ruoyi.system.dto.TaskDetailDto; import com.ruoyi.system.model.TAppeal; import com.ruoyi.system.model.TLocation; import com.ruoyi.system.model.TTask; import com.ruoyi.system.model.TTaskDetail; import com.ruoyi.system.service.TAppealService; import com.ruoyi.system.service.TLocationService; import com.ruoyi.system.service.TTaskCleanService; import com.ruoyi.system.service.TTaskDetailService; import com.ruoyi.web.controller.tool.AmapApiClient; import com.ruoyi.web.controller.tool.GeoChecker; import com.ruoyi.web.controller.tool.PathParser; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; @@ -24,6 +31,7 @@ import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -47,10 +55,46 @@ private TTaskCleanService taskService; @Autowired private TAppealService appealService; @Autowired private TLocationService locationService; @ApiOperation(value = "上传任务") @PostMapping(value = "/uploadTask") public R<Boolean> uploadTask(@RequestBody TaskDetailDto dto) { double radius = 50; // 单位:米 int segments = 4; // 四段,共 5 个点 TTask task = taskService.getById(dto.getTaskId()); if (task==null)return R.fail("任务不存在"); TLocation location = locationService.getById(task.getLocationId()); if (location==null)return R.fail("点位不存在"); try { String routeJson = AmapApiClient.getDrivingRoute(Double.parseDouble(location.getLocationLat()), Double.parseDouble(location.getLocationLon()), Double.parseDouble(location.getLocationLatEnd()), Double.parseDouble(location.getLocationLonEnd())); // 转化为json对象 JSONObject jsonObject = JSONObject.parseObject(routeJson); JSONObject route = jsonObject.getJSONObject("route"); JSONArray paths = route.getJSONArray("paths"); JSONObject o = (JSONObject)paths.get(0); BigDecimal distance = o.getBigDecimal("distance"); System.err.println( paths); List<double[]> fivePoints = PathParser.parseAndInterpolate(routeJson, segments, Double.parseDouble(location.getLocationLat()), Double.parseDouble(location.getLocationLon()), Double.parseDouble(location.getLocationLatEnd()), Double.parseDouble(location.getLocationLonEnd())); if (GeoChecker.isInAnyCircle(Double.parseDouble(dto.getLat()), Double.parseDouble(dto.getLon()), fivePoints, radius)) { System.out.println("✅ 成功!您位于某个圆形电子围栏范围内。"); } else { System.out.println("❌ 失败!您不在任何圆形电子围栏范围内。"); return R.fail("位置信息与点位不一致,请点击此处更新定位"); } } catch (Exception e) { e.printStackTrace(); } taskDetailService.save(dto); // 修改任务状态 taskService.update(Wrappers.<TTask>lambdaUpdate().set(TTask::getStatus, 3).eq(TTask::getId, dto.getTaskId())); ruoyi-applet/src/main/java/com/ruoyi/web/controller/tool/AmapApiClient.java
@@ -31,7 +31,7 @@ return response.body().string(); } } public Map<String, String> getDistance(String origins, String destination, Integer type) throws IOException { public static Map<String, String> getDistance(String origins, String destination, Integer type) throws IOException { String url = "https://restapi.amap.com/v3/distance?key=" + KEY + "&origins=" + origins + "&destination=" + destination + "&type=" + type; ruoyi-applet/src/main/java/com/ruoyi/web/controller/tool/GeoChecker.java
New file @@ -0,0 +1,15 @@ package com.ruoyi.web.controller.tool; import java.util.List; public class GeoChecker { public static boolean isInAnyCircle(double userLat, double userLon, List<double[]> circleCenters, double radius) { for (double[] center : circleCenters) { double distance = PathParser.calculateDistance(userLat, userLon, center[0], center[1]); if (distance <= radius) { return true; } } return false; } } ruoyi-applet/src/main/java/com/ruoyi/web/controller/tool/PathParser.java
New file @@ -0,0 +1,82 @@ package com.ruoyi.web.controller.tool; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; import java.util.List; public class PathParser { public static List<double[]> parseAndInterpolate(String jsonResponse, int segments,double startLat, double startLon, double endLat, double endLon) throws Exception { ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(jsonResponse); JsonNode steps = root.at("/route/paths/0/steps"); List<double[]> allPoints = new ArrayList<>(); allPoints.add(new double[]{startLat, startLon}); if (startLat==endLat&&startLon==endLon){ allPoints.add(new double[]{startLat, startLon}); }else{ for (JsonNode step : steps) { String polyline = step.get("polyline").asText(); String[] points = polyline.split(";"); for (String point : points) { String[] lonlat = point.split(","); double lon = Double.parseDouble(lonlat[0]); double lat = Double.parseDouble(lonlat[1]); allPoints.add(new double[]{lat, lon}); } } } allPoints.add(new double[]{endLat, endLon}); // 计算总距离 double totalDistance = 0; for (int i = 1; i < allPoints.size(); i++) { totalDistance += calculateDistance(allPoints.get(i - 1)[0], allPoints.get(i - 1)[1], allPoints.get(i)[0], allPoints.get(i)[1]); } // 均分距离 double segmentLength = totalDistance / segments; List<double[]> resultPoints = new ArrayList<>(); resultPoints.add(allPoints.get(0)); double accumulatedDistance = 0; int currentPointIndex = 0; for (int i = 1; i < segments; i++) { double targetDistance = i * segmentLength; while (accumulatedDistance < targetDistance && currentPointIndex < allPoints.size() - 1) { double[] p1 = allPoints.get(currentPointIndex); double[] p2 = allPoints.get(currentPointIndex + 1); double d = calculateDistance(p1[0], p1[1], p2[0], p2[1]); if (accumulatedDistance + d >= targetDistance) { double ratio = (targetDistance - accumulatedDistance) / d; double lat = p1[0] + ratio * (p2[0] - p1[0]); double lon = p1[1] + ratio * (p2[1] - p1[1]); resultPoints.add(new double[]{lat, lon}); accumulatedDistance = targetDistance; } else { accumulatedDistance += d; currentPointIndex++; } } } resultPoints.add(allPoints.get(allPoints.size() - 1)); return resultPoints; } public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) { double R = 6371000; // 地球半径单位米 double dLat = Math.toRadians(lat2 - lat1); double dLon = Math.toRadians(lon2 - lon1); double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return R * c; } } ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseModel.java
@@ -88,13 +88,7 @@ this.disabled = disabled; } public LocalDateTime getCreateTime() { return createTime; } public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; } public LocalDateTime getUpdateTime() { return updateTime; ruoyi-system/src/main/java/com/ruoyi/system/mapper/TInspectorMapper.java
@@ -21,4 +21,5 @@ public interface TInspectorMapper extends BaseMapper<TInspector> { List<InspectorListVO> pageList(@Param("query")InsepectorListQuery query, @Param("pageInfo")PageInfo<InspectorListVO> pageInfo); List<InspectorListVO> pageListExport(@Param("query")InsepectorListQuery query, @Param("pageInfo")PageInfo<InspectorListVO> pageInfo); } ruoyi-system/src/main/java/com/ruoyi/system/model/TInspector.java
@@ -1,7 +1,9 @@ package com.ruoyi.system.model; import cn.afterturn.easypoi.excel.annotation.Excel; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import com.ruoyi.common.core.domain.BaseModel; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -23,7 +25,7 @@ @EqualsAndHashCode(callSuper = false) @TableName("t_inspector") @ApiModel(value="TInspector对象", description="督察记录") public class TInspector extends BaseModel { public class TInspector implements Serializable { private static final long serialVersionUID = 1L; @@ -56,6 +58,7 @@ @ApiModelProperty(value = "状态1待确认 2待整改 3整改完成 4已完成") @TableField("status") @Excel(name = "执行状态", orderNum = "8", width = 20,replace = {"待确认","2_待整改","3_整改完成","4_已完成"}) private Integer status; @ApiModelProperty(value = "审核人id") @@ -65,6 +68,7 @@ @ApiModelProperty(value = "审核时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @TableField("audit_time") private LocalDateTime auditTime; @ApiModelProperty(value = "审核状态1通过2驳回") @@ -77,6 +81,36 @@ @ApiModelProperty(value = "提交人id") @TableField("commit_person") private String commitPerson; @ApiModelProperty(value = "记录创建人,前端忽略") @TableField(value = "create_by", fill = FieldFill.INSERT) private String createBy; /** * 新增和更新执行 */ @ApiModelProperty(value = "记录修改人,前端忽略") @TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE) private String updateBy; /** * 删除 未删除 */ @JsonIgnore @TableField("`disabled`") @TableLogic private Boolean disabled; @ApiModelProperty(value = "记录创建时间,前端忽略") @TableField("create_time") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @Excel(name = "任务时间", orderNum = "9", width = 30, exportFormat = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; /** * 最后修改时间 */ @ApiModelProperty(value = "记录修改时间,前端忽略") @TableField("update_time") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private LocalDateTime updateTime; } ruoyi-system/src/main/java/com/ruoyi/system/query/InsepectorListQuery.java
@@ -35,4 +35,6 @@ private Integer status; @ApiModelProperty(value = "用户id 前端忽略") private String userId; @ApiModelProperty(value = "督察记录ids 选中导出使用") private List<String> insepectorIds; } ruoyi-system/src/main/java/com/ruoyi/system/service/TInspectorService.java
@@ -7,6 +7,8 @@ import com.ruoyi.system.vo.system.InspectorListVO; import com.ruoyi.system.vo.system.TaskListVO; import java.util.List; /** * <p> * 督察记录 服务类 @@ -18,4 +20,5 @@ public interface TInspectorService extends IService<TInspector> { PageInfo<InspectorListVO> pageList(InsepectorListQuery query); List<InspectorListVO> pageListExport(InsepectorListQuery query); } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TInspectorServiceImpl.java
@@ -78,4 +78,43 @@ pageInfo.setRecords(list); return pageInfo; } public List<InspectorListVO> pageListExport(InsepectorListQuery query) { List<SysUser> sysUsers = sysUserMapper.selectAllList(); PageInfo<InspectorListVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); List<InspectorListVO> list = this.baseMapper.pageListExport(query,pageInfo); List<TTaskDetail> tTaskDetails = taskDetailMapper.selectList(new LambdaQueryWrapper<TTaskDetail>() .orderByDesc(BaseModel::getCreateTime) .in(TTaskDetail::getHandleType, Arrays.asList(1,4))); List<TTask> tTasks = taskMapper.selectList(null); for (InspectorListVO taskListVO : list) { TTask tTask = tTasks.stream().filter(e -> e.getId().equals(taskListVO.getTaskId())).findFirst().orElse(null); if (tTask!=null){ SysUser sysUser = sysUsers.stream().filter(e -> e.getUserId().equals(Long.valueOf(tTask.getPatrolInspector()))).findFirst().orElse(null); if (sysUser!=null){ if (sysUser.getDeptType()==2){ TDept tDept = deptMapper.selectById(tTask.getPatrolInspectorDept()); if (tDept!=null){ taskListVO.setDeptName(tDept.getDeptName()); } }else{ TProjectDept tProjectDept = projectDeptMapper.selectById(tTask.getPatrolInspectorDept()); if (tProjectDept!=null){ taskListVO.setDeptName(tProjectDept.getProjectName()); } } } TTaskDetail tTaskDetail = tTaskDetails.stream().filter(e -> e.getTaskId().equals(taskListVO.getId())).findFirst().orElse(null); if (tTaskDetail!=null){ taskListVO.setPicture(tTaskDetail.getPicture()); taskListVO.setClearStatus(tTaskDetail.getClearStatus()); } } } pageInfo.setRecords(list); return list; } } ruoyi-system/src/main/java/com/ruoyi/system/vo/system/InspectorListVO.java
@@ -1,5 +1,6 @@ package com.ruoyi.system.vo.system; import cn.afterturn.easypoi.excel.annotation.Excel; import com.ruoyi.system.model.TInspector; import com.ruoyi.system.model.TTask; import io.swagger.annotations.ApiModel; @@ -11,18 +12,31 @@ public class InspectorListVO extends TInspector { @ApiModelProperty(value = "点位名称") @Excel(name = "点位名称", orderNum = "1", width = 20) private String locationName; @ApiModelProperty(value = "点位类型名称") @Excel(name = "点位类型名称", orderNum = "2", width = 20) private String locationTypeName; @ApiModelProperty(value = "部门名称") @Excel(name = "部门名称", orderNum = "3", width = 20) private String deptName; @ApiModelProperty("巡查员名称") @Excel(name = "巡查员名称", orderNum = "4", width = 20) private String patrolInspectorName; @ApiModelProperty("电话") @Excel(name = "电话", orderNum = "5", width = 20) private String phonenumber; @ApiModelProperty("图片 多个逗号拼接") @Excel(name = "图片", orderNum = "6", width = 20) private String picture; @ApiModelProperty(value = "清洁情况 1合格2不合格") @Excel(name = "清洁情况 1合格2不合格", orderNum = "7", width = 20,replace = {"1_合格","2_不合格"}) private Integer clearStatus; } ruoyi-system/src/main/resources/mapper/system/TInspectorMapper.xml
@@ -65,5 +65,49 @@ and (t5.implement_time between #{startTime} and #{endTime}) </if> </select> <select id="pageListExport" resultType="com.ruoyi.system.vo.system.InspectorListVO"> select t1.*,t2.location_name as locationName,t3.location_name as locationTypeName, t4.nick_name as patrolInspectorName, t4.phonenumber as phonenumber from t_inspector t1 left join t_task t5 on t5.id = t1.task_id left join t_location t2 on t5.location_id = t2.id left join t_location_type t3 on t2.location_type = t3.id left join sys_user t4 on t5.patrol_inspector = t4.user_id where 1=1 and t1.`disabled` = ${@com.ruoyi.common.enums.DisabledEnum@NO.getCode()} <if test="query.patrolInspectorIds != null and query.patrolInspectorIds.size()>0"> AND t4.user_id IN <foreach collection="query.patrolInspectorIds" separator="," item="id" open="(" close=")"> #{id} </foreach> </if> <if test="query.taskIds != null and query.taskIds.size()>0"> AND t1.task_id IN <foreach collection="query.taskIds" separator="," item="id" open="(" close=")"> #{id} </foreach> </if> <if test="query.locationIds != null and query.locationIds.size()>0"> AND t5.location_id IN <foreach collection="query.locationIds" separator="," item="id" open="(" close=")"> #{id} </foreach> </if> <if test="query.insepectorIds != null and query.insepectorIds.size()>0"> AND t1.id IN <foreach collection="query.insepectorIds" separator="," item="id" open="(" close=")"> #{id} </foreach> </if> <if test="query.status != null"> and t1.status = #{query.status} </if> <if test="query.startTime != null and startTime != ''"> and (t5.implement_time between #{startTime} and #{endTime}) </if> </select> </mapper>