feat(aihr): complete uni-app role workflows
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
import type {
|
||||
CandidateMaterial,
|
||||
CandidateSelectedFile,
|
||||
InterviewFinishResponse,
|
||||
InterviewRecord,
|
||||
InterviewStartResponse
|
||||
} from '@/types/api';
|
||||
import { apiRequest, apiUrl, authHeaders, readTextPayload } from './api';
|
||||
import { getAuth } from './auth';
|
||||
|
||||
const materialExtensions = ['.pdf', '.doc', '.docx', '.jpg', '.jpeg', '.png', '.webp'];
|
||||
|
||||
export const getCandidateId = () => {
|
||||
const phone = getAuth().phone.trim();
|
||||
if (!phone) {
|
||||
throw new Error('请先登录后再查看候选人进度');
|
||||
}
|
||||
return phone;
|
||||
};
|
||||
|
||||
export const getCandidateName = () => {
|
||||
const phone = getAuth().phone.trim();
|
||||
return phone ? `候选人${phone.slice(-4)}` : '候选人';
|
||||
};
|
||||
|
||||
export const getCandidateMaterials = () =>
|
||||
apiRequest<CandidateMaterial[]>({
|
||||
url: `/api/aihr/mobile/candidate/materials?candidateId=${encodeURIComponent(getCandidateId())}`,
|
||||
method: 'GET',
|
||||
timeout: 15000
|
||||
});
|
||||
|
||||
export const getCandidateInterviewRecords = () =>
|
||||
apiRequest<InterviewRecord[]>({
|
||||
url: `/api/recruit/interview/records?limit=5&candidateId=${encodeURIComponent(getCandidateId())}`,
|
||||
method: 'GET',
|
||||
timeout: 15000
|
||||
});
|
||||
|
||||
export const chooseCandidateFile = () =>
|
||||
new Promise<CandidateSelectedFile>((resolve, reject) => {
|
||||
uni.chooseFile({
|
||||
count: 1,
|
||||
type: 'all',
|
||||
extension: materialExtensions,
|
||||
success: (result) => {
|
||||
const tempFiles = Array.isArray(result.tempFiles) ? result.tempFiles : [];
|
||||
const file = (tempFiles[0] || {}) as Partial<CandidateSelectedFile>;
|
||||
const path = file.path || result.tempFilePaths?.[0] || '';
|
||||
if (!path) {
|
||||
reject(new Error('未获取到文件路径'));
|
||||
return;
|
||||
}
|
||||
resolve({
|
||||
path,
|
||||
name: file.name || path.split('/').pop() || 'candidate-material',
|
||||
size: Number(file.size || 0)
|
||||
});
|
||||
},
|
||||
fail: () => reject(new Error('未选择文件'))
|
||||
});
|
||||
});
|
||||
|
||||
export const uploadCandidateMaterial = (file: CandidateSelectedFile, materialType = '补充资料') =>
|
||||
new Promise<CandidateMaterial>((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: apiUrl('/api/aihr/mobile/candidate/materials'),
|
||||
filePath: file.path,
|
||||
name: 'file',
|
||||
header: authHeaders(false),
|
||||
formData: {
|
||||
candidateId: getCandidateId(),
|
||||
candidateName: getCandidateName(),
|
||||
materialType
|
||||
},
|
||||
success: (response) => {
|
||||
try {
|
||||
resolve(readTextPayload<CandidateMaterial>(response.statusCode, response.data));
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
},
|
||||
fail: () => reject(new Error('资料上传失败'))
|
||||
});
|
||||
});
|
||||
|
||||
export const startCandidateInterview = () =>
|
||||
apiRequest<InterviewStartResponse>({
|
||||
url: '/api/recruit/interview/start',
|
||||
method: 'POST',
|
||||
data: {
|
||||
candidateId: getCandidateId(),
|
||||
candidateName: getCandidateName(),
|
||||
positionCode: 'customer-service',
|
||||
mode: 'mobile'
|
||||
},
|
||||
timeout: 30000
|
||||
});
|
||||
|
||||
export const saveInterviewAnswer = (sessionId: string, questionId: string, answerText: string) =>
|
||||
apiRequest<void>({
|
||||
url: '/api/recruit/interview/answer',
|
||||
method: 'POST',
|
||||
data: { sessionId, questionId, answerText },
|
||||
timeout: 30000
|
||||
});
|
||||
|
||||
export const finishCandidateInterview = (sessionId: string, answers: Record<string, string>) =>
|
||||
apiRequest<InterviewFinishResponse>({
|
||||
url: '/api/recruit/interview/finish',
|
||||
method: 'POST',
|
||||
data: { sessionId, answers },
|
||||
timeout: 45000
|
||||
});
|
||||
Reference in New Issue
Block a user