kindergarten_java/reading-platform-frontend/src/api/course-center.ts
zhonghua 40782a8905 feat(theme): 主题字典颜色、课程主题 Tag 展示与列表数据规范化
- 后端:theme 表增加 color 字段;主题创建/更新/课程响应返回 themeColor
- 前端:主题管理页颜色选择器与列表;管理端课程列表与详情主题 Tag
- 课程中心/课程包卡片展示主题 Tag,course-center 规范化接口字段
- 隐藏管理端课程配置列与筛选;课程详情关联主题使用 themeName/color

Made-with: Cursor
2026-03-24 15:11:40 +08:00

149 lines
3.8 KiB
TypeScript

import { http } from './index';
// ============= 类型定义 =============
/** 套餐信息 */
export interface CourseCollection {
id: number;
name: string;
description?: string;
packageCount: number;
gradeLevels?: string[];
status: string;
startDate?: string;
endDate?: string;
}
/** 课程包中的课程项(用于提取课程配置) */
export interface CoursePackageCourseItem {
id?: number;
name?: string;
lessonType?: string;
}
/** 课程包信息 */
export interface CoursePackage {
id: number;
name: string;
description?: string;
coverImagePath?: string;
pictureBookName?: string;
gradeTags: string[];
domainTags?: string[]; // 不再展示,由课程配置替代
courses?: CoursePackageCourseItem[]; // 用于课程配置展示
themeId?: number;
themeName?: string;
/** 主题颜色(hex),来自主题字典 */
themeColor?: string;
durationMinutes?: number;
usageCount?: number;
avgRating?: number;
sortOrder?: number;
}
/** 筛选元数据 - 年级选项 */
export interface GradeOption {
label: string;
count: number;
}
/** 筛选元数据 - 课程配置选项 */
export interface LessonTypeOption {
lessonType: string;
name: string;
count: number;
}
/** 筛选元数据 - 课程包主题选项 */
export interface ThemeOption {
themeId: number;
name: string;
count: number;
}
/** 筛选元数据响应 */
export interface FilterMetaResponse {
grades: GradeOption[];
lessonTypes: LessonTypeOption[];
themes?: ThemeOption[];
}
// ============= 响应规范化(学校端/教师端共用同一接口,兼容字段形态) =============
function normalizeGradeTags(raw: unknown): string[] {
if (raw == null) return [];
if (Array.isArray(raw)) return raw.map(String).filter(Boolean);
if (typeof raw === 'string' && raw.trim()) {
const s = raw.trim();
if (s.startsWith('[')) {
try {
const j = JSON.parse(s);
return Array.isArray(j) ? j.map(String).filter(Boolean) : [];
} catch {
/* fallthrough */
}
}
return s.split(',').map((x) => x.trim()).filter(Boolean);
}
return [];
}
/** 统一课程包卡片所需字段,避免学校端/代理层返回 snake_case 或嵌套 theme 时主题不显示 */
export function normalizeCoursePackage(raw: any): CoursePackage {
if (!raw || typeof raw !== 'object') {
return raw as CoursePackage;
}
const nested =
raw.theme && typeof raw.theme === 'object' ? (raw.theme as Record<string, unknown>) : null;
const themeName = String(
raw.themeName ?? raw.theme_name ?? nested?.name ?? ''
).trim();
const themeColor = (raw.themeColor ?? raw.theme_color ?? nested?.color) as string | undefined;
const themeId = (raw.themeId ?? raw.theme_id ?? nested?.id) as number | undefined;
return {
...raw,
themeId: themeId ?? raw.themeId,
themeName: themeName || undefined,
themeColor: themeColor || undefined,
gradeTags: normalizeGradeTags(raw.gradeTags ?? raw.grade_tags),
};
}
// ============= API 接口 =============
/**
* 获取租户的课程套餐列表
*/
export function getCollections(): Promise<CourseCollection[]> {
return http.get<CourseCollection[]>('/v1/school/packages');
}
/**
* 获取套餐下的课程包列表(支持筛选)
*/
export function getPackages(
collectionId: number,
params?: {
grade?: string;
lessonType?: string;
themeId?: number;
keyword?: string;
}
): Promise<CoursePackage[]> {
return http
.get<any[]>(`/v1/school/packages/${collectionId}/packages`, {
params,
})
.then((list) =>
Array.isArray(list) ? list.map((item) => normalizeCoursePackage(item)) : []
);
}
/**
* 获取套餐的筛选元数据
*/
export function getFilterMeta(collectionId: number): Promise<FilterMetaResponse> {
return http.get<FilterMetaResponse>(`/v1/school/packages/${collectionId}/filter-meta`);
}