256 lines
6.8 KiB
TypeScript
256 lines
6.8 KiB
TypeScript
import { getReadingPlatformAPI } from './generated';
|
||
import { axios } from './generated/mutator';
|
||
|
||
// 创建 API 实例
|
||
const api = getReadingPlatformAPI();
|
||
|
||
// ============= 类型定义(保持向后兼容) =============
|
||
|
||
export interface CourseQueryParams {
|
||
pageNum?: number;
|
||
pageSize?: number;
|
||
grade?: string;
|
||
status?: string;
|
||
keyword?: string;
|
||
/** 审核管理页专用:仅返回待审核和已驳回,排除已通过 */
|
||
reviewOnly?: boolean;
|
||
}
|
||
|
||
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 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 interface LessonStep {
|
||
id: number;
|
||
lessonId: number;
|
||
name: string;
|
||
content?: string;
|
||
duration: number;
|
||
objective?: string;
|
||
resourceIds?: string;
|
||
sortOrder: number;
|
||
}
|
||
|
||
export interface ValidationResult {
|
||
valid: boolean;
|
||
errors: ValidationError[];
|
||
warnings: ValidationWarning[];
|
||
}
|
||
|
||
export interface ValidationError {
|
||
field: string;
|
||
message: string;
|
||
code: string;
|
||
}
|
||
|
||
export interface ValidationWarning {
|
||
field: string;
|
||
message: string;
|
||
code: string;
|
||
}
|
||
|
||
// ============= API 函数(使用生成的客户端) =============
|
||
|
||
// 转换查询参数类型
|
||
const toFindAllParams = (params: CourseQueryParams): any => ({
|
||
pageNum: params.pageNum ?? 1,
|
||
pageSize: params.pageSize ?? 10,
|
||
keyword: params.keyword,
|
||
category: params.grade,
|
||
status: params.status || undefined,
|
||
reviewOnly: params.reviewOnly,
|
||
});
|
||
|
||
// 后端 PageResult 返回 list,前端统一转为 items
|
||
function normalizePageResult(raw: any): {
|
||
items: Course[];
|
||
total: number;
|
||
page: number;
|
||
pageSize: number;
|
||
} {
|
||
const list = raw?.list ?? raw?.items ?? [];
|
||
return {
|
||
items: Array.isArray(list) ? list : [],
|
||
total: raw?.total ?? 0,
|
||
page: raw?.pageNum ?? raw?.page ?? 1,
|
||
pageSize: raw?.pageSize ?? 10,
|
||
};
|
||
}
|
||
|
||
// 获取课程包列表
|
||
export function getCourses(params: CourseQueryParams): Promise<{
|
||
items: Course[];
|
||
total: number;
|
||
page: number;
|
||
pageSize: number;
|
||
}> {
|
||
return api.getCoursePage1(toFindAllParams(params)).then(normalizePageResult) as any;
|
||
}
|
||
|
||
// 获取审核列表(仅返回待审核和已驳回,不含已通过)
|
||
export function getReviewList(params: CourseQueryParams): Promise<{
|
||
items: Course[];
|
||
total: number;
|
||
page: number;
|
||
pageSize: number;
|
||
}> {
|
||
return api.getCoursePage1(toFindAllParams({ ...params, reviewOnly: true })).then(normalizePageResult) as any;
|
||
}
|
||
|
||
// 获取课程包详情(id 支持 number | string,避免大整数精度丢失)
|
||
export function getCourse(id: number | string): Promise<any> {
|
||
return api.getCourse1(id as number) as any;
|
||
}
|
||
|
||
// 创建课程包
|
||
export function createCourse(data: any): Promise<any> {
|
||
return api.createCourse(data) as any;
|
||
}
|
||
|
||
// 更新课程包
|
||
export function updateCourse(id: number | string, data: any): Promise<any> {
|
||
return api.updateCourse(id as number, data) as any;
|
||
}
|
||
|
||
// 删除课程包
|
||
export function deleteCourse(id: number | string): Promise<any> {
|
||
return api.deleteCourse(id as number) as any;
|
||
}
|
||
|
||
// 验证课程完整性 (暂时返回 true,后端可能没有此接口)
|
||
export function validateCourse(id: number): Promise<ValidationResult> {
|
||
return Promise.resolve({ valid: true, errors: [], warnings: [] });
|
||
}
|
||
|
||
// 提交审核
|
||
export function submitCourse(id: number, copyrightConfirmed?: boolean): Promise<any> {
|
||
return api.submit(id) as any;
|
||
}
|
||
|
||
// 撤销审核 (暂时使用更新接口,需要确认后端是否有此功能)
|
||
export function withdrawCourse(id: number): Promise<any> {
|
||
return api.updateCourse(id, { status: 'DRAFT' }) as any;
|
||
}
|
||
|
||
// 审核通过
|
||
export function approveCourse(id: number, data: { checklist?: any; comment?: string }): Promise<any> {
|
||
return api.publishCourse(id) as any;
|
||
}
|
||
|
||
// 审核驳回(课程专用,调用 POST /api/v1/admin/courses/{id}/reject)
|
||
export function rejectCourse(id: number, data: { checklist?: any; comment: string }): Promise<any> {
|
||
return axios.post(`/api/v1/admin/courses/${id}/reject`, { comment: data.comment }).then((res: any) => {
|
||
const body = res?.data;
|
||
if (body && typeof body === 'object' && 'code' in body && body.code !== 200 && body.code !== 0) {
|
||
throw new Error(body.message || '驳回失败');
|
||
}
|
||
return body?.data;
|
||
});
|
||
}
|
||
|
||
// 直接发布(超级管理员)
|
||
export function directPublishCourse(id: number, skipValidation?: boolean): Promise<any> {
|
||
return api.publishCourse(id) as any;
|
||
}
|
||
|
||
// 发布课程包
|
||
export function publishCourse(id: number): Promise<any> {
|
||
return api.publishCourse(id) as any;
|
||
}
|
||
|
||
// 下架课程包
|
||
export function unpublishCourse(id: number): Promise<any> {
|
||
return api.archiveCourse(id) as any;
|
||
}
|
||
|
||
// 重新发布 (使用发布接口)
|
||
export function republishCourse(id: number): Promise<any> {
|
||
return api.publishCourse(id) as any;
|
||
}
|
||
|
||
// 获取课程包统计数据 (暂时返回空对象)
|
||
export function getCourseStats(id: number | string): Promise<any> {
|
||
return Promise.resolve({});
|
||
}
|
||
|
||
// 获取版本历史 (暂时返回空数组)
|
||
export function getCourseVersions(id: number): Promise<any[]> {
|
||
return Promise.resolve([]);
|
||
}
|
||
|
||
// ============= 常量 =============
|
||
|
||
// 课程状态映射
|
||
export const COURSE_STATUS_MAP: Record<string, { label: string; color: string }> = {
|
||
DRAFT: { label: '草稿', color: 'default' },
|
||
PENDING: { label: '审核中', color: 'processing' },
|
||
REJECTED: { label: '已驳回', color: 'error' },
|
||
PUBLISHED: { label: '已发布', color: 'success' },
|
||
ARCHIVED: { label: '已下架', color: 'warning' },
|
||
};
|
||
|
||
// 获取状态显示信息
|
||
export function getCourseStatusInfo(status: string) {
|
||
return COURSE_STATUS_MAP[status] || { label: status, color: 'default' };
|
||
}
|