Merge branch 'main' of ssh://124.243.245.42:2222/zkr/shz-backend

This commit is contained in:
2026-07-03 13:19:52 +08:00
20 changed files with 1591 additions and 79 deletions

View File

@@ -107,6 +107,17 @@ public class CmsPolicyInfoController extends BaseController {
return toAjax(policyInfoService.deleteByIds(ids));
}
/**
* 更新政策状态(启用/禁用)
*/
@PreAuthorize("@ss.hasPermi('cms:policyInfo:status')")
@Log(title = "政策信息", businessType = BusinessType.UPDATE)
@ApiOperation("更新政策状态")
@PutMapping("/changeStatus")
public AjaxResult changeStatus(@RequestParam Long id, @RequestParam String status) {
return toAjax(policyInfoService.updateStatus(id, status));
}
/**
* 上传政策文件
*/

View File

@@ -117,6 +117,7 @@ public class ESJobDocument
private String industry;
@ApiModelProperty("岗位分类")
@IndexField(fieldType = FieldType.TEXT, analyzer = Analyzer.IK_SMART, searchAnalyzer = Analyzer.IK_SMART)
private String jobCategory;
@JsonIgnore

View File

@@ -97,4 +97,10 @@ public class InterviewInvitation extends BaseEntity {
*/
@ApiModelProperty("状态")
private String status;
/**
* 备注(覆盖父类,去掉 @JsonIgnore 以支持序列化)
*/
@ApiModelProperty("备注")
private String remark;
}

View File

@@ -67,4 +67,7 @@ public class PolicyInfo extends BaseEntity {
//标签
/** 1-大龄人员;2-低保人员;3-残疾人员;4-失地农名或联队职工;5-防止返贫;6-未就业大中专毕业生;7-退役军人;8-长期失业人员;9-城镇零就业家庭成员10.刑满释放人员 **/
private String policyTag;
@ApiModelProperty("状态0启用 1禁用")
private String status;
}

View File

@@ -28,5 +28,8 @@ public class PolicyInfoQuery {
@ApiModelProperty("标签")
private String policyTag;
@ApiModelProperty("状态0启用 1禁用空表示不过滤")
private String status;
private List<String> policyTags;
}

View File

@@ -12,7 +12,7 @@ public class CandidateVO extends AppUser {
@JsonFormat(pattern = "yyyy-MM-dd")
private Date applyDate;
private Integer matchingDegree;
private String applyId;
private Long applyId;
private String hire;
@Excel(name = "公司名称", sort = 0)
private String companyName;

View File

@@ -42,4 +42,9 @@ public interface PolicyInfoMapper {
* 批量删除政策
*/
int deletePolicyInfoByIds(@Param("ids") Long[] ids);
/**
* 更新政策状态(启用/禁用)
*/
int updateStatus(@Param("id") Long id, @Param("status") String status);
}

View File

@@ -61,8 +61,6 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper,AppUser> imple
if (appUser == null) {
return null;
}
//处理身份证脱敏
appUser.setIdCard(StringUtil.desensitizeIdCard(appUser.getIdCard()));
if(StringUtils.isNotEmpty(appUser.getJobTitleId())){
List<String> list = Arrays.asList(appUser.getJobTitleId().split(","));
List<Long> collect = list.stream().map(Long::valueOf).collect(Collectors.toList());
@@ -95,6 +93,8 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper,AppUser> imple
List<File> files=fileMapper.selectFileList(file);
appUser.setFileList(files);
}
//处理身份证脱敏
appUser.setIdCard(StringUtil.desensitizeIdCard(appUser.getIdCard()));
return appUser;
}

View File

