gwy-exam/client/src/api/index.ts

174 lines
8.1 KiB
TypeScript

import { apiClient, unwrap } from './client'
import type { paths } from './generated/schema'
export type { ApiPaths, ApiErrorDetail } from './client'
export { ApiError } from './client'
export type { paths }
// ---- 从生成的 paths 推导请求/响应类型的工具类型(避免页面重复定义接口类型)----
type Methods = 'get' | 'post' | 'patch' | 'delete' | 'put'
type SuccessBody<Op> = Op extends {
responses: { 200: { content: { 'application/json': infer D } } }
}
? D
: never
type QueryOf<P extends keyof paths, M extends Methods> = paths[P][M] extends {
parameters: { query?: infer Q }
}
? Q
: never
type BodyOf<P extends keyof paths, M extends Methods> = paths[P][M] extends {
requestBody: { content: { 'application/json': infer B } }
}
? B
: never
// ---- 常用响应类型 ----
export type DashboardOverview = SuccessBody<paths['/api/dashboard/overview']['get']>
export type DashboardTrends = SuccessBody<paths['/api/dashboard/trends']['get']>
export type DashboardMastery = SuccessBody<paths['/api/dashboard/mastery']['get']>
export type DashboardWeakPoints = SuccessBody<paths['/api/dashboard/weak-points']['get']>
export type PracticeModules = SuccessBody<paths['/api/practice/modules']['get']>
export type PracticeSessionStart = SuccessBody<paths['/api/practice/start']['post']>
export type PracticeQuestion = SuccessBody<paths['/api/practice/{sessionId}/question']['get']>
export type PracticeAnswer = SuccessBody<paths['/api/practice/{sessionId}/answer']['post']>
export type PracticeFinish = SuccessBody<paths['/api/practice/{sessionId}/finish']['post']>
export type PracticeWrongReasons = SuccessBody<paths['/api/practice/wrong-reasons']['get']>
export type Profile = SuccessBody<paths['/api/profile']['get']>
export type Settings = SuccessBody<paths['/api/settings']['get']>
export type PlansToday = SuccessBody<paths['/api/plans/today']['get']>
export type PlansWeek = SuccessBody<paths['/api/plans/week']['get']>
export type PlanReview = SuccessBody<paths['/api/plans/review']['get']>
export type StudyPlanItem = SuccessBody<paths['/api/plans/today']['get']>['tasks'][number]
export type NewsItem = SuccessBody<paths['/api/news/list']['get']>['items'][number]
export type ImportResult = SuccessBody<paths['/api/news/import/json']['post']>
export type QuestionListItem = SuccessBody<paths['/api/questions/list']['get']>['items'][number]
export type QuestionListPage = SuccessBody<paths['/api/questions/list']['get']>
export type QuestionImportBody = BodyOf<'/api/questions/import', 'post'>
export type QuestionExport = SuccessBody<paths['/api/questions/export']['get']>
export type QuestionRefs = SuccessBody<paths['/api/questions/{id}/refs']['get']>
// ---- 数据中枢 ----
export const dashboardApi = {
overview: () => unwrap(apiClient.GET('/api/dashboard/overview')),
trends: (days?: number) =>
unwrap(apiClient.GET('/api/dashboard/trends', { params: { query: { days } } })),
mastery: () => unwrap(apiClient.GET('/api/dashboard/mastery')),
weakPoints: () => unwrap(apiClient.GET('/api/dashboard/weak-points'))
}
// ---- 刷题 ----
export const practiceApi = {
modules: () => unwrap(apiClient.GET('/api/practice/modules')),
start: (body: BodyOf<'/api/practice/start', 'post'>) =>
unwrap(apiClient.POST('/api/practice/start', { body })),
question: (sessionId: string) =>
unwrap(apiClient.GET('/api/practice/{sessionId}/question', { params: { path: { sessionId } } })),
answer: (sessionId: string, body: BodyOf<'/api/practice/{sessionId}/answer', 'post'>) =>
unwrap(
apiClient.POST('/api/practice/{sessionId}/answer', {
params: { path: { sessionId } },
body
})
),
finish: (sessionId: string) =>
unwrap(apiClient.POST('/api/practice/{sessionId}/finish', { params: { path: { sessionId } } })),
wrongReasons: () => unwrap(apiClient.GET('/api/practice/wrong-reasons'))
}
// ---- 错题复习 ----
export const reviewApi = {
list: (query?: QueryOf<'/api/review/list', 'get'>) =>
unwrap(apiClient.GET('/api/review/list', { params: { query } })),
detail: (id: string) =>
unwrap(apiClient.GET('/api/review/{id}/detail', { params: { path: { id } } })),
submit: (id: string, body: BodyOf<'/api/review/{id}/submit', 'post'>) =>
unwrap(apiClient.POST('/api/review/{id}/submit', { params: { path: { id } }, body })),
selfAssess: (id: string, body: BodyOf<'/api/review/{id}/self-assess', 'post'>) =>
unwrap(
apiClient.POST('/api/review/{id}/self-assess', {
params: { path: { id } },
body
})
),
markMastered: (id: string) =>
unwrap(apiClient.POST('/api/review/{id}/mark-mastered', { params: { path: { id } } }))
}
export type ReviewListItem = SuccessBody<paths['/api/review/list']['get']>['items'][number]
export type ReviewDetail = SuccessBody<paths['/api/review/{id}/detail']['get']>
export type ReviewSubmitResult = SuccessBody<paths['/api/review/{id}/submit']['post']>
// ---- 备考计划 ----
export const plansApi = {
today: (date?: string) => unwrap(apiClient.GET('/api/plans/today', { params: { query: { date } } })),
week: (start?: string) => unwrap(apiClient.GET('/api/plans/week', { params: { query: { start } } })),
createTask: (body: BodyOf<'/api/plans/tasks', 'post'>) =>
unwrap(apiClient.POST('/api/plans/tasks', { body })),
toggleTask: (id: string) =>
unwrap(apiClient.PATCH('/api/plans/tasks/{id}/toggle', { params: { path: { id } } })),
review: () => unwrap(apiClient.GET('/api/plans/review'))
}
// ---- 模考 ----
export const mockApi = {
analysis: () => unwrap(apiClient.GET('/api/mock-exams/analysis')),
record: (body: BodyOf<'/api/mock-exams/record', 'post'>) =>
unwrap(apiClient.POST('/api/mock-exams/record', { body })),
update: (id: string, body: BodyOf<'/api/mock-exams/{id}/update', 'post'>) =>
unwrap(apiClient.POST('/api/mock-exams/{id}/update', { params: { path: { id } }, body })),
remove: (id: string) => unwrap(apiClient.DELETE('/api/mock-exams/{id}', { params: { path: { id } } }))
}
export type MockExamRecord = SuccessBody<paths['/api/mock-exams/record']['post']>
export type MockExamAnalysis = SuccessBody<paths['/api/mock-exams/analysis']['get']>
export type MockExamListItem = MockExamAnalysis['records'][number]
// ---- 要闻 ----
export const newsApi = {
list: (query?: QueryOf<'/api/news/list', 'get'>) =>
unwrap(apiClient.GET('/api/news/list', { params: { query } })),
detail: (id: string) => unwrap(apiClient.GET('/api/news/{id}', { params: { path: { id } } })),
importJson: (body: BodyOf<'/api/news/import/json', 'post'>) =>
unwrap(apiClient.POST('/api/news/import/json', { body })),
importRss: (body: BodyOf<'/api/news/import/rss', 'post'>) =>
unwrap(apiClient.POST('/api/news/import/rss', { body })),
importApi: (body: BodyOf<'/api/news/import/api', 'post'>) =>
unwrap(apiClient.POST('/api/news/import/api', { body })),
importUrl: (body: BodyOf<'/api/news/import/url', 'post'>) =>
unwrap(apiClient.POST('/api/news/import/url', { body }))
}
// ---- 题库管理 ----
export const questionsApi = {
list: (query?: QueryOf<'/api/questions/list', 'get'>) =>
unwrap(apiClient.GET('/api/questions/list', { params: { query } })),
importQuestions: (body: BodyOf<'/api/questions/import', 'post'>) =>
unwrap(apiClient.POST('/api/questions/import', { body })),
exportQuestions: () => unwrap(apiClient.GET('/api/questions/export')),
refs: (id: string) => unwrap(apiClient.GET('/api/questions/{id}/refs', { params: { path: { id } } })),
remove: (id: string) => unwrap(apiClient.DELETE('/api/questions/{id}', { params: { path: { id } } }))
}
// ---- AI 讲解 ----
export const aiApi = {
explain: (body: BodyOf<'/api/ai/explain-question', 'post'>) =>
unwrap(apiClient.POST('/api/ai/explain-question', { body }))
}
// ---- 个人档案 / 设置 ----
export const profileApi = {
get: () => unwrap(apiClient.GET('/api/profile')),
patch: (body: BodyOf<'/api/profile', 'patch'>) =>
unwrap(apiClient.PATCH('/api/profile', { body }))
}
export const settingsApi = {
get: () => unwrap(apiClient.GET('/api/settings')),
patch: (body: BodyOf<'/api/settings', 'patch'>) =>
unwrap(apiClient.PATCH('/api/settings', { body }))
}