This commit is contained in:
ditiqi 2025-02-24 19:56:43 +08:00
parent 6d14e4ecdc
commit 7047445c52
7 changed files with 126 additions and 76 deletions

View File

@ -98,11 +98,10 @@ export class PostService extends BaseTreeService<Prisma.PostDelegate> {
async createCourse(
args: {
courseDetail: Prisma.PostCreateArgs;
sections?: z.infer<typeof CourseMethodSchema.createSection>[];
},
params: { staff?: UserProfile; tx?: Prisma.TransactionClient },
) {
const { courseDetail, sections } = args;
const { courseDetail } = args;
// If no transaction is provided, create a new one
if (!params.tx) {
return await db.$transaction(async (tx) => {
@ -112,20 +111,6 @@ export class PostService extends BaseTreeService<Prisma.PostDelegate> {
console.log('courseDetail', courseDetail);
const createdCourse = await this.create(courseDetail, courseParams);
// If sections are provided, create them
if (sections && sections.length > 0) {
const sectionPromises = sections.map((section) =>
this.createSection(
{
courseId: createdCourse.id,
title: section.title,
lectures: section.lectures,
},
courseParams,
),
);
// Create all sections (and their lectures) in parallel
await Promise.all(sectionPromises);
}
return createdCourse;
});
}
@ -133,21 +118,6 @@ export class PostService extends BaseTreeService<Prisma.PostDelegate> {
console.log('courseDetail', courseDetail);
const createdCourse = await this.create(courseDetail, params);
// If sections are provided, create them
if (sections && sections.length > 0) {
const sectionPromises = sections.map((section) =>
this.createSection(
{
courseId: createdCourse.id,
title: section.title,
lectures: section.lectures,
},
params,
),
);
// Create all sections (and their lectures) in parallel
await Promise.all(sectionPromises);
}
return createdCourse;
}
async create(

View File

@ -161,12 +161,12 @@ export async function setCourseInfo({ data }: { data: Post }) {
sections.map((section) => section.id).includes(descendant.parentId)
);
});
const lectureCount = lectures?.length || 0;
sections.forEach((section) => {
section.lectures = lectures.filter(
(lecture) => lecture.parentId === section.id,
);
});
Object.assign(data, { sections });
Object.assign(data, { sections, lectureCount });
}
}

View File

