e1bd0e3ef7
改了什么:新增新版大盘日期窗口聚合、广告收益拆分、比价耗时字段、美团 CPS 拉单入库与大盘展示,并同步反馈审核和邀请奖励下线口径。 验证:python -m pytest tests/test_admin_read.py tests/test_admin_write.py tests/test_compare_record.py tests/test_invite.py tests/test_feedback.py -q。
149 lines
4.7 KiB
Python
149 lines
4.7 KiB
Python
"""admin 反馈工单:列表(读)+ 采纳发金币 / 拒绝写原因(写,带审计)。"""
|
|
from __future__ import annotations
|
|
|
|
from typing import Annotated
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query, 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.repositories import mutations, queries
|
|
from app.admin.schemas.common import CursorPage, OkResponse
|
|
from app.admin.schemas.feedback import FeedbackApproveRequest, FeedbackOut, FeedbackRejectRequest
|
|
from app.models.admin import AdminUser
|
|
from app.models.feedback import Feedback
|
|
from app.repositories import wallet as wallet_repo
|
|
|
|
router = APIRouter(
|
|
prefix="/admin/api/feedbacks",
|
|
tags=["admin-feedback"],
|
|
dependencies=[Depends(get_current_admin)],
|
|
)
|
|
|
|
|
|
@router.get("", response_model=CursorPage[FeedbackOut], summary="反馈工单列表")
|
|
def list_feedbacks(
|
|
db: AdminDb,
|
|
status: Annotated[str | None, Query()] = None,
|
|
user_id: Annotated[int | None, Query()] = None,
|
|
limit: Annotated[int, Query(ge=1, le=100)] = 20,
|
|
cursor: Annotated[int | None, Query()] = None,
|
|
) -> CursorPage[FeedbackOut]:
|
|
items, next_cursor = queries.list_feedbacks(
|
|
db, status=status, user_id=user_id, limit=limit, cursor=cursor,
|
|
)
|
|
return CursorPage(
|
|
items=[FeedbackOut.model_validate(f) for f in items], next_cursor=next_cursor,
|
|
)
|
|
|
|
|
|
@router.post("/{feedback_id}/handle", response_model=OkResponse, summary="标记反馈已处理")
|
|
def handle_feedback(
|
|
feedback_id: int,
|
|
request: Request,
|
|
admin: Annotated[AdminUser, Depends(require_role("operator"))],
|
|
db: AdminDb,
|
|
) -> OkResponse:
|
|
fb = db.get(Feedback, feedback_id)
|
|
if fb is None:
|
|
raise HTTPException(status_code=404, detail="反馈不存在")
|
|
before = fb.status
|
|
mutations.update_feedback_status(db, fb, status="adopted", commit=False)
|
|
write_audit(
|
|
db, admin, action="feedback.handle", target_type="feedback", target_id=feedback_id,
|
|
detail={"before": before, "after": "adopted", "deprecated": True},
|
|
ip=get_client_ip(request), commit=False,
|
|
)
|
|
db.commit()
|
|
return OkResponse()
|
|
|
|
|
|
@router.post("/{feedback_id}/approve", response_model=OkResponse, summary="采纳反馈并发金币")
|
|
def approve_feedback(
|
|
feedback_id: int,
|
|
body: FeedbackApproveRequest,
|
|
request: Request,
|
|
admin: Annotated[AdminUser, Depends(require_role("operator"))],
|
|
db: AdminDb,
|
|
) -> OkResponse:
|
|
fb = db.get(Feedback, feedback_id)
|
|
if fb is None:
|
|
raise HTTPException(status_code=404, detail="反馈不存在")
|
|
if fb.status != "pending":
|
|
raise HTTPException(status_code=400, detail=f"该反馈已审核过(当前 {fb.status}),不可重复操作")
|
|
|
|
note = body.note.strip() if body.note else None
|
|
mutations.review_feedback(
|
|
db,
|
|
fb,
|
|
status="adopted",
|
|
admin_id=admin.id,
|
|
reward_coins=body.reward_coins,
|
|
review_note=note,
|
|
commit=False,
|
|
)
|
|
acc, _ = wallet_repo.grant_coins(
|
|
db,
|
|
fb.user_id,
|
|
body.reward_coins,
|
|
biz_type="feedback_reward",
|
|
ref_id=str(fb.id),
|
|
remark="意见反馈被采纳",
|
|
)
|
|
write_audit(
|
|
db,
|
|
admin,
|
|
action="feedback.approve",
|
|
target_type="feedback",
|
|
target_id=feedback_id,
|
|
detail={
|
|
"user_id": fb.user_id,
|
|
"reward_coins": body.reward_coins,
|
|
"balance_after": acc.coin_balance,
|
|
"note": note,
|
|
},
|
|
ip=get_client_ip(request),
|
|
commit=False,
|
|
)
|
|
db.commit()
|
|
return OkResponse()
|
|
|
|
|
|
@router.post("/{feedback_id}/reject", response_model=OkResponse, summary="拒绝反馈并写明原因")
|
|
def reject_feedback(
|
|
feedback_id: int,
|
|
body: FeedbackRejectRequest,
|
|
request: Request,
|
|
admin: Annotated[AdminUser, Depends(require_role("operator"))],
|
|
db: AdminDb,
|
|
) -> OkResponse:
|
|
fb = db.get(Feedback, feedback_id)
|
|
if fb is None:
|
|
raise HTTPException(status_code=404, detail="反馈不存在")
|
|
if fb.status != "pending":
|
|
raise HTTPException(status_code=400, detail=f"该反馈已审核过(当前 {fb.status}),不可重复操作")
|
|
|
|
reason = body.reason.strip()
|
|
note = body.note.strip() if body.note else None
|
|
mutations.review_feedback(
|
|
db,
|
|
fb,
|
|
status="rejected",
|
|
admin_id=admin.id,
|
|
reject_reason=reason,
|
|
review_note=note,
|
|
commit=False,
|
|
)
|
|
write_audit(
|
|
db,
|
|
admin,
|
|
action="feedback.reject",
|
|
target_type="feedback",
|
|
target_id=feedback_id,
|
|
detail={"user_id": fb.user_id, "reason": reason, "note": note},
|
|
ip=get_client_ip(request),
|
|
commit=False,
|
|
)
|
|
db.commit()
|
|
return OkResponse()
|