From 8b66945823ff009de95952d9c4bc2863ff9a68b0 Mon Sep 17 00:00:00 2001 From: xiamuceer Date: Wed, 19 Nov 2025 14:50:28 +0800 Subject: [PATCH] =?UTF-8?q?update:1.=E6=9B=B4=E6=96=B0=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=A4=A7=E7=BA=B2=E7=BB=86=E5=8C=96=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/schemas/import_export.py | 5 ++ backend/app/services/import_export_service.py | 88 ++++++++++++++----- 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/backend/app/schemas/import_export.py b/backend/app/schemas/import_export.py index 0e3dba3..85383f2 100644 --- a/backend/app/schemas/import_export.py +++ b/backend/app/schemas/import_export.py @@ -19,6 +19,11 @@ class ChapterExportData(BaseModel): word_count: int = 0 status: str = "draft" created_at: Optional[str] = None + + # 大纲细化功能新增字段 + outline_title: Optional[str] = None # 关联的大纲标题(用于导入时重建关联) + sub_index: Optional[int] = None # 大纲下的子章节序号 + expansion_plan: Optional[Dict[str, Any]] = None # 展开规划详情(JSON对象) class CharacterExportData(BaseModel): diff --git a/backend/app/services/import_export_service.py b/backend/app/services/import_export_service.py index 3f2c86f..0a0f478 100644 --- a/backend/app/services/import_export_service.py +++ b/backend/app/services/import_export_service.py @@ -144,18 +144,41 @@ class ImportExportService: ) chapters = result.scalars().all() - return [ - ChapterExportData( + # 构建大纲ID到标题的映射 + outline_mapping = {} + if chapters: + outline_ids = [ch.outline_id for ch in chapters if ch.outline_id] + if outline_ids: + outline_result = await db.execute( + select(Outline).where(Outline.id.in_(outline_ids)) + ) + outlines = outline_result.scalars().all() + outline_mapping = {ol.id: ol.title for ol in outlines} + + exported_chapters = [] + for ch in chapters: + # 解析expansion_plan JSON + expansion_plan = None + if ch.expansion_plan: + try: + expansion_plan = json.loads(ch.expansion_plan) if isinstance(ch.expansion_plan, str) else ch.expansion_plan + except: + expansion_plan = None + + exported_chapters.append(ChapterExportData( title=ch.title, content=ch.content, summary=ch.summary, chapter_number=ch.chapter_number, word_count=ch.word_count or 0, status=ch.status, - created_at=ch.created_at.isoformat() if ch.created_at else None - ) - for ch in chapters - ] + created_at=ch.created_at.isoformat() if ch.created_at else None, + outline_title=outline_mapping.get(ch.outline_id) if ch.outline_id else None, + sub_index=ch.sub_index, + expansion_plan=expansion_plan + )) + + return exported_chapters @staticmethod async def _export_characters(project_id: str, db: AsyncSession) -> List[CharacterExportData]: @@ -482,26 +505,26 @@ class ImportExportService: logger.info(f"创建项目成功: {new_project.id}") - # 导入章节 - chapters_count = await ImportExportService._import_chapters( - new_project.id, data.get("chapters", []), db - ) - statistics["chapters"] = chapters_count - logger.info(f"导入章节数: {chapters_count}") - - # 导入角色(包括组织) + # 导入角色(包括组织)- 需要先导入角色,因为大纲可能需要角色信息 char_mapping = await ImportExportService._import_characters( new_project.id, data.get("characters", []), db ) statistics["characters"] = len(char_mapping) logger.info(f"导入角色数: {len(char_mapping)}") - # 导入大纲 - outlines_count = await ImportExportService._import_outlines( + # 导入大纲 - 需要在章节之前导入,以便建立关联 + outline_mapping = await ImportExportService._import_outlines( new_project.id, data.get("outlines", []), db ) - statistics["outlines"] = outlines_count - logger.info(f"导入大纲数: {outlines_count}") + statistics["outlines"] = len(outline_mapping) + logger.info(f"导入大纲数: {len(outline_mapping)}") + + # 导入章节 - 使用大纲映射重建关联关系 + chapters_count = await ImportExportService._import_chapters( + new_project.id, data.get("chapters", []), outline_mapping, db + ) + statistics["chapters"] = chapters_count + logger.info(f"导入章节数: {chapters_count}") # 导入关系 relationships_count = await ImportExportService._import_relationships( @@ -558,11 +581,23 @@ class ImportExportService: async def _import_chapters( project_id: str, chapters_data: List[Dict], + outline_mapping: Dict[str, str], db: AsyncSession ) -> int: """导入章节""" count = 0 for ch_data in chapters_data: + # 根据大纲标题查找对应的新大纲ID + outline_id = None + outline_title = ch_data.get("outline_title") + if outline_title and outline_title in outline_mapping: + outline_id = outline_mapping[outline_title] + + # 处理expansion_plan + expansion_plan = ch_data.get("expansion_plan") + if expansion_plan and isinstance(expansion_plan, dict): + expansion_plan = json.dumps(expansion_plan, ensure_ascii=False) + chapter = Chapter( project_id=project_id, title=ch_data.get("title"), @@ -570,7 +605,10 @@ class ImportExportService: summary=ch_data.get("summary"), chapter_number=ch_data.get("chapter_number"), word_count=ch_data.get("word_count", 0), - status=ch_data.get("status", "draft") + status=ch_data.get("status", "draft"), + outline_id=outline_id, + sub_index=ch_data.get("sub_index"), + expansion_plan=expansion_plan ) db.add(chapter) count += 1 @@ -617,9 +655,10 @@ class ImportExportService: project_id: str, outlines_data: List[Dict], db: AsyncSession - ) -> int: - """导入大纲""" - count = 0 + ) -> Dict[str, str]: + """导入大纲,返回标题到ID的映射""" + outline_mapping = {} + for ol_data in outlines_data: outline = Outline( project_id=project_id, @@ -629,9 +668,10 @@ class ImportExportService: order_index=ol_data.get("order_index") ) db.add(outline) - count += 1 + await db.flush() # 获取ID + outline_mapping[ol_data.get("title")] = outline.id - return count + return outline_mapping @staticmethod async def _import_relationships(