feat(aihr): allow employees to complete onboarding tasks

This commit is contained in:
2026-07-15 02:49:40 +08:00
parent 2f21895597
commit 82d93a1af1
11 changed files with 112 additions and 5 deletions
@@ -15,6 +15,7 @@ import org.dromara.aihr.domain.AihrPracticeDto.PracticeAssignmentRequest;
import org.dromara.aihr.domain.AihrPracticeDto.PracticeAssignmentResponse;
import org.dromara.aihr.domain.AihrPracticeDto.PracticeTeamResponse;
import org.dromara.aihr.domain.AihrPracticeDto.OnboardTaskResponse;
import org.dromara.aihr.domain.AihrPracticeDto.OnboardTaskCompleteRequest;
import org.dromara.aihr.domain.AihrPracticeDto.PromotionEvidenceResponse;
import org.dromara.aihr.domain.AihrPracticeDto.QualificationResponse;
import org.dromara.aihr.domain.AihrPracticeDto.RecordResponse;
@@ -205,6 +206,14 @@ public class AihrMobileController {
return R.ok(mobileSeedService.onboardTasks(ownMobileExtPartyId(null)));
}
@PostMapping("/onboard/tasks/{id}/complete")
public R<Void> completeOnboardTask(@PathVariable Long id,
@RequestBody(required = false) OnboardTaskCompleteRequest request) {
String identity = ownMobileExtPartyId(null);
String evidenceRef = request == null ? null : request.evidenceRef();
return mobileSeedService.completeOnboardTask(id, identity, evidenceRef) ? R.ok() : R.fail("任务不存在、已完成或无权操作");
}
@GetMapping("/qualification")
public R<QualificationResponse> qualification() {
return R.ok(mobileSeedService.qualification(ownMobileExtPartyId(null)));
@@ -293,6 +293,9 @@ public final class AihrPracticeDto {
) {
}
public record OnboardTaskCompleteRequest(String evidenceRef) {
}
public record QualificationGateResponse(
Long id,
String projectCode,
@@ -172,6 +172,10 @@ public class AihrMobileSeedService {
return practiceSeedService.onboardTasks(extPartyId, 20);
}
public boolean completeOnboardTask(Long taskId, String extPartyId, String evidenceRef) {
return practiceSeedService.completeOnboardTask(taskId, extPartyId, evidenceRef);
}
public QualificationResponse qualification(String extPartyId) {
return practiceSeedService.qualification(extPartyId);
}
@@ -2086,6 +2086,38 @@ public class AihrPracticeSeedService {
), args.toArray());
}
public boolean completeOnboardTask(Long taskId, String extPartyId, String evidenceRef) {
String identity = isBlank(extPartyId) ? "" : extPartyId.trim();
if (taskId == null || taskId <= 0 || identity.isEmpty() || !formalPositionTablesExist("aihr_onboard_task")) {
return false;
}
String normalizedEvidenceRef = isBlank(evidenceRef) ? null : evidenceRef.trim();
if (normalizedEvidenceRef != null && normalizedEvidenceRef.length() > 500) {
normalizedEvidenceRef = normalizedEvidenceRef.substring(0, 500);
}
boolean hasOrgSnapshot = orgSnapshotTableExists() && orgSnapshotColumnExists("person_phone");
String identityPredicate = hasOrgSnapshot
? "(ext_party_id = ? OR ext_party_id IN (SELECT o.ext_party_id FROM aihr_org_snapshot o WHERE o.tenant_id = ? AND o.employment_status = 'active' AND (o.ext_party_id = ? OR o.person_phone = ?)))"
: "ext_party_id = ?";
List<Object> args = new ArrayList<>();
args.add(normalizedEvidenceRef);
args.add(tenantId());
args.add(taskId);
args.add(identity);
if (hasOrgSnapshot) {
args.add(tenantId());
args.add(identity);
args.add(identity);
}
return jdbcTemplate.update("""
UPDATE aihr_onboard_task
SET status = '已完成', completed_time = now(),
evidence_ref = COALESCE(NULLIF(?, ''), evidence_ref), update_time = now()
WHERE tenant_id = ? AND id = ? AND %s
AND status IN ('待完成', '进行中')
""".formatted(identityPredicate), args.toArray()) > 0;
}
/**
* Return qualification evidence for the current APP user without treating an
* empty rules table as a pass. Formal qualification remains NOT_CONFIGURED until
@@ -660,7 +660,7 @@ public class AihrPracticeSeedServiceTest {
}
@Test
public void formalOnboardingReadsAreLoginScopedAndReadOnly() throws Exception {
public void formalOnboardingReadsAndCompletionAreLoginScoped() throws Exception {
Path source = Path.of("src/main/java/org/dromara/aihr/controller/AihrMobileController.java");
if (!Files.exists(source)) {
source = Path.of("ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java");
@@ -672,7 +672,8 @@ public class AihrPracticeSeedServiceTest {
assertTrue(controllerSource.contains("@GetMapping(\"/qualification\")"));
assertTrue(controllerSource.contains("mobileSeedService.onboardTasks(ownMobileExtPartyId(null))"));
assertTrue(controllerSource.contains("mobileSeedService.qualification(ownMobileExtPartyId(null))"));
assertFalse(controllerSource.contains("@PostMapping(\"/onboard/tasks\")"));
assertTrue(controllerSource.contains("@PostMapping(\"/onboard/tasks/{id}/complete\")"));
assertTrue(controllerSource.contains("mobileSeedService.completeOnboardTask(id, identity, evidenceRef)"));
assertFalse(controllerSource.contains("@PostMapping(\"/qualification\")"));
}