c9578f5ba2
轮播 feed(marquee_seed,全新): - 新增 marquee_seed 表 + admin CRUD/批量生成/预览;真实比价记录(success 且 0<省额≤300元、按 user 去重)优先,种子兜底混播 - 种子为「生成规则」:用户名可空(空则按脱敏格式随机合成、避开同屏撞名),金额改 [min,max] 区间随机,feed 公平随机抽取(不看 sort_order) - 新增 GET /api/v1/platform/savings-feed(无鉴权);展示时间统一刷新为相对当前的最近时刻 三统计配置(platform_stat_display)增强: - 自增长新增「绝对增量」方式(random_kind=add,每周期 +[step_min,step_max]) - 真实值模式加基数偏移(real_offset,展示=真实+偏移) - 只增不减护栏(allow_decrease 默认关,real/manual 不回退防门面缩水) - 累计节省 real 口径只计 0<单条≤300元防虚高;倍率上限 5.0→1.5;PATCH 支持 apply_now 立即更新 迁移:marquee_seed_table / marquee_seed_range / platform_stat_growth_offset(均可逆,已验证) 文档:API/DB 对应文档同步更新 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
75 lines
2.6 KiB
Python
75 lines
2.6 KiB
Python
"""admin 首页三统计展示配置:列出三指标配置(+ 真实值预览)+ 改某指标(带审计 + 校验)。
|
|
|
|
每指标可独立选 real/manual/random。计算逻辑见 app/repositories/platform_stat.py。
|
|
权限:operator 可改(运营调门面数字),super 恒可。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from typing import Annotated
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Request
|
|
|
|
from app.admin.audit import write_audit
|
|
from app.admin.deps import AdminDb, get_client_ip, get_current_admin, require_role
|
|
from app.admin.schemas.dashboard_display import (
|
|
PlatformStatItemOut,
|
|
PlatformStatUpdateRequest,
|
|
)
|
|
from app.models.admin import AdminUser
|
|
from app.repositories import platform_stat
|
|
|
|
router = APIRouter(
|
|
prefix="/admin/api/dashboard-display",
|
|
tags=["admin-dashboard-display"],
|
|
dependencies=[Depends(get_current_admin)],
|
|
)
|
|
|
|
|
|
@router.get("", response_model=list[PlatformStatItemOut], summary="首页三统计配置 + 真实值预览")
|
|
def list_display(db: AdminDb) -> list[PlatformStatItemOut]:
|
|
return [PlatformStatItemOut(**item) for item in platform_stat.get_config(db)]
|
|
|
|
|
|
@router.patch(
|
|
"/{metric}", response_model=PlatformStatItemOut, summary="改某指标展示配置(带审计)"
|
|
)
|
|
def update_display(
|
|
metric: str,
|
|
body: PlatformStatUpdateRequest,
|
|
request: Request,
|
|
admin: Annotated[AdminUser, Depends(require_role("operator"))],
|
|
db: AdminDb,
|
|
) -> PlatformStatItemOut:
|
|
try:
|
|
before, after = platform_stat.update_config(
|
|
db,
|
|
metric,
|
|
mode=body.mode,
|
|
manual_value=body.manual_value,
|
|
random_mult_min=body.random_mult_min,
|
|
random_mult_max=body.random_mult_max,
|
|
random_tick_seconds=body.random_tick_seconds,
|
|
random_anchor_minutes=body.random_anchor_minutes,
|
|
random_kind=body.random_kind,
|
|
random_step_min=body.random_step_min,
|
|
random_step_max=body.random_step_max,
|
|
real_offset=body.real_offset,
|
|
allow_decrease=body.allow_decrease,
|
|
random_initial=body.random_initial,
|
|
apply_now=body.apply_now,
|
|
admin_id=admin.id,
|
|
commit=False,
|
|
)
|
|
except ValueError as e:
|
|
raise HTTPException(status_code=400, detail=str(e)) from e
|
|
|
|
write_audit(
|
|
db, admin, action="dashboard_display.set", target_type="platform_stat",
|
|
target_id=metric, detail={"before": before, "after": after},
|
|
ip=get_client_ip(request), commit=False,
|
|
)
|
|
db.commit()
|
|
|
|
item = next(it for it in platform_stat.get_config(db) if it["metric"] == metric)
|
|
return PlatformStatItemOut(**item)
|