|
|
@@ -32,6 +32,7 @@ import java.math.BigDecimal;
|
|
|
import java.math.RoundingMode;
|
|
|
import java.net.URLEncoder;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
+import java.time.LocalDateTime;
|
|
|
import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@@ -52,7 +53,9 @@ public class OpsDailyServiceImpl implements OpsDailyService {
|
|
|
@Override
|
|
|
public List<CruiseOpsDailyRespVO> getCruiseOpsDailyList(CruiseOpsDailyReqVO reqVO) {
|
|
|
// 1. 查询本期原始数据
|
|
|
+ log.info("查询CruiseOpsDailyList任务开始时间{}", LocalDateTime.now());
|
|
|
List<CruiseOpsDailyRespVO> currentDataList = cruiseOpsDailyMapper.selectCruiseOpsDailyList(reqVO);
|
|
|
+ log.info("查询CruiseOpsDailyList任务结束时间{}", LocalDateTime.now());
|
|
|
if (CollUtil.isEmpty(currentDataList)) {
|
|
|
return new ArrayList<>();
|
|
|
}
|
|
|
@@ -131,13 +134,39 @@ public class OpsDailyServiceImpl implements OpsDailyService {
|
|
|
* 构建导出表头(与前端页面15列一一对应)
|
|
|
*/
|
|
|
private List<List<String>> buildExportHeaders() {
|
|
|
- String[] headers = {"序号", "月份", "日期", "船舶", "航线", "航次号",
|
|
|
- "客容量", "载客量", "载客率", "房总数", "用房数", "用房率",
|
|
|
- "船票收入", "二消收入", "收入合计"};
|
|
|
- List<List<String>> head = new ArrayList<>(headers.length);
|
|
|
- for (String h : headers) {
|
|
|
- head.add(Collections.singletonList(h));
|
|
|
- }
|
|
|
+
|
|
|
+ List<List<String>> head = new ArrayList<>();
|
|
|
+
|
|
|
+ // 一级表头列(无二级表头,只设置一个元素)
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("序号")));
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("月份")));
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("日期")));
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("船舶")));
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("航线")));
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("航次号")));
|
|
|
+
|
|
|
+ // 客容量(无二级表头)
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("客容量")));
|
|
|
+
|
|
|
+ // 乘客统计(二级表头)
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("载客量", "购票")));
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("载客量", "免票")));
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("载客量", "合计")));
|
|
|
+
|
|
|
+ // 载客率(无二级表头)
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("购票载客率")));
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("床位载客率")));
|
|
|
+
|
|
|
+ // 房间统计(无二级表头)
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("房总数")));
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("用房数")));
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("用房率")));
|
|
|
+
|
|
|
+ // 收入统计(无二级表头)
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("船票收入")));
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("二消收入")));
|
|
|
+ head.add(new ArrayList<>(Arrays.asList("收入合计")));
|
|
|
+
|
|
|
return head;
|
|
|
}
|
|
|
|
|
|
@@ -161,7 +190,10 @@ public class OpsDailyServiceImpl implements OpsDailyService {
|
|
|
rowData.add(""); // 航线 - 合并
|
|
|
rowData.add("同比");
|
|
|
rowData.add(formatYoyForExport(row.getPassengerCapacityYoy()));
|
|
|
+ rowData.add(formatYoyForExport(row.getTicketCountYoy()));
|
|
|
+ rowData.add(formatYoyForExport(row.getFreeCountYoy()));
|
|
|
rowData.add(formatYoyForExport(row.getPassengerCountYoy()));
|
|
|
+ rowData.add(formatYoyForExport(row.getTicketRateYoy()));
|
|
|
rowData.add(formatYoyForExport(row.getPassengerRateYoy()));
|
|
|
rowData.add(formatYoyForExport(row.getTotalRoomsYoy()));
|
|
|
rowData.add(formatYoyForExport(row.getUsedRoomsYoy()));
|
|
|
@@ -178,7 +210,10 @@ public class OpsDailyServiceImpl implements OpsDailyService {
|
|
|
rowData.add(row.getRoute() != null ? row.getRoute() : "");
|
|
|
rowData.add(row.getVoyageNo() != null ? row.getVoyageNo() : "");
|
|
|
rowData.add(formatNumber(row.getPassengerCapacity()));
|
|
|
+ rowData.add(formatNumber(row.getTicketCount()));
|
|
|
+ rowData.add(formatNumber(row.getFreeCount()));
|
|
|
rowData.add(formatNumber(row.getPassengerCount()));
|
|
|
+ rowData.add(row.getTicketRate() != null ? row.getTicketRate() : "");
|
|
|
rowData.add(row.getPassengerRate() != null ? row.getPassengerRate() : "");
|
|
|
rowData.add(formatNumber(row.getTotalRooms()));
|
|
|
rowData.add(row.getUsedRooms() != null ? row.getUsedRooms() : "");
|
|
|
@@ -242,17 +277,20 @@ public class OpsDailyServiceImpl implements OpsDailyService {
|
|
|
private void calculateDerivedFields(List<CruiseOpsDailyRespVO> dataList) {
|
|
|
for (CruiseOpsDailyRespVO item : dataList) {
|
|
|
// 载客率 = 载客量 / 客容量 * 100
|
|
|
+ // 购票载客率 = 购票 / 客容量 * 100
|
|
|
if (item.getPassengerCapacity() != null && item.getPassengerCapacity() > 0
|
|
|
&& item.getPassengerCount() != null) {
|
|
|
double rate = (double) item.getPassengerCount() / item.getPassengerCapacity() * 100;
|
|
|
- item.setPassengerRate(String.format("%.1f%%", rate));
|
|
|
+ item.setPassengerRate(String.format("%.2f%%", rate));
|
|
|
+ double ticketRate = (double) item.getTicketCount() / item.getPassengerCapacity() * 100;
|
|
|
+ item.setTicketRate(String.format("%.2f%%", ticketRate));
|
|
|
}
|
|
|
// 用房率 = 用房数 / 房总数 * 100
|
|
|
if (item.getTotalRooms() != null && item.getTotalRooms() > 0
|
|
|
&& item.getUsedRooms() != null) {
|
|
|
- double usedRoomsVal = safeParseInt(item.getUsedRooms());
|
|
|
+ double usedRoomsVal = safeParseDouble(item.getUsedRooms());
|
|
|
double rate = usedRoomsVal / item.getTotalRooms() * 100;
|
|
|
- item.setRoomRate(String.format("%.1f%%", rate));
|
|
|
+ item.setRoomRate(String.format("%.2f%%", rate));
|
|
|
}
|
|
|
// 收入合计 = 船票收入 + 二消收入
|
|
|
BigDecimal ticket = item.getTicketIncome() != null ? item.getTicketIncome() : BigDecimal.ZERO;
|
|
|
@@ -384,22 +422,28 @@ public class OpsDailyServiceImpl implements OpsDailyService {
|
|
|
|
|
|
// 数值汇总
|
|
|
int passengerCapacitySum = 0;
|
|
|
+ int ticketCountSum = 0;
|
|
|
+ int freeCountSum = 0;
|
|
|
int passengerCountSum = 0;
|
|
|
int totalRoomsSum = 0;
|
|
|
- int usedRoomsSum = 0;
|
|
|
+ double usedRoomsSum = 0;
|
|
|
BigDecimal ticketIncomeSum = BigDecimal.ZERO;
|
|
|
BigDecimal secondIncomeSum = BigDecimal.ZERO;
|
|
|
|
|
|
for (CruiseOpsDailyRespVO item : items) {
|
|
|
passengerCapacitySum += safeInt(item.getPassengerCapacity());
|
|
|
+ ticketCountSum += safeInt(item.getTicketCount());
|
|
|
+ freeCountSum += safeInt(item.getFreeCount());
|
|
|
passengerCountSum += safeInt(item.getPassengerCount());
|
|
|
totalRoomsSum += safeInt(item.getTotalRooms());
|
|
|
- usedRoomsSum += safeParseInt(item.getUsedRooms());
|
|
|
+ usedRoomsSum += safeParseDouble(item.getUsedRooms());
|
|
|
ticketIncomeSum = ticketIncomeSum.add(safeBigDecimal(item.getTicketIncome()));
|
|
|
secondIncomeSum = secondIncomeSum.add(safeBigDecimal(item.getSecondIncome()));
|
|
|
}
|
|
|
|
|
|
row.setPassengerCapacity(passengerCapacitySum);
|
|
|
+ row.setTicketCount(ticketCountSum);
|
|
|
+ row.setFreeCount(freeCountSum);
|
|
|
row.setPassengerCount(passengerCountSum);
|
|
|
row.setTotalRooms(totalRoomsSum);
|
|
|
row.setUsedRooms(String.valueOf(usedRoomsSum));
|
|
|
@@ -409,11 +453,13 @@ public class OpsDailyServiceImpl implements OpsDailyService {
|
|
|
// 派生字段重新计算
|
|
|
if (passengerCapacitySum > 0) {
|
|
|
double rate = (double) passengerCountSum / passengerCapacitySum * 100;
|
|
|
- row.setPassengerRate(String.format("%.1f%%", rate));
|
|
|
+ row.setPassengerRate(String.format("%.2f%%", rate));
|
|
|
+ double ticketRate = (double) ticketCountSum / passengerCapacitySum * 100;
|
|
|
+ row.setTicketRate(String.format("%.2f%%", ticketRate));
|
|
|
}
|
|
|
if (totalRoomsSum > 0) {
|
|
|
double rate = (double) usedRoomsSum / totalRoomsSum * 100;
|
|
|
- row.setRoomRate(String.format("%.1f%%", rate));
|
|
|
+ row.setRoomRate(String.format("%.2f%%", rate));
|
|
|
}
|
|
|
row.setTotalIncome(ticketIncomeSum.add(secondIncomeSum));
|
|
|
|
|
|
@@ -438,16 +484,21 @@ public class OpsDailyServiceImpl implements OpsDailyService {
|
|
|
// ===== 计算各指标的同比率 =====
|
|
|
yoyRow.setPassengerCapacityYoy(calcYoyPercent(
|
|
|
safeInt(currentRow.getPassengerCapacity()), safeInt(lastYearRow.getPassengerCapacity())));
|
|
|
+ yoyRow.setTicketCountYoy(calcYoyPercent(
|
|
|
+ safeInt(currentRow.getTicketCount()), safeInt(lastYearRow.getTicketCount())));
|
|
|
+ yoyRow.setFreeCountYoy(calcYoyPercent(
|
|
|
+ safeInt(currentRow.getFreeCount()), safeInt(lastYearRow.getFreeCount())));
|
|
|
yoyRow.setPassengerCountYoy(calcYoyPercent(
|
|
|
safeInt(currentRow.getPassengerCount()), safeInt(lastYearRow.getPassengerCount())));
|
|
|
|
|
|
// 载客率同比(百分点差异)
|
|
|
+ yoyRow.setTicketRateYoy(calcRateDiff(currentRow.getTicketRate(), lastYearRow.getTicketRate()));
|
|
|
yoyRow.setPassengerRateYoy(calcRateDiff(currentRow.getPassengerRate(), lastYearRow.getPassengerRate()));
|
|
|
|
|
|
yoyRow.setTotalRoomsYoy(calcYoyPercent(
|
|
|
safeInt(currentRow.getTotalRooms()), safeInt(lastYearRow.getTotalRooms())));
|
|
|
yoyRow.setUsedRoomsYoy(calcYoyPercent(
|
|
|
- safeParseInt(currentRow.getUsedRooms()), safeParseInt(lastYearRow.getUsedRooms())));
|
|
|
+ safeParseDouble(currentRow.getUsedRooms()), safeParseDouble(lastYearRow.getUsedRooms())));
|
|
|
|
|
|
// 用房率同比(百分点差异)
|
|
|
yoyRow.setRoomRateYoy(calcRateDiff(currentRow.getRoomRate(), lastYearRow.getRoomRate()));
|
|
|
@@ -514,6 +565,17 @@ public class OpsDailyServiceImpl implements OpsDailyService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private double safeParseDouble(String val) {
|
|
|
+ if (val == null || val.isEmpty()) {
|
|
|
+ return 0.0;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return Double.parseDouble(val);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ return 0.0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private BigDecimal safeBigDecimal(BigDecimal val) {
|
|
|
return val != null ? val : BigDecimal.ZERO;
|
|
|
}
|