@ -45,6 +45,7 @@ export class GenDevService {
await this.generateDepartments(3, 6);
await this.generateTerms(2, 6);
await this.generateStaffs(4);
await this.generateCourses();
} catch (err) {
this.logger.error(err);
}
@ -142,6 +143,64 @@ export class GenDevService {
collectChildren(domainId);
return children;
}
private async generateCourses(countPerCate: number = 3) {
const titleList = [
'计算机科学导论',
'数据结构与算法',
'网络安全',
'机器学习',
'数据库管理系统',
'Web开发',
'移动应用开发',
'人工智能',
'计算机网络',
'操作系统',
'数字信号处理',
'无线通信',
'信息论',
'密码学',
'计算机图形学',
];
if (!this.counts.courseCount) {
this.logger.log('Generating courses...');
const depts = await db.department.findMany({
select: { id: true, name: true },
});
const cates = await db.term.findMany({
where: {
taxonomy: { slug: TaxonomySlug.CATEGORY },
},
select: { id: true, name: true },
});
const total = cates.length * countPerCate;
const levels = await db.term.findMany({
where: {
taxonomy: { slug: TaxonomySlug.LEVEL },
},
select: { id: true, name: true },
});
for (const cate of cates) {
for (let i = 0; i < countPerCate; i++) {
const randomTitle = `${titleList[Math.floor(Math.random() * titleList.length)]} ${Math.random().toString(36).substring(7)}`;
const randomLevelId =
levels[Math.floor(Math.random() * levels.length)].id;
const randomDeptId =
depts[Math.floor(Math.random() * depts.length)].id;
await this.createCourse(
randomTitle,
randomDeptId,
cate.id,
randomLevelId,
);
this.logger.log(
`Generated ${this.deptGeneratedCount}/${total} departments`,
);
}
}
}
}
private async generateStaffs(countPerDept: number = 3) {
if (this.counts.staffCount === 1) {
this.logger.log('Generating staffs...');
@ -214,16 +273,19 @@ export class GenDevService {
type: PostType.COURSE,
title: title,
updatedAt: dayjs().toDate(),
// depts: {
// connect: {
// id: deptId,
// },
// },
// terms:{
// connect:[cateId,levelId].map
// }
depts: {
connect: {
id: deptId,
},
},
terms: {
connect: [cateId, levelId].map((id) => ({
id: id,
})),
},
},
});
return course;
}
private async createDepartment(
name: string,

View File

@ -1,34 +1,44 @@
import { db, getRandomElement, getRandomIntInRange, getRandomTimeInterval, } from '@nice/common';
import {
db,
getRandomElement,
getRandomIntInRange,
getRandomTimeInterval,
PostType,
} from '@nice/common';
import dayjs from 'dayjs';
export interface DevDataCounts {
deptCount: number;
deptCount: number;
staffCount: number
termCount: number
staffCount: number;
termCount: number;
courseCount: number;
}
export async function getCounts(): Promise<DevDataCounts> {
const counts = {
deptCount: await db.department.count(),
const counts = {
deptCount: await db.department.count(),
staffCount: await db.staff.count(),
termCount: await db.term.count(),
};
return counts;
staffCount: await db.staff.count(),
termCount: await db.term.count(),
courseCount: await db.post.count({
where: {
type: PostType.COURSE,
},
}),
};
return counts;
}
export function capitalizeFirstLetter(string: string) {
return string.charAt(0).toUpperCase() + string.slice(1);
return string.charAt(0).toUpperCase() + string.slice(1);
}
export function getRandomImageLinks(count: number = 5): string[] {
const baseUrl = 'https://picsum.photos/200/300?random=';
const imageLinks: string[] = [];
const baseUrl = 'https://picsum.photos/200/300?random=';
const imageLinks: string[] = [];
for (let i = 0; i < count; i++) {
// 生成随机数以确保每个链接都是唯一的
const randomId = Math.floor(Math.random() * 1000);
imageLinks.push(`${baseUrl}${randomId}`);
}
for (let i = 0; i < count; i++) {
// 生成随机数以确保每个链接都是唯一的
const randomId = Math.floor(Math.random() * 1000);
imageLinks.push(`${baseUrl}${randomId}`);
}
return imageLinks;
return imageLinks;
}

View File

@ -24,6 +24,7 @@ import { CourseContentFormHeader } from "./CourseContentFormHeader";
import { CourseSectionEmpty } from "./CourseSectionEmpty";
import { SortableSection } from "./SortableSection";
import { LectureList } from "./LectureList";
import toast from "react-hot-toast";
const CourseContentForm: React.FC = () => {
const { editId } = useCourseEditor();
@ -110,10 +111,11 @@ const CourseContentForm: React.FC = () => {
icon={<PlusOutlined />}
className="mt-4"
onClick={() => {
setItems([
...items.filter((item) => !!item.id),
{ id: null, title: "" },
]);
if (items.some((item) => item.id === null)) {
toast.error("请先保存当前编辑章节");
} else {
setItems([...items, { id: null, title: "" }]);
}
}}>
</Button>

View File

@ -38,6 +38,7 @@ import { useCourseEditor } from "../../context/CourseEditorContext";
import { usePost } from "@nice/client";
import { LectureData, SectionData } from "./interface";
import { SortableLecture } from "./SortableLecture";
import toast from "react-hot-toast";
interface LectureListProps {
field: SectionData;
@ -135,16 +136,20 @@ export const LectureList: React.FC<LectureListProps> = ({
icon={<PlusOutlined />}
className="mt-4"
onClick={() => {
setItems((prevItems) => [
...prevItems.filter((item) => !!item.id),
{
id: null,
title: "",
meta: {
type: LectureType.ARTICLE,
},
} as Lecture,
]);
if (items.some((item) => item.id === null)) {
toast.error("请先保存当前编辑章节");
} else {
setItems((prevItems) => [
...prevItems.filter((item) => !!item.id),
{
id: null,
title: "",
meta: {
type: LectureType.ARTICLE,
},
} as Lecture,
]);
}
}}>
</Button>

View File

@ -78,4 +78,5 @@ export type CourseDto = Course & {
enrollments?: Enrollment[];
sections?: SectionDto[];
terms: Term[];
lectureCount?: number;
};