"""用户反馈表(帮助与反馈)。 每条 = 用户一次提交。content 必填;contact 原为必填(微信/QQ/手机),原型改版后客户端不再采集, 新数据存空串(列保持 NOT NULL,免迁移;历史数据仍有值);images 为可选的截图 URL 列表 (/media/feedback/...,JSON 存)。status: pending(审核中)/adopted(已采纳)/rejected(未采纳)。 """ from __future__ import annotations from datetime import datetime from sqlalchemy import JSON, DateTime, ForeignKey, Integer, String, Text, func from sqlalchemy.orm import Mapped, mapped_column from app.db.base import Base class Feedback(Base): __tablename__ = "feedback" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) user_id: Mapped[int] = mapped_column( Integer, ForeignKey("user.id"), index=True, nullable=False ) content: Mapped[str] = mapped_column(Text, nullable=False) contact: Mapped[str] = mapped_column(String(128), nullable=False) # 截图 URL 列表(相对路径,如 ["/media/feedback/u1_ab12.jpg"]);无图为 None images: Mapped[list[str] | None] = mapped_column(JSON, nullable=True) # pending(审核中) / adopted(已采纳) / rejected(未采纳) status: Mapped[str] = mapped_column(String(16), nullable=False, default="pending", index=True) reject_reason: Mapped[str | None] = mapped_column(String(256), nullable=True) reward_coins: Mapped[int | None] = mapped_column(Integer, nullable=True) # 审核批注:采纳时可写采纳要点,未采纳时也可保留运营侧备注 review_note: Mapped[str | None] = mapped_column(String(256), nullable=True) reviewed_by_admin_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("admin_user.id"), nullable=True ) reviewed_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), index=True, nullable=False ) def __repr__(self) -> str: # pragma: no cover return f""