from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///shop.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
# 用户模型
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(128))
orders = db.relationship('Order', backref='user', lazy=True)
cart_items = db.relationship('CartItem', backref='user', lazy=True)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
# 商品模型
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
description = db.Column(db.Text)
price = db.Column(db.Float, nullable=False)
stock = db.Column(db.Integer, nullable=False)
image_url = db.Column(db.String(200))
# 订单模型
class Order(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
date_ordered = db.Column(db.DateTime, default=datetime.utcnow)
status = db.Column(db.String(20), default='pending') # pending, completed, refunded
items = db.relationship('OrderItem', backref='order', lazy=True)
total_amount = db.Column(db.Float, nullable=False)
def can_delete(self):
"""判断订单是否可以删除"""
return self.status in ['pending', 'cancelled']
def can_deliver(self):
"""判断订单是否可以交付"""
return self.status == 'pending'
# 订单项模型
class OrderItem(db.Model):
id = db.Column(db.Integer, primary_key=True)
order_id = db.Column(db.Integer, db.ForeignKey('order.id'), nullable=False)
product_id = db.Column(db.Integer, db.ForeignKey('product.id'), nullable=False)
quantity = db.Column(db.Integer, nullable=False)
price = db.Column(db.Float, nullable=False)
product = db.relationship('Product')
# 购物车项模型
class CartItem(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
product_id = db.Column(db.Integer, db.ForeignKey('product.id'), nullable=False)
quantity = db.Column(db.Integer, nullable=False)
product = db.relationship('Product')
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
# 首页 - 商品展示
@app.route('/')
def index():
products = Product.query.all()
return render_template('index.html', products=products)
# 用户个人信息
@app.route('/profile')
@login_required
def profile():
return render_template('profile.html')
# 购物车
@app.route('/cart')
@login_required
def cart():
cart_items = CartItem.query.filter_by(user_id=current_user.id).all()
total = sum(item.product.price * item.quantity for item in cart_items)
return render_template('cart.html', cart_items=cart_items, total=total)
# 订单历史
@app.route('/orders')
@login_required
def orders():
user_orders = Order.query.filter_by(user_id=current_user.id).all()
return render_template('orders.html', orders=user_orders)
# 添加到购物车
@app.route('/add_to_cart/<int:product_id>', methods=['POST'])
@login_required
def add_to_cart(product_id):
quantity = int(request.form.get('quantity', 1))
cart_item = CartItem.query.filter_by(user_id=current_user.id, product_id=product_id).first()
if cart_item:
cart_item.quantity += quantity
else:
cart_item = CartItem(user_id=current_user.id, product_id=product_id, quantity=quantity)
db.session.add(cart_item)
db.session.commit()
flash('商品已添加到购物车!')
return redirect(url_for('cart'))
# 创建订单
@app.route('/create_order', methods=['POST'])
@login_required
def create_order():
cart_items = CartItem.query.filter_by(user_id=current_user.id).all()
if not cart_items:
flash('购物车为空!')
return redirect(url_for('cart'))
total_amount = sum(item.product.price * item.quantity for item in cart_items)
order = Order(user_id=current_user.id, total_amount=total_amount)
db.session.add(order)
for cart_item in cart_items:
order_item = OrderItem(
order=order,
product_id=cart_item.product_id,
quantity=cart_item.quantity,
price=cart_item.product.price
)
db.session.add(order_item)
# 更新库存
product = cart_item.product
product.stock -= cart_item.quantity
db.session.delete(cart_item)
db.session.commit()
flash('订单创建成功!')
return redirect(url_for('orders'))
# 申请退款
@app.route('/refund/<int:order_id>', methods=['POST'])
@login_required
def refund_order(order_id):
order = Order.query.get_or_404(order_id)
if order.user_id != current_user.id:
flash('无权限操作此订单!')
return redirect(url_for('orders'))
if order.status == 'completed':
order.status = 'refunded'
# 恢复库存
for item in order.items:
product = item.product
product.stock += item.quantity
db.session.commit()
flash('退款申请已提交!')
else:
flash('订单状态不允许退款!')
return redirect(url_for('orders'))
# 用户认证相关路由
@app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('index'))
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
remember = 'remember' in request.form
user = User.query.filter_by(username=username).first()
if user and user.check_password(password):
login_user(user, remember=remember)
next_page = request.args.get('next')
return redirect(next_page or url_for('index'))
flash('用户名或密码错误')
return render_template('login.html')
@app.route('/register', methods=['GET', 'POST'])
def register():
if current_user.is_authenticated:
return redirect(url_for('index'))
if request.method == 'POST':
username = request.form.get('username')
email = request.form.get('email')
password = request.form.get('password')
confirm_password = request.form.get('confirm_password')
if password != confirm_password:
flash('两次输入的密码不一致')
return redirect(url_for('register'))
if User.query.filter_by(username=username).first():
flash('用户名已存在')
return redirect(url_for('register'))
if User.query.filter_by(email=email).first():
flash('邮箱已被注册')
return redirect(url_for('register'))
user = User(username=username, email=email)
user.set_password(password)
db.session.add(user)
db.session.commit()
flash('注册成功,请登录')
return redirect(url_for('login'))
return render_template('register.html')
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('index'))
@app.route('/update_profile', methods=['POST'])
@login_required
def update_profile():
email = request.form.get('email')
if email != current_user.email:
if User.query.filter_by(email=email).first():
flash('邮箱已被使用')
else:
current_user.email = email
db.session.commit()
flash('个人信息更新成功')
return redirect(url_for('profile'))
@app.route('/change_password', methods=['POST'])
@login_required
def change_password():
current_password = request.form.get('current_password')
new_password = request.form.get('new_password')
confirm_password = request.form.get('confirm_password')
if not current_user.check_password(current_password):
flash('当前密码错误')
elif new_password != confirm_password:
flash('两次输入的新密码不一致')
else:
current_user.set_password(new_password)
db.session.commit()
flash('密码修改成功')
return redirect(url_for('profile'))
# 购物车相关路由
@app.route('/update_cart_item/<int:item_id>', methods=['POST'])
@login_required
def update_cart_item(item_id):
cart_item = CartItem.query.get_or_404(item_id)
if cart_item.user_id != current_user.id:
flash('无权限操作此购物车项')
return redirect(url_for('cart'))
quantity = int(request.form.get('quantity', 1))
if quantity > cart_item.product.stock:
flash('商品库存不足')
else:
cart_item.quantity = quantity
db.session.commit()
flash('购物车更新成功')
return redirect(url_for('cart'))
@app.route('/remove_from_cart/<int:item_id>', methods=['POST'])
@login_required
def remove_from_cart(item_id):
cart_item = CartItem.query.get_or_404(item_id)
if cart_item.user_id != current_user.id:
flash('无权限操作此购物车项')
return redirect(url_for('cart'))
db.session.delete(cart_item)
db.session.commit()
flash('商品已从购物车中移除')
return redirect(url_for('cart'))
# 添加删除订单功能
@app.route('/cancel_order/<int:order_id>', methods=['POST'])
@login_required
def cancel_order(order_id):
order = Order.query.get_or_404(order_id)
# 验证订单属于当前用户
if order.user_id != current_user.id:
flash('无权限操作此订单', 'danger')
return redirect(url_for('orders'))
# 检查订单状态是否可以取消
if not order.can_delete():
flash('订单当前状态不可取消', 'danger')
return redirect(url_for('orders'))
try:
# 恢复库存
for item in order.items:
product = item.product
product.stock += item.quantity
# 更新订单状态为已取消
order.status = 'cancelled'
db.session.commit()
flash('订单已成功取消', 'success')
except Exception as e:
db.session.rollback()
flash('取消订单时出错: {}'.format(str(e)), 'danger')
return redirect(url_for('orders'))
# 添加管理员端订单交付功能
@app.route('/admin/deliver_order/<int:order_id>', methods=['POST'])
@login_required
def deliver_order(order_id):
# 检查是否是管理员
if not current_user.is_authenticated or current_user.username != 'admin':
flash('需要管理员权限', 'danger')
return redirect(url_for('index'))
order = Order.query.get_or_404(order_id)
# 检查订单状态是否可以交付
if not order.can_deliver():
flash('订单当前状态不可交付', 'danger')
return redirect(url_for('admin_orders'))
try:
# 更新订单状态为已完成
order.status = 'completed'
db.session.commit()
flash('订单已标记为已交付', 'success')
except Exception as e:
db.session.rollback()
flash('交付订单时出错: {}'.format(str(e)), 'danger')
return redirect(url_for('admin_orders'))
# 添加管理员端订单删除功能
@app.route('/admin/delete_order/<int:order_id>', methods=['POST'])
@login_required
def admin_delete_order(order_id):
# 检查是否是管理员
if not current_user.is_authenticated or current_user.username != 'admin':
flash('需要管理员权限', 'danger')
return redirect(url_for('index'))
order = Order.query.get_or_404(order_id)
# 检查订单状态是否可以删除
if not order.can_delete():
flash('订单当前状态不可删除', 'danger')
return redirect(url_for('admin_orders'))
try:
# 如果是待处理订单,需要恢复库存
if order.status == 'pending':
for item in order.items:
product = item.product
product.stock += item.quantity
# 删除订单项
for item in order.items:
db.session.delete(item)
# 删除订单
db.session.delete(order)
db.session.commit()
flash('订单已成功删除', 'success')
except Exception as e:
db.session.rollback()
flash('删除订单时出错: {}'.format(str(e)), 'danger')
return redirect(url_for('admin_orders'))
# 添加管理员端页面管理路由
@app.route('/admin/orders')来自csdn里的哪个人
@login_required
def admin_orders():
# 检查是否是管理员
if not current_user.is_authenticated or current_user.username != 'admin':
flash('需要管理员权限', 'danger')
return redirect(url_for('index'))
# 获取所有订单,按日期降序排列
orders = Order.query.order_by(Order.date_ordered.desc()).all()
return render_template('admin_orders.html', orders=orders)
# 添加订单详情页面路由
@app.route('/order/<int:order_id>')
@login_required
def order_details(order_id):
order = Order.query.get_or_404(order_id)
# 检查是否是订单所有者或管理员
if order.user_id != current_user.id and current_user.username != 'admin':
flash('无权限查看此订单', 'danger')
return redirect(url_for('index'))
return render_template('order_details.html', order=order)
if __name__ == '__main__':
with app.app_context():
db.create_all()
app.run(debug=True)