无人机使用率+任务执行平均周期等

This commit is contained in:
温文静WWW 2025-07-17 23:10:19 +08:00
parent 6bb01e0e27
commit d673362a77
10 changed files with 143 additions and 34 deletions

View File

@ -53,7 +53,7 @@ public class CpTextController {
@Autowired @Autowired
private CpTextMapper cpTextMapper; private CpTextMapper cpTextMapper;
// @AnonymousAccess @AnonymousAccess
@ApiOperation(value = "分页查询文本内容", notes = "分页查询文本内容") @ApiOperation(value = "分页查询文本内容", notes = "分页查询文本内容")
@RequestMapping(method = RequestMethod.GET) @RequestMapping(method = RequestMethod.GET)
@ApiImplicitParams({ @ApiImplicitParams({

View File

@ -61,8 +61,6 @@ public class OrderDetailAnalysisController {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
} }
} }
@ApiOperation("按日范围分析子单任务") @ApiOperation("按日范围分析子单任务")
@GetMapping("/day") @GetMapping("/day")
// 额外返回时间范围内任务列表 // 额外返回时间范围内任务列表

View File

@ -1,5 +1,6 @@
package com.aircraft.modules.order.domain; package com.aircraft.modules.order.domain;
import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.aircraft.base.BaseEntity; import com.aircraft.base.BaseEntity;
@ -8,6 +9,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime;
/** /**
* <p> * <p>

View File

@ -6,5 +6,7 @@ import lombok.Data;
@Data @Data
public class DailyStat { public class DailyStat {
private String date; private String date;
private Long dailyCount;//每日数量 private Long dailyTotalCount;//每日总数量
private Long dailyCompletedCount;//每日完成数量
private Long dailyFailedCount;//每日失败数量
} }

View File

@ -5,5 +5,7 @@ import lombok.Data;
@Data @Data
public class MonthlyStat { public class MonthlyStat {
private String month; private String month;
private Long monthlyCount;//每月数量 private Long monthlyTotalCount;//每月数量
private Long monthlyCompletedCount;//每月完成数量
private Long monthlyFailedCount;//每月失败数量
} }

View File

@ -19,7 +19,7 @@ public class OrderDetailAnalysisResult<T> {
private BigDecimal failedRate; // 任务失败率 private BigDecimal failedRate; // 任务失败率
private Double averageTaskCycle; // 平均任务周期 private Double averageTaskCycle; // 平均任务周期
private BigDecimal droneUsageRate; // 无人机使用率 private BigDecimal droneUsageRate; // 今日无人机使用率
private List<RouteStat> routeDistribution; // 景区路线统计分布 private List<RouteStat> routeDistribution; // 景区路线统计分布
private PageInfo pageInfo; // 分页信息 private PageInfo pageInfo; // 分页信息

View File

@ -5,5 +5,7 @@ import lombok.Data;
@Data @Data
public class QuarterlyStat { public class QuarterlyStat {
private String quarter; // 季度标识如2025-Q1 private String quarter; // 季度标识如2025-Q1
private Long QuarterlyCount; // 每季度数量 private Long quarterlyTotalCount; // 每季度数量
private Long quarterlyCompletedCount;//每季完成数量
private Long quarterlyFailedCount;//每季失败数量
} }

View File

@ -5,5 +5,7 @@ import lombok.Data;
@Data @Data
public class YearlyStat { public class YearlyStat {
private String year; private String year;
private Long yearlyCount; private Long yearlyTotalCount;//每年总数量
private Long yearlyCompletedCount;//每年完成数量
private Long yearlyFailedCount;//每年失败数量
} }

View File

@ -88,7 +88,7 @@ public class OrderAnalysisServiceImpl implements OrderAnalysisService {
String dateStr = current.format(DAY_FORMATTER); String dateStr = current.format(DAY_FORMATTER);
DailyStat stat = new DailyStat(); DailyStat stat = new DailyStat();
stat.setDate(dateStr); stat.setDate(dateStr);
stat.setDailyCount(dailyCountMap.getOrDefault(dateStr, 0L)); stat.setDailyTotalCount(dailyCountMap.getOrDefault(dateStr, 0L));
dailyStats.add(stat); dailyStats.add(stat);
current = current.plusDays(1); // 移至下一天 current = current.plusDays(1); // 移至下一天
} }
@ -128,7 +128,7 @@ public class OrderAnalysisServiceImpl implements OrderAnalysisService {
String monthStr = current.format(MONTH_FORMATTER); String monthStr = current.format(MONTH_FORMATTER);
MonthlyStat stat = new MonthlyStat(); MonthlyStat stat = new MonthlyStat();
stat.setMonth(monthStr); stat.setMonth(monthStr);
stat.setMonthlyCount(monthlyCountMap.getOrDefault(monthStr, 0L)); stat.setMonthlyTotalCount(monthlyCountMap.getOrDefault(monthStr, 0L));
monthlyStats.add(stat); monthlyStats.add(stat);
current = current.plusMonths(1); // 移至下一月 current = current.plusMonths(1); // 移至下一月
} }
@ -175,7 +175,7 @@ public class OrderAnalysisServiceImpl implements OrderAnalysisService {
QuarterlyStat stat = new QuarterlyStat(); QuarterlyStat stat = new QuarterlyStat();
stat.setQuarter(quarterStr); stat.setQuarter(quarterStr);
stat.setQuarterlyCount(quarterCountMap.getOrDefault(quarterStr, 0L)); stat.setQuarterlyTotalCount(quarterCountMap.getOrDefault(quarterStr, 0L));
quarterlyStats.add(stat); quarterlyStats.add(stat);
// 移至下一季度第一天 // 移至下一季度第一天
@ -216,7 +216,7 @@ public class OrderAnalysisServiceImpl implements OrderAnalysisService {
String yearStr = String.valueOf(year); String yearStr = String.valueOf(year);
YearlyStat stat = new YearlyStat(); YearlyStat stat = new YearlyStat();
stat.setYear(yearStr); stat.setYear(yearStr);
stat.setYearlyCount(yearCountMap.getOrDefault(yearStr, 0L)); stat.setYearlyTotalCount(yearCountMap.getOrDefault(yearStr, 0L));
yearlyStats.add(stat); yearlyStats.add(stat);
} }

View File

@ -6,6 +6,7 @@ import com.aircraft.modules.order.controller.OrderAnalysisController;
import com.aircraft.modules.order.domain.OrderDetail; import com.aircraft.modules.order.domain.OrderDetail;
import com.aircraft.modules.order.domain.dto.*; import com.aircraft.modules.order.domain.dto.*;
import com.aircraft.modules.order.mapper.OrderDetailMapper; import com.aircraft.modules.order.mapper.OrderDetailMapper;
import com.aircraft.modules.order.service.IOrderDetailService;
import com.aircraft.modules.order.service.OrderDetailAnalysisService; import com.aircraft.modules.order.service.OrderDetailAnalysisService;
import com.aircraft.modules.route.domain.CpRoute; import com.aircraft.modules.route.domain.CpRoute;
import com.aircraft.modules.route.mapper.CpRouteMapper; import com.aircraft.modules.route.mapper.CpRouteMapper;
@ -21,10 +22,7 @@ import org.springframework.util.CollectionUtils;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.time.Duration; import java.time.*;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal; import java.time.temporal.Temporal;
import java.util.*; import java.util.*;
@ -55,6 +53,8 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
private EmScenicMapper emScenicMapper; private EmScenicMapper emScenicMapper;
@Autowired @Autowired
private AircraftDeviceService aircraftDeviceService; private AircraftDeviceService aircraftDeviceService;
@Autowired
private IOrderDetailService orderDetailService;
@Override @Override
public OrderDetailAnalysisResult<T> analyzeAllOrderDetails(List<OrderDetail> allDetails) { public OrderDetailAnalysisResult<T> analyzeAllOrderDetails(List<OrderDetail> allDetails) {
@ -69,30 +69,36 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
return buildEmptyResult(); return buildEmptyResult();
} }
// 2. 按日分组统计每日订单量 // 2. 时间范围内总订单量
Map<String, Long> dailyCountMap = orders.stream() Map<String, Long> dailyTotalCountMap = orders.stream()
.filter(order -> order.getCreateTime() != null) // 过滤掉创建时间为空的订单
.collect(Collectors.groupingBy( .collect(Collectors.groupingBy(
order -> { order -> {
// 将订单创建时间转换为yyyy-MM-dd格式的日期字符串
LocalDate localDate = order.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); LocalDate localDate = order.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
return localDate.format(DAY_FORMATTER); // 按日期字符串分组 return localDate.format(DAY_FORMATTER);
}, },
Collectors.counting() // 统计每组数量 Collectors.counting()
)); ));
System.out.println(dailyCountMap); System.out.println(dailyTotalCountMap);
// 3. 填充每日统计数据确保日期连续性即使某天无订单也显示0 // 3. 填充每日统计数据确保日期连续性即使某天无订单也显示0
List<DailyStat> dailyStats = new ArrayList<>(); List<DailyStat> dailyStats = new ArrayList<>();
LocalDate current = start; LocalDate current = start;
// 4.计算每日完成量和失败量
Map<String, Long> dailyCompletedMap = calculateDailyStatusCount(orders, STATUS_COMPLETED);
Map<String, Long> dailyFailedMap = calculateDailyStatusCount(orders, STATUS_FAILED);
while (!current.isAfter(end)) { while (!current.isAfter(end)) {
String dateStr = current.format(DAY_FORMATTER); String dateStr = current.format(DAY_FORMATTER);
DailyStat stat = new DailyStat(); DailyStat stat = new DailyStat();
stat.setDate(dateStr); stat.setDate(dateStr);
stat.setDailyCount(dailyCountMap.getOrDefault(dateStr, 0L)); stat.setDailyTotalCount(dailyTotalCountMap.getOrDefault(dateStr, 0L));//每日任务总数量
stat.setDailyCompletedCount(dailyCompletedMap.getOrDefault(dateStr, 0L)); //每日完成量
stat.setDailyFailedCount(dailyFailedMap.getOrDefault(dateStr, 0L));//每日失败量
dailyStats.add(stat); dailyStats.add(stat);
current = current.plusDays(1); // 移至下一天 current = current.plusDays(1); // 移至下一天
} }
// 4. 构建并返回完整结果 // 4. 构建并返回完整结果
return buildAnalysisResult(orders, dailyStats); return buildAnalysisResult(orders, dailyStats);
} }
@ -119,12 +125,15 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
List<MonthlyStat> monthlyStats = new ArrayList<>(); List<MonthlyStat> monthlyStats = new ArrayList<>();
LocalDate current = start.withDayOfMonth(1); // 从当月第一天开始 LocalDate current = start.withDayOfMonth(1); // 从当月第一天开始
LocalDate endMonth = end.withDayOfMonth(1); // 结束月份第一天 LocalDate endMonth = end.withDayOfMonth(1); // 结束月份第一天
Map<String, Long> monthlyCompletedMap = calculateMonthlyStatusCount(orders, STATUS_COMPLETED);
Map<String, Long> monthlyFailedMap = calculateMonthlyStatusCount(orders, STATUS_FAILED);
while (!current.isAfter(endMonth)) { while (!current.isAfter(endMonth)) {
String monthStr = current.format(MONTH_FORMATTER); String monthStr = current.format(MONTH_FORMATTER);
MonthlyStat stat = new MonthlyStat(); MonthlyStat stat = new MonthlyStat();
stat.setMonth(monthStr); stat.setMonth(monthStr);
stat.setMonthlyCount(monthlyCountMap.getOrDefault(monthStr, 0L)); stat.setMonthlyTotalCount(monthlyCountMap.getOrDefault(monthStr, 0L));
stat.setMonthlyCompletedCount(monthlyCompletedMap.getOrDefault(monthStr, 0L));
stat.setMonthlyFailedCount(monthlyFailedMap.getOrDefault(monthStr, 0L));
monthlyStats.add(stat); monthlyStats.add(stat);
current = current.plusMonths(1); // 移至下一月 current = current.plusMonths(1); // 移至下一月
} }
@ -146,7 +155,7 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
.collect(Collectors.groupingBy( .collect(Collectors.groupingBy(
order -> { order -> {
// java.util.Date 转换为 java.time.YearMonth // java.util.Date 转换为 java.time.YearMonth
YearMonth yearMonth = YearMonth.from(order.getCreateTime().toInstant().atZone(ZoneId.systemDefault())); YearMonth yearMonth = YearMonth.from(order.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
int quarter = (yearMonth.getMonthValue() - 1) / 3 + 1; int quarter = (yearMonth.getMonthValue() - 1) / 3 + 1;
return yearMonth.format(YEAR_FORMATTER) + "-Q" + quarter; return yearMonth.format(YEAR_FORMATTER) + "-Q" + quarter;
}, },
@ -159,7 +168,8 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
// 调整至当前季度第一天如2025-05-10 2025-04-01 // 调整至当前季度第一天如2025-05-10 2025-04-01
currentQuarterStart = currentQuarterStart.minusMonths((currentQuarterStart.getMonthValue() - 1) % 3); currentQuarterStart = currentQuarterStart.minusMonths((currentQuarterStart.getMonthValue() - 1) % 3);
currentQuarterStart = currentQuarterStart.withDayOfMonth(1); currentQuarterStart = currentQuarterStart.withDayOfMonth(1);
Map<String, Long> quarterlyCompletedMap = calculateQuarterlyStatusCount(orders, STATUS_COMPLETED);
Map<String, Long> quarterlyFailedMap = calculateQuarterlyStatusCount(orders, STATUS_FAILED);
while (!currentQuarterStart.isAfter(end)) { while (!currentQuarterStart.isAfter(end)) {
// 计算当前季度标识如2025-Q2 // 计算当前季度标识如2025-Q2
int quarter = (currentQuarterStart.getMonthValue() - 1) / 3 + 1; int quarter = (currentQuarterStart.getMonthValue() - 1) / 3 + 1;
@ -167,7 +177,9 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
QuarterlyStat stat = new QuarterlyStat(); QuarterlyStat stat = new QuarterlyStat();
stat.setQuarter(quarterStr); stat.setQuarter(quarterStr);
stat.setQuarterlyCount(quarterCountMap.getOrDefault(quarterStr, 0L)); stat.setQuarterlyTotalCount(quarterCountMap.getOrDefault(quarterStr, 0L));
stat.setQuarterlyCompletedCount(quarterlyCompletedMap.getOrDefault(quarterStr, 0L));
stat.setQuarterlyFailedCount(quarterlyFailedMap.getOrDefault(quarterStr, 0L));
quarterlyStats.add(stat); quarterlyStats.add(stat);
// 移至下一季度第一天 // 移至下一季度第一天
@ -199,12 +211,15 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
List<YearlyStat> yearlyStats = new ArrayList<>(); List<YearlyStat> yearlyStats = new ArrayList<>();
int startYear = start.getYear(); int startYear = start.getYear();
int endYear = end.getYear(); int endYear = end.getYear();
Map<String, Long> yearlyCompletedMap = calculateYearlyStatusCount(orders, STATUS_COMPLETED);
Map<String, Long> yearlyFailedMap = calculateYearlyStatusCount(orders, STATUS_FAILED);
for (int year = startYear; year <= endYear; year++) { for (int year = startYear; year <= endYear; year++) {
String yearStr = String.valueOf(year); String yearStr = String.valueOf(year);
YearlyStat stat = new YearlyStat(); YearlyStat stat = new YearlyStat();
stat.setYear(yearStr); stat.setYear(yearStr);
stat.setYearlyCount(yearCountMap.getOrDefault(yearStr, 0L)); stat.setYearlyTotalCount(yearCountMap.getOrDefault(yearStr, 0L));
stat.setYearlyCompletedCount(yearlyCompletedMap.getOrDefault(yearStr, 0L));
stat.setYearlyFailedCount(yearlyFailedMap.getOrDefault(yearStr, 0L));
yearlyStats.add(stat); yearlyStats.add(stat);
} }
@ -268,8 +283,10 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
double averageTaskCycle = calculateAverageTaskCycle(orderDetails); double averageTaskCycle = calculateAverageTaskCycle(orderDetails);
result.setAverageTaskCycle(averageTaskCycle); result.setAverageTaskCycle(averageTaskCycle);
// 新增 计算无人机使用率 // 新增 计算今日无人机使用率
BigDecimal droneUsageRate = calculateDroneUsageRate(orderDetails); BigDecimal droneUsageRate = calculateTodayDroneUsageRate();
// 时间范围内的无人机使用率
// BigDecimal droneUsageRate = calculateTodayDroneUsageRate(orderDetails);
result.setDroneUsageRate(droneUsageRate); result.setDroneUsageRate(droneUsageRate);
// 5. 景区路线订单分布 // 5. 景区路线订单分布
@ -286,6 +303,42 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
return result; return result;
} }
//计算当日无人机使用率
private BigDecimal calculateTodayDroneUsageRate() {
//1. 获取今日订单中出现的无人机数量去重
LocalDate today = LocalDate.now();
LocalDateTime todayStart = today.atStartOfDay();
LocalDateTime todayEnd = today.plusDays(1).atStartOfDay();
QueryWrapper<OrderDetail> orderQueryWrapper = new QueryWrapper<>();
// 筛选今日创建的订单
orderQueryWrapper.ge("create_time", todayStart)
.lt("create_time", todayEnd);
List<OrderDetail> todayOrders = orderDetailService.list(orderQueryWrapper);
Set<Long> usedDroneIds = new HashSet<>();
for (OrderDetail order : todayOrders) {
Long droneId = order.getDeviceId();
if (droneId != null) {
usedDroneIds.add(droneId);
}
}
int usedDroneCount = usedDroneIds.size();
// 2. 获取无人机总量
QueryWrapper<AircraftDevice> queryWrapper = new QueryWrapper<>();
int totalDroneCount = aircraftDeviceService.count(queryWrapper);
// 3. 计算使用率保留两位小数
if (totalDroneCount == 0) {
return BigDecimal.ZERO;
}
return BigDecimal.valueOf((double) usedDroneCount / totalDroneCount)
.setScale(2, RoundingMode.HALF_UP);
}
//计算平均任务周期 //计算平均任务周期
private double calculateAverageTaskCycle(List<OrderDetail> orderDetails) { private double calculateAverageTaskCycle(List<OrderDetail> orderDetails) {
//获取任务数 //获取任务数
@ -307,7 +360,7 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
return (double) totalSeconds / (60.0 * completedTaskCount); return (double) totalSeconds / (60.0 * completedTaskCount);
} }
//计算无人机使用率 //计算时间范围内无人机使用率
private BigDecimal calculateDroneUsageRate(List<OrderDetail> orderDetails) { private BigDecimal calculateDroneUsageRate(List<OrderDetail> orderDetails) {
// 1. 获取时间范围内订单中出现的无人机数量去重 // 1. 获取时间范围内订单中出现的无人机数量去重
Set<Long> usedDroneIds = orderDetails.stream() Set<Long> usedDroneIds = orderDetails.stream()
@ -329,7 +382,7 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
} }
/** /**
* 按状态统计任务数量 * 按状态统计时间范围内的任务数量
*/ */
private long countTasksByStatus(List<OrderDetail> tasks, Integer status) { private long countTasksByStatus(List<OrderDetail> tasks, Integer status) {
return tasks.stream() return tasks.stream()
@ -337,6 +390,54 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
.count(); .count();
} }
/**
* 按日期和状态统计每日订单数量
*/
private Map<String, Long> calculateDailyStatusCount(List<OrderDetail> orderDetails, Integer status) {
return orderDetails.stream()
.filter(order -> order.getOrderItemStatus().equals(status))
.collect(Collectors.groupingBy(
order -> order.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().format(DAY_FORMATTER),
Collectors.counting()
));
}
/**
* 按月份和状态统计每月订单数量
*/
private Map<String, Long> calculateMonthlyStatusCount(List<OrderDetail> orderDetails, Integer status) {
return orderDetails.stream()
.filter(order -> order.getOrderItemStatus().equals(status))
.collect(Collectors.groupingBy(
order -> order.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().format(MONTH_FORMATTER),
Collectors.counting()
));
}
/**
* 按季节和状态统计每计季节订单数量
*/
private Map<String, Long> calculateQuarterlyStatusCount(List<OrderDetail> orderDetails, Integer status) {
return orderDetails.stream()
.filter(order -> order.getOrderItemStatus().equals(status))
.collect(Collectors.groupingBy(
order -> order.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().format(QUARTER_FORMATTER),
Collectors.counting()
));
}
/**
* 按年份和状态统计每计年订单数量
*/
private Map<String, Long> calculateYearlyStatusCount(List<OrderDetail> orderDetails, Integer status) {
return orderDetails.stream()
.filter(order -> order.getOrderItemStatus().equals(status))
.collect(Collectors.groupingBy(
order -> order.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().format(YEAR_FORMATTER),
Collectors.counting()
));
}
/** /**
* 计算比率保留两位小数 * 计算比率保留两位小数
*/ */