- gradeLevels: 后端 JSON 解析修复,前端兼容错误格式 - 筛选下拉: 状态选项按业务流程排序 - 已下架: 列表与详情页增加编辑、删除操作 - 课程包关联: 前后端去重,修复 uk_collection_package 唯一约束冲突 Made-with: Cursor
237 lines
6.4 KiB
TypeScript
237 lines
6.4 KiB
TypeScript
import { getReadingPlatformAPI } from './generated';
|
|
|
|
const api = getReadingPlatformAPI();
|
|
|
|
// ============= 类型定义 =============
|
|
|
|
export interface CollectionQueryParams {
|
|
pageNum?: number;
|
|
pageSize?: number;
|
|
status?: string;
|
|
}
|
|
|
|
export interface Collection {
|
|
id: number;
|
|
name: string;
|
|
description?: string;
|
|
price: number;
|
|
discountPrice?: number;
|
|
discountType?: string;
|
|
gradeLevels: string[];
|
|
packageCount?: number;
|
|
status: string;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
packages?: CollectionPackage[];
|
|
reviewComment?: string;
|
|
}
|
|
|
|
export interface CollectionPackage {
|
|
id: number;
|
|
name: string;
|
|
description?: string;
|
|
}
|
|
|
|
export interface CreateCollectionDto {
|
|
name: string;
|
|
description?: string;
|
|
price: number;
|
|
discountPrice?: number;
|
|
discountType?: string;
|
|
gradeLevels: string[];
|
|
}
|
|
|
|
export interface UpdateCollectionDto {
|
|
name?: string;
|
|
description?: string;
|
|
price?: number;
|
|
discountPrice?: number;
|
|
discountType?: string;
|
|
gradeLevels?: string[];
|
|
}
|
|
|
|
// ============= 辅助函数 =============
|
|
|
|
// 修复 gradeLevels 格式:后端返回的格式是 ["[\"小班\"", " \"中班\""]
|
|
// 需要转换为 ["小班", "中班"]
|
|
function fixGradeLevels(gradeLevels: string | string[] | undefined): string[] {
|
|
if (!gradeLevels) return [];
|
|
|
|
// 如果是字符串数组,尝试拼接并解析
|
|
if (Array.isArray(gradeLevels)) {
|
|
if (gradeLevels.length === 0) return [];
|
|
// 检查是否是被分割的 JSON 字符串
|
|
if (gradeLevels[0]?.startsWith('[')) {
|
|
try {
|
|
const joined = gradeLevels.join('');
|
|
return JSON.parse(joined);
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
return gradeLevels;
|
|
}
|
|
|
|
// 如果是字符串,尝试解析 JSON
|
|
if (typeof gradeLevels === 'string') {
|
|
try {
|
|
return JSON.parse(gradeLevels);
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
// 转换 API 响应数据为前端格式
|
|
function normalizeCollection(data: any): Collection {
|
|
// 如果数据是包装的响应格式 { code, message, data },提取 data 字段
|
|
const collectionData = data?.data ?? data;
|
|
|
|
if (!collectionData) {
|
|
throw new Error('套餐数据为空');
|
|
}
|
|
|
|
return {
|
|
...collectionData,
|
|
id: Number(collectionData.id),
|
|
price: Number(collectionData.price),
|
|
discountPrice: collectionData.discountPrice ? Number(collectionData.discountPrice) : undefined,
|
|
gradeLevels: fixGradeLevels(collectionData.gradeLevels),
|
|
};
|
|
}
|
|
|
|
function normalizePageResult(raw: any): {
|
|
items: Collection[];
|
|
total: number;
|
|
page: number;
|
|
pageSize: number;
|
|
} {
|
|
const list = raw?.list ?? raw?.items ?? [];
|
|
return {
|
|
items: Array.isArray(list) ? list.map(normalizeCollection) : [],
|
|
total: Number(raw?.total ?? 0),
|
|
page: Number(raw?.pageNum ?? raw?.page ?? 1),
|
|
pageSize: Number(raw?.pageSize ?? 10),
|
|
};
|
|
}
|
|
|
|
// ============= API 函数 =============
|
|
|
|
// 获取课程套餐列表
|
|
export function getCollections(params: CollectionQueryParams = {}): Promise<{
|
|
items: Collection[];
|
|
total: number;
|
|
page: number;
|
|
pageSize: number;
|
|
}> {
|
|
return (api.page as any)({
|
|
pageNum: params.pageNum ?? 1,
|
|
pageSize: params.pageSize ?? 10,
|
|
...(params.status ? { status: params.status } : {}),
|
|
}).then(normalizePageResult) as any;
|
|
}
|
|
|
|
// 获取课程套餐详情
|
|
export async function getCollection(id: number | string): Promise<Collection> {
|
|
const data = await (api.findOne2 as any)(Number(id)) as any;
|
|
if (!data) {
|
|
throw new Error('获取套餐详情失败:返回数据为空');
|
|
}
|
|
return normalizeCollection(data);
|
|
}
|
|
|
|
// 创建课程套餐
|
|
export function createCollection(data: CreateCollectionDto): Promise<Collection> {
|
|
return (api.create as any)(data) as any;
|
|
}
|
|
|
|
// 更新课程套餐
|
|
export function updateCollection(id: number | string, data: UpdateCollectionDto): Promise<Collection> {
|
|
return (api.update2 as any)(id as number, data) as any;
|
|
}
|
|
|
|
// 删除课程套餐
|
|
export function deleteCollection(id: number | string): Promise<void> {
|
|
return (api.delete2 as any)(id as number) as any;
|
|
}
|
|
|
|
// 设置套餐课程包
|
|
export function setCollectionPackages(id: number | string, packageIds: number[]): Promise<void> {
|
|
return (api.setPackages as any)(id as number, packageIds) as any;
|
|
}
|
|
|
|
// 发布课程套餐
|
|
export function publishCollection(id: number | string): Promise<void> {
|
|
return (api.publish as any)(id as number) as any;
|
|
}
|
|
|
|
// 下架课程套餐
|
|
export function archiveCollection(id: number | string): Promise<void> {
|
|
return (api.archive as any)(id as number) as any;
|
|
}
|
|
|
|
// 重新发布课程套餐
|
|
export function republishCollection(id: number | string): Promise<void> {
|
|
return (api.republish as any)(id as number) as any;
|
|
}
|
|
|
|
// 撤销审核
|
|
export function withdrawCollection(id: number | string): Promise<void> {
|
|
return (api.withdraw as any)(id as number) as any;
|
|
}
|
|
|
|
// 授予租户
|
|
export function grantToTenant(collectionId: number | string, tenantIds: number[]): Promise<void> {
|
|
return (api.grantToTenant as any)(collectionId as number, tenantIds) as any;
|
|
}
|
|
|
|
// ============= 常量 =============
|
|
|
|
export const COLLECTION_STATUS_MAP: Record<string, { label: string; color: string }> = {
|
|
DRAFT: { label: '草稿', color: 'default' },
|
|
PENDING: { label: '待审核', color: 'processing' },
|
|
APPROVED: { label: '已通过', color: 'success' },
|
|
PUBLISHED: { label: '已发布', color: 'blue' },
|
|
ARCHIVED: { label: '已下架', color: 'warning' },
|
|
REJECTED: { label: '已驳回', color: 'error' },
|
|
};
|
|
|
|
export function getCollectionStatusInfo(status: string) {
|
|
return COLLECTION_STATUS_MAP[status] || { label: status, color: 'default' };
|
|
}
|
|
|
|
// 解析适用年级(统一处理列表展示与创建时的格式)
|
|
export function parseGradeLevels(gradeLevels: string | string[] | undefined): string[] {
|
|
if (!gradeLevels) return [];
|
|
if (Array.isArray(gradeLevels)) {
|
|
if (gradeLevels.length === 0) return [];
|
|
// 兼容后端错误格式:["[\"小班\"", " \"中班\""] -> 拼接后解析
|
|
if (gradeLevels[0]?.toString().startsWith('[')) {
|
|
try {
|
|
return JSON.parse(gradeLevels.join(''));
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
return gradeLevels;
|
|
}
|
|
try {
|
|
return JSON.parse(gradeLevels || '[]');
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// 格式化价格
|
|
export function formatPrice(price: number | null | undefined): string {
|
|
if (price === null || price === undefined) return '-';
|
|
return `¥${(price / 100).toFixed(2)}`;
|
|
}
|
|
|
|
// 格式化日期
|
|
export function formatDate(date: string): string {
|
|
return new Date(date).toLocaleString('zh-CN');
|
|
}
|