python web项目(django……+Layui+mysql)


  • 1.结果图
  • 2目录结构
  • 3.开干
  • 4.总结


为了完成期末作业,做的一个学生成绩管理系统,采用django+Layui+mysql5.5,实现了学生成绩的增删改查,分页显示,批量从文件导入数据,将学生数据导出为excel文件,用pyecharts对学生成绩进行分析,登录、等功能整个采用异步请求,看这篇文章首先你要对ajax有了解,对layui框架有了解,会简单实用即可

1.结果图

Python HTML 报表工具 python报表web开发_json


Python HTML 报表工具 python报表web开发_python_02


Python HTML 报表工具 python报表web开发_html_03


Python HTML 报表工具 python报表web开发_html_04


Python HTML 报表工具 python报表web开发_django_05


Python HTML 报表工具 python报表web开发_Python HTML 报表工具_06


Python HTML 报表工具 python报表web开发_python_07


Python HTML 报表工具 python报表web开发_html_08


Python HTML 报表工具 python报表web开发_html_09

导入的文件格式必须是.csv,学生学号字段不能重复,数据库中有学号的就不能再插入当前学号的了

Python HTML 报表工具 python报表web开发_html_10

2目录结构

Python HTML 报表工具 python报表web开发_html_11


1111.py文件没多大用处,那是我做图表时写的测试文件,可以删除

3.开干

我用的PyCharm开发工具

新建一个django项目,创建好以后在settings.py中添加把项目demo1添加进去

Python HTML 报表工具 python报表web开发_Python HTML 报表工具_12


在settings.py修改DATABASES,改成mysql数据库

# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'text1',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

创建一个文件夹media用于存放上传及下载的文件,,创建一个static文件夹用于存放静态资源,和项目同级,打开settings.py在末尾添加

STATIC_URL = '/static/'

# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]


X_FRAME_OPTIONS = 'ALLOWALL url'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

X_FRAME_OPTIONS = 'ALLOWALL url’用于前端的ifram嵌套,不加网页不能嵌套

然后再_init_.py中添加
import pymysql
pymysql.install_as_MySQLdb()

模型文件(model.py)

from django.db import models
class Student(models.Model):

    Sno = models.AutoField(primary_key=True,max_length=32) # 学号会自动创建,可以手动写入
    Sname= models.CharField(max_length=32) # 学生姓名
    Sage=models.CharField(max_length=11)  #学生年龄
    Ssex=models.CharField(max_length=11)#性别
    YuWen=models.CharField(max_length=11)#语文成绩
    ShuXue = models.CharField(max_length=11)  # 语文成绩

    YingYu=models.CharField(max_length=11)#语文成绩

    ZhengZhi = models.CharField(max_length=11)  # 语文成绩
    @staticmethod
    def get_title_list():
        return ["学号", "姓名", "年龄","性别","语文","数学","英语","政治"]

因为我的djiango版本和mysql不对应,没有进行迁移, 想迁移也行,方法另行百度

数据库表,不迁移表名字一定要写成这样,前面加上你的工程名,迁移的话表名是自动生成的

Python HTML 报表工具 python报表web开发_django_13


路由 urls.py

from django.contrib import admin
from django.urls import path
from .demo import view
from .demo import stucrud,userInfo


urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', view.index),
    path('', view.index),
    path('stuList/', view.stuList),
    path('updatestu.html/', view.toUpdateUser),

    path('addstu.html/', view.toAddUser),

    path('select/', stucrud.select),
    #导入学生
    path('file/', stucrud.importFile),
    #模糊查询
    path('search/', stucrud.search),
    #添加学生
    path('addstu/', stucrud.addstu),
    #删除学生
    path('delestu/', stucrud.delestu),
    #修改学生
    path('edistu/', stucrud.edistu),
    path('addFile.html/', view.toaddAll),
    #导出学生

    path('export_student_excel/', stucrud.export_student_excel),
    path('echarts/', stucrud.echarts),
    path('tubiao/', view.tubiao),



    path('login/', userInfo.login),


]

视图view.py

from django.shortcuts import render, redirect


def index(request):
    status = request.COOKIES.get('is_login')  # 收到浏览器的再次请求,判断浏览器携带的cookie是不是登录成功的时候响应的 cookie
    if not status:
        return render(request, 'index.html', {"msg": "没有权限请先登录!!!"})
    return render(request, "system/Student/stutable.html")

def stuList(request):
    status = request.COOKIES.get('is_login')  # 收到浏览器的再次请求,判断浏览器携带的cookie是不是登录成功的时候响应的 cookie
    if not status:
        return render(request,'index.html',{"msg":"没有权限请先登录!!!"})
    return render(request, "system/Student/stutable.html")

def toUpdateUser(request):
    return  render(request, "system/Student/updatestu.html")
def toAddUser(request):

    return  render(request, "system/Student/addstu.html")

def toaddAll(request):
        return render(request, "system/Student/addFile.html")

#成绩
def toScoreaddlist(request):
    return render(request, "system/Score/ScoreaddFile.html")
def scorelist(request):
    return render(request, "system/Score/scoretable.html")
def tubiao(request):
    return  render(request,"tubiao.html")

