# 企业评分运营看板 API > 企业评分运营看板 / 评分排名 / 评分趋势 v0.1 > 基础路径:`/api/v1` · 全部接口需 `Authorization: Bearer ` ## 概述 - **只读聚合**:仅查询 `jobs` / `applications` / `job_reviews` / `job_review_dimension_scores` / `candidate_dimension_scores` 等业务表,**不写入任何业务表**、不产生新快照。 - **候选人按学生去重**:同一学生多次投递视为 1 名候选人,代表投递取该企业下该学生 `applicationId` 最大的一条;`WITHDRAWN` / `REJECTED` 投递排除在统计外。 - **候选人综合分复用** `CandidateScoringCalculator.overallScoreFromSnapshots`:读取每个候选人 `<= asOfPeriod`(当前月)的最新期维度快照,用引擎公式计算;无可计算维度时 `overallScore=null`。 - **岗位评价过滤与 `JobReviewService.getReviewSummary` 口径一致**:`status='PUBLISHED'` 且 `moderation_status IN ('AUTO_APPROVED','APPROVED')`。 - **企业数据隔离**:`companyId` 从 JWT 推导(`companyRepository.findByOwnerUserId`),所有 SQL 限定 `company_id`,不接受请求参数传入企业 ID。 ## 接口列表 | # | 方法 | 路径 | 角色 | 说明 | |---|------|------|------|------| | 1 | GET | `/company/scoring/dashboard/overview` | COMPANY | 企业评分运营概览 | | 2 | GET | `/company/scoring/dashboard/job-rankings?page&size` | COMPANY | 岗位评分排名(分页) | | 3 | GET | `/company/scoring/dashboard/job-rankings/{jobId}` | COMPANY | 单岗位评分排名明细 | | 4 | GET | `/company/scoring/dashboard/candidate-rankings?page&size` | COMPANY | 候选人评分排名(按学生去重,分页) | | 5 | GET | `/company/scoring/dashboard/candidate-rankings/{applicationId}` | COMPANY | 单候选人评分排名明细 | | 6 | GET | `/company/scoring/dashboard/trend?months=6` | COMPANY | 企业评分趋势(按月) | | 7 | GET | `/admin/scoring/dashboard/overview` | ADMIN | 全局运营概览 | ## 权限矩阵 | 接口 | 未登录 | STUDENT | COMPANY | ADMIN | |------|--------|---------|---------|-------| | 企业看板 6 接口 | 401 | 403 | ✅(本企业) | 403 | | 全局概览 | 401 | 403 | 403 | ✅ | 企业归属校验(单条详情): - 岗位不存在 → `JOB_NOT_FOUND(7001)` → 404; - 岗位不属于本企业 → `JOB_OWNER_MISMATCH(7002)` → 400; - 投递不存在 → `APPLICATION_NOT_FOUND(8002)` → 404; - 投递岗位不属于本企业 → `APPLICATION_OWNER_MISMATCH(8004)` → 403。 ## 1. 企业评分运营概览 ``` GET /company/scoring/dashboard/overview ``` ### 响应 ```json { "code": 200, "message": "ok", "data": { "companyId": 1, "totalJobs": 5, "publishedJobs": 3, "avgJobScore": 4.50, "totalCandidates": 3, "avgCandidateScore": 80.00, "scoreDistribution": { "1": 0, "2": 0, "3": 1, "4": 2, "5": 2 }, "updatedAt": "2026-08-21T10:00:00" } } ``` - `totalJobs`:本企业岗位总数;`publishedJobs`:`PUBLISHED` 岗位数。 - `avgJobScore`:审核通过评价的均值(无评价 → `null`)。 - `totalCandidates`:管线内去重候选人(含无分);`avgCandidateScore`:有分候选人综合分均值(无 → `null`)。 - `scoreDistribution`:1–5 星评价分布,全键恒存在(无评价为 0)。 ## 2. 岗位评分排名 ``` GET /company/scoring/dashboard/job-rankings?page=0&size=20 ``` | 参数 | 类型 | 必填 | 默认 | 说明 | |------|------|------|------|------| | page | int | 否 | 0 | 页码 (0-based) | | size | int | 否 | 20 | 每页条数 (1–100) | `page<0` 或 `size<1 || size>100` → `400 / 1001`。 排序:`avgRating DESC, jobId DESC`(无评价岗位 `avgRating=null` 排在末尾);`rank` 为 1-based,`cohortSize` 为本企业岗位总数。 ### 响应 ```json { "code": 200, "message": "ok", "data": { "items": [{ "jobId": 10, "title": "Java 后端工程师", "city": "北京", "employmentType": "FULL_TIME", "avgRating": 4.50, "reviewCount": 12, "rank": 1, "cohortSize": 5, "dimensionAverages": { "AUTHENTICITY": 4.50, "TEAM_ATMOSPHERE": 4.20 } }], "total": 5, "page": 0, "size": 20, "totalPages": 1 } } ``` `dimensionAverages`:审核通过评价的八维均值(`dimension_code → avg(score)`,scale 2)。 ## 3. 单岗位评分排名明细 ``` GET /company/scoring/dashboard/job-rankings/{jobId} ``` 返回结构与列表项一致(`rank` 在本企业内计算)。跨企业 → `400 / 7002`。 ## 4. 候选人评分排名 ``` GET /company/scoring/dashboard/candidate-rankings?page=0&size=20 ``` | 参数 | 类型 | 必填 | 默认 | 说明 | |------|------|------|------|------| | page | int | 否 | 0 | 页码 (0-based) | | size | int | 否 | 20 | 每页条数 (1–100) | `page<0` 或 `size<1 || size>100` → `400 / 1001`。 排序:`overallScore DESC, applicationId DESC`;`percentile` 在有分候选人集合内计算(升序百分位 = `小于自己的人数 / (有分人数-1) × 100`,scale 2,`overallScore=null` → `null`)。 ### 响应 ```json { "code": 200, "message": "ok", "data": { "items": [{ "applicationId": 30, "jobId": 10, "candidateName": "张三", "candidateSchool": "清华大学", "overallScore": 90.00, "percentile": 100.00, "sampleCount": 3 }], "total": 3, "page": 0, "size": 20, "totalPages": 1 } } ``` - `applicationId` 为**代表投递**(该学生在企业下最大 `applicationId`);`candidateName`/`candidateSchool` 取 `student_profiles`。 - `sampleCount`:有分候选人总数(不分页)。 ## 5. 单候选人评分排名明细 ``` GET /company/scoring/dashboard/candidate-rankings/{applicationId} ``` - 投递不存在 → `404 / 8002`;投递岗位不属于本企业 → `403 / 8004`;投递状态为 `WITHDRAWN`/`REJECTED` → `404 / 8002`。 - 若该候选人快照缺失,仍返回其档案信息,`overallScore`/`percentile` 为 `null`。 ### 响应 ```json { "code": 200, "message": "ok", "data": { "applicationId": 30, "jobId": 10, "candidateName": "张三", "candidateSchool": "清华大学", "overallScore": 90.00, "percentile": 88.00, "cohortSize": 3, "dimensionScores": [ { "dimension": "COMPLIANCE", "score": 100.00, "status": "OK" } ] } } ``` `dimensionScores`:该候选人最新期快照的各维度(按维度名升序);仅含 `dimension / score / status`,不暴露 `subScores` 与内部日志。 ## 6. 企业评分趋势 ``` GET /company/scoring/dashboard/trend?months=6 ``` | 参数 | 类型 | 必填 | 默认 | 说明 | |------|------|------|------|------| | months | int | 否 | 6 | 统计月数,1–24 | `months` 越界(<1 或 >24)→ `400 / 1001`。 - 岗位评价趋势:按 `job_reviews.created_at` 年月分组(审核通过评价)求均值。 - 候选人综合分趋势:读取范围内各期快照,用 `overallScoreFromSnapshots` 计算每期综合分后求均值(`candidateCount` 为该期有分候选人数)。 - 仅返回有数据的月份;`avgJobScore`/`avgCandidateScore` 某期无数据时该期缺失(不补 null 空期)。 ### 响应 ```json { "code": 200, "message": "ok", "data": { "companyId": 1, "months": 6, "items": [ { "period": "2026-08", "avgJobScore": 4.50, "avgCandidateScore": 80.00, "candidateCount": 2 } ] } } ``` ## 7. 全局运营概览(ADMIN) ``` GET /admin/scoring/dashboard/overview ``` ### 响应 ```json { "code": 200, "message": "ok", "data": { "totalCompanies": 12, "totalJobs": 45, "totalCandidates": 220, "avgCandidateScore": 70.00, "topCompanies": [{ "companyId": 3, "companyName": "示例企业", "avgCandidateScore": 88.50, "jobCount": 5 }] } } ``` - `totalCandidates`:全平台管线内去重候选人(排除 `WITHDRAWN`/`REJECTED`)。 - `avgCandidateScore`:全平台有分候选人综合分均值。 - `topCompanies`:按候选人综合分均值排序的前 10 家企业。 ## 错误码 复用既有错误码,不新增: | 状态码 | 错误码 | 说明 | |--------|--------|------| | 400 | 1001 | 参数非法(page/size/months 越界) | | 400 | 7002 | 岗位不属于本企业 | | 401 | — | 未登录(安全过滤器) | | 403 | 2002 | 非 COMPANY/ADMIN 角色、无企业资料 | | 403 | 8004 | 投递岗位不属于本企业 | | 404 | 4001 | 用户不存在(ADMIN 概览) | | 404 | 7001 | 岗位不存在 | | 404 | 8002 | 投递不存在或投递已撤回/被拒 | ## 安全说明 - 全部为 GET 只读;不返回 `studentUserId`、`phone`、`email`、`resumeUrl`、`passwordHash`。 - `companyId` 一律从 JWT 推导并限定 `jobs.company_id`,天然隔离企业数据。 - 候选人排名/趋势不写快照、不触发评分计算,仅读最新期已存在快照。