diff --git a/client-api/src/main/java/org/jiayunet/controller/JobController.java b/client-api/src/main/java/org/jiayunet/controller/JobController.java
index 2f7d4e0..83b33d7 100644
--- a/client-api/src/main/java/org/jiayunet/controller/JobController.java
+++ b/client-api/src/main/java/org/jiayunet/controller/JobController.java
@@ -47,6 +47,23 @@ public class JobController {
return jobService.listJobs(param, userId);
}
+ /**
+ * 岗位列表总数查询
+ *
筛选条件与 /job/list 一致,仅返回符合条件的岗位总数,接口允许不登录访问
+ */
+ @PostMapping("/list/count")
+ public Long countJobs(@Validated @RequestBody JobQueryParam param) {
+
+ Long userId = 0L;
+ try {
+ userId = UserSecurityTool.getUserId();
+ } catch (Exception e) {
+ // 接口允许不登录,不处理
+ }
+
+ return jobService.countJobs(param, userId);
+ }
+
/**
* 岗位详情
* 返回岗位完整信息、公司信息、匹配度、收藏状态
diff --git a/client-api/src/main/java/org/jiayunet/service/JobService.java b/client-api/src/main/java/org/jiayunet/service/JobService.java
index 1432311..0c275aa 100644
--- a/client-api/src/main/java/org/jiayunet/service/JobService.java
+++ b/client-api/src/main/java/org/jiayunet/service/JobService.java
@@ -161,6 +161,49 @@ public class JobService {
return new PageResult<>(page.getCurrent(), page.getSize(), page.getTotal(), dtoList);
}
+ /**
+ * 岗位列表总数查询
+ * 过滤条件与 listJobs 完全一致(SQL 层共用 jobPageWhere 片段),不分页、不查收藏/投递状态、不算匹配度
+ * 方法逻辑流程:
+ * 1. 扩展筛选条件的子级(地区/岗位类型/行业)
+ * 2. 查询用户不感兴趣记录
+ * 3. 提取排除列表(岗位/公司/地区/行业)
+ * 4. 执行统计查询
+ */
+ public Long countJobs(JobQueryParam param, Long userId) {
+
+ // 默认只查有效岗位
+ if (param.getStatusFilter() == null) {
+ param.setStatusFilter(Collections.singletonList(0));
+ }
+
+ // 1. 扩展筛选条件的子级
+ List expandedRegionCodes = expandRegionCodes(param.getRegionCodes());
+ List expandedCategoryIds = expandCategoryIds(param.getCategoryIds());
+ List expandedIndustryIds = expandIndustryIds(param.getIndustryIds());
+
+ // 2. 查询用户不感兴趣记录
+ List dislikes = userJobDislikeMapper.selectList(new LambdaQueryWrapper().eq(UserJobDislike::getUserId, userId));
+
+ // 3. 提取排除列表
+ List excludeJobIds = dislikes.stream().map(UserJobDislike::getJobId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
+ if (param.getExcludeJobIds() != null && !param.getExcludeJobIds().isEmpty()) {
+ excludeJobIds.addAll(param.getExcludeJobIds());
+ }
+ List excludeCompanyIds = dislikes.stream().map(UserJobDislike::getCompanyId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
+
+ // 4. 提取不感兴趣的地区(直接使用,不扩展子级)
+ List excludeRegionCodes = dislikes.stream().map(UserJobDislike::getRegionCode).filter(Objects::nonNull).distinct().collect(Collectors.toList());
+
+ // 5. 提取不感兴趣的行业(直接使用,不扩展子级)
+ List excludeIndustryIds = dislikes.stream().map(UserJobDislike::getIndustryId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
+
+ // 6. 执行统计查询
+ Long total = jobMapper.countJobPage(param.getJobIds(), param.getStatusFilter(), param.getKeyword(), expandedRegionCodes, expandedCategoryIds, expandedIndustryIds, param.getEmploymentType(), excludeJobIds, excludeCompanyIds, excludeRegionCodes, excludeIndustryIds, param.getRecruitCategory(), param.getCompanyTypes(), param.getCompanyId(), param.getEducations(), param.getPublishStartTime(), param.getPublishEndTime());
+
+ return total == null ? 0L : total;
+ }
+
/**
* 扩展地区编码(包含自身和所有子级)
* 一次查询:code本身 + provinceCode匹配 + cityCode匹配
diff --git a/manager/src/main/java/org/jiayunet/mapper/JobMapper.java b/manager/src/main/java/org/jiayunet/mapper/JobMapper.java
index b4a5616..b8cef8c 100644
--- a/manager/src/main/java/org/jiayunet/mapper/JobMapper.java
+++ b/manager/src/main/java/org/jiayunet/mapper/JobMapper.java
@@ -21,4 +21,10 @@ public interface JobMapper extends CommonMapper {
* 分页查询岗位列表
*/
Page selectJobPage(Page page, @Param("jobIds") List jobIds, @Param("statusFilter") List statusFilter, @Param("keyword") String keyword, @Param("regionCodes") List regionCodes, @Param("categoryIds") List categoryIds, @Param("industryIds") List industryIds, @Param("employmentType") Integer employmentType, @Param("excludeJobIds") List excludeJobIds, @Param("excludeCompanyIds") List excludeCompanyIds, @Param("excludeRegionCodes") List excludeRegionCodes, @Param("excludeIndustryIds") List excludeIndustryIds, @Param("recruitCategory") Integer recruitCategory, @Param("companyTypes") List companyTypes, @Param("companyId") Long companyId, @Param("educations") List educations, @Param("publishStartTime") Instant publishStartTime, @Param("publishEndTime") Instant publishEndTime);
+
+ /**
+ * 统计岗位列表总数
+ * 过滤条件与 selectJobPage 共用同一段 SQL(jobPageWhere),保证列表与总数口径一致
+ */
+ Long countJobPage(@Param("jobIds") List jobIds, @Param("statusFilter") List statusFilter, @Param("keyword") String keyword, @Param("regionCodes") List regionCodes, @Param("categoryIds") List categoryIds, @Param("industryIds") List industryIds, @Param("employmentType") Integer employmentType, @Param("excludeJobIds") List excludeJobIds, @Param("excludeCompanyIds") List excludeCompanyIds, @Param("excludeRegionCodes") List excludeRegionCodes, @Param("excludeIndustryIds") List excludeIndustryIds, @Param("recruitCategory") Integer recruitCategory, @Param("companyTypes") List companyTypes, @Param("companyId") Long companyId, @Param("educations") List educations, @Param("publishStartTime") Instant publishStartTime, @Param("publishEndTime") Instant publishEndTime);
}
diff --git a/manager/src/main/resources/mapper/JobMapper.xml b/manager/src/main/resources/mapper/JobMapper.xml
index 7697f88..a08e9db 100644
--- a/manager/src/main/resources/mapper/JobMapper.xml
+++ b/manager/src/main/resources/mapper/JobMapper.xml
@@ -30,37 +30,11 @@
-