@@ -9,7 +9,9 @@ import com.ruoyi.cms.domain.Job;
import com.ruoyi.cms.domain.query.ESJobSearch;
import com.ruoyi.cms.mapper.es.EsJobDocumentMapper;
import com.ruoyi.cms.mapper.JobMapper;
import com.ruoyi.cms.mapper.JobTitleMapper;
import com.ruoyi.cms.service.IESJobSearchService;
import com.ruoyi.common.core.domain.entity.JobTitle;
import com.ruoyi.cms.util.ListUtil;
import com.ruoyi.cms.util.StringUtil;
import com.ruoyi.common.core.domain.entity.Company;
@@ -68,6 +70,8 @@ public class ESJobSearchImpl implements IESJobSearchService
@Autowired
private BussinessDictDataServiceImpl bussinessDictDataServicel;
@Autowired
private JobTitleMapper jobTitleMapper;
Logger logger = LoggerFactory.getLogger(JobServiceImpl.class);
/**
* 项目启动时,初始化索引及数据
@@ -181,6 +185,7 @@ public class ESJobSearchImpl implements IESJobSearchService
for (Job job : jobList) {
ESJobDocument esJobDocument = new ESJobDocument();
BeanUtils.copyBeanProp(esJobDocument, job);
esJobDocument.setJobCategory(resolveJobCategoryLabel(job.getJobCategory()));
//类型转换导致赋值问题,重新赋值
esJobDocument.setScale(org.apache.commons.lang3.StringUtils.isNotEmpty(job.getScale()) ? Integer.parseInt(job.getScale()) : 0);
CompanyVo vo=job.getCompanyVo();
@@ -260,14 +265,13 @@ public class ESJobSearchImpl implements IESJobSearchService
List<ESJobDocument> esJobDocuments = esJobDocumentMapper.selectList(wrapper);
if (!isCompanyUser &&esJobDocuments.size() < esJobSearch.getPageSize()) {
// 定义要逐步放宽的搜索条件字段
// 定义要逐步放宽的搜索条件字段(不放松核心文本搜索条件)
List<Runnable> relaxConditions = new ArrayList<>();
relaxConditions.add(() -> newSearch.setArea(null));
relaxConditions.add(() -> newSearch.setExperience(null));
relaxConditions.add(() -> newSearch.setMaxSalary(null));
relaxConditions.add(() -> newSearch.setMinSalary(null));
relaxConditions.add(() -> newSearch.setEducation(null));
relaxConditions.add(()-> newSearch.setJobTitle(null));
// 保存所有查询到的文档
List<ESJobDocument> allDocuments = new ArrayList<>(esJobDocuments);
@@ -513,13 +517,20 @@ public class ESJobSearchImpl implements IESJobSearchService
String[] words = titleStr.split(",");
for (String w : words) {
if (!first) sub.or();
// 同时匹配岗位名称和岗位分类jobCategory 已存储为标签文字)
sub.match(ESJobDocument::getJobTitle, w, 5.0f);
sub.or();
sub.match(ESJobDocument::getJobCategory, w, 5.0f);
first = false;
}
}
if (!StringUtil.isEmptyOrNull(cateStr)) {
// category 搜索时同时匹配 jobCategory 和 jobTitle避免因 jobCategory 字段为空而搜不到
if (!first) sub.or();
sub.eq(ESJobDocument::getJobCategory, cateStr);
sub.match(ESJobDocument::getJobCategory, cateStr, 5.0f);
first = false;
sub.or();
sub.match(ESJobDocument::getJobTitle, cateStr, 5.0f);
}
});
}
@@ -535,17 +546,17 @@ public class ESJobSearchImpl implements IESJobSearchService
Long userMinSalary = Objects.nonNull(esJobSearch.getSalaryMin()) ? esJobSearch.getSalaryMin() : esJobSearch.getMinSalary();
Long userMaxSalary = Objects.nonNull(esJobSearch.getSalaryMax()) ? esJobSearch.getSalaryMax() : esJobSearch.getMaxSalary();
// 岗位薪资范围与用户期望薪资范围有交集
// 条件:岗位最薪资 <= 用户最大薪资 AND 岗位最大薪资 >= 用户最小薪资
// 岗位最高薪资必须在用户筛选范围内
// 条件:岗位最薪资 <= 用户最大薪资 AND 岗位最大薪资 >= 用户最小薪资
if(Objects.nonNull(userMinSalary) && Objects.nonNull(userMaxSalary)){
wrapper.and(x->x.le(ESJobDocument::getMinSalary,userMaxSalary)
wrapper.and(x->x.le(ESJobDocument::getMaxSalary,userMaxSalary)
.ge(ESJobDocument::getMaxSalary,userMinSalary));
} else if(Objects.nonNull(userMinSalary)){
// 只有最小薪资:岗位最大薪资 >= 用户最小薪资
wrapper.and(x->x.ge(ESJobDocument::getMaxSalary,userMinSalary));
} else if(Objects.nonNull(userMaxSalary)){
// 只有最大薪资:岗位最薪资 <= 用户最大薪资
wrapper.and(x->x.le(ESJobDocument::getMinSalary,userMaxSalary));
// 只有最大薪资:岗位最薪资 <= 用户最大薪资
wrapper.and(x->x.le(ESJobDocument::getMaxSalary,userMaxSalary));
}
if(!StringUtil.isEmptyOrNull(esJobSearch.getExperience())){
Integer maxValue = StringUtil.findMaxValue(esJobSearch.getExperience());
@@ -644,20 +655,37 @@ public class ESJobSearchImpl implements IESJobSearchService
.match(ESJobDocument::getDescription,jobQuery.getJobTitle().trim(),1.0f));
}
if(hasText(jobQuery.getEducation())){
wrapper.and(a->a.eq(ESJobDocument::getEducation,jobQuery.getEducation().trim()));
// 支持逗号分隔的多值筛选(如 "3,4"
String eduStr = jobQuery.getEducation().trim();
if (eduStr.contains(",")) {
List<String> eduList = StringUtil.convertStringToStringList(eduStr);
wrapper.and(a->a.in(ESJobDocument::getEducation,eduList));
} else {
wrapper.and(a->a.eq(ESJobDocument::getEducation,eduStr));
}
}
if(hasText(jobQuery.getArea())){
List<Integer> integers = StringUtil.convertStringToIntegerList(jobQuery.getArea().trim());
wrapper.and(x->x.in(ESJobDocument::getJobLocationAreaCode,integers));
}
if(hasText(jobQuery.getExperience())){
wrapper.and(a->a.le(ESJobDocument::getExperience,jobQuery.getExperience().trim()));
// 支持逗号分隔的多值筛选,取最大值(最宽松的经验要求)
String expStr = jobQuery.getExperience().trim();
if (expStr.contains(",")) {
Integer maxExp = StringUtil.findMaxValue(expStr);
if (maxExp != null) {
wrapper.and(a->a.le(ESJobDocument::getExperience,maxExp.toString()));
}
} else {
wrapper.and(a->a.le(ESJobDocument::getExperience,expStr));
}
}
// 薪资范围:岗位最高薪资必须在用户筛选范围内
if(Objects.nonNull(jobQuery.getMaxSalary())){
wrapper.and(x->x.le(ESJobDocument::getMaxSalary,jobQuery.getMaxSalary()));
}
if(Objects.nonNull(jobQuery.getMinSalary())){
wrapper.and(x->x.ge(ESJobDocument::getMinSalary,jobQuery.getMinSalary()));
wrapper.and(x->x.ge(ESJobDocument::getMaxSalary,jobQuery.getMinSalary()));
}
if(hasText(jobQuery.getScaleDictCode())){
wrapper.and(a->a.eq(ESJobDocument::getScaleDictCode,jobQuery.getScaleDictCode().trim()));
@@ -684,7 +712,12 @@ public class ESJobSearchImpl implements IESJobSearchService
wrapper.and(a->a.eq(ESJobDocument::getType,jobQuery.getType().trim()));
}
if(Objects.nonNull(jobQuery.getOrder())){
wrapper.sort(SortBuilders.fieldSort("postingDate").order(SortOrder.DESC).missing("_last"));
if (jobQuery.getOrder()==3){
// 最大薪资排序
wrapper.sort(SortBuilders.fieldSort("maxSalary").order(SortOrder.DESC).missing("_last"));
} else {
wrapper.sort(SortBuilders.fieldSort("postingDate").order(SortOrder.DESC).missing("_last"));
}
if (jobQuery.getOrder()==1){
wrapper.orderByDesc(ESJobDocument::getIsHot);
wrapper.orderByDesc(ESJobDocument::getApplyNum);
@@ -741,11 +774,12 @@ public class ESJobSearchImpl implements IESJobSearchService
if(hasText(jobQuery.getExperience())){
wrapper.and(a->a.le(ESJobDocument::getExperience,jobQuery.getExperience().trim()));
}
// 薪资范围:岗位最高薪资必须在用户筛选范围内
if(Objects.nonNull(jobQuery.getMaxSalary())){
wrapper.and(x->x.le(ESJobDocument::getMaxSalary,jobQuery.getMaxSalary()));
}
if(Objects.nonNull(jobQuery.getMinSalary())){
wrapper.and(x->x.ge(ESJobDocument::getMinSalary,jobQuery.getMinSalary()));
wrapper.and(x->x.ge(ESJobDocument::getMaxSalary,jobQuery.getMinSalary()));
}
if(hasText(jobQuery.getScaleDictCode())){
wrapper.and(a->a.eq(ESJobDocument::getScaleDictCode,jobQuery.getScaleDictCode().trim()));
@@ -831,6 +865,7 @@ public class ESJobSearchImpl implements IESJobSearchService
}
BeanUtils.copyBeanProp(esJobDocument, job);
esJobDocument.setJobCategory(resolveJobCategoryLabel(job.getJobCategory()));
esJobDocument.setAppJobUrl("https://www.xjksly.cn/app#/packageA/pages/post/post?jobId="+ Base64.getEncoder().encodeToString(String.valueOf(job.getJobId()).getBytes()));
if(!StringUtil.isEmptyOrNull(job.getScale())){
esJobDocument.setScale(Integer.valueOf(job.getScale()));
@@ -974,15 +1009,13 @@ public class ESJobSearchImpl implements IESJobSearchService
List<ESJobDocument> esJobDocuments = esJobDocumentMapper.selectList(wrapper);
if (esJobDocuments.size() < esJobSearch.getPageSize()) {
// 定义要逐步放宽的搜索条件字段
// 定义要逐步放宽的搜索条件字段(不放松核心文本搜索条件)
List<Runnable> relaxConditions = new ArrayList<>();
relaxConditions.add(() -> newSearch.setArea(null));
relaxConditions.add(() -> newSearch.setExperience(null));
relaxConditions.add(() -> newSearch.setMaxSalary(null));
relaxConditions.add(() -> newSearch.setMinSalary(null));
relaxConditions.add(() -> newSearch.setEducation(null));
relaxConditions.add(()-> newSearch.setJobCategory(null));
relaxConditions.add(()-> newSearch.setJobTitle(null));
// 保存所有查询到的文档
List<ESJobDocument> allDocuments = new ArrayList<>(esJobDocuments);
@@ -1021,4 +1054,24 @@ public class ESJobSearchImpl implements IESJobSearchService
return esJobDocuments;
}
/**
* 将 jobCategory 从数字ID解析为标签文字如 "45" → "销售顾问"
* 如果已经是文字标签或解析失败,返回原值
*/
private String resolveJobCategoryLabel(String jobCategory) {
if (StringUtils.isEmpty(jobCategory)) {
return jobCategory;
}
try {
Long categoryId = Long.parseLong(jobCategory);
JobTitle jobTitle = jobTitleMapper.selectById(categoryId);
if (jobTitle != null && StringUtils.isNotEmpty(jobTitle.getJobName())) {
return jobTitle.getJobName();
}
} catch (NumberFormatException e) {
// 已经是文字标签,直接返回原值
}
return jobCategory;
}
}