视图stucrud.py

import hashlib
import json
import os
import uuid

from django.core import serializers
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.shortcuts import render
from django.http import JsonResponse, HttpResponse, StreamingHttpResponse

from demo1 import settings
from  demo1.demo import models
import openpyxl
import xlrd
import numpy as np
from pyecharts.charts import Bar,Pie,Scatter

from pyecharts.faker import Faker
from pyecharts import options as opts


######################## 图表分析开始 ##############################
def echarts(request):

    name = request.GET.get("name")

    obj_student = models.Student.objects.all().values()
    students = list(obj_student)
    excel_name = '学生信息表' + '.xlsx'
    # 准备写入的路径
    path = os.path.join(settings.MEDIA_ROOT, excel_name)
    # 写入到Excel
    write_to_excel(students, path)
    # 导入Excel 文件
    data = xlrd.open_workbook(path)
    # 载入第一个表格
    table = data.sheets()[0]
    tables = []
    # 从第2行开始读取数据,
    for rows in range(1, table.nrows - 1):
        dict_ = {"学号": "", "姓名": "", "语文": "", "数学": "", "英语": "", "政治": ""}
        dict_["学号"] = table.cell_value(rows, 0)
        dict_["姓名"] = table.cell_value(rows, 1)
        dict_["语文"] = table.cell_value(rows, 4)
        dict_["数学"] = table.cell_value(rows, 5)
        dict_["英语"] = table.cell_value(rows, 6)
        dict_["政治"] = table.cell_value(rows, 7)
        tables.append(dict_)

        # page = Page()  # 实例化page类
        score_0_10 = 0
        score_10_20 = 0
        score_20_30 = 0
        score_30_40 = 0
        score_40_50 = 0
        score_50_60 = 0
        score_60_70 = 0
        score_70_80 = 0
        score_80_90 = 0
        score_90_100 = 0

        min_score = 100
        max_score = 0
        scores=[]
        # 将各个分段的数量统计
        for i in tables:
            score = int(i[name])
            scores.append(score)
            if score > max_score:
                max_score = score
            if score < min_score:
                min_score = score

            if score in range(0, 10):
                score_0_10 = score_0_10 + 1
            elif score in range(10, 20):
                score_10_20 = score_10_20 + 1
            elif score in range(20, 30):
                score_20_30 = score_20_30 + 1
            elif score in range(30, 40):
                score_30_40 = score_30_40 + 1
            elif score in range(40, 50):
                score_40_50 = score_40_50 + 1
            elif score in range(50, 60):
                score_50_60 = score_50_60 + 1
            elif score in range(60, 70):
                score_60_70 = score_60_70 + 1
            elif score in range(70, 80):
                score_70_80 = score_70_80 + 1
            elif score in range(80, 90):
                score_80_90 = score_80_90 + 1
            elif score in range(90, 100):
                score_90_100 = score_90_100 + 1

        # 构建两个元组用以后期建表方便
        bar_x_axis_data = (
            "00-10", "10-20", "20-30", "30-40", "40-50", "50-60", "60-70", "70-80", "80-90", "90-100")
        bar_y_axis_data = (score_0_10, score_10_20, score_20_30, \
                           score_30_40, score_40_50, score_50_60, \
                           score_60_70, score_70_80, score_80_90, \
                           score_90_100)



    def response_as_json(data):
        json_str = json.dumps(data)
        response = HttpResponse(
            json_str,
            content_type="application/json",
        )
        response["Access-Control-Allow-Origin"] = "*"
        return response

    def json_response(data, code=200):
        data = {
            "code": code,
            "msg": "success",
            "data": data,
        }
        return response_as_json(data)

    def json_error(error_string="error", code=500, **kwargs):
        data = {
            "code": code,
            "msg": error_string,
            "data": {}
        }
        data.update(kwargs)
        return response_as_json(data)

    JsonResponse = json_response
    JsonError = json_error
    a=(
        Scatter()
            .add_xaxis(scores)
            .add_yaxis(name,scores)

            .set_global_opts(title_opts=opts.TitleOpts(title=name + "散点图成绩分析"))
            .dump_options_with_quotes()
    )
    c = (
        Bar()
            .add_xaxis(bar_x_axis_data)
            .add_yaxis(name,bar_y_axis_data)

            .set_global_opts(title_opts=opts.TitleOpts(title=name+"柱状图成绩分析", subtitle="各分段人数"))
            .dump_options_with_quotes()

    )
    d = (
         Pie()
            .add(name, [list(z) for z in zip(bar_x_axis_data, bar_y_axis_data)])
             .set_global_opts(title_opts=opts.TitleOpts(title=name+"饼状图成绩分析"))
             .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}"))
             .dump_options_with_quotes()

        # Pie()
         #    .add(name, bar_x_axis_data)
         #
         #    .set_global_opts()
         #    .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}"))
         #    .dump_options_with_quotes()


    )
    data={"Bar":json.loads(c),"Pie":json.loads(d),"Scatter":json.loads(a)}

    return JsonResponse(data)

######################## 图表分析结束 ##############################
######################## 导出为EXCEL文件开始 #######################

