Compare commits

...

70 Commits

Author SHA1 Message Date
dbeeb4d25a 更新 requirements.txt 2023-12-31 00:22:29 +08:00
58c4b85e6a 删除 requirements.txt 2023-12-29 17:31:25 +08:00
b6fc41994e 创建 ReceiveExcelTest.py 2023-12-29 17:31:23 +08:00
1a08ba460c 创建 StudentSignInTest.py 2023-12-29 17:25:11 +08:00
692631e395 创建 TeacherSignInTest.py 2023-12-29 17:25:09 +08:00
1174b225a7 创建 TestGetHtml.py 2023-12-29 17:25:05 +08:00
ded28f6a1e 创建 TestLogout.py 2023-12-29 16:31:56 +08:00
4e64fb2422 创建 TestGetMenu.py 2023-12-29 16:31:55 +08:00
eb074e5dd5 更新 database_manager.py 2023-12-29 16:07:22 +08:00
6ef3faf149 创建 TestLogin.py 2023-12-29 16:07:20 +08:00
9b519f4650 更新 login.html 2023-12-29 16:04:57 +08:00
d6bef5812b 删除 init.py 2023-12-29 16:04:54 +08:00
8e8fccbb1a 创建 app.py 2023-12-29 16:04:52 +08:00
237f0acf8d 删除 app.py 2023-12-29 16:04:50 +08:00
44ce96c7d9 更新 views.py 2023-12-29 16:04:42 +08:00
dae0ce21be 更新 announcement.html 2023-12-29 15:19:49 +08:00
a94dc7b415 更新 app.py 2023-12-29 15:06:04 +08:00
ca44cf0eaa 创建 requirements.txt 2023-12-29 15:05:23 +08:00
18c3968e59 更新 database_manager.py 2023-12-29 15:02:57 +08:00
5ce9ee1b1e 更新 mysql.sql 2023-12-29 14:47:07 +08:00
2596680c3a 更新 views.py 2023-12-29 14:47:05 +08:00
ff030444e4 更新 mysql.sql 2023-12-29 14:39:51 +08:00
e14688471a 更新 mysql.sql 2023-12-29 14:31:29 +08:00
c554d2d7af 创建 parse_table.py 2023-12-29 14:27:59 +08:00
9296b70ac3 更新 mysql.sql 2023-12-29 14:27:57 +08:00
cff2b66bc0 更新 template.xlsx 2023-12-29 14:27:54 +08:00
9d68073dd5 更新 database_manager.py 2023-12-29 14:27:52 +08:00
894d075d55 更新 views.py 2023-12-29 14:27:49 +08:00
8021f15e58 更新 import-class.html 2023-12-29 14:27:46 +08:00
b5461dbff4 更新 attendance-teacher.html 2023-12-29 14:27:44 +08:00
aab814a23a 更新 get_teacher_attendance_table.js 2023-12-29 14:27:38 +08:00
c0d0e43e73 创建 get_teacher_attendance_table.js 2023-12-29 11:34:34 +08:00
3e79a22956 更新 attendance-teacher.html 2023-12-29 11:34:31 +08:00
ca55d9d2fd 更新 views.py 2023-12-29 11:34:26 +08:00
e655b72a5c 更新 database_manager.py 2023-12-29 11:34:24 +08:00
e75cce4dc9 更新 mysql.sql 2023-12-29 11:34:18 +08:00
a2be2f6378 更新 announcement.html 2023-12-29 10:12:56 +08:00
b07880eb7d 创建 time_utils.py 2023-12-29 01:58:24 +08:00
9048134f55 创建 allowed_files.py 2023-12-29 01:58:22 +08:00
dc2aedb06b 创建 __init__.py 2023-12-29 01:58:19 +08:00
74d63734bc 更新 database_manager.py 2023-12-29 01:58:17 +08:00
70c0c7925d 更新 views.py 2023-12-29 01:58:15 +08:00
1dddf07b54 删除 time_utils.py 2023-12-29 01:58:12 +08:00
88f5713f16 删除 allowed_files.py 2023-12-29 01:58:10 +08:00
7075531fc6 更新 announcement.html 2023-12-29 01:58:02 +08:00
908fa9344b 更新 mysql.sql 2023-12-29 01:15:55 +08:00
519d77d5b2 更新 database_manager.py 2023-12-29 01:15:53 +08:00
d404ccfa78 更新 views.py 2023-12-29 01:15:51 +08:00
1deec07d33 更新 announcement.html 2023-12-29 01:15:49 +08:00
a00a85efdb 更新 database_manager.py 2023-12-29 00:47:59 +08:00
feb6d1e2ce 更新 views.py 2023-12-29 00:47:57 +08:00
548120f9db 更新 views.py 2023-12-29 00:21:54 +08:00
964332cf44 更新 mysql.sql 2023-12-29 00:21:30 +08:00
b5b5e92b73 更新 database_manager.py 2023-12-29 00:21:28 +08:00
f59b43c99e 更新 views.py 2023-12-29 00:21:26 +08:00
68a126cb8b 更新 attendance.html 2023-12-29 00:21:24 +08:00
dc66080c22 更新 mysql.sql 2023-12-28 23:32:11 +08:00
f69c0a112f 更新 database_manager.py 2023-12-28 23:32:08 +08:00
d41e846ee4 更新 views.py 2023-12-28 23:32:06 +08:00
c7024d5851 创建 time_utils.py 2023-12-28 23:32:03 +08:00
ada0a97a42 更新 attendance.html 2023-12-28 23:32:00 +08:00
fdd09d5e4d 更新 upload_excel.js 2023-12-28 23:31:52 +08:00
6ce370db9c 更新 mysql.sql 2023-12-28 20:14:39 +08:00
1edb119983 更新 course-category.html 2023-12-28 20:10:22 +08:00
ad9fcf4781 更新 attendance.html 2023-12-28 20:10:19 +08:00
7c13aa0e6c 更新 mysql.sql 2023-12-28 20:10:13 +08:00
8f5b0e7dd2 更新 database_manager.py 2023-12-28 19:27:22 +08:00
cffeebdec4 更新 import-class.html 2023-12-28 19:27:19 +08:00
22e3b797cb 更新 course-info.html 2023-12-28 19:27:14 +08:00
514d86e77c 创建 upload_excel.js 2023-12-28 19:27:03 +08:00
26 changed files with 989 additions and 236 deletions

View File

@@ -0,0 +1,2 @@
import views

View File

@@ -0,0 +1,60 @@
layui.use(['laypage', 'element', 'jquery', 'dropdown'], function () {
var laypage = layui.laypage;
var $ = layui.jquery;
function renderTable(page) {
$.get('/api/get-teacher-attendance-table?page=' + page, function (response) {
var $tbody = $('#attendanceTable tbody');
$tbody.empty(); // 清空表格内容
response.data.forEach(function (item) {
var $row = $('<tr></tr>');
$row.append(`<td>${item.course_id}</td>`);
$row.append(`<td>${item.course_name}</td>`);
$row.append(`<td>${item.class_name}</td>`);
$row.append(`<td>${item.major}</td>`);
$row.append(`<td><div class="layui-btn-container">
<button type="button" class="layui-btn btn-sign-in"
data-course-id="${item.course_id}"
data-course-name="${item.course_name}"
data-class-name = "${item.class_name}"
data-major-id = "${item.major_id}"
>签到</button>
</div>
</td>`)
$tbody.append($row);
});
laypage.render({
elem: 'pagination',
count: response.count,
limit: 10,
curr: page,
jump: function (obj, first) {
if (!first) {
renderTable(obj.curr);
}
}
});
});
}
// 为动态生成的按钮添加点击事件
$(document).on('click', '.btn-sign-in', function () {
var courseId = $(this).data('course-id'); // 获取课程ID
var courseName = $(this).data('course-name'); // 获取课程名
var className = $(this).data('class-name'); // 获取课程名
var majorId = $(this).data('major-id'); // 获取课程名
// console.log(courseId,courseName,className,majorId)
// 向后端发送POST请求
$.post('/api/teacher-sign-in', {
course_id: courseId,
course_name: courseName,
class_name: className,
major_id:majorId
}, function (response) {
layer.msg(response.msg);
});
});
renderTable(1); // 初始加载第一页
});

