forked from baskbuddy/zhangshun
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
8.8 KiB
8.8 KiB
企业评分运营看板 API
企业评分运营看板 / 评分排名 / 评分趋势 v0.1 基础路径:
/api/v1· 全部接口需Authorization: Bearer <accessToken>
概述
- 只读聚合:仅查询
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
响应
{
"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 为本企业岗位总数。
响应
{
"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)。
响应
{
"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。
响应
{
"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 空期)。
响应
{
"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
响应
{
"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,天然隔离企业数据。- 候选人排名/趋势不写快照、不触发评分计算,仅读最新期已存在快照。