Compare commits
6 Commits
fcfb36868a
...
d673362a77
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d673362a77 | ||
![]() |
6bb01e0e27 | ||
![]() |
15761826c4 | ||
10a890a3cb | |||
![]() |
3570a1d69c | ||
![]() |
761e923f89 |
@ -17,6 +17,7 @@ package com.aircraft.config.webConfig;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.aircraft.utils.AnonTagUtils;
|
||||
import org.apache.commons.lang3.RegExUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
@ -43,6 +44,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -66,6 +68,10 @@ public class SwaggerConfig {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
|
||||
|
||||
public String ASTERISK = "*";
|
||||
|
||||
@Bean
|
||||
public Docket createRestApi() {
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
@ -106,7 +112,12 @@ public class SwaggerConfig {
|
||||
|
||||
private SecurityContext getContextByPath() {
|
||||
Set<String> urls = AnonTagUtils.getAllAnonymousUrl(applicationContext);
|
||||
urls = urls.stream().filter(url -> !url.equals("/")).collect(Collectors.toSet());
|
||||
urls = urls.stream().filter(url -> !url.equals("/"))
|
||||
.map(url -> {
|
||||
//替代path variable 为 *
|
||||
return RegExUtils.replaceAll(url, PATTERN, ASTERISK);
|
||||
})
|
||||
.collect(Collectors.toSet());
|
||||
String regExp = "^(?!" + apiPath + String.join("|" + apiPath, urls) + ").*$";
|
||||
return SecurityContext.builder()
|
||||
.securityReferences(defaultAuth())
|
||||
|
@ -9,7 +9,6 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@ -21,11 +20,11 @@ import java.util.Map;
|
||||
*/
|
||||
public interface AircraftDeviceMapper extends BaseMapper<AircraftDevice> {
|
||||
|
||||
Map<Long, AircraftDevice> getAircraftDeviceById(List<Long> deviceIds);
|
||||
List<AircraftDevice> getAircraftDeviceById(List<Long> deviceIds);
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询 飞行器设备
|
||||
*/
|
||||
IPage<AircraftDevicePageVO> page(@Param("search")AircraftDevicePageDTO search, Page page);
|
||||
IPage<AircraftDevicePageVO> page(@Param("search") AircraftDevicePageDTO search, Page page);
|
||||
}
|
||||
|
@ -107,8 +107,8 @@ public class CpArticleController {
|
||||
errorResponse.put("message", "不存在该文章");
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
|
||||
}
|
||||
cpArticleMapper.updateViewCountById(id);
|
||||
entity.setViewCount(entity.getViewCount()+1);
|
||||
// cpArticleMapper.updateViewCountById(id);
|
||||
// entity.setViewCount(entity.getViewCount()+1);
|
||||
return ResponseEntity.ok(entity);
|
||||
} catch (Exception e) {
|
||||
LOG.error("查询单个文章失败", e);
|
||||
|
@ -63,15 +63,12 @@ public class CpMaterialController {
|
||||
@RequestParam(required = false) String keyword) {
|
||||
try {
|
||||
QueryWrapper<CpMaterial> wrapper = new QueryWrapper<>();
|
||||
|
||||
// 仅对素材名称进行模糊查询
|
||||
if (keyword != null && !keyword.isEmpty()) {
|
||||
wrapper.like("name", keyword);
|
||||
}
|
||||
|
||||
// 只查询未删除的素材
|
||||
wrapper.eq("del_flag", 0);
|
||||
|
||||
wrapper.eq("del_flag", 0); // 只查询未删除的素材
|
||||
wrapper.orderByDesc("create_time");//按时间倒序排序
|
||||
IPage<CpMaterial> records = materialService.page(page, wrapper);
|
||||
return new ResponseEntity<>(records, HttpStatus.OK);
|
||||
} catch (Exception e) {
|
||||
@ -102,7 +99,7 @@ public class CpMaterialController {
|
||||
@PostMapping
|
||||
public ResponseEntity<CpMaterial> add(@Valid @RequestBody CpMaterialDTO material) {
|
||||
try {
|
||||
CpMaterial cpMaterial=new CpMaterial();
|
||||
CpMaterial cpMaterial = new CpMaterial();
|
||||
BeanUtils.copyProperties(material, cpMaterial);
|
||||
// 填充默认值
|
||||
cpMaterial.setCreateTime(LocalDateTime.now());
|
||||
@ -152,6 +149,7 @@ public class CpMaterialController {
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation(value = "删除素材", notes = "逻辑删除:将cp_material表中的del_flag设为1")
|
||||
@ApiImplicitParam(name = "id", value = "素材ID", required = true, paramType = "path", dataType = "int")
|
||||
@DeleteMapping("/{id}")
|
||||
@ -165,7 +163,7 @@ public class CpMaterialController {
|
||||
|
||||
// 逻辑删除:更新del_flag=1
|
||||
material.setDelFlag(1);
|
||||
materialService.updateDelFlagById(material.getId(),material.getDelFlag());
|
||||
materialService.updateDelFlagById(material.getId(), material.getDelFlag());
|
||||
// 3. 删除成功,返回成功信息
|
||||
Map<String, Object> success = new HashMap<>();
|
||||
success.put("code", 200);
|
||||
|
@ -1,7 +1,11 @@
|
||||
package com.aircraft.modules.article.controller;
|
||||
|
||||
import com.aircraft.annotation.rest.AnonymousAccess;
|
||||
import com.aircraft.annotation.rest.AnonymousGetMapping;
|
||||
import com.aircraft.modules.article.domain.CpArticle;
|
||||
import com.aircraft.modules.article.domain.CpText;
|
||||
import com.aircraft.modules.article.mapper.CpLabelMapper;
|
||||
import com.aircraft.modules.article.mapper.CpTextMapper;
|
||||
import com.aircraft.modules.article.service.CpArticleService;
|
||||
import com.aircraft.modules.article.service.CpTextService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
@ -44,13 +48,12 @@ public class CpTextController {
|
||||
|
||||
@Autowired
|
||||
private CpTextService cpTextService;
|
||||
|
||||
@Autowired
|
||||
private CpArticleService cpArticleService;
|
||||
|
||||
@Autowired
|
||||
private CpLabelMapper cpLabelMapper;
|
||||
private CpTextMapper cpTextMapper;
|
||||
|
||||
@AnonymousAccess
|
||||
@ApiOperation(value = "分页查询文本内容", notes = "分页查询文本内容")
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
@ApiImplicitParams({
|
||||
@ -101,8 +104,10 @@ public class CpTextController {
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
}
|
||||
|
||||
@AnonymousAccess
|
||||
@ApiOperation(value = "查询单个文本内容")
|
||||
@RequestMapping(value = "{id}", method = {RequestMethod.GET})
|
||||
@GetMapping(value = "/{id}")
|
||||
@ApiImplicitParam(name = "id", value = "文本内容ID", required = true, paramType = "path")
|
||||
public ResponseEntity<CpText> one(@PathVariable final Integer id) {
|
||||
try {
|
||||
@ -110,7 +115,8 @@ public class CpTextController {
|
||||
if (entity == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
cpTextMapper.updateViewCountById(id);
|
||||
entity.setViewCount(entity.getViewCount() + 1);
|
||||
return ResponseEntity.ok(entity);
|
||||
} catch (Exception e) {
|
||||
LOG.error("查询单个文本内容失败", e);
|
||||
|
@ -30,6 +30,9 @@ public class CpText {
|
||||
@ApiModelProperty(value = "文章正文")
|
||||
private String text;
|
||||
|
||||
@ApiModelProperty(value = "浏览量")
|
||||
private Long viewCount;
|
||||
|
||||
@ApiModelProperty(value = "逻辑删除:1删除,0正常")
|
||||
private Integer del_flag;
|
||||
}
|
||||
|
@ -18,4 +18,6 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
public interface CpTextMapper extends BaseMapper<CpText> {
|
||||
|
||||
IPage<CpText> findByPage(Page<CpText> page, String keyWord);
|
||||
|
||||
void updateViewCountById(Integer id);
|
||||
}
|
||||
|
@ -61,8 +61,6 @@ public class OrderDetailAnalysisController {
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation("按日范围分析子单任务")
|
||||
@GetMapping("/day")
|
||||
// 额外返回:时间范围内任务列表
|
||||
|
@ -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>
|
||||
|
@ -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;//每日失败数量
|
||||
}
|
||||
|
@ -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;//每月失败数量
|
||||
}
|
||||
|
@ -18,6 +18,9 @@ public class OrderDetailAnalysisResult<T> {
|
||||
private BigDecimal completionRate; // 任务完成率
|
||||
private BigDecimal failedRate; // 任务失败率
|
||||
|
||||
private Double averageTaskCycle; // 平均任务周期
|
||||
private BigDecimal droneUsageRate; // 今日无人机使用率
|
||||
|
||||
private List<RouteStat> routeDistribution; // 景区路线统计分布
|
||||
private PageInfo pageInfo; // 分页信息
|
||||
private List<?> orderDetailList; // 子单列表(分页)
|
||||
|
@ -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;//每季失败数量
|
||||
}
|
||||
|
@ -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;//每年失败数量
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
@ -341,7 +341,13 @@ public class OrderAnalysisServiceImpl implements OrderAnalysisService {
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 获取飞行设备 ID 对应的 AircraftDevice 对象的映射
|
||||
Map<Long, AircraftDevice> deviceMap = aircraftDeviceMapper.getAircraftDeviceById(deviceIds);
|
||||
List<AircraftDevice> deviceList = aircraftDeviceMapper.getAircraftDeviceById(deviceIds);
|
||||
Map<Long, AircraftDevice> deviceMap = deviceList.stream()
|
||||
.collect(Collectors.toMap(
|
||||
AircraftDevice::getId, // 提取 ID 作为 key
|
||||
device -> device, // 设备对象作为 value
|
||||
(existing, replacement) -> existing // 处理 ID 重复(保留第一个)
|
||||
));
|
||||
|
||||
// 按型号分组统计数量(处理设备不存在的情况)
|
||||
Map<String, Long> modelCountMap = orderDetails.stream()
|
||||
|
@ -1,30 +1,30 @@
|
||||
package com.aircraft.modules.order.service.impl;
|
||||
|
||||
import com.aircraft.modules.aircraft.domain.AircraftDevice;
|
||||
import com.aircraft.modules.aircraft.service.AircraftDeviceService;
|
||||
import com.aircraft.modules.order.controller.OrderAnalysisController;
|
||||
import com.aircraft.modules.order.domain.OrderDetail;
|
||||
import com.aircraft.modules.order.domain.OrderMain;
|
||||
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;
|
||||
import com.aircraft.modules.system.mapper.EmScenicMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.YearMonth;
|
||||
import java.time.ZoneId;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
@ -51,10 +51,14 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
|
||||
private CpRouteMapper cpRouteMapper;
|
||||
@Autowired
|
||||
private EmScenicMapper emScenicMapper;
|
||||
@Autowired
|
||||
private AircraftDeviceService aircraftDeviceService;
|
||||
@Autowired
|
||||
private IOrderDetailService orderDetailService;
|
||||
|
||||
@Override
|
||||
public OrderDetailAnalysisResult<T> analyzeAllOrderDetails(List<OrderDetail> allDetails) {
|
||||
return buildOrderDetailAnalysisResult(allDetails);
|
||||
return buildOrderDetailAnalysisResult(allDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,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);
|
||||
}
|
||||
@ -115,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); // 移至下一月
|
||||
}
|
||||
@ -142,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;
|
||||
},
|
||||
@ -155,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;
|
||||
@ -163,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);
|
||||
|
||||
// 移至下一季度第一天
|
||||
@ -195,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);
|
||||
}
|
||||
|
||||
@ -260,6 +279,16 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
|
||||
result.setCompletionRate(calculateRate(completedCount, total));
|
||||
result.setFailedRate(calculateRate(failedCount, total));
|
||||
|
||||
// 新增: 计算平均任务周期(单位:分钟)
|
||||
double averageTaskCycle = calculateAverageTaskCycle(orderDetails);
|
||||
result.setAverageTaskCycle(averageTaskCycle);
|
||||
|
||||
// 新增: 计算今日无人机使用率
|
||||
BigDecimal droneUsageRate = calculateTodayDroneUsageRate();
|
||||
// 时间范围内的无人机使用率
|
||||
// BigDecimal droneUsageRate = calculateTodayDroneUsageRate(orderDetails);
|
||||
result.setDroneUsageRate(droneUsageRate);
|
||||
|
||||
// 5. 景区路线订单分布
|
||||
result.setRouteDistribution(calculateRouteDistribution(orderDetails));
|
||||
|
||||
@ -269,13 +298,91 @@ public class OrderDetailAnalysisServiceImpl implements OrderDetailAnalysisServic
|
||||
result.setOrderDetailList(getPagedTasks(orderDetails, pageInfo));
|
||||
|
||||
// 7. 时间序列数据(在调用此方法的上层设置)
|
||||
result.setTimeSeriesData(null); // 由调用者设置具体时间序列数据
|
||||
result.setTimeSeriesData(null);
|
||||
|
||||
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) {
|
||||
//获取任务数
|
||||
List<OrderDetail> completedTasks = orderDetails.stream()
|
||||
.filter(task -> task.getOrderItemStatus() == STATUS_COMPLETED)
|
||||
.collect(Collectors.toList());
|
||||
int completedTaskCount = completedTasks.size();
|
||||
if (completedTasks.isEmpty()) {
|
||||
return 0.0;
|
||||
}
|
||||
//获取时间范围内任务的执行总时间:更新时间-创建时间
|
||||
long totalSeconds = completedTasks.stream()
|
||||
.mapToLong(task ->
|
||||
Duration.between(task.getCreateTime().toInstant(), task.getUpdateTime().toInstant()).getSeconds()
|
||||
)
|
||||
.sum();
|
||||
|
||||
//平均执行任务时间=总执行任务时间÷总任务数
|
||||
return (double) totalSeconds / (60.0 * completedTaskCount);
|
||||
}
|
||||
|
||||
//计算时间范围内无人机使用率
|
||||
private BigDecimal calculateDroneUsageRate(List<OrderDetail> orderDetails) {
|
||||
// 1. 获取时间范围内订单中出现的无人机数量(去重)
|
||||
Set<Long> usedDroneIds = orderDetails.stream()
|
||||
.filter(task -> task.getDeviceId() != null) // 过滤使用了无人机的任务
|
||||
.map(OrderDetail::getDeviceId)
|
||||
.collect(Collectors.toSet());
|
||||
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 long countTasksByStatus(List<OrderDetail> tasks, Integer status) {
|
||||
return tasks.stream()
|
||||
@ -283,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()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算比率(保留两位小数)
|
||||
*/
|
||||
|
@ -88,6 +88,10 @@ public class SpringSecurityConfig {
|
||||
// 静态资源等等
|
||||
.antMatchers(
|
||||
HttpMethod.GET,
|
||||
// "/swagger-ui.html",
|
||||
// "/swagger-resources/**",
|
||||
// "/*/api-docs", // Swagger API 文档接口
|
||||
// "/doc.html" , // Knife4j 文档页面
|
||||
"/*.html",
|
||||
"/**/*.html",
|
||||
"/**/*.css",
|
||||
|
@ -3,22 +3,21 @@
|
||||
<mapper namespace="com.aircraft.modules.aircraft.mapper.AircraftDeviceMapper">
|
||||
<!-- 飞行器设备基础映射 -->
|
||||
<resultMap id="BaseResultMap" type="com.aircraft.modules.aircraft.domain.AircraftDevice">
|
||||
<id column="id" property="id" jdbcType="BIGINT" />
|
||||
<result column="name" property="name" jdbcType="VARCHAR" />
|
||||
<result column="model" property="model" jdbcType="VARCHAR" />
|
||||
<result column="brand" property="brand" jdbcType="VARCHAR" />
|
||||
<result column="use_type" property="useType" jdbcType="INTEGER" />
|
||||
<result column="area_id" property="areaId" jdbcType="BIGINT" />
|
||||
<result column="scenic_id" property="scenicId" jdbcType="BIGINT" />
|
||||
<result column="employees_id" property="employeesId" jdbcType="BIGINT" />
|
||||
<result column="remark" property="remark" jdbcType="VARCHAR" />
|
||||
<id column="id" property="id" jdbcType="BIGINT"/>
|
||||
<result column="name" property="name" jdbcType="VARCHAR"/>
|
||||
<result column="model" property="model" jdbcType="VARCHAR"/>
|
||||
<result column="brand" property="brand" jdbcType="VARCHAR"/>
|
||||
<result column="use_type" property="useType" jdbcType="INTEGER"/>
|
||||
<result column="area_id" property="areaId" jdbcType="BIGINT"/>
|
||||
<result column="scenic_id" property="scenicId" jdbcType="BIGINT"/>
|
||||
<result column="employees_id" property="employeesId" jdbcType="BIGINT"/>
|
||||
<result column="remark" property="remark" jdbcType="VARCHAR"/>
|
||||
<!-- 继承BaseEntity的公共字段映射 -->
|
||||
<result column="create_by" property="createBy" jdbcType="VARCHAR" />
|
||||
<result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
|
||||
<result column="update_by" property="updateBy" jdbcType="VARCHAR" />
|
||||
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP" />
|
||||
<result column="create_by" property="createBy" jdbcType="VARCHAR"/>
|
||||
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
|
||||
<result column="update_by" property="updateBy" jdbcType="VARCHAR"/>
|
||||
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 通过设备ID列表查询飞行器设备 -->
|
||||
<select id="getAircraftDeviceById" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
@ -41,15 +40,6 @@
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<!-- 结果处理器:将List转换为Map<Long, AircraftDevice> -->
|
||||
<resultMap id="DeviceMapResultMap" type="java.util.HashMap">
|
||||
<result column="id" property="key" javaType="java.lang.Long" />
|
||||
<association property="value" resultMap="BaseResultMap" />
|
||||
</resultMap>
|
||||
|
||||
|
||||
|
||||
<select id="page" resultType="com.aircraft.modules.aircraft.domain.vo.AircraftDevicePageVO">
|
||||
select d.id,
|
||||
d.name,
|
||||
@ -64,7 +54,7 @@
|
||||
from fms_ac_aircraft_device d
|
||||
left join em_area a on d.area_id = a.id
|
||||
left join em_scenic s on d.scenic_id = s.id
|
||||
left join em_employees e on d.employees_id = e.id
|
||||
left join em_employees e on d.employees_id = e.id
|
||||
where d.del_flag = 0
|
||||
<if test="search.name != null and search.name != ''">
|
||||
and d.name like concat('%',#{search.name},'%')
|
||||
|
@ -30,6 +30,7 @@
|
||||
<if test="titleKeyword != null and titleKeyword != ''">
|
||||
AND a.title LIKE CONCAT('%', #{titleKeyword}, '%')
|
||||
</if>
|
||||
ORDER BY create_time DESC
|
||||
</select>
|
||||
|
||||
<!--通过文章id查询文章-->
|
||||
|
@ -10,4 +10,11 @@
|
||||
</if>
|
||||
ORDER BY id DESC
|
||||
</select>
|
||||
<!-- 浏览量+1-->
|
||||
<update id="updateViewCountById">
|
||||
UPDATE cp_text
|
||||
SET view_count = view_count + 1 -- 自增1
|
||||
WHERE id = #{id}
|
||||
AND del_flag = 0 -- 确保只更新未删除的文章
|
||||
</update>
|
||||
</mapper>
|
||||
|
Loading…
Reference in New Issue
Block a user