package com.mydreamjob.onlineresume; import jakarta.validation.Valid; import jakarta.validation.constraints.*; import lombok.Data; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; /** 本人在线简历。PUT 为完整替换;经历 id 由服务器生成,更新时保留。 */ @Data public class OnlineResumeContent { @Valid @NotNull private BasicInfo basicInfo = new BasicInfo(); @Valid @NotNull private JobIntention jobIntention = new JobIntention(); @Valid @NotNull @Size(max = 20) private List<@NotNull Education> educationExperiences = new ArrayList<>(); @Valid @NotNull @Size(max = 30) private List<@NotNull Work> workExperiences = new ArrayList<>(); @Valid @NotNull @Size(max = 30) private List<@NotNull Project> projectExperiences = new ArrayList<>(); @Valid @NotNull @Size(max = 50) private List<@NotNull Skill> skills = new ArrayList<>(); @Size(max = 5000) private String selfEvaluation; @Data @io.swagger.v3.oas.annotations.media.Schema(name = "OnlineResumeBasicInfo") public static class BasicInfo { @Size(max = 50) private String realName; // 这是简历联系方式,不修改 users.phone / users.email 或登录认证。 @Size(max = 30) @Pattern(regexp = "^$|\\+?[0-9][0-9() -]{4,29}") private String phone; @Email @Size(max = 100) private String email; @Size(max = 100) private String location; @Size(max = 100) private String education; @Size(max = 150) private String school; @Min(1900) @Max(2200) private Integer graduationYear; } public enum JobSeekingStatus { LOOKING, OPEN_TO_OPPORTUNITIES, NOT_LOOKING, STUDENT } public enum EmploymentStatus { EMPLOYED, UNEMPLOYED, STUDENT } @Data @io.swagger.v3.oas.annotations.media.Schema(name = "OnlineResumeJobIntention") public static class JobIntention { @Size(max = 120) private String targetPosition; @Min(0) private Integer expectedSalaryMin; @Min(0) private Integer expectedSalaryMax; @NotNull @Size(max = 20) private List<@NotBlank @Size(max = 100) String> preferredCities = new ArrayList<>(); @NotNull @Size(max = 20) private List<@NotBlank @Size(max = 100) String> employmentTypes = new ArrayList<>(); @NotNull @Size(max = 20) private List<@NotBlank @Size(max = 100) String> preferredIndustries = new ArrayList<>(); @Size(max = 20) private List<@NotBlank @Size(max = 64) String> preferredIndustryCodes; @NotNull @Size(max = 20) private List<@NotBlank @Size(max = 100) String> preferredJobTypes = new ArrayList<>(); private boolean remoteAllowed; private JobSeekingStatus jobSeekingStatus; private EmploymentStatus employmentStatus; private LocalDate availableFrom; @AssertTrue(message = "expectedSalaryMin must not exceed expectedSalaryMax") @com.fasterxml.jackson.annotation.JsonIgnore public boolean isSalaryRangeValid() { return expectedSalaryMin == null || expectedSalaryMax == null || expectedSalaryMin <= expectedSalaryMax; } } @Data @io.swagger.v3.oas.annotations.media.Schema(name = "OnlineResumeDatedEntry") public static class DatedEntry { @Pattern(regexp = "[a-f0-9\\-]{36}") private String id; @NotNull private LocalDate startDate; private LocalDate endDate; private boolean ongoing; @Size(max = 5000) private String description; @AssertTrue(message = "ongoing entries have no endDate; otherwise endDate >= startDate is required") @com.fasterxml.jackson.annotation.JsonIgnore public boolean isDateRangeValid() { return ongoing ? endDate == null : startDate != null && endDate != null && !endDate.isBefore(startDate); } } @Data @lombok.EqualsAndHashCode(callSuper = true) @io.swagger.v3.oas.annotations.media.Schema(name = "OnlineResumeEducation", additionalProperties = io.swagger.v3.oas.annotations.media.Schema.AdditionalPropertiesValue.FALSE) public static class Education extends DatedEntry { @NotBlank @Size(max = 150) private String school; @Size(max = 150) private String major; @NotBlank @Size(max = 100) private String degree; } @Data @lombok.EqualsAndHashCode(callSuper = true) @io.swagger.v3.oas.annotations.media.Schema(name = "OnlineResumeWork", additionalProperties = io.swagger.v3.oas.annotations.media.Schema.AdditionalPropertiesValue.FALSE) public static class Work extends DatedEntry { @NotBlank @Size(max = 150) private String company; @NotBlank @Size(max = 120) private String position; @Pattern(regexp = "^(FULL_TIME|INTERNSHIP)$") @io.swagger.v3.oas.annotations.media.Schema(types = {"string", "null"}, pattern = "^(FULL_TIME|INTERNSHIP)$", description = "经历类型:FULL_TIME 正式工作、INTERNSHIP 实习;省略或null表示未区分,不推断历史记录。条目PUT为完整替换,保留类型须回传该字段。") private String experienceType; } @Data @lombok.EqualsAndHashCode(callSuper = true) @io.swagger.v3.oas.annotations.media.Schema(name = "OnlineResumeProject", additionalProperties = io.swagger.v3.oas.annotations.media.Schema.AdditionalPropertiesValue.FALSE) public static class Project extends DatedEntry { @NotBlank @Size(max = 150) private String name; @Size(max = 120) private String role; } public enum SkillLevel { BEGINNER, FAMILIAR, PROFICIENT, EXPERT } @Data @io.swagger.v3.oas.annotations.media.Schema(name = "OnlineResumeSkill", additionalProperties = io.swagger.v3.oas.annotations.media.Schema.AdditionalPropertiesValue.FALSE) public static class Skill { @Pattern(regexp = "[a-f0-9\\-]{36}") private String id; @NotBlank @Size(max = 100) private String name; private SkillLevel level; @Min(0) @Max(80) private Integer years; @Size(max = 1000) private String description; } }