View File

@@ -419,7 +419,7 @@ public class JobServiceImpl extends ServiceImpl<JobMapper,Job> implements IJobSe
if(!longs.isEmpty()){
fileMapper.updateBussinessids(longs,job.getJobId());
}
if (job.getIsPublish() == 1) {
if (Integer.valueOf(1).equals(job.getIsPublish())) {
//同步到es
iesJobSearchService.updateJob(job.getJobId());
}
@@ -581,7 +581,7 @@ public class JobServiceImpl extends ServiceImpl<JobMapper,Job> implements IJobSe
List<ESJobDocument> jobListResult = iesJobSearchService.selectTextListExceptJobId(esJobSearch,jobList);
//存入当前session中查看的岗位 避免重复 todo 定时删除 key上保存用户信息
jobList.addAll(jobListResult.stream().map(ESJobDocument::getJobId).collect(Collectors.toList()));
redisCache.setCacheObject(esJobSearch.getSessionId(),jobList);
redisCache.setCacheObject(esJobSearch.getSessionId(),jobList,2,TimeUnit.HOURS);
List<ESJobDocument> esJobDocuments = userCollection(jobListResult);
return esJobDocuments;
}

View File

@@ -54,4 +54,9 @@ public interface IPolicyInfoService {
* 批量删除政策
*/
int deleteByIds(Long[] ids);
/**
* 更新政策状态(启用/禁用)
*/
int updateStatus(Long id, String status);
}

