"""admin 用户管理 schemas。""" from __future__ import annotations from datetime import datetime from typing import Literal from pydantic import BaseModel, ConfigDict, Field, field_validator class AdminUserListItem(BaseModel): model_config = ConfigDict(from_attributes=True) id: int phone: str nickname: str | None = None register_channel: str status: str debug_trace_enabled: bool = False wechat_openid: str | None = None created_at: datetime last_login_at: datetime class AdminUserOverview(BaseModel): """用户 360 概览:基础资料 + 钱包余额 + 各项 count(历史明细走各自分页接口)。""" model_config = ConfigDict(from_attributes=True) user: AdminUserListItem coin_balance: int cash_balance_cents: int total_coin_earned: int comparison_total: int comparison_success: int withdraw_total: int withdraw_success_cents: int feedback_total: int def _strip_reason(v: str) -> str: # min_length=1 放过纯空白(" "),trim 后再校验非空,避免审计记到空原因 if not v.strip(): raise ValueError("操作原因不能为空") return v.strip() class GrantCoinsRequest(BaseModel): mode: Literal["delta", "set"] = Field( "delta", description="delta=增减(amount 为变动量) / set=设为(amount 为目标值,须≥0)" ) amount: int = Field( ..., description="delta 模式:金币变动(正=增加,负=扣减,不可为 0);set 模式:目标金币值(须≥0)", ) reason: str = Field(..., min_length=1, max_length=128, description="操作原因(必填,入审计)") _v_reason = field_validator("reason")(_strip_reason) class GrantCashRequest(BaseModel): mode: Literal["delta", "set"] = Field( "delta", description="delta=增减(amount_cents 为变动量) / set=设为(amount_cents 为目标值,须≥0)" ) amount_cents: int = Field( ..., description="delta 模式:现金变动(分,正=增加,负=扣减,不可为 0);set 模式:目标现金值(分,须≥0)", ) reason: str = Field(..., min_length=1, max_length=128, description="操作原因(必填,入审计)") _v_reason = field_validator("reason")(_strip_reason) class SetUserStatusRequest(BaseModel): status: Literal["active", "disabled"] = Field( ..., description="active=解封 / disabled=封禁(注销 deleted 不走此接口)" ) class SetDebugTraceRequest(BaseModel): enabled: bool = Field(..., description="是否给该用户开「复制调试链接」权限")