package com.mydreamjob.preference; import com.mydreamjob.auth.User; import com.mydreamjob.auth.UserRepository; import com.mydreamjob.common.exception.BusinessException; import com.mydreamjob.common.exception.ErrorCode; import com.mydreamjob.candidatescore.refresh.CandidateScoringRefreshRequestService; import com.mydreamjob.preference.dto.StudentPreferenceRequest; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.mydreamjob.security.UserRoleGuard; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.HashMap; import java.util.List; import java.util.Map; @Slf4j @Service @RequiredArgsConstructor public class PreferenceService { private final com.mydreamjob.security.UserRoleGuard userRoleGuard; private final StudentPreferenceRepository preferenceRepository; private final UserRepository userRepository; /** R01-D4-1:求职偏好更新后登记评分快照刷新(COMPLIANCE 维度)。 */ private final CandidateScoringRefreshRequestService scoringRefreshRequestService; private static final ObjectMapper mapper = new ObjectMapper(); // ── 角色校验 ────────────────────────────────────────────── public void assertStudentRole(Long userId) { userRoleGuard.requireStudent(userId); } // ── 查询 ────────────────────────────────────────────────── public Map getPreferences(Long studentUserId) { assertStudentRole(studentUserId); return preferenceRepository.findByStudentUserId(studentUserId) .map(this::toView) .orElse(emptyView()); } // ── 保存/更新 ──────────────────────────────────────────── @Transactional public Map savePreferences(Long studentUserId, StudentPreferenceRequest req) { assertStudentRole(studentUserId); StudentPreference pref = preferenceRepository.findByStudentUserId(studentUserId) .orElse(StudentPreference.builder() .studentUserId(studentUserId) .remoteAllowed(false) .build()); if (req.getExpectedSalaryMin() != null) pref.setExpectedSalaryMin(req.getExpectedSalaryMin()); if (req.getExpectedSalaryMax() != null) pref.setExpectedSalaryMax(req.getExpectedSalaryMax()); if (req.getPreferredCities() != null) pref.setPreferredCities(toJson(req.getPreferredCities())); if (req.getEmploymentTypes() != null) pref.setEmploymentTypes(toJson(req.getEmploymentTypes())); if (req.getPreferredIndustries() != null) pref.setPreferredIndustries(toJson(req.getPreferredIndustries())); if (req.getPreferredJobTypes() != null) pref.setPreferredJobTypes(toJson(req.getPreferredJobTypes())); if (req.getRemoteAllowed() != null) pref.setRemoteAllowed(req.getRemoteAllowed()); StudentPreference saved = preferenceRepository.save(pref); // R01-D4-1:偏好更新影响 COMPLIANCE 维度 → 登记当前周期刷新。 scoringRefreshRequestService.requestRefresh(studentUserId, LocalDateTime.now()); return toView(saved); } // ── 视图 ────────────────────────────────────────────────── private Map toView(StudentPreference pref) { Map view = new HashMap<>(); view.put("id", pref.getId()); view.put("studentUserId", pref.getStudentUserId()); view.put("expectedSalaryMin", pref.getExpectedSalaryMin()); view.put("expectedSalaryMax", pref.getExpectedSalaryMax()); view.put("preferredCities", fromJson(pref.getPreferredCities())); view.put("employmentTypes", fromJson(pref.getEmploymentTypes())); view.put("preferredIndustries", fromJson(pref.getPreferredIndustries())); view.put("preferredJobTypes", fromJson(pref.getPreferredJobTypes())); view.put("remoteAllowed", pref.getRemoteAllowed()); view.put("createdAt", pref.getCreatedAt()); view.put("updatedAt", pref.getUpdatedAt()); return view; } private Map emptyView() { Map view = new HashMap<>(); view.put("expectedSalaryMin", null); view.put("expectedSalaryMax", null); view.put("preferredCities", List.of()); view.put("employmentTypes", List.of()); view.put("preferredIndustries", List.of()); view.put("preferredJobTypes", List.of()); view.put("remoteAllowed", false); return view; } private String toJson(List list) { try { return mapper.writeValueAsString(list); } catch (JsonProcessingException e) { throw new RuntimeException("Failed to serialize", e); } } private List fromJson(String json) { if (json == null || json.isBlank()) return List.of(); try { return mapper.readValue(json, new TypeReference>() {}); } catch (JsonProcessingException e) { return List.of(); } } }