Compare commits

...

14 Commits

Author SHA1 Message Date
wangsiyuan ba95a8e886 更新 mysql.sql 2023-12-28 16:34:38 +08:00
wangsiyuan ca8cbadccc 更新 User.py 2023-12-28 16:34:35 +08:00
wangsiyuan eaea8e1f0f 创建 Teacher.py 2023-12-28 16:34:33 +08:00
wangsiyuan 638dded5a1 创建 Student.py 2023-12-28 16:34:29 +08:00
wangsiyuan 95bd7c7e65 更新 database_manager.py 2023-12-28 16:34:27 +08:00
wangsiyuan e11cddd05e 更新 views.py 2023-12-28 16:34:24 +08:00
wangsiyuan 1ed2e473e1 更新 register.html 2023-12-28 16:34:22 +08:00
wangsiyuan 3694a91c74 更新 profile.html 2023-12-28 16:34:20 +08:00
wangsiyuan f3b0064dc7 更新 login.html 2023-12-28 16:34:17 +08:00
wangsiyuan fca154ee23 更新 attendance.html 2023-12-28 16:34:15 +08:00
wangsiyuan d7a82f6780 更新 attendance-reminder.html 2023-12-28 16:34:13 +08:00
wangsiyuan 1bb907c71e 更新 announcement.html 2023-12-28 16:34:10 +08:00
wangsiyuan 20bb7bd1f6 创建 menu.js 2023-12-28 16:34:08 +08:00
wangsiyuan 756e2ca96e 创建 logout.js 2023-12-28 16:34:05 +08:00
14 changed files with 200 additions and 142 deletions

9
app/static/js/logout.js Normal file
View File

@ -0,0 +1,9 @@
var $ = layui.jquery; // 获取Layui的jQuery对象
$('#logoutLink').on('click', function () {
// 向后端发送登出请求
$.get('/logout', function (data) {
// 重定向到登录页面,或根据后端响应做其他处理
window.location.href = '/login';
});
});

11
app/static/js/menu.js Normal file
View File

@ -0,0 +1,11 @@
$.get('/api/menu', function (menuItems) {
var menuList = $('.layui-nav.layui-nav-tree');
menuList.empty();
menuItems.forEach(function (item) {
var href = item.path || 'javascript:void(0);'; // 提供一个默认值
menuList.append('<li class="layui-nav-item"><a href="' + href + '">' + item.name + '</a></li>');
});
layui.element.render('nav', 'test');
});

View File

