"""站内通知模型(追加型,类似审计日志,不用业务表 mixin)。""" from __future__ import annotations from datetime import datetime, timezone from sqlalchemy import BigInteger, CheckConstraint, Index, String, text from sqlalchemy.dialects.mysql import DATETIME from sqlalchemy.orm import Mapped, mapped_column from dms.extensions import db class Notification(db.Model): """用户站内通知:审批流等待处理等需用户关注的信息。 通知只追加与状态流转(未读→已读、待处理→已同意/已拒绝), 不做软删与乐观锁,故不使用 BusinessTableMixin。 """ __tablename__ = "sys_notification" __table_args__ = ( CheckConstraint( "notify_type IN ('APPROVAL')", name="notification_notify_type", ), CheckConstraint( "action IN ('NONE', 'PENDING', 'AGREE', 'REJECT')", name="notification_action", ), CheckConstraint( "status IN ('UNREAD', 'READ')", name="notification_status", ), Index("ix_sys_notification_user_id", "user_id", "id"), ) id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) user_id: Mapped[int] = mapped_column(BigInteger, nullable=False) title: Mapped[str] = mapped_column(String(200), nullable=False) content: Mapped[str | None] = mapped_column(String(1000), nullable=True) # 通知类别:APPROVAL 审批待办(后续审批流写入,预留扩展) notify_type: Mapped[str] = mapped_column(String(32), nullable=False) # 待办操作:NONE 无需操作 / PENDING 待处理 / AGREE 已同意 / REJECT 已拒绝 action: Mapped[str] = mapped_column(String(16), nullable=False) status: Mapped[str] = mapped_column(String(16), nullable=False) created_at: Mapped[datetime] = mapped_column( DATETIME(fsp=3), nullable=False, # 应用侧 UTC 落库(与 sys_audit_log 同口径,序列化追加 Z) default=lambda: datetime.now(timezone.utc).replace(tzinfo=None), server_default=text("CURRENT_TIMESTAMP(3)"), ) handled_at: Mapped[datetime | None] = mapped_column(DATETIME(fsp=3), nullable=True)