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

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
private CpTextMapper cpTextMapper;
// @AnonymousAccess
@AnonymousAccess
@ApiOperation(value = "分页查询文本内容", notes = "分页查询文本内容")
@RequestMapping(method = RequestMethod.GET)
@ApiImplicitParams({

View File

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

View File

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

View File

@ -6,5 +6,7 @@ import lombok.Data;
@Data
public class DailyStat {
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
public class MonthlyStat {
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 Double averageTaskCycle; // 平均任务周期
private BigDecimal droneUsageRate; // 无人机使用率
private BigDecimal droneUsageRate; // 今日无人机使用率
private List<RouteStat> routeDistribution; // 景区路线统计分布
private PageInfo pageInfo; // 分页信息

View File

@ -5,5 +5,7 @@ import lombok.Data;
@Data
public class QuarterlyStat {
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
public class YearlyStat {
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);
DailyStat stat = new DailyStat();
stat.setDate(dateStr);
stat.setDailyCount(dailyCountMap.getOrDefault(dateStr, 0L));
stat.setDailyTotalCount(dailyCountMap.getOrDefault(dateStr, 0L));
dailyStats.add(stat);
current = current.plusDays(1); // 移至下一天
}
@ -128,7 +128,7 @@ public class OrderAnalysisServiceImpl implements OrderAnalysisService {
String monthStr = current.format(MONTH_FORMATTER);
MonthlyStat stat = new MonthlyStat();
stat.setMonth(monthStr);
stat.setMonthlyCount(monthlyCountMap.getOrDefault(monthStr, 0L));
stat.setMonthlyTotalCount(monthlyCountMap.getOrDefault(monthStr, 0L));
monthlyStats.add(stat);
current = current.plusMonths(1); // 移至下一月
}
@ -175,7 +175,7 @@ public class OrderAnalysisServiceImpl implements OrderAnalysisService {
QuarterlyStat stat = new QuarterlyStat();
stat.setQuarter(quarterStr);
stat.setQuarterlyCount(quarterCountMap.getOrDefault(quarterStr, 0L));
stat.setQuarterlyTotalCount(quarterCountMap.getOrDefault(quarterStr, 0L));
quarterlyStats.add(stat);
// 移至下一季度第一天
@ -216,7 +216,7 @@ public class OrderAnalysisServiceImpl implements OrderAnalysisService {
String yearStr = String.valueOf(year);
YearlyStat stat = new YearlyStat();
stat.setYear(yearStr);
stat.setYearlyCount(yearCountMap.getOrDefault(yearStr, 0L));
stat.setYearlyTotalCount(yearCountMap.getOrDefault(yearStr, 0L));
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.dto.*;
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.route.domain.CpRoute;
import com.aircraft.modules.route.mapper.CpRouteMapper;
@ -21,10 +22,7 @@ import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.util.*;
@ -55,6 +53,8 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
private EmScenicMapper emScenicMapper;
@Autowired
private AircraftDeviceService aircraftDeviceService;
@Autowired
private IOrderDetailService orderDetailService;
@Override
public OrderDetailAnalysisResult<T> analyzeAllOrderDetails(List<OrderDetail> allDetails) {
@ -69,30 +69,36 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
return buildEmptyResult();
}
// 2. 按日分组统计每日订单量
Map<String, Long> dailyCountMap = orders.stream()
// 2. 时间范围内总订单量
Map<String, Long> dailyTotalCountMap = orders.stream()
.filter(order -> order.getCreateTime() != null) // 过滤掉创建时间为空的订单
.collect(Collectors.groupingBy(
order -> {
// 将订单创建时间转换为yyyy-MM-dd格式的日期字符串
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
List<DailyStat> dailyStats = new ArrayList<>();
LocalDate current = start;
// 4.计算每日完成量和失败量
Map<String, Long> dailyCompletedMap = calculateDailyStatusCount(orders, STATUS_COMPLETED);
Map<String, Long> dailyFailedMap = calculateDailyStatusCount(orders, STATUS_FAILED);
while (!current.isAfter(end)) {
String dateStr = current.format(DAY_FORMATTER);
DailyStat stat = new DailyStat();
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);
current = current.plusDays(1); // 移至下一天
}
// 4. 构建并返回完整结果
return buildAnalysisResult(orders, dailyStats);
}
@ -119,12 +125,15 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
List<MonthlyStat> monthlyStats = new ArrayList<>();
LocalDate current = start.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)) {
String monthStr = current.format(MONTH_FORMATTER);
MonthlyStat stat = new MonthlyStat();
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);
current = current.plusMonths(1); // 移至下一月
}
@ -146,7 +155,7 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
.collect(Collectors.groupingBy(
order -> {
// 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;
return yearMonth.format(YEAR_FORMATTER) + "-Q" + quarter;
},
@ -159,7 +168,8 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
// 调整至当前季度第一天如2025-05-10 2025-04-01
currentQuarterStart = currentQuarterStart.minusMonths((currentQuarterStart.getMonthValue() - 1) % 3);
currentQuarterStart = currentQuarterStart.withDayOfMonth(1);
Map<String, Long> quarterlyCompletedMap = calculateQuarterlyStatusCount(orders, STATUS_COMPLETED);
Map<String, Long> quarterlyFailedMap = calculateQuarterlyStatusCount(orders, STATUS_FAILED);
while (!currentQuarterStart.isAfter(end)) {
// 计算当前季度标识如2025-Q2
int quarter = (currentQuarterStart.getMonthValue() - 1) / 3 + 1;
@ -167,7 +177,9 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
QuarterlyStat stat = new QuarterlyStat();
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);
// 移至下一季度第一天
@ -199,12 +211,15 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
List<YearlyStat> yearlyStats = new ArrayList<>();
int startYear = start.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++) {
String yearStr = String.valueOf(year);
YearlyStat stat = new YearlyStat();
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);
}
@ -268,8 +283,10 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
double averageTaskCycle = calculateAverageTaskCycle(orderDetails);
result.setAverageTaskCycle(averageTaskCycle);
// 新增 计算无人机使用率
BigDecimal droneUsageRate = calculateDroneUsageRate(orderDetails);
// 新增 计算今日无人机使用率
BigDecimal droneUsageRate = calculateTodayDroneUsageRate();
// 时间范围内的无人机使用率
// BigDecimal droneUsageRate = calculateTodayDroneUsageRate(orderDetails);
result.setDroneUsageRate(droneUsageRate);
// 5. 景区路线订单分布
@ -286,6 +303,42 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
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) {
//获取任务数
@ -307,7 +360,7 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
return (double) totalSeconds / (60.0 * completedTaskCount);
}
//计算无人机使用率
//计算时间范围内无人机使用率
private BigDecimal calculateDroneUsageRate(List<OrderDetail> orderDetails) {
// 1. 获取时间范围内订单中出现的无人机数量去重
Set<Long> usedDroneIds = orderDetails.stream()
@ -329,7 +382,7 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
}
/**
* 按状态统计任务数量
* 按状态统计时间范围内的任务数量
*/
private long countTasksByStatus(List<OrderDetail> tasks, Integer status) {
return tasks.stream()
@ -337,6 +390,54 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
.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()
));
}
/**
* 计算比率保留两位小数
*/