Files
congsh 5c028d7952 Initial commit: snapAna 截图智能整理工具
包含 FastAPI 后端、React 前端、队列/OCR/标签/待办等完整功能。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 15:45:50 +08:00

87 lines
2.6 KiB
Python

"""截图主表与处理状态。"""
from __future__ import annotations
from datetime import datetime
from enum import Enum
from sqlalchemy import (
BigInteger,
DateTime,
ForeignKey,
Index,
Integer,
String,
UniqueConstraint,
func,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.core.db import Base
class ProcessStatus(str, Enum):
"""处理流水线的状态枚举。"""
PENDING = "pending"
RUNNING = "running"
DONE = "done"
FAILED = "failed"
SKIPPED = "skipped"
class Screenshot(Base):
"""截图文件主记录。"""
__tablename__ = "screenshots"
__table_args__ = (
UniqueConstraint("file_hash", name="uq_screenshots_file_hash"),
Index("ix_screenshots_captured_at", "captured_at"),
Index("ix_screenshots_ai_status", "ai_status"),
Index("ix_screenshots_category_id", "category_id"),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
path: Mapped[str] = mapped_column(String(1024), nullable=False)
file_hash: Mapped[str] = mapped_column(String(64), nullable=False)
width: Mapped[int] = mapped_column(Integer, default=0)
height: Mapped[int] = mapped_column(Integer, default=0)
size: Mapped[int] = mapped_column(BigInteger, default=0)
captured_at: Mapped[datetime] = mapped_column(DateTime, nullable=False)
imported_at: Mapped[datetime] = mapped_column(
DateTime, server_default=func.now(), nullable=False
)
thumb_path: Mapped[str | None] = mapped_column(String(1024), nullable=True)
ocr_status: Mapped[str] = mapped_column(String(16), default=ProcessStatus.PENDING.value)
ai_status: Mapped[str] = mapped_column(String(16), default=ProcessStatus.PENDING.value)
# AI 写回的分类:外键 + SET NULL,删除分类时自动把引用置空
category_id: Mapped[int | None] = mapped_column(
Integer,
ForeignKey("categories.id", ondelete="SET NULL"),
nullable=True,
)
is_favorite: Mapped[int] = mapped_column(Integer, default=0) # 0/1,便于 SQLite 索引
is_hidden: Mapped[int] = mapped_column(Integer, default=0)
meta = relationship(
"ScreenshotMeta",
back_populates="screenshot",
uselist=False,
cascade="all, delete-orphan",
)
tags = relationship(
"Tag",
secondary="screenshot_tags",
back_populates="screenshots",
lazy="selectin",
)
todos = relationship(
"Todo",
back_populates="screenshot",
cascade="all, delete-orphan",
)