View File

@@ -0,0 +1,45 @@
// 获取上传按钮和文件输入元素
var uploadBtn = document.getElementById('uploadExcel');
var fileInput = document.getElementById('excelFile');
// 当点击上传按钮时触发文件输入的点击事件
uploadBtn.addEventListener('click', function () {
fileInput.click();
});
// 处理文件选择事件
fileInput.addEventListener('change', function () {
var file = this.files[0]; // 获取文件对象
if (file) {
// 检查文件类型
var fileName = file.name;
var fileExt = fileName.split('.').pop().toLowerCase();
if (fileExt === 'xlsx' || fileExt === 'xls') {
// 使用 FormData 上传文件
var formData = new FormData();
formData.append('file', file, fileName); // 'file' 是你的服务器端期待的字段名
// 使用 fetch 发送文件
fetch('/api/receive-excel', {
method: 'POST',
body: formData // 传递表单数据
})
.then(response => {
if (response.ok) {
return response.json(); // 如果上传成功解析JSON响应
}
throw new Error('Network response was not ok.'); // 如果上传失败,抛出错误
})
.then(data => {
// 处理响应数据
layer.msg('上传成功!'); // 弹出成功消息
})
.catch(error => {
console.error('Upload failed:', error);
layer.msg("文件上传失败!"); // 弹出失败消息
});
} else {
alert("请上传Excel文件!");
}
}
});

View File

@@ -21,7 +21,7 @@
src="//unpkg.com/outeres@0.0.10/img/layui/icon-v2.png" src="//unpkg.com/outeres@0.0.10/img/layui/icon-v2.png"
class="layui-nav-img" class="layui-nav-img"
/> />
{{ session.nickname }} {{ session.name }}
</a> </a>
<dl class="layui-nav-child"> <dl class="layui-nav-child">
<dd><a href="/home/profile">资料</a></dd> <!-- 修改这里的href指向/profile --> <dd><a href="/home/profile">资料</a></dd> <!-- 修改这里的href指向/profile -->
@@ -54,11 +54,8 @@
<div class="layui-col-md6"> <div class="layui-col-md6">
<fieldset class="layui-elem-field"> <fieldset class="layui-elem-field">
<legend>今日课程</legend> <legend>今日课程</legend>
<div class="layui-field-box"> <div class="layui-field-box" id="courses-container">
<!-- 这里可以动态列出今日课程 --> <!-- 课程信息将通过JavaScript动态添加 -->
<p>1. 数学 - 上午9:00</p>
<p>2. 物理 - 下午1:00</p>
<p>3. 文学 - 下午3:00</p>
</div> </div>
</fieldset> </fieldset>
</div> </div>
@@ -72,6 +69,20 @@
<script src="/static/js/menu.js"></script> <script src="/static/js/menu.js"></script>
<script src="/static/js/logout.js"></script> <script src="/static/js/logout.js"></script>
<script> <script>
$(document).ready(function () {
// 请求后端获取课程信息
$.get('/api/get-today-courses', function (data) {
if (data.msg == "ok") {
data.data.forEach(function (course) {
// 为每个课程创建一个段落<p>并添加到容器中,并设置样式使字体更大且更加好看
$('#courses-container').append('<p style="font-size: 1.2em; margin: 5px 0;">课程: ' + course.course_name + ' <br> 时间: ' + course.time + '</p>');
});
} else {
$('#courses-container').append(data.msg)
}
});
});
</script> </script>
</body> </body>
</html> </html>

View File

@@ -55,10 +55,10 @@
<!-- 表头 --> <!-- 表头 -->
<thead> <thead>
<tr> <tr>
<th>课程名称</th>
<th>课程代码</th> <th>课程代码</th>
<th>学分</th> <th>课程名称</th>
<th>班级专业</th> <th>班级</th>
<th>专业</th>
<th>签到</th> <th>签到</th>
</tr> </tr>
</thead> </thead>
@@ -74,50 +74,8 @@
<script src="/static/layui.js"></script> <script src="/static/layui.js"></script>
<script src="/static/js/menu.js"></script> <script src="/static/js/menu.js"></script>
<script src="/static/js/logout.js"></script> <script src="/static/js/logout.js"></script>
<script src="/static/js/get_teacher_attendance_table.js"></script>
<script> <script>
layui.use(['laypage', 'element', 'jquery', 'dropdown'], function () {
var laypage = layui.laypage;
var $ = layui.jquery;
function renderTable(page) {
// 发送GET请求到服务器端点
$.get('/api/get-teacher-attendance-table?page=' + page, function (response) {
var $tbody = $('#attendanceTable tbody');
$tbody.empty(); // 清空表格内容
// 遍历返回的数据数组
response.data.forEach(function (item) {
// 创建新的行并填充数据
var $row = $('<tr></tr>');
$row.append(`<td>${item.course_name}</td>`);
$row.append(`<td>${item.course_code}</td>`);
$row.append(`<td>${item.credits}</td>`);
$row.append(`<td>${item.class_name + item.major}</td>`);
$row.append(`<td><div class="layui-btn-container">
<button type="button" class="layui-btn">签到</button>
</div>
</td>`)
$tbody.append($row);
});
// 渲染分页控件
laypage.render({
elem: 'pagination', // 分页容器的id
count: response.count, // 总条数
limit: 10, // 每页显示条数
curr: page, // 当前页
jump: function (obj, first) {
if (!first) { // 首次不执行
renderTable(obj.curr); // 根据页码加载数据
}
}
});
});
}
// 初始加载第一页
renderTable(1);
});
</script> </script>
</body> </body>
</html> </html>

View File

@@ -44,17 +44,10 @@
</div> </div>
<div class="layui-body"> <div class="layui-body">
<div id="sign-in-reminder" class="layui-container"> <div id="sign-in-reminder" class="layui-container">
<h1>每日签到</h1> <blockquote class="layui-elem-quote layui-text" id="title">
<p>每天签到,享受连续签到奖励!</p> 课程签到
</blockquote>
<!-- 签到状态 --> <div class="layui-text" id="course-info"></div>
<div class="layui-row">
<div class="layui-col-xs12">
<div id="sign-in-status">你已连续签到 <span id="days-count">0</span></div>
</div>
</div>
<!-- 操作按钮 -->
<div class="layui-row" style="margin-top: 20px;"> <div class="layui-row" style="margin-top: 20px;">
<div class="layui-col-xs12"> <div class="layui-col-xs12">
<button class="layui-btn" id="sign-in-btn">立即签到</button> <button class="layui-btn" id="sign-in-btn">立即签到</button>
@@ -70,7 +63,43 @@
<script src="/static/js/menu.js"></script> <script src="/static/js/menu.js"></script>
<script src="/static/js/logout.js"></script> <script src="/static/js/logout.js"></script>
<script> <script>
// 请求后端获取菜单数 $(document).ready(function () {
let courseData = {};
// 获取课程名称或状态
$.get("/api/get-course-name", function (response) {
if (response.msg === "ok") {
// 如果后端返回课程名
$("#course-info").text("课程:" + response.data.course_name + "。在上课时间内,请及时签到!");
// 启用签到按钮
$("#sign-in-btn").prop('disabled', false);
courseData = response.data;
} else {
// 根据不同的消息更新状态
$("#course-info").text(response.msg); // 显示没有课程的消息
// 禁用签到按钮
$("#sign-in-btn").prop('disabled', true);
}
});
// 绑定签到按钮事件
$("#sign-in-btn").click(function () {
if (!$(this).prop('disabled')) {
// 发送签到请求到后端
$.post("/api/student-sign-in",courseData,function (response) {
// 处理签到后的响应
if (response.msg === 'ok') {
layer.msg('签到成功!');
} else {
layer.msg(response.data);
}
});
} else {
layer.msg("当前不可签到"); // Or handle disabled button click as needed
}
});
});
</script> </script>
</body> </body>
</html> </html>

