订单后台管理系统-day07菜品模块

发布于:2025-09-02 ⋅ 阅读:(16) ⋅ 点赞:(0)

添加和编辑菜品模块

文件上传

  • 菜品的添加需要使用到富文本编辑器

  • 添加菜品时需要上传图片,所以我们需要配置文件上传的操作,设定全局变量

 UPLOAD = {
        # 定义可上传的图片类型
        'ext': ['jpg', 'gif', 'bmp', 'jpeg', 'png'],
        # 普通文件保存路径
        'prefix_path': 'web/static/upload/',
        # 富文本图片路径
        'prefix_url': 'static/upload/'
    }
  • utils/views.py全局工具文件中

@utils_bp.route('/upload_pic', methods=['GET', 'POST'])
def upload_pic():
    # 获取传递过来的值,这里的值需要前后端配合。固定为upfile,这个属性可以修改,但是前端请求时也需要使用对应的属性
    file_target = request.files
    upfile = file_target['upfile'] if 'upfile' in file_target else None
    
    # 用于触发,set.js文件中的success方法,回显图片
    callback_target = 'window.parent'
    
    # 如果没有值,则弹窗显示上传失败。此处我们前后端未分离,后期可以修改为返回json格式的内容,由前端弹窗提示
    if upfile is None:
        return '<script>{0}.error("{1}")</script>'.format(callback_target, '上传失败')
    
    # 调用upload_file方法,实现图片上传,此方法在utils/utils.py文件中
    ret = upload_file(upfile)
    
    # 判断图片上传的返回值,给出不同反馈
    if ret['code'] != 200:
        return '<script>{0}.error("{1}")</script>'.format(callback_target, '上传失败:' + ret['msg'])
​
    return '<script>{0}.success("{1}")</script>'.format(callback_target, ret['data']['file_key'])
  • utils/utils.py中实现了upload_file方法,用于文件上传

# 文件上传本地
def upload_file(file_storage):
    resp = {'code': 200, 'msg': '操作成功!', 'data': {}}
    # 获取文件名称
    filename = secure_filename(file_storage.filename)
    # 按照文件名进行分割,并且取后缀
    ext = filename.rsplit('.', 1)[1]
    # 如果该后缀名不在配置文件里面,那么就要返回错误消息
    if ext not in Config.UPLOAD['ext']:
        resp['code'] = -1
        resp['msg'] = '不允许的扩展类型文件'
        return resp
​
    file_dir = datetime.now().strftime('%Y%m%d')
    save_dir = Config.UPLOAD['prefix_path'] + file_dir
​
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)
        os.chmod(save_dir, stat.S_IRWXU | stat.S_IRGRP | stat.S_IRWXO)
​
    # 构建文件名称
    file_name = str(uuid.uuid4().hex) + '.' + ext
    # 保存文件
    file_storage.save('{0}/{1}'.format(save_dir, file_name))
​
    # 将上传记录存储到数据库中
    add_file_obj = Files()
    add_file_obj.file_key = file_dir + '/' + file_name
    db.session.add(add_file_obj)
    db.session.commit()
​
    resp['data'] = {
        'file_key': add_file_obj.file_key
    }
​
    return resp
# 上传图片
def upload_image():
    resp = {
        'state': 'SUCCESS',
        'url': '',
        'title': '',
        'original': ''
    }
    file_target = request.files
    upfile = file_target['upfile'] if 'upfile' in file_target else None
    if upfile is None:
        resp['state'] = '上传失败'
        return jsonify(resp)
​
    ret = upload_file(upfile)
    if ret['code'] != 200:
        resp['state'] = '上传失败:' + ret['msg']
    # 调用图片回显方法,传入图片名称
    resp['url'] = build_image_url(ret['data']['file_key'])

图片回显

# 返回图片地址
def build_image_url(path):
    url = Config.DOMAIN + '/' + Config.UPLOAD['prefix_url'] + path
    return url

添加和编辑菜品

  • 富文本的添加图片逻辑类似。不过路由返回的是一个完整路径http://127.0.0.1:8999/static/upload/20250709/84a0dc4388154fd18c224cc6d3123270.jpg。方便后续在富文本中编译显示

  • 准备添加路由,开始添加和编辑菜品

@manage_bp.route('/food/edit', methods=['GET', 'POST'])
def food_edit():
    resp = {'code': 200, 'msg': '操作成功', 'data': {}}
    if request.method == 'GET':
​
        resp_data = {}
        req = request.args
        f_id = int(req.get('id', 0))
​
        food_obj = None
        if f_id:
            food_obj = Food.query.get(f_id)
​
        cat_list = FoodCat.query.all()
        resp_data['info'] = food_obj
        resp_data['current'] = 'index'
        resp_data['cat_list'] = cat_list
​
        return ops_render('food/set.html', resp_data)
​
    if request.method == 'POST':
        req = request.values
​
        f_id = req['food_id'] if 'food_id' in req else 0
        c_id = int(req['cat_id']) if 'cat_id' in req else 0
        name = req['name'] if 'name' in req else ''
        price = req['price'] if 'price' in req else ''
        main_image = req['main_image'] if 'main_image' in req else ''
        summary = req['summary'] if 'summary' in req else ''
        stock = int(req['stock']) if 'stock' in req else ''
        tags = req['tags'] if 'tags' in req else ''
