Browse Source

feat(api): 接入双向打分(候选人意向分 / HR 适配分)

- PUT /applications/{id}/candidate-interest-score(学生,0-100)、
  PUT /applications/{id}/hr-suitability-score(企业,0-100),body {score}
- 返回最新匹配状态 ApplicationMatch(学生打分后 PENDING_BOTH→PENDING_HR)
- 实网已验:越界 score 返回 400 validation failed
- 补测试锁住 body 只带 score、方法 PUT、路径正确
master
doublex001 4 weeks ago
parent
commit
61b0d150d6
  1. 20
      src/__tests__/enterprise-applications.test.ts
  2. 33
      src/api/api.ts
  3. 2
      src/api/index.ts
  4. 4
      src/types/application.ts

20
src/__tests__/enterprise-applications.test.ts

@ -46,6 +46,8 @@ import {
fetchApplicationTimeline,
fetchCompanyApplicationDetail,
fetchCompanyApplications,
submitCandidateInterestScore,
submitHrSuitabilityScore,
toBackendApplicationStatus,
updateApplicationStatus,
updateCandidateFeedback,
@ -267,4 +269,22 @@ describe('企业端投递 / 反馈(真实模式)', () => {
expect(match.studentRequiredHrScore).toBe(60);
expect(match.jobId).toBe(166);
});
it('双向打分分别走 PUT candidate-interest-score / hr-suitability-score,body 只带 score', async () => {
setMockMode(false);
const seen: Array<{ url: string; method: string; body: unknown }> = [];
responder = (url, init) => {
seen.push({ url, method: String(init.method), body: JSON.parse(String(init.body)) });
return okData({ status: 'PENDING_HR', candidateInterestScore: 80, applicationId: 1, jobId: 166, companyId: 48, candidateId: 4 });
};
await submitCandidateInterestScore('1', 80);
expect(seen[0].url).toBe(`${API_BASE_URL}/applications/1/candidate-interest-score`);
expect(seen[0].method).toBe('PUT');
expect(seen[0].body).toEqual({ score: 80 });
await submitHrSuitabilityScore('1', 70);
expect(seen[1].url).toBe(`${API_BASE_URL}/applications/1/hr-suitability-score`);
expect(seen[1].method).toBe('PUT');
expect(seen[1].body).toEqual({ score: 70 });
});
});

33
src/api/api.ts

@ -2217,6 +2217,39 @@ export async function fetchApplicationMatch(id: string): Promise<ApplicationMatc
return request<ApplicationMatch>(`/applications/${id}/match`, { method: 'GET', auth: true });
}
/**
* 提交候选人意向分(0-100,仅投递本人;MATCHED/CLOSED 后不可改)。
* 返回最新匹配状态(学生打分后 status 从 PENDING_BOTH 变为 PENDING_HR)。
* @method PUT
* @url /applications/{id}/candidate-interest-score
*/
export async function submitCandidateInterestScore(id: string, score: number): Promise<ApplicationMatch> {
if (isMockMode()) {
throw new Error('mock 模式下无匹配数据');
}
return request<ApplicationMatch>(`/applications/${id}/candidate-interest-score`, {
method: 'PUT',
auth: true,
body: { score },
});
}
/**
* 提交企业 HR 适配分(0-100,仅岗位所属企业;MATCHED/CLOSED 后不可改)。
* @method PUT
* @url /applications/{id}/hr-suitability-score
*/
export async function submitHrSuitabilityScore(id: string, score: number): Promise<ApplicationMatch> {
if (isMockMode()) {
throw new Error('mock 模式下无匹配数据');
}
return request<ApplicationMatch>(`/applications/${id}/hr-suitability-score`, {
method: 'PUT',
auth: true,
body: { score },
});
}
/**
* 撤回投递
* @method POST

2
src/api/index.ts

@ -211,6 +211,8 @@ export {
fetchApplicationDetail,
fetchApplicationTimeline,
fetchApplicationMatch,
submitCandidateInterestScore,
submitHrSuitabilityScore,
withdrawApplication,
toBackendApplicationStatus,
fetchCompanyApplications,

4
src/types/application.ts

@ -93,6 +93,10 @@ export interface ApplicationMatch {
jobId: number;
companyId: number;
candidateId: number;
/** 候选人意向分(0-100,仅打分接口下发) */
candidateInterestScore?: number;
/** 企业 HR 适配分(0-100,仅打分接口下发) */
hrSuitabilityScore?: number;
}
/** 分页结果(后端统一分页结构) */

Loading…
Cancel
Save