"""迁移 014: 导入 PPT 配置数据。 使用原始 SQL 而非 ORM,避免模型字段与实际表结构不一致的问题。 (ORM 模型包含 migrate_017 才创建的 slides_config_json 字段) """ import os import json import logging from sqlalchemy import text 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 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 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): if not d.get("id") or _record_exists(db, "insurance_ppt_companies", "id", d["id"]): continue 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), }) 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): if not d.get("id") or _record_exists(db, "insurance_ppt_products", "id", d["id"]): continue 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), }) count += 1 db.session.commit() logger.info(f"[migrate_014] 导入 {count} 个产品") # 模板(只使用 migrate_014 时已存在的列) templates_dir = os.path.join(CONFIG_DIR, "templates") count = 0 for d in _read_json_files_in_dir(templates_dir): if not d.get("id") or _record_exists(db, "insurance_ppt_templates", "id", d["id"]): continue 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), }) 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): if not d.get("id") or _record_exists(db, "insurance_ppt_bundles", "id", d["id"]): continue 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), }) count += 1 db.session.commit() logger.info(f"[migrate_014] 导入 {count} 个 Bundle")