View File

@@ -36,6 +36,8 @@ public class PolicyInfoServiceImpl implements IPolicyInfoService {
List<String> policyTags = Arrays.asList(query.getPolicyTag().split(","));
query.setPolicyTags(policyTags);
}
// 仅返回启用状态的政策给前端
query.setStatus("0");
List<PolicyInfo> list = policyInfoMapper.selectPolicyInfoList(query);
PageInfo<PolicyInfo> pageInfo = new PageInfo<>(list);
@@ -94,4 +96,9 @@ public class PolicyInfoServiceImpl implements IPolicyInfoService {
public int deleteByIds(Long[] ids) {
return policyInfoMapper.deletePolicyInfoByIds(ids);
}
@Override
public int updateStatus(Long id, String status) {
return policyInfoMapper.updateStatus(id, status);
}
}

View File

@@ -46,6 +46,7 @@
<select id="getInterviewInvitationList" resultMap="InterviewInvitationResult" parameterType="InterviewInvitation">
<include refid="selectInterviewInvitationVo"/>
<where> del_flag = '0'
<if test="id != null and id != ''"> and id = #{id}</if>
<if test="companyId != null and companyId != ''"> and company_id = #{companyId}</if>
<if test="jobId != null and jobId != ''"> and job_id = #{jobId}</if>
<if test="userId != null and userId != ''"> and user_id = #{userId}</if>
@@ -73,6 +74,7 @@
left join job j on j.job_id = t.job_id and j.del_flag = '0'
left join app_user u on u.user_id = t.user_id and u.del_flag = '0'
<where> t.del_flag = '0'
<if test="id != null and id != ''"> and t.id = #{id}</if>
<if test="companyId != null and companyId != ''"> and t.company_id = #{companyId}</if>
<if test="jobId != null and jobId != ''"> and t.job_id = #{jobId}</if>
<if test="userId != null and userId != ''"> and t.user_id = #{userId}</if>

