"""飞书分流队列项模型""" from __future__ import annotations from datetime import datetime from typing import Optional from sqlalchemy import ( BigInteger, Boolean, Float, ForeignKey, Index, Integer, TEXT, TIMESTAMP, VARCHAR, text, ) from sqlalchemy.orm import Mapped, mapped_column from .base import Base from .types import JSONB class FeishuItem(Base): __tablename__ = "feishu_items" __table_args__ = ( Index( "uq_feishu_items_tenant_message_root", "tenant_id", "feishu_message_id", unique=True, postgresql_where=text("split_from_item_id IS NULL AND feishu_message_id IS NOT NULL"), ), Index( "uq_feishu_items_tenant_message_split", "tenant_id", "feishu_message_id", "split_from_item_id", unique=True, postgresql_where=text("split_from_item_id IS NOT NULL AND feishu_message_id IS NOT NULL"), ), ) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) feishu_message_id: Mapped[Optional[str]] = mapped_column(VARCHAR(128), nullable=True, index=True) project_score: Mapped[Optional[float]] = mapped_column(Float, nullable=True) signal_confidence: Mapped[Optional[float]] = mapped_column(Float, nullable=True) raw_message: Mapped[str] = mapped_column(TEXT, nullable=False) split_from_item_id: Mapped[Optional[int]] = mapped_column( BigInteger, ForeignKey("feishu_items.id"), nullable=True, index=True ) level: Mapped[str] = mapped_column(VARCHAR(20), nullable=False, index=True) level_confidence: Mapped[Optional[float]] = mapped_column(Float, nullable=True) level_reasoning: Mapped[Optional[str]] = mapped_column(TEXT, nullable=True) card_type: Mapped[str] = mapped_column(VARCHAR(30), nullable=False, default="signal", index=True) route_status: Mapped[str] = mapped_column(VARCHAR(30), nullable=False, default="pending", index=True) matched_project_id: Mapped[Optional[int]] = mapped_column(BigInteger, nullable=True, index=True) source_chat_id: Mapped[Optional[str]] = mapped_column(VARCHAR(128), nullable=True) source_sender: Mapped[Optional[str]] = mapped_column(VARCHAR(120), nullable=True) source_sender_open_id: Mapped[Optional[str]] = mapped_column(VARCHAR(128), nullable=True) source_occurred_at: Mapped[Optional[datetime]] = mapped_column(TIMESTAMP, nullable=True) ai_output: Mapped[Optional[str]] = mapped_column(TEXT, nullable=True) decision_reason: Mapped[Optional[str]] = mapped_column(TEXT, nullable=True) blocking_reason: Mapped[Optional[str]] = mapped_column(TEXT, nullable=True) safe_to_auto_execute: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, index=True) auto_execute_state: Mapped[Optional[str]] = mapped_column(VARCHAR(30), nullable=True, index=True) dedupe_key: Mapped[Optional[str]] = mapped_column(VARCHAR(255), nullable=True, index=True) message_class: Mapped[Optional[str]] = mapped_column(VARCHAR(30), nullable=True, index=True) occurrence_count: Mapped[int] = mapped_column(Integer, nullable=False, default=1) next_step_text: Mapped[Optional[str]] = mapped_column(TEXT, nullable=True) undoable_until: Mapped[Optional[datetime]] = mapped_column(TIMESTAMP, nullable=True) result_payload: Mapped[Optional[dict]] = mapped_column(JSONB, nullable=True) queue_visible: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True, index=True) processed_at: Mapped[Optional[datetime]] = mapped_column(TIMESTAMP, nullable=True) dismissed_reason: Mapped[Optional[str]] = mapped_column(TEXT, nullable=True)