|
@@ -53,6 +53,71 @@ function outlineChapterFromDb(dbChapter: any) {
|
|
|
// ============ 存储类 ============
|
|
// ============ 存储类 ============
|
|
|
|
|
|
|
|
export class BookStore {
|
|
export class BookStore {
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 从数据库章节记录构建树形结构的outline
|
|
|
|
|
+ */
|
|
|
|
|
+ private buildOutlineFromChapters(chapters: any[]): BookOutline | null {
|
|
|
|
|
+ if (!chapters || chapters.length === 0) return null;
|
|
|
|
|
+
|
|
|
|
|
+ // 获取所有level=1的章
|
|
|
|
|
+ const level1Chapters = chapters.filter(c => c.level === 1);
|
|
|
|
|
+ if (level1Chapters.length === 0) return null;
|
|
|
|
|
+
|
|
|
|
|
+ // 构建映射表
|
|
|
|
|
+ const chapterMap = new Map<number, any>();
|
|
|
|
|
+ const sectionMap = new Map<number, any>();
|
|
|
|
|
+
|
|
|
|
|
+ chapters.forEach(c => {
|
|
|
|
|
+ if (c.level === 1) {
|
|
|
|
|
+ chapterMap.set(c.id, {
|
|
|
|
|
+ number: c.number,
|
|
|
|
|
+ title: c.title,
|
|
|
|
|
+ summary: c.summary || '',
|
|
|
|
|
+ keyPoints: c.keyPoints ? JSON.parse(c.keyPoints) : [],
|
|
|
|
|
+ estimatedWords: c.estimatedWords,
|
|
|
|
|
+ sections: []
|
|
|
|
|
+ });
|
|
|
|
|
+ } else if (c.level === 2) {
|
|
|
|
|
+ sectionMap.set(c.id, {
|
|
|
|
|
+ number: c.number,
|
|
|
|
|
+ title: c.title,
|
|
|
|
|
+ summary: c.summary || '',
|
|
|
|
|
+ keyPoints: c.keyPoints ? JSON.parse(c.keyPoints) : [],
|
|
|
|
|
+ estimatedWords: c.estimatedWords,
|
|
|
|
|
+ subsections: []
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 构建节和小节的关系
|
|
|
|
|
+ chapters.forEach(c => {
|
|
|
|
|
+ if (c.level === 2 && c.parentId) {
|
|
|
|
|
+ const chapter = chapterMap.get(c.parentId);
|
|
|
|
|
+ const section = sectionMap.get(c.id);
|
|
|
|
|
+ if (chapter && section) {
|
|
|
|
|
+ chapter.sections.push(section);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (c.level === 3 && c.parentId) {
|
|
|
|
|
+ const section = sectionMap.get(c.parentId);
|
|
|
|
|
+ if (section) {
|
|
|
|
|
+ section.subsections.push({
|
|
|
|
|
+ number: c.number,
|
|
|
|
|
+ title: c.title,
|
|
|
|
|
+ summary: c.summary || '',
|
|
|
|
|
+ keyPoints: c.keyPoints ? JSON.parse(c.keyPoints) : [],
|
|
|
|
|
+ estimatedWords: c.estimatedWords
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ mainTheme: '',
|
|
|
|
|
+ structureLogic: '',
|
|
|
|
|
+ chapters: Array.from(chapterMap.values())
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 创建书籍
|
|
* 创建书籍
|
|
|
*/
|
|
*/
|
|
@@ -95,13 +160,28 @@ export class BookStore {
|
|
|
async getById(id: string, filterPublic: boolean = false, userId?: number): Promise<Book | null> {
|
|
async getById(id: string, filterPublic: boolean = false, userId?: number): Promise<Book | null> {
|
|
|
const book = await prisma.book.findUnique({
|
|
const book = await prisma.book.findUnique({
|
|
|
where: { id: parseInt(id) },
|
|
where: { id: parseInt(id) },
|
|
|
- include: { chapters: { where: { level: 1 }, orderBy: { number: 'asc' } } },
|
|
|
|
|
|
|
+ include: {
|
|
|
|
|
+ chapters: {
|
|
|
|
|
+ orderBy: [
|
|
|
|
|
+ { level: 'asc' },
|
|
|
|
|
+ { number: 'asc' }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
if (!book) return null;
|
|
if (!book) return null;
|
|
|
|
|
|
|
|
|
|
+ // 构建树形结构的outline(从数据库章节记录构建)
|
|
|
|
|
+ const outline = this.buildOutlineFromChapters(book.chapters);
|
|
|
|
|
+
|
|
|
let result = this.toBook(book);
|
|
let result = this.toBook(book);
|
|
|
|
|
|
|
|
|
|
+ // 用数据库构建的outline替换outlineJson解析的
|
|
|
|
|
+ if (outline) {
|
|
|
|
|
+ result.outline = outline;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 如果需要过滤公开音频
|
|
// 如果需要过滤公开音频
|
|
|
if (filterPublic && userId) {
|
|
if (filterPublic && userId) {
|
|
|
const isOwner = book.userId === userId;
|
|
const isOwner = book.userId === userId;
|