View File

@@ -385,27 +385,28 @@
FROM (
SELECT
r.*,
ja.id AS apply_id,
CASE
WHEN CAST(j.job_id AS TEXT) = ANY(string_to_array(r.job_title_id, ','))
WHEN (CAST(p.job_category AS TEXT) = ANY(string_to_array(r.job_title_id, ',')) OR p.job_category IS NULL)
AND ((CAST(r.salary_min AS INTEGER) &lt;= p.max_salary AND CAST(r.salary_max AS INTEGER) >= p.min_salary) OR p.max_salary IS NULL)
AND (CAST(r.area AS INTEGER) = CAST(p.job_location_area_code AS INTEGER) OR p.job_location_area_code IS NULL)
AND (CAST(r.education AS INTEGER) >=CAST(p.education AS INTEGER) OR p.education IS NULL OR p.education = '-1')
THEN 1
WHEN CAST(j.job_id AS TEXT) = ANY(string_to_array(r.job_title_id, ','))
WHEN (CAST(p.job_category AS TEXT) = ANY(string_to_array(r.job_title_id, ',')) OR p.job_category IS NULL)
AND ((CAST(r.salary_min AS INTEGER) &lt;= p.max_salary AND CAST(r.salary_max AS INTEGER) >= p.min_salary) OR p.max_salary IS NULL)
AND (CAST(r.area AS INTEGER) = CAST(p.job_location_area_code AS INTEGER) OR p.job_location_area_code IS NULL)
THEN 2
WHEN CAST(j.job_id AS TEXT) = ANY(string_to_array(r.job_title_id, ','))
WHEN (CAST(p.job_category AS TEXT) = ANY(string_to_array(r.job_title_id, ',')) OR p.job_category IS NULL)
AND ((CAST(r.salary_min AS INTEGER) &lt;= p.max_salary AND CAST(r.salary_max AS INTEGER) >= p.min_salary) OR p.max_salary IS NULL)
THEN 3
WHEN (CAST(j.job_id AS TEXT) = ANY(string_to_array(r.job_title_id, ',')) OR p.job_category IS NULL)
WHEN (CAST(p.job_category AS TEXT) = ANY(string_to_array(r.job_title_id, ',')) OR p.job_category IS NULL)
THEN 4
ELSE 5
END AS match_level
FROM shz.job p
JOIN shz.app_user r ON r.del_flag = '0'
JOIN shz.job_title j ON j.job_name = p.job_category
WHERE p.job_id = #{jobId}
LEFT JOIN shz.job_apply ja ON ja.user_id = r.user_id AND ja.job_id = p.job_id AND ja.del_flag = '0'
WHERE r.is_company_user = '1' and p.job_id = #{jobId}
) c
) t
WHERE best_rn = 1

View File

@@ -24,17 +24,18 @@
<result property="delFlag" column="del_flag"/>
<result property="remark" column="remark"/>
<result property="policyTag" column="policy_tag"/>
<result property="status" column="status"/>
</resultMap>
<sql id="selectPolicyInfoListVo">
select id, zcmc, zclx, zc_level, source_unit, accept_unit, publish_time, view_num, create_time, policy_tag
select id, zcmc, zclx, zc_level, source_unit, accept_unit, publish_time, view_num, create_time, policy_tag, status
from policy_info
</sql>
<sql id="selectPolicyInfoDetailVo">
select id, zcmc, zclx, zc_level, source_unit, accept_unit, publish_time,
select id, zcmc, zclx, zc_level, source_unit, accept_unit, publish_time,
zc_content, subsidy_standard, handle_channel, apply_condition,
file_url, file_name, view_num, create_by, create_time, update_by, update_time, remark, policy_tag
file_url, file_name, view_num, create_by, create_time, update_by, update_time, remark, policy_tag, status
from policy_info
</sql>
@@ -53,6 +54,9 @@
</foreach>
]
</if>
<if test="query.status != null">
and (status IS NULL or status = #{query.status})
</if>
</where>
order by publish_time desc, create_time desc
</select>
@@ -70,11 +74,11 @@
insert into policy_info (
zcmc, zclx, zc_level, source_unit, accept_unit, publish_time,
zc_content, subsidy_standard, handle_channel, apply_condition,
file_url, file_name, view_num, create_by, create_time, del_flag, remark, policy_tag
file_url, file_name, view_num, create_by, create_time, del_flag, remark, policy_tag, status
) values (
#{zcmc}, #{zclx}, #{zcLevel}, #{sourceUnit}, #{acceptUnit}, #{publishTime},
#{zcContent}, #{subsidyStandard}, #{handleChannel}, #{applyCondition},
#{fileUrl}, #{fileName}, #{viewNum}, #{createBy}, now(), '0', #{remark}, #{policyTag}
#{fileUrl}, #{fileName}, #{viewNum}, #{createBy}, now(), '0', #{remark}, #{policyTag}, #{status}
)
</insert>
@@ -95,6 +99,7 @@
<if test="fileName != null">file_name = #{fileName},</if>
<if test="remark != null">remark = #{remark},</if>
<if test="policyTag != null">policy_tag = #{policyTag},</if>
<if test="status != null">status = #{status},</if>
update_by = #{updateBy},
update_time = now()
</set>
@@ -109,4 +114,8 @@
</foreach>
</update>
<update id="updateStatus">
update policy_info set status = #{status} where id = #{id}
</update>
</mapper>