修复邮件发送时的收件方地址验证问题,添加域名解析检查 更新评估状态字段值从"approved"为"pending"以保持一致性 修改发票创建接口以支持无凭证上传的情况 添加用户管理接口的时间范围查询功能 更新SMTP和短信服务的默认配置
136 lines
6.0 KiB
Python
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="更新成功")
|