初始化提交

This commit is contained in:
2025-12-14 15:40:49 +08:00
commit 410b2f068d
72 changed files with 10460 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
"""管理员相关路由"""
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from models import User
from services.admin_service import AdminService
admin_bp = Blueprint('admin', __name__)
def admin_required():
"""管理员权限验证装饰器"""
current_user_id = get_jwt_identity()
user = User.query.get(current_user_id)
if not user or not user.is_admin:
return None
return user
@admin_bp.route('/users', methods=['GET'])
@jwt_required()
def get_users():
"""获取用户列表"""
if not admin_required():
return jsonify({'error': '需要管理员权限'}), 403
# 分页参数
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 20, type=int)
search = request.args.get('search', '')
result, status_code = AdminService.get_users(page, per_page, search)
return jsonify(result), status_code
@admin_bp.route('/users/<int:user_id>', methods=['GET'])
@jwt_required()
def get_user_detail(user_id):
"""获取用户详情"""
if not admin_required():
return jsonify({'error': '需要管理员权限'}), 403
result, status_code = AdminService.get_user_detail(user_id)
return jsonify(result), status_code
@admin_bp.route('/users/<int:user_id>/toggle-status', methods=['POST'])
@jwt_required()
def toggle_user_status(user_id):
"""启用/禁用用户"""
admin = admin_required()
if not admin:
return jsonify({'error': '需要管理员权限'}), 403
result, status_code = AdminService.toggle_user_status(admin.id, user_id)
return jsonify(result), status_code
@admin_bp.route('/users/<int:user_id>/adjust-balance', methods=['POST'])
@jwt_required()
def adjust_balance(user_id):
"""调整用户余额"""
if not admin_required():
return jsonify({'error': '需要管理员权限'}), 403
data = request.get_json()
result, status_code = AdminService.adjust_balance(user_id, data)
return jsonify(result), status_code
@admin_bp.route('/orders', methods=['GET'])
@jwt_required()
def get_all_orders():
"""获取所有订单"""
if not admin_required():
return jsonify({'error': '需要管理员权限'}), 403
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 20, type=int)
status = request.args.get('status')
result, status_code = AdminService.get_all_orders(page, per_page, status)
return jsonify(result), status_code
@admin_bp.route('/api-calls', methods=['GET'])
@jwt_required()
def get_all_api_calls():
"""获取所有API调用记录"""
if not admin_required():
return jsonify({'error': '需要管理员权限'}), 403
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 20, type=int)
status = request.args.get('status')
result, status_code = AdminService.get_all_api_calls(page, per_page, status)
return jsonify(result), status_code
@admin_bp.route('/stats/overview', methods=['GET'])
@jwt_required()
def get_overview_stats():
"""获取总览统计"""
if not admin_required():
return jsonify({'error': '需要管理员权限'}), 403
result, status_code = AdminService.get_overview_stats()
return jsonify(result), status_code
@admin_bp.route('/stats/chart', methods=['GET'])
@jwt_required()
def get_chart_data():
"""获取图表数据最近7天"""
if not admin_required():
return jsonify({'error': '需要管理员权限'}), 403
days = request.args.get('days', 7, type=int)
result, status_code = AdminService.get_chart_data(days)
return jsonify(result), status_code

View File

@@ -0,0 +1,45 @@
"""API服务相关路由 - 支持 Nano Banana API 代理"""
from flask import Blueprint, request, jsonify, current_app
from flask_jwt_extended import jwt_required, get_jwt_identity
from services.api_proxy_service import ApiProxyService
api_bp = Blueprint('api_service', __name__)
@api_bp.route('/text-to-image', methods=['POST'])
@jwt_required()
def text_to_image():
"""
通用 API 代理 (支持文生图和对话)
"""
current_user_id = get_jwt_identity()
data = request.get_json()
result, status_code = ApiProxyService.handle_api_request(current_user_id, data)
if status_code == 200 and data.get('stream', False):
return current_app.response_class(result, mimetype='text/event-stream')
return jsonify(result), status_code
@api_bp.route('/models', methods=['GET'])
@jwt_required()
def get_models():
"""
获取可用的模型列表
"""
result, status_code = ApiProxyService.get_models()
return jsonify(result), status_code
@api_bp.route('/pricing', methods=['GET'])
def get_pricing():
"""获取价格信息(公开接口)"""
result, status_code = ApiProxyService.get_pricing()
return jsonify(result), status_code
@api_bp.route('/call/<int:call_id>', methods=['GET'])
@jwt_required()
def get_api_call(call_id):
"""获取API调用详情"""
current_user_id = get_jwt_identity()
result, status_code = ApiProxyService.get_api_call(current_user_id, call_id)
return jsonify(result), status_code

