feat(aihr): close functional checklist gaps
This commit is contained in:
@@ -20,6 +20,7 @@ export interface BroadcastMessageSummary {
|
||||
requiredRead: boolean;
|
||||
targeted: boolean;
|
||||
targetReason?: string;
|
||||
visibilityMode: 'ALL' | 'TARGET_ONLY';
|
||||
}
|
||||
|
||||
export interface BroadcastMessage extends BroadcastMessageSummary {
|
||||
@@ -50,13 +51,32 @@ export interface BroadcastAttachment {
|
||||
contentType: string;
|
||||
status: 'READY';
|
||||
summary?: string;
|
||||
downloadUrl: string;
|
||||
viewUrl: string;
|
||||
downloadUrl?: string;
|
||||
allowDownload: boolean;
|
||||
watermarkText?: string;
|
||||
topicTags: BroadcastTopicTag[];
|
||||
insightStatus: BroadcastInsightStatus;
|
||||
defaultPerspectiveCode?: string;
|
||||
perspectiveLabels: string[];
|
||||
perspectives: BroadcastPerspective[];
|
||||
}
|
||||
|
||||
export interface BroadcastTopicTag {
|
||||
name: string;
|
||||
sourceType: 'AUTO' | 'MANUAL';
|
||||
evidenceQuote: string;
|
||||
}
|
||||
|
||||
export interface BroadcastAttachmentView {
|
||||
id: number;
|
||||
fileName: string;
|
||||
content: string;
|
||||
truncated: boolean;
|
||||
watermarkText: string;
|
||||
topicTags: BroadcastTopicTag[];
|
||||
}
|
||||
|
||||
export interface BroadcastMessagePage {
|
||||
total: number;
|
||||
pageNum: number;
|
||||
@@ -78,11 +98,19 @@ export const listBroadcastMessages = (pageNum = 1, pageSize = 20, scope: Broadca
|
||||
url: `/api/aihr/broadcast/messages?pageNum=${pageNum}&pageSize=${pageSize}&scope=${scope}`,
|
||||
method: 'GET',
|
||||
timeout: 15000
|
||||
});
|
||||
}).then((page) => ({
|
||||
...page,
|
||||
rows: (page.rows || []).map((message) => ({
|
||||
...message,
|
||||
visibilityMode: message.visibilityMode || 'ALL'
|
||||
}))
|
||||
}));
|
||||
|
||||
const normalizeBroadcastAttachment = (attachment: BroadcastAttachment): BroadcastAttachment => ({
|
||||
...attachment,
|
||||
allowDownload: attachment.allowDownload !== false,
|
||||
insightStatus: attachment.insightStatus || 'NOT_PROCESSED',
|
||||
topicTags: Array.isArray(attachment.topicTags) ? attachment.topicTags : [],
|
||||
perspectiveLabels: Array.isArray(attachment.perspectiveLabels) ? attachment.perspectiveLabels : [],
|
||||
perspectives: Array.isArray(attachment.perspectives) ? attachment.perspectives : []
|
||||
});
|
||||
@@ -94,8 +122,8 @@ export const getBroadcastMessage = async (id: number) => {
|
||||
timeout: 15000
|
||||
});
|
||||
return message.attachment
|
||||
? { ...message, attachment: normalizeBroadcastAttachment(message.attachment) }
|
||||
: message;
|
||||
? { ...message, visibilityMode: message.visibilityMode || 'ALL', attachment: normalizeBroadcastAttachment(message.attachment) }
|
||||
: { ...message, visibilityMode: message.visibilityMode || 'ALL' };
|
||||
};
|
||||
|
||||
export const markBroadcastMessageRead = (id: number) =>
|
||||
@@ -105,6 +133,13 @@ export const markBroadcastMessageRead = (id: number) =>
|
||||
timeout: 15000
|
||||
});
|
||||
|
||||
export const getBroadcastAttachmentView = (id: number) =>
|
||||
apiRequest<BroadcastAttachmentView>({
|
||||
url: `/api/aihr/broadcast/attachments/${id}/view`,
|
||||
method: 'GET',
|
||||
timeout: 15000
|
||||
});
|
||||
|
||||
const isSafeMessageId = (value: unknown): value is number =>
|
||||
typeof value === 'number' && Number.isSafeInteger(value) && value > 0;
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ type RawExamQuestion = {
|
||||
score: number;
|
||||
explanation?: string;
|
||||
sortOrder?: number;
|
||||
sourceQuestionCode?: string | null;
|
||||
sourceContentVersion?: string | null;
|
||||
};
|
||||
|
||||
type RawExamSummary = {
|
||||
@@ -53,7 +55,9 @@ const normalizeDetail = (item: RawExamDetail): ExamDetail => ({
|
||||
options: question.options || [],
|
||||
score: question.score,
|
||||
answer: question.correctAnswers || [],
|
||||
explanation: question.explanation || ''
|
||||
explanation: question.explanation || '',
|
||||
sourceQuestionCode: question.sourceQuestionCode || null,
|
||||
sourceContentVersion: question.sourceContentVersion || null
|
||||
})),
|
||||
targets: item.targets || []
|
||||
});
|
||||
@@ -64,6 +68,7 @@ const serializeDraft = (draft: SupervisorExamDraft) => ({
|
||||
positionCode: draft.positionCode,
|
||||
passScore: draft.passScore,
|
||||
dueDate: draft.dueDate,
|
||||
questionDrawRequestId: draft.questionDrawRequestId || null,
|
||||
targets: draft.targets,
|
||||
questions: draft.questions.map((question, index) => ({
|
||||
id: question.id > 0 && question.id < 1_000_000_000 ? question.id : null,
|
||||
@@ -181,3 +186,31 @@ export const generateSupervisorExamQuestions = async (data: {
|
||||
}))
|
||||
};
|
||||
};
|
||||
|
||||
export const drawSupervisorExamQuestions = async (data: {
|
||||
requestId: string;
|
||||
positionCode: string;
|
||||
count: number;
|
||||
formats: string[];
|
||||
}): Promise<{ requestId: string; questions: ExamQuestion[] }> => {
|
||||
const response = await apiRequest<{ requestId: string; questions: RawExamQuestion[] }>({
|
||||
url: '/api/aihr/mobile/exams/supervisor/question-bank/draw',
|
||||
method: 'POST',
|
||||
data,
|
||||
timeout: 30000
|
||||
});
|
||||
return {
|
||||
requestId: response.requestId,
|
||||
questions: (response.questions || []).map((question, index) => ({
|
||||
id: Date.now() + index,
|
||||
format: question.questionType,
|
||||
stem: question.stem,
|
||||
options: question.options || [],
|
||||
score: question.score,
|
||||
answer: question.questionType === 'multiple' ? (question.correctAnswers || []) : (question.correctAnswers?.[0] || ''),
|
||||
explanation: question.explanation || '',
|
||||
sourceQuestionCode: question.sourceQuestionCode || null,
|
||||
sourceContentVersion: question.sourceContentVersion || null
|
||||
}))
|
||||
};
|
||||
};
|
||||
|
||||
@@ -203,6 +203,20 @@ export const completeOnboardTask = (id: number, evidenceRef?: string) =>
|
||||
timeout: 15000
|
||||
});
|
||||
|
||||
export const reportOnboardProgress = (id: number, data: {
|
||||
progressPercent?: number;
|
||||
positionSeconds?: number;
|
||||
durationSeconds?: number;
|
||||
materialVersion?: string | null;
|
||||
completed?: boolean;
|
||||
}) =>
|
||||
apiRequest<void>({
|
||||
url: `/api/aihr/mobile/onboard/tasks/${id}/progress`,
|
||||
method: 'POST',
|
||||
data,
|
||||
timeout: 15000
|
||||
});
|
||||
|
||||
export const getQualification = () =>
|
||||
apiRequest<QualificationSummary>({
|
||||
url: '/api/aihr/mobile/qualification',
|
||||
|
||||
@@ -109,6 +109,17 @@ export const publishQuestion = (data: { title: string; content: string; category
|
||||
timeout: 15000
|
||||
}).then(normalizeQuestion);
|
||||
|
||||
export const publishQuestionFromAnswerFeedback = (data: { requestId: string; idempotencyKey: string }) =>
|
||||
apiRequest<RawQuestion>({
|
||||
url: '/api/aihr/community/questions/from-answer-feedback',
|
||||
method: 'POST',
|
||||
data: {
|
||||
requestId: data.requestId,
|
||||
idempotencyKey: data.idempotencyKey
|
||||
},
|
||||
timeout: 15000
|
||||
}).then(normalizeQuestion);
|
||||
|
||||
export const answerQuestion = (questionId: number, content: string) =>
|
||||
apiRequest<RawAnswer>({
|
||||
url: `/api/aihr/community/questions/${questionId}/answers`,
|
||||
|
||||
Reference in New Issue
Block a user