#创建文件名
def get_random_str():
    """获取UUID"""
    uuid_val = uuid.uuid4()
    uuid_str = str(uuid_val).encode('utf-8')
    md5 = hashlib.md5()
    md5.update(uuid_str)
    return md5.hexdigest()
#导出学生
def export_student_excel(request):
    """
    导出数据到excel
    :param request:
    :return:
    """

    def file_iterator(file_name, chunk_size=512):  # 用于形成二进制数据
        with open(file_name, 'rb') as f:
            while True:
                c = f.read(chunk_size)
                if c:
                    yield c
                else:
                    break
    obj_student = models.Student.objects.all().values()
    students = list(obj_student)
    # excel_name = get_random_str() + '.xlsx'
    excel_name = '学生信息表' + '.xlsx'
    # 准备写入的路径
    path = os.path.join(settings.MEDIA_ROOT, excel_name)
    # 写入到Excel
    write_to_excel(students, path)
    # 返回

    response = StreamingHttpResponse(file_iterator(path))  # 这里创建返回
    response['Content-Type'] = 'application/vnd.ms-excel'  # 注意格式
    response['Content-Disposition'] = 'attachment;filename=学生信息表.xlsx'# 注意filename 这个是下载后的名字
    return response

    # return JsonResponse(
    #     {'code': 200, "data": "/media/" + excel_name, "message": "操作成功"})


def write_to_excel(data: list, path: str):
    """
    把数据库写入excel

    """
    # 实例化一个wrokbook
    wrokbook = openpyxl.Workbook()
    # 激活一个sheet
    sheet = wrokbook.active
    # 为sheet命名
    sheet.title = 'student'
    # 准备keys
    keys = data[0].keys()
    # 写标题的第一行

    for index, item in enumerate(models.Student.get_title_list()):
        sheet.cell(row=1, column=index + 1, value=item)
    # 准备写入数据
    for index, item in enumerate(data):
        # 遍历每个元素
        for k, v in enumerate(keys):
            # 这里要从第二列开始
            sheet.cell(row=index + 2, column=k + 1, value=str(item[v]))
    # 写入到文件
    wrokbook.save(path)
######################## 导出为EXCEL文件结束 #######################
#修改学生
def edistu(request):
    if request.method == 'POST':

        sno = request.POST.get("sno", None)
        sname = request.POST.get("name", None)
        sage = request.POST.get("age", None)
        ssex = request.POST.get("sex", None)

        if models.Student.objects.filter(id=int(sno)).update( Sname=sname, Sage=sage, Ssex=ssex):

            return JsonResponse({"code": 200, "msg": "添加成功"}, safe=False)
        else:
            return JsonResponse({"code": 300, "msg": "添加失败"}, safe=False)


#删除学生
def delestu(request):
     sno=  request.GET.get("id",None)
     if models.Student.objects.filter(pk__in=[1,int(sno)]).delete():
         return JsonResponse({"code": 200, "msg": "删除成功"}, safe=False)
     else:
         return JsonResponse({"code": 300, "msg": "添加失败"}, safe=False)
#添加学生
def addstu(request):

    if request.method == 'POST':
        sno = request.POST.get("sno", None)
        sname = request.POST.get("name",None)
        sage = request.POST.get("age",None)
        ssex= request.POST.get("sex",None)

        if  models.Student.objects.create(Sno=sno,Sname=sname,Sage=sage,Ssex=ssex):

           return JsonResponse({"code": 200, "msg": "添加成功"}, safe=False)
        else:
          return  JsonResponse( {"code": 300, "msg": "添加失败"},safe=False)

 #模糊查询学生
def search(request):
    sno=request.GET.get("id")
    sname=request.GET.get("name")
    nowPage = request.GET.get("page")
    limit = request.GET.get("limit")
    if limit == "":
        limit = 5

    if sno!="":
        student =  models.Student.objects.values().filter(Sno=sno)
    if sname != "":
        student=models.Student.objects.values().filter(Sname=sname)
    paginator = Paginator(list(student), int(limit))
    if int(nowPage) >= int(paginator.num_pages):
        nowPage = paginator.num_pages
    try:
        page = paginator.page(nowPage)
    except:
        page = paginator.page(paginator.num_pages)
    data = {
          'data':list(page),
          'code':"200",
          'count':paginator.count,
          'page':page.number,
          'limit':page.__len__(),
          'pages':paginator.num_pages

     }
    return  JsonResponse(data)
#查询所有数据
def select(request):
     nowPage=request.GET.get("page")
     limit=request.GET.get("limit")
     if limit=="":
          limit=5

     student=models.Student.objects.values()
     paginator=Paginator(list(student),int(limit))
     print(list(student))
     if int(nowPage)>=int(paginator.num_pages):
          nowPage=paginator.num_pages
     try:
          page=paginator.page(nowPage)
     except:
          page=paginator.page(paginator.num_pages)

     data = {
          'data':list(page),
          'code':"200",
          'count':paginator.count,
          'page':page.number,
          'limit':page.__len__(),
          'pages':paginator.num_pages

     }
     return  JsonResponse(data)
