| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706 |
- """
- 客户端认证接口 - 统一API格式
- """
- from fastapi import APIRouter, Depends, HTTPException, Request
- from fastapi.responses import JSONResponse
- from sqlalchemy.orm import Session
- from app.database import get_db
- from app.api.deps import get_current_user_session, get_current_user_session_for_heartbeat
- from app.models.user import User
- from app.models.card import Card
- from app.models.recharge_record import RechargeRecord
- from app.models.system_config import SystemConfig
- from app.core.security import verify_password, get_password_hash
- from app.core.encrypt import encryptor
- from app.core.logger import logger
- from app.config import settings
- from app.schemas.client_api import *
- from app.services.key_rotation_service import KeyRotationService
- from app.services.session_service import SessionService
- from app.services.heartbeat_monitor import HeartbeatMonitor
- from app.utils.timestamp_validator import TimestampValidator
- from app.utils.timezone import beijing_now
- from datetime import datetime, timedelta
- import json
- router = APIRouter()
- def process_client_request(request: Request, db: Session) -> tuple[ClientApiRequest, dict]:
- """
- 处理客户端请求:解密、验证时间戳
- Returns:
- tuple: (解析后的请求对象, 响应头)
- """
- try:
- # 获取请求数据
- data = request.json() if hasattr(request, 'json') else {}
- # 调试日志:打印原始请求数据
- logger.debug(f"[API请求] 原始请求数据: {json.dumps(data, ensure_ascii=False, indent=2)}")
- # 解密请求数据
- if settings.ENCRYPT_ENABLED:
- encrypted_req = EncryptedRequest(**data)
- decrypted_data = encryptor.decrypt_from_client(
- encrypted_req.encrypted,
- encrypted_req.key_version,
- db
- )
- logger.debug(f"[API请求] 解密后数据: {json.dumps(decrypted_data, ensure_ascii=False, indent=2)}")
- else:
- decrypted_data = data
- logger.debug(f"[API请求] 未加密数据: {json.dumps(decrypted_data, ensure_ascii=False, indent=2)}")
- # 解析为统一格式
- api_request = ClientApiRequest(**decrypted_data)
- logger.info(f"[API请求] 解析后的请求 - 操作: {api_request.action}, 时间戳: {api_request.timestamp}, 版本: {api_request.version}")
- # 验证时间戳
- is_valid, error_msg = TimestampValidator.validate_timestamp(api_request.timestamp, db)
- if not is_valid:
- logger.warning(f"[API请求] 时间戳验证失败: {error_msg}")
- raise HTTPException(status_code=400, detail=error_msg)
- # 准备响应头
- response_headers = {}
- if settings.ENCRYPT_ENABLED:
- active_version = KeyRotationService.get_active_key_version(db)
- response_headers["X-Key-Version"] = str(active_version)
- logger.debug(f"[API请求] 响应密钥版本: {active_version}")
- return api_request, response_headers
- except Exception as e:
- logger.error(f"[API请求] 处理客户端请求失败: {e}")
- raise HTTPException(status_code=400, detail=f"请求格式错误: {str(e)}")
- def create_client_response(data: dict = None, code: int = 200, msg: str = "成功", db: Session = None) -> dict:
- """
- 创建客户端响应:统一格式化并加密
- Returns:
- dict: 响应数据(已加密)
- """
- try:
- # 创建响应对象
- response_data = ClientApiResponse(
- code=code,
- msg=msg,
- data=data,
- timestamp=TimestampValidator.generate_timestamp(),
- version="1.0"
- )
- # 转换为字典
- response_dict = response_data.dict()
- # 调试日志:打印响应数据
- logger.info(f"[API响应] 响应数据 - 状态码: {code}, 消息: {msg}, 数据大小: {len(str(data)) if data else 0} 字符")
- logger.debug(f"[API响应] 完整响应数据: {json.dumps(response_dict, ensure_ascii=False, indent=2)}")
- # 加密响应
- if settings.ENCRYPT_ENABLED and db:
- encrypted_data, key_version = encryptor.encrypt_for_client(response_dict, db)
- encrypted_response = {
- "encrypted": encrypted_data,
- "key_version": key_version
- }
- logger.debug(f"[API响应] 加密响应数据: {json.dumps(encrypted_response, ensure_ascii=False, indent=2)}")
- return encrypted_response
- return response_dict
- except Exception as e:
- logger.error(f"[API响应] 创建客户端响应失败: {e}")
- # 返回未加密的错误响应
- error_response = {
- "code": 500,
- "msg": f"响应处理失败: {str(e)}",
- "timestamp": TimestampValidator.generate_timestamp(),
- "version": "1.0"
- }
- logger.debug(f"[API响应] 错误响应数据: {json.dumps(error_response, ensure_ascii=False, indent=2)}")
- return error_response
- @router.post("/register")
- async def register(
- request: Request,
- db: Session = Depends(get_db)
- ):
- """用户注册"""
- try:
- # 处理客户端请求
- api_request, response_headers = process_client_request(request, db)
- # 验证操作类型
- if api_request.action != ApiActions.REGISTER:
- return create_client_response(code=400, msg="操作类型不匹配", db=db)
- # 解析注册参数
- register_params = RegisterRequest(**api_request.params)
- # 检查用户名是否存在
- existing_user = db.query(User).filter(User.username == register_params.username).first()
- if existing_user:
- return create_client_response(code=400, msg="用户名已存在", db=db)
- # 验证卡密
- card = db.query(Card).filter(
- Card.card_code == register_params.card_code,
- Card.status == 0
- ).first()
- if not card:
- return create_client_response(code=400, msg="卡密无效或已被使用", db=db)
- # 计算到期时间
- expire_time = beijing_now() + timedelta(days=card.days)
- # 创建用户
- user = User(
- username=register_params.username,
- password=get_password_hash(register_params.password),
- email=register_params.email,
- machine_code=register_params.machine_code,
- card_id=card.id,
- expire_time=expire_time,
- status=1,
- created_at=beijing_now(),
- updated_at=beijing_now()
- )
- db.add(user)
- db.flush() # 刷新以获取user.id
-
- # 更新卡密状态
- card.user_id = user.id
- card.activated_at = beijing_now()
- card.expire_time = expire_time
- card.status = 1
- card.updated_at = beijing_now()
-
- # 创建充值记录
- recharge_record = RechargeRecord(
- user_id=user.id,
- card_id=card.id,
- software_code=card.software_code,
- days=card.days,
- expire_time_before=None, # 新用户,之前没有到期时间
- expire_time_after=expire_time,
- created_at=beijing_now()
- )
- db.add(recharge_record)
- # 创建历史记录
- from app.utils.history import create_user_history, create_card_history, create_recharge_record_history
- create_user_history(db, user, "INSERT")
- create_card_history(db, card, "UPDATE")
- create_recharge_record_history(db, recharge_record, "INSERT")
- # 一次性提交所有更改
- db.commit()
- # 准备响应数据
- response_data = RegisterResponseData(user_id=user.id)
- logger.info(f"用户注册成功: {register_params.username}")
- return create_client_response(data=response_data.dict(), db=db)
- except Exception as e:
- db.rollback()
- logger.error(f"用户注册失败: {e}")
- return create_client_response(code=500, msg="注册失败", db=db)
- @router.post("/login")
- async def login(
- request: Request,
- db: Session = Depends(get_db)
- ):
- """用户登录"""
- try:
- logger.info("[用户登录] 开始处理登录请求")
- # 处理客户端请求
- api_request, response_headers = process_client_request(request, db)
- # 验证操作类型
- if api_request.action != ApiActions.LOGIN:
- logger.warning(f"[用户登录] 操作类型不匹配: {api_request.action}")
- return create_client_response(code=400, msg="操作类型不匹配", db=db)
- # 解析登录参数
- login_params = LoginRequest(**api_request.params)
- logger.info(f"[用户登录] 用户名: {login_params.username}, 机器码: {login_params.machine_code}")
- # 获取系统配置
- config = KeyRotationService.get_config(db)
- # 查找用户
- user = db.query(User).filter(User.username == login_params.username).first()
- if not user:
- logger.warning(f"[用户登录] 用户不存在: {login_params.username}")
- return create_client_response(code=401, msg="用户名或密码错误", db=db)
- # 验证密码
- if not verify_password(login_params.password, user.password):
- logger.warning(f"[用户登录] 密码验证失败: {login_params.username}")
- return create_client_response(code=401, msg="用户名或密码错误", db=db)
- # 验证/绑定机器码
- if user.machine_code:
- if user.machine_code != login_params.machine_code:
- logger.warning(f"[用户登录] 机器码不匹配 - 用户: {user.machine_code}, 请求: {login_params.machine_code}")
- return create_client_response(code=403, msg="机器码不匹配,请先解绑", db=db)
- else:
- # 用户已解绑或尚未绑定机器码,第一次登录时绑定当前机器码
- user.machine_code = login_params.machine_code
- logger.info(f"[用户登录] 绑定新机器码: {login_params.machine_code}")
- # 检查是否过期
- if user.expire_time and user.expire_time < beijing_now():
- logger.warning(f"[用户登录] 用户卡密已过期: {user.expire_time}")
- return create_client_response(code=403, msg="卡密已过期", db=db)
- # 获取客户端IP和User-Agent
- client_ip = request.client.host if request.client else None
- user_agent = request.headers.get("User-Agent")
- # 创建用户会话
- logger.debug(f"[用户登录] 创建会话 - 用户ID: {user.id}, IP: {client_ip}")
- session_success, session_msg, session_id = SessionService.create_session(
- db=db,
- user_id=user.id,
- machine_code=login_params.machine_code,
- ip_address=client_ip,
- user_agent=user_agent
- )
- if not session_success:
- logger.error(f"[用户登录] 创建会话失败: {session_msg}")
- return create_client_response(code=500, msg=f"创建会话失败: {session_msg}", db=db)
- # 更新登录信息
- user.last_login_time = beijing_now()
- user.last_login_ip = client_ip
- user.updated_at = beijing_now()
- db.commit()
- # 准备响应数据
- response_data = LoginResponseData(
- user_id=user.id,
- username=user.username,
- session_id=session_id,
- expire_time=user.expire_time.isoformat() if user.expire_time else None,
- machine_code=user.machine_code
- )
- logger.info(f"[用户登录] 登录成功 - 用户: {login_params.username}, SessionID: {session_id[:8]}...")
- return create_client_response(data=response_data.dict(), db=db)
-
- except Exception as e:
- # 回滚数据库事务以避免半提交状态
- try:
- db.rollback()
- except Exception:
- # 回滚失败不影响主流程,继续记录异常
- logger.warning("回滚数据库事务时发生异常")
- # 记录完整堆栈以便排查
- logger.exception("用户登录失败")
- # 返回给客户端一个友好的错误提示(不暴露内部细节)
- return create_client_response(code=500, msg="系统异常,登录失败,请稍后重试;若持续发生请联系客服", db=db)
- @router.post("/unbind")
- async def unbind(
- request: Request,
- db: Session = Depends(get_db)
- ):
- """机器解绑"""
- try:
- # 获取请求数据
- data = await request.json()
-
- # 解密请求数据
- if settings.ENCRYPT_ENABLED:
- encrypted_data = data.get("encrypted", "")
- if not encrypted_data:
- return {"code": 400, "msg": "缺少加密数据"}
- decrypted = encryptor.decrypt(encrypted_data)
- else:
- decrypted = data
-
- req = UnbindRequest(**decrypted)
-
- # 查找用户
- user = db.query(User).filter(User.username == req.username).first()
- if not user:
- return {"code": 401, "msg": "用户名或密码错误"}
-
- # 验证密码
- if not verify_password(req.password, user.password):
- return {"code": 401, "msg": "用户名或密码错误"}
-
- # 解绑机器码
- user.machine_code = None
- user.updated_at = beijing_now()
- db.commit()
-
- logger.info(f"机器解绑成功: {req.username}")
- return {"code": 200, "msg": "解绑成功"}
-
- except Exception as e:
- try:
- db.rollback()
- except Exception:
- logger.warning("回滚数据库事务时发生异常")
- logger.exception("机器解绑失败")
- return {"code": 500, "msg": "系统异常,操作未完成,请稍后重试;若持续发生请联系客服"}
- @router.post("/heartbeat")
- async def heartbeat(
- user_session: tuple[User, Session] = Depends(get_current_user_session_for_heartbeat),
- db: Session = Depends(get_db)
- ):
- """心跳检测"""
- try:
- user, session = user_session
- # 记录心跳日志
- logger.info(f"[心跳检测] 用户: {user.username}(ID:{user.id}), Session: {session.session_id[:8]}...")
- # 记录心跳成功
- HeartbeatMonitor.record_heartbeat_success(db, user.id, session.session_id)
- # 检查用户是否过期
- if user.expire_time and user.expire_time < beijing_now():
- logger.warning(f"用户 {user.username} 卡密已过期")
- return create_client_response(code=403, msg="卡密已过期", db=db)
- # 检查用户状态
- if user.status != 1:
- logger.warning(f"用户 {user.username} 状态异常: {user.status}")
- return create_client_response(code=403, msg="账号状态异常", db=db)
- # 更新会话活动时间(已在依赖注入中自动更新)
- # SessionService.validate_session 中已经调用了 update_activity
- # 获取系统配置
- from app.services.session_service import SessionService
- config = SessionService.get_session_config(db)
- # 返回心跳响应,包含更多状态信息
- response_data = HeartbeatResponseData(
- expire_time=user.expire_time.isoformat() if user.expire_time else None
- )
- # 获取session延长配置
- session_config = SessionService.get_session_config(db)
- # 获取客户端配置(通过心跳实时更新)
- from app.models.system_config import SystemConfig
- client_configs = {
- "api_timeout_seconds": SystemConfig.get_config_value('api_timeout_seconds', 30),
- "client_heartbeat_interval_seconds": SystemConfig.get_config_value('client_heartbeat_interval_seconds', 30),
- "max_heartbeat_failures": SystemConfig.get_config_value('max_heartbeat_failures', 10),
- "max_network_failures": SystemConfig.get_config_value('max_network_failures', 15),
- "sweep_batch_size": SystemConfig.get_config_value('sweep_batch_size', 10),
- "sweep_purchase_interval": SystemConfig.get_config_value('sweep_purchase_interval', 30),
- "sweep_max_purchases": SystemConfig.get_config_value('sweep_max_purchases', 100),
- "page_size": SystemConfig.get_config_value('page_size', 10),
- "steam_auth_countdown_seconds": SystemConfig.get_config_value('steam_auth_countdown_seconds', 30),
- }
- # 获取当前激活的密钥信息
- from app.models.api_key import APIKey
- current_key = db.query(APIKey).filter(APIKey.is_active == 1).first()
- key_info = None
- if current_key:
- key_info = {
- "key_version": current_key.key_version,
- "key_updated_at": current_key.updated_at.isoformat() if current_key.updated_at else None,
- }
- # 添加扩展响应数据
- extended_data = response_data.dict()
- extended_data.update({
- "server_time": beijing_now().isoformat(),
- "session_status": "active",
- "next_heartbeat": client_configs.get("client_heartbeat_interval_seconds", 30),
- "session_expires_at": session.expires_at.isoformat(),
- "session_extend_enabled": session_config.get("session_extend_enabled", True),
- "session_extend_threshold_hours": session_config.get("session_extend_threshold_hours", 4),
- # 实时配置更新
- "client_configs": client_configs,
- # 密钥版本信息(用于客户端密钥同步)
- "key_info": key_info
- })
- logger.debug(f"用户 {user.username} 心跳检测成功")
- return create_client_response(data=extended_data, db=db)
- except Exception as e:
- logger.error(f"心跳检测失败: {e}")
- return create_client_response(code=500, msg="心跳检测失败", db=db)
- @router.post("/logout")
- async def logout(
- request: Request,
- db: Session = Depends(get_db)
- ):
- """用户登出"""
- try:
- logger.info("[用户登出] 开始处理登出请求")
- # 处理客户端请求
- api_request, response_headers = process_client_request(request, db)
- # 验证操作类型
- if api_request.action != ApiActions.LOGOUT:
- logger.warning(f"[用户登出] 操作类型不匹配: {api_request.action}")
- return create_client_response(code=400, msg="操作类型不匹配", db=db)
- # 解析登出参数
- logout_params = LogoutRequest(**api_request.params)
- logger.info(f"[用户登出] 用户ID: {logout_params.user_id}, Session: {logout_params.session_id[:8]}...")
- # 验证会话(确保是当前用户的有效会话)
- is_valid, session, error_msg = SessionService.validate_session(db, logout_params.session_id)
- if not is_valid:
- logger.warning(f"[用户登出] 会话验证失败: {error_msg}")
- # 即使会话验证失败,也允许登出(可能是会话已过期但用户主动登出)
- logger.info("[用户登出] 会话验证失败但仍允许登出")
- # 停用会话
- if session:
- SessionService.deactivate_session(db, logout_params.session_id)
- logger.info(f"[用户登出] 用户 {logout_params.user_id} 的会话已停用")
- # 记录心跳监控:清除用户的缓存状态
- HeartbeatMonitor.reset_user_heartbeat(logout_params.user_id, logout_params.session_id)
- # 记录登出日志(可以后续在API日志中体现)
- logger.info(f"[用户登出] 用户 {logout_params.user_id} 成功登出")
- return create_client_response(msg="登出成功", db=db)
- except Exception as e:
- logger.error(f"[用户登出] 登出失败: {e}")
- return create_client_response(code=500, msg="登出失败", db=db)
- @router.post("/validate-session")
- async def validate_session(
- request: Request,
- db: Session = Depends(get_db)
- ):
- """验证用户会话(用于自动登录验证)"""
- try:
- logger.info("[会话验证] 开始验证用户会话")
- # 处理客户端请求
- api_request, response_headers = process_client_request(request, db)
- # 验证操作类型
- if api_request.action != ApiActions.VALIDATE_SESSION:
- logger.warning(f"[会话验证] 操作类型不匹配: {api_request.action}")
- return create_client_response(code=400, msg="操作类型不匹配", db=db)
- # 解析验证参数
- validate_params = ValidateSessionRequest(**api_request.params)
- logger.info(f"[会话验证] 验证会话ID: {validate_params.session_id[:8]}...")
- # 验证会话
- is_valid, session, error_msg = SessionService.validate_session(db, validate_params.session_id)
- if not is_valid:
- logger.warning(f"[会话验证] 会话验证失败: {error_msg}")
- return create_client_response(code=401, msg=f"会话验证失败: {error_msg}", db=db)
- # 获取用户信息
- user = db.query(User).filter(User.id == session.user_id).first()
- if not user:
- logger.warning("[会话验证] 用户不存在")
- return create_client_response(code=401, msg="用户不存在", db=db)
- # 检查用户是否过期
- if user.expire_time and user.expire_time < beijing_now():
- logger.warning(f"[会话验证] 用户 {user.username} 卡密已过期")
- return create_client_response(code=403, msg="卡密已过期", db=db)
- # 检查用户状态
- if user.status != 1:
- logger.warning(f"[会话验证] 用户 {user.username} 状态异常: {user.status}")
- return create_client_response(code=403, msg="账号状态异常", db=db)
- # 更新会话活动时间
- SessionService.update_session_activity(db, session.session_id)
- # 准备响应数据
- response_data = ValidateSessionResponseData(
- user_id=user.id,
- username=user.username,
- expire_time=user.expire_time.isoformat() if user.expire_time else None,
- is_active=user.status == 1,
- machine_code=user.machine_code or ""
- )
- logger.info(f"[会话验证] 用户 {user.username} 会话验证成功")
- return create_client_response(data=response_data.dict(), db=db)
- except Exception as e:
- logger.error(f"[会话验证] 验证失败: {e}")
- return create_client_response(code=500, msg="会话验证失败", db=db)
- @router.post("/activate-card")
- async def activate_card(
- user: User = Depends(get_current_user_session),
- request: Request = None,
- db: Session = Depends(get_db)
- ):
- """激活卡密(充值)"""
- try:
- logger.info(f"[卡密激活] 开始处理激活请求 - 用户: {user.username}(ID:{user.id})")
- # 处理客户端请求
- api_request, response_headers = process_client_request(request, db)
- # 验证操作类型
- if api_request.action != ApiActions.ACTIVATE_CARD:
- logger.warning(f"[卡密激活] 操作类型不匹配: {api_request.action}")
- return create_client_response(code=400, msg="操作类型不匹配", db=db)
- # 解析激活参数
- activate_params = ActivateCardRequest(**api_request.params)
- logger.info(f"[卡密激活] 激活参数 - 用户ID: {activate_params.user_id}, 卡密: {activate_params.card_code[:8]}...")
- # 验证用户ID是否匹配当前登录用户
- if activate_params.user_id != user.id:
- return create_client_response(code=403, msg="无权操作其他用户", db=db)
-
- # 验证卡密
- card = db.query(Card).filter(
- Card.card_code == activate_params.card_code,
- Card.status == 0
- ).first()
- if not card:
- return create_client_response(code=400, msg="卡密无效或已被使用", db=db)
- # 检查软件特征码是否匹配
- software_code = api_request.params.get("software_code", "")
- if card.software_code != software_code:
- return create_client_response(code=400, msg="卡密与当前软件不匹配", db=db)
-
- # 计算新的到期时间
- expire_time_before = user.expire_time
- if expire_time_before and expire_time_before > beijing_now():
- # 如果还有有效期,则累加
- expire_time_after = expire_time_before + timedelta(days=card.days)
- else:
- # 如果已过期或没有有效期,则从当前时间开始计算
- expire_time_after = beijing_now() + timedelta(days=card.days)
-
- # 更新用户到期时间
- user.expire_time = expire_time_after
- user.updated_at = beijing_now()
-
- # 更新卡密状态
- card.user_id = user.id
- card.activated_at = beijing_now()
- card.expire_time = expire_time_after
- card.status = 1
- card.updated_at = beijing_now()
-
- # 创建充值记录
- recharge_record = RechargeRecord(
- user_id=user.id,
- card_id=card.id,
- software_code=card.software_code,
- days=card.days,
- expire_time_before=expire_time_before,
- expire_time_after=expire_time_after,
- created_at=beijing_now()
- )
- db.add(recharge_record)
- # 创建历史记录
- from app.utils.history import create_user_history, create_card_history, create_recharge_record_history
- create_user_history(db, user, "UPDATE")
- create_card_history(db, card, "UPDATE")
- create_recharge_record_history(db, recharge_record, "INSERT")
- # 一次性提交所有更改
- db.commit()
- # 准备响应数据
- response_data = ActivateCardResponseData(
- expire_time=expire_time_after.isoformat(),
- days=card.days
- )
- logger.info(f"用户 {user.username} 激活卡密成功: {activate_params.card_code}")
- return create_client_response(data=response_data.dict(), db=db)
- except Exception as e:
- db.rollback()
- logger.error(f"激活卡密失败: {e}")
- return create_client_response(code=500, msg="激活失败", db=db)
- @router.get("/recharge-records")
- async def get_recharge_records(
- request: Request,
- db: Session = Depends(get_db)
- ):
- """获取充值记录"""
- try:
- # 获取请求参数
- params = dict(request.query_params)
-
- # 解密请求数据(如果有)
- user_id = None
- if settings.ENCRYPT_ENABLED:
- # GET请求可能通过query参数传递加密数据
- encrypted_data = params.get("encrypted", "")
- if encrypted_data:
- decrypted = encryptor.decrypt(encrypted_data)
- user_id = decrypted.get("user_id")
- else:
- user_id = params.get("user_id")
- if user_id:
- user_id = int(user_id)
-
- if not user_id:
- return {"code": 400, "msg": "缺少用户ID"}
-
- # 查询充值记录
- records = db.query(RechargeRecord).filter(
- RechargeRecord.user_id == user_id,
- RechargeRecord.is_deleted == 0
- ).order_by(RechargeRecord.created_at.desc()).all()
-
- # 格式化返回数据
- records_data = []
- for record in records:
- # 获取卡密代码
- card_code = ""
- if record.card_id:
- card = db.query(Card).filter(Card.id == record.card_id).first()
- if card:
- card_code = card.card_code
-
- records_data.append({
- "id": record.id,
- "card_code": card_code,
- "days": record.days,
- "expire_time_before": record.expire_time_before.isoformat() if record.expire_time_before else None,
- "expire_time_after": record.expire_time_after.isoformat() if record.expire_time_after else None,
- "created_at": record.created_at.isoformat() if record.created_at else None
- })
-
- return {
- "code": 200,
- "msg": "成功",
- "data": records_data
- }
-
- except Exception as e:
- logger.exception("获取充值记录失败")
- return {"code": 500, "msg": "系统异常,操作未完成,请稍后重试;若持续发生请联系客服"}
|