chenshudong 1 неделя назад
Родитель
Сommit
5209b057cf

+ 265 - 0
airport-admin/src/main/java/com/sundot/airport/web/controller/item/PerformanceIndicatorsController.java

@@ -4,11 +4,16 @@ import cn.hutool.core.collection.CollectionUtil;
4 4
 import cn.hutool.core.date.DateUtil;
5 5
 import com.sundot.airport.common.core.controller.BaseController;
6 6
 import com.sundot.airport.common.core.domain.AjaxResult;
7
+import com.sundot.airport.common.core.domain.entity.SysUser;
7 8
 import com.sundot.airport.common.dto.*;
9
+import com.sundot.airport.common.enums.RoleTypeEnum;
10
+import com.sundot.airport.common.utils.DeptUtils;
8 11
 import com.sundot.airport.common.utils.GeometricMeanUtils;
9 12
 import com.sundot.airport.common.utils.poi.ExcelUtil;
10 13
 import com.sundot.airport.system.domain.SysConfig;
14
+import com.sundot.airport.system.mapper.SysUserMapper;
11 15
 import com.sundot.airport.system.service.ISysConfigService;
16
+import com.sundot.airport.system.service.ISysDeptService;
12 17
 import io.swagger.annotations.Api;
13 18
 import lombok.extern.slf4j.Slf4j;
14 19
 import org.springframework.beans.factory.annotation.Autowired;