#批量导入成绩
def importFile(request):
    # 导入必要模块
    import pandas as pd
    import csv
    if request.method == 'POST':
        file=request.FILES.get('studentfile')
        excel_type = file.name.split('.')[1]
        if not file:
            return render(request, "system/Student/addFile.html", {"msg": "请上传文件"})
        if excel_type in ['csv']:
            media_root = settings.MEDIA_ROOT
            filepath = os.path.join(media_root, file.name)
            with open(filepath, 'wb')as  fp:
                for chunk in file.chunks():
                    fp.write(chunk)
            with open(filepath, newline='', encoding='GBK')as f:
                f_csv = csv.reader(f)
                headers = next(f_csv)

                for row in f_csv:
                    models.Student.objects.update_or_create(
                         Sno=row[0],
                         Sname=row[1],
                         Sage=row[2],
                         Ssex=row[3],
                         YuWen=row[4],
                         ShuXue=row[5],
                         YingYu=row[6],
                         ZhengZhi=row[7]
                    )

            # return JsonResponse({'msg': '批量导入成功','code':'200'},json_dumps_params={'ensure_ascii':False},  safe=False)
            return render(request, "system/Student/addFile.html", {"msg": "学生批量导入成功"})
        else:
             # return  JsonResponse({'msg': '文件格式错误,请上传正确格式的文件','code':'300'}, json_dumps_params={'ensure_ascii':False}, safe=False)
             return render(request, "system/Student/addFile.html", {"msg": "文件格式错误,请上传正确格式的文件"})

index.html(登录界面)

{% load static %}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="UTF-8">
	<title>后台管理-登陆</title>
	<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
	<meta http-equiv="Access-Control-Allow-Origin" content="*">
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
	<meta name="apple-mobile-web-app-status-bar-style" content="black">
	<meta name="apple-mobile-web-app-capable" content="yes">
	<meta name="format-detection" content="telephone=no">
 <link rel="stylesheet" href="{% static 'layui/css/layui.css' %}">

	<!--[if lt IE 9]>
	<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
	<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
	<![endif]-->
	<style>
		body {
			background-image: url("{%static '/images/bg.jpg' %}");
            height: 100%;
			width: 100%;
		}

		#container {
			height: 100%;
			width: 100%;
		}

		input:-webkit-autofill {
			-webkit-box-shadow: inset 0 0 0 1000px #fff;
			background-color: transparent;
		}

		.admin-login-background {
			width: 300px;
			height: 300px;
			position: absolute;
			left: 50%;
			top: 40%;
			margin-left: -150px;
			margin-top: -100px;
		}

		.admin-header {
			text-align: center;
			margin-bottom: 20px;
			color: #ffffff;
			font-weight: bold;
			font-size: 25px
		}

		.admin-input {
			border-top-style: none;
			border-right-style: solid;
			border-bottom-style: solid;
			border-left-style: solid;
			height: 50px;
			width: 300px;
			padding-bottom: 0px;
		}

		.admin-input::-webkit-input-placeholder {
			color: #a78369
		}

		.layui-icon-username {
			color: #a78369 !important;
		}

		.layui-icon-username:hover {
			color: #9dadce !important;
		}

		.layui-icon-password {
			color: #a78369 !important;
		}

		.layui-icon-password:hover {
			color: #9dadce !important;
		}

		.admin-input-username {
			border-top-style: solid;
			border-radius: 10px 10px 0 0;
		}

		.admin-input-verify {
			border-radius: 0 0 10px 10px;
		}

		.admin-button {
			margin-top: 20px;
			font-weight: bold;
			font-size: 18px;
			width: 300px;
			height: 50px;
			border-radius: 5px;
			background-color: #a78369;
			border: 1px solid #d8b29f
		}

		.admin-icon {
			margin-left: 260px;
			margin-top: 10px;
			font-size: 30px;
		}

		i {
			position: absolute;
		}

		.admin-captcha {
			position: absolute;
			margin-left: 205px;
			margin-top: -40px;
		}

		.title {
			margin: auto;
		}

	</style>
</head>

<div id="container">
	<div></div>
	<div class="admin-login-background">
		<div class="admin-header">
			<span>简单的成绩管理</span>
		</div>
		<form class="layui-form" action="/login/"method="post" >
			<div>
				<i class="layui-icon layui-icon-username admin-icon"></i>
				<input type="text" name="username" placeholder="请输入用户名" autocomplete="off" class="layui-input admin-input admin-input-username" >
			</div>
			<div>
				<i class="layui-icon layui-icon-password admin-icon"></i>
				<input type="password" name="pwd" placeholder="请输入密码" autocomplete="off" class="layui-input admin-input" >
			</div>




            <input class="layui-btn admin-button" type="submit" value="登录" >

		</form>

		<span style="color: red" >{{ msg }}</span>
	</div>
