27f76918b2
本 PR 汇合三块运营后台改动(原 #50 仅含其中「加固」一块,已并入本 PR 并关闭)。 ## 1. review 加固 (436b2a3) - 超管防自锁:降级/禁用最后一个 active super_admin 前校验,杜绝零超管死局 - 时间筛选统一 tz-aware(列为 timestamptz),比较绝对时刻、不依赖 DB 会话时区 - 上报审核 / 调余额(set·扣减)加行锁,防并发/连点重复发钱 - ad_audit 复算排序补 id 次级键;health-check 限 finance;调账/拒绝 reason 去空白校验 ## 2. 反馈改版 (5a18dbb) - contact 可选、截图≤6;admin 反馈列表筛选/排序;admin·wallet 接口调整 + docs ## 3. 列表页码分页 (1a7a624) - CursorPage 加 total;新增 offset_paginate(count 与分页同源) - 上报/审计日志从 id 游标改 offset 分页(支持跳页) - 用户 / 提现 / 上报 / 审计日志 四页接入页码分页 测试:admin 套件 47 passed。前端配套改动见 shaguabijia-admin-web。 --------- Co-authored-by: OuYingJun1024 <1034284404@qq.com> Reviewed-on: #51 Co-authored-by: ouzhou <ouzhou@wonderable.ai> Co-committed-by: ouzhou <ouzhou@wonderable.ai>
55 lines
1.6 KiB
Python
55 lines
1.6 KiB
Python
"""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
|
|
|
|
|
|
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
|