陆运产品价无费名时默认陆运费;看板指标与工单列表共用起止日,趋势按日铺点。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+5
-2
@@ -27,7 +27,10 @@ public class InquiryDashboardController {
|
||||
|
||||
@ApiOperation("看板指标")
|
||||
@GetMapping("/metrics")
|
||||
public Result<Map<String, Object>> metrics(@RequestParam(name = "range", defaultValue = "today") String range) {
|
||||
return Result.OK(dashboardService.metrics(range));
|
||||
public Result<Map<String, Object>> metrics(
|
||||
@RequestParam(name = "range", defaultValue = "today") String range,
|
||||
@RequestParam(name = "dateFrom", required = false) String dateFrom,
|
||||
@RequestParam(name = "dateTo", required = false) String dateTo) {
|
||||
return Result.OK(dashboardService.metrics(range, dateFrom, dateTo));
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -9,9 +9,13 @@ public interface IInquiryDashboardService {
|
||||
|
||||
/**
|
||||
* 返回看板指标:metrics + trend + rankings + costDates/costRoutes。
|
||||
* rankings 与工单列表同套发起人解析;costRoutes 为近 7 日线路均价(主账工单投影)。
|
||||
* rankings 与工单列表同套发起人解析;costRoutes 为选定周期内线路均价(主账工单投影)。
|
||||
* <p>
|
||||
* 有 dateFrom/dateTo 时以显式日期为准(与工单列表筛选同源);否则回退 range=today|7d|30d。
|
||||
*
|
||||
* @param range today|7d|30d,默认 today
|
||||
* @param range today|7d|30d,默认 today(无显式日期时)
|
||||
* @param dateFrom 起日 yyyy-MM-dd,可空
|
||||
* @param dateTo 止日 yyyy-MM-dd,可空
|
||||
*/
|
||||
Map<String, Object> metrics(String range);
|
||||
Map<String, Object> metrics(String range, String dateFrom, String dateTo);
|
||||
}
|
||||
|
||||
+47
-27
@@ -78,19 +78,14 @@ public class InquiryDashboardServiceImpl implements IInquiryDashboardService {
|
||||
private InquiryQuoteMapper quoteMapper;
|
||||
|
||||
@Override
|
||||
public Map<String, Object> metrics(String range) {
|
||||
LocalDate today = LocalDate.now(ZONE);
|
||||
LocalDate fromDate;
|
||||
if ("7d".equalsIgnoreCase(range)) {
|
||||
fromDate = today.minusDays(6);
|
||||
} else if ("30d".equalsIgnoreCase(range)) {
|
||||
fromDate = today.minusDays(29);
|
||||
} else {
|
||||
fromDate = today;
|
||||
}
|
||||
public Map<String, Object> metrics(String range, String dateFromStr, String dateToStr) {
|
||||
LocalDate[] bounds = resolveMetricBounds(range, dateFromStr, dateToStr);
|
||||
LocalDate fromDate = bounds[0];
|
||||
LocalDate toDate = bounds[1];
|
||||
Date from = Date.from(fromDate.atStartOfDay(ZONE).toInstant());
|
||||
Date to = Date.from(LocalDateTime.of(today, LocalTime.MAX).atZone(ZONE).toInstant());
|
||||
Date to = Date.from(LocalDateTime.of(toDate, LocalTime.MAX).atZone(ZONE).toInstant());
|
||||
|
||||
// 指标 / 排名 / 趋势 / 成本:同一批工单、同一日期窗,与工单列表 dateFrom~dateTo 对齐
|
||||
LambdaQueryWrapper<InquiryTicket> qw = new LambdaQueryWrapper<InquiryTicket>()
|
||||
.ge(InquiryTicket::getCreateTime, from)
|
||||
.le(InquiryTicket::getCreateTime, to);
|
||||
@@ -127,28 +122,24 @@ public class InquiryDashboardServiceImpl implements IInquiryDashboardService {
|
||||
metricCards.add(card("avgResp", "内部报价平均响应",
|
||||
"AVG(首次有效回复时间 − 分发时间)", avgResp, true));
|
||||
|
||||
// 近 7 日趋势 + 成本:一次拉周内工单,避免 7 次 count
|
||||
Date weekFrom = Date.from(today.minusDays(6).atStartOfDay(ZONE).toInstant());
|
||||
LambdaQueryWrapper<InquiryTicket> weekQw = new LambdaQueryWrapper<InquiryTicket>()
|
||||
.ge(InquiryTicket::getCreateTime, weekFrom)
|
||||
.le(InquiryTicket::getCreateTime, to);
|
||||
InquiryDataScopeSupport.applySelfOnly(weekQw);
|
||||
List<InquiryTicket> weekTickets = ticketMapper.selectList(weekQw);
|
||||
|
||||
List<String> trendDates = new ArrayList<>(7);
|
||||
List<Map<String, Object>> trend = new ArrayList<>(7);
|
||||
// 趋势 / 成本:按选定起止日逐日铺点(单日则一点;长周期最多 62 天防图爆炸)
|
||||
List<String> trendDates = new ArrayList<>();
|
||||
List<Map<String, Object>> trend = new ArrayList<>();
|
||||
Map<LocalDate, Integer> dayIndex = new HashMap<>();
|
||||
for (int i = 6; i >= 0; i--) {
|
||||
LocalDate d = today.minusDays(i);
|
||||
dayIndex.put(d, trendDates.size());
|
||||
String label = d.format(DAY_FMT);
|
||||
LocalDate cursor = fromDate;
|
||||
int dayGuard = 0;
|
||||
while (!cursor.isAfter(toDate) && dayGuard < 62) {
|
||||
dayIndex.put(cursor, trendDates.size());
|
||||
String label = cursor.format(DAY_FMT);
|
||||
trendDates.add(label);
|
||||
Map<String, Object> p = new HashMap<>();
|
||||
p.put("date", label);
|
||||
p.put("value", 0L);
|
||||
trend.add(p);
|
||||
cursor = cursor.plusDays(1);
|
||||
dayGuard++;
|
||||
}
|
||||
for (InquiryTicket t : weekTickets) {
|
||||
for (InquiryTicket t : tickets) {
|
||||
LocalDate d = toLocalDate(t.getCreateTime());
|
||||
Integer idx = d == null ? null : dayIndex.get(d);
|
||||
if (idx == null) {
|
||||
@@ -174,10 +165,12 @@ public class InquiryDashboardServiceImpl implements IInquiryDashboardService {
|
||||
}
|
||||
|
||||
List<Map<String, Object>> rankings = buildRankings(tickets, staffByWecom, staffByName);
|
||||
List<Map<String, Object>> costRoutes = buildCostRoutes(weekTickets, dayIndex, trendDates);
|
||||
List<Map<String, Object>> costRoutes = buildCostRoutes(tickets, dayIndex, trendDates);
|
||||
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("range", range == null ? "today" : range);
|
||||
result.put("dateFrom", fromDate.toString());
|
||||
result.put("dateTo", toDate.toString());
|
||||
result.put("metrics", metricCards);
|
||||
result.put("trend", trend);
|
||||
result.put("rankings", rankings);
|
||||
@@ -186,6 +179,33 @@ public class InquiryDashboardServiceImpl implements IInquiryDashboardService {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析看板统计起止日。
|
||||
* 优先用显式 dateFrom/dateTo(与工单列表同源);否则按 range=today|7d|30d 相对「今天」。
|
||||
*/
|
||||
private static LocalDate[] resolveMetricBounds(String range, String dateFromStr, String dateToStr) {
|
||||
if (StringUtils.isNotBlank(dateFromStr) && StringUtils.isNotBlank(dateToStr)) {
|
||||
LocalDate fromDate = LocalDate.parse(dateFromStr.trim());
|
||||
LocalDate toDate = LocalDate.parse(dateToStr.trim());
|
||||
if (toDate.isBefore(fromDate)) {
|
||||
LocalDate tmp = fromDate;
|
||||
fromDate = toDate;
|
||||
toDate = tmp;
|
||||
}
|
||||
return new LocalDate[]{fromDate, toDate};
|
||||
}
|
||||
LocalDate today = LocalDate.now(ZONE);
|
||||
LocalDate fromDate;
|
||||
if ("7d".equalsIgnoreCase(range)) {
|
||||
fromDate = today.minusDays(6);
|
||||
} else if ("30d".equalsIgnoreCase(range)) {
|
||||
fromDate = today.minusDays(29);
|
||||
} else {
|
||||
fromDate = today;
|
||||
}
|
||||
return new LocalDate[]{fromDate, today};
|
||||
}
|
||||
|
||||
/**
|
||||
* 人员排名:与工单列表 enrichDisplayFields 同口径。
|
||||
* 聚合键优先 salesWecomId(同人合并),展示名走 resolveSalesDisplayName。
|
||||
|
||||
Reference in New Issue
Block a user