v0.1测试
This commit is contained in:
11
backend/models/__init__.py
Normal file
11
backend/models/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# ===========================================
|
||||
# 班级操行分管理系统 - 后端服务
|
||||
#
|
||||
# 开发者: Canglan
|
||||
# 联系方式: admin@sea-studio.top
|
||||
# 版权归属: Sea Network Technology Studio
|
||||
# 许可证: MIT License
|
||||
#
|
||||
# 版权所有 © Sea Network Technology Studio
|
||||
# ===========================================
|
||||
|
||||
60
backend/models/admin_role.py
Normal file
60
backend/models/admin_role.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# ===========================================
|
||||
# 班级操行分管理系统 - 后端服务
|
||||
#
|
||||
# 开发者: Canglan
|
||||
# 联系方式: admin@sea-studio.top
|
||||
# 版权归属: Sea Network Technology Studio
|
||||
# 许可证: MIT License
|
||||
#
|
||||
# 版权所有 © Sea Network Technology Studio
|
||||
# ===========================================
|
||||
|
||||
from typing import Optional, Dict, Any, List
|
||||
from utils.database import execute_one, execute_query, execute_insert, execute_update
|
||||
|
||||
|
||||
class AdminRoleModel:
|
||||
"""管理员角色数据模型"""
|
||||
|
||||
@staticmethod
|
||||
async def get_by_user_id(user_id: int) -> Optional[Dict[str, Any]]:
|
||||
sql = """
|
||||
SELECT ar.*, c.class_name, s.subject_name
|
||||
FROM admin_roles ar
|
||||
LEFT JOIN classes c ON ar.class_id = c.class_id
|
||||
LEFT JOIN subjects s ON ar.subject_id = s.subject_id
|
||||
WHERE ar.user_id = %s
|
||||
LIMIT 1
|
||||
"""
|
||||
return await execute_one(sql, (user_id,))
|
||||
|
||||
@staticmethod
|
||||
async def get_class_id_by_user(user_id: int) -> Optional[int]:
|
||||
sql = "SELECT class_id FROM admin_roles WHERE user_id = %s LIMIT 1"
|
||||
result = await execute_one(sql, (user_id,))
|
||||
return result["class_id"] if result else None
|
||||
|
||||
@staticmethod
|
||||
async def get_by_class(class_id: int) -> List[Dict[str, Any]]:
|
||||
sql = """
|
||||
SELECT ar.*, u.real_name, u.username
|
||||
FROM admin_roles ar
|
||||
JOIN users u ON ar.user_id = u.user_id
|
||||
WHERE ar.class_id = %s
|
||||
ORDER BY ar.role_type
|
||||
"""
|
||||
return await execute_query(sql, (class_id,))
|
||||
|
||||
@staticmethod
|
||||
async def create(user_id: int, role_type: str, class_id: int, subject_id: int = None) -> int:
|
||||
sql = """
|
||||
INSERT INTO admin_roles (user_id, role_type, class_id, subject_id)
|
||||
VALUES (%s, %s, %s, %s)
|
||||
"""
|
||||
return await execute_insert(sql, (user_id, role_type, class_id, subject_id))
|
||||
|
||||
@staticmethod
|
||||
async def delete(user_id: int) -> bool:
|
||||
sql = "DELETE FROM admin_roles WHERE user_id = %s"
|
||||
result = await execute_update(sql, (user_id,))
|
||||
return result > 0
|
||||
98
backend/models/attenddance.py
Normal file
98
backend/models/attenddance.py
Normal file
@@ -0,0 +1,98 @@
|
||||
# ===========================================
|
||||
# 班级操行分管理系统 - 后端服务
|
||||
#
|
||||
# 开发者: Canglan
|
||||
# 联系方式: admin@sea-studio.top
|
||||
# 版权归属: Sea Network Technology Studio
|
||||
# 许可证: MIT License
|
||||
#
|
||||
# 版权所有 © Sea Network Technology Studio
|
||||
# ===========================================
|
||||
|
||||
from typing import Optional, Dict, Any, List
|
||||
from datetime import datetime
|
||||
from utils.database import execute_one, execute_query, execute_insert, execute_update
|
||||
|
||||
|
||||
class AttendanceModel:
|
||||
"""考勤数据模型"""
|
||||
|
||||
@staticmethod
|
||||
async def get_student_records(student_id: int, month: str = None) -> List[Dict[str, Any]]:
|
||||
sql = """
|
||||
SELECT attendance_id, date, status, reason, deduction_applied, created_at
|
||||
FROM attendance_records
|
||||
WHERE student_id = %s
|
||||
"""
|
||||
params = [student_id]
|
||||
|
||||
if month:
|
||||
sql += " AND DATE_FORMAT(date, '%%Y-%%m') = %s"
|
||||
params.append(month)
|
||||
|
||||
sql += " ORDER BY date DESC"
|
||||
|
||||
return await execute_query(sql, tuple(params))
|
||||
|
||||
@staticmethod
|
||||
async def get_class_records(
|
||||
class_id: int,
|
||||
date: str = None,
|
||||
student_id: int = None
|
||||
) -> List[Dict[str, Any]]:
|
||||
sql = """
|
||||
SELECT ar.*, s.name as student_name, s.student_no
|
||||
FROM attendance_records ar
|
||||
JOIN students s ON ar.student_id = s.student_id
|
||||
WHERE s.class_id = %s
|
||||
"""
|
||||
params = [class_id]
|
||||
|
||||
if date:
|
||||
sql += " AND ar.date = %s"
|
||||
params.append(date)
|
||||
|
||||
if student_id:
|
||||
sql += " AND ar.student_id = %s"
|
||||
params.append(student_id)
|
||||
|
||||
sql += " ORDER BY ar.date DESC, s.student_no"
|
||||
|
||||
return await execute_query(sql, tuple(params))
|
||||
|
||||
@staticmethod
|
||||
async def create_record(
|
||||
student_id: int,
|
||||
date: str,
|
||||
status: str,
|
||||
reason: str = None,
|
||||
recorder_id: int = None
|
||||
) -> int:
|
||||
# 检查是否已存在当天记录
|
||||
existing = await execute_one(
|
||||
"SELECT attendance_id FROM attendance_records WHERE student_id = %s AND date = %s",
|
||||
(student_id, date)
|
||||
)
|
||||
|
||||
if existing:
|
||||
# 更新已有记录
|
||||
sql = """
|
||||
UPDATE attendance_records
|
||||
SET status = %s, reason = %s, recorder_id = %s
|
||||
WHERE student_id = %s AND date = %s
|
||||
"""
|
||||
await execute_update(sql, (status, reason, recorder_id, student_id, date))
|
||||
return existing["attendance_id"]
|
||||
else:
|
||||
# 插入新记录
|
||||
sql = """
|
||||
INSERT INTO attendance_records (student_id, date, status, reason, recorder_id)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
"""
|
||||
return await execute_insert(sql, (student_id, date, status, reason, recorder_id))
|
||||
|
||||
@staticmethod
|
||||
async def mark_deduction_applied(attendance_id: int) -> bool:
|
||||
sql = "UPDATE attendance_records SET deduction_applied = 1 WHERE attendance_id = %s"
|
||||
result = await execute_update(sql, (attendance_id,))
|
||||
return result > 0
|
||||
35
backend/models/class_model.py
Normal file
35
backend/models/class_model.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# ===========================================
|
||||
# 班级操行分管理系统 - 后端服务
|
||||
#
|
||||
# 开发者: Canglan
|
||||
# 联系方式: admin@sea-studio.top
|
||||
# 版权归属: Sea Network Technology Studio
|
||||
# 许可证: MIT License
|
||||
#
|
||||
# 版权所有 © Sea Network Technology Studio
|
||||
# ===========================================
|
||||
|
||||
from typing import Optional, Dict, Any, List
|
||||
from utils.database import execute_one, execute_query, execute_insert, execute_update
|
||||
|
||||
|
||||
class ClassModel:
|
||||
"""班级数据模型"""
|
||||
|
||||
@staticmethod
|
||||
async def get_by_id(class_id: int) -> Optional[Dict[str, Any]]:
|
||||
sql = "SELECT * FROM classes WHERE class_id = %s"
|
||||
return await execute_one(sql, (class_id,))
|
||||
|
||||
@staticmethod
|
||||
async def get_all() -> List[Dict[str, Any]]:
|
||||
sql = "SELECT * FROM classes ORDER BY class_id"
|
||||
return await execute_query(sql)
|
||||
|
||||
@staticmethod
|
||||
async def create(class_name: str, grade: str = None, academic_year: str = None) -> int:
|
||||
sql = """
|
||||
INSERT INTO classes (class_name, grade, academic_year)
|
||||
VALUES (%s, %s, %s)
|
||||
"""
|
||||
return await execute_insert(sql, (class_name, grade, academic_year))
|
||||
166
backend/models/conduct.py
Normal file
166
backend/models/conduct.py
Normal file
@@ -0,0 +1,166 @@
|
||||
# ===========================================
|
||||
# 班级操行分管理系统 - 后端服务
|
||||
#
|
||||
# 开发者: Canglan
|
||||
# 联系方式: admin@sea-studio.top
|
||||
# 版权归属: Sea Network Technology Studio
|
||||
# 许可证: MIT License
|
||||
#
|
||||
# 版权所有 © Sea Network Technology Studio
|
||||
# ===========================================
|
||||
|
||||
from typing import Optional, List, Dict, Any
|
||||
from datetime import datetime
|
||||
from utils.database import execute_one, execute_query, execute_insert, execute_update, call_procedure
|
||||
from utils.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class ConductModel:
|
||||
"""操行分数据模型"""
|
||||
|
||||
@staticmethod
|
||||
async def create_record(
|
||||
student_id: int,
|
||||
points_change: int,
|
||||
reason: str,
|
||||
recorder_id: int,
|
||||
recorder_name: str = None,
|
||||
related_type: str = 'manual',
|
||||
related_id: int = None
|
||||
) -> int:
|
||||
"""创建操行分记录"""
|
||||
sql = """
|
||||
INSERT INTO conduct_records
|
||||
(student_id, points_change, reason, recorder_id, recorder_name, related_type, related_id)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
return await execute_insert(sql, (
|
||||
student_id, points_change, reason, recorder_id, recorder_name, related_type, related_id
|
||||
))
|
||||
|
||||
@staticmethod
|
||||
async def get_student_records(
|
||||
student_id: int,
|
||||
limit: int = 50,
|
||||
offset: int = 0,
|
||||
include_revoked: bool = False
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""获取学生操行分记录"""
|
||||
sql = """
|
||||
SELECT cr.*, u.real_name as recorder_name
|
||||
FROM conduct_records cr
|
||||
LEFT JOIN users u ON cr.recorder_id = u.user_id
|
||||
WHERE cr.student_id = %s
|
||||
"""
|
||||
if not include_revoked:
|
||||
sql += " AND cr.is_revoked = 0"
|
||||
sql += " ORDER BY cr.created_at DESC LIMIT %s OFFSET %s"
|
||||
return await execute_query(sql, (student_id, limit, offset))
|
||||
|
||||
@staticmethod
|
||||
async def get_records_by_recorder(
|
||||
recorder_id: int,
|
||||
limit: int = 50,
|
||||
offset: int = 0
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""获取操作人提交的记录"""
|
||||
sql = """
|
||||
SELECT cr.*, s.name as student_name
|
||||
FROM conduct_records cr
|
||||
JOIN students s ON cr.student_id = s.student_id
|
||||
WHERE cr.recorder_id = %s AND cr.is_revoked = 0
|
||||
ORDER BY cr.created_at DESC
|
||||
LIMIT %s OFFSET %s
|
||||
"""
|
||||
return await execute_query(sql, (recorder_id, limit, offset))
|
||||
|
||||
@staticmethod
|
||||
async def get_all_records(
|
||||
class_id: int = None,
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
start_date: str = None,
|
||||
end_date: str = None
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""获取所有记录(班主任/班长专用)"""
|
||||
sql = """
|
||||
SELECT cr.*, s.name as student_name, s.student_no, u.real_name as recorder_name
|
||||
FROM conduct_records cr
|
||||
JOIN students s ON cr.student_id = s.student_id
|
||||
JOIN users u ON cr.recorder_id = u.user_id
|
||||
WHERE cr.is_revoked = 0
|
||||
"""
|
||||
params = []
|
||||
|
||||
if class_id:
|
||||
sql += " AND s.class_id = %s"
|
||||
params.append(class_id)
|
||||
|
||||
if start_date:
|
||||
sql += " AND DATE(cr.created_at) >= %s"
|
||||
params.append(start_date)
|
||||
|
||||
if end_date:
|
||||
sql += " AND DATE(cr.created_at) <= %s"
|
||||
params.append(end_date)
|
||||
|
||||
sql += " ORDER BY cr.created_at DESC LIMIT %s OFFSET %s"
|
||||
params.extend([limit, offset])
|
||||
|
||||
return await execute_query(sql, tuple(params))
|
||||
|
||||
@staticmethod
|
||||
async def get_record_by_id(record_id: int) -> Optional[Dict[str, Any]]:
|
||||
"""根据ID获取记录"""
|
||||
sql = """
|
||||
SELECT cr.*, s.name as student_name, s.total_points
|
||||
FROM conduct_records cr
|
||||
JOIN students s ON cr.student_id = s.student_id
|
||||
WHERE cr.record_id = %s
|
||||
"""
|
||||
return await execute_one(sql, (record_id,))
|
||||
|
||||
@staticmethod
|
||||
async def revoke_record(record_id: int, revoker_id: int) -> bool:
|
||||
"""撤销记录"""
|
||||
try:
|
||||
await call_procedure('revoke_conduct_record', (record_id, revoker_id))
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"撤销记录失败: {e}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
async def batch_create_records(records_data: List[Dict]) -> List[Dict]:
|
||||
"""批量创建操行分记录"""
|
||||
results = []
|
||||
for record in records_data:
|
||||
try:
|
||||
record_id = await ConductModel.create_record(
|
||||
student_id=record.get('student_id'),
|
||||
points_change=record.get('points_change'),
|
||||
reason=record.get('reason'),
|
||||
recorder_id=record.get('recorder_id'),
|
||||
recorder_name=record.get('recorder_name')
|
||||
)
|
||||
results.append({
|
||||
'student_id': record.get('student_id'),
|
||||
'success': True,
|
||||
'record_id': record_id
|
||||
})
|
||||
except Exception as e:
|
||||
results.append({
|
||||
'student_id': record.get('student_id'),
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
})
|
||||
return results
|
||||
|
||||
@staticmethod
|
||||
async def get_student_total_points(student_id: int) -> int:
|
||||
"""获取学生当前总分"""
|
||||
sql = "SELECT total_points FROM students WHERE student_id = %s"
|
||||
result = await execute_one(sql, (student_id,))
|
||||
return result['total_points'] if result else 100
|
||||
118
backend/models/homework.py
Normal file
118
backend/models/homework.py
Normal file
@@ -0,0 +1,118 @@
|
||||
# ===========================================
|
||||
# 班级操行分管理系统 - 后端服务
|
||||
#
|
||||
# 开发者: Canglan
|
||||
# 联系方式: admin@sea-studio.top
|
||||
# 版权归属: Sea Network Technology Studio
|
||||
# 许可证: MIT License
|
||||
#
|
||||
# 版权所有 © Sea Network Technology Studio
|
||||
# ===========================================
|
||||
|
||||
from typing import Optional, Dict, Any, List
|
||||
from utils.database import execute_one, execute_query, execute_insert, execute_update
|
||||
|
||||
|
||||
class HomeworkModel:
|
||||
"""作业数据模型"""
|
||||
|
||||
@staticmethod
|
||||
async def get_assignments_by_class(class_id: int) -> List[Dict[str, Any]]:
|
||||
sql = """
|
||||
SELECT a.*, s.subject_name, u.real_name as created_by_name
|
||||
FROM assignments a
|
||||
JOIN subjects s ON a.subject_id = s.subject_id
|
||||
JOIN users u ON a.created_by = u.user_id
|
||||
WHERE a.class_id = %s
|
||||
ORDER BY a.deadline ASC, a.created_at DESC
|
||||
"""
|
||||
return await execute_query(sql, (class_id,))
|
||||
|
||||
@staticmethod
|
||||
async def get_assignments_by_subjects(class_id: int, subject_ids: List[int]) -> List[Dict[str, Any]]:
|
||||
if not subject_ids:
|
||||
return []
|
||||
placeholders = ','.join(['%s'] * len(subject_ids))
|
||||
sql = f"""
|
||||
SELECT a.*, s.subject_name, u.real_name as created_by_name
|
||||
FROM assignments a
|
||||
JOIN subjects s ON a.subject_id = s.subject_id
|
||||
JOIN users u ON a.created_by = u.user_id
|
||||
WHERE a.class_id = %s AND a.subject_id IN ({placeholders})
|
||||
ORDER BY a.deadline ASC, a.created_at DESC
|
||||
"""
|
||||
params = [class_id] + subject_ids
|
||||
return await execute_query(sql, tuple(params))
|
||||
|
||||
@staticmethod
|
||||
async def get_student_homework(student_id: int) -> List[Dict[str, Any]]:
|
||||
sql = """
|
||||
SELECT a.assignment_id, a.title, a.description, a.deadline,
|
||||
s.subject_name, hs.status, hs.submit_time, hs.comments, hs.deduction_applied
|
||||
FROM assignments a
|
||||
JOIN subjects s ON a.subject_id = s.subject_id
|
||||
LEFT JOIN homework_submissions hs ON a.assignment_id = hs.assignment_id AND hs.student_id = %s
|
||||
WHERE a.class_id = (SELECT class_id FROM students WHERE student_id = %s)
|
||||
ORDER BY a.deadline ASC, a.created_at DESC
|
||||
"""
|
||||
return await execute_query(sql, (student_id, student_id))
|
||||
|
||||
@staticmethod
|
||||
async def get_submission(submission_id: int) -> Optional[Dict[str, Any]]:
|
||||
sql = """
|
||||
SELECT hs.*, a.title, a.subject_id, a.assignment_id, s.name as student_name
|
||||
FROM homework_submissions hs
|
||||
JOIN assignments a ON hs.assignment_id = a.assignment_id
|
||||
JOIN students s ON hs.student_id = s.student_id
|
||||
WHERE hs.submission_id = %s
|
||||
"""
|
||||
return await execute_one(sql, (submission_id,))
|
||||
|
||||
@staticmethod
|
||||
async def create_assignment(
|
||||
class_id: int,
|
||||
subject_id: int,
|
||||
title: str,
|
||||
description: str,
|
||||
deadline: str,
|
||||
created_by: int
|
||||
) -> int:
|
||||
sql = """
|
||||
INSERT INTO assignments (class_id, subject_id, title, description, deadline, created_by)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
assignment_id = await execute_insert(sql, (class_id, subject_id, title, description, deadline, created_by))
|
||||
|
||||
# 为班级所有学生创建提交记录
|
||||
from models.student import StudentModel
|
||||
students = await StudentModel.get_by_class(class_id)
|
||||
|
||||
for student in students:
|
||||
sql_sub = """
|
||||
INSERT INTO homework_submissions (assignment_id, student_id, status)
|
||||
VALUES (%s, %s, 'not_submitted')
|
||||
"""
|
||||
await execute_insert(sql_sub, (assignment_id, student["student_id"]))
|
||||
|
||||
return assignment_id
|
||||
|
||||
@staticmethod
|
||||
async def update_submission(
|
||||
submission_id: int,
|
||||
status: str,
|
||||
comments: str = None,
|
||||
updated_by: int = None
|
||||
) -> bool:
|
||||
sql = """
|
||||
UPDATE homework_submissions
|
||||
SET status = %s, comments = %s, updated_by = %s, updated_at = NOW()
|
||||
WHERE submission_id = %s
|
||||
"""
|
||||
result = await execute_update(sql, (status, comments, updated_by, submission_id))
|
||||
return result > 0
|
||||
|
||||
@staticmethod
|
||||
async def mark_deduction_applied(submission_id: int) -> bool:
|
||||
sql = "UPDATE homework_submissions SET deduction_applied = 1 WHERE submission_id = %s"
|
||||
result = await execute_update(sql, (submission_id,))
|
||||
return result > 0
|
||||
146
backend/models/student.py
Normal file
146
backend/models/student.py
Normal file
@@ -0,0 +1,146 @@
|
||||
# ===========================================
|
||||
# 班级操行分管理系统 - 学生数据模型
|
||||
#
|
||||
# 开发者: Canglan
|
||||
# 联系方式: admin@sea-studio.top
|
||||
# 版权归属: Sea Network Technology Studio
|
||||
# 许可证: MIT License
|
||||
#
|
||||
# 版权所有 © Sea Network Technology Studio
|
||||
# ===========================================
|
||||
|
||||
from typing import Optional, List, Dict, Any
|
||||
from utils.database import execute_one, execute_query, execute_insert, execute_update, execute_many
|
||||
from utils.security import security
|
||||
from utils.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class StudentModel:
|
||||
"""学生数据模型"""
|
||||
|
||||
@staticmethod
|
||||
async def get_by_id(student_id: int) -> Optional[Dict[str, Any]]:
|
||||
"""根据ID获取学生信息"""
|
||||
sql = """
|
||||
SELECT s.*
|
||||
FROM students s
|
||||
WHERE s.student_id = %s
|
||||
"""
|
||||
return await execute_one(sql, (student_id,))
|
||||
|
||||
@staticmethod
|
||||
async def get_by_student_no(student_no: str) -> Optional[Dict[str, Any]]:
|
||||
"""根据学号获取学生信息"""
|
||||
sql = """
|
||||
SELECT s.*
|
||||
FROM students s
|
||||
WHERE s.student_no = %s
|
||||
"""
|
||||
return await execute_one(sql, (student_no,))
|
||||
|
||||
@staticmethod
|
||||
async def get_all(include_disabled: bool = False) -> List[Dict[str, Any]]:
|
||||
"""获取所有学生列表(单班级)"""
|
||||
sql = """
|
||||
SELECT student_id, student_no, name, total_points, parent_phone, status
|
||||
FROM students
|
||||
WHERE 1=1
|
||||
"""
|
||||
if not include_disabled:
|
||||
sql += " AND status = 1"
|
||||
sql += " ORDER BY student_no"
|
||||
return await execute_query(sql)
|
||||
|
||||
@staticmethod
|
||||
async def create(
|
||||
student_no: str,
|
||||
name: str,
|
||||
class_id: int,
|
||||
parent_phone: str = None,
|
||||
initial_points: int = 60
|
||||
) -> int:
|
||||
"""创建学生(初始操行分默认60分)"""
|
||||
sql = """
|
||||
INSERT INTO students (student_no, name, class_id, parent_phone, total_points)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
"""
|
||||
return await execute_insert(sql, (student_no, name, class_id, parent_phone, initial_points))
|
||||
|
||||
@staticmethod
|
||||
async def update(student_id: int, name: str = None, parent_phone: str = None, status: int = None) -> bool:
|
||||
"""更新学生信息"""
|
||||
updates = []
|
||||
params = []
|
||||
|
||||
if name is not None:
|
||||
updates.append("name = %s")
|
||||
params.append(name)
|
||||
if parent_phone is not None:
|
||||
updates.append("parent_phone = %s")
|
||||
params.append(parent_phone)
|
||||
if status is not None:
|
||||
updates.append("status = %s")
|
||||
params.append(status)
|
||||
|
||||
if not updates:
|
||||
return True
|
||||
|
||||
params.append(student_id)
|
||||
sql = f"UPDATE students SET {', '.join(updates)} WHERE student_id = %s"
|
||||
result = await execute_update(sql, tuple(params))
|
||||
return result > 0
|
||||
|
||||
@staticmethod
|
||||
async def delete(student_id: int) -> bool:
|
||||
"""删除学生(软删除)"""
|
||||
sql = "UPDATE students SET status = 0 WHERE student_id = %s"
|
||||
result = await execute_update(sql, (student_id,))
|
||||
return result > 0
|
||||
|
||||
@staticmethod
|
||||
async def update_total_points(student_id: int, points_change: int) -> bool:
|
||||
"""更新学生总分"""
|
||||
sql = "UPDATE students SET total_points = total_points + %s WHERE student_id = %s"
|
||||
result = await execute_update(sql, (points_change, student_id))
|
||||
return result > 0
|
||||
|
||||
@staticmethod
|
||||
async def get_ranking(limit: int = 50) -> List[Dict[str, Any]]:
|
||||
"""获取学生排行(单班级)"""
|
||||
sql = """
|
||||
SELECT student_id, student_no, name, total_points,
|
||||
RANK() OVER (ORDER BY total_points DESC) as rank
|
||||
FROM students
|
||||
WHERE status = 1
|
||||
ORDER BY total_points DESC
|
||||
LIMIT %s
|
||||
"""
|
||||
return await execute_query(sql, (limit,))
|
||||
|
||||
@staticmethod
|
||||
async def batch_create(students_data: List[Dict], initial_points: int = 60) -> List[Dict]:
|
||||
"""批量创建学生"""
|
||||
results = []
|
||||
for student in students_data:
|
||||
try:
|
||||
student_id = await StudentModel.create(
|
||||
student_no=student.get('student_no'),
|
||||
name=student.get('name'),
|
||||
class_id=1, # 单班级,固定为1
|
||||
parent_phone=student.get('parent_phone'),
|
||||
initial_points=initial_points
|
||||
)
|
||||
results.append({
|
||||
'student_no': student.get('student_no'),
|
||||
'success': True,
|
||||
'student_id': student_id
|
||||
})
|
||||
except Exception as e:
|
||||
results.append({
|
||||
'student_no': student.get('student_no'),
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
})
|
||||
return results
|
||||
82
backend/models/subject.py
Normal file
82
backend/models/subject.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# ===========================================
|
||||
# 班级操行分管理系统 - 后端服务
|
||||
#
|
||||
# 开发者: Canglan
|
||||
# 联系方式: admin@sea-studio.top
|
||||
# 版权归属: Sea Network Technology Studio
|
||||
# 许可证: MIT License
|
||||
#
|
||||
# 版权所有 © Sea Network Technology Studio
|
||||
# ===========================================
|
||||
|
||||
from typing import Optional, Dict, Any, List
|
||||
from utils.database import execute_one, execute_query, execute_insert, execute_update
|
||||
|
||||
|
||||
class SubjectModel:
|
||||
"""科目数据模型"""
|
||||
|
||||
@staticmethod
|
||||
async def get_all(is_active: bool = None) -> List[Dict[str, Any]]:
|
||||
if is_active is not None:
|
||||
sql = "SELECT * FROM subjects WHERE is_active = %s ORDER BY sort_order, subject_id"
|
||||
return await execute_query(sql, (1 if is_active else 0,))
|
||||
else:
|
||||
sql = "SELECT * FROM subjects ORDER BY sort_order, subject_id"
|
||||
return await execute_query(sql)
|
||||
|
||||
@staticmethod
|
||||
async def get_by_id(subject_id: int) -> Optional[Dict[str, Any]]:
|
||||
sql = "SELECT * FROM subjects WHERE subject_id = %s"
|
||||
return await execute_one(sql, (subject_id,))
|
||||
|
||||
@staticmethod
|
||||
async def get_by_name(subject_name: str) -> Optional[Dict[str, Any]]:
|
||||
sql = "SELECT * FROM subjects WHERE subject_name = %s"
|
||||
return await execute_one(sql, (subject_name,))
|
||||
|
||||
@staticmethod
|
||||
async def create(subject_name: str, subject_code: str = None, sort_order: int = 0) -> int:
|
||||
sql = """
|
||||
INSERT INTO subjects (subject_name, subject_code, sort_order)
|
||||
VALUES (%s, %s, %s)
|
||||
"""
|
||||
return await execute_insert(sql, (subject_name, subject_code, sort_order))
|
||||
|
||||
@staticmethod
|
||||
async def update(subject_id: int, **kwargs) -> bool:
|
||||
updates = []
|
||||
params = []
|
||||
|
||||
if "subject_name" in kwargs:
|
||||
updates.append("subject_name = %s")
|
||||
params.append(kwargs["subject_name"])
|
||||
if "subject_code" in kwargs:
|
||||
updates.append("subject_code = %s")
|
||||
params.append(kwargs["subject_code"])
|
||||
if "is_active" in kwargs:
|
||||
updates.append("is_active = %s")
|
||||
params.append(1 if kwargs["is_active"] else 0)
|
||||
if "sort_order" in kwargs:
|
||||
updates.append("sort_order = %s")
|
||||
params.append(kwargs["sort_order"])
|
||||
|
||||
if not updates:
|
||||
return True
|
||||
|
||||
params.append(subject_id)
|
||||
sql = f"UPDATE subjects SET {', '.join(updates)} WHERE subject_id = %s"
|
||||
result = await execute_update(sql, tuple(params))
|
||||
return result > 0
|
||||
|
||||
@staticmethod
|
||||
async def delete(subject_id: int) -> bool:
|
||||
sql = "UPDATE subjects SET is_active = 0 WHERE subject_id = %s"
|
||||
result = await execute_update(sql, (subject_id,))
|
||||
return result > 0
|
||||
|
||||
@staticmethod
|
||||
async def activate(subject_id: int) -> bool:
|
||||
sql = "UPDATE subjects SET is_active = 1 WHERE subject_id = %s"
|
||||
result = await execute_update(sql, (subject_id,))
|
||||
return result > 0
|
||||
101
backend/models/user.py
Normal file
101
backend/models/user.py
Normal file
@@ -0,0 +1,101 @@
|
||||
# ===========================================
|
||||
# 班级操行分管理系统 - 后端服务
|
||||
#
|
||||
# 开发者: Canglan
|
||||
# 联系方式: admin@sea-studio.top
|
||||
# 版权归属: Sea Network Technology Studio
|
||||
# 许可证: MIT License
|
||||
#
|
||||
# 版权所有 © Sea Network Technology Studio
|
||||
# ===========================================
|
||||
|
||||
from utils.database import execute_one, execute_insert, execute_update
|
||||
from utils.security import security
|
||||
from utils.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class UserModel:
|
||||
"""用户数据模型"""
|
||||
|
||||
@staticmethod
|
||||
async def get_by_username(username: str) -> dict:
|
||||
"""根据用户名获取用户"""
|
||||
sql = """
|
||||
SELECT user_id, username, password_hash, real_name, user_type,
|
||||
student_id, status, need_change_password, last_login_time, last_login_ip
|
||||
FROM users
|
||||
WHERE username = %s AND status = 1
|
||||
"""
|
||||
return await execute_one(sql, (username,))
|
||||
|
||||
@staticmethod
|
||||
async def get_by_user_id(user_id: int) -> dict:
|
||||
"""根据用户ID获取用户"""
|
||||
sql = """
|
||||
SELECT user_id, username, real_name, user_type, student_id,
|
||||
need_change_password, status
|
||||
FROM users
|
||||
WHERE user_id = %s
|
||||
"""
|
||||
return await execute_one(sql, (user_id,))
|
||||
|
||||
@staticmethod
|
||||
async def create_student(username: str, password: str, real_name: str, student_id: int) -> int:
|
||||
"""创建学生账号"""
|
||||
password_hash = security.sha1_md5_password(password)
|
||||
sql = """
|
||||
INSERT INTO users (username, password_hash, real_name, user_type, student_id, need_change_password)
|
||||
VALUES (%s, %s, %s, 'student', %s, 1)
|
||||
"""
|
||||
return await execute_insert(sql, (username, password_hash, real_name, student_id))
|
||||
|
||||
@staticmethod
|
||||
async def create_parent(username: str, password: str, real_name: str, student_id: int) -> int:
|
||||
"""创建家长账号"""
|
||||
password_hash = security.sha1_md5_password(password)
|
||||
sql = """
|
||||
INSERT INTO users (username, password_hash, real_name, user_type, student_id, need_change_password)
|
||||
VALUES (%s, %s, %s, 'parent', %s, 0)
|
||||
"""
|
||||
return await execute_insert(sql, (username, password_hash, real_name, student_id))
|
||||
|
||||
@staticmethod
|
||||
async def create_admin(username: str, password: str, real_name: str) -> int:
|
||||
"""创建管理员账号"""
|
||||
password_hash = security.sha1_md5_password(password)
|
||||
sql = """
|
||||
INSERT INTO users (username, password_hash, real_name, user_type, need_change_password)
|
||||
VALUES (%s, %s, %s, 'admin', 1)
|
||||
"""
|
||||
return await execute_insert(sql, (username, password_hash, real_name))
|
||||
|
||||
@staticmethod
|
||||
async def update_password(user_id: int, new_password: str) -> bool:
|
||||
"""更新密码"""
|
||||
password_hash = security.sha1_md5_password(new_password)
|
||||
sql = """
|
||||
UPDATE users
|
||||
SET password_hash = %s, need_change_password = 0
|
||||
WHERE user_id = %s
|
||||
"""
|
||||
result = await execute_update(sql, (password_hash, user_id))
|
||||
return result > 0
|
||||
|
||||
@staticmethod
|
||||
async def update_last_login(user_id: int, ip: str) -> None:
|
||||
"""更新最后登录信息"""
|
||||
sql = """
|
||||
UPDATE users
|
||||
SET last_login_time = NOW(), last_login_ip = %s
|
||||
WHERE user_id = %s
|
||||
"""
|
||||
await execute_update(sql, (ip, user_id))
|
||||
|
||||
@staticmethod
|
||||
async def check_username_exists(username: str) -> bool:
|
||||
"""检查用户名是否存在"""
|
||||
sql = "SELECT 1 FROM users WHERE username = %s"
|
||||
result = await execute_one(sql, (username,))
|
||||
return result is not None
|
||||
Reference in New Issue
Block a user