|
|
@@ -30,6 +30,7 @@ public class OkrService {
|
|
|
private final AssessmentPeriodMapper periodMapper;
|
|
|
private final SysUserMapper userMapper;
|
|
|
private final SysDepartmentMapper departmentMapper;
|
|
|
+ private final AuthorizationService authorizationService;
|
|
|
private final ApplicationEventPublisher publisher;
|
|
|
|
|
|
@Transactional
|
|
|
@@ -152,6 +153,15 @@ public class OkrService {
|
|
|
if (krs == null || krs.size() < 2 || krs.size() > 5) {
|
|
|
throw new BusinessException("个人OKR需配置2~5条KR");
|
|
|
}
|
|
|
+ long existingCount = objectiveMapper.selectCount(
|
|
|
+ new LambdaQueryWrapper<OkrObjective>()
|
|
|
+ .eq(OkrObjective::getPeriodId, periodId)
|
|
|
+ .eq(OkrObjective::getUserId, userId)
|
|
|
+ .eq(OkrObjective::getLevel, "INDIVIDUAL")
|
|
|
+ .ne(OkrObjective::getStatus, "REJECTED"));
|
|
|
+ if (existingCount > 0) {
|
|
|
+ throw new BusinessException("你已提交过本周期个人OKR,如需修改请先由上级驳回");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
int weightSum = krs.stream().mapToInt(k -> k.getWeight() != null ? k.getWeight() : 0).sum();
|
|
|
@@ -160,6 +170,20 @@ public class OkrService {
|
|
|
if (parentObjectiveId != null) {
|
|
|
OkrObjective parent = objectiveMapper.selectById(parentObjectiveId);
|
|
|
if (parent == null) throw new BusinessException(404, "对齐目标不存在");
|
|
|
+ if (!Objects.equals(parent.getPeriodId(), periodId)) {
|
|
|
+ throw new BusinessException("只能对齐同一考核周期内的OKR");
|
|
|
+ }
|
|
|
+ authorizationService.requireCanViewOkr(userId, parent);
|
|
|
+ }
|
|
|
+ if (alignedObjectiveIds != null && !alignedObjectiveIds.isEmpty()) {
|
|
|
+ for (Long alignedId : alignedObjectiveIds) {
|
|
|
+ OkrObjective aligned = objectiveMapper.selectById(alignedId);
|
|
|
+ if (aligned == null) throw new BusinessException(404, "对齐目标不存在");
|
|
|
+ if (!Objects.equals(aligned.getPeriodId(), periodId)) {
|
|
|
+ throw new BusinessException("只能对齐同一考核周期内的OKR");
|
|
|
+ }
|
|
|
+ authorizationService.requireCanViewOkr(userId, aligned);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
OkrObjective obj = new OkrObjective();
|
|
|
@@ -291,6 +315,11 @@ public class OkrService {
|
|
|
if (period == null || period.getStatus() != PeriodStatus.EXECUTING) {
|
|
|
throw new BusinessException("当前周期不在执行阶段");
|
|
|
}
|
|
|
+ boolean isOwner = Objects.equals(userId, obj.getUserId());
|
|
|
+ boolean isAssignee = kr.getAssignedTo() != null && Objects.equals(userId, kr.getAssignedTo());
|
|
|
+ if (!isOwner && !isAssignee) {
|
|
|
+ throw new BusinessException(403, "无权更新该KR进度");
|
|
|
+ }
|
|
|
KrProgressLog log = new KrProgressLog();
|
|
|
log.setKrId(krId);
|
|
|
log.setOldValue(kr.getCurrentValue());
|
|
|
@@ -387,7 +416,8 @@ public class OkrService {
|
|
|
return enrichObjectives(objectives);
|
|
|
}
|
|
|
|
|
|
- public List<OkrDetailDto> getDeptMemberOkrs(Long periodId, Long deptId) {
|
|
|
+ public List<OkrDetailDto> getDeptMemberOkrs(Long periodId, Long deptId, Long actorId) {
|
|
|
+ authorizationService.requireCanViewDepartment(actorId, deptId);
|
|
|
List<SysUser> members = userMapper.selectList(
|
|
|
new LambdaQueryWrapper<SysUser>().eq(SysUser::getDepartmentId, deptId));
|
|
|
if (members.isEmpty()) return List.of();
|
|
|
@@ -420,33 +450,39 @@ public class OkrService {
|
|
|
return enrichObjectives(objectives);
|
|
|
}
|
|
|
|
|
|
- public OkrDetailDto getOkrDetail(Long objectiveId) {
|
|
|
+ public OkrDetailDto getOkrDetail(Long objectiveId, Long actorId) {
|
|
|
OkrObjective obj = objectiveMapper.selectById(objectiveId);
|
|
|
if (obj == null) throw new BusinessException(404, "OKR不存在");
|
|
|
+ authorizationService.requireCanViewOkr(actorId, obj);
|
|
|
return enrichObjectives(List.of(obj)).get(0);
|
|
|
}
|
|
|
|
|
|
- public List<KrProgressLog> getKrProgressHistory(Long krId) {
|
|
|
+ public List<KrProgressLog> getKrProgressHistory(Long krId, Long actorId) {
|
|
|
+ KrKeyResult kr = krMapper.selectById(krId);
|
|
|
+ if (kr == null) throw new BusinessException(404, "KR不存在");
|
|
|
+ OkrObjective obj = objectiveMapper.selectById(kr.getObjectiveId());
|
|
|
+ if (obj == null) throw new BusinessException(404, "OKR目标不存在");
|
|
|
+ authorizationService.requireCanViewOkr(actorId, obj);
|
|
|
return progressLogMapper.selectList(
|
|
|
new LambdaQueryWrapper<KrProgressLog>()
|
|
|
.eq(KrProgressLog::getKrId, krId)
|
|
|
.orderByDesc(KrProgressLog::getCreatedAt));
|
|
|
}
|
|
|
|
|
|
- public List<OkrDetailDto> getAllOkrsForPeriod(Long periodId) {
|
|
|
+ public List<OkrDetailDto> getAllOkrsForPeriod(Long periodId, Long actorId) {
|
|
|
List<OkrObjective> objectives = objectiveMapper.selectList(
|
|
|
new LambdaQueryWrapper<OkrObjective>().eq(OkrObjective::getPeriodId, periodId));
|
|
|
- return enrichObjectives(objectives);
|
|
|
+ return enrichObjectives(filterVisibleObjectives(objectives, actorId));
|
|
|
}
|
|
|
|
|
|
public List<OkrDetailDto> getDeptOkrsForPeriod(Long periodId, Long deptId) {
|
|
|
return List.of(); // deprecated
|
|
|
}
|
|
|
|
|
|
- public List<OkrDetailDto> getOkrTree(Long periodId) {
|
|
|
+ public List<OkrDetailDto> getOkrTree(Long periodId, Long actorId) {
|
|
|
List<OkrObjective> all = objectiveMapper.selectList(
|
|
|
new LambdaQueryWrapper<OkrObjective>().eq(OkrObjective::getPeriodId, periodId));
|
|
|
- List<OkrDetailDto> enriched = enrichObjectives(all);
|
|
|
+ List<OkrDetailDto> enriched = enrichObjectives(filterVisibleObjectives(all, actorId));
|
|
|
|
|
|
Map<Long, OkrDetailDto> map = enriched.stream()
|
|
|
.collect(Collectors.toMap(OkrDetailDto::getId, o -> o, (a, b) -> a));
|
|
|
@@ -468,13 +504,51 @@ public class OkrService {
|
|
|
return roots;
|
|
|
}
|
|
|
|
|
|
- public List<OkrDetailDto> getOrphanOkrs(Long periodId) {
|
|
|
+ public List<OkrDetailDto> getOrphanOkrs(Long periodId, Long actorId) {
|
|
|
List<OkrObjective> individuals = objectiveMapper.selectList(
|
|
|
new LambdaQueryWrapper<OkrObjective>()
|
|
|
.eq(OkrObjective::getPeriodId, periodId)
|
|
|
.eq(OkrObjective::getLevel, "INDIVIDUAL")
|
|
|
.isNull(OkrObjective::getParentObjectiveId));
|
|
|
- return enrichObjectives(individuals);
|
|
|
+ return enrichObjectives(filterVisibleObjectives(individuals, actorId));
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<OkrDetailDto> getChildren(Long objectiveId, Long actorId) {
|
|
|
+ OkrObjective parent = objectiveMapper.selectById(objectiveId);
|
|
|
+ if (parent == null) throw new BusinessException(404, "OKR不存在");
|
|
|
+ authorizationService.requireCanViewOkr(actorId, parent);
|
|
|
+ List<OkrObjective> children = objectiveMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<OkrObjective>().eq(OkrObjective::getParentObjectiveId, objectiveId));
|
|
|
+ return enrichObjectives(filterVisibleObjectives(children, actorId));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public void setAlignment(Long objectiveId, Long parentId, Long actorId) {
|
|
|
+ OkrObjective obj = objectiveMapper.selectById(objectiveId);
|
|
|
+ if (obj == null) throw new BusinessException(404, "OKR不存在");
|
|
|
+ if (!Objects.equals(obj.getUserId(), actorId) && !authorizationService.isHrOrAbove(actorId)) {
|
|
|
+ throw new BusinessException(403, "只能调整自己的OKR对齐关系");
|
|
|
+ }
|
|
|
+ AssessmentPeriod period = periodMapper.selectById(obj.getPeriodId());
|
|
|
+ if (period == null || period.getStatus() != PeriodStatus.OKR_ALIGN) {
|
|
|
+ throw new BusinessException("当前周期不在OKR对齐阶段");
|
|
|
+ }
|
|
|
+ if (parentId != null) {
|
|
|
+ OkrObjective parent = objectiveMapper.selectById(parentId);
|
|
|
+ if (parent == null) throw new BusinessException(404, "对齐目标不存在");
|
|
|
+ if (!Objects.equals(parent.getPeriodId(), obj.getPeriodId())) {
|
|
|
+ throw new BusinessException("只能对齐同一考核周期内的OKR");
|
|
|
+ }
|
|
|
+ authorizationService.requireCanViewOkr(actorId, parent);
|
|
|
+ }
|
|
|
+ obj.setParentObjectiveId(parentId);
|
|
|
+ objectiveMapper.updateById(obj);
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<OkrObjective> filterVisibleObjectives(List<OkrObjective> objectives, Long actorId) {
|
|
|
+ return objectives.stream()
|
|
|
+ .filter(obj -> authorizationService.canViewOkr(actorId, obj))
|
|
|
+ .toList();
|
|
|
}
|
|
|
|
|
|
// --- Helper ---
|