from flask import Blueprint, request, jsonify, g, render_template, redirect, url_for from sqlmodel import Session, select from sqlalchemy import text from .models import User, Order from .schemas import UserLogin, OrderCreate, OrderUpdate, UserUpdate from .utils import hash_password, verify_password, create_jwt_token, decode_jwt_token, admin_required from .db import engine from .schemas import OrderStatus auth_bp = Blueprint('auth', __name__) order_bp = Blueprint('order', __name__) def jwt_required(f): def wrapper(*args, **kwargs): auth = request.headers.get('Authorization', None) if not auth or not auth.startswith('Bearer '): return jsonify({'msg': 'Missing or invalid token'}), 401 token = auth.split(' ')[1] user_data = decode_jwt_token(token) if not user_data: return jsonify({'msg': 'Token invalid or expired'}), 401 g.user_id = user_data['user_id'] g.role = user_data['role'] return f(*args, **kwargs) wrapper.__name__ = f.__name__ return wrapper @auth_bp.route('/login', methods=['POST']) def login(): data = request.get_json() login_data = UserLogin(**data) with Session(engine) as session: user = session.exec(select(User).where(User.username == login_data.username)).first() if not user or not verify_password(login_data.password, user.password_hash): return jsonify({'msg': 'Invalid credentials'}), 401 token = create_jwt_token(user) return jsonify({'token': token}) @auth_bp.route('/') def index(): return redirect(url_for('auth.login_page')) @auth_bp.route('/login_page') def login_page(): return render_template('login.html') # 订单管理接口 @order_bp.route('/', methods=['GET']) @jwt_required def list_orders(): with Session(engine) as session: orders = session.exec(select(Order)).all() return jsonify([order.dict() for order in orders]) @order_bp.route('/', methods=['POST']) @jwt_required def create_order(): data = request.get_json() order_data = OrderCreate(**data) order = Order(title=order_data.title, description=order_data.description) with Session(engine) as session: session.add(order) session.commit() session.refresh(order) return jsonify(order.dict()), 201 @order_bp.route('/', methods=['PUT']) @jwt_required def update_order(order_id): data = request.get_json() with Session(engine) as session: order = session.get(Order, order_id) if not order: return jsonify({'msg': 'Order not found'}), 404 update_data = OrderUpdate(**data) for field, value in update_data.dict(exclude_unset=True).items(): if field == "status" and value is not None: order.status = value elif field != "status": setattr(order, field, value) session.add(order) session.commit() return jsonify(order.dict()) @order_bp.route('/', methods=['DELETE']) @jwt_required def delete_order(order_id): with Session(engine) as session: order = session.get(Order, order_id) if not order: return jsonify({'msg': 'Order not found'}), 404 session.delete(order) session.commit() return jsonify({'msg': 'Deleted'}) @auth_bp.route('/users/', methods=['PUT']) @jwt_required def update_user(user_id): data = request.get_json() update_data = UserUpdate(**data) with Session(engine) as session: user = session.get(User, user_id) if not user: return jsonify({'msg': 'User not found'}), 404 for field, value in update_data.dict(exclude_unset=True).items(): setattr(user, field, value) session.add(user) session.commit() return jsonify(user.dict()) @order_bp.route('/panel') def order_panel(): return render_template('orders.html') @order_bp.route('/summary') @jwt_required def get_order_summary(): with Session(engine) as session: # 查询all_orders_summary表,按status分组统计count总和 result = session.execute( text("SELECT status, SUM(count) as total_count " "FROM all_orders_summary " "GROUP BY status") ).fetchall() # 转换为字典列表格式 status_mapping = { "0": "差评", "50": "中评", "100": "好评" } summary = [{"status": status_mapping.get(str(row[0]), str(row[0])), "count": row[1]} for row in result] return jsonify(summary) @order_bp.route('/rating_summary') @jwt_required def get_rating_summary(): with Session(engine) as session: # 查询each_order_summary表,按order_id和status分组统计 result = session.execute( text("SELECT order_id, status, SUM(count) as total_count " "FROM each_order_summary " "GROUP BY order_id, status " "ORDER BY order_id, status") ).fetchall() # 获取所有种类 categories = sorted({row[0] for row in result}) status_mapping = { "0": "差评", "50": "中评", "100": "好评" } # 初始化数据结构,确保每个种类都有三种评分 series_data = { "差评": [0] * len(categories), "中评": [0] * len(categories), "好评": [0] * len(categories) } # 填充数据 for row in result: category_idx = categories.index(row[0]) status = status_mapping[row[1]] series_data[status][category_idx] = row[2] return jsonify({ "categories": categories, "series": [ {"name": "差评", "data": series_data["差评"]}, {"name": "中评", "data": series_data["中评"]}, {"name": "好评", "data": series_data["好评"]} ] }) @order_bp.route('/type_summary') @jwt_required def get_type_summary(): with Session(engine) as session: # 查询order_type_summary表,按order_type分组统计count总和 result = session.execute( text("SELECT order_type, SUM(count) as total_count " "FROM order_type_summary " "GROUP BY order_type") ).fetchall() # 转换为字典列表格式 summary = [{"order_type": row[0], "count": row[1]} for row in result] return jsonify(summary) @order_bp.route('/top_products') @jwt_required def get_top_products(): with Session(engine) as session: # 查询top_products_summary表,按sales_count降序获取前5条记录 result = session.execute( text("SELECT order_type, SUM(count) as total_count " "FROM order_type_summary " "GROUP BY order_type" " ORDER BY total_count DESC " "LIMIT 5") ).fetchall() # 转换为字典列表格式 top_products = [{"product_name": row[0], "sales_count": row[1]} for row in result] return jsonify(top_products) @auth_bp.route('/users/', methods=['GET']) @jwt_required @admin_required def list_users(): with Session(engine) as session: users = session.exec(select(User)).all() return jsonify([user.dict() for user in users]) @auth_bp.route('/users/panel') def users_panel(): return render_template('users.html') @auth_bp.route('/users/', methods=['POST']) @jwt_required @admin_required def create_user(): data = request.get_json() username = data.get('username') password = data.get('password') role = data.get('role', 'user') if not username or not password: return jsonify({'msg': '用户名和密码必填'}), 400 with Session(engine) as session: if session.exec(select(User).where(User.username == username)).first(): return jsonify({'msg': '用户名已存在'}), 400 from .utils import hash_password user = User(username=username, password_hash=hash_password(password), role=role) session.add(user) session.commit() return jsonify(user.dict()), 201 @auth_bp.route('/users/', methods=['DELETE']) @jwt_required @admin_required def delete_user(user_id): with Session(engine) as session: user = session.get(User, user_id) if not user: return jsonify({'msg': '用户不存在'}), 404 session.delete(user) session.commit() return jsonify({'msg': '已删除'})