"""admin 上报更低价审核 schemas。""" from __future__ import annotations from datetime import datetime from pydantic import BaseModel, ConfigDict, Field, field_validator class PriceReportOut(BaseModel): """admin 列表项:price_report 全字段(审核要看的快照 + 截图 + 状态 + 奖励)。""" model_config = ConfigDict(from_attributes=True) id: int user_id: int comparison_record_id: int | None = None # 选中比价记录的快照 store_name: str | None = None dish_summary: str | None = None original_platform_id: str | None = None original_platform_name: str | None = None original_price_cents: int | None = None # 用户上报的更低价 reported_platform_id: str reported_platform_name: str reported_price_cents: int images: list[str] = [] # 审核 status: str reject_reason: str | None = None reward_coins: int | None = None reviewed_at: datetime | None = None created_at: datetime # 联表瞬态字段:phone/nickname 由 _attach_user_info 挂(展示完整手机号、点击查该用户全部上报); # 其余由 _attach_price_report_comparison 从关联比价记录挂:trace_*(Trace 列点跳调试链接)、 # device_model/rom_name/android_version(机型OS版本列)、app_version(提交版本号列) phone: str | None = None nickname: str | None = None trace_id: str | None = None trace_url: str | None = None device_model: str | None = None rom_name: str | None = None android_version: str | None = None app_version: str | None = None class PriceReportRejectRequest(BaseModel): reason: str = Field(min_length=1, max_length=256, description="拒绝理由,用户端记录页会看到") @field_validator("reason") @classmethod def _reason_not_blank(cls, v: str) -> str: # min_length=1 放过纯空白(" "),trim 后再校验非空,避免审计/用户端记录到空理由 if not v.strip(): raise ValueError("拒绝理由不能为空") return v.strip() class PriceReportSummary(BaseModel): """审核台顶部各状态计数。""" pending: int approved: int rejected: int total: int