baodan/api/insurance/db/migrate_017.py

145 lines
6.1 KiB
Python
Raw Normal View History

"""迁移 017: 给 PPT 模板表新增 slides_config_json 列。
该列存储每种模板的逐页幻灯片配置标题模板叙事提示图表类型等
使管理员可以在后台管理页面中配置 PPT 的每一页内容
"""
import json
import logging
from sqlalchemy import text
logger = logging.getLogger(__name__)
def migrate():
"""执行迁移。"""
from insurance.db.compat import db
# 检查列是否已存在
result = db.session.execute(text(
"SELECT COUNT(*) FROM information_schema.columns "
"WHERE table_name = 'insurance_ppt_templates' AND column_name = 'slides_config_json'"
))
if result.scalar() > 0:
logger.info("slides_config_json 列已存在,跳过迁移")
return
db.session.execute(text(
"ALTER TABLE insurance_ppt_templates ADD COLUMN slides_config_json TEXT"
))
db.session.commit()
logger.info("已添加 slides_config_json 列")
# 为现有模板填充默认 slides_config
_seed_default_slides_config(db)
def _seed_default_slides_config(db):
"""为现有模板填充默认的逐页配置。"""
templates = db.session.execute(text(
"SELECT id, plan_type, required_page_types_json FROM insurance_ppt_templates WHERE status = 1"
)).fetchall()
for tpl in templates:
tpl_id, plan_type, rpt_json = tpl
if not rpt_json:
continue
try:
page_types = json.loads(rpt_json)
except (json.JSONDecodeError, TypeError):
continue
slides_config = _build_default_slides_config(page_types, plan_type)
db.session.execute(text(
"UPDATE insurance_ppt_templates SET slides_config_json = :config WHERE id = :id"
), {"config": json.dumps(slides_config, ensure_ascii=False), "id": tpl_id})
db.session.commit()
logger.info(f"已为 {len(templates)} 个模板填充默认 slides_config")
def _build_default_slides_config(page_types, plan_type):
"""根据 pageType 列表构建默认的逐页配置。"""
defaults = {
"cover": {"pageType": "cover", "title": "{{customerName}} 专属方案",
"subtitle": "{{productName}}", "narrativeHint": ""},
"company": {"pageType": "company", "title": "{{companyName}} 公司介绍",
"narrativeHint": "公司事实来自内部知识库权威口径"},
"narrative": {"pageType": "narrative", "title": "方案核心逻辑",
"narrativeHint": "先看结构,再看收益与保障"},
"chart": {"pageType": "chart", "title": "价值增长曲线",
"chartType": "growth", "narrativeHint": "先看回本区间再看20/30年关键点"},
"timeline": {"pageType": "timeline", "title": "家庭时间轴",
"narrativeHint": "把谁在什么阶段发挥作用讲清楚"},
"table": {"pageType": "table", "title": "数据表每10年",
"tableType": "no_withdraw", "narrativeHint": "含单利复利,便于长期价值对比"},
"compare": {"pageType": "compare", "title": "产品对比",
"narrativeHint": "保证部分是底线,非保证部分是弹性"},
"synergy": {"pageType": "synergy", "title": "协同关系",
"narrativeHint": "功能分层,互不冲突"},
"conclusion": {"pageType": "conclusion", "title": "结论",
"narrativeHint": "一张保家庭不失速,一张保未来不落空"},
"closing": {"pageType": "closing", "title": "感谢信任",
"narrativeHint": "方案可继续迭代优化,如有疑问请随时联系"},
}
# 根据产品类型调整默认标题
if plan_type == "ci":
defaults["narrative"]["title"] = "家庭风险防线"
defaults["narrative"]["narrativeHint"] = "先防风险,再做未来"
defaults["chart"]["title"] = "重疾保障数据曲线"
defaults["chart"]["chartType"] = "growth"
elif plan_type == "iul":
defaults["narrative"]["title"] = "传承杠杆设计"
defaults["narrative"]["narrativeHint"] = "先看杠杆,再看现金价值弹性"
defaults["chart"]["title"] = "IUL 长期利益曲线"
defaults["chart"]["chartType"] = "growth"
slides = []
table_count = 0
chart_count = 0
for pt in page_types:
if pt == "chart":
meta = dict(defaults.get(pt, {"pageType": pt}))
if chart_count == 0:
meta["chartType"] = "growth"
meta["title"] = "价值增长曲线"
else:
meta["chartType"] = "stacked"
meta["title"] = "保证/非保证构成"
chart_count += 1
elif pt == "table":
meta = dict(defaults.get(pt, {"pageType": pt}))
if table_count == 0:
meta["tableType"] = "no_withdraw"
meta["title"] = "不提领方案数据表每10年"
else:
meta["tableType"] = "withdraw"
meta["title"] = "提领方案数据表每10年"
table_count += 1
elif pt == "timeline":
meta = dict(defaults.get(pt, {"pageType": pt}))
# 第二个 timeline 用不同标题
if sum(1 for s in slides if s["pageType"] == "timeline") > 0:
meta["title"] = "中后期里程碑"
meta["narrativeHint"] = "养老金与长期传承阶段"
elif pt == "conclusion":
meta = dict(defaults.get(pt, {"pageType": pt}))
if sum(1 for s in slides if s["pageType"] == "conclusion") > 0:
meta["title"] = "下一步行动建议"
meta["narrativeHint"] = "建议尽快与保险经纪人预约确认方案"
else:
meta = dict(defaults.get(pt, {"pageType": pt}))
slides.append(meta)
return {"slides": slides}
def downgrade(engine):
"""回滚迁移。"""
with engine.begin() as conn:
conn.execute(text(
"ALTER TABLE insurance_ppt_templates DROP COLUMN IF EXISTS slides_config_json"
))
logger.info("已删除 slides_config_json 列")