from fastapi import APIRouter, Query, Depends, HTTPException from typing import Optional, List from datetime import datetime from app.schemas.base import Success, SuccessExtra, BasicResponse, PageResponse from app.schemas.app_user import AppUserQuotaUpdateSchema, AppUserQuotaLogOut, AppUserUpdateSchema from app.controllers.app_user import app_user_controller from app.models.user import AppUser, AppUserQuotaLog from app.core.dependency import DependAuth, DependPermission, AuthControl admin_app_users_router = APIRouter(dependencies=[DependAuth, DependPermission], tags=["admin-App用户管理"]) @admin_app_users_router.get("/list", summary="App用户列表", response_model=PageResponse[dict]) async def list_app_users( phone: Optional[str] = Query(None), wechat: Optional[str] = Query(None), include_deleted: Optional[bool] = Query(False), id: Optional[str] = Query(None), created_start: Optional[str] = Query(None), created_end: Optional[str] = Query(None), created_at: Optional[List[int]] = Query(None), page: int = Query(1, ge=1), page_size: int = Query(10, ge=1, le=100), ): qs = AppUser.filter() if not include_deleted: qs = qs.filter(is_deleted=False) if id is not None and id.strip().isdigit(): qs = qs.filter(id=int(id.strip())) if phone: qs = qs.filter(phone__icontains=phone) if wechat: qs = qs.filter(alias__icontains=wechat) if created_start or created_end: def _parse_dt(s: Optional[str]): if not s: return None s = s.replace('+', ' ').strip() try: return datetime.strptime(s, "%Y-%m-%d %H:%M:%S") except Exception: try: ms = float(s) return datetime.fromtimestamp(ms / 1000) except Exception: return None start_dt = _parse_dt(created_start) end_dt = _parse_dt(created_end) if start_dt and end_dt: qs = qs.filter(created_at__gte=start_dt, created_at__lte=end_dt) elif start_dt: qs = qs.filter(created_at__gte=start_dt) elif end_dt: qs = qs.filter(created_at__lte=end_dt) elif created_at and len(created_at) == 2: start_dt = datetime.fromtimestamp(created_at[0] / 1000) end_dt = datetime.fromtimestamp(created_at[1] / 1000) qs = qs.filter(created_at__gte=start_dt, created_at__lte=end_dt) total = await qs.count() rows = await qs.order_by("-created_at").offset((page - 1) * page_size).limit(page_size) items = [] for u in rows: last_log = await AppUserQuotaLog.filter(app_user_id=u.id).order_by("-created_at").first() items.append({ "id": u.id, "phone": u.phone, "wechat": u.alias, "created_at": u.created_at.isoformat() if u.created_at else "", "notes": getattr(u, "notes", "") or "", "remaining_count": int(getattr(u, "remaining_quota", 0) or 0), "user_type": getattr(last_log, "op_type", None), }) return SuccessExtra(data=items, total=total, page=page, page_size=page_size, msg="获取成功") @admin_app_users_router.post("/quota", summary="调整用户剩余估值次数", response_model=BasicResponse[dict]) async def update_quota(payload: AppUserQuotaUpdateSchema, operator=Depends(AuthControl.is_authed)): user = await app_user_controller.update_quota( operator_id=getattr(operator, "id", 0), operator_name=getattr(operator, "username", "admin"), user_id=payload.user_id, target_count=payload.target_count, delta=payload.delta, op_type=payload.op_type, remark=payload.remark, ) if not user: raise HTTPException(status_code=404, detail="用户不存在") # if payload.remark is not None: # user.notes = payload.remark # await user.save() return Success(data={"user_id": user.id, "remaining_quota": user.remaining_quota}, msg="调整成功") @admin_app_users_router.get("/{user_id}/quota-logs", summary="用户估值次数操作日志", response_model=PageResponse[AppUserQuotaLogOut]) async def quota_logs(user_id: int, page: int = Query(1, ge=1), page_size: int = Query(10, ge=1, le=100)): qs = AppUserQuotaLog.filter(app_user_id=user_id) total = await qs.count() rows = await qs.order_by("-created_at").offset((page - 1) * page_size).limit(page_size) models = [ AppUserQuotaLogOut( id=r.id, app_user_id=r.app_user_id, operator_id=r.operator_id, operator_name=r.operator_name, before_count=r.before_count, after_count=r.after_count, op_type=r.op_type, remark=r.remark, created_at=r.created_at.isoformat() if r.created_at else "", ) for r in rows ] data_items = [m.model_dump() for m in models] return SuccessExtra(data=data_items, total=total, page=page, page_size=page_size, msg="获取成功") @admin_app_users_router.put("/{user_id}", summary="更新App用户信息", response_model=BasicResponse[dict]) async def update_app_user(user_id: int, data: AppUserUpdateSchema): user = await app_user_controller.update_user_info(user_id, data) if not user: raise HTTPException(status_code=404, detail="用户不存在") return Success(data={ "id": user.id, "phone": user.phone, "wechat": getattr(user, "alias", None), "company_name": getattr(user, "company_name", None), "company_address": getattr(user, "company_address", None), "company_contact": getattr(user, "company_contact", None), "company_phone": getattr(user, "company_phone", None), "company_email": getattr(user, "company_email", None), "notes": getattr(user, "notes", None), "is_active": user.is_active, "created_at": user.created_at.isoformat() if user.created_at else "", "updated_at": user.updated_at.isoformat() if user.updated_at else "", "remaining_quota": int(getattr(user, "remaining_quota", 0) or 0), }, msg="更新成功") @admin_app_users_router.delete("/{user_id}", summary="注销App用户", response_model=BasicResponse[dict]) async def admin_delete_app_user(user_id: int): ok = await app_user_controller.delete_user_account(user_id) if not ok: raise HTTPException(status_code=404, detail="用户不存在") return Success(data={"user_id": user_id}, msg="账号已注销")