@ -44,45 +44,45 @@
</div>
<div class="layui-body">
<div class="layui-container">
<div class="layui-row">
<div class="layui-col-xs12">
<h1 class="layui-header">公告</h1>
</div>
</div>
<div class="layui-row">
<div class="layui-col-xs12">
<h1 class="layui-header">公告</h1>
</div>
</div>
<div class="layui-row">
<div class="layui-col-md6">
<fieldset class="layui-elem-field">
<legend>今日课程</legend>
<div class="layui-field-box">
<!-- 这里可以动态列出今日课程 -->
<p>1. 数学 - 上午9:00</p>
<p>2. 物理 - 下午1:00</p>
<p>3. 文学 - 下午3:00</p>
</div>
</fieldset>
<div class="layui-row">
<div class="layui-col-md6">
<fieldset class="layui-elem-field">
<legend>今日课程</legend>
<div class="layui-field-box">
<!-- 这里可以动态列出今日课程 -->
<p>1. 数学 - 上午9:00</p>
<p>2. 物理 - 下午1:00</p>
<p>3. 文学 - 下午3:00</p>
</div>
</fieldset>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="static/jquery.min.js"></script> <!-- 确保已经引入jQuery -->
<script src="static/layui.js"></script>
<script>
// 请求后端获取菜单数据
$.get('/api/menu', function (menuItems) {
var menuList = $('.layui-nav.layui-nav-tree');
menuList.empty();
$.get('/api/menu', function (menuItems) {
var menuList = $('.layui-nav.layui-nav-tree');
menuList.empty();
menuItems.forEach(function (item) {
var href = item.path || 'javascript:void(0);'; // 提供一个默认值
menuList.append('<li class="layui-nav-item"><a href="' + href + '">' + item.name + '</a></li>');
menuItems.forEach(function (item) {
var href = item.path || 'javascript:void(0);'; // 提供一个默认值
menuList.append('<li class="layui-nav-item"><a href="' + href + '">' + item.name + '</a></li>');
});
layui.element.render('nav', 'test');
});
layui.element.render('nav', 'test');
});
layui.use(['jquery'], function () {
var $ = layui.jquery; // 获取Layui的jQuery对象

View File

@ -69,7 +69,7 @@
src="//unpkg.com/outeres@0.0.10/img/layui/icon-v2.png"
class="layui-nav-img"
/>
{{ session.nickname }}
{{ session.name }}
</a>
<dl class="layui-nav-child">
<dd><a href="/home/profile">资料</a></dd> <!-- 修改这里的href指向/profile -->
@ -124,32 +124,9 @@
<script src="static/jquery.min.js"></script> <!-- 确保已经引入jQuery -->
<script src="static/layui.js"></script>
<script src="/static/js/menu.js"></script>
<script src="/static/js/logout.js"></script>
<script>
// 请求后端获取菜单数据
$.get('/api/menu', function (menuItems) {
var menuList = $('.layui-nav.layui-nav-tree');
menuList.empty();
menuItems.forEach(function (item) {
var href = item.path || 'javascript:void(0);'; // 提供一个默认值
menuList.append('<li class="layui-nav-item"><a href="' + href + '">' + item.name + '</a></li>');
});
layui.element.render('nav', 'test');
});
layui.use(['jquery'], function () {
var $ = layui.jquery; // 获取Layui的jQuery对象
$('#logoutLink').on('click', function () {
// 向后端发送登出请求
$.get('/logout', function (data) {
// 重定向到登录页面,或根据后端响应做其他处理
window.location.href = '/login';
});
});
});
layui.use(['layer'], function () {
var layer = layui.layer;

View File

@ -67,31 +67,10 @@
<script src="static/jquery.min.js"></script> <!-- 确保已经引入jQuery -->
<script src="static/layui.js"></script>
<script src="/static/js/menu.js"></script>
<script src="/static/js/logout.js"></script>
<script>
// 请求后端获取菜单数据
$.get('/api/menu', function (menuItems) {
var menuList = $('.layui-nav.layui-nav-tree');
menuList.empty();
menuItems.forEach(function (item) {
var href = item.path || 'javascript:void(0);'; // 提供一个默认值
menuList.append('<li class="layui-nav-item"><a href="' + href + '">' + item.name + '</a></li>');
});
layui.element.render('nav', 'test');
});
layui.use(['jquery'], function () {
var $ = layui.jquery; // 获取Layui的jQuery对象
$('#logoutLink').on('click', function () {
// 向后端发送登出请求
$.get('/logout', function (data) {
// 重定向到登录页面,或根据后端响应做其他处理
window.location.href = '/login';
});
});
});
// 请求后端获取菜单数
</script>
</body>
</html>

View File

@ -20,8 +20,8 @@
<div class="layui-input-prefix">
<i class="layui-icon layui-icon-username"></i>
</div>
<input type="text" name="username" value="" lay-verify="required" placeholder="手机号"
lay-reqtext="请填写手机号" autocomplete="off" class="layui-input" lay-affix="clear">
<input type="text" name="number" value="" lay-verify="required" placeholder="学号/工号"
lay-reqtext="学号/工号" autocomplete="off" class="layui-input" lay-affix="clear">
</div>
</div>
<div class="layui-form-item">
@ -64,9 +64,6 @@
data: data.field, // 表单数据
dataType: 'json',
success: function (response) {
// 根据返回的结果进行操作
// 如果成功,可能会重定向到其他页面
// 如果失败,可能会显示错误信息
if (response.success) {
window.location.href = '/attendance-reminder'; // 或者你的成功页面
} else {

View File

@ -14,7 +14,6 @@
<div class="layui-header">
<div class="layui-logo layui-hide-xs layui-bg-black" href="/home">网上上课点名系统</div>
</div>
<div class="layui-body">
<!-- 内容主体区域 -->
<div style="padding: 15px">
@ -30,14 +29,6 @@
<input type="file" name="avatar"/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">昵称:</label>
<div class="layui-input-block">
<input type="text" name="nickname" required lay-verify="required"
placeholder="请输入新的昵称"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" type="submit">更新</button>

View File

@ -27,7 +27,7 @@
<div class="layui-input-prefix">
<i class="layui-icon layui-icon-username"></i>
</div>
<input type="text" name="nickname" value="" lay-verify="required" placeholder="昵称"
<input type="text" name="name" value="" lay-verify="required" placeholder="姓名"
autocomplete="off" class="layui-input" lay-affix="clear">
</div>
</div>
@ -36,8 +36,9 @@
<div class="layui-input-prefix">
<i class="layui-icon layui-icon-cellphone"></i>
</div>
<input type="text" name="cellphone" value="" lay-verify="required|phone" placeholder="手机号"
lay-reqtext="请填写手机号" autocomplete="off" class="layui-input" id="reg-cellphone">
<input type="text" name="number" value="" placeholder="学号X开头/工号G开头"
lay-reqtext="请填写学号/工号" autocomplete="off" class="layui-input" id="reg-number"
lay-verify="customRule">
</div>
</div>
<div class="layui-form-item demo-reg-item">
@ -58,15 +59,6 @@
placeholder="确认密码" autocomplete="off" class="layui-input" lay-affix="eye">
</div>
</div>
<div class="layui-form">
<div class="layui-form-item">
<label class="layui-form-label">身份</label>
<div class="layui-input-block">
<input type="radio" name="identity" value="teacher" title="教师" checked>
<input type="radio" name="identity" value="student" title="学生">
</div>
</div>
</div>
<div class="layui-form-item">
<button class="layui-btn layui-btn-fluid" type="submit" lay-submit lay-filter="btnRegister">注册</button>
</div>
@ -88,7 +80,23 @@
if (value !== passwordValue) {
return '两次密码输入不一致';
}
},
customRule: function (value, item) {
// 首先检查是否以X或G开头
if (!value.startsWith('X') && !value.startsWith('G')) {
return '学号必须以X开头工号必须以G开头';
}
// 如果以X开头检查长度是否为13位
if (value.startsWith('X') && value.length !== 13) {
return '学号长度必须为13位';
}
// 如果以G开头检查长度是否为5位
if (value.startsWith('G') && value.length !== 5) {
return '工号长度必须为5位';
}
}
});
layui.use(['form', 'layer'], function () {
@ -99,10 +107,9 @@
form.on('submit(btnRegister)', function (data) {
// 构建要提交的数据对象
var postData = {
nickname: data.field.nickname, // 昵称
cellphone: data.field.cellphone, // 手机号
name: data.field.name, // 昵称
number: data.field.number, // 手机号
password: data.field.password, // 密码
identity: data.field.identity // 身份
};
// 发送AJAX POST请求
@ -141,3 +148,4 @@
</body>
</html>
xw

View File

@ -1,7 +1,9 @@
from flask import Flask, request, redirect, url_for, render_template, session, jsonify
from flask import Flask, redirect, url_for, render_template, session, jsonify
from db.connection import MySQLPool
from config import SECRET_KEY
from db.database_manager import DatabaseManager
from models.Student import Student
from models.Teacher import Teacher
from models.User import User
app = Flask(__name__, static_folder='static')
@ -24,17 +26,29 @@ def index():
def register():
if request.method == 'POST':
data = request.get_json()
# print(data)
print(data)
user = User(
nickname=data.get('nickname'),
phone_number=data.get('cellphone'), # 确保JSON中的键和这里匹配
password=data.get('password'),
identity=data.get('identity'),
status=True # 或者根据你的逻辑设置
name=data.get('name'),
number=data.get('number'),
password=data.get('password'), # 确保密码安全处理
status=True
)
identity = check_identity(user.number)
db_manager = DatabaseManager()
if not db_manager.user_exists(user.phone_number):
if not db_manager.user_exists(user.number):
db_manager.insert_user(user)
user_id = db_manager.query_user_id(user.number)
if identity == "teacher":
teacher = Teacher(name=user.name, teacher_number=user.number, user_id=user_id)
db_manager.insert_teacher(teacher)
else: # assumed student
class_name = user.number[1:5] + "" + user.number[5:7] + ""
major_id = user.number[7:10]
student = Student(student_name=user.name, student_number=user.number, user_id=user_id,
major_id=major_id,
class_name=class_name)
print(student)
db_manager.insert_student(student)
return jsonify({"success": True, "message": "注册成功"})
else:
return jsonify({"success": False, "message": "用户已存在"})
@ -42,23 +56,36 @@ def register():
return render_template('register.html')
def check_identity(number):
identity = None
if number[0] == 'G':
identity = "teacher"
return identity
else:
identity = "student"
return identity
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
else:
phone_number = request.form['username']
print(request.form)
number = request.form['number']
password = request.form['password']
print(number, password)
db_manager = DatabaseManager()
result = db_manager.valid_login(phone_number, password) # 获取验证结果
result = db_manager.valid_login(number, password) # 获取验证结果
# 确保用户已验证且活跃(未被禁用)
if result['valid'] and result['status'] == 1:
# 登录成功
session['username'] = phone_number
session['role'] = result['identity'] # 设置用户角色
session['nickname'] = result['nickname']
session['username'] = number
session['role'] = check_identity(number)
print(session['role'])
session['name'] = result['name']
return jsonify(success=True, message="登录成功")
elif not result['status']:
# 用户被禁用的情况
@ -154,6 +181,14 @@ def get_course_type():
return jsonify(course_info)
@app.route('/api/get-announcement-info', methods=['GET'])
def get_announcement_info():
db_manager = DatabaseManager()
announcement_info = db_manager.get_announcement_info()
return jsonify(course_info)
@app.route('/attendance', methods=['GET', 'POST'])
def course_checkin():
return render_template('attendance.html')

View File

@ -30,33 +30,33 @@ class DatabaseManager:
conn.close()
def user_exists(self, phone_number):
sql = "SELECT 1 FROM user WHERE phone_number=%s LIMIT 1"
sql = "SELECT 1 FROM user WHERE number=%s LIMIT 1"
result = self.fetch(sql, (phone_number,))
return len(result) > 0
def insert_user(self, user):
sql = """
INSERT INTO user (nickname, phone_number, password, identity, status)
VALUES (%s, %s, %s, %s, %s)
INSERT INTO user (name, number, password, status)
VALUES (%s, %s, %s, %s)
"""
data = (user.nickname, user.phone_number, user.password, user.identity, user.status)
data = (user.name, user.number, user.password, user.status)
# print(data)
return self.execute(sql, data)
def valid_login(self, phone_number, password_attempt):
def valid_login(self, number, password_attempt):
# SQL查询获取用户的哈希密码身份和状态
sql = "SELECT password, identity, status,nickname FROM user WHERE phone_number=%s LIMIT 1"
result = self.fetch(sql, (phone_number,))
sql = "SELECT password, status,name FROM user WHERE number=%s LIMIT 1"
result = self.fetch(sql, (number,))
print(result)
if result:
stored_hash = result[0]['password'] # 假设结果是密码字段
identity = result[0]['identity'] # 用户身份
status = result[0]['status'] # 用户状态
nickname = result[0]['nickname']
name = result[0]['name']
# 使用bcrypt进行密码验证
if bcrypt.checkpw(password_attempt.encode('utf-8'), stored_hash.encode('utf-8')):
# 密码匹配,返回登录成功,身份和状态
return {'valid': True, 'identity': identity, 'status': status, 'nickname': nickname}
return {'valid': True, 'status': status, 'name': name}
# 密码不匹配或用户不存在,返回登录失败
return {'valid': False}
@ -73,7 +73,7 @@ class DatabaseManager:
def get_current_teacher_courses(self, phone_number):
# 根据电话号码查询user_id
user_sql = "SELECT user_id FROM user WHERE phone_number = %s"
user_sql = "SELECT user_id FROM user WHERE number = %s"
user_result = self.fetch(user_sql, (phone_number,))
if user_result:
@ -100,3 +100,28 @@ class DatabaseManager:
result = self.fetch(sql)
return result
def get_announcement_info(self):
sql = "SELECT course_name, course_type FROM course"
result = self.fetch(sql)
return result
def insert_teacher(self, teacher):
sql = "INSERT INTO teacher (name, user_id,teacher_number) VALUES (%s, %s, %s);"
data = (teacher.name, teacher.user_id,teacher.teacher_number)
print(data)
return self.execute(sql, data)
def query_user_id(self, phone_number):
sql = "SELECT user_id from user WHERE number = %s;"
data = self.fetch(sql, phone_number)
return data[0]['user_id']
def insert_student(self, student):
sql = """
INSERT INTO student (student_name, student_number, user_id, major_id, class_name)
VALUES (%s, %s, %s, %s, %s)
"""
data = (student.student_name, student.student_number, student.user_id, student.major_id, student.class_name)
return self.execute(sql, data)

16
models/Student.py Normal file
View File

@ -0,0 +1,16 @@
class Student:
def __init__(self, student_name, student_number, user_id, major_id, class_name):
self.student_name = student_name
self.student_number = student_number
self.user_id = user_id
self.major_id = major_id
self.class_name = class_name
def __str__(self):
return (f"Student Name: {self.student_name}, "
f"User ID: {self.user_id}, "
f"Student Number: {self.student_number}, "
f"Major ID: {self.major_id}, "
f"Class Name: {self.class_name}")

8
models/Teacher.py Normal file
View File

@ -0,0 +1,8 @@
class Teacher:
def __init__(self, name, user_id, teacher_number):
self.name = name
self.user_id = user_id
self.teacher_number = teacher_number
def __str__(self):
return f"Teacher: {self.name}, {self.user_id},{self.teacher_number}"

View File

@ -1,14 +1,15 @@
import bcrypt
class User:
def __init__(self, nickname, phone_number, password, identity, status):
self.nickname = nickname # 用户昵称
self.phone_number = phone_number # 手机号
def __init__(self, name, number, password, status):
self.name = name # 用户昵称
self.number = number # 手机号
self.password = self.hash_password(password) # 哈希密码
self.identity = identity # 身份(老师或学生)
self.status = status # 状态(是否可用)
def hash_password(self, password):
return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
def __str__(self):
return f"User({self.nickname}, {self.phone_number}, {'Teacher' if self.identity == 'teacher' else 'Student'}, {'Active' if self.status else 'Inactive'})"
return f"User({self.name}, {self.number}, {'Active' if self.status else 'Inactive'})"

View File

@ -94,16 +94,17 @@ CREATE TABLE attendance_records
CREATE TABLE major
(
id INT AUTO_INCREMENT,
major_id INT NOT NULL,
id INT AUTO_INCREMENT PRIMARY KEY,
major_id VARCHAR(20) NOT NULL UNIQUE,
major VARCHAR(255)
);
INSERT INTO major(major_id,major)
values (000, '计算机科学与技术'),
(001, '电子工程'),
(002, '经济学'),
(003, '生物学');
values ('000', '计算机科学与技术'),
('001', '电子工程'),
('002', '经济学'),
('003', '生物学');
CREATE TABLE student
(
@ -112,7 +113,7 @@ CREATE TABLE student
student_number VARCHAR(20) NOT NULL UNIQUE,
student_name VARCHAR(255) NOT NULL,
class_name VARCHAR(20) NOT NULL,
major_id INT NOT NULL,
major_id VARCHAR(20) NOT NULL,
FOREIGN KEY (user_id) REFERENCES user (user_id),
FOREIGN KEY (major_id) REFERENCES major (major_id)
);