diff --git a/klp-admin/src/main/java/com/klp/web/controller/monitor/OperPerformanceController.java b/klp-admin/src/main/java/com/klp/web/controller/monitor/OperPerformanceController.java index 7416f808d..4052a05fb 100644 --- a/klp-admin/src/main/java/com/klp/web/controller/monitor/OperPerformanceController.java +++ b/klp-admin/src/main/java/com/klp/web/controller/monitor/OperPerformanceController.java @@ -4,6 +4,7 @@ import cn.dev33.satoken.annotation.SaCheckPermission; import com.klp.common.core.controller.BaseController; import com.klp.common.core.domain.R; import com.klp.system.domain.bo.OperPerformanceQuery; +import com.klp.system.domain.vo.OperMenuGroupVO; import com.klp.system.domain.vo.OperModuleStatVO; import com.klp.system.domain.vo.OperPersonVO; import com.klp.system.domain.vo.OperSummaryVO; @@ -55,4 +56,13 @@ public class OperPerformanceController extends BaseController { public R> module(OperPerformanceQuery query) { return R.ok(operLogService.selectModuleRanking(query)); } + + /** + * 按菜单分组绩效统计(oper_page 匹配一级菜单 path) + */ + @SaCheckPermission("monitor:performance:list") + @GetMapping("/menuGroup") + public R> menuGroup(OperPerformanceQuery query) { + return R.ok(operLogService.selectMenuGroupPerformance(query)); + } } diff --git a/klp-system/src/main/java/com/klp/system/domain/bo/OperPerformanceQuery.java b/klp-system/src/main/java/com/klp/system/domain/bo/OperPerformanceQuery.java index e75f0e93b..7787e103f 100644 --- a/klp-system/src/main/java/com/klp/system/domain/bo/OperPerformanceQuery.java +++ b/klp-system/src/main/java/com/klp/system/domain/bo/OperPerformanceQuery.java @@ -40,4 +40,9 @@ public class OperPerformanceQuery implements Serializable { * 模块标题 */ private String title; + + /** + * oper_page 路径前缀(用于按一级菜单过滤,如 /wip) + */ + private String operPagePrefix; } diff --git a/klp-system/src/main/java/com/klp/system/domain/vo/OperMenuGroupVO.java b/klp-system/src/main/java/com/klp/system/domain/vo/OperMenuGroupVO.java new file mode 100644 index 000000000..237c833e2 --- /dev/null +++ b/klp-system/src/main/java/com/klp/system/domain/vo/OperMenuGroupVO.java @@ -0,0 +1,44 @@ +package com.klp.system.domain.vo; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 菜单分组绩效统计 VO(按一级菜单 oper_page 归类) + * + * @author Reasonix + */ +@Data +@NoArgsConstructor +public class OperMenuGroupVO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 菜单名称(驾驶舱、生产管控……) */ + private String menuName; + + /** 菜单路由路径前缀(post、wip……) */ + private String menuPath; + + /** 该分类操作总次数 */ + private Long totalCount; + + /** 成功次数 */ + private Long successCount; + + /** 失败次数 */ + private Long failCount; + + /** 成功率 (%) */ + private Double successRate; + + /** 使用人数 */ + private Long personCount; + + /** 该分类下的模块明细列表 */ + private List modules = new ArrayList<>(); +} diff --git a/klp-system/src/main/java/com/klp/system/domain/vo/OperModuleStatVO.java b/klp-system/src/main/java/com/klp/system/domain/vo/OperModuleStatVO.java index e9c26ee3e..96af83072 100644 --- a/klp-system/src/main/java/com/klp/system/domain/vo/OperModuleStatVO.java +++ b/klp-system/src/main/java/com/klp/system/domain/vo/OperModuleStatVO.java @@ -16,6 +16,11 @@ public class OperModuleStatVO implements Serializable { private static final long serialVersionUID = 1L; + /** + * 所属菜单分组(菜单名称,如"驾驶舱") + */ + private String menuGroup; + /** * 模块标题 */ diff --git a/klp-system/src/main/java/com/klp/system/mapper/SysOperLogMapper.java b/klp-system/src/main/java/com/klp/system/mapper/SysOperLogMapper.java index 2dfc22d48..c134129b0 100644 --- a/klp-system/src/main/java/com/klp/system/mapper/SysOperLogMapper.java +++ b/klp-system/src/main/java/com/klp/system/mapper/SysOperLogMapper.java @@ -35,4 +35,9 @@ public interface SysOperLogMapper extends BaseMapperPlus selectMenuGroupDetail(OperPerformanceQuery query); } diff --git a/klp-system/src/main/java/com/klp/system/service/ISysOperLogService.java b/klp-system/src/main/java/com/klp/system/service/ISysOperLogService.java index 9f11aeeeb..f5c8db56d 100644 --- a/klp-system/src/main/java/com/klp/system/service/ISysOperLogService.java +++ b/klp-system/src/main/java/com/klp/system/service/ISysOperLogService.java @@ -4,6 +4,7 @@ import com.klp.common.core.domain.PageQuery; import com.klp.common.core.page.TableDataInfo; import com.klp.system.domain.SysOperLog; import com.klp.system.domain.bo.OperPerformanceQuery; +import com.klp.system.domain.vo.OperMenuGroupVO; import com.klp.system.domain.vo.OperModuleStatVO; import com.klp.system.domain.vo.OperPersonVO; import com.klp.system.domain.vo.OperSummaryVO; @@ -69,4 +70,9 @@ public interface ISysOperLogService { * 模块使用排行 */ List selectModuleRanking(OperPerformanceQuery query); + + /** + * 按菜单分组绩效统计(oper_page 匹配一级菜单 path) + */ + List selectMenuGroupPerformance(OperPerformanceQuery query); } diff --git a/klp-system/src/main/java/com/klp/system/service/impl/SysOperLogServiceImpl.java b/klp-system/src/main/java/com/klp/system/service/impl/SysOperLogServiceImpl.java index 9a5a36d30..d6977eebc 100644 --- a/klp-system/src/main/java/com/klp/system/service/impl/SysOperLogServiceImpl.java +++ b/klp-system/src/main/java/com/klp/system/service/impl/SysOperLogServiceImpl.java @@ -11,6 +11,7 @@ import com.klp.common.utils.StringUtils; import com.klp.common.utils.ip.AddressUtils; import com.klp.system.domain.SysOperLog; import com.klp.system.domain.bo.OperPerformanceQuery; +import com.klp.system.domain.vo.OperMenuGroupVO; import com.klp.system.domain.vo.OperModuleStatVO; import com.klp.system.domain.vo.OperPersonVO; import com.klp.system.domain.vo.OperSummaryVO; @@ -151,6 +152,86 @@ public class SysOperLogServiceImpl implements ISysOperLogService { return baseMapper.selectModuleSummary(query); } + @Override + public List selectMenuGroupPerformance(OperPerformanceQuery query) { + // 1. 查询原始数据(按 menu_group + title 双维度聚合) + List rawList = baseMapper.selectMenuGroupDetail(query); + if (rawList == null || rawList.isEmpty()) { + return Collections.emptyList(); + } + + // 2. 按 menuGroup 分组 + Map> groupMap = rawList.stream() + .collect(Collectors.groupingBy( + m -> m.getMenuGroup() != null ? m.getMenuGroup() : "其他", + LinkedHashMap::new, + Collectors.toList() + )); + + // 3. 固定顺序 + List orderNames = java.util.Arrays.asList( + "驾驶舱", "生产管控", "数字仓储", "质量管理", + "销售中心", "生产辅助", "科学排产", "文件夹", "其他" + ); + // path 前缀映射 + Map nameToPath = new LinkedHashMap<>(); + nameToPath.put("驾驶舱", "post"); + nameToPath.put("生产管控", "wip"); + nameToPath.put("数字仓储", "stock"); + nameToPath.put("质量管理", "quality"); + nameToPath.put("销售中心", "crm"); + nameToPath.put("生产辅助", "helper"); + nameToPath.put("科学排产", "aps"); + nameToPath.put("文件夹", "file"); + nameToPath.put("其他", ""); + + // 4. 构建 VO 列表 + List result = new ArrayList<>(); + for (String name : orderNames) { + List modules = groupMap.get(name); + if (modules == null || modules.isEmpty()) { + continue; // 没有数据的分类不展示 + } + + OperMenuGroupVO vo = new OperMenuGroupVO(); + vo.setMenuName(name); + vo.setMenuPath(nameToPath.getOrDefault(name, "")); + + // 汇总该分类的总量 + long total = modules.stream().mapToLong(m -> m.getTotalCount() != null ? m.getTotalCount() : 0).sum(); + long success = modules.stream() + .mapToLong(m -> Math.round((m.getTotalCount() != null ? m.getTotalCount() : 0) + * (m.getSuccessRate() != null ? m.getSuccessRate() : 0) / 100.0)) + .sum(); + long fail = total - success; + long persons = modules.stream() + .mapToLong(m -> m.getPersonCount() != null ? m.getPersonCount() : 0).sum(); + // 去重人数更合理:取各模块人数最大值作为估算(无法精确去重) + long distinctPersons = modules.stream() + .mapToLong(m -> m.getPersonCount() != null ? m.getPersonCount() : 0) + .max().orElse(0); + // 用 distinct 人数更合理,取模块中最大人数(保守估计) + // 实际跨模块可能有重复,这里用最大模块人数作为下限 + vo.setTotalCount(total); + vo.setSuccessCount(success); + vo.setFailCount(fail); + vo.setSuccessRate(total > 0 ? Math.round(success * 10000.0 / total) / 100.0 : 0.0); + vo.setPersonCount(distinctPersons); + + // 模块明细按 totalCount 降序排列 + modules.sort((a, b) -> { + long ta = a.getTotalCount() != null ? a.getTotalCount() : 0; + long tb = b.getTotalCount() != null ? b.getTotalCount() : 0; + return Long.compare(tb, ta); + }); + vo.setModules(modules); + + result.add(vo); + } + + return result; + } + @Override public List selectPersonPerformance(OperPerformanceQuery query) { // 1. 查询人员汇总 diff --git a/klp-system/src/main/resources/mapper/system/SysOperLogMapper.xml b/klp-system/src/main/resources/mapper/system/SysOperLogMapper.xml index c1a6f309b..66a15573d 100644 --- a/klp-system/src/main/resources/mapper/system/SysOperLogMapper.xml +++ b/klp-system/src/main/resources/mapper/system/SysOperLogMapper.xml @@ -40,6 +40,7 @@ + @@ -90,6 +91,9 @@ AND l.title LIKE CONCAT('%', #{title}, '%') + + AND l.oper_page LIKE CONCAT(#{operPagePrefix}, '%') + GROUP BY l.title ORDER BY total_count DESC @@ -126,6 +130,9 @@ AND l.title LIKE CONCAT('%', #{title}, '%') + + AND l.oper_page LIKE CONCAT(#{operPagePrefix}, '%') + GROUP BY l.oper_name, l.dept_name ORDER BY total_count DESC @@ -159,6 +166,9 @@ AND l.title LIKE CONCAT('%', #{title}, '%') + + AND l.oper_page LIKE CONCAT(#{operPagePrefix}, '%') + GROUP BY l.oper_name, l.title ORDER BY l.oper_name, total_count DESC @@ -190,7 +200,57 @@ AND l.title LIKE CONCAT('%', #{title}, '%') + + AND l.oper_page LIKE CONCAT(#{operPagePrefix}, '%') + + + + diff --git a/klp-ui/src/api/monitor/performance.js b/klp-ui/src/api/monitor/performance.js index a79abc42e..f8ad1bd24 100644 --- a/klp-ui/src/api/monitor/performance.js +++ b/klp-ui/src/api/monitor/performance.js @@ -26,3 +26,12 @@ export function getModuleRanking(params) { params: params }) } + +// 按菜单分组绩效统计(oper_page 匹配一级菜单) +export function getMenuGroup(params) { + return request({ + url: '/monitor/performance/menuGroup', + method: 'get', + params: params + }) +} diff --git a/klp-ui/src/views/monitor/performance/index.vue b/klp-ui/src/views/monitor/performance/index.vue index 92de84554..552e029ea 100644 --- a/klp-ui/src/views/monitor/performance/index.vue +++ b/klp-ui/src/views/monitor/performance/index.vue @@ -77,6 +77,70 @@ + +
+ + +
+
+ 各模块操作量对比 + 点击柱子可按分类筛选下方图表 +
+
+
+ + + + +
+
分类模块明细
+
+ + + + + + + + + + + + + + + +
+
+
+ + +
+ + + {{ selectedMenuGroup.menuName }} + + — 以下图表仅显示该分类数据 +
+
@@ -176,16 +240,30 @@