</div>
	<script type="text/javascript" src="{% static 'layui/layui.js' %}"></script>
	<script type="text/javascript">


		layui.use(['form','layer','jquery'],function(){
			var form = layui.form,
					layer = parent.layer === undefined ? layui.layer : top.layer
			      $ = layui.jquery,


			        //登录按钮
					form.on("submit(login)",function(data){

						console.log(data.field)

						$.ajax({
							type:"post",
							url:"/login/",
							data:{
								username:data.field.username,
								pwd:data.field.password,

							},
							success:function (result) {
								console.log(result);
								if(result.code==200){
									//设置用户登录状态

									layer.msg("登录成功",function () {

										window.location.href="/stuList/";


									});

								}
								else {
									layer.msg(result.msg,{icon:5});

								}

							}
						});
						return false;
					});


		});


	</script>




</body>
</html>

stutable.html(主界面)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="utf-8">
    <title>Layui</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <link rel="stylesheet" href="../static/layui/css/layui.css" th:href="@{/layui/css/layui.css}" media="all">
    <!-- 注意:如果你直接复制所有代码到本地,上述css路径需要改成你本地的 -->
</head>

<body>
    <!--搜索条件开始 -->
    <fieldset class="layui-elem-field layui-field-title" style="margin-top: 20px;">
        <legend>查询条件</legend>
    </fieldset>
    <form class="dataFrm" >
        <div class="layui-form-item">
            <div class="layui-inline">
                <label class="layui-form-label">学号:</label>
                <div class="layui-input-inline">
                    <input type="tel" name="id"  id="id" autocomplete="off" class="layui-input">
                </div>
            </div>
            <div class="layui-inline">
                <label class="layui-form-label">姓名:</label>
                <div class="layui-input-inline">
                    <input type="text" name="name"  id="name" autocomplete="off" class="layui-input">
                </div>
            </div>

            <div class="layui-inline">
                <button th:style=" ${#lists.contains(session.aclValue,'101005')}?'':'display:none'" type="button" class="layui-btn  search_btn  layui-btn-normal layui-icon layui-icon-search select-btn"
                        id="search_btn">搜索</button>
                <button type="reset" class="layui-btn  layui-btn-warm    layui-icon layui-icon-refresh">重置</button>

            </div>
            </div>

        </div>




    </form>
    <!--搜索条件结束 -->
    <!-- 数据表格开始 -->
    <table class="layui-hide" id="userTable" lay-data="id:userTable" lay-filter="userTable"></table>

    <script type="text/html" id="toolbarDemo">


    <button class="layui-btn layui-btn-sm" lay-event="add">添加</button>


    <button  class="layui-btn layui-btn-sm" id="batchDelete" lay-event="batchDelete">批量导入</button>
     <button  class="layui-btn layui-btn-sm" id="fenxi" lay-event="fenxi">分析</button>

    <a class="layui-btn layui-btn-sm"  href="/export_student_excel/" id="export" >导出数据</a>
    </script>

    <script type="text/html" id="barDemo">

  <a  class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
  <a  class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
