会员积分改版V1

This commit is contained in:
2026-08-11 09:24:18 +08:00
parent fe24e51b97
commit b9fd07f293
111 changed files with 9355 additions and 3900 deletions
@@ -0,0 +1,89 @@
from __future__ import annotations
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.dependencies import get_admin_user, get_db
from app.enums.llm_billing import LLM_BILLING_SCENE_LABELS
from app.models.llm_billing.policy import LlmBillingPolicyModel
from app.models.user import User
from app.schemas.llm_billing import LlmBillingPolicyCreate, LlmBillingPolicyUpdate
from app.services.llm_billing.query_service import list_executions_with_calls
from app.services.operation_log_service import log_operation_event
from app.utils.id_gen import generate_id
router = APIRouter(prefix="/admin/llm-billing", tags=["admin-llm-billing"])
@router.get("/policies")
async def list_policies(
admin: User = Depends(get_admin_user),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(select(LlmBillingPolicyModel).order_by(LlmBillingPolicyModel.scene_code))
return list(result.scalars().all())
@router.post("/policies")
async def create_policy(
data: LlmBillingPolicyCreate,
admin: User = Depends(get_admin_user),
db: AsyncSession = Depends(get_db),
):
if data.scene_code not in LLM_BILLING_SCENE_LABELS:
raise HTTPException(status_code=400, detail="不支持的LLM业务场景")
existing = await db.execute(select(LlmBillingPolicyModel.id).where(LlmBillingPolicyModel.scene_code == data.scene_code).limit(1))
if existing.scalar_one_or_none():
raise HTTPException(status_code=409, detail="该LLM业务场景已存在")
policy = LlmBillingPolicyModel(
id=generate_id(),
scene_code=data.scene_code,
scene_name=LLM_BILLING_SCENE_LABELS[data.scene_code],
pre_deduct_credits=data.pre_deduct_credits,
is_active=data.is_active,
version=1,
created_by=admin.id,
updated_by=admin.id,
)
db.add(policy)
await db.flush()
log_operation_event(domain="llm_billing", module="admin", event_type="LLM_BILLING_POLICY_CREATED", user_id=admin.id, detail={"scene_code": policy.scene_code, "credits": float(policy.pre_deduct_credits)})
return policy
@router.put("/policies/{policy_id}")
async def update_policy(
policy_id: str,
data: LlmBillingPolicyUpdate,
admin: User = Depends(get_admin_user),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(select(LlmBillingPolicyModel).where(LlmBillingPolicyModel.id == policy_id).limit(1).with_for_update())
policy = result.scalar_one_or_none()
if not policy:
raise HTTPException(status_code=404, detail="LLM计费场景不存在")
payload = data.model_dump(exclude_unset=True)
payload.pop("scene_name", None)
for key, value in payload.items():
setattr(policy, key, value)
policy.scene_name = LLM_BILLING_SCENE_LABELS.get(policy.scene_code, policy.scene_name)
policy.version += 1
policy.updated_by = admin.id
await db.flush()
log_operation_event(domain="llm_billing", module="admin", event_type="LLM_BILLING_POLICY_UPDATED", user_id=admin.id, detail={"scene_code": policy.scene_code, "version": policy.version})
return policy
@router.get("/executions")
async def list_executions(
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
scene_code: str | None = Query(default=None),
status: str | None = Query(default=None),
user_id: str | None = Query(default=None),
admin: User = Depends(get_admin_user),
db: AsyncSession = Depends(get_db),
):
items, total = await list_executions_with_calls(db, page=page, page_size=page_size, scene_code=scene_code, status=status, user_id=user_id)
return {"items": items, "total": total}