add
This commit is contained in:
parent
6d14e4ecdc
commit
7047445c52
|
@ -98,11 +98,10 @@ export class PostService extends BaseTreeService<Prisma.PostDelegate> {
|
||||||
async createCourse(
|
async createCourse(
|
||||||
args: {
|
args: {
|
||||||
courseDetail: Prisma.PostCreateArgs;
|
courseDetail: Prisma.PostCreateArgs;
|
||||||
sections?: z.infer<typeof CourseMethodSchema.createSection>[];
|
|
||||||
},
|
},
|
||||||
params: { staff?: UserProfile; tx?: Prisma.TransactionClient },
|
params: { staff?: UserProfile; tx?: Prisma.TransactionClient },
|
||||||
) {
|
) {
|
||||||
const { courseDetail, sections } = args;
|
const { courseDetail } = args;
|
||||||
// If no transaction is provided, create a new one
|
// If no transaction is provided, create a new one
|
||||||
if (!params.tx) {
|
if (!params.tx) {
|
||||||
return await db.$transaction(async (tx) => {
|
return await db.$transaction(async (tx) => {
|
||||||
|
@ -112,20 +111,6 @@ export class PostService extends BaseTreeService<Prisma.PostDelegate> {
|
||||||
console.log('courseDetail', courseDetail);
|
console.log('courseDetail', courseDetail);
|
||||||
const createdCourse = await this.create(courseDetail, courseParams);
|
const createdCourse = await this.create(courseDetail, courseParams);
|
||||||
// If sections are provided, create them
|
// 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;
|
return createdCourse;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -133,21 +118,6 @@ export class PostService extends BaseTreeService<Prisma.PostDelegate> {
|
||||||
console.log('courseDetail', courseDetail);
|
console.log('courseDetail', courseDetail);
|
||||||
const createdCourse = await this.create(courseDetail, params);
|
const createdCourse = await this.create(courseDetail, params);
|
||||||
// If sections are provided, create them
|
// 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;
|
return createdCourse;
|
||||||
}
|
}
|
||||||
async create(
|
async create(
|
||||||
|
|
|
@ -161,12 +161,12 @@ export async function setCourseInfo({ data }: { data: Post }) {
|
||||||
sections.map((section) => section.id).includes(descendant.parentId)
|
sections.map((section) => section.id).includes(descendant.parentId)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
const lectureCount = lectures?.length || 0;
|
||||||
sections.forEach((section) => {
|
sections.forEach((section) => {
|
||||||
section.lectures = lectures.filter(
|
section.lectures = lectures.filter(
|
||||||
(lecture) => lecture.parentId === section.id,
|
(lecture) => lecture.parentId === section.id,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
Object.assign(data, { sections });
|
Object.assign(data, { sections, lectureCount });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ export class GenDevService {
|
||||||
await this.generateDepartments(3, 6);
|
await this.generateDepartments(3, 6);
|
||||||
await this.generateTerms(2, 6);
|
await this.generateTerms(2, 6);
|
||||||
await this.generateStaffs(4);
|
await this.generateStaffs(4);
|
||||||
|
await this.generateCourses();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.error(err);
|
this.logger.error(err);
|
||||||
}
|
}
|
||||||
|
@ -142,6 +143,64 @@ export class GenDevService {
|
||||||
collectChildren(domainId);
|
collectChildren(domainId);
|
||||||
return children;
|
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) {
|
private async generateStaffs(countPerDept: number = 3) {
|
||||||
if (this.counts.staffCount === 1) {
|
if (this.counts.staffCount === 1) {
|
||||||
this.logger.log('Generating staffs...');
|
this.logger.log('Generating staffs...');
|
||||||
|
@ -214,16 +273,19 @@ export class GenDevService {
|
||||||
type: PostType.COURSE,
|
type: PostType.COURSE,
|
||||||
title: title,
|
title: title,
|
||||||
updatedAt: dayjs().toDate(),
|
updatedAt: dayjs().toDate(),
|
||||||
// depts: {
|
depts: {
|
||||||
// connect: {
|
connect: {
|
||||||
// id: deptId,
|
id: deptId,
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// terms:{
|
terms: {
|
||||||
// connect:[cateId,levelId].map
|
connect: [cateId, levelId].map((id) => ({
|
||||||
// }
|
id: id,
|
||||||
|
})),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
return course;
|
||||||
}
|
}
|
||||||
private async createDepartment(
|
private async createDepartment(
|
||||||
name: string,
|
name: string,
|
||||||
|
|
|
@ -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';
|
import dayjs from 'dayjs';
|
||||||
export interface DevDataCounts {
|
export interface DevDataCounts {
|
||||||
deptCount: number;
|
deptCount: number;
|
||||||
|
|
||||||
staffCount: number
|
staffCount: number;
|
||||||
termCount: number
|
termCount: number;
|
||||||
|
courseCount: number;
|
||||||
}
|
}
|
||||||
export async function getCounts(): Promise<DevDataCounts> {
|
export async function getCounts(): Promise<DevDataCounts> {
|
||||||
const counts = {
|
const counts = {
|
||||||
deptCount: await db.department.count(),
|
deptCount: await db.department.count(),
|
||||||
|
|
||||||
staffCount: await db.staff.count(),
|
staffCount: await db.staff.count(),
|
||||||
termCount: await db.term.count(),
|
termCount: await db.term.count(),
|
||||||
};
|
courseCount: await db.post.count({
|
||||||
return counts;
|
where: {
|
||||||
|
type: PostType.COURSE,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
return counts;
|
||||||
}
|
}
|
||||||
export function capitalizeFirstLetter(string: string) {
|
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[] {
|
export function getRandomImageLinks(count: number = 5): string[] {
|
||||||
const baseUrl = 'https://picsum.photos/200/300?random=';
|
const baseUrl = 'https://picsum.photos/200/300?random=';
|
||||||
const imageLinks: string[] = [];
|
const imageLinks: string[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
// 生成随机数以确保每个链接都是唯一的
|
// 生成随机数以确保每个链接都是唯一的
|
||||||
const randomId = Math.floor(Math.random() * 1000);
|
const randomId = Math.floor(Math.random() * 1000);
|
||||||
imageLinks.push(`${baseUrl}${randomId}`);
|
imageLinks.push(`${baseUrl}${randomId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return imageLinks;
|
return imageLinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import { CourseContentFormHeader } from "./CourseContentFormHeader";
|
||||||
import { CourseSectionEmpty } from "./CourseSectionEmpty";
|
import { CourseSectionEmpty } from "./CourseSectionEmpty";
|
||||||
import { SortableSection } from "./SortableSection";
|
import { SortableSection } from "./SortableSection";
|
||||||
import { LectureList } from "./LectureList";
|
import { LectureList } from "./LectureList";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
|
||||||
const CourseContentForm: React.FC = () => {
|
const CourseContentForm: React.FC = () => {
|
||||||
const { editId } = useCourseEditor();
|
const { editId } = useCourseEditor();
|
||||||
|
@ -110,10 +111,11 @@ const CourseContentForm: React.FC = () => {
|
||||||
icon={<PlusOutlined />}
|
icon={<PlusOutlined />}
|
||||||
className="mt-4"
|
className="mt-4"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setItems([
|
if (items.some((item) => item.id === null)) {
|
||||||
...items.filter((item) => !!item.id),
|
toast.error("请先保存当前编辑章节");
|
||||||
{ id: null, title: "" },
|
} else {
|
||||||
]);
|
setItems([...items, { id: null, title: "" }]);
|
||||||
|
}
|
||||||
}}>
|
}}>
|
||||||
添加章节
|
添加章节
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -38,6 +38,7 @@ import { useCourseEditor } from "../../context/CourseEditorContext";
|
||||||
import { usePost } from "@nice/client";
|
import { usePost } from "@nice/client";
|
||||||
import { LectureData, SectionData } from "./interface";
|
import { LectureData, SectionData } from "./interface";
|
||||||
import { SortableLecture } from "./SortableLecture";
|
import { SortableLecture } from "./SortableLecture";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
|
||||||
interface LectureListProps {
|
interface LectureListProps {
|
||||||
field: SectionData;
|
field: SectionData;
|
||||||
|
@ -135,16 +136,20 @@ export const LectureList: React.FC<LectureListProps> = ({
|
||||||
icon={<PlusOutlined />}
|
icon={<PlusOutlined />}
|
||||||
className="mt-4"
|
className="mt-4"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setItems((prevItems) => [
|
if (items.some((item) => item.id === null)) {
|
||||||
...prevItems.filter((item) => !!item.id),
|
toast.error("请先保存当前编辑章节");
|
||||||
{
|
} else {
|
||||||
id: null,
|
setItems((prevItems) => [
|
||||||
title: "",
|
...prevItems.filter((item) => !!item.id),
|
||||||
meta: {
|
{
|
||||||
type: LectureType.ARTICLE,
|
id: null,
|
||||||
},
|
title: "",
|
||||||
} as Lecture,
|
meta: {
|
||||||
]);
|
type: LectureType.ARTICLE,
|
||||||
|
},
|
||||||
|
} as Lecture,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}}>
|
}}>
|
||||||
添加课时
|
添加课时
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -78,4 +78,5 @@ export type CourseDto = Course & {
|
||||||
enrollments?: Enrollment[];
|
enrollments?: Enrollment[];
|
||||||
sections?: SectionDto[];
|
sections?: SectionDto[];
|
||||||
terms: Term[];
|
terms: Term[];
|
||||||
|
lectureCount?: number;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue