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 {
account: string;
password: string;
role: string;
}
export type LoginParams = LoginRequest
// Java 后端返回的平铺结构
export interface LoginResponse {
token: string;
userId: number;
username: string;
name: string;
role: 'admin' | 'school' | 'teacher' | 'parent';
tenantId?: number;
// Java 后端返回的平铺结构(保持与现有业务使用一致)
export interface LoginResponse extends Required<Omit<ApiLoginResponse, 'tenantId' | 'role'>> {
role: 'admin' | 'school' | 'teacher' | 'parent'
tenantId?: number
}
export interface UserProfile {
@ -29,20 +28,48 @@ export interface UserProfile {
// 登录
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> {
return http.post('/auth/logout');
return readingApi.logout().then(() => undefined)
}
// 刷新Token
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> {
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 {
page?: number;
pageSize?: number;
grade?: string;
status?: string;
keyword?: string;
}
export type CourseQueryParams = GetCoursePage1Params
export interface Course {
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 type Course = ApiCourse
export interface CourseLesson {
id: number;
@ -101,14 +63,26 @@ export interface ValidationWarning {
code: string;
}
// 获取课程包列表
export function getCourses(params: CourseQueryParams): Promise<{
items: Course[];
total: number;
page: number;
pageSize: number;
// 获取课程包列表(使用 Orval 生成的分页接口,并适配为原有扁平结构)
export function getCourses(
params: CourseQueryParams,
): Promise<{
items: Course[]
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;
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> {
return http.get(`/admin/courses/${id}`);
return readingApi.getCourse3(id).then((res) => res)
}
// 创建课程包
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> {
return http.put(`/admin/courses/${id}`, data);
return readingApi.updateCourse1(id, data).then((res) => res)
}
// 删除课程包
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> {
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> {
return http.post(`/admin/courses/${id}/submit`, { copyrightConfirmed });
export function submitCourse(id: number, _copyrightConfirmed: boolean): Promise<any> {
// 后端接口签名只需要 ID版权确认逻辑在前端自行控制
return readingApi.submitCourse(id).then((res) => res)
}
// 撤销审核
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> {
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> {
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> {
return http.post(`/admin/courses/${id}/direct-publish`, { skipValidation });
export function directPublishCourse(id: number, _skipValidation?: boolean): Promise<any> {
// skipValidation 由后端接口定义控制,这里总是调用“直接发布”接口
return readingApi.directPublishCourse(id).then((res) => res)
}
// 发布课程包兼容旧API
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> {
return http.post(`/admin/courses/${id}/unpublish`);
return readingApi.unpublishCourse(id).then((res) => res)
}
// 重新发布
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> {
// 统计接口在 OpenAPI 中与当前使用的字段含义略有差异,暂时保留旧实现
const { http } = require('./index')
return http.get(`/admin/courses/${id}/stats`);
}
// 获取版本历史
export function getCourseVersions(id: number): Promise<any[]> {
const { http } = require('./index')
return http.get(`/admin/courses/${id}/versions`);
}

View File

@ -3,7 +3,8 @@ import { message } from 'ant-design-vue';
// 创建axios实例
const request: AxiosInstance = axios.create({
baseURL: '/api/v1', // 使用 /api/v1代理会保留完整路径
// 由各调用方提供完整路径(例如 /api/v1/teacher/tasks这里不再追加前缀
baseURL: '',
timeout: 30000,
headers: {
'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 {
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 type CourseLesson = ApiCourseLesson
export interface LessonStep {
id: number;
@ -84,14 +67,17 @@ export interface CreateStepData {
// ==================== 超管端 API ====================
// 获取课程列表
// 获取课程列表(系统课程课时)
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) {
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) {
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>) {
// Orval 接口需要同时提供 courseId 和 lessonId这里仅有 lessonId 时保留旧实现
const { http } = require('./index')
return http.put(`/admin/courses/0/lessons/${lessonId}`, data);
}
// 删除课程
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[]) {
const { http } = require('./index')
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) {
const { http } = require('./index')
return http.get(`/admin/courses/${courseId}/lessons/${lessonId}/steps`);
}
// 创建环节
export function createStep(courseId: number, lessonId: number, data: CreateStepData) {
const { http } = require('./index')
return http.post(`/admin/courses/${courseId}/lessons/${lessonId}/steps`, data);
}
// 更新环节
export function updateStep(stepId: number, data: Partial<CreateStepData>) {
const { http } = require('./index')
return http.put(`/admin/courses/0/lessons/steps/${stepId}`, data);
}
// 删除环节
export function deleteStep(courseId: number, lessonId: number, stepId: number) {
const { http } = require('./index')
return http.delete(`/admin/courses/${courseId}/lessons/steps/${stepId}`);
}
// 重新排序环节
export function reorderSteps(courseId: number, lessonId: number, stepIds: number[]) {
const { http } = require('./index')
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 {
id: number;
name: string;
description?: string;
sortOrder: number;
status: string;
createdAt: string;
courses?: {
id: number;
name: string;
coverImagePath?: string;
}[];
}
export type Theme = ApiTheme
export interface CreateThemeData {
name: string;
@ -29,27 +18,33 @@ export interface UpdateThemeData {
// 获取主题列表
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) {
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) {
return http.post('/admin/themes', data);
return readingApi.createTheme(data as any).then((res) => res)
}
// 更新主题
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) {
return http.delete(`/admin/themes/${id}`);
return readingApi.deleteTheme(id).then((res) => res)
}
// 重新排序主题