@@ -37,6 +42,12 @@ public class PerformanceIndicatorsController extends BaseController {
37 42
     @Autowired
38 43
     private PerformanceMetricsController performanceMetricsController;
39 44
 
45
+    @Autowired
46
+    private SysUserMapper userMapper;
47
+
48
+    @Autowired
49
+    private ISysDeptService sysDeptService;
50
+
40 51
 
41 52
     // 绩效矩阵参数的配置键名
42 53
     private static final String CONFIG_KEY_PARAM_A = "item.performance.matrix.param_a";
@@ -179,6 +190,260 @@ public class PerformanceIndicatorsController extends BaseController {
179 190
     }
180 191
 
181 192
     /**
193
+     * 班组组建
194
+     *
195
+     * @param param 组建参数
196
+     * @return 组建结果
197
+     */
198
+    @PostMapping("/team/build")
199
+    public AjaxResult teamBuild(@RequestBody TeamBuildParamDto param) {
200
+        try {
201
+            // 参数校验
202
+            if (param.getTeamCount() == null || param.getTeamCount() < 1 || param.getTeamCount() > 10) {
203
+                return error("重点班组数量必须在1-10之间");
204
+            }
205
+            if (param.getTargetSize() == null || param.getTargetSize() < 2) {
206
+                return error("目标班组人数至少为2人");
207
+            }
208
+            if (param.getLeaderCondition() == null || param.getLeaderCondition() < 1 || param.getLeaderCondition() > 3) {
209
+                return error("组建班组长条件必须为1-综合能力、2-管理能力、3-业务能力");
210
+            }
211
+
212
+            // 查询个人维度的绩效数据(包含班组长和安检员)
213
+            PerformanceMetricsParamDto metricsParam = new PerformanceMetricsParamDto();
214
+            metricsParam.setDimension(1); // 个人维度
215
+            metricsParam.setStartTime(DateUtil.parse(param.getStartTime(), "yyyy-MM-dd"));
216
+            metricsParam.setEndTime(DateUtil.parse(param.getEndTime(), "yyyy-MM-dd"));
217
+            metricsParam.setSortField("totalScore");
218
+            metricsParam.setSortOrder(2); // 降序
219
+
220
+            AjaxResult result = performanceMetricsController.getPerformanceMetrics(metricsParam);
221
+            List<PerformanceMetricsResultDto> personalMetrics = (List<PerformanceMetricsResultDto>) result.get("data");
222
+
223
+            if (personalMetrics == null || personalMetrics.isEmpty()) {
224
+                return error("未查询到绩效数据");
225
+            }
226
+
227
+            // 获取所有班组长和安检员的用户信息
228
+            Long topSiteId = DeptUtils.getTopSiteId(sysDeptService.selectDeptById(getDeptId()));
229
+            if (topSiteId == null) {
230
+                return error("无法找到有效的站点信息");
231
+            }
232
+
233
+            List<SysUser> allUsers = userMapper.selectUserByDeptId(topSiteId);
234
+            Map<Long, SysUser> userMap = allUsers.stream()
235
+                    .filter(user -> user.getRoles() != null)
236
+                    .filter(user -> user.getRoles().stream()
237
+                            .anyMatch(role -> RoleTypeEnum.banzuzhang.getCode().equals(role.getRoleKey())
238
+                                    || RoleTypeEnum.SecurityCheck.getCode().equals(role.getRoleKey())))
239
+                    .collect(Collectors.toMap(SysUser::getUserId, user -> user, (u1, u2) -> u1));
240
+
241
+            // 根据组建条件选择班组长
242
+            List<TeamBuildResultDto> teamResults = new ArrayList<>();
243
+            Set<Long> selectedUserIds = new HashSet<>(); // 记录已选中的用户
244
+
245
+            // 1. 选择班组长
246
+            List<TeamMemberDto> leaders = selectLeaders(param, personalMetrics, userMap);
247
+            if (leaders.size() < param.getTeamCount()) {
248
+                return error("班组长人数不足,无法组建" + param.getTeamCount() + "个重点班组");
249
+            }
250
+
251
+            // 2. 选择成员并分配
252
+            List<TeamMemberDto> members = selectMembers(param, personalMetrics, userMap, selectedUserIds);
253
+
254
+            // 3. 组建班组
255
+            int memberCount = param.getTargetSize() - 1; // 每个班组的成员数 = 目标人数 - 1个班组长
256
+            int totalMembersNeeded = param.getTeamCount() * memberCount; // 总共需要的成员数
257
+
258
+            if (members.size() < totalMembersNeeded) {
259
+                return error("成员人数不足,需要" + totalMembersNeeded + "人,但只有" + members.size() + "人");
260
+            }
261
+
262
+            // 4. 分配成员到各个班组
263
+            for (int i = 0; i < param.getTeamCount(); i++) {
264
+                TeamBuildResultDto teamResult = new TeamBuildResultDto();
265
+                teamResult.setTeamNo(i + 1);
266
+
267
+                List<TeamMemberDto> teamMembers = new ArrayList<>();
268
+                // 添加班组长
269
+                teamMembers.add(leaders.get(i));
270
+                selectedUserIds.add(leaders.get(i).getUserId());
271
+
272
+                // 随机分配成员
273
+                for (int j = 0; j < memberCount; j++) {
274
+                    int randomIndex = new Random().nextInt(members.size());
275
+                    TeamMemberDto member = members.remove(randomIndex);
276
+                    teamMembers.add(member);
277
+                    selectedUserIds.add(member.getUserId());
278
+                }
279
+
280
+                teamResult.setMembers(teamMembers);
281
+                teamResults.add(teamResult);
282
+            }
283
+
284
+            return success(teamResults);
285
+        } catch (Exception e) {
286
+            log.error("班组组建失败:{}", e.getMessage());
287
+            return error("班组组建失败:" + e.getMessage());
288
+        }
289
+    }
290
+
291
+    /**
292
+     * 根据条件选择班组长
293
+     */
294
+    private List<TeamMemberDto> selectLeaders(TeamBuildParamDto param,
295
+                                              List<PerformanceMetricsResultDto> personalMetrics,
296
+                                              Map<Long, SysUser> userMap) {
297
+        List<TeamMemberDto> leaders = new ArrayList<>();
298
+
299
+        // 筛选出班组长角色的用户绩效数据
300
+        List<PerformanceMetricsResultDto> leaderMetrics = personalMetrics.stream()
301
+                .filter(metric -> {
302
+                    SysUser user = userMap.get(metric.getId());
303
+                    return user != null && user.getRoles().stream()
304
+                            .anyMatch(role -> RoleTypeEnum.banzuzhang.getCode().equals(role.getRoleKey()));
305
+                })
306
+                .collect(Collectors.toList());
307
+
308
+        Integer leaderCondition = param.getLeaderCondition();
309
+        if (leaderCondition == 1) {
310
+            // 综合能力:个人总分和班组总分之和除以2
311
+            // 获取班组绩效数据
312
+            PerformanceMetricsParamDto teamParam = new PerformanceMetricsParamDto();
313
+            teamParam.setDimension(2);
314
+            teamParam.setStartTime(DateUtil.parse(param.getStartTime(), "yyyy-MM-dd"));
315
+            teamParam.setEndTime(DateUtil.parse(param.getEndTime(), "yyyy-MM-dd"));
316
+            teamParam.setSortField("totalScore");
317
+            teamParam.setSortOrder(2);
318
+
319
+            AjaxResult teamResult = performanceMetricsController.getPerformanceMetrics(teamParam);
320
+            List<PerformanceMetricsResultDto> teamMetrics = (List<PerformanceMetricsResultDto>) teamResult.get("data");
321
+            Map<Long, BigDecimal> teamScoreMap = teamMetrics.stream()
322
+                    .collect(Collectors.toMap(PerformanceMetricsResultDto::getId, PerformanceMetricsResultDto::getTotalScore, (s1, s2) -> s1));
323
+
324
+            // 计算综合得分
325
+            for (PerformanceMetricsResultDto metric : leaderMetrics) {
326
+                SysUser user = userMap.get(metric.getId());
327
+                if (user != null && user.getDeptId() != null) {
328
+                    BigDecimal teamScore = teamScoreMap.getOrDefault(user.getDeptId(), BigDecimal.ZERO);
329
+                    BigDecimal comprehensiveScore = metric.getTotalScore()
330
+                            .add(teamScore)
331
+                            .divide(new BigDecimal("2"), 2, BigDecimal.ROUND_HALF_UP);
332
+
333
+                    TeamMemberDto leader = new TeamMemberDto();
334
+                    leader.setUserId(user.getUserId());
335
+                    leader.setName(user.getNickName());
336
+                    leader.setUserName(user.getUserName());
337
+                    leader.setRole("班组长");
338
+                    leader.setScore(comprehensiveScore);
339
+                    leaders.add(leader);
340
+                }
341
+            }
342
+
343
+            // 按综合得分降序排序
344
+            leaders.sort((a, b) -> b.getScore().compareTo(a.getScore()));
345
+
346
+        } else if (leaderCondition == 2) {
347
+            // 管理能力:使用班组维度的绩效总分
348
+            PerformanceMetricsParamDto teamParam = new PerformanceMetricsParamDto();
349
+            teamParam.setDimension(2);
350
+            teamParam.setStartTime(DateUtil.parse(param.getStartTime(), "yyyy-MM-dd"));
351
+            teamParam.setEndTime(DateUtil.parse(param.getEndTime(), "yyyy-MM-dd"));
352
+            teamParam.setSortField("totalScore");
353
+            teamParam.setSortOrder(2);
354
+
355
+            AjaxResult teamResult = performanceMetricsController.getPerformanceMetrics(teamParam);
356
+            List<PerformanceMetricsResultDto> teamMetrics = (List<PerformanceMetricsResultDto>) teamResult.get("data");
357
+            Map<Long, BigDecimal> teamScoreMap = teamMetrics.stream()
358
+                    .collect(Collectors.toMap(PerformanceMetricsResultDto::getId, PerformanceMetricsResultDto::getTotalScore, (s1, s2) -> s1));
359
+
360
+            // 获取班组长所在的班组得分
361
+            for (PerformanceMetricsResultDto metric : leaderMetrics) {
362
+                SysUser user = userMap.get(metric.getId());
363
+                if (user != null && user.getDeptId() != null) {
364
+                    BigDecimal teamScore = teamScoreMap.getOrDefault(user.getDeptId(), BigDecimal.ZERO);
365
+
366
+                    TeamMemberDto leader = new TeamMemberDto();
367
+                    leader.setUserId(user.getUserId());
368
+                    leader.setName(user.getNickName());
369
+                    leader.setUserName(user.getUserName());
370
+                    leader.setRole("班组长");
371
+                    leader.setScore(teamScore);
372
+                    leaders.add(leader);
373
+                }
374
+            }
375
+
376
+            // 按班组得分降序排序
377
+            leaders.sort((a, b) -> b.getScore().compareTo(a.getScore()));
378
+
379
+        } else if (leaderCondition == 3) {
380
+            // 业务能力:使用个人的绩效总分
381
+            for (PerformanceMetricsResultDto metric : leaderMetrics) {
382
+                SysUser user = userMap.get(metric.getId());
383
+                if (user != null) {
384
+                    TeamMemberDto leader = new TeamMemberDto();
385
+                    leader.setUserId(user.getUserId());
386
+                    leader.setName(user.getNickName());
387
+                    leader.setUserName(user.getUserName());
388
+                    leader.setRole("班组长");
389
+                    leader.setScore(metric.getTotalScore());
390
+                    leaders.add(leader);
391
+                }
392
+            }
393
+
394
+            // 按个人总分降序排序
395
+            leaders.sort((a, b) -> b.getScore().compareTo(a.getScore()));
396
+        }
397
+
398
+        // 取前 teamCount 个班组长
399
+        int teamCount = param.getTeamCount();
400
+        return leaders.subList(0, Math.min(teamCount, leaders.size()));
401
+    }
402
+
403
+    /**
404
+     * 选择成员(安检员角色)
405
+     */
406
+    private List<TeamMemberDto> selectMembers(TeamBuildParamDto param,
407
+                                              List<PerformanceMetricsResultDto> personalMetrics,
408
+                                              Map<Long, SysUser> userMap,
409
+                                              Set<Long> selectedUserIds) {
410
+        List<TeamMemberDto> members = new ArrayList<>();
411
+
412
+        // 筛选出安检员角色的用户绩效数据
413
+        List<PerformanceMetricsResultDto> memberMetrics = personalMetrics.stream()
414
+                .filter(metric -> {
415
+                    SysUser user = userMap.get(metric.getId());
416
+                    return user != null && user.getRoles().stream()
417
+                            .anyMatch(role -> RoleTypeEnum.SecurityCheck.getCode().equals(role.getRoleKey()));
418
+                })
419
+                .collect(Collectors.toList());
420
+
421
+        // 转换为成员DTO
422
+        for (PerformanceMetricsResultDto metric : memberMetrics) {
423
+            if (selectedUserIds.contains(metric.getId())) {
424
+                continue; // 跳过已选中的用户
425
+            }
426
+
427
+            SysUser user = userMap.get(metric.getId());
428
+            if (user != null) {
429
+                TeamMemberDto member = new TeamMemberDto();
430
+                member.setUserId(user.getUserId());
431
+                member.setName(user.getNickName());
432
+                member.setUserName(user.getUserName());
433
+                member.setRole("安检员");
434
+                member.setScore(metric.getTotalScore());
435
+                members.add(member);
436
+            }
437
+        }
438
+
439
+        // 按个人总分降序排序
440
+        members.sort((a, b) -> b.getScore().compareTo(a.getScore()));
441
+
442
+        return members;
443
+    }
444
+
445
+
446
+    /**
182 447
      * 转换为人员导出 DTO 列表
183 448
      */
184 449
     private List<PerformanceMetricsPersonalExportDto> convertToPersonalExportList(List<PerformanceMetricsResultDto> dataList, Date startTime, Date endTime) {

+ 31 - 0
airport-common/src/main/java/com/sundot/airport/common/dto/TeamBuildParamDto.java

@@ -0,0 +1,31 @@
1
+package com.sundot.airport.common.dto;
2
+
3
+import io.swagger.annotations.ApiModel;
4
+import io.swagger.annotations.ApiModelProperty;
5
+import lombok.Data;
6
+
7
+/**
8
+ * 班组组建参数DTO
9
+ *
10
+ * @author sundot
11
+ * @date 2026-04-07
12
+ */
13
+@Data
14
+@ApiModel("班组组建参数DTO")
15
+public class TeamBuildParamDto {
16
+
17
+    @ApiModelProperty("重点班组数量(1-10)")
18
+    private Integer teamCount;
19
+
20
+    @ApiModelProperty("目标班组人数(班组长1人 + 成员N人)")
21
+    private Integer targetSize;
22
+
23
+    @ApiModelProperty("组建班组长条件:1-综合能力,2-管理能力,3-业务能力")
24
+    private Integer leaderCondition;
25
+
26
+    @ApiModelProperty("开始时间")
27
+    private String startTime;
28
+
29
+    @ApiModelProperty("结束时间")
30
+    private String endTime;
31
+}

+ 24 - 0
airport-common/src/main/java/com/sundot/airport/common/dto/TeamBuildResultDto.java

@@ -0,0 +1,24 @@
1
+package com.sundot.airport.common.dto;
2
+
3
+import io.swagger.annotations.ApiModel;
4
+import io.swagger.annotations.ApiModelProperty;
5
+import lombok.Data;
6
+
7
+import java.util.List;
8
+
9
+/**
10
+ * 班组组建结果DTO
11
+ *
12
+ * @author sundot
13
+ * @date 2026-04-07
14
+ */
15
+@Data
16
+@ApiModel("班组组建结果DTO")
17
+public class TeamBuildResultDto {
18
+
19
+    @ApiModelProperty("班组编号")
20
+    private Integer teamNo;
21
+
22
+    @ApiModelProperty("班组成员列表")
23
+    private List<TeamMemberDto> members;
24
+}

+ 33 - 0
airport-common/src/main/java/com/sundot/airport/common/dto/TeamMemberDto.java

@@ -0,0 +1,33 @@
1
+package com.sundot.airport.common.dto;
2
+
3
+import io.swagger.annotations.ApiModel;
4
+import io.swagger.annotations.ApiModelProperty;
5
+import lombok.Data;
6
+
7
+import java.math.BigDecimal;
8
+
9
+/**
10
+ * 班组成员DTO
11
+ *
12
+ * @author sundot
13
+ * @date 2026-04-07
14
+ */
15
+@Data
16
+@ApiModel("班组成员DTO")
17
+public class TeamMemberDto {
18
+
19
+    @ApiModelProperty("用户ID")
20
+    private Long userId;
21
+
22
+    @ApiModelProperty("姓名")
23
+    private String name;
24
+
25
+    @ApiModelProperty("账号")
26
+    private String userName;
27
+
28
+    @ApiModelProperty("角色(班组长/安检员)")
29
+    private String role;
30
+
31
+    @ApiModelProperty("分数")
32
+    private BigDecimal score;
33
+}