</script>
    <!-- 数据表格结束 -->


    <script th:src="@{/layui/layui.js}" src="../static/layui/layui.js" charset="utf-8"></script>
    <!-- 注意:如果你直接复制所有代码到本地,上述 JS 路径需要改成你本地的 -->

    <script type="text/javascript"  >
        layui.use(['form', 'layer', 'table', 'laytpl', 'laydate'], function () {
            var form = layui.form,
                layer = parent.layer === undefined ? layui.layer : top.layer,
                $ = layui.jquery,
                laytpl = layui.laytpl,
                table = layui.table,
                laydate = layui.laydate;

            //绑定时间选择器
            laydate.render({
                elem: '#startTime'

            });
            laydate.render({
                elem: '#endTime'

            });

            //渲染数据表格
           table.render({
                elem: '#userTable'
                , url: "/select"
                ,parseData: function(res){ //res 即为原始返回的数据
                    return {
                        "code": res.code, //解析接口状态
                         "count": res.count, //解析数据长度
                          "page":res.page,//当前页
                        "limit":res.limit,//当前页数据条数
                        "data": res.data,//解析数据列表
                        "pages":res.pages

                    };
                }

                   ,response: {

                    statusCode: 200 //规定成功的状态码,默认:0

                   }
                 , toolbar: '#toolbarDemo' //开启头部工具栏,并为其绑定左侧模板
                , page: true

                , id: 'table'
                , defaultToolbar: ['filter', 'exports', 'print',]
                , title: '用户数据表'
                , height: 'full-200'
                , cols:
                    [
                    [
                    { type: 'checkbox', fixed: 'left' }

                    , { field: 'Sno', title: '学号', width: 100, fixed: 'left', align: 'center'  , sort: true}
                    , { field: 'Sname', title: '姓名', width: 100, align: 'center' }
                    , {field: 'Sage', title: '年龄', width: 100, align: 'center'}
                        , {field: 'Ssex', title: '性别', width: 100, align: 'center'}
                     , {field: 'YuWen', title: '语文', width: 100, align: 'center'}
                         , {field: 'ShuXue', title: '数学', width: 100, align: 'center'}
                             , {field: 'YingYu', title: '英语', width: 100, align: 'center'}
                                 , {field: 'ZhengZhi', title: '政治', width: 100, align: 'center'}
                    , { fixed: 'right', title: '操作', toolbar: '#barDemo', width: 150, align: 'center' }
                    ]
                    ]

            });





            //监听头部工具栏事件
            table.on("toolbar(userTable)", function (obj) {
                var data = obj.data; //获得当前行数据
                var layEvent = obj.event; //获得 lay-event 对应的值(也可以是表头的 event 参数对应的值)
                var tr = obj.tr; //获得当前行 tr 的 DOM 对象(如果有的话)
                switch (layEvent) {
                    case "add":
                       addUser();
                        break;
                    case 'batchDelete':

                       addAll();
                        break;
                      case 'fenxi':

                         fenxi();
                        break;

                };


            });
             //分析
            function fenxi(data) {
                var index = layui.layer.open({
                    title: "成绩统计分析",
                    type: 2,
                    content:  "/tubiao",
                    area:["450px","600px"],
                    maxmin:true,
                    success: function (layero, index) {
                        var body = layui.layer.getChildFrame('body', index);

                        setTimeout(function () {
                            layui.layer.tips('点击此处返回用户列表', '.layui-layer-setwin .layui-layer-close', {
                                tips: 3
                            });
                        }, 100)
                    }
                })



            }
            //添加用户
            function addUser(data) {
                var index = layui.layer.open({
                    title: "添加用户",
                    type: 2,
                    content:  "/addstu.html",
                    area:["450px","600px"],
                    maxmin:true,
                    success: function (layero, index) {
                        var body = layui.layer.getChildFrame('body', index);

                        setTimeout(function () {
                            layui.layer.tips('点击此处返回用户列表', '.layui-layer-setwin .layui-layer-close', {
                                tips: 3
                            });
                        }, 100)
                    }
                })



            }


          //批量导入
            function addAll(data) {
                var index = layui.layer.open({
                    title: "批量添加学生",
                    type: 2,
                    content:  "/addFile.html",
                    area:["450px","600px"],
                    maxmin:true,
                    success: function (layero, index) {
                        var body = layui.layer.getChildFrame('body', index);

                        setTimeout(function () {
                            layui.layer.tips('点击此处返回列表', '.layui-layer-setwin .layui-layer-close', {
                                tips: 3
                            });
                        }, 100)
                    }
                })



            }


            //模糊查询
            $('.dataFrm .search_btn').on('click', function () {
                var id = $('#id').val();
                var name = $('#name').val();


                //执行重载
                if (id == "" && name == "") {
                    layer.msg("请先输入数据再查询")

                } else {
                    table.reload('table', {
                        url: "/search/"
                        , method: "get"
                        , where: {

                            "id": id,
                            "name": name,


                        }

                        , page: {
                            curr: 1 //重新从第 1 页开始
                        }

                    })
                }

            });


            //工具条事件
            table.on('tool(userTable)', function (obj) { //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
                var data = obj.data; //获得当前行数据
                var layEvent = obj.event; //获得 lay-event 对应的值(也可以是表头的 event 参数对应的值)
                var tr = obj.tr; //获得当前行 tr 的 DOM 对象(如果有的话)

                if (layEvent === 'detail') { //查看


                } else if (layEvent === 'del') { //删除
                    layer.confirm('真的删除行么', function (index) {

                        layer.close(index);
                        $.ajax({
                            url:"/delestu/?id="+data.id,
                            type:"GET",
                            success(res){
                                if (res.code===200){
                                 layer.msg("删除成功");

                                    setTimeout(function(){


                                         //刷新父页面
                                        parent.location.reload();
                                           },1000);


                   return false;
                                }else{
                                    layer.msg("删除失败");
                                }

                            },
                            error(){
                                layer.msg("删除失败");
                            }

                        });

                    });
                } else if (layEvent === 'edit') { //编辑
                    // layer.alert('编辑行:<br>'+ JSON.stringify(data))

                    openUpdateUser(data);
                }
            });



            //打开修改页面
            
            function  openUpdateUser(data) {
                var index = layui.layer.open({
                    title: "编辑学生",
                    type: 2,
                    content:  "/updatestu.html",
                    area:["450px","600px"],
                    maxmin:true,
                    success: function (layero, index) {
                        var body = layui.layer.getChildFrame('body', index);
                        if (data) {

                            body.find(".sno").val(data.Sno);//id
                            body.find(".name").val(data.Sname);  //用户名
                            body.find(".age").val(data.Sage);  //密码
                            body.find(".sex").val(data.Ssex);//真实姓名




                             form.render();
                        }
                        setTimeout(function () {
                            layui.layer.tips('点击此处返回用户列表', '.layui-layer-setwin .layui-layer-close', {
                                tips: 3
                            });
                        }, 500)
                    }
                })


            }



        });
    </script>

</body>

</html>

addstu.html(添加学生界面)

{% load static %}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" th:href="@{/css/formSelects-v4.css}" href="../static/css/formSelects-v4.css" />
    <link rel="stylesheet" href="../static/layui/css/layui.css" th:href="@{/layui/css/layui.css}" media="all">
    <title>Document</title>