View File

@@ -0,0 +1,56 @@
"""用户 API Key 管理相关路由"""
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from services.apikey_service import APIKeyService
apikey_bp = Blueprint('apikey', __name__)
@apikey_bp.route('/keys', methods=['GET'])
@jwt_required()
def list_api_keys():
"""获取用户的所有 API Key"""
user_id = get_jwt_identity()
result, status_code = APIKeyService.list_api_keys(user_id)
return jsonify(result), status_code
@apikey_bp.route('/keys', methods=['POST'])
@jwt_required()
def create_api_key():
"""创建新的 API Key"""
user_id = get_jwt_identity()
data = request.get_json()
result, status_code = APIKeyService.create_api_key(user_id, data)
return jsonify(result), status_code
@apikey_bp.route('/keys/<int:key_id>', methods=['GET'])
@jwt_required()
def get_api_key(key_id):
"""获取单个 API Key 详情"""
user_id = get_jwt_identity()
result, status_code = APIKeyService.get_api_key(user_id, key_id)
return jsonify(result), status_code
@apikey_bp.route('/keys/<int:key_id>', methods=['PUT'])
@jwt_required()
def update_api_key(key_id):
"""更新 API Key 名称或状态"""
user_id = get_jwt_identity()
data = request.get_json()
result, status_code = APIKeyService.update_api_key(user_id, key_id, data)
return jsonify(result), status_code
@apikey_bp.route('/keys/<int:key_id>', methods=['DELETE'])
@jwt_required()
def delete_api_key(key_id):
"""删除 API Key"""
user_id = get_jwt_identity()
result, status_code = APIKeyService.delete_api_key(user_id, key_id)
return jsonify(result), status_code
@apikey_bp.route('/keys/<int:key_id>/regenerate', methods=['POST'])
@jwt_required()
def regenerate_api_key(key_id):
"""重置/轮换 API Key"""
user_id = get_jwt_identity()
result, status_code = APIKeyService.regenerate_api_key(user_id, key_id)
return jsonify(result), status_code

View File

@@ -0,0 +1,70 @@
"""认证相关路由"""
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity, create_access_token
from services.auth_service import AuthService
from services.user_service import UserService
auth_bp = Blueprint('auth', __name__)
@auth_bp.route('/send-verification-code', methods=['POST'])
def send_verification_code():
"""发送验证码"""
data = request.get_json()
result, status_code = AuthService.send_verification_code(data)
return jsonify(result), status_code
@auth_bp.route('/register', methods=['POST'])
def register():
"""用户注册 - 需要验证码"""
data = request.get_json()
result, status_code = AuthService.register(data)
return jsonify(result), status_code
@auth_bp.route('/login', methods=['POST'])
def login():
"""用户登录"""
data = request.get_json()
result, status_code = AuthService.login(data)
return jsonify(result), status_code
@auth_bp.route('/me', methods=['GET'])
@jwt_required()
def get_current_user():
"""获取当前用户信息"""
current_user_id = get_jwt_identity()
result, status_code = UserService.get_profile(current_user_id)
return jsonify(result), status_code
@auth_bp.route('/change-password', methods=['POST'])
@jwt_required()
def change_password():
"""修改密码"""
current_user_id = get_jwt_identity()
data = request.get_json()
result, status_code = AuthService.change_password(current_user_id, data)
return jsonify(result), status_code
@auth_bp.route('/reset-password', methods=['POST'])
def reset_password():
"""重置密码 - 需要验证码"""
data = request.get_json()
result, status_code = AuthService.reset_password(data)
return jsonify(result), status_code
@auth_bp.route('/verify-code', methods=['POST'])
def verify_code():
"""验证验证码是否有效(不标记为已使用)"""
data = request.get_json()
result, status_code = AuthService.verify_code(data)
return jsonify(result), status_code
@auth_bp.route('/refresh', methods=['POST'])
@jwt_required(refresh=True)
def refresh():
"""刷新访问令牌"""
current_user_id = get_jwt_identity()
access_token = create_access_token(identity=current_user_id)
return jsonify({
'access_token': access_token
}), 200

View File

