from fastapi import APIRouter, Request from fastapi.responses import JSONResponse from database import SessionLocal from models.user_data import UserData from models.total import User from models.points import PointsConsumptionLog from utils.logger import logger import time router = APIRouter() REQUIRED_POINTS = 10 @router.get("/points/balance") async def get_balance(request: Request): """获取用户积分余额(支持本地用户和外部用户)""" user_info = request.state.user if not user_info: return JSONResponse(status_code=401, content={"statusCode": 401, "msg": "未认证"}) db = SessionLocal() try: # 优先查询本地用户 user = db.query(User).filter( User.id == user_info.user_id, User.is_deleted == 0 ).first() if user: return JSONResponse(content={ "statusCode": 200, "msg": "success", "data": {"points": user.points or 0} }) # 查询外部用户 user_data = db.query(UserData).filter( UserData.accountID == user_info.account ).first() if not user_data: return JSONResponse(content={"statusCode": 404, "msg": "未找到用户数据"}) return JSONResponse(content={ "statusCode": 200, "msg": "success", "data": {"points": user_data.points or 0} }) except Exception as e: logger.error(f"获取积分余额失败: {e}") return JSONResponse(content={"statusCode": 500, "msg": f"获取积分余额失败: {str(e)}"}) finally: db.close() @router.post("/points/consume") async def consume_points(request: Request): """消费积分下载文件(每次消耗10积分,支持本地用户和外部用户)""" user_info = request.state.user if not user_info: return JSONResponse(status_code=401, content={"statusCode": 401, "msg": "未认证"}) try: body = await request.json() except Exception: return JSONResponse(content={"statusCode": 400, "msg": "JSON解析失败"}) file_name = body.get("file_name", "") file_url = body.get("file_url", "") db = SessionLocal() try: # 优先查询本地用户 user = db.query(User).filter( User.id == user_info.user_id, User.is_deleted == 0 ).first() if user: current_points = user.points or 0 if current_points < REQUIRED_POINTS: return JSONResponse(content={ "statusCode": 400, "msg": "积分不足,下载需要10积分", "data": { "current_points": current_points, "required_points": REQUIRED_POINTS } }) new_balance = current_points - REQUIRED_POINTS user.points = new_balance now = int(time.time()) log = PointsConsumptionLog( user_id=str(user.id), file_name=file_name, file_url=file_url, points_consumed=REQUIRED_POINTS, balance_after=new_balance, created_at=now, updated_at=now, ) db.add(log) db.commit() return JSONResponse(content={ "statusCode": 200, "msg": "success", "data": { "new_balance": new_balance, "points_consumed": REQUIRED_POINTS } }) # 查询外部用户 user_data = db.query(UserData).filter( UserData.accountID == user_info.account ).first() if not user_data: return JSONResponse(content={"statusCode": 404, "msg": "未找到用户数据"}) current_points = user_data.points or 0 if current_points < REQUIRED_POINTS: return JSONResponse(content={ "statusCode": 400, "msg": "积分不足,下载需要10积分", "data": { "current_points": current_points, "required_points": REQUIRED_POINTS } }) new_balance = current_points - REQUIRED_POINTS user_data.points = new_balance now = int(time.time()) log = PointsConsumptionLog( user_id=user_info.account, file_name=file_name, file_url=file_url, points_consumed=REQUIRED_POINTS, balance_after=new_balance, created_at=now, updated_at=now, ) db.add(log) db.commit() return JSONResponse(content={ "statusCode": 200, "msg": "success", "data": { "new_balance": new_balance, "points_consumed": REQUIRED_POINTS } }) except Exception as e: db.rollback() logger.error(f"消费积分失败: {e}") return JSONResponse(content={"statusCode": 500, "msg": f"消费积分失败: {str(e)}"}) finally: db.close() @router.post("/points/add") async def add_points(request: Request): """增加积分(仅管理员)""" user_info = request.state.user if not user_info: return JSONResponse(status_code=401, content={"statusCode": 401, "msg": "未认证"}) # 检查管理员权限 if user_info.role != "admin": return JSONResponse(status_code=403, content={"statusCode": 403, "msg": "权限不足"}) try: body = await request.json() except Exception: return JSONResponse(content={"statusCode": 400, "msg": "JSON解析失败"}) user_id = body.get("user_id") points = body.get("points", 0) reason = body.get("reason", "") if not user_id or points <= 0: return JSONResponse(content={"statusCode": 400, "msg": "参数错误"}) db = SessionLocal() try: # 优先查询本地用户 user = db.query(User).filter( User.id == user_id, User.is_deleted == 0 ).first() if user: user.points = (user.points or 0) + points db.commit() logger.info(f"管理员 {user_info.username} 为用户 {user_id} 添加 {points} 积分,原因: {reason}") return JSONResponse(content={ "statusCode": 200, "msg": "积分添加成功", "data": {"new_balance": user.points} }) # 查询外部用户 user_data = db.query(UserData).filter(UserData.id == user_id).first() if not user_data: return JSONResponse(content={"statusCode": 404, "msg": "用户不存在"}) user_data.points = (user_data.points or 0) + points db.commit() logger.info(f"管理员 {user_info.username} 为外部用户 {user_id} 添加 {points} 积分,原因: {reason}") return JSONResponse(content={ "statusCode": 200, "msg": "积分添加成功", "data": {"new_balance": user_data.points} }) except Exception as e: db.rollback() logger.error(f"添加积分失败: {e}") return JSONResponse(content={"statusCode": 500, "msg": f"添加积分失败: {str(e)}"}) finally: db.close() @router.get("/points/logs") @router.get("/points/history") async def get_consumption_history(request: Request, page: int = 1, pageSize: int = 10): """获取积分消费记录(支持本地用户和外部用户)""" user_info = request.state.user if not user_info: return JSONResponse(status_code=401, content={"statusCode": 401, "msg": "未认证"}) db = SessionLocal() try: # 确定用户ID(本地用户用user_id,外部用户用account) user = db.query(User).filter( User.id == user_info.user_id, User.is_deleted == 0 ).first() user_identifier = str(user.id) if user else user_info.account query = db.query(PointsConsumptionLog).filter( PointsConsumptionLog.user_id == user_identifier ) total = query.count() logs = query.order_by(PointsConsumptionLog.id.desc()) \ .offset((page - 1) * pageSize) \ .limit(pageSize) \ .all() items = [ { "id": log.id, "file_name": log.file_name, "file_url": log.file_url, "points_consumed": log.points_consumed, "balance_after": log.balance_after, "created_at": log.created_at, } for log in logs ] return JSONResponse(content={ "statusCode": 200, "msg": "success", "data": { "list": items, "total": total, "page": page, "pageSize": pageSize, } }) except Exception as e: logger.error(f"获取消费记录失败: {e}") return JSONResponse(content={"statusCode": 500, "msg": f"获取消费记录失败: {str(e)}"}) finally: db.close()