</head>
<body>
    <!-- 添加和修改的弹出层开始 -->

    <div  id="saveOrUpdateDiv">


        <form class="layui-form" action="" lay-filler="dataFrm" id="dataFrm" >
 <div class="layui-form-item">
                <div class="layui-inline">
                    <label class="layui-form-label">学号:</label>
                    <div class="layui-input-inline">
                        <input type="text"  lay-verify="required"  required="required" autocomplete="off"
                            class="layui-input sno">
                    </div>
                </div>
            </div>
            <div class="layui-form-item">
                <div class="layui-inline">
                    <label class="layui-form-label">姓名:</label>
                    <div class="layui-input-inline">
                        <input type="text"  lay-verify="required"  required="required" autocomplete="off"
                            class="layui-input name">
                    </div>
                </div>
            </div>
            <div class="layui-form-item">
                <div class="layui-inline">
                    <label class="layui-form-label">年龄:</label>
                    <div class="layui-input-inline">
                        <input type="text"  lay-verify="required|userpw" autocomplete="off"
                            class="layui-input age">
                    </div>
                </div>
            </div>
            <div class="layui-form-item">
                <div class="layui-inline">
                    <label class="layui-form-label">性别:</label>
                    <div class="layui-input-inline">
                        <input type="text"  lay-verify="required|truename" autocomplete="off"
                               class="layui-input  sex">
                    </div>
                </div>
            </div>


            <div class="layui-form-item">
                <div class="layui-input-block">
                    <button type="button" class="layui-btn   layui-btn-normal layui-btn-sm layui-icon layui-icon-ok"
                            lay-submit lay-filter="doSubmit">添加</button>
                    <button type="reset"
                            class="layui-btn  layui-btn-warm  layui-btn-sm  layui-icon  layui-icon-refresh">重置</button>
                </div>
            </div>


        </form>



    </div>
    <script th:src="@{/layui/layui.js}" src="../static/layui/layui.js" charset="utf-8"></script>

    <!-- 注意:如果你直接复制所有代码到本地,上述 JS 路径需要改成你本地的 -->
<script >

    //全局定义一次, 加载formSelects
    layui.config({
        base: "{%static '/js/' %}"  //此处路径请自行处理, 可以使用绝对路径
    }).extend({
        formSelects: 'formSelects'
    });

     layui.use(['form', 'layer', 'table','formSelects', 'laytpl', 'laydate'], function () {
    var form = layui.form,
        layer = parent.layer === undefined ? layui.layer : top.layer,
        $ = layui.jquery,
        laytpl = layui.laytpl,
        table = layui.table,

        laydate = layui.laydate;
       var  formSelects=layui.formSelects;
        
    
         form.on("submit(doSubmit)",function(data){



                 // 实际使用时的提交信息


             var name =$('.name').val();
             var age =$('.age').val();
             var sex =$('.sex').val();
             var sno =$('.sno').val();


                $.ajax({
                     type: "post",
                     url:"/addstu/",
                    data: {
                         "sno":sno,
                        "name": name,
                        "age": age,
                        "sex": sex,
                         },
                        success(res) {
                            if (res.code ===200) {
                                layer.msg(res.msg, {icon: 6 });


                            } else {
                                layer.msg(res.msg, {icon: 5});
                            }

                        }


                });
                    setTimeout(function(){

                         layer.closeAll("addstu.html");
                         //刷新父页面
                         parent.location.reload();
                     },1000);


                   return false;


                  return false;
    })



        });
    </script>
</body>

</html>

updatestu.html(修改学生界面)

{% load static %}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <link rel="stylesheet" href="../static/layui/css/layui.css" th:href="@{/layui/css/layui.css}" media="all">
    <title>Document</title>
</head>
<body>
    <!-- 添加和修改的弹出层开始 -->

    <div  id="saveOrUpdateDiv">

        <form class="layui-form" action="" lay-filler="dataFrm" id="dataFrm" >

            <div class="layui-form-item">

                <div class="layui-inline">
                    <label class="layui-form-label">学号:</label>
                    <div class="layui-input-inline">
                        <input type="text"  readonly="readonly"  required="required" autocomplete="off" class="layui-input sno">
                    </div>
                </div>
            </div>
            <div class="layui-form-item">
                <div class="layui-inline">
                    <label class="layui-form-label">姓名:</label>
                    <div class="layui-input-inline">
                        <input type="text"  lay-verify="required"  required="required" autocomplete="off"
                            class="layui-input name">
                    </div>
                </div>
            </div>
            <div class="layui-form-item">
                <div class="layui-inline">
                    <label class="layui-form-label">年龄:</label>
                    <div class="layui-input-inline">
                        <input type="text"  lay-verify="required|userpw" autocomplete="off"
                            class="layui-input age">
                    </div>
                </div>
            </div>
            <div class="layui-form-item">
                <div class="layui-inline">
                    <label class="layui-form-label">性别:</label>
                    <div class="layui-input-inline">
                        <input type="text"  lay-verify="required|truename" autocomplete="off"
                               class="layui-input  sex">
                    </div>
                </div>
            </div>


