- questions admin: 转为经验候选 action on published best answers, moderator-gated, confirm dialog, idempotent feedback
99 lines
3.9 KiB
TypeScript
99 lines
3.9 KiB
TypeScript
import request from '@/utils/request';
|
|
|
|
type ApiResult<T> = { code: number; msg: string; data: T };
|
|
|
|
export type AdminQuestionAnswer = {
|
|
id: number;
|
|
questionId: number;
|
|
content: string;
|
|
authorName: string;
|
|
authorPosition?: string;
|
|
status: string;
|
|
best: boolean;
|
|
recommended?: boolean;
|
|
createTime: string;
|
|
};
|
|
|
|
export type AdminQuestion = {
|
|
id: number;
|
|
type: 'HELP' | 'BOUNTY' | string;
|
|
title: string;
|
|
content: string;
|
|
category: string;
|
|
authorName: string;
|
|
status: string;
|
|
rewardPoints: number;
|
|
rewardAccountType: 'POINTS' | 'STUDY_CREDIT' | string;
|
|
answerCount: number;
|
|
deadline?: string | null;
|
|
createTime: string;
|
|
bestAnswerId?: number | null;
|
|
answers?: AdminQuestionAnswer[];
|
|
};
|
|
|
|
export type IncentiveRule = {
|
|
id?: number;
|
|
ruleCode: string;
|
|
displayName: string;
|
|
accountType: 'POINTS' | 'STUDY_CREDIT';
|
|
value: number;
|
|
dailyCap?: number | null;
|
|
enabled: boolean;
|
|
};
|
|
|
|
type RawAdminQuestionAnswer = Omit<AdminQuestionAnswer, 'createTime'> & { createdAt: string };
|
|
type RawAdminQuestion = Omit<AdminQuestion, 'createTime' | 'answers'> & {
|
|
createdAt: string;
|
|
answers?: RawAdminQuestionAnswer[];
|
|
};
|
|
|
|
const normalizeAnswer = (item: RawAdminQuestionAnswer): AdminQuestionAnswer => ({
|
|
...item,
|
|
createTime: item.createdAt
|
|
});
|
|
|
|
const normalizeQuestion = (item: RawAdminQuestion): AdminQuestion => ({
|
|
...item,
|
|
createTime: item.createdAt,
|
|
answers: (item.answers || []).map(normalizeAnswer)
|
|
});
|
|
|
|
export const listAdminQuestions = (status?: string): Promise<ApiResult<AdminQuestion[]>> =>
|
|
request<unknown, ApiResult<RawAdminQuestion[]>>({
|
|
url: '/api/aihr/question-admin/questions', method: 'get', params: { status }
|
|
}).then((result) => ({ ...result, data: (result.data || []).map(normalizeQuestion) }));
|
|
|
|
export const createBountyQuestion = (data: { title: string; content: string; category: string; rewardPoints: number; deadline: string }): Promise<ApiResult<AdminQuestion>> =>
|
|
request<unknown, ApiResult<RawAdminQuestion>>({
|
|
url: '/api/aihr/question-admin/questions', method: 'post', data: { ...data, ruleCode: 'BEST_ANSWER' }, headers: { repeatSubmit: false }
|
|
}).then((result) => ({ ...result, data: normalizeQuestion(result.data) }));
|
|
|
|
export const reviewQuestion = (id: number, decision: 'APPROVE' | 'REJECT', note = ''): Promise<ApiResult<AdminQuestion>> =>
|
|
request<unknown, ApiResult<RawAdminQuestion>>({
|
|
url: `/api/aihr/question-admin/questions/${id}/review`, method: 'post', data: { decision, note }, headers: { repeatSubmit: false }
|
|
}).then((result) => ({ ...result, data: normalizeQuestion(result.data) }));
|
|
|
|
export const reviewQuestionAnswer = (id: number, decision: 'APPROVE' | 'REJECT', note = ''): Promise<ApiResult<AdminQuestionAnswer>> =>
|
|
request<unknown, ApiResult<RawAdminQuestionAnswer>>({
|
|
url: `/api/aihr/question-admin/answers/${id}/review`, method: 'post', data: { decision, note }, headers: { repeatSubmit: false }
|
|
}).then((result) => ({ ...result, data: normalizeAnswer(result.data) }));
|
|
|
|
export const selectBestAnswer = (questionId: number, answerId: number): Promise<ApiResult<unknown>> => request({
|
|
url: `/api/aihr/question-admin/questions/${questionId}/best-answer`, method: 'post', data: { answerId }, headers: { repeatSubmit: false }
|
|
});
|
|
|
|
export type PromoteCaseCandidateResult = { caseId: number; created: boolean };
|
|
|
|
export const promoteAnswerToCaseCandidate = (answerId: number): Promise<ApiResult<PromoteCaseCandidateResult>> => request({
|
|
url: `/api/aihr/question-admin/answers/${answerId}/to-case-candidate`, method: 'post', headers: { repeatSubmit: false }
|
|
});
|
|
|
|
export const listIncentiveRules = (): Promise<ApiResult<IncentiveRule[]>> => request({
|
|
url: '/api/aihr/incentive-admin/rules', method: 'get'
|
|
});
|
|
|
|
export const saveIncentiveRule = (data: IncentiveRule): Promise<ApiResult<IncentiveRule>> => request({
|
|
url: '/api/aihr/incentive-admin/rules',
|
|
method: data.id ? 'put' : 'post', data, headers: { repeatSubmit: false }
|
|
});
|