feat(ops): 实现工单统计看板功能
1. 修复 MyBatis 类型安全问题 - 创建 9 个 DTO 类替换 List<Map<String, Object>> - 修复 @MapKey 错误,使用强类型返回值 2. 实现工单统计看板 5 大功能 - 漏斗统计:支持时间范围过滤 - 时段热力图:改为近 7 天,Y 轴显示日期(MM-dd) - 功能类型排行:替换区域排行,JOIN ops_bus_area 表 - 今日工单时段分布:X 轴优化为每 2 小时展示 - 近七天客流统计:独立接口,支持工作台实时趋势 3. 字典转换实现 - 新增 DictTypeConstants.OPS_AREA_FUNCTION_TYPE(保留供未来扩展) - 使用硬编码 Map 实现功能类型中文转换(性能最优) - 添加 TODO 说明未来可切换 DictFrameworkUtils 4. SQL 优化 - 功能类型统计:INNER JOIN ops_bus_area 表 - 热力图查询:按日期和小时分组统计 - 时段分布:仅统计当天数据 5. 缓存策略 - 看板统计:5 分钟缓存(@Cacheable) - 客流监测:5 分钟缓存 - 防止高并发查询压力 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
package com.viewsh.module.ops.config;
|
||||
|
||||
import com.viewsh.module.ops.api.badge.BadgeDeviceStatusDTO;
|
||||
import com.viewsh.module.ops.dal.dataobject.area.OpsAreaDeviceRelationDO;
|
||||
import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusService;
|
||||
import com.viewsh.module.ops.service.area.AreaDeviceService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* 统计服务配置,注册跨模块依赖的 Bean
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
@Configuration
|
||||
public class StatisticsConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private BadgeDeviceStatusService badgeDeviceStatusService;
|
||||
|
||||
@Autowired(required = false)
|
||||
private AreaDeviceService areaDeviceService;
|
||||
|
||||
@Bean
|
||||
public Supplier<int[]> staffCountProvider() {
|
||||
return () -> {
|
||||
if (badgeDeviceStatusService == null) {
|
||||
return new int[]{0, 0};
|
||||
}
|
||||
List<BadgeDeviceStatusDTO> activeBadges = badgeDeviceStatusService.listActiveBadges();
|
||||
int onlineCount = activeBadges.size();
|
||||
// 从区域设备关联表查询所有已注册的工牌设备总数
|
||||
int totalCount = onlineCount;
|
||||
if (areaDeviceService != null) {
|
||||
try {
|
||||
List<OpsAreaDeviceRelationDO> allBadges = areaDeviceService.listByAreaIdAndType(null, "BADGE");
|
||||
totalCount = Math.max(onlineCount, allBadges.size());
|
||||
} catch (Exception ignored) {
|
||||
// 查询失败时使用在线数作为兜底
|
||||
}
|
||||
}
|
||||
return new int[]{onlineCount, totalCount};
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,10 +3,15 @@ package com.viewsh.module.ops.controller.admin;
|
||||
import com.viewsh.framework.common.pojo.CommonResult;
|
||||
import com.viewsh.framework.common.pojo.PageResult;
|
||||
import com.viewsh.module.ops.api.clean.QuickStatsRespDTO;
|
||||
import com.viewsh.module.ops.controller.admin.workorder.vo.statistics.DashboardStatsRespVO;
|
||||
import com.viewsh.module.ops.controller.admin.workorder.vo.statistics.TrafficRealtimeRespVO;
|
||||
import com.viewsh.module.ops.controller.admin.workorder.vo.statistics.TrafficTrendRespVO;
|
||||
import com.viewsh.module.ops.controller.admin.workorder.vo.statistics.WorkspaceStatsRespVO;
|
||||
import com.viewsh.module.ops.environment.service.dashboard.CleanDashboardService;
|
||||
import com.viewsh.module.ops.service.OrderDetailVO;
|
||||
import com.viewsh.module.ops.service.OrderQueryService;
|
||||
import com.viewsh.module.ops.service.OrderSummaryVO;
|
||||
import com.viewsh.module.ops.service.statistics.OpsStatisticsService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@@ -14,10 +19,12 @@ import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.viewsh.framework.common.pojo.CommonResult.success;
|
||||
@@ -42,6 +49,9 @@ public class OrderCenterController {
|
||||
@Autowired(required = false)
|
||||
private CleanDashboardService cleanDashboardService;
|
||||
|
||||
@Autowired(required = false)
|
||||
private OpsStatisticsService opsStatisticsService;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "工单中心分页查询")
|
||||
@PreAuthorize("@ss.hasPermission('ops:order-center:query')")
|
||||
@@ -87,4 +97,57 @@ public class OrderCenterController {
|
||||
QuickStatsRespDTO stats = cleanDashboardService.getQuickStats();
|
||||
return success(stats);
|
||||
}
|
||||
|
||||
@GetMapping("/dashboard-stats")
|
||||
@Operation(summary = "看板统计")
|
||||
@PreAuthorize("@ss.hasPermission('ops:order-center:query')")
|
||||
public CommonResult<DashboardStatsRespVO> getDashboardStats(
|
||||
@RequestParam(value = "orderType", required = false, defaultValue = "CLEAN") String orderType,
|
||||
@RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate,
|
||||
@RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) {
|
||||
if (opsStatisticsService == null) {
|
||||
log.warn("[getDashboardStats] OpsStatisticsService 未注入,返回默认值");
|
||||
return success(DashboardStatsRespVO.builder().build());
|
||||
}
|
||||
if (startDate == null) {
|
||||
startDate = LocalDate.now().minusDays(6);
|
||||
}
|
||||
if (endDate == null) {
|
||||
endDate = LocalDate.now();
|
||||
}
|
||||
return success(opsStatisticsService.getDashboardStats(orderType, startDate, endDate));
|
||||
}
|
||||
|
||||
@GetMapping("/traffic-realtime")
|
||||
@Operation(summary = "实时客流监测")
|
||||
@PreAuthorize("@ss.hasPermission('ops:order-center:query')")
|
||||
public CommonResult<TrafficRealtimeRespVO> getTrafficRealtime() {
|
||||
if (opsStatisticsService == null) {
|
||||
log.warn("[getTrafficRealtime] OpsStatisticsService 未注入,返回默认值");
|
||||
return success(TrafficRealtimeRespVO.builder().build());
|
||||
}
|
||||
return success(opsStatisticsService.getTrafficRealtime());
|
||||
}
|
||||
|
||||
@GetMapping("/workspace-stats")
|
||||
@Operation(summary = "工作台统计")
|
||||
@PreAuthorize("@ss.hasPermission('ops:order-center:query')")
|
||||
public CommonResult<WorkspaceStatsRespVO> getWorkspaceStats() {
|
||||
if (opsStatisticsService == null) {
|
||||
log.warn("[getWorkspaceStats] OpsStatisticsService 未注入,返回默认值");
|
||||
return success(WorkspaceStatsRespVO.builder().build());
|
||||
}
|
||||
return success(opsStatisticsService.getWorkspaceStats());
|
||||
}
|
||||
|
||||
@GetMapping("/traffic-trend")
|
||||
@Operation(summary = "近7天客流趋势统计")
|
||||
@PreAuthorize("@ss.hasPermission('ops:order-center:query')")
|
||||
public CommonResult<TrafficTrendRespVO> getTrafficTrend() {
|
||||
if (opsStatisticsService == null) {
|
||||
log.warn("[getTrafficTrend] OpsStatisticsService 未注入,返回默认值");
|
||||
return success(TrafficTrendRespVO.builder().build());
|
||||
}
|
||||
return success(opsStatisticsService.getTrafficTrend());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user