​
        price = Decimal(price).quantize(Decimal('0.00'))
​
        # if f_id < 1:
        #     resp['code'] = -1
        #     resp['msg'] = '商品不存在!'
        #     return jsonify(resp)
​
        if c_id < 1:
            resp['code'] = -1
            resp['msg'] = '请选择分类'
            return jsonify(resp)
​
        if len(name) < 1 or name is None:
            resp['code'] = -1
            resp['msg'] = '名称不符合规范'
            return jsonify(resp)
​
        if price <= 0 or price is None:
            resp['code'] = -1
            resp['msg'] = '售卖价格不能为空且大于等于0'
            return jsonify(resp)
​
        if main_image is None or len(main_image) < 3:
            resp['code'] = -1
            resp['msg'] = '请上传封面图'
            return jsonify(resp)
​
        if summary is None or len(summary) < 10:
            resp['code'] = -1
            resp['msg'] = '详情不能少于十个字符!'
            return jsonify(resp)
​
        if stock < 1:
            resp['code'] = -1
            resp['msg'] = '库存不能小于1'
            return jsonify(resp)
​
        if tags is None or len(tags) < 1:
            resp['code'] = -1
            resp['msg'] = '请输入标签!'
            return jsonify(resp)
​
        food_obj = Food.query.get(f_id)
        before_stock = 0
​
        if not food_obj:
            food_obj = Food()
        else:
            before_stock = food_obj.stock
​
        food_obj.cat_id = c_id
        food_obj.name = name
        food_obj.price = price
        food_obj.main_image = main_image
        food_obj.summary = summary
        food_obj.stock = stock
        food_obj.tags = tags
​
        db.session.add(food_obj)
        db.session.commit()
​
        stock_change = FoodStockChangeLog()
        stock_change.food_id = food_obj.id
        stock_change.unit = int(stock) - int(before_stock)
        stock_change.total_stock = stock
        stock_change.note = '后台调整'
        db.session.add(stock_change)
        db.session.commit()
​
        return jsonify(resp)

显示所有菜品

@manage_bp.route('/food/list')
def food_list():
    resp_data = {}
    # 有page就取page
    page = int(request.args.get('page', 1))
​
    query = Food.query
    # 有status就取status
    status_name = int(request.args.get('status', '-1'))
    if status_name > -1:
        query = query.filter(Food.status == status_name)
    # 有cat_id就取cat_id
    cat_id = int(request.args.get('cat_id', 0))
    if cat_id > 0:
        query = query.filter_by(cat_id=cat_id)
    # 有查询的信息就使用查询信息
    mix_kw = request.args.get('mix_kw', '')
    if mix_kw:
        rule = or_(Food.name.contains('%s' % mix_kw), Food.tags.contains('%s' % mix_kw))
        page_data = query.filter(rule).order_by(Food.id.desc()).paginate(page=page, per_page=Config.PER_PAGE)
    else:
        page_data = query.order_by(Food.id.desc()).paginate(page=page, per_page=Config.PER_PAGE)
​
    resp_data = {
        'list': page_data,
        'status_mapping': constants.STATUS_MAPPING
    }
    
    # 这里获取分类数据,用于筛选.
    food_list_obj = FoodCat.query.all()
    resp_data['current'] = 'index'
    resp_data['cat_list'] = food_list_obj
    return ops_render('food/index.html', resp_data)

查看菜品详情

  • 路由中接收传递过来的id值,根据id查询数据

  • 详情中,我们还需要展示当前菜品的库存变更记录

  • 后期还可以加上销售记录

@manage_bp.route('/food/info')
def food_info():
    resp_data = {}
​
    req = request.args
    f_id = int(req.get('id', 0))
    if f_id < 1:
        return redirect('manage.food_list')
​
    food_obj = Food.query.get(f_id)
    if not food_obj:
        return redirect('manage.food_list')
    
    # 关联查询,库存记录变更表
    stock_change_list = FoodStockChangeLog.query.filter(FoodStockChangeLog.food_id == f_id).order_by(
        FoodStockChangeLog.id.desc()).all()
​
    resp_data['info'] = food_obj
    resp_data['current'] = 'index'
    resp_data['stock_change_list'] = stock_change_list
​
    return ops_render('food/info.html', resp_data)

删除菜品(修改状态)

  • 同理可得,根据传递过来的id和act的值,修改状态

@manage_bp.route('/food/ops', methods=['PUT'])
def foot_ops():
    resp = {'code': 200, 'msg': '操作成功!', 'data': {}}
    req = request.values
​
    f_id = req['id'] if 'id' in req else 0
    act = req['act'] if 'act' in req else ''
    if not f_id:
        resp['code'] = -1
        resp['msg'] = '操作失败!'
        return jsonify(resp)
    if act not in ['remove', 'recover']:
        resp['code'] = -1
        resp['msg'] = '操作失败!'
        return jsonify(resp)
    food_obj = Food.query.get(f_id)
    if not food_obj:
        resp['code'] = -1
        resp['msg'] = '指定食物不存在!'
        return jsonify(resp)
    if act == 'remove':
        food_obj.status = 0
    elif act == 'recover':
        food_obj.status = 1
    db.session.commit()
    return jsonify(resp)


网站公告

今日签到

点亮在社区的每一天
去签到