@@ -0,0 +1,57 @@
"""订单相关路由"""
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from services.order_service import OrderService
order_bp = Blueprint('order', __name__)
@order_bp.route('/create', methods=['POST'])
@jwt_required()
def create_order():
"""创建充值订单"""
current_user_id = get_jwt_identity()
data = request.get_json()
result, status_code = OrderService.create_order(current_user_id, data)
return jsonify(result), status_code
@order_bp.route('/list', methods=['GET'])
@jwt_required()
def get_orders():
"""获取订单列表"""
current_user_id = get_jwt_identity()
# 分页参数
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 20, type=int)
status = request.args.get('status')
result, status_code = OrderService.get_orders(current_user_id, page, per_page, status)
return jsonify(result), status_code
@order_bp.route('/<int:order_id>', methods=['GET'])
@jwt_required()
def get_order(order_id):
"""获取订单详情"""
current_user_id = get_jwt_identity()
result, status_code = OrderService.get_order(current_user_id, order_id)
return jsonify(result), status_code
@order_bp.route('/callback/alipay', methods=['POST'])
def alipay_callback():
"""支付宝支付回调(预留接口)"""
data = request.get_json() or request.form.to_dict()
result, status_code = OrderService.alipay_callback(data)
return jsonify(result), status_code
@order_bp.route('/callback/wechat', methods=['POST'])
def wechat_callback():
"""微信支付回调(预留接口)"""
data = request.get_json() or request.form.to_dict()
result, status_code = OrderService.wechat_callback(data)
return jsonify(result), status_code
@order_bp.route('/notify/<order_no>', methods=['POST'])
def payment_notify(order_no):
"""模拟支付通知(仅用于测试)"""
result, status_code = OrderService.payment_notify(order_no)
return jsonify(result), status_code

View File

@@ -0,0 +1,65 @@
"""用户相关路由"""
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from services.user_service import UserService
user_bp = Blueprint('user', __name__)
@user_bp.route('/profile', methods=['GET'])
@jwt_required()
def get_profile():
"""获取用户资料"""
current_user_id = get_jwt_identity()
result, status_code = UserService.get_profile(current_user_id)
return jsonify(result), status_code
@user_bp.route('/profile', methods=['PUT'])
@jwt_required()
def update_profile():
"""更新用户资料"""
current_user_id = get_jwt_identity()
data = request.get_json()
result, status_code = UserService.update_profile(current_user_id, data)
return jsonify(result), status_code
@user_bp.route('/balance', methods=['GET'])
@jwt_required()
def get_balance():
"""获取账户余额"""
current_user_id = get_jwt_identity()
result, status_code = UserService.get_balance(current_user_id)
return jsonify(result), status_code
@user_bp.route('/transactions', methods=['GET'])
@jwt_required()
def get_transactions():
"""获取交易记录"""
current_user_id = get_jwt_identity()
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 20, type=int)
result, status_code = UserService.get_transactions(current_user_id, page, per_page)
return jsonify(result), status_code
@user_bp.route('/api-calls', methods=['GET'])
@jwt_required()
def get_api_calls():
"""获取API调用记录"""
current_user_id = get_jwt_identity()
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 20, type=int)
result, status_code = UserService.get_api_calls(current_user_id, page, per_page)
return jsonify(result), status_code
@user_bp.route('/stats', methods=['GET'])
@jwt_required()
def get_stats():
"""获取用户统计信息"""
current_user_id = get_jwt_identity()
result, status_code = UserService.get_stats(current_user_id)
return jsonify(result), status_code

View File

@@ -0,0 +1,36 @@
"""对外公开的 API 路由 (v1) - 支持 API Key 认证"""
from flask import Blueprint, request, jsonify, current_app
from services.apikey_service import APIKeyService
from services.v1_service import V1Service
v1_bp = Blueprint('v1_api', __name__)
@v1_bp.route('/chat/completions', methods=['POST'])
def chat_completions():
"""
OpenAI 兼容的 Chat Completions 接口
支持多模型,通过 modelapiservice 分发
"""
# 1. 认证
auth_header = request.headers.get('Authorization')
user, error = APIKeyService.authenticate_api_key(auth_header)
if error:
return jsonify({'error': {'message': error, 'type': 'auth_error', 'code': 401}}), 401
# 2. 获取请求数据
data = request.get_json()
if not data:
return jsonify({'error': {'message': '无效的 JSON 请求体', 'type': 'invalid_request_error', 'code': 400}}), 400
result, status_code = V1Service.chat_completions(user, data)
if status_code == 200 and data.get('stream', False):
return current_app.response_class(result, mimetype='text/event-stream')
return jsonify(result), status_code
@v1_bp.route('/text-to-image', methods=['POST'])
def text_to_image_alias():
"""兼容旧接口路径"""
return chat_completions()