From 9334290fd6005e3f5467f0f611492268a4a8851a Mon Sep 17 00:00:00 2001
From: lapuda <577732344@qq.com>
Date: Mon, 20 Jul 2026 11:30:22 +0800
Subject: [PATCH] feat: Add salary composition, welfare benefits, and work
schedule fields to Job model and database
---
.../main/java/com/ruoyi/cms/domain/Job.java | 12 ++
.../main/resources/mapper/app/JobMapper.xml | 11 +-
.../ruoyi/cms/domain/JobDetailTagsTest.java | 33 ++++++
...igration_add_job_compensation_benefits.sql | 106 ++++++++++++++++++
4 files changed, 161 insertions(+), 1 deletion(-)
create mode 100644 ruoyi-bussiness/src/test/java/com/ruoyi/cms/domain/JobDetailTagsTest.java
create mode 100644 sql/migration_add_job_compensation_benefits.sql
diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/Job.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/Job.java
index 32a3141..4fbf8a8 100644
--- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/Job.java
+++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/Job.java
@@ -48,6 +48,18 @@ public class Job extends BaseEntity
@ApiModelProperty("最大薪资(元)")
private Long maxSalary;
+ @Excel(name = "薪资范围与构成")
+ @ApiModelProperty("薪资范围与构成(薪资数值范围使用 minSalary/maxSalary),对应业务字典 salary_composition,多项及手动输入值以英文逗号分隔")
+ private String salaryComposition;
+
+ @Excel(name = "福利待遇")
+ @ApiModelProperty("福利待遇,对应业务字典 welfare_benefits,多项及手动输入值以英文逗号分隔")
+ private String welfareBenefits;
+
+ @Excel(name = "工作时间安排")
+ @ApiModelProperty("工作时间安排,对应业务字典 work_schedule,多项及手动输入值以英文逗号分隔")
+ private String workSchedule;
+
@TableField(exist = false)
private Long salaryMin;
diff --git a/ruoyi-bussiness/src/main/resources/mapper/app/JobMapper.xml b/ruoyi-bussiness/src/main/resources/mapper/app/JobMapper.xml
index 913d525..568329f 100644
--- a/ruoyi-bussiness/src/main/resources/mapper/app/JobMapper.xml
+++ b/ruoyi-bussiness/src/main/resources/mapper/app/JobMapper.xml
@@ -9,6 +9,9 @@
+
+
+
@@ -113,7 +116,13 @@
- select job_id, job_title, min_salary, max_salary, education, experience, company_name, job_location, posting_date, vacancies, del_flag, create_by, create_time, update_by, update_time, remark, latitude, longitude, "view", company_id , is_hot ,is_urgent,apply_num,is_publish, description,job_location_area_code,data_source,job_url,job_category,is_explain,explain_url,cover,job_type,job_address, review_status,is_key_populations,key_populations from job
+ select job_id, job_title, min_salary, max_salary, salary_composition, welfare_benefits,
+ work_schedule, education, experience, company_name, job_location, posting_date, vacancies,
+ del_flag, create_by, create_time, update_by, update_time, remark, latitude, longitude, "view",
+ company_id, is_hot, is_urgent, apply_num, is_publish, description, job_location_area_code,
+ data_source, job_url, job_category, is_explain, explain_url, cover, job_type, job_address,
+ review_status, is_key_populations, key_populations
+ from job
INSERT INTO row_work (
diff --git a/ruoyi-bussiness/src/test/java/com/ruoyi/cms/domain/JobDetailTagsTest.java b/ruoyi-bussiness/src/test/java/com/ruoyi/cms/domain/JobDetailTagsTest.java
new file mode 100644
index 0000000..7420ce8
--- /dev/null
+++ b/ruoyi-bussiness/src/test/java/com/ruoyi/cms/domain/JobDetailTagsTest.java
@@ -0,0 +1,33 @@
+package com.ruoyi.cms.domain;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class JobDetailTagsTest
+{
+ private final ObjectMapper objectMapper = new ObjectMapper();
+
+ @Test
+ void detailTagsRoundTripAsCommaSeparatedStrings() throws Exception
+ {
+ String requestJson = "{"
+ + "\"salaryComposition\":\"基本工资,绩效工资,项目提成\","
+ + "\"welfareBenefits\":\"五险一金,带薪年假,生日福利\","
+ + "\"workSchedule\":\"早10点-下午7点,午休2小时,周末双休\""
+ + "}";
+
+ Job job = objectMapper.readValue(requestJson, Job.class);
+
+ assertEquals("基本工资,绩效工资,项目提成", job.getSalaryComposition());
+ assertEquals("五险一金,带薪年假,生日福利", job.getWelfareBenefits());
+ assertEquals("早10点-下午7点,午休2小时,周末双休", job.getWorkSchedule());
+
+ JsonNode responseJson = objectMapper.readTree(objectMapper.writeValueAsString(job));
+ assertEquals("基本工资,绩效工资,项目提成", responseJson.get("salaryComposition").asText());
+ assertEquals("五险一金,带薪年假,生日福利", responseJson.get("welfareBenefits").asText());
+ assertEquals("早10点-下午7点,午休2小时,周末双休", responseJson.get("workSchedule").asText());
+ }
+}
diff --git a/sql/migration_add_job_compensation_benefits.sql b/sql/migration_add_job_compensation_benefits.sql
new file mode 100644
index 0000000..2885dcb
--- /dev/null
+++ b/sql/migration_add_job_compensation_benefits.sql
@@ -0,0 +1,106 @@
+-- 岗位薪资构成、福利待遇、工作时间安排字段及业务字典初始化。
+-- 执行目标:对应环境 HighGo 数据库的 shz schema。
+-- 可重复执行:字段使用 IF NOT EXISTS,字典类型和字典项分别按 dict_type、dict_value 去重。
+
+BEGIN;
+
+ALTER TABLE "shz"."job"
+ ADD COLUMN IF NOT EXISTS "salary_composition" VARCHAR(1000),
+ ADD COLUMN IF NOT EXISTS "welfare_benefits" VARCHAR(1000),
+ ADD COLUMN IF NOT EXISTS "work_schedule" VARCHAR(1000);
+
+COMMENT ON COLUMN "shz"."job"."salary_composition"
+ IS '薪资范围与构成(数值范围使用 min_salary/max_salary),多项及手动输入值以英文逗号分隔,对应业务字典 salary_composition';
+COMMENT ON COLUMN "shz"."job"."welfare_benefits"
+ IS '福利待遇,多项及手动输入值以英文逗号分隔,对应业务字典 welfare_benefits';
+COMMENT ON COLUMN "shz"."job"."work_schedule"
+ IS '工作时间安排,多项及手动输入值以英文逗号分隔,对应业务字典 work_schedule';
+
+WITH seed("dict_sort", "dict_name", "dict_type", "remark") AS (
+ VALUES
+ (1, '薪资范围与构成', 'salary_composition', '岗位薪资范围与构成,可与手动输入值组合使用'),
+ (2, '福利待遇', 'welfare_benefits', '岗位福利待遇,可与手动输入值组合使用'),
+ (3, '工作时间安排', 'work_schedule', '岗位工作时间安排,可与手动输入值组合使用')
+),
+new_rows AS (
+ SELECT
+ ROW_NUMBER() OVER (ORDER BY seed."dict_sort") AS rn,
+ seed.*
+ FROM seed
+ WHERE NOT EXISTS (
+ SELECT 1
+ FROM "shz"."bussiness_dict_type" existing_type
+ WHERE existing_type."dict_type" = seed."dict_type"
+ )
+),
+base AS (
+ SELECT COALESCE(MAX("dict_id"), 0) AS max_id
+ FROM "shz"."bussiness_dict_type"
+)
+INSERT INTO "shz"."bussiness_dict_type" (
+ "dict_id", "dict_name", "dict_type", "status", "create_by", "create_time", "remark"
+)
+SELECT
+ base.max_id + new_rows.rn,
+ new_rows."dict_name",
+ new_rows."dict_type",
+ '0',
+ 'system',
+ CURRENT_TIMESTAMP,
+ new_rows."remark"
+FROM new_rows
+CROSS JOIN base;
+
+WITH seed("dict_type", "dict_sort", "dict_label", "dict_value") AS (
+ VALUES
+ ('salary_composition', 1, '基本工资', '基本工资'),
+ ('salary_composition', 2, '绩效工资', '绩效工资'),
+ ('salary_composition', 3, '奖金', '奖金'),
+ ('welfare_benefits', 1, '五险一金', '五险一金'),
+ ('welfare_benefits', 2, '带薪年假', '带薪年假'),
+ ('welfare_benefits', 3, '节日福利', '节日福利'),
+ ('welfare_benefits', 4, '定期体检', '定期体检'),
+ ('welfare_benefits', 5, '培训机会', '培训机会'),
+ ('welfare_benefits', 6, '员工团建', '员工团建'),
+ ('welfare_benefits', 7, '餐补', '餐补'),
+ ('welfare_benefits', 8, '房补', '房补'),
+ ('work_schedule', 1, '早10点-下午7点', '早10点-下午7点'),
+ ('work_schedule', 2, '午休2小时', '午休2小时')
+),
+new_rows AS (
+ SELECT
+ ROW_NUMBER() OVER (ORDER BY seed."dict_type", seed."dict_sort") AS rn,
+ seed.*
+ FROM seed
+ WHERE NOT EXISTS (
+ SELECT 1
+ FROM "shz"."bussiness_dict_data" data
+ WHERE data."dict_type" = seed."dict_type"
+ AND data."dict_value" = seed."dict_value"
+ )
+),
+base AS (
+ SELECT COALESCE(MAX("dict_code"), 0) AS max_code
+ FROM "shz"."bussiness_dict_data"
+)
+INSERT INTO "shz"."bussiness_dict_data" (
+ "dict_code", "dict_sort", "dict_label", "dict_value", "dict_type",
+ "css_class", "list_class", "is_default", "status", "create_by", "create_time", "remark"
+)
+SELECT
+ base.max_code + new_rows.rn,
+ new_rows."dict_sort",
+ new_rows."dict_label",
+ new_rows."dict_value",
+ new_rows."dict_type",
+ NULL,
+ 'default',
+ 'N',
+ '0',
+ 'system',
+ CURRENT_TIMESTAMP,
+ '岗位详情标签'
+FROM new_rows
+CROSS JOIN base;
+
+COMMIT;