View File

@@ -62,7 +62,6 @@
// 发起GET请求获取数据 // 发起GET请求获取数据
$.get('/api/get-course-type', function (res) { $.get('/api/get-course-type', function (res) {
// 假设返回的res是一个对象包含必修和选修的课程名数组 // 假设返回的res是一个对象包含必修和选修的课程名数组
console.log(res);
// 处理返回的数据,转换为表格能接受的格式 // 处理返回的数据,转换为表格能接受的格式
var tableData = []; var tableData = [];

View File

@@ -60,7 +60,6 @@
<tr> <tr>
<th>课程名称</th> <th>课程名称</th>
<th>课程代码</th> <th>课程代码</th>
<th>课程类别</th>
<th>学分</th> <th>学分</th>
<th>课程描述</th> <th>课程描述</th>
</tr> </tr>
@@ -86,7 +85,6 @@
var row = '<tr>' + var row = '<tr>' +
'<td>' + course.course_name + '</td>' + '<td>' + course.course_name + '</td>' +
'<td>' + course.course_code + '</td>' + '<td>' + course.course_code + '</td>' +
'<td>' + course.course_type + '</td>' +
'<td>' + course.credits + '</td>' + '<td>' + course.credits + '</td>' +
'<td>' + course.description + '</td>' + '<td>' + course.description + '</td>' +
'</tr>'; '</tr>';

View File

@@ -29,7 +29,7 @@
src="//unpkg.com/outeres@0.0.10/img/layui/icon-v2.png" src="//unpkg.com/outeres@0.0.10/img/layui/icon-v2.png"
class="layui-nav-img" class="layui-nav-img"
/> />
{{ session.nickname }} {{ session.name }}
</a> </a>
<dl class="layui-nav-child"> <dl class="layui-nav-child">
<dd><a href="/home/profile">资料</a></dd> <!-- 修改这里的href指向/profile --> <dd><a href="/home/profile">资料</a></dd> <!-- 修改这里的href指向/profile -->
@@ -80,56 +80,12 @@
</div> </div>
</div> </div>
<script src="/static/jquery.min.js"></script> <!-- 确保已经引入jQuery --> <script src="/static/jquery.min.js"></script>
<script src="/static/layui.js"></script> <script src="/static/layui.js"></script>
<script src="/static/js/menu.js"></script> <script src="/static/js/menu.js"></script>
<script src="/static/js/logout.js"></script> <script src="/static/js/logout.js"></script>
<script src="/static/js/upload_excel.js"></script>
<script> <script>
// 获取上传按钮和文件输入元素
var uploadBtn = document.getElementById('uploadExcel');
var fileInput = document.getElementById('excelFile');
// 当点击上传按钮时触发文件输入的点击事件
uploadBtn.addEventListener('click', function () {
fileInput.click();
});
// 处理文件选择事件
fileInput.addEventListener('change', function () {
var file = this.files[0]; // 获取文件对象
if (file) {
// 检查文件类型
var fileName = file.name;
var fileExt = fileName.split('.').pop().toLowerCase();
if (fileExt === 'xlsx' || fileExt === 'xls') {
// 使用 FormData 上传文件
var formData = new FormData();
formData.append('file', file, fileName); // 'file' 是你的服务器端期待的字段名
// 使用 fetch 发送文件
fetch('/api/receive-excel', {
method: 'POST',
body: formData // 传递表单数据
})
.then(response => {
if (response.ok) {
return response.json(); // 如果上传成功解析JSON响应
}
throw new Error('Network response was not ok.'); // 如果上传失败,抛出错误
})
.then(data => {
// 处理响应数据
layer.msg('上传成功!'); // 弹出成功消息
})
.catch(error => {
console.error('Upload failed:', error);
alert("文件上传失败!"); // 弹出失败消息
});
} else {
alert("请上传Excel文件!");
}
}
});
</script> </script>
</body> </body>

View File

@@ -64,6 +64,7 @@
data: data.field, // 表单数据 data: data.field, // 表单数据
dataType: 'json', dataType: 'json',
success: function (response) { success: function (response) {
console.log(response)
if (response.success) { if (response.success) {
window.location.href = '/attendance-reminder'; // 或者你的成功页面 window.location.href = '/attendance-reminder'; // 或者你的成功页面
} else { } else {

View File

@@ -0,0 +1,43 @@
import unittest
import os
from app.views import *
from werkzeug.datastructures import FileStorage # 用于创建测试文件
class ReceiveExcelTestCase(unittest.TestCase):
def setUp(self):
app.testing = True # 设置 Flask 应用为测试模式
self.client = app.test_client()
# 创建一个测试用的Excel文件或使用一个真实的Excel文件路径
self.test_file_path = 'template.xlsx'
def test_receive_excel_no_file(self):
# 测试没有文件时的情况
response = self.client.post('/api/receive-excel')
self.assertEqual(response.status_code, 400)
self.assertEqual(response.get_json(), {"error": "No file part"})
def test_receive_excel_with_file(self):
# 模拟已登录用户
with self.client.session_transaction() as sess:
sess['number'] = 'X202301000001'
# 使用 FileStorage 创建测试文件对象
data = {
'file': (open(self.test_file_path, 'rb'), self.test_file_path)
}
# 发送 POST 请求到 /api/receive-excel
response = self.client.post('/api/receive-excel', data=data, content_type='multipart/form-data')
# 验证返回的状态码和响应
self.assertEqual(response.status_code, 200)
self.assertEqual(response.get_json(), {"message": "File successfully processed"})
def tearDown(self):
# 清理测试用的文件或数据
if os.path.exists(self.test_file_path):
os.remove(self.test_file_path)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,39 @@
import unittest
from app.views import *
from unittest.mock import patch
from flask import session
class StudentSignInTestCase(unittest.TestCase):
def setUp(self):
# 设置 Flask 测试模式
app.testing = True
self.client = app.test_client()
@patch('db.database_manager.DatabaseManager.update_sign_in_info')
def test_student_sign_in(self, mock_update_sign_in_info):
# 模拟已登录用户
with self.client.session_transaction() as sess:
sess['number'] = 'X202301000001'
# 模拟数据库操作
mock_update_sign_in_info.return_value = 1 # 假设成功更新签到信息
# 发送 POST 请求到/api/student-sign-in
response = self.client.post('/api/student-sign-in', data={
'course_name': '计算机导论',
'course_id': '2',
'student_number': 'X202301000001',
})
# 验证返回的状态码和JSON数据
self.assertEqual(response.status_code, 200)
json_data = response.get_json()
self.assertEqual(json_data, {"msg": "ok", "data": "签到成功!"})
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,37 @@
import unittest
from app.views import *
from unittest.mock import patch
from flask import session
class TeacherSignInTestCase(unittest.TestCase):
def setUp(self):
# 设置 Flask 测试模式
app.testing = True
self.client = app.test_client()
@patch('db.database_manager.DatabaseManager.update_sign_in_info')
def test_teacher_sign_in(self, mock_teacher_sign_in):
# 模拟已登录用户
with self.client.session_transaction() as sess:
sess['number'] = 'X202301000001'
# 模拟数据库操作的返回值
mock_teacher_sign_in.return_value = {"msg": "当前班级专业没有学生'"}
# 发送 POST 请求到/api/teacher-sign-in
response = self.client.post('/api/teacher-sign-in', data={
'course_id': '123',
'course_name': 'Test Course',
'class_name': 'TestClass',
'major_id': '456'
})
# 验证返回的状态码和数据
self.assertEqual(response.status_code, 200)
json_data = response.get_json()
self.assertEqual(json_data, {"msg": "当前班级专业没有学生"})
if __name__ == '__main__':
unittest.main()

73
app/tests/TestGetHtml.py Normal file
View File

@@ -0,0 +1,73 @@
import unittest
from app.views import *
class HtmlTestCase(unittest.TestCase):
def setUp(self):
app.testing = True # 设置 Flask 应用为测试模式
self.client = app.test_client() # 创建一个测试客户端
def test_get_course_info(self):
# 测试 GET 请求
response = self.client.get('/course-info')
# 验证响应状态码
self.assertEqual(response.status_code, 200)
# 验证响应的Content-Type头部值
self.assertIn('text/html', response.content_type)
def test_get_attendance(self):
# 测试 GET 请求
response = self.client.get('/attendance')
# 验证响应状态码
self.assertEqual(response.status_code, 200)
# 验证响应的Content-Type头部值
self.assertIn('text/html', response.content_type)
def test_get_announcement(self):
# 测试 GET 请求
response = self.client.get('/announcement')
# 验证响应状态码
self.assertEqual(response.status_code, 200)
# 验证响应的Content-Type头部值
self.assertIn('text/html', response.content_type)
def test_get_attendance_reminder(self):
# 测试 GET 请求
response = self.client.get('/attendance-reminder')
# 验证响应状态码
self.assertEqual(response.status_code, 200)
# 验证响应的Content-Type头部值
self.assertIn('text/html', response.content_type)
def test_get_course_category(self):
# 测试 GET 请求
response = self.client.get('/course-category')
# 验证响应状态码
self.assertEqual(response.status_code, 200)
# 验证响应的Content-Type头部值
self.assertIn('text/html', response.content_type)
def test_get_attendance_teacher(self):
# 测试 GET 请求
response = self.client.get('/attendance-teacher')
# 验证响应状态码
self.assertEqual(response.status_code, 200)
# 验证响应的Content-Type头部值
self.assertIn('text/html', response.content_type)
if __name__ == '__main__':
unittest.main()

44
app/tests/TestGetMenu.py Normal file
View File

@@ -0,0 +1,44 @@
import unittest
from app.views import *
from flask import session
from unittest.mock import patch # 如果需要模拟数据库方法
class MenuAPITestCase(unittest.TestCase):
def setUp(self):
app.testing = True # 设置 Flask 应用为测试模式
self.client = app.test_client() # 创建一个测试客户端
self.expected_menu = [
{"name": "课程类别", "path": "/course-category"},
{"name": "课程信息", "path": "/course-info"},
{"name": "课程签到", "path": "/attendance-teacher"},
{"name": "签到提醒", "path": "/attendance-reminder"}
]
def test_menu_no_login(self):
# 测试未登录情况下请求API
response = self.client.get('/api/menu')
self.assertEqual(response.status_code, 401)
self.assertEqual(response.get_json(), [])
def test_login(self):
with self.client:
self.client.post('/login', data=dict(
number='G0001',
password='1'
))
# 确认登录后session中有数据
self.assertIn('role', session)
# 执行logout
response = self.client.get('/api/menu')
print(response.get_json())
# 确认响应是重定向到登录页面
self.assertEqual(response.status_code, 200)
self.assertEqual(self.expected_menu,response.get_json())
if __name__ == '__main__':
unittest.main()

45
app/tests/TestLogin.py Normal file
View File

@@ -0,0 +1,45 @@
import unittest
from app.views import *
from db.database_manager import DatabaseManager # 确保你可以导入DatabaseManager
class LoginTestCase(unittest.TestCase):
def setUp(self):
# 设置 Flask 测试模式
app.testing = True
self.client = app.test_client()
def test_login_get(self):
# 测试 GET 请求返回登录页面
response = self.client.get('/login')
self.assertEqual(response.status_code, 200)
self.assertIn('text/html', response.content_type)
def test_successful_login_post(self):
# 测试有效的登录 POST 请求
with self.client:
response = self.client.post('/login', data={
'number': 'G0001',
'password': '1'
})
# 根据你的应用逻辑调整断言
self.assertEqual(response.status_code, 200)
def test_invalid_login_post(self):
# 测试无效的登录 POST 请求
response = self.client.post('/login', data={
'number': 'admin',
'password': 'admin'
})
# 将返回的数据解析为JSON
json_data = response.get_json()
# 确认JSON响应中的值
self.assertEqual(response.status_code, 200)
self.assertFalse(json_data['success'])
self.assertEqual(json_data['message'], "无效的用户名或密码")
# 运行测试
if __name__ == '__main__':
unittest.main()

34
app/tests/TestLogout.py Normal file
View File

@@ -0,0 +1,34 @@
import unittest
from app.views import *
class LogoutTestCase(unittest.TestCase):
def setUp(self):
# 设置 Flask 测试模式
app.testing = True
self.client = app.test_client()
def test_logout(self):
# 先登录,确保 session 是设置的
with self.client:
self.client.post('/login', data=dict(
number='G0001',
password='1'
))
# 确认登录后session中有数据
self.assertIn('number', session)
# 执行logout
response = self.client.get('/logout')
# 确认 session 被清空
self.assertNotIn('number', session)
# 确认响应是重定向到登录页面
self.assertEqual(response.status_code, 302)
self.assertTrue(response.location.endswith('/login'))
if __name__ == '__main__':
unittest.main()

View File

@@ -1,18 +1,21 @@
import os import os
import logging
import openpyxl as openpyxl # 第三方库
import openpyxl
from flask import Flask, redirect, url_for, render_template, session, jsonify, request, send_file from flask import Flask, redirect, url_for, render_template, session, jsonify, request, send_file
from datetime import datetime
# 应用内部模块
from utils.time_utils import check_now_time
from utils.parse_table import parse_table
from utils.allowed_files import allowed_excel from utils.allowed_files import allowed_excel
from db.connection import MySQLPool from db.connection import MySQLPool
from config import SECRET_KEY
from db.database_manager import DatabaseManager from db.database_manager import DatabaseManager
from models.Student import Student from models.Student import Student
from models.Teacher import Teacher from models.Teacher import Teacher
from models.User import User from models.User import User
import logging from config import SECRET_KEY, LOGGING_CONFIG, FILE_PATH
from config import LOGGING_CONFIG
from config import FILE_PATH
app = Flask(__name__, static_folder='static') app = Flask(__name__, static_folder='static')
app.secret_key = SECRET_KEY # 从配置文件设置 app.secret_key = SECRET_KEY # 从配置文件设置
@@ -86,7 +89,7 @@ def login():
db_manager = DatabaseManager() db_manager = DatabaseManager()
result = db_manager.valid_login(number, password) # 获取验证结果 result = db_manager.valid_login(number, password) # 获取验证结果
print(result)
# 确保用户已验证且活跃(未被禁用) # 确保用户已验证且活跃(未被禁用)
if result['valid'] and result['status'] == 1: if result['valid'] and result['status'] == 1:
# 登录成功 # 登录成功
@@ -94,7 +97,7 @@ def login():
session['role'] = check_identity(number) session['role'] = check_identity(number)
session['name'] = result['name'] session['name'] = result['name']
return jsonify(success=True, message="登录成功") return jsonify(success=True, message="登录成功")
elif not result['status']: elif not result.get('status'):
# 用户被禁用的情况 # 用户被禁用的情况
return jsonify(success=False, message="账户已被禁用") return jsonify(success=False, message="账户已被禁用")
else: else:
@@ -166,9 +169,14 @@ def course_info():
@app.route('/api/get-course-info', methods=['GET']) @app.route('/api/get-course-info', methods=['GET'])
def get_course_info(): def get_course_info():
student_number = session.get('number')
db_manager = DatabaseManager() db_manager = DatabaseManager()
course_data = db_manager.get_all_courses() if check_identity(student_number) == "student":
return jsonify(course_data) course_data = db_manager.get_class_courses(student_number)
return jsonify(course_data)
else:
course_data = db_manager.get_all_courses()
return jsonify(course_data)
@app.route('/api/get-course-type', methods=['GET']) @app.route('/api/get-course-type', methods=['GET'])
@@ -239,6 +247,7 @@ def get_current_teacher_courses():
# 获取所有课程数据 # 获取所有课程数据
db_manager = DatabaseManager() db_manager = DatabaseManager()
all_course_data = db_manager.get_current_teacher_courses(number) all_course_data = db_manager.get_current_teacher_courses(number)
print(all_course_data)
logging.info(f"all_course_data: {all_course_data}") logging.info(f"all_course_data: {all_course_data}")
# 计算分页的起始和结束索引 # 计算分页的起始和结束索引
start = (page - 1) * limit start = (page - 1) * limit
@@ -267,6 +276,7 @@ def download_template():
@app.route('/api/receive-excel', methods=['POST']) @app.route('/api/receive-excel', methods=['POST'])
def receive_excel(): def receive_excel():
number = session.get('number')
# 检查是否有文件在请求中 # 检查是否有文件在请求中
if 'file' not in request.files: if 'file' not in request.files:
return jsonify({"error": "No file part"}), 400 return jsonify({"error": "No file part"}), 400
@@ -281,9 +291,10 @@ def receive_excel():
if file and allowed_excel(file.filename): if file and allowed_excel(file.filename):
try: try:
# 使用 openpyxl 读取文件内容 # 使用 openpyxl 读取文件内容
workbook = openpyxl.load_workbook(file) data = parse_table(file, number)
# TODO: 在这里处理你的Excel文件例如读取数据 db_manager = DatabaseManager()
print(workbook) result = db_manager.insert_into_class_student(data)
print(result)
return jsonify({"message": "File successfully processed"}), 200 return jsonify({"message": "File successfully processed"}), 200
except Exception as e: except Exception as e:
return jsonify({"error": str(e)}), 500 return jsonify({"error": str(e)}), 500
@@ -291,5 +302,102 @@ def receive_excel():
return jsonify({"error": "Invalid file type"}), 400 return jsonify({"error": "Invalid file type"}), 400
@app.route('/api/get-course-name', methods=['GET'])
def get_course_name():
period_id, period_name = check_now_time() # 获取当前时间段信息
print(f"period_id: {period_id}, period_name: {period_name}")
# 如果当前不在任何时间段内
if period_id is None:
return jsonify({
'msg': period_name, # 返回不在课程时间段内的消息
'data': None
})
# 获取当前用户编号
number = session.get('number')
if not number:
return jsonify({"msg": "用户未登录或编号不可用", "data": None})
# 获取今天是星期几
now = datetime.now()
day_of_week = now.weekday() + 1
# 如果是周末
if not (1 <= day_of_week <= 5):
return jsonify({"msg": "周末没有课程", "data": None})
# 如果是工作日,获取课程信息
print(f"day of week: {day_of_week}")
db_manager = DatabaseManager()
data = db_manager.get_course_name(number, day_of_week, period_id)
print(data)
# 返回课程信息
return jsonify({
'msg': 'ok',
'data': data
})
@app.route('/api/student-sign-in', methods=['POST'])
def student_sign_in():
number = session.get("number")
course_name = request.form.get('course_name')
course_id = request.form.get('course_id')
now = datetime.now()
date = now.strftime("%Y年%m月%d%H:%M")
status = "出勤"
print(f"number: {number},course_name: {course_name},course_id: {course_id}")
db_manager = DatabaseManager()
result = db_manager.update_sign_in_info(number, course_id, course_name, date, status)
if result == 1:
return jsonify({"msg": "ok", "data": "签到成功!"})
else:
return jsonify({"msg": "fail", "data": "签到失败!"})
@app.route('/api/get-today-courses')
def student_get_today_courses():
number = session.get('number')
if not number:
return jsonify({"msg": "用户未登录或编号不可用", "data": None})
# 获取今天是星期几
now = datetime.now() # 获取当前时间
day_of_week = now.weekday() + 1
# 如果是周末
if not (1 <= day_of_week <= 5):
return jsonify({"msg": "周末没有课程", "data": None})
db_manager = DatabaseManager()
data = db_manager.student_get_today_courses(number, day_of_week)
# 返回课程信息
return jsonify({
'msg': 'ok',
'data': data
})
@app.route('/api/teacher-sign-in', methods=['POST'])
def teacher_sign_in():
teacher_number = session.get('number')
course_id = request.form['course_id']
course_name = request.form['course_name']
class_name = request.form['class_name']
major_id = request.form['major_id']
now = datetime.now()
date = now.strftime("%Y年%m月%d%H:%M")
status = "出勤"
print(f"course_id: {course_id},course_name: {course_name},class_name: {class_name},major_id: {major_id}")
db_manager = DatabaseManager()
data = db_manager.teacher_sign_in(course_id, course_name, class_name, major_id, date, status, teacher_number)
return data
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=True) app.run(debug=True)

View File

@@ -1,3 +1,5 @@
from utils.time_utils import check_now_time
from utils.time_utils import get_time_by_ids
from db.connection import MySQLPool from db.connection import MySQLPool
import bcrypt import bcrypt
@@ -29,6 +31,22 @@ class DatabaseManager:
cursor.close() cursor.close()
conn.close() conn.close()
def executemany(self, query, params_list):
conn = self.pool.get_connection()
try:
cursor = conn.cursor()
cursor.executemany(query, params_list) # 使用executemany代替execute
conn.commit() # 提交事务
return cursor.rowcount # 返回受影响的行数
except Exception as e:
# 可以在这里添加错误处理逻辑,例如打印错误日志、回滚事务等
print("An error occurred: ", e)
conn.rollback()
return None
finally:
cursor.close()
conn.close()
def user_exists(self, phone_number): def user_exists(self, phone_number):
sql = "SELECT 1 FROM user WHERE number=%s LIMIT 1" sql = "SELECT 1 FROM user WHERE number=%s LIMIT 1"
result = self.fetch(sql, (phone_number,)) result = self.fetch(sql, (phone_number,))
@@ -59,7 +77,7 @@ class DatabaseManager:
return {'valid': True, 'status': status, 'name': name} return {'valid': True, 'status': status, 'name': name}
# 密码不匹配或用户不存在,返回登录失败 # 密码不匹配或用户不存在,返回登录失败
return {'valid': False} return {'valid': False, 'status': True}
def get_menu(self, role): def get_menu(self, role):
sql = "SELECT menu_name,path FROM menu_items WHERE role=%s ORDER BY `order`" sql = "SELECT menu_name,path FROM menu_items WHERE role=%s ORDER BY `order`"
@@ -67,19 +85,21 @@ class DatabaseManager:
return result return result
def get_all_courses(self): def get_all_courses(self):
sql = "SELECT course_name, course_code, course_type, credits, description FROM course" sql = "SELECT course_name, course_code, credits, description FROM course"
result = self.fetch(sql) result = self.fetch(sql)
return result return result
def get_current_teacher_courses(self, teacher_number): def get_current_teacher_courses(self, teacher_number):
# 使用INNER JOIN连接teacher_class_course表和course表 # 使用INNER JOIN连接teacher_class_course表和course表
sql = """ sql = """
SELECT SELECT
c.course_id,
c.course_name, c.course_name,
c.course_code, c.course_code,
c.credits, c.credits,
tcc.class_name, tcc.class_name,
m.major m.major,
m.major_id
FROM FROM
teacher_class_course tcc teacher_class_course tcc
JOIN JOIN
@@ -91,8 +111,34 @@ WHERE
""" """
# 执行查询并返回结果 # 执行查询并返回结果
result = self.fetch(sql, (teacher_number,)) class_student_sql = """SELECT course_id, course_name,class_name,major,major_id,major FROM class_student where teacher_number = %s;"""
return result result1 = self.fetch(sql, (teacher_number,))
result2 = self.fetch(class_student_sql, (teacher_number))
data = []
# 遍历第一个结果集
if result1:
for row in result1:
data.append({
"course_id": row['course_id'],
"course_name": row['course_name'],
"class_name": row['class_name'],
"major_id": row['major_id'],
"major": row['major']
})
# 遍历第二个结果集
if result2:
for row in result2:
data.append({
"course_id": row['course_id'],
"course_name": row['course_name'],
"class_name": row['class_name'],
"major_id": row['major_id'],
"major": row['major']
})
# 返回包含两个结果集信息的data列表
return data
def get_course_type(self): def get_course_type(self):
sql = "SELECT course_name, course_type FROM course" sql = "SELECT course_name, course_type FROM course"
@@ -124,3 +170,130 @@ WHERE
""" """
data = (student.student_name, student.student_number, student.user_id, student.major_id, student.class_name) data = (student.student_name, student.student_number, student.user_id, student.major_id, student.class_name)
return self.execute(sql, data) return self.execute(sql, data)
def get_course_name(self, student_number, day_of_week, period_id):
print(f"student_number: {student_number}, day_of_week: {day_of_week}, period_id: {period_id}")
# 从student表获取class_name
sql_student = "SELECT class_name FROM student WHERE student_number = %s;"
class_name = self.fetch(sql_student, (student_number,))[0]['class_name']
# 使用class_name和day_of_week从schedule表获取course_id
sql_schedule = "SELECT course_id FROM schedule WHERE day_of_week = %s AND class_name = %s AND period_id = %s;"
course_id = self.fetch(sql_schedule, (day_of_week, class_name, period_id))
print(f"course_id: {course_id}")
id = course_id[0]['course_id']
print(f"id: {id}")
# 对于每一个course_id从course表中查询course_name
sql_course = "SELECT course_name FROM course WHERE course_id = %s;"
course_name = self.fetch(sql_course, (id,))[0]['course_name']
print(f"course_name: {course_name}")
data = {"course_name": course_name, "course_id": id}
return data
def update_sign_in_info(self, student_number, course_id, course_name, date, status):
sql = """
INSERT INTO attendance_record (student_number, course_id, course_name, date, status)
VALUES (%s, %s, %s, %s, %s)
"""
val = (student_number, course_id, course_name, date, status)
result = self.execute(sql, val)
return result
def get_class_courses(self, student_number):
# 1. 查询学生的主修专业
major_sql = "SELECT major_id FROM student WHERE student_number = %s;"
major_result = self.fetch(major_sql, student_number)
print(major_result)
major_id = major_result[0]['major_id']
# 2. 查询专业的所有课程ID
course_ids_sql = "SELECT course_id FROM major_course WHERE major_id = %s;"
courses_result = self.fetch(course_ids_sql, major_id)
course_ids = [course['course_id'] for course in courses_result]
# 3. 对每个课程ID查询课程详细信息
courses_data = []
for course_id in course_ids:
course_sql = "SELECT course_name, course_code, credits, description FROM course WHERE course_id = %s;"
result = self.fetch(course_sql, course_id)
courses_data.append(result[0])
return courses_data # 返回课程详细信息列表
def student_get_today_courses(self, student_number, day_of_week):
# 从student表获取class_name
sql_student = "SELECT class_name FROM student WHERE student_number = %s;"
class_name = self.fetch(sql_student, (student_number,))[0]['class_name']
# 使用class_name和day_of_week从schedule表获取course_id
sql_schedule = "SELECT course_id,period_id FROM schedule WHERE day_of_week = %s AND class_name = %s;"
schedule_results = self.fetch(sql_schedule, (day_of_week, class_name))
print(schedule_results)
data = []
for i in schedule_results:
course_id = i['course_id']
sql_course = "SELECT course_name FROM course WHERE course_id = %s;"
course_name = self.fetch(sql_course, (course_id))[0]['course_name']
id = i['period_id']
time = get_time_by_ids(id)
data.append({"course_name": course_name, "time": time})
return data
def teacher_sign_in(self, course_id, course_name, class_name, major_id, date, status, teacher_number):
class_student_sql = "SELECT student_number FROM class_student WHERE teacher_number = %s AND major_id = %s AND class_name = %s"
class_student_result = self.fetch(class_student_sql, (teacher_number, major_id, class_name))
student_sql = "SELECT student_number FROM student WHERE class_name = %s AND major_id = %s;"
student_sql_result = self.fetch(student_sql, (class_name, major_id))
values_list = []
# 检查是否有学生编号被返回
if student_sql_result:
for student in student_sql_result:
# 对于每个学生编号,创建一条记录的值元组
student_number = student['student_number']
values_list.append((student_number, course_id, course_name, date, status))
if class_student_result:
for class_student in class_student_result:
# 注意这里变量名已经修改为class_student
student_number = class_student['student_number']
values_list.append((student_number, course_id, course_name, date, status))
# 如果没有任何学生编号,返回相应的消息
if not values_list:
return {"msg": "当前班级专业没有学生"}
# 构建一次性插入多条记录的SQL语句
attendance_sql = "INSERT INTO attendance_record (student_number, course_id, course_name, date, status) VALUES (%s, %s, %s, %s, %s)"
# 使用executemany一次性插入多条记录
result = self.executemany(attendance_sql, values_list)
print(f"Inserted rows: {result}")
return {"msg": "班级签到成功,签到人数:" + str(result)}
def insert_into_class_student(self, class_students):
try:
values_list = [
(
cs['teacher_number'],
cs['class_name'],
cs['student_name'],
cs['student_number'],
cs['course_id'],
cs['course_name'],
cs['major_id'],
cs['major']
)
for cs in class_students
]
sql = """INSERT INTO class_student
(teacher_number, class_name, student_name, student_number, course_id, course_name, major_id, major)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)"""
result = self.executemany(sql, values_list)
return {"inserted_rows": result}
except Exception as e:
# 这里应根据实际情况记录日志或返回错误信息
print(f"An error occurred: {e}")
return {"error": str(e)}

Binary file not shown.

241
mysql.sql
View File

@@ -1,18 +1,3 @@
CREATE TABLE user
(
user_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
number VARCHAR(15) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
status BOOLEAN NOT NULL
);
INSERT INTO user (name, number, password, identity, status)
VALUES ('学生', '1', '$2b$12$okY88GrzlUHb/Ox1ENwtqeBUnE0bgMOCPy.UKmFaTnu3El7EYX8Em', 'student', TRUE),
('老师', '2', '$2b$12$okY88GrzlUHb/Ox1ENwtqeBUnE0bgMOCPy.UKmFaTnu3El7EYX8Em', 'teacher', TRUE);
CREATE TABLE menu_items CREATE TABLE menu_items
( (
id INT AUTO_INCREMENT PRIMARY KEY, id INT AUTO_INCREMENT PRIMARY KEY,
@@ -27,11 +12,8 @@ INSERT INTO menu_items (menu_name, role, path, `order`)
VALUES ('课程信息', 'student', '/course-info', 1), VALUES ('课程信息', 'student', '/course-info', 1),
('课程签到', 'student', '/attendance', 2), ('课程签到', 'student', '/attendance', 2),
('公告信息', 'student', '/announcement', 3), ('公告信息', 'student', '/announcement', 3),
('签到提醒', 'student', '/attendance-reminder', 4); ('签到提醒', 'student', '/attendance-reminder', 4),
('课程类别', 'teacher', '/course-category', 1),
INSERT INTO menu_items (menu_name, role, path, `order`)
VALUES ('课程类别', 'teacher', '/course-category', 1),
('课程信息', 'teacher', '/course-info', 2), ('课程信息', 'teacher', '/course-info', 2),
('课程签到', 'teacher', '/attendance-teacher', 3), ('课程签到', 'teacher', '/attendance-teacher', 3),
('签到提醒', 'teacher', '/attendance-reminder', 4); ('签到提醒', 'teacher', '/attendance-reminder', 4);
@@ -79,18 +61,71 @@ VALUES ('大学计算机基础', 'CF001', '必修', 3, '介绍计算机基础知
('离散数学导论', 'IDTM01', '必修', 3, '介绍离散数学的基础知识和应用'), ('离散数学导论', 'IDTM01', '必修', 3, '介绍离散数学的基础知识和应用'),
('计算机网络', 'CN002', '必修', 4, '学习计算机网络的基础理论和协议'); ('计算机网络', 'CN002', '必修', 4, '学习计算机网络的基础理论和协议');
CREATE TABLE attendance_record
CREATE TABLE attendance_records
( (
record_id INT AUTO_INCREMENT PRIMARY KEY, record_id INT AUTO_INCREMENT PRIMARY KEY,
student_number VARCHAR(20) NOT NULL,
course_id INT NOT NULL, course_id INT NOT NULL,
student_id INT NOT NULL, course_name VARCHAR(255) NOT NULL,
date DATE NOT NULL, date VARCHAR(255) NOT NULL,
status ENUM('present', 'absent', 'late', 'excused'), status VARCHAR(20)
FOREIGN KEY (course_id) REFERENCES course (course_id),
FOREIGN KEY (student_id) REFERENCES student (student_id)
); );
CREATE TABLE time_period
(
period_id INT AUTO_INCREMENT UNIQUE,
period_name VARCHAR(10),
start_time TIME,
end_time TIME,
PRIMARY KEY (period_id)
);
INSERT INTO time_period (period_name, start_time, end_time)
VALUES ('一、二节', '08:00:00', '09:30:00'),
('三、四节', '10:00:00', '11:30:00'),
('五、六节', '14:30:00', '16:00:00'),
('七、八节', '16:30:00', '18:00:00');
CREATE TABLE class_student (
id INT AUTO_INCREMENT PRIMARY KEY,
teacher_number VARCHAR(20) NOT NULL,
class_name VARCHAR(20) NOT NULL , -- 班级
student_name VARCHAR(50) NOT NULL , -- 姓名
student_number VARCHAR(20) NOT NULL UNIQUE, -- 学号
course_id INT NOT NULL , -- 课程ID
course_name VARCHAR(100) NOT NULL , -- 课程名称
major_id VARCHAR(20) NOT NULL,
major VARCHAR(255) NOT NULL
);
CREATE TABLE user
(
user_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
number VARCHAR(15) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
status BOOLEAN NOT NULL
);
INSERT INTO user (name, number, password, status) VALUES
('教师1','G0001','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('教师2','G0002','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('教师3','G0003','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('教师4','G0004','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('学生1','X202301000001','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('学生2','X202301000002','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('学生3','X202301000003','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('学生4','X202301000004','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('学生5','X202301000005','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('学生6','X202301000006','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('学生7','X202301000007','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('学生8','X202301000008','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('学生9','X202301000009','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('学生10','X2023010000010','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('学生11','X2023010000011','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE),
('学生12','X2023010000012','$2b$12$COT85R.ice41B/ofAra2ZewTe1En3ZhF6CBKOv2WScTcy.jQAhEVO',TRUE);
CREATE TABLE major CREATE TABLE major
( (
@@ -118,27 +153,20 @@ CREATE TABLE student
FOREIGN KEY (major_id) REFERENCES major (major_id) FOREIGN KEY (major_id) REFERENCES major (major_id)
); );
INSERT INTO student (user_id, student_number, student_name, class_id) INSERT INTO student (user_id, student_number, student_name, class_name,major_id)
VALUES (5,'王伟', 202300001000, 1), VALUES
(6,'李娜', 202300001001, 1), (5,'X202301000001','学生1','2023级01班','000'),
(7,'张伟', 202300001002, 1), (6,'X202301000002','学生2','2023级01班','000'),
(8,'刘洋', 202300001003, 1), (7,'X202301000003','学生3','2023级01班','000'),
(9,'陈敏', 202300001004, 1), (8,'X202301000004','学生4','2023级01班','000'),
(10,'杨静', 202300001005, 2), (9,'X202302000005','学生5','2023级02班','000'),
(11,'赵媛媛', 202300001006, 2), (10,'X202302000006','学生6','2023级02班','000'),
(12,'黄进', 202300001007, 2), (11,'X202302000007','学生7','2023级02班','000'),
(13,'周杰', 202300001008, 2), (12,'X202302000008','学生8','2023级02班','000'),
(14,'吴琳', 202300001009, 2), (13,'X202303000009','学生9','2023级03班','001'),
(15,'徐涛', 202300001010, 3), (14,'X202303000010','学生10','2023级03班','001'),
(16,'孙怡', 202300001011, 3), (15,'X202303000011','学生11','2023级03班','001'),
(17,'朱元璋', 202300001012, 3), (16,'X202303000012','学生12','2023级03班','001');
(18,'马云', 202300001013, 3),
(19,'胡雪', 202300001014, 3),
(20,'郭敬明', 202300001015, 4),
(21,'林芳', 202300001016, 4),
(22,'段誉', 202300001017, 4),
(23,'曹操', 202300001018, 4),
(24,'刘备', 202300001019, 4);
CREATE TABLE teacher CREATE TABLE teacher
( (
@@ -150,11 +178,11 @@ CREATE TABLE teacher
FOREIGN KEY (user_id) REFERENCES user (user_id) FOREIGN KEY (user_id) REFERENCES user (user_id)
); );
INSERT INTO teacher (name, user_id) INSERT INTO teacher (name, user_id,teacher_number)
VALUES ('教师1', 1), VALUES ('教师1', 1,'G0001'),
('教师2', 2), ('教师2', 2,'G0002'),
('教师3', 3), ('教师3', 3,'G0003'),
('教师4', 4); ('教师4', 4,'G0004');
CREATE TABLE major_course CREATE TABLE major_course
( (
@@ -189,65 +217,70 @@ CREATE TABLE teacher_class_course
); );
INSERT INTO teacher_class_course(teacher_number, course_id, class_name,major_id) VALUES INSERT INTO teacher_class_course(teacher_number, course_id, class_name,major_id) VALUES
('G0000',1,'2023级01班','000'); ('G0001',1,'2023级01班','000'),
('G0001',3,'2023级01班','000'),
INSERT INTO teacher_class_course(teacher_id, course_id, class_id) ('G0002',2,'2023级02班','000'),
VALUES (1, 1, 1), ('G0002',4,'2023级02班','000'),
(1, 2, 1), ('G0001',1,'2023级02班','000'),
(1, 1, 3), ('G0001',3,'2023级02班','000'),
(1, 1, 4), ('G0002',2,'2023级03班','001'),
(2, 2, 1), ('G0002',4,'2023级03班','001');
(2, 2, 2),
(2, 2, 3),
(2, 2, 4),
(3, 2, 1),
(3, 2, 2),
(3, 2, 3),
(3, 2, 4);
CREATE TABLE schedule CREATE TABLE schedule
( (
schedule_id INT AUTO_INCREMENT, schedule_id INT AUTO_INCREMENT UNIQUE,
day_of_week INT, day_of_week INT NOT NULL,
period_id INT, period_id INT NOT NULL,
teacher_id INT, teacher_number VARCHAR(20) NOT NULL,
class_id INT, class_name VARCHAR(20) NOT NULL,
course_id INT, course_id INT NOT NULL,
PRIMARY KEY (schedule_id), PRIMARY KEY (schedule_id),
FOREIGN KEY (period_id) REFERENCES time_period (period_id), FOREIGN KEY (period_id) REFERENCES time_period (period_id),
FOREIGN KEY (teacher_id) REFERENCES teacher (teacher_id), FOREIGN KEY (teacher_number) REFERENCES teacher (teacher_number),
FOREIGN KEY (class_id) REFERENCES class (class_id),
FOREIGN KEY (course_id) REFERENCES course (course_id) FOREIGN KEY (course_id) REFERENCES course (course_id)
); );
INSERT INTO schedule (day_of_week, period_id, teacher_id, class_id, course_id) VALUES INSERT INTO schedule (day_of_week, period_id, teacher_number, class_name, course_id) VALUES
(1,1,1,1,1), (1,1,'G0001','2023级01班',1),
(1,2,1,2,1), (1,2,'G0001','2023级01班',3),
(2,3,1,1,3), (1,3,'G0002','2023级01班',2),
(2,4,1,1,4), (1,4,'G0002','2023级01班',4),
(3,1,1,1,2), (2,1,'G0001','2023级01班',1),
(3,4,1,1,1), (2,2,'G0001','2023级01班',3),
(4,2,1,2,1), (2,3,'G0002','2023级01班',2),
(4,3,1,1,1), (2,4,'G0002','2023级01班',4),
(5,1,1,1,3), (3,1,'G0001','2023级01班',1),
(5,3,1,1,1); (3,2,'G0001','2023级01班',3),
(3,3,'G0002','2023级01班',2),
(3,4,'G0002','2023级01班',4),
(4,1,'G0001','2023级01班',1),
(4,2,'G0001','2023级01班',3),
(4,3,'G0002','2023级01班',2),
(4,4,'G0002','2023级01班',4),
(5,1,'G0001','2023级01班',1),
(5,2,'G0001','2023级01班',3),
(5,3,'G0002','2023级01班',2),
(5,4,'G0002','2023级01班',4),
(1,1,'G0002','2023级03班',2),
(1,2,'G0002','2023级03班',4),
(1,3,'G0001','2023级02班',1),
(1,4,'G0001','2023级02班',3),
(2,1,'G0002','2023级02班',2),
(2,2,'G0002','2023级02班',4),
(2,3,'G0001','2023级02班',1),
(2,4,'G0001','2023级02班',3),
(3,1,'G0002','2023级03班',2),
(3,2,'G0002','2023级03班',4),
(3,3,'G0001','2023级02班',1),
(3,4,'G0001','2023级02班',3),
(4,1,'G0002','2023级02班',2),
(4,2,'G0002','2023级02班',4),
(4,3,'G0001','2023级02班',1),
(4,4,'G0001','2023级02班',3),
(5,1,'G0002','2023级03班',2),
(5,2,'G0002','2023级03班',4),
(5,3,'G0001','2023级02班',1),
(5,4,'G0001','2023级02班',3);
CREATE TABLE time_period
(
period_id INT AUTO_INCREMENT,
period_name VARCHAR(10),
start_time TIME,
end_time TIME,
PRIMARY KEY (period_id)
);
INSERT INTO time_period (period_name, start_time, end_time)
VALUES ('一、二节', '08:00:00', '09:30:00'),
('三、四节', '10:00:00', '11:30:00'),
('五、六节', '14:30:00', '16:00:00'),
('七、八节', '16:30:00', '18:00:00');

Binary file not shown.

30
utils/parse_table.py Normal file
View File

@@ -0,0 +1,30 @@
from openpyxl import load_workbook
def parse_table(file_path, number):
# 加载Excel工作簿
work_book = load_workbook(file_path)
# 选择工作簿中的第一个工作表
sheet = work_book.active
# 创建一个列表来存储所有行的数据
data = []
# 从第二行开始遍历(假设第一行是标题行)
for row in sheet.iter_rows(min_row=2, values_only=True):
# 创建一个字典来存储每行的数据
row_data = {
"teacher_number": number,
"class_name": row[0], # 班级
"student_name": row[1], # 姓名
"student_number": row[2], # 学号
"course_id": row[3], # 课程id
"course_name": row[4], # 课程
"major_id": row[5], # 专业代码
"major": row[6]
}
data.append(row_data)
# 返回解析后的数据
return data

35
utils/time_utils.py Normal file
View File

@@ -0,0 +1,35 @@
import datetime
time_periods = {
1: {"period_name": "一、二节", "start_time": "08:00:00", "end_time": "09:30:00"},
2: {"period_name": "三、四节", "start_time": "10:00:00", "end_time": "11:30:00"},
3: {"period_name": "五、六节", "start_time": "14:30:00", "end_time": "16:00:00"},
4: {"period_name": "七、八节", "start_time": "16:30:00", "end_time": "18:00:00"}
}
def check_now_time():
# 获取当前时间
current_time = datetime.datetime.now().time()
# 遍历time_periods的每个时间段
for period_id, period_info in time_periods.items():
start_time = datetime.datetime.strptime(period_info["start_time"], "%H:%M:%S").time()
end_time = datetime.datetime.strptime(period_info["end_time"], "%H:%M:%S").time()
# 检查当前时间是否在时间段内
if start_time <= current_time <= end_time:
return period_id, period_info["period_name"]
# 如果当前时间不在任何一个时间段内
return None, "当前不在任何课程时间段内"
def get_time_by_ids(id):
# 获取对应的时间信息并添加到结果列表
period = time_periods.get(id)
if period: # 确保id是有效的
return period["start_time"][0:5] + "-" + period["end_time"][0:5]
else:
return None