guzhi/app/api/v1/app_users/admin_manage.py
邹方成 5ca0152c55 feat: 更新邮件客户端和评估状态处理逻辑
修复邮件发送时的收件方地址验证问题,添加域名解析检查
更新评估状态字段值从"approved"为"pending"以保持一致性
修改发票创建接口以支持无凭证上传的情况
添加用户管理接口的时间范围查询功能
更新SMTP和短信服务的默认配置
2025-11-27 15:04:37 +08:00

136 lines
6.0 KiB
Python

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),
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 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="更新成功")