"""方案分类模型。""" from __future__ import annotations from sqlalchemy import ( BigInteger, Boolean, CheckConstraint, Computed, ForeignKey, Index, Integer, String, UniqueConstraint, text, ) from sqlalchemy.orm import Mapped, mapped_column from dms.database.base import BusinessTableMixin from dms.extensions import db class Category(BusinessTableMixin, db.Model): __tablename__ = "doc_category" __table_args__ = ( UniqueConstraint( "category_code", "active_marker", name="uq_doc_category_category_code_active", ), CheckConstraint( "category_type IN ('SCENE', 'STYLE', 'SITUATION', 'VERSION', 'OTHER')", name="category_type", ), CheckConstraint( "status IN ('ENABLED', 'DISABLED')", name="category_status", ), Index( "ix_doc_category_parent_active_sort", "parent_id", "is_deleted", "sort_no", ), Index( "ix_doc_category_status_active", "status", "is_deleted", ), Index( "ix_doc_category_type_active", "category_type", "is_deleted", ), ) parent_id: Mapped[int | None] = mapped_column( BigInteger, ForeignKey("doc_category.id", ondelete="RESTRICT"), nullable=True, ) category_code: Mapped[str] = mapped_column( String(64), nullable=False, ) category_name: Mapped[str] = mapped_column(String(128), nullable=False) category_type: Mapped[str] = mapped_column( String(32), nullable=False, server_default=text("'OTHER'"), ) category_path: Mapped[str] = mapped_column(String(1000), nullable=False) sort_no: Mapped[int] = mapped_column( Integer, nullable=False, server_default=text("0"), ) document_count: Mapped[int] = mapped_column( Integer, nullable=False, server_default=text("0"), ) status: Mapped[str] = mapped_column( String(20), nullable=False, server_default=text("'ENABLED'"), ) # 扁平模式:仅一级分类(parent_id IS NULL)有意义。 # true 表示挂在该分类(含子分类)下的主案在前端不展示 # "挂载子方案"与"挂载配套资料"入口;后端挂载接口不强制拒绝(弱约束)。 flat_mode: Mapped[bool] = mapped_column( Boolean, nullable=False, server_default=text("0"), ) # 类型显示名称:仅一级分类(parent_id IS NULL)有意义。 # 检索结果列表中,该分类(含子分类)下主体方案的类型徽标 # 显示该名称;NULL 表示未设置,回退显示分类名称。 type_display_name: Mapped[str | None] = mapped_column( String(128), nullable=True, ) active_marker: Mapped[int | None] = mapped_column( Integer, Computed("IF(is_deleted = 0, 1, NULL)", persisted=False), nullable=True, )