{#            <div class="layui-form-item">#}
{#                <div class="layui-row laui-icon-xs12">#}
{#                    <label class="layui-form-label">角色:</label>#}
{#                    <div class="layui-input-inline">#}
{#                        <select class="roleIds" name="roleIds" xm-select="selectId">#}
{##}
{#                        </select>#}
{#                    </div>#}
{#                </div>#}
{#            </div>#}

            <div class="layui-form-item">
                <div class="layui-input-block">
                    <button type="button" class="layui-btn   layui-btn-normal layui-btn-sm layui-icon layui-icon-ok"
                        lay-submit="" lay-filter="updateSubmit">修改</button>
                    <button type="reset"
                        class="layui-btn  layui-btn-warm  layui-btn-sm  layui-icon  layui-icon-refresh">重置</button>
                </div>
            </div>


         </form>



    </div>
    <script th:src="@{/layui/layui.js}" src="../static/layui/layui.js" charset="utf-8"></script>
    <!-- 注意:如果你直接复制所有代码到本地,上述 JS 路径需要改成你本地的 -->
<script >
    //全局定义一次, 加载formSelects
    layui.config({
        base: "{%static '/js/' %}" //此处路径请自行处理, 可以使用绝对路径
    }).extend({
        formSelects: 'formSelects'
    });

    layui.use(['form', 'layer', 'table',"formSelects" ,'laytpl', 'laydate'], function () {
    var form = layui.form,
        layer = parent.layer === undefined ? layui.layer : top.layer,
        $ = layui.jquery,
        laytpl = layui.laytpl,
        table = layui.table,
        laydate = layui.laydate;
     var   formSelects=layui.formSelects;
        
         form.on("submit(updateSubmit)",function(data){


              //弹出loading


         // 实际使用时的提交信息

             var sno=$('.sno').val();
            var name =$('.name').val();
            var age =$('.age').val();
             var sex =$('.sex').val();


         //弹出loading
         var index = layer.msg('数据提交中,请稍候',{icon: 16,time:false,shade:0.8});
         $.ajax({
             url:"/edistu/",
             // data:$("#dataFrm").serialize(),
             data:{
                 "sno":sno,
                 "name":name,
                 "age":age,
                 "sex":sex ,

             },
                type:"post",
                 success(res){
                 if(res.code===200){
                     layer.msg("操作成功!",{icon:6});
                 }
             },

             error(){
                 layer.msg("操作失败!",{icon:5});
             }
         });
         setTimeout(function(){
              layer.closeAll(index);
             layer.closeAll("updatestu.html");
             //刷新父页面
             parent.location.reload();
         },1000);


         return false;
     });



         /**
          * 配置下拉框
          */
          var id=$('.id').val();
          layui.config(id);
         formSelects.config("selectId",{

             type:"POST",
             searchUrl:"/role/allRole?userId="+id,

             keyName: "roleName", //下拉框中的文本内容,要与返回的数据中对相应的key一致
             keyVal: "id" //

         },true);

     });



    </script>
</body>

</html>

addFile.html(批量导入学生界面)

{% load static %}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" th:href="@{/css/formSelects-v4.css}" href="../static/css/formSelects-v4.css" />
    <link rel="stylesheet" href="../static/layui/css/layui.css" th:href="@{/layui/css/layui.css}" media="all">
    <title>Document</title>

</head>
<body>
    <!-- 添加和修改的弹出层开始 -->

    <div  id="saveOrUpdateDiv">

<form  method="post" action="/file/" enctype="multipart/form-data">


        <input type="file" name="studentfile" />
        <input type="submit" value="上传" />
<span style="background: red">{{ msg }}</span>

</form>

    </div>
    <script th:src="@{/layui/layui.js}" src="../static/layui/layui.js" charset="utf-8"></script>

    <!-- 注意:如果你直接复制所有代码到本地,上述 JS 路径需要改成你本地的 -->
<script >

    </script>
</body>

</html>

tubiao.html(图表分析界面)

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Awesome-pyecharts</title>
    <script src="https://cdn.bootcss.com/jquery/3.0.0/jquery.min.js"></script>
    <script type="text/javascript" src="https://assets.pyecharts.org/assets/echarts.min.js"></script>

</head>
<body>
<select id="select">

    <option value="语文">语文</option>
    <option value="数学">数学</option>
    <option value="英语">英语</option>
    <option value="政治">政治</option>

</select>
{#<input type="text" id="name" name="name" class="name">#}

<button id="chaxun" > 查询</button>
<hr>
<div  id="bar" style="width:400px; height:400px;float: left"></div>
<div  id="pie" style="width:1100px; height:500px; float: left"></div>
<div  id="Scatter" style="width:1100px; height:500px; float: left"></div>
<script>
    var bar = echarts.init(document.getElementById('bar'), 'white', {renderer: 'canvas'});
     var pie = echarts.init(document.getElementById('pie'), 'white', {renderer: 'canvas'});

     var Scatter=echarts.init(document.getElementById('Scatter'), 'white', {renderer: 'canvas'});
$("#chaxun").click(

     function fetchData() {
            var name=$("#select").val();
         $.ajax({
             type: "GET",
             url: "/echarts/?name=" + name,
             dataType: 'json',
             success: function (result) {
                 bar.setOption(result.data.Bar);
                 pie.setOption(result.data.Pie);
                 Scatter.setOption(result.data.Scatter)
             }
         });
     }


    )

</script>
</body>
</html>

Layui需要的css,js文件自行下载引入,放在static文件夹下