baodan/api/insurance/models/ppt_session.py
wsb1224 25c6f2a3b7 阶段 3 剩余:编辑与版本化
功能	文件	说明
幻灯片显隐	routes.py, PptResult.vue, ppt-api.ts	每页可点击隐藏/恢复,隐藏页在缩略图中半透明显示,页码标注隐藏数量
DeckContract 快照	renderer.py, celery_tasks.py, ppt_session.py	生成时保存完整 deck JSON 到文件系统,供版本化回溯
版本化生成	celery_tasks.py, task_service.py, routes.py	POST /preview/:id/regenerate → 递增版本号 → 用 deck 重新渲染 → 追加到版本历史,不覆盖旧版
版本历史 UI	PptResult.vue	右栏显示版本列表(版本号/页数/时间),当前版本高亮标记
数据库迁移	migrate_025.py	新增 deck_contract_path、versions_json 字段
阶段 4:UI 重构
功能	文件	说明
保险绿主题	PptPage.vue, PptGenerate.vue, PptResult.vue, PptSlideCanvas.vue	主色从 #2563eb 蓝改为 #3B7A57 保险绿,背景暖灰 #f0f7f3
生成决策展示	PptGenerate.vue	新增"系统决策"区域,展示检测场景、选用模板、计划书数量、险种类型、保司
骨架屏加载	PptResult.vue	preview_status=none/generating 时显示骨架屏 + 加载动画,不再显示静态 fallback
新增后端接口(本轮)
方法	路径	功能
POST	/ppt/preview/:id/regenerate	基于编辑内容生成新版本
PUT	/ppt/preview/:id/slide/:index	增加 hidden 字段支持
新增 Celery 任务
任务名	说明
insurance.regenerate_ppt	读取 DeckContract → 应用编辑 → 重新渲染 → 保存新版本
2026-07-29 21:41:28 +08:00

81 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""PPT 生成会话模型。"""
from sqlalchemy import Column, String, Text, Integer, TIMESTAMP, func
from insurance.db.compat import db
class PptSession(db.Model):
"""PPT 生成会话表。"""
__tablename__ = "insurance_ppt_sessions"
id = Column(String(36), primary_key=True, comment="UUID")
user_id = Column(String(64), nullable=False, comment="用户 ID")
status = Column(String(20), default="created", nullable=False,
comment="状态: created/parsing/parsed/generating/done/error")
files_json = Column(Text, nullable=True, comment="上传文件列表 JSON")
extractions_json = Column(Text, nullable=True, comment="提取结果 JSON")
parse_progress = Column(Integer, default=0, nullable=False, comment="解析进度 0-100")
parse_message = Column(Text, nullable=True, comment="解析进度说明")
parse_error = Column(Text, nullable=True, comment="解析任务错误")
parse_started_at = Column(TIMESTAMP, nullable=True, comment="解析开始时间")
parse_finished_at = Column(TIMESTAMP, nullable=True, comment="解析完成时间")
chat_history_json = Column(Text, nullable=True, comment="对话历史 JSON")
ppt_path = Column(String(500), nullable=True, comment="生成的 PPT 路径")
markdown_path = Column(String(500), nullable=True, comment="Markdown 路径")
preview_paths_json = Column(Text, nullable=True, comment="预览图路径 JSON")
preview_pdf_path = Column(String(500), nullable=True, comment="预览 PDF 路径")
slide_count = Column(Integer, nullable=True, comment="幻灯片数量")
# 工作区字段migrate_022
title = Column(String(200), default="", comment="用户可识别名称")
workflow_step = Column(String(20), default="upload", comment="当前业务步骤")
draft_options_json = Column(Text, nullable=True, comment="模板、公司、脱敏等草稿设置")
draft_revision = Column(Integer, default=1, comment="当前草稿版本")
generated_revision = Column(Integer, default=0, comment="最新成品版本")
latest_task_id = Column(String(36), nullable=True, comment="最近一次任务 ID")
latest_output_path = Column(String(500), nullable=True, comment="最新成品路径")
archived_at = Column(TIMESTAMP, nullable=True, comment="归档时间")
# 预览与质量检查migrate_025
slides_json_path = Column(String(500), nullable=True, comment="幻灯片结构 JSON 路径")
quality_report_json = Column(Text, nullable=True, comment="质量检查报告 JSON")
preview_status = Column(String(20), default="none", nullable=False,
comment="预览状态: none/generating/ready/failed")
deck_contract_path = Column(String(500), nullable=True, comment="DeckContract 快照路径")
versions_json = Column(Text, nullable=True, comment="版本历史 JSON 数组")
created_at = Column(TIMESTAMP, server_default=func.now())
updated_at = Column(TIMESTAMP, server_default=func.now(), onupdate=func.now())
def to_dict(self):
import json
return {
"id": self.id,
"user_id": self.user_id,
"status": self.status,
"files": json.loads(self.files_json) if self.files_json else [],
"extractions": json.loads(self.extractions_json) if self.extractions_json else [],
"parse_progress": self.parse_progress or 0,
"parse_message": self.parse_message,
"parse_error": self.parse_error,
"parse_started_at": str(self.parse_started_at) if self.parse_started_at else None,
"parse_finished_at": str(self.parse_finished_at) if self.parse_finished_at else None,
"chat_history": json.loads(self.chat_history_json) if self.chat_history_json else [],
"ppt_path": self.ppt_path,
"markdown_path": self.markdown_path,
"preview_paths": json.loads(self.preview_paths_json) if self.preview_paths_json else [],
"preview_pdf_path": self.preview_pdf_path,
"slide_count": self.slide_count,
"title": self.title or "",
"workflow_step": self.workflow_step or "upload",
"draft_options": json.loads(self.draft_options_json) if self.draft_options_json else None,
"draft_revision": self.draft_revision or 1,
"generated_revision": self.generated_revision or 0,
"latest_task_id": self.latest_task_id,
"latest_output_path": self.latest_output_path,
"archived_at": str(self.archived_at) if self.archived_at else None,
"slides_json_path": self.slides_json_path,
"quality_report": json.loads(self.quality_report_json) if self.quality_report_json else None,
"preview_status": self.preview_status or "none",
"deck_contract_path": self.deck_contract_path,
"versions": json.loads(self.versions_json) if self.versions_json else [],
"created_at": str(self.created_at) if self.created_at else None,
"updated_at": str(self.updated_at) if self.updated_at else None,
}