""" 评价管理视图 """ from flask import Blueprint, render_template, request, jsonify, redirect, url_for, session, flash, g from sqlalchemy import func, desc from config.database import db from app.models.review import Review from app.models.order import Order, OrderItem from app.models.product import Product from app.models.user import User from app.utils.decorators import login_required, log_operation from app.utils.file_upload import file_upload_handler import json review_bp = Blueprint('review', __name__, url_prefix='/review') @review_bp.route('/product/') def product_reviews(product_id): """商品评价列表(AJAX接口)""" try: page = request.args.get('page', 1, type=int) rating_filter = request.args.get('rating', type=int) # 基础查询 query = Review.query.filter_by(product_id=product_id, status=1) # 评分筛选 if rating_filter: query = query.filter_by(rating=rating_filter) # 分页查询 reviews = query.order_by(desc(Review.created_at)).paginate( page=page, per_page=10, error_out=False ) # 评价统计 stats = db.session.query( Review.rating, func.count(Review.id).label('count') ).filter_by(product_id=product_id, status=1).group_by(Review.rating).all() rating_stats = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0} total_reviews = 0 for stat in stats: rating_stats[stat.rating] = stat.count total_reviews += stat.count # 好评率计算 good_rate = 0 if total_reviews > 0: good_reviews = rating_stats[4] + rating_stats[5] good_rate = round(good_reviews / total_reviews * 100, 1) # 转换为字典 reviews_data = [] for review in reviews.items: review_dict = review.to_dict() # 添加用户头像 if review.user: review_dict['user_avatar'] = review.user.avatar_url reviews_data.append(review_dict) return jsonify({ 'success': True, 'reviews': reviews_data, 'pagination': { 'page': reviews.page, 'pages': reviews.pages, 'per_page': reviews.per_page, 'total': reviews.total, 'has_next': reviews.has_next, 'has_prev': reviews.has_prev }, 'stats': { 'total_reviews': total_reviews, 'good_rate': good_rate, 'rating_stats': rating_stats } }) except Exception as e: return jsonify({'success': False, 'message': str(e)}) @review_bp.route('/write//') @login_required def write_review(order_id, product_id): """写评价页面""" # 验证订单和商品 order = Order.query.filter_by(id=order_id, user_id=session["user_id"]).first() if not order: flash('订单不存在', 'error') return redirect(url_for('order.list')) # 检查订单状态 if order.status not in [4, 5]: # 待评价或已完成 flash('该订单暂时无法评价', 'error') return redirect(url_for('order.detail', order_id=order_id)) # 检查商品是否在订单中 order_item = OrderItem.query.filter_by(order_id=order_id, product_id=product_id).first() if not order_item: flash('商品不在此订单中', 'error') return redirect(url_for('order.detail', order_id=order_id)) # 检查是否已经评价过 existing_review = Review.query.filter_by( user_id=session["user_id"], product_id=product_id, order_id=order_id ).first() if existing_review: flash('您已经评价过该商品', 'info') return redirect(url_for('order.detail', order_id=order_id)) return render_template('review/write.html', order=order, order_item=order_item, product=order_item.product) @review_bp.route('/submit', methods=['POST']) @login_required @log_operation('提交商品评价') def submit_review(): """提交评价""" try: data = request.get_json() order_id = data.get('order_id') product_id = data.get('product_id') rating = data.get('rating') content = data.get('content', '').strip() is_anonymous = data.get('is_anonymous', False) images = data.get('images', []) # 参数验证 if not all([order_id, product_id, rating]): return jsonify({'success': False, 'message': '参数不完整'}) if not (1 <= rating <= 5): return jsonify({'success': False, 'message': '评分必须在1-5星之间'}) # 验证订单 order = Order.query.filter_by(id=order_id, user_id=session["user_id"]).first() if not order: return jsonify({'success': False, 'message': '订单不存在'}) if order.status not in [4, 5]: return jsonify({'success': False, 'message': '该订单暂时无法评价'}) # 验证商品在订单中 order_item = OrderItem.query.filter_by(order_id=order_id, product_id=product_id).first() if not order_item: return jsonify({'success': False, 'message': '商品不在此订单中'}) # 检查是否已评价 existing_review = Review.query.filter_by( user_id=session["user_id"], product_id=product_id, order_id=order_id ).first() if existing_review: return jsonify({'success': False, 'message': '您已经评价过该商品'}) # 创建评价 review = Review( user_id=session["user_id"], product_id=product_id, order_id=order_id, rating=rating, content=content if content else None, is_anonymous=1 if is_anonymous else 0 ) # 设置图片 if images: review.set_images(images) db.session.add(review) # 检查订单中所有商品是否都已评价 total_items = OrderItem.query.filter_by(order_id=order_id).count() reviewed_items = Review.query.filter_by(order_id=order_id).count() + 1 # +1 是当前这个评价 # 如果所有商品都已评价,更新订单状态为已完成 if reviewed_items >= total_items and order.status == 4: order.status = 5 # 已完成 db.session.commit() return jsonify({ 'success': True, 'message': '评价提交成功', 'review_id': review.id }) except Exception as e: db.session.rollback() return jsonify({'success': False, 'message': f'提交失败: {str(e)}'}) @review_bp.route('/upload_image', methods=['POST']) @login_required def upload_review_image(): """上传评价图片""" try: if 'file' not in request.files: return jsonify({'success': False, 'message': '没有选择文件'}) file = request.files['file'] if file.filename == '': return jsonify({'success': False, 'message': '没有选择文件'}) # 使用现有的文件上传处理器 result = file_upload_handler.upload_image(file, 'reviews', process_image=True) if result['success']: return jsonify({ 'success': True, 'message': '图片上传成功', 'url': result['url'] }) else: return jsonify({'success': False, 'message': result['error']}) except Exception as e: return jsonify({'success': False, 'message': f'上传失败: {str(e)}'}) @review_bp.route('/my_reviews') @login_required def my_reviews(): """我的评价列表""" page = request.args.get('page', 1, type=int) reviews = Review.query.filter_by(user_id=session["user_id"]).order_by( desc(Review.created_at) ).paginate(page=page, per_page=10, error_out=False) return render_template('review/my_reviews.html', reviews=reviews) @review_bp.route('/delete/', methods=['POST']) @login_required @log_operation('删除商品评价') def delete_review(review_id): """删除评价(仅限自己的评价)""" try: review = Review.query.filter_by(id=review_id, user_id=session["user_id"]).first() if not review: return jsonify({'success': False, 'message': '评价不存在'}) db.session.delete(review) db.session.commit() return jsonify({'success': True, 'message': '评价删除成功'}) except Exception as e: db.session.rollback() return jsonify({'success': False, 'message': f'删除失败: {str(e)}'})