2026-07-27 13:52:09 +08:00
|
|
|
|
"""迁移 014: 导入 PPT 配置数据。
|
|
|
|
|
|
|
|
|
|
|
|
使用原始 SQL 而非 ORM,避免模型字段与实际表结构不一致的问题。
|
|
|
|
|
|
(ORM 模型包含 migrate_017 才创建的 slides_config_json 字段)
|
|
|
|
|
|
"""
|
2026-07-23 13:10:50 +08:00
|
|
|
|
import os
|
|
|
|
|
|
import json
|
|
|
|
|
|
import logging
|
2026-07-27 13:52:09 +08:00
|
|
|
|
from sqlalchemy import text
|
2026-07-23 13:10:50 +08:00
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
CONFIG_DIR = os.path.join(os.path.dirname(__file__), "..", "ppt", "config")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _read_json_file(filepath):
|
|
|
|
|
|
try:
|
|
|
|
|
|
with open(filepath, "r", encoding="utf-8") as f:
|
|
|
|
|
|
return json.load(f)
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _read_json_files_in_dir(dirpath):
|
|
|
|
|
|
results = []
|
|
|
|
|
|
if not os.path.isdir(dirpath):
|
|
|
|
|
|
return results
|
|
|
|
|
|
for root, _, files in os.walk(dirpath):
|
|
|
|
|
|
for fname in files:
|
|
|
|
|
|
if fname.endswith(".json"):
|
|
|
|
|
|
data = _read_json_file(os.path.join(root, fname))
|
|
|
|
|
|
if data is not None:
|
|
|
|
|
|
results.append(data)
|
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-07-27 13:52:09 +08:00
|
|
|
|
def _record_exists(db, table: str, id_col: str, id_val: str) -> bool:
|
|
|
|
|
|
"""检查记录是否存在。"""
|
|
|
|
|
|
result = db.session.execute(
|
|
|
|
|
|
text(f"SELECT 1 FROM {table} WHERE {id_col} = :id LIMIT 1"),
|
|
|
|
|
|
{"id": id_val},
|
|
|
|
|
|
)
|
|
|
|
|
|
return result.fetchone() is not None
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-07-23 13:10:50 +08:00
|
|
|
|
def migrate():
|
|
|
|
|
|
"""迁移入口。"""
|
|
|
|
|
|
from insurance.db.compat import db
|
|
|
|
|
|
|
|
|
|
|
|
# 公司
|
|
|
|
|
|
companies_dir = os.path.join(CONFIG_DIR, "companies")
|
|
|
|
|
|
count = 0
|
|
|
|
|
|
for d in _read_json_files_in_dir(companies_dir):
|
2026-07-27 13:52:09 +08:00
|
|
|
|
if not d.get("id") or _record_exists(db, "insurance_ppt_companies", "id", d["id"]):
|
2026-07-23 13:10:50 +08:00
|
|
|
|
continue
|
2026-07-27 13:52:09 +08:00
|
|
|
|
db.session.execute(text(
|
|
|
|
|
|
"INSERT INTO insurance_ppt_companies "
|
|
|
|
|
|
"(id, display_name, aliases_json, tenant_id, knowledge_directories_json, "
|
|
|
|
|
|
"evidence_ranking_json, company_intro, company_highlights_json) "
|
|
|
|
|
|
"VALUES (:id, :display_name, :aliases_json, :tenant_id, :knowledge_directories_json, "
|
|
|
|
|
|
":evidence_ranking_json, :company_intro, :company_highlights_json)"
|
|
|
|
|
|
), {
|
|
|
|
|
|
"id": d["id"],
|
|
|
|
|
|
"display_name": d.get("displayName", ""),
|
|
|
|
|
|
"aliases_json": json.dumps(d.get("aliases", []), ensure_ascii=False),
|
|
|
|
|
|
"tenant_id": d.get("tenantId", "default"),
|
|
|
|
|
|
"knowledge_directories_json": json.dumps(d.get("knowledgeDirectories", []), ensure_ascii=False),
|
|
|
|
|
|
"evidence_ranking_json": json.dumps(d.get("evidenceRanking", []), ensure_ascii=False),
|
|
|
|
|
|
"company_intro": d.get("companyIntro", ""),
|
|
|
|
|
|
"company_highlights_json": json.dumps(d.get("companyHighlights", []), ensure_ascii=False),
|
|
|
|
|
|
})
|
2026-07-23 13:10:50 +08:00
|
|
|
|
count += 1
|
|
|
|
|
|
db.session.commit()
|
|
|
|
|
|
logger.info(f"[migrate_014] 导入 {count} 家公司")
|
|
|
|
|
|
|
|
|
|
|
|
# 产品
|
|
|
|
|
|
products_dir = os.path.join(CONFIG_DIR, "products")
|
|
|
|
|
|
count = 0
|
|
|
|
|
|
for d in _read_json_files_in_dir(products_dir):
|
2026-07-27 13:52:09 +08:00
|
|
|
|
if not d.get("id") or _record_exists(db, "insurance_ppt_products", "id", d["id"]):
|
2026-07-23 13:10:50 +08:00
|
|
|
|
continue
|
2026-07-27 13:52:09 +08:00
|
|
|
|
db.session.execute(text(
|
|
|
|
|
|
"INSERT INTO insurance_ppt_products "
|
|
|
|
|
|
"(id, company_id, plan_type, display_name, aliases_json, required_modules_json) "
|
|
|
|
|
|
"VALUES (:id, :company_id, :plan_type, :display_name, :aliases_json, :required_modules_json)"
|
|
|
|
|
|
), {
|
|
|
|
|
|
"id": d["id"],
|
|
|
|
|
|
"company_id": d.get("companyId", ""),
|
|
|
|
|
|
"plan_type": d.get("planType", "savings"),
|
|
|
|
|
|
"display_name": d.get("displayName", ""),
|
|
|
|
|
|
"aliases_json": json.dumps(d.get("aliases", []), ensure_ascii=False),
|
|
|
|
|
|
"required_modules_json": json.dumps(d.get("requiredModules", []), ensure_ascii=False),
|
|
|
|
|
|
})
|
2026-07-23 13:10:50 +08:00
|
|
|
|
count += 1
|
|
|
|
|
|
db.session.commit()
|
|
|
|
|
|
logger.info(f"[migrate_014] 导入 {count} 个产品")
|
|
|
|
|
|
|
2026-07-27 13:52:09 +08:00
|
|
|
|
# 模板(只使用 migrate_014 时已存在的列)
|
2026-07-23 13:10:50 +08:00
|
|
|
|
templates_dir = os.path.join(CONFIG_DIR, "templates")
|
|
|
|
|
|
count = 0
|
|
|
|
|
|
for d in _read_json_files_in_dir(templates_dir):
|
2026-07-27 13:52:09 +08:00
|
|
|
|
if not d.get("id") or _record_exists(db, "insurance_ppt_templates", "id", d["id"]):
|
2026-07-23 13:10:50 +08:00
|
|
|
|
continue
|
2026-07-27 13:52:09 +08:00
|
|
|
|
db.session.execute(text(
|
|
|
|
|
|
"INSERT INTO insurance_ppt_templates "
|
|
|
|
|
|
"(id, plan_type, style_preset, source_template_asset_id, clone_ready, "
|
|
|
|
|
|
"clone_renderer, required_page_types_json) "
|
|
|
|
|
|
"VALUES (:id, :plan_type, :style_preset, :source_template_asset_id, :clone_ready, "
|
|
|
|
|
|
":clone_renderer, :required_page_types_json)"
|
|
|
|
|
|
), {
|
|
|
|
|
|
"id": d["id"],
|
|
|
|
|
|
"plan_type": d.get("planType", "savings"),
|
|
|
|
|
|
"style_preset": d.get("stylePreset", "broker"),
|
|
|
|
|
|
"source_template_asset_id": d.get("sourceTemplateAssetId"),
|
|
|
|
|
|
"clone_ready": d.get("cloneReady", False),
|
|
|
|
|
|
"clone_renderer": d.get("cloneRenderer"),
|
|
|
|
|
|
"required_page_types_json": json.dumps(d.get("requiredPageTypes", []), ensure_ascii=False),
|
|
|
|
|
|
})
|
2026-07-23 13:10:50 +08:00
|
|
|
|
count += 1
|
|
|
|
|
|
db.session.commit()
|
|
|
|
|
|
logger.info(f"[migrate_014] 导入 {count} 个模板")
|
|
|
|
|
|
|
|
|
|
|
|
# Bundle
|
|
|
|
|
|
bundles_dir = os.path.join(CONFIG_DIR, "bundles")
|
|
|
|
|
|
count = 0
|
|
|
|
|
|
for d in _read_json_files_in_dir(bundles_dir):
|
2026-07-27 13:52:09 +08:00
|
|
|
|
if not d.get("id") or _record_exists(db, "insurance_ppt_bundles", "id", d["id"]):
|
2026-07-23 13:10:50 +08:00
|
|
|
|
continue
|
2026-07-27 13:52:09 +08:00
|
|
|
|
db.session.execute(text(
|
|
|
|
|
|
"INSERT INTO insurance_ppt_bundles "
|
|
|
|
|
|
"(id, display_name, products_json, template_family, status, modules_json) "
|
|
|
|
|
|
"VALUES (:id, :display_name, :products_json, :template_family, :status, :modules_json)"
|
|
|
|
|
|
), {
|
|
|
|
|
|
"id": d["id"],
|
|
|
|
|
|
"display_name": d.get("displayName", ""),
|
|
|
|
|
|
"products_json": json.dumps(d.get("products", []), ensure_ascii=False),
|
|
|
|
|
|
"template_family": d.get("templateFamily", "bundle"),
|
|
|
|
|
|
"status": d.get("status", "active"),
|
|
|
|
|
|
"modules_json": json.dumps(d.get("modules", []), ensure_ascii=False),
|
|
|
|
|
|
})
|
2026-07-23 13:10:50 +08:00
|
|
|
|
count += 1
|
|
|
|
|
|
db.session.commit()
|
|
|
|
|
|
logger.info(f"[migrate_014] 导入 {count} 个 Bundle")
|