baodan/api/insurance/models/ppt_config.py

225 lines
12 KiB
Python
Raw Normal View History

2026-07-23 13:10:50 +08:00
"""PPT 配置模型(公司、产品、模板)。"""
import uuid
2026-07-23 15:04:16 +08:00
from sqlalchemy import Column, String, Text, Boolean, Integer, SmallInteger, TIMESTAMP, func
2026-07-23 13:10:50 +08:00
from insurance.db.compat import db
class PptCompany(db.Model):
"""保险公司配置表。"""
__tablename__ = "insurance_ppt_companies"
id = Column(String(50), primary_key=True, comment="公司 ID如 aia/ctf/fwd")
display_name = Column(String(100), nullable=False, comment="显示名称")
aliases_json = Column(Text, nullable=True, comment="别名列表 JSON")
tenant_id = Column(String(50), default="default", comment="租户 ID")
knowledge_directories_json = Column(Text, nullable=True, comment="知识库目录 JSON")
evidence_ranking_json = Column(Text, nullable=True, comment="证据排序关键词 JSON")
company_intro = Column(Text, nullable=True, comment="公司简介")
company_highlights_json = Column(Text, nullable=True, comment="公司亮点 JSON")
2026-07-28 16:45:14 +08:00
# 脱敏展示名PPT/海报导出时替代真实名称)
masked_display_name = Column(String(100), nullable=True, comment="脱敏展示名")
2026-07-23 13:10:50 +08:00
# 品牌信息
name_zh = Column(String(100), nullable=True, comment="中文名称")
name_en = Column(String(100), nullable=True, comment="英文名称")
short_en = Column(String(20), nullable=True, comment="英文缩写")
rating = Column(String(50), nullable=True, comment="评级")
founded_year = Column(Integer, nullable=True, comment="成立年份")
2026-07-23 15:04:16 +08:00
# 扩展字段PPT/海报功能)
logo_url = Column(String(500), nullable=True, comment="公司 Logo 图片地址")
status = Column(SmallInteger, default=1, comment="1=启用, 0=停用")
sort_order = Column(Integer, default=0, comment="排序权重")
2026-07-23 13:10:50 +08:00
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,
"displayName": self.display_name,
2026-07-28 16:45:14 +08:00
"maskedDisplayName": self.masked_display_name or "",
2026-07-23 13:10:50 +08:00
"aliases": json.loads(self.aliases_json) if self.aliases_json else [],
"tenantId": self.tenant_id,
"knowledgeDirectories": json.loads(self.knowledge_directories_json) if self.knowledge_directories_json else [],
"evidenceRanking": json.loads(self.evidence_ranking_json) if self.evidence_ranking_json else [],
"companyIntro": self.company_intro,
"companyHighlights": json.loads(self.company_highlights_json) if self.company_highlights_json else [],
"rating": self.rating,
"foundedYear": self.founded_year,
2026-07-29 12:19:26 +08:00
"nameZh": self.name_zh,
"nameEn": self.name_en,
"shortEn": self.short_en,
2026-07-23 15:04:16 +08:00
"logoUrl": self.logo_url,
"status": self.status,
"sortOrder": self.sort_order,
2026-07-23 13:10:50 +08:00
}
class PptProduct(db.Model):
"""保险产品配置表。"""
__tablename__ = "insurance_ppt_products"
id = Column(String(50), primary_key=True, comment="产品 ID")
company_id = Column(String(50), nullable=False, comment="所属公司 ID")
plan_type = Column(String(10), nullable=False, comment="产品类型: savings/ci/iul")
display_name = Column(String(100), nullable=False, comment="显示名称")
aliases_json = Column(Text, nullable=True, comment="别名列表 JSON")
required_modules_json = Column(Text, nullable=True, comment="所需模块 JSON")
2026-07-28 16:45:14 +08:00
# 脱敏展示名PPT/海报导出时替代真实名称)
masked_display_name = Column(String(100), nullable=True, comment="脱敏展示名")
2026-07-23 15:04:16 +08:00
# 扩展字段
product_code = Column(String(50), nullable=True, comment="产品编码")
product_type = Column(String(20), nullable=True, comment="产品类型: savings/ci/iul")
coverage_period = Column(String(50), nullable=True, comment="保障期限")
payment_period = Column(String(50), nullable=True, comment="缴费期限")
insured_age_range = Column(String(50), nullable=True, comment="投保年龄范围")
waiting_period = Column(String(50), nullable=True, comment="等待期")
highlights = Column(Text, nullable=True, comment="产品亮点 JSON")
extra_fields = Column(Text, nullable=True, comment="扩展字段 JSON")
status = Column(SmallInteger, default=1, comment="1=启用, 0=停用")
sort_order = Column(Integer, default=0, comment="排序")
# 海报相关
manual_file_url = Column(String(500), nullable=True, comment="产品小册子 PDF 地址")
manual_parse_status = Column(String(20), default="none", comment="none/pending/queued/parsing/parsed/reviewed/failed")
manual_parse_message = Column(String(500), default="", comment="解析进度消息")
manual_parse_error = Column(Text, nullable=True, comment="解析失败原因")
manual_parse_task_id = Column(String(200), nullable=True, comment="Celery 任务ID")
manual_parse_started_at = Column(TIMESTAMP, nullable=True, comment="解析开始时间")
manual_parse_finished_at = Column(TIMESTAMP, nullable=True, comment="解析完成时间")
2026-07-23 15:04:16 +08:00
manual_parsed_rules = Column(Text, nullable=True, comment="解析出的产品规则 JSON")
manual_reviewed_by = Column(String(50), nullable=True, comment="核对人")
manual_reviewed_at = Column(TIMESTAMP, nullable=True, comment="核对时间")
2026-07-23 13:10:50 +08:00
created_at = Column(TIMESTAMP, server_default=func.now())
2026-07-23 15:04:16 +08:00
updated_at = Column(TIMESTAMP, server_default=func.now(), onupdate=func.now())
2026-07-23 13:10:50 +08:00
def to_dict(self):
import json
return {
"id": self.id,
"companyId": self.company_id,
"planType": self.plan_type,
"displayName": self.display_name,
2026-07-28 16:45:14 +08:00
"maskedDisplayName": self.masked_display_name or "",
2026-07-23 13:10:50 +08:00
"aliases": json.loads(self.aliases_json) if self.aliases_json else [],
"requiredModules": json.loads(self.required_modules_json) if self.required_modules_json else [],
2026-07-23 15:04:16 +08:00
"productCode": self.product_code,
"productType": self.product_type,
"coveragePeriod": self.coverage_period,
"paymentPeriod": self.payment_period,
"insuredAgeRange": self.insured_age_range,
"waitingPeriod": self.waiting_period,
"highlights": json.loads(self.highlights) if self.highlights else [],
"extraFields": json.loads(self.extra_fields) if self.extra_fields else {},
"status": self.status,
"sortOrder": self.sort_order,
"manualFileUrl": self.manual_file_url,
"manualParseStatus": self.manual_parse_status,
"manualParseMessage": self.manual_parse_message or "",
"manualParseError": self.manual_parse_error or "",
"manualParseTaskId": self.manual_parse_task_id,
"manualParseStartedAt": self.manual_parse_started_at.isoformat() if self.manual_parse_started_at else None,
"manualParseFinishedAt": self.manual_parse_finished_at.isoformat() if self.manual_parse_finished_at else None,
2026-07-23 15:04:16 +08:00
"manualParsedRules": json.loads(self.manual_parsed_rules) if self.manual_parsed_rules else None,
"manualReviewedBy": self.manual_reviewed_by,
"manualReviewedAt": self.manual_reviewed_at.isoformat() if self.manual_reviewed_at else None,
2026-07-23 13:10:50 +08:00
}
class PptTemplate(db.Model):
"""PPT 模板配置表。"""
__tablename__ = "insurance_ppt_templates"
id = Column(String(50), primary_key=True, comment="模板 ID")
plan_type = Column(String(10), nullable=False, comment="产品类型: savings/ci/iul")
style_preset = Column(String(20), nullable=False, comment="风格: broker/business/minimal/chinese/ink")
source_template_asset_id = Column(String(50), nullable=True, comment="源模板资产 ID")
clone_ready = Column(Boolean, default=False, comment="是否克隆就绪")
clone_renderer = Column(String(100), nullable=True, comment="克隆渲染器 ID")
required_page_types_json = Column(Text, nullable=True, comment="必需页面类型 JSON")
2026-07-23 15:04:16 +08:00
# 扩展字段
name = Column(String(100), nullable=True, comment="模板名称")
scenario_tag = Column(String(50), nullable=True, comment="场景标签")
preview_image = Column(String(500), nullable=True, comment="预览图地址")
applicable_company_ids = Column(Text, nullable=True, comment="适用保司 ID 列表 JSON")
applicable_product_ids = Column(Text, nullable=True, comment="适用产品 ID 列表 JSON")
slides_config_json = Column(Text, nullable=True, comment="逐页幻灯片配置 JSON")
2026-07-23 15:04:16 +08:00
status = Column(SmallInteger, default=1, comment="1=启用, 0=停用")
2026-07-23 13:10:50 +08:00
created_at = Column(TIMESTAMP, server_default=func.now())
def to_dict(self):
import json
slides = json.loads(self.slides_config_json) if self.slides_config_json else []
2026-07-23 13:10:50 +08:00
return {
"id": self.id,
"planType": self.plan_type,
"stylePreset": self.style_preset,
"sourceTemplateAssetId": self.source_template_asset_id,
"sourceFileUrl": (
f"/insurance/admin/ppt/templates/{self.id}/file"
if self.source_template_asset_id else ""
),
"isBuiltIn": str(self.source_template_asset_id or "").startswith("builtin://"),
2026-07-23 13:10:50 +08:00
"cloneReady": self.clone_ready,
"cloneRenderer": self.clone_renderer,
"requiredPageTypes": json.loads(self.required_page_types_json) if self.required_page_types_json else [],
2026-07-23 15:04:16 +08:00
"name": self.name,
"scenarioTag": self.scenario_tag,
"previewImage": self.preview_image,
"applicableCompanyIds": json.loads(self.applicable_company_ids) if self.applicable_company_ids else [],
"applicableProductIds": json.loads(self.applicable_product_ids) if self.applicable_product_ids else [],
"slidesConfig": slides,
"slideCount": len(slides),
2026-07-23 15:04:16 +08:00
"status": self.status,
2026-07-23 13:10:50 +08:00
}
class PptBundle(db.Model):
"""PPT Bundle 组合配置表。"""
__tablename__ = "insurance_ppt_bundles"
id = Column(String(50), primary_key=True, comment="Bundle ID")
display_name = Column(String(100), nullable=False, comment="显示名称")
products_json = Column(Text, nullable=False, comment="产品类型列表 JSON")
template_family = Column(String(50), default="bundle", comment="模板族")
status = Column(String(20), default="active", comment="状态: active/inactive")
modules_json = Column(Text, nullable=True, comment="模块列表 JSON")
created_at = Column(TIMESTAMP, server_default=func.now())
def to_dict(self):
import json
return {
"id": self.id,
"displayName": self.display_name,
"products": json.loads(self.products_json) if self.products_json else [],
"templateFamily": self.template_family,
"status": self.status,
"modules": json.loads(self.modules_json) if self.modules_json else [],
}
class CompanyLogo(db.Model):
"""保司Logo图片表支持多张"""
__tablename__ = "insurance_ppt_company_logos"
id = Column(String(36), primary_key=True, default=lambda: uuid.uuid4().hex)
company_id = Column(String(50), nullable=False, index=True, comment="所属公司 ID")
file_path = Column(String(500), nullable=False, comment="服务器文件路径")
file_url = Column(String(500), nullable=True, comment="可访问的URL")
original_name = Column(String(200), nullable=True, comment="原始文件名")
mime_type = Column(String(50), nullable=True, comment="MIME类型")
file_size = Column(Integer, nullable=True, comment="文件大小(字节)")
is_primary = Column(Boolean, default=False, comment="是否为主Logo")
sort_order = Column(Integer, default=0, comment="排序权重")
created_at = Column(TIMESTAMP, server_default=func.now())
def to_dict(self):
return {
"id": self.id,
"companyId": self.company_id,
"url": self.file_url or f"/insurance/admin/ppt/assets/company-logos/{self.id}",
"originalName": self.original_name or "",
"mimeType": self.mime_type,
"fileSize": self.file_size,
"isPrimary": self.is_primary,
"sortOrder": self.sort_order,
}