refactor(api): 重构 API 接口以使用新的 readingApi 客户端

- 将多个 API 函数从旧的 http 实现迁移到新的 readingApi 客户端
- 更新登录、登出、获取用户信息等功能以适应新的数据结构
- 统一课程、主题和课时的 API 调用方式,简化代码结构
- 保留部分旧接口以兼容后端,确保现有功能不受影响
This commit is contained in:
zhonghua 2026-03-10 16:44:24 +08:00
parent 583b47c430
commit 5d96c832f6
6 changed files with 168 additions and 137 deletions

View File

@ -1,19 +1,18 @@
import { http } from './index'; import { readingApi } from './client'
import type {
LoginRequest,
LoginResponse as ApiLoginResponse,
ResultLoginResponse,
ResultUserInfoResponse,
UserInfoResponse,
} from './generated/model'
export interface LoginParams { export type LoginParams = LoginRequest
account: string;
password: string;
role: string;
}
// Java 后端返回的平铺结构 // Java 后端返回的平铺结构(保持与现有业务使用一致)
export interface LoginResponse { export interface LoginResponse extends Required<Omit<ApiLoginResponse, 'tenantId' | 'role'>> {
token: string; role: 'admin' | 'school' | 'teacher' | 'parent'
userId: number; tenantId?: number
username: string;
name: string;
role: 'admin' | 'school' | 'teacher' | 'parent';
tenantId?: number;
} }
export interface UserProfile { export interface UserProfile {
@ -29,20 +28,48 @@ export interface UserProfile {
// 登录 // 登录
export function login(params: LoginParams): Promise<LoginResponse> { export function login(params: LoginParams): Promise<LoginResponse> {
return http.post('/auth/login', params).then((res: any) => res.data); return readingApi.login(params).then((res) => {
const wrapped = res as ResultLoginResponse
const data = (wrapped.data ?? {}) as ApiLoginResponse
return {
token: data.token ?? '',
userId: data.userId ?? 0,
username: data.username ?? '',
name: data.name ?? '',
role: (data.role as LoginResponse['role']) ?? 'teacher',
tenantId: data.tenantId,
}
})
} }
// 登出 // 登出
export function logout(): Promise<void> { export function logout(): Promise<void> {
return http.post('/auth/logout'); return readingApi.logout().then(() => undefined)
} }
// 刷新Token // 刷新Token
export function refreshToken(): Promise<{ token: string }> { export function refreshToken(): Promise<{ token: string }> {
return http.post('/auth/refresh'); // OpenAPI 目前未定义 refresh 接口,暂时保留原有调用路径以兼容后端
const { http } = require('./index')
return http.post('/auth/refresh')
} }
// 获取当前用户信息 // 获取当前用户信息
export function getProfile(): Promise<UserProfile> { export function getProfile(): Promise<UserProfile> {
return http.get('/auth/profile'); return readingApi.getCurrentUser().then((res) => {
const wrapped = res as ResultUserInfoResponse
const data = (wrapped.data ?? {}) as UserInfoResponse
return {
id: data.id ?? 0,
name: data.name ?? '',
role: (data.role as UserProfile['role']) ?? 'teacher',
tenantId: data.tenantId,
tenantName: undefined,
email: data.email,
phone: data.phone,
avatar: data.avatarUrl,
}
})
} }

View File

@ -0,0 +1,16 @@
import { getReadingPlatformAPI } from './generated/api'
import type { ResultUserInfoResponse } from './generated/model'
// Orval 生成的完整 API 客户端
export const readingApi = getReadingPlatformAPI()
// 通用工具类型:根据方法名拿到返回 Promise 的结果类型
export type ApiResultOf<K extends keyof ReturnType<typeof getReadingPlatformAPI>> =
Awaited<ReturnType<ReturnType<typeof getReadingPlatformAPI>[K]>>
// 如果后端统一使用 Result<T> 包裹,这个类型可以从中解包出 data
export type UnwrapResult<R> = R extends { data: infer D } ? D : R
// 示例:当前登录用户信息的解包类型
export type CurrentUserInfo = UnwrapResult<ResultUserInfoResponse>

View File

@ -1,53 +1,15 @@
import { http } from './index'; import { readingApi } from './client'
import type {
GetCoursePage1Params,
ResultPageResultCourse,
Course as ApiCourse,
ApproveCourseParams,
RejectCourseParams,
} from './generated/model'
export interface CourseQueryParams { export type CourseQueryParams = GetCoursePage1Params
page?: number;
pageSize?: number;
grade?: string;
status?: string;
keyword?: string;
}
export interface Course { export type Course = ApiCourse
id: number;
name: string;
description?: string;
pictureBookName?: string;
grades: string[];
status: string;
version: string;
usageCount: number;
teacherCount: number;
avgRating: number;
createdAt: Date;
updatedAt: Date;
submittedAt?: Date;
reviewedAt?: Date;
reviewComment?: string;
// 新增字段
themeId?: number;
theme?: { id: number; name: string };
coreContent?: string;
coverImagePath?: string;
domainTags?: string[];
gradeTags?: string[];
duration?: number;
// 课程介绍字段
introSummary?: string;
introHighlights?: string;
introGoals?: string;
introSchedule?: string;
introKeyPoints?: string;
introMethods?: string;
introEvaluation?: string;
introNotes?: string;
// 排课计划参考
scheduleRefData?: string;
// 环创建设
environmentConstruction?: string;
// 关联课程
courseLessons?: CourseLesson[];
}
export interface CourseLesson { export interface CourseLesson {
id: number; id: number;
@ -101,14 +63,26 @@ export interface ValidationWarning {
code: string; code: string;
} }
// 获取课程包列表 // 获取课程包列表(使用 Orval 生成的分页接口,并适配为原有扁平结构)
export function getCourses(params: CourseQueryParams): Promise<{ export function getCourses(
items: Course[]; params: CourseQueryParams,
total: number; ): Promise<{
page: number; items: Course[]
pageSize: number; total: number
page: number
pageSize: number
}> { }> {
return http.get('/admin/courses', { params }); return readingApi.getCoursePage1(params).then((res) => {
const wrapped = res as ResultPageResultCourse
const pageData = wrapped.data
return {
items: (pageData?.items as Course[]) ?? [],
total: pageData?.total ?? 0,
page: pageData?.page ?? params.page ?? 1,
pageSize: pageData?.pageSize ?? params.pageSize ?? 10,
}
})
} }
// 获取审核列表 // 获取审核列表
@ -118,81 +92,105 @@ export function getReviewList(params: CourseQueryParams): Promise<{
page: number; page: number;
pageSize: number; pageSize: number;
}> { }> {
return http.get('/admin/courses/review', { params }); // 审核列表对应 Orval 的 getReviewCoursePage返回结构同课程分页
return readingApi.getReviewCoursePage(params as any).then((res) => {
const wrapped = res as ResultPageResultCourse
const pageData = wrapped.data
return {
items: (pageData?.items as Course[]) ?? [],
total: pageData?.total ?? 0,
page: pageData?.page ?? params.page ?? 1,
pageSize: pageData?.pageSize ?? params.pageSize ?? 10,
}
})
} }
// 获取课程包详情 // 获取课程包详情
export function getCourse(id: number): Promise<any> { export function getCourse(id: number): Promise<any> {
return http.get(`/admin/courses/${id}`); return readingApi.getCourse3(id).then((res) => res)
} }
// 创建课程包 // 创建课程包
export function createCourse(data: any): Promise<any> { export function createCourse(data: any): Promise<any> {
return http.post('/admin/courses', data); return readingApi.createCourse1(data).then((res) => res)
} }
// 更新课程包 // 更新课程包
export function updateCourse(id: number, data: any): Promise<any> { export function updateCourse(id: number, data: any): Promise<any> {
return http.put(`/admin/courses/${id}`, data); return readingApi.updateCourse1(id, data).then((res) => res)
} }
// 删除课程包 // 删除课程包
export function deleteCourse(id: number): Promise<any> { export function deleteCourse(id: number): Promise<any> {
return http.delete(`/admin/courses/${id}`); return readingApi.deleteCourse1(id).then((res) => res)
} }
// 验证课程完整性 // 验证课程完整性
export function validateCourse(id: number): Promise<ValidationResult> { export function validateCourse(id: number): Promise<ValidationResult> {
return http.get(`/admin/courses/${id}/validate`); // 暂无对应 Orval 接口,继续使用旧路径
const { http } = require('./index')
return http.get(`/admin/courses/${id}/validate`)
} }
// 提交审核 // 提交审核
export function submitCourse(id: number, copyrightConfirmed: boolean): Promise<any> { export function submitCourse(id: number, _copyrightConfirmed: boolean): Promise<any> {
return http.post(`/admin/courses/${id}/submit`, { copyrightConfirmed }); // 后端接口签名只需要 ID版权确认逻辑在前端自行控制
return readingApi.submitCourse(id).then((res) => res)
} }
// 撤销审核 // 撤销审核
export function withdrawCourse(id: number): Promise<any> { export function withdrawCourse(id: number): Promise<any> {
return http.post(`/admin/courses/${id}/withdraw`); return readingApi.withdrawCourse(id).then((res) => res)
} }
// 审核通过 // 审核通过
export function approveCourse(id: number, data: { checklist?: any; comment?: string }): Promise<any> { export function approveCourse(id: number, data: { checklist?: any; comment?: string }): Promise<any> {
return http.post(`/admin/courses/${id}/approve`, data); const params: ApproveCourseParams = {
comment: data.comment,
}
return readingApi.approveCourse(id, params).then((res) => res)
} }
// 审核驳回 // 审核驳回
export function rejectCourse(id: number, data: { checklist?: any; comment: string }): Promise<any> { export function rejectCourse(id: number, data: { checklist?: any; comment: string }): Promise<any> {
return http.post(`/admin/courses/${id}/reject`, data); const params: RejectCourseParams = {
comment: data.comment,
}
return readingApi.rejectCourse(id, params).then((res) => res)
} }
// 直接发布(超级管理员) // 直接发布(超级管理员)
export function directPublishCourse(id: number, skipValidation?: boolean): Promise<any> { export function directPublishCourse(id: number, _skipValidation?: boolean): Promise<any> {
return http.post(`/admin/courses/${id}/direct-publish`, { skipValidation }); // skipValidation 由后端接口定义控制,这里总是调用“直接发布”接口
return readingApi.directPublishCourse(id).then((res) => res)
} }
// 发布课程包兼容旧API // 发布课程包兼容旧API
export function publishCourse(id: number): Promise<any> { export function publishCourse(id: number): Promise<any> {
return http.post(`/admin/courses/${id}/publish`); return readingApi.publishCourse(id).then((res) => res)
} }
// 下架课程包 // 下架课程包
export function unpublishCourse(id: number): Promise<any> { export function unpublishCourse(id: number): Promise<any> {
return http.post(`/admin/courses/${id}/unpublish`); return readingApi.unpublishCourse(id).then((res) => res)
} }
// 重新发布 // 重新发布
export function republishCourse(id: number): Promise<any> { export function republishCourse(id: number): Promise<any> {
return http.post(`/admin/courses/${id}/republish`); return readingApi.republishCourse(id).then((res) => res)
} }
// 获取课程包统计数据 // 获取课程包统计数据
export function getCourseStats(id: number): Promise<any> { export function getCourseStats(id: number): Promise<any> {
// 统计接口在 OpenAPI 中与当前使用的字段含义略有差异,暂时保留旧实现
const { http } = require('./index')
return http.get(`/admin/courses/${id}/stats`); return http.get(`/admin/courses/${id}/stats`);
} }
// 获取版本历史 // 获取版本历史
export function getCourseVersions(id: number): Promise<any[]> { export function getCourseVersions(id: number): Promise<any[]> {
const { http } = require('./index')
return http.get(`/admin/courses/${id}/versions`); return http.get(`/admin/courses/${id}/versions`);
} }

View File

@ -3,7 +3,8 @@ import { message } from 'ant-design-vue';
// 创建axios实例 // 创建axios实例
const request: AxiosInstance = axios.create({ const request: AxiosInstance = axios.create({
baseURL: '/api/v1', // 使用 /api/v1代理会保留完整路径 // 由各调用方提供完整路径(例如 /api/v1/teacher/tasks这里不再追加前缀
baseURL: '',
timeout: 30000, timeout: 30000,
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',

View File

@ -1,29 +1,12 @@
import { http } from './index'; import { readingApi } from './client'
import type {
ResultListCourseLesson,
CourseLesson as ApiCourseLesson,
} from './generated/model'
// ==================== 课程类型 ==================== // ==================== 课程类型 ====================
export interface CourseLesson { export type CourseLesson = ApiCourseLesson
id: number;
courseId: number;
lessonType: string;
name: string;
description?: string;
duration: number;
videoPath?: string;
videoName?: string;
pptPath?: string;
pptName?: string;
pdfPath?: string;
pdfName?: string;
objectives?: string;
preparation?: string;
extension?: string;
reflection?: string;
assessmentData?: string;
useTemplate: boolean;
sortOrder: number;
steps?: LessonStep[];
}
export interface LessonStep { export interface LessonStep {
id: number; id: number;
@ -84,14 +67,17 @@ export interface CreateStepData {
// ==================== 超管端 API ==================== // ==================== 超管端 API ====================
// 获取课程列表 // 获取课程列表(系统课程课时)
export function getLessonList(courseId: number) { export function getLessonList(courseId: number) {
return http.get(`/admin/courses/${courseId}/lessons`); return readingApi.getLessons1(courseId).then((res) => {
const wrapped = res as ResultListCourseLesson
return wrapped.data?.items ?? []
})
} }
// 获取课程详情 // 获取课程详情
export function getLessonDetail(courseId: number, lessonId: number) { export function getLessonDetail(courseId: number, lessonId: number) {
return http.get(`/admin/courses/${courseId}/lessons/${lessonId}`); return readingApi.getLesson2(courseId, lessonId).then((res) => res.data ?? res)
} }
// 按类型获取课程 // 按类型获取课程
@ -101,21 +87,24 @@ export function getLessonByType(courseId: number, lessonType: string) {
// 创建课程 // 创建课程
export function createLesson(courseId: number, data: CreateLessonData) { export function createLesson(courseId: number, data: CreateLessonData) {
return http.post(`/admin/courses/${courseId}/lessons`, data); return readingApi.createLesson1(courseId, data as any).then((res) => res)
} }
// 更新课程 // 更新课程
export function updateLesson(lessonId: number, data: Partial<CreateLessonData>) { export function updateLesson(lessonId: number, data: Partial<CreateLessonData>) {
// Orval 接口需要同时提供 courseId 和 lessonId这里仅有 lessonId 时保留旧实现
const { http } = require('./index')
return http.put(`/admin/courses/0/lessons/${lessonId}`, data); return http.put(`/admin/courses/0/lessons/${lessonId}`, data);
} }
// 删除课程 // 删除课程
export function deleteLesson(courseId: number, lessonId: number) { export function deleteLesson(courseId: number, lessonId: number) {
return http.delete(`/admin/courses/${courseId}/lessons/${lessonId}`); return readingApi.deleteLesson(courseId, lessonId).then((res) => res)
} }
// 重新排序课程 // 重新排序课程
export function reorderLessons(courseId: number, lessonIds: number[]) { export function reorderLessons(courseId: number, lessonIds: number[]) {
const { http } = require('./index')
return http.put(`/admin/courses/${courseId}/lessons/reorder`, { lessonIds }); return http.put(`/admin/courses/${courseId}/lessons/reorder`, { lessonIds });
} }
@ -123,26 +112,31 @@ export function reorderLessons(courseId: number, lessonIds: number[]) {
// 获取环节列表 // 获取环节列表
export function getStepList(courseId: number, lessonId: number) { export function getStepList(courseId: number, lessonId: number) {
const { http } = require('./index')
return http.get(`/admin/courses/${courseId}/lessons/${lessonId}/steps`); return http.get(`/admin/courses/${courseId}/lessons/${lessonId}/steps`);
} }
// 创建环节 // 创建环节
export function createStep(courseId: number, lessonId: number, data: CreateStepData) { export function createStep(courseId: number, lessonId: number, data: CreateStepData) {
const { http } = require('./index')
return http.post(`/admin/courses/${courseId}/lessons/${lessonId}/steps`, data); return http.post(`/admin/courses/${courseId}/lessons/${lessonId}/steps`, data);
} }
// 更新环节 // 更新环节
export function updateStep(stepId: number, data: Partial<CreateStepData>) { export function updateStep(stepId: number, data: Partial<CreateStepData>) {
const { http } = require('./index')
return http.put(`/admin/courses/0/lessons/steps/${stepId}`, data); return http.put(`/admin/courses/0/lessons/steps/${stepId}`, data);
} }
// 删除环节 // 删除环节
export function deleteStep(courseId: number, lessonId: number, stepId: number) { export function deleteStep(courseId: number, lessonId: number, stepId: number) {
const { http } = require('./index')
return http.delete(`/admin/courses/${courseId}/lessons/steps/${stepId}`); return http.delete(`/admin/courses/${courseId}/lessons/steps/${stepId}`);
} }
// 重新排序环节 // 重新排序环节
export function reorderSteps(courseId: number, lessonId: number, stepIds: number[]) { export function reorderSteps(courseId: number, lessonId: number, stepIds: number[]) {
const { http } = require('./index')
return http.put(`/admin/courses/${courseId}/lessons/${lessonId}/steps/reorder`, { stepIds }); return http.put(`/admin/courses/${courseId}/lessons/${lessonId}/steps/reorder`, { stepIds });
} }

View File

@ -1,18 +1,7 @@
import { http } from './index'; import { readingApi } from './client'
import type { ResultListTheme, ResultTheme, Theme as ApiTheme } from './generated/model'
export interface Theme { export type Theme = ApiTheme
id: number;
name: string;
description?: string;
sortOrder: number;
status: string;
createdAt: string;
courses?: {
id: number;
name: string;
coverImagePath?: string;
}[];
}
export interface CreateThemeData { export interface CreateThemeData {
name: string; name: string;
@ -29,27 +18,33 @@ export interface UpdateThemeData {
// 获取主题列表 // 获取主题列表
export function getThemeList() { export function getThemeList() {
return http.get('/admin/themes'); return readingApi.getThemes().then((res) => {
const wrapped = res as ResultListTheme
return wrapped.data ?? []
})
} }
// 获取主题详情 // 获取主题详情
export function getThemeDetail(id: number) { export function getThemeDetail(id: number) {
return http.get(`/admin/themes/${id}`); return readingApi.getTheme(id).then((res) => {
const wrapped = res as ResultTheme
return wrapped.data ?? res
})
} }
// 创建主题 // 创建主题
export function createTheme(data: CreateThemeData) { export function createTheme(data: CreateThemeData) {
return http.post('/admin/themes', data); return readingApi.createTheme(data as any).then((res) => res)
} }
// 更新主题 // 更新主题
export function updateTheme(id: number, data: UpdateThemeData) { export function updateTheme(id: number, data: UpdateThemeData) {
return http.put(`/admin/themes/${id}`, data); return readingApi.updateTheme(id, data as any).then((res) => res)
} }
// 删除主题 // 删除主题
export function deleteTheme(id: number) { export function deleteTheme(id: number) {
return http.delete(`/admin/themes/${id}`); return readingApi.deleteTheme(id).then((res) => res)
} }
// 重新排序主题 // 重新排序主题