学弟划水日记-Bootstrap+Flask实现上传作业平台

    技术2023-05-19  90

    Docker

    docker run -itd -p 80:8080 registry.cn-beijing.aliyuncs.com/liyuanhao/homework:v3

    前言

    博主最近小学期,每天得收三十多份报告;原采用QQ发送形式,但效率太低,很多时间都花在收发和修改命名格式上,因而博主打算写个提交作业平台,部署于阿里云,每个同学均可通过它上传当日作业,最后博主统一上交

    PS:由于开发周期只有一天半,所以有些地方可能存有BUG,恳请指正

    文章目录

    前言结果一、需求分析1.1 上传1.2 重命名1.3 打包 二、设计2.1 技术2.2 存储 三、过程3.1 前端3.1.1 表格3.1.2 提交框3.1.3 JS 3.2 后端

    结果

    主页面

    上传页面,点击可上传自己的作业文件 文件为空时提示

    上传成功时提示

    一、需求分析

    1.1 上传

    同学将每天的作业(Word文档)上传到该平台

    1.2 重命名

    按老师要求的格式给每份文件命名

    1.3 打包

    将收齐的word文件放入一个文件夹内,压缩并下载

    二、设计

    2.1 技术

    该系统采取C/S架构

    部署环境 : CentOS7

    前端 : Bootstrap + Jquery+SweetAlert2

    WEB框架 : Flask

    2.2 存储

    博主将上传文件存到了项目中文件夹内,所以此处没有使用数据库

    三、过程

    项目结构

    index.html为主页面信1701-3班-报告文件夹存储上传文件modles.py 存储学生学号与姓名信息

    3.1 前端

    3.1.1 表格

    主页面初始时显示一个提交表格,内容为每位同学的提交状态、学号、姓名、提交时间以及操作按钮. 图示

    data是后端传来的一个列表,内含每个学生信息的字典 <!--提交信息的表格--> <table class="table table-hover" id="stuInfoTable"> <thead> <tr> <th>提交状态</th> <th>学号</th> <th>姓名</th> <th>上传时间</th> <th>操作</th> </tr> </thead> <tbody> {% for i in data %} <tr> {% if i['status'] == 'yes' %} <td style="color: green"> <strong>已提交</strong> </td> {% else %} <td style="color: red"> <strong>未提交</strong> </td> {% endif %} <td>{{ i['num'] }}</td> <td>{{ i['name'] }}</td> <td>{{ i['time'] }}</td> <!--已经提交则提交按钮为不可操作状态--> {% if i['status'] == 'yes' %} <td> <button class="btn btn-primary" disabled="disabled"> 已上传 </button> </td> {% else %} <!--否则当点击上传按钮时将字典i的值传给对应函数--> <td> <button class="btn btn-primary btn-lg" data-toggle="modal" onclick="display_form({{ i }})"> 文件上传 </button> </td> {% endif %} </tr> {% endfor %} </tbody> </table>

    3.1.2 提交框

    <!--上传文件弹出框--> <div class="modal fade" id="stu_modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title" id="myModalLabel"> 操作系统每日报告上传 </h4> </div> <div class="modal-body"> <!--上传信息表格--> <form id="upload" action="/upload" enctype='multipart/form-data' method='POST'> <div class="input-group mb-3"> <div class="input-group-prepend"> <span class="input-group-text">姓名</span> </div> <label for="name"></label> <input type="text" class="form-control" id="name" name="name"> </div> <div class="input-group mb-3"> <div class="input-group-prepend"> <span class="input-group-text">学号</span> </div> <label for="num"></label> <input type="text" class="form-control" id="num" name="num"> </div> <div class="input-group mb-3"> <div class="input-group-prepend"> <span class="input-group-text">班级</span> </div> <select class="form-control" name="classes" disabled> <option value="1701_1">信1701-1班</option> <option value="1701_2">信1701-2班</option> <!--默认值--> <option value="1701_3" selected>信1701-3班</option> </select> </div> <!--上传文件的控件--> <input id='file' class="btn btn-info" name="file" type="file"> <div class="modal-footer"> <button type="button" onclick="submit_form()" class="btn btn-primary">提交</button> <button type="button" class="btn btn-danger" data-dismiss="modal">关闭</button> </div> </form> </div> </div> </div> </div>

    3.1.3 JS

    <script> //实现表格信息的分页操作 $('#stuInfoTable').bootstrapTable({ pagination: true, //是否显示分页条 pageSize: 5, //一页显示的行数 paginationLoop: false, //是否开启分页条无限循环,最后一页时点击下一页是否转到第一页 pageList: [5, 10, 20] //选择每页显示多少行,数据过少时可能会没有效果 }) //显示模态框 function display_form(data) { //模态框显示事件 $('#stu_modal').modal('show') //自动给姓名与学号控件赋值 $('#name').val(data['name']) $('#num').val(data['num']) } //提交表格 function submit_form() { var form = document.getElementById("upload"); var formData = new FormData(form); var name = formData.get("name") var num = formData.get("num") //用户名为2-5个汉字 var name_reg = /^[\u4e00-\u9fa5]{2,5}$/ //学号为8位数字 var num_reg = /^\d{8}$/ if (!name_reg.test(name)) { swal("用户名错误!", "", "warning") return } if (!num_reg.test(num)) { swal("学号错误!", "", "warning") return } //判断文件是否为空 //var file = formData.get("file") var fileInput = $('#file').get(0).files[0]; if (!fileInput) { swal("请选择上传文件!", "", "warning") return } //发送ajax请求 $.ajax({ async: false, type: "POST", url: "/upload", data: formData, dataType: "JSON", mimeType: "multipart/form-data", contentType: false, cache: false, processData: false, success: function () { swal({ title: "上传成功", text: "", type: "success", timer: 2000 }, function () { location.reload() }) }, error: function () { alert("网络异常,请稍后重试") } }) } </script>

    3.2 后端

    app.py

    import os import time from flask import Flask, render_template, request, redirect, url_for import models app = Flask(__name__) @app.route('/') def hello_world(): #上交作业的情况信息 data = get_upload_info() #已经上交的份数 num1 = len(get_stu_num()) return render_template('index.html', data=data, num1=num1) # 上传 @app.route('/upload', methods=['POST', 'GET']) def upload_file(): if request.method == 'POST': f = request.files['file'] name = request.form.get('name') num = request.form.get('num') # 获取文件格式 file_format = f.filename.split('.')[1] # 按老师要求命名 new_name = '%s-%s-课程设计工作日报表.%s' % (num, name, file_format) f.filename = new_name # 上传文件的所在路径 upload_path = os.path.join(os.getcwd(), '信1701-3班-报表-7月3日', f.filename) # 将路径转换为绝对路径 upload_path = os.path.abspath(upload_path) f.save(upload_path) return json.dumps({"result": 1}) # 下载文件 @app.route('/download/', methods=['GET']) def download(): zip_file() path = os.path.join(os.getcwd()) return send_from_directory(path, dir + '.zip', as_attachment=True) #压缩文件 def zip_file(): # 压缩文件夹 startdir = os.path.join(os.getcwd(), dir) file_news = dir + '.zip' z = zipfile.ZipFile(file_news, 'w', zipfile.ZIP_DEFLATED) # 参数一:文件夹名 for dirpath, dirnames, filenames in os.walk(startdir): fpath = dirpath.replace(startdir, '') # 这一句很重要,不replace的话,就从根目录开始复制 fpath = fpath and fpath + os.sep or '' for filename in filenames: z.write(os.path.join(dirpath, filename), fpath + filename) z.close() # 根据学号获取文件路径 def get_file_path(num): folder_path = os.path.join(os.getcwd(), '信1701-3班-报表-7月3日') for i in os.listdir(folder_path): if num in i: # 返回对应文件的绝对路径 return os.path.join(folder_path, i) # 获取文件修改时间 def get_upload_time(num): path = get_file_path(num) times = os.path.getmtime(path) return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(times)) # 获取已经上传学生的学号 def get_stu_num(): data = [] folder_path = os.path.join(os.getcwd(), '信1701-3班-报表-7月3日') for i in os.listdir(folder_path): path = os.path.join(folder_path, i) if os.path.isfile(path): num, name, file_format = i.split('-') data.append(num) return data # 获取上传情况 def get_upload_info(): data2 = [] num_info = get_stu_num() for i in models.stu_info: info = { 'status': 'no', 'num': i['num'], 'name': i['name'], 'time': '-----' } # 若该人已经提交 if num_info and i['num'] in num_info: info['status'] = 'yes' info['time'] = get_upload_time(i['num']) data2.append(info) return data2 if __name__ == '__main__': app.run()

    models.py 数据仅做示例

    stu_info = [ {'num': '2015****', 'name': '李**'}, {'num': '2016****', 'name': '张**'}, {'num': '2017****', 'name': '张**'}, {'num': '2017****', 'name': '王**'}, {'num': '2017****', 'name': '张**'}, ]

    Processed: 0.035, SQL: 10