v0.8测试
This commit is contained in:
@@ -85,13 +85,28 @@ app.add_middleware(
|
|||||||
async def global_exception_handler(request: Request, exc: Exception):
|
async def global_exception_handler(request: Request, exc: Exception):
|
||||||
"""全局异常处理器 - 捕获所有未处理异常"""
|
"""全局异常处理器 - 捕获所有未处理异常"""
|
||||||
logger.error(f"未处理异常: {exc}", exc_info=True)
|
logger.error(f"未处理异常: {exc}", exc_info=True)
|
||||||
|
|
||||||
|
# 获取origin用于CORS头
|
||||||
|
origin = request.headers.get("origin", "")
|
||||||
|
allowed_origins = settings.CORS_ORIGINS or []
|
||||||
|
|
||||||
|
# 使用HTTP 200 + 业务错误码返回,避免CORS头丢失问题
|
||||||
|
# (FastAPI exception_handler返回的500响应可能不经过CORS中间件,导致跨域读取失败)
|
||||||
|
headers = {}
|
||||||
|
if origin in allowed_origins:
|
||||||
|
headers["access-control-allow-origin"] = origin
|
||||||
|
headers["access-control-allow-credentials"] = "true"
|
||||||
|
headers["access-control-expose-headers"] = "*"
|
||||||
|
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
status_code=500,
|
status_code=200,
|
||||||
content={
|
content={
|
||||||
"success": False,
|
"success": False,
|
||||||
|
"code": 500,
|
||||||
"message": f"服务器内部错误: {str(exc)}",
|
"message": f"服务器内部错误: {str(exc)}",
|
||||||
"detail": traceback.format_exc() if settings.DEBUG else None
|
"detail": traceback.format_exc() if settings.DEBUG else None
|
||||||
}
|
},
|
||||||
|
headers=headers
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,12 @@ class PermissionChecker:
|
|||||||
role = await PermissionChecker.get_user_role(user_id)
|
role = await PermissionChecker.get_user_role(user_id)
|
||||||
return role == "劳动委员"
|
return role == "劳动委员"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def check_is_volunteer_rep(user_id: int) -> bool:
|
||||||
|
"""检查是否为志愿委员"""
|
||||||
|
role = await PermissionChecker.get_user_role(user_id)
|
||||||
|
return role == "志愿委员"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def check_can_manage_subjects(user_id: int) -> bool:
|
async def check_can_manage_subjects(user_id: int) -> bool:
|
||||||
"""检查是否可以管理科目(班主任或学习委员)"""
|
"""检查是否可以管理科目(班主任或学习委员)"""
|
||||||
@@ -127,7 +133,7 @@ class PermissionChecker:
|
|||||||
if not record:
|
if not record:
|
||||||
return False
|
return False
|
||||||
role = await PermissionChecker.get_user_role(user_id)
|
role = await PermissionChecker.get_user_role(user_id)
|
||||||
if role in ["班主任", "班长"]:
|
if role in ["班主任", "班长", "志愿委员"]:
|
||||||
return True
|
return True
|
||||||
return record["recorder_id"] == user_id
|
return record["recorder_id"] == user_id
|
||||||
|
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ async def get_conduct_history(
|
|||||||
return success_response(data=result)
|
return success_response(data=result)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取历史记录失败: {e}", exc_info=True)
|
logger.error(f"获取历史记录失败: {e}", exc_info=True)
|
||||||
return error_response(message=f"获取历史记录失败: {str(e)}", code=500)
|
return error_response(message=f"获取历史记录失败: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
# ========== 作业管理 ==========
|
# ========== 作业管理 ==========
|
||||||
@@ -299,7 +299,8 @@ async def add_attendance(request: Request, req: AddAttendanceRequest):
|
|||||||
status=req.status,
|
status=req.status,
|
||||||
reason=req.reason,
|
reason=req.reason,
|
||||||
apply_deduction=req.apply_deduction,
|
apply_deduction=req.apply_deduction,
|
||||||
recorder_id=user["user_id"]
|
recorder_id=user["user_id"],
|
||||||
|
custom_deduction=req.custom_deduction
|
||||||
)
|
)
|
||||||
if result["success"]:
|
if result["success"]:
|
||||||
await LogService.write_operation_log(
|
await LogService.write_operation_log(
|
||||||
@@ -339,7 +340,7 @@ async def add_admin(request: Request, req: AddAdminRequest):
|
|||||||
is_teacher = await PermissionChecker.check_is_teacher(user["user_id"])
|
is_teacher = await PermissionChecker.check_is_teacher(user["user_id"])
|
||||||
if not is_teacher:
|
if not is_teacher:
|
||||||
return error_response(message="仅班主任可添加管理员", code=403)
|
return error_response(message="仅班主任可添加管理员", code=403)
|
||||||
if req.role_type not in ["班长", "学习委员", "考勤委员", "劳动委员"]:
|
if req.role_type not in ["班长", "学习委员", "考勤委员", "劳动委员", "志愿委员"]:
|
||||||
return error_response(message="无效的角色类型", code=400)
|
return error_response(message="无效的角色类型", code=400)
|
||||||
result = await AdminService.add_admin(
|
result = await AdminService.add_admin(
|
||||||
username=req.username,
|
username=req.username,
|
||||||
@@ -373,4 +374,4 @@ async def get_admins(request: Request):
|
|||||||
return success_response(data=result)
|
return success_response(data=result)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取管理员列表失败: {e}", exc_info=True)
|
logger.error(f"获取管理员列表失败: {e}", exc_info=True)
|
||||||
return error_response(message=f"获取管理员列表失败: {str(e)}", code=500)
|
return error_response(message=f"获取管理员列表失败: {str(e)}")
|
||||||
@@ -34,7 +34,7 @@ class AddAdminDebugRequest(BaseModel):
|
|||||||
async def debug_add_admin(request: Request, req: AddAdminDebugRequest):
|
async def debug_add_admin(request: Request, req: AddAdminDebugRequest):
|
||||||
from models.user import UserModel
|
from models.user import UserModel
|
||||||
|
|
||||||
valid_roles = ["班主任", "班长", "学习委员", "考勤委员", "劳动委员"]
|
valid_roles = ["班主任", "班长", "学习委员", "考勤委员", "劳动委员", "志愿委员"]
|
||||||
if req.role_type not in valid_roles:
|
if req.role_type not in valid_roles:
|
||||||
return error_response(message=f"无效的角色类型,可选: {', '.join(valid_roles)}")
|
return error_response(message=f"无效的角色类型,可选: {', '.join(valid_roles)}")
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ async def get_conduct_history(
|
|||||||
return success_response(data=result)
|
return success_response(data=result)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取学生操行分失败: {e}", exc_info=True)
|
logger.error(f"获取学生操行分失败: {e}", exc_info=True)
|
||||||
return error_response(message=f"获取学生操行分失败: {str(e)}", code=500)
|
return error_response(message=f"获取学生操行分失败: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
@router.get("/homework/{student_id}")
|
@router.get("/homework/{student_id}")
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ async def get_subjects(request: Request, is_active: Optional[bool] = None):
|
|||||||
return success_response(data=result)
|
return success_response(data=result)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取科目列表失败: {e}", exc_info=True)
|
logger.error(f"获取科目列表失败: {e}", exc_info=True)
|
||||||
return error_response(message=f"获取科目列表失败: {str(e)}", code=500)
|
return error_response(message=f"获取科目列表失败: {str(e)}")
|
||||||
|
|
||||||
@router.post("/create")
|
@router.post("/create")
|
||||||
async def create_subject(request: Request, req: CreateSubjectRequest):
|
async def create_subject(request: Request, req: CreateSubjectRequest):
|
||||||
|
|||||||
@@ -84,4 +84,5 @@ class AddAttendanceRequest(BaseModel):
|
|||||||
date: date
|
date: date
|
||||||
status: str
|
status: str
|
||||||
reason: Optional[str] = None
|
reason: Optional[str] = None
|
||||||
apply_deduction: bool = False
|
apply_deduction: bool = True
|
||||||
|
custom_deduction: Optional[int] = Field(default=None, gt=0, description="自定义扣分值")
|
||||||
@@ -32,7 +32,8 @@ class AttendanceService:
|
|||||||
status: str,
|
status: str,
|
||||||
reason: Optional[str],
|
reason: Optional[str],
|
||||||
apply_deduction: bool,
|
apply_deduction: bool,
|
||||||
recorder_id: int
|
recorder_id: int,
|
||||||
|
custom_deduction: Optional[int] = None
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""添加考勤记录"""
|
"""添加考勤记录"""
|
||||||
# 检查权限
|
# 检查权限
|
||||||
@@ -57,8 +58,10 @@ class AttendanceService:
|
|||||||
|
|
||||||
# 应用扣分
|
# 应用扣分
|
||||||
if apply_deduction and status in ["absent", "late", "leave"]:
|
if apply_deduction and status in ["absent", "late", "leave"]:
|
||||||
# 确定扣分数值
|
# 确定扣分数值(优先使用自定义扣分)
|
||||||
if status == "absent":
|
if custom_deduction is not None:
|
||||||
|
points_change = -custom_deduction
|
||||||
|
elif status == "absent":
|
||||||
points_change = -settings.DEDUCTION_ATTENDANCE_ABSENT
|
points_change = -settings.DEDUCTION_ATTENDANCE_ABSENT
|
||||||
elif status == "late":
|
elif status == "late":
|
||||||
points_change = -settings.DEDUCTION_ATTENDANCE_LATE
|
points_change = -settings.DEDUCTION_ATTENDANCE_LATE
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ class ConductService:
|
|||||||
# 劳动委员固定 ±1分
|
# 劳动委员固定 ±1分
|
||||||
if points_change not in [settings.LABOR_POINTS_ADD, settings.LABOR_POINTS_SUBTRACT]:
|
if points_change not in [settings.LABOR_POINTS_ADD, settings.LABOR_POINTS_SUBTRACT]:
|
||||||
return {"success": False, "message": "劳动委员只能进行±1分操作"}
|
return {"success": False, "message": "劳动委员只能进行±1分操作"}
|
||||||
|
elif role == "志愿委员":
|
||||||
|
# 志愿委员只能加分,不限制正分上限
|
||||||
|
if points_change < 0:
|
||||||
|
return {"success": False, "message": "志愿委员只能加分"}
|
||||||
elif role in ["学习委员", "考勤委员"]:
|
elif role in ["学习委员", "考勤委员"]:
|
||||||
# 学习委员和考勤委员只能扣分
|
# 学习委员和考勤委员只能扣分
|
||||||
if points_change > 0:
|
if points_change > 0:
|
||||||
@@ -147,8 +151,8 @@ class ConductService:
|
|||||||
role = await PermissionChecker.get_user_role(user_id)
|
role = await PermissionChecker.get_user_role(user_id)
|
||||||
offset = (page - 1) * page_size
|
offset = (page - 1) * page_size
|
||||||
|
|
||||||
# 班主任/班长可查看全班
|
# 班主任/班长/志愿委员可查看全班
|
||||||
if role in ["班主任", "班长"]:
|
if role in ["班主任", "班长", "志愿委员"]:
|
||||||
records = await ConductModel.get_all_records(
|
records = await ConductModel.get_all_records(
|
||||||
limit=page_size,
|
limit=page_size,
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|||||||
@@ -70,10 +70,11 @@ include __DIR__ . '/../includes/header.php';
|
|||||||
<label>角色</label>
|
<label>角色</label>
|
||||||
<select id="adminRole" required>
|
<select id="adminRole" required>
|
||||||
<option value="">请选择角色</option>
|
<option value="">请选择角色</option>
|
||||||
<option value="班长">班长</option>
|
<option value='班长'>班长</option>
|
||||||
<option value="学习委员">学习委员</option>
|
<option value='学习委员'>学习委员</option>
|
||||||
<option value="考勤委员">考勤委员</option>
|
<option value='考勤委员'>考勤委员</option>
|
||||||
<option value="劳动委员">劳动委员</option>
|
<option value='劳动委员'>劳动委员</option>
|
||||||
|
<option value='志愿委员'>志愿委员</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
|||||||
@@ -39,9 +39,10 @@ include __DIR__ . '/../includes/header.php';
|
|||||||
<input type="date" id="attendanceDate" value="<?php echo date('Y-m-d'); ?>">
|
<input type="date" id="attendanceDate" value="<?php echo date('Y-m-d'); ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="status-group">
|
<div class="status-group">
|
||||||
<button class="status-btn active" data-status="absent" onclick="selectStatus(this)">缺勤(-<span class="att-absent"></span>分)</button>
|
<button class="status-btn active" data-status="absent" onclick="selectStatus(this)" data-default-deduction="3">缺勤(-<span class="att-absent"></span>分)</button>
|
||||||
<button class="status-btn" data-status="late" onclick="selectStatus(this)">迟到(-<span class="att-late"></span>分)</button>
|
<button class="status-btn" data-status="late" onclick="selectStatus(this)" data-default-deduction="1">迟到(-<span class="att-late"></span>分)</button>
|
||||||
<button class="status-btn" data-status="leave" onclick="selectStatus(this)">请假(-<span class="att-leave"></span>分)</button>
|
<button class="status-btn" data-status="leave" onclick="selectStatus(this)" data-default-deduction="0">请假(-<span class="att-leave"></span>分)</button>
|
||||||
|
<input type="number" id="customDeduction" placeholder="自定义扣分" min="0" max="10" style="width:100px;margin-left:10px;" title="留空或0使用默认值">
|
||||||
</div>
|
</div>
|
||||||
<input type="text" id="attendanceReason" placeholder="原因(可选)" style="flex:1;min-width:150px;">
|
<input type="text" id="attendanceReason" placeholder="原因(可选)" style="flex:1;min-width:150px;">
|
||||||
<button class="btn btn-primary" onclick="selectAllStudents()">全选</button>
|
<button class="btn btn-primary" onclick="selectAllStudents()">全选</button>
|
||||||
@@ -93,6 +94,13 @@ function selectStatus(btn) {
|
|||||||
document.querySelectorAll('.status-btn').forEach(b => b.classList.remove('active'));
|
document.querySelectorAll('.status-btn').forEach(b => b.classList.remove('active'));
|
||||||
btn.classList.add('active');
|
btn.classList.add('active');
|
||||||
currentStatus = btn.dataset.status;
|
currentStatus = btn.dataset.status;
|
||||||
|
// 自动设置默认扣分值
|
||||||
|
const defaultDeduction = btn.dataset.defaultDeduction;
|
||||||
|
if (defaultDeduction && defaultDeduction !== '0') {
|
||||||
|
document.getElementById('customDeduction').value = defaultDeduction;
|
||||||
|
} else {
|
||||||
|
document.getElementById('customDeduction').value = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载学生列表
|
// 加载学生列表
|
||||||
@@ -165,6 +173,8 @@ async function submitAttendance() {
|
|||||||
|
|
||||||
const date = document.getElementById('attendanceDate').value;
|
const date = document.getElementById('attendanceDate').value;
|
||||||
const reason = document.getElementById('attendanceReason').value;
|
const reason = document.getElementById('attendanceReason').value;
|
||||||
|
const customDeduction = document.getElementById('customDeduction').value;
|
||||||
|
const customDeductionValue = customDeduction ? parseInt(customDeduction) : null;
|
||||||
|
|
||||||
// 检查是否有已存在记录的学生
|
// 检查是否有已存在记录的学生
|
||||||
const hasRecordStudents = [];
|
const hasRecordStudents = [];
|
||||||
@@ -183,15 +193,18 @@ async function submitAttendance() {
|
|||||||
const promises = [];
|
const promises = [];
|
||||||
selectedCells.forEach(cell => {
|
selectedCells.forEach(cell => {
|
||||||
const studentId = parseInt(cell.dataset.id);
|
const studentId = parseInt(cell.dataset.id);
|
||||||
promises.push(
|
const payload = {
|
||||||
apiPost('/api/admin/attendance', {
|
|
||||||
student_id: studentId,
|
student_id: studentId,
|
||||||
date: date,
|
date: date,
|
||||||
status: currentStatus,
|
status: currentStatus,
|
||||||
reason: reason,
|
reason: reason,
|
||||||
apply_deduction: true
|
apply_deduction: true
|
||||||
})
|
};
|
||||||
);
|
// 只有设置了自定义扣分时才发送
|
||||||
|
if (customDeductionValue !== null && customDeductionValue > 0) {
|
||||||
|
payload.custom_deduction = customDeductionValue;
|
||||||
|
}
|
||||||
|
promises.push(apiPost('/api/admin/attendance', payload));
|
||||||
});
|
});
|
||||||
|
|
||||||
const results = await Promise.allSettled(promises);
|
const results = await Promise.allSettled(promises);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ if (!isset($_SESSION['user_id']) || $_SESSION['user_type'] !== 'admin') {
|
|||||||
$page_title = '操行分管理';
|
$page_title = '操行分管理';
|
||||||
$role = $_SESSION['role'] ?? '';
|
$role = $_SESSION['role'] ?? '';
|
||||||
|
|
||||||
if (!in_array($role, ['班主任', '班长', '劳动委员'])) {
|
if (!in_array($role, ['班主任', '班长', '劳动委员', '志愿委员'])) {
|
||||||
header('Location: /admin/dashboard.php');
|
header('Location: /admin/dashboard.php');
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
@@ -115,6 +115,7 @@ loadStudents();
|
|||||||
<small><?php
|
<small><?php
|
||||||
if ($role === '班长') echo '班长单次±5分以内';
|
if ($role === '班长') echo '班长单次±5分以内';
|
||||||
elseif ($role === '劳动委员') echo '劳动委员仅限±1分';
|
elseif ($role === '劳动委员') echo '劳动委员仅限±1分';
|
||||||
|
elseif ($role === '志愿委员') echo '志愿委员仅限加分';
|
||||||
else echo '班主任无限制';
|
else echo '班主任无限制';
|
||||||
?></small>
|
?></small>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ async function loadDashboard() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let quickActions = '';
|
let quickActions = '';
|
||||||
if ('<?php echo $role; ?>' === '班主任' || '<?php echo $role; ?>' === '班长' || '<?php echo $role; ?>' === '劳动委员') {
|
if ('<?php echo $role; ?>' === '班主任' || '<?php echo $role; ?>' === '班长' || '<?php echo $role; ?>' === '劳动委员' || '<?php echo $role; ?>' === '志愿委员') {
|
||||||
quickActions += '<button class="btn btn-primary" onclick="location.href=\'/admin/conduct.php\'">操行分管理</button>';
|
quickActions += '<button class="btn btn-primary" onclick="location.href=\'/admin/conduct.php\'">操行分管理</button>';
|
||||||
}
|
}
|
||||||
if ('<?php echo $role; ?>' === '班主任') {
|
if ('<?php echo $role; ?>' === '班主任') {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ include __DIR__ . '/../includes/header.php';
|
|||||||
<th>分数变动</th>
|
<th>分数变动</th>
|
||||||
<th>原因</th>
|
<th>原因</th>
|
||||||
<th>操作人</th>
|
<th>操作人</th>
|
||||||
<?php if ($role === '班主任' || $role === '班长'): ?>
|
<?php if ($role === '班主任' || $role === '班长' || $role === '志愿委员'): ?>
|
||||||
<th>操作</th>
|
<th>操作</th>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -105,14 +105,14 @@ async function loadHistory(page = 1) {
|
|||||||
<td class="${pointsClass}">${record.points_change > 0 ? '+' : ''}${record.points_change}</td>
|
<td class="${pointsClass}">${record.points_change > 0 ? '+' : ''}${record.points_change}</td>
|
||||||
<td>${escapeHtml(record.reason)}</td>
|
<td>${escapeHtml(record.reason)}</td>
|
||||||
<td>${escapeHtml(record.recorder_name)}</td>`;
|
<td>${escapeHtml(record.recorder_name)}</td>`;
|
||||||
<?php if ($role === '班主任' || $role === '班长'): ?>
|
<?php if ($role === '班主任' || $role === '班长' || $role === '志愿委员'): ?>
|
||||||
html += `<td><button class="btn btn-sm btn-danger" onclick="revokeRecord(${record.record_id})">撤销</button></td>`;
|
html += `<td><button class="btn btn-sm btn-danger" onclick="revokeRecord(${record.record_id})">撤销</button></td>`;
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
html += `</tr>`;
|
html += `</tr>`;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.data.records.length === 0) {
|
if (res.data.records.length === 0) {
|
||||||
const colSpan = <?php echo ($role === '班主任' || $role === '班长') ? '6' : '5'; ?>;
|
const colSpan = <?php echo ($role === '班主任' || $role === '班长' || $role === '志愿委员') ? '6' : '5'; ?>;
|
||||||
html = `<tr><td colspan="${colSpan}" style="text-align:center;">暂无记录</td></tr>`;
|
html = `<tr><td colspan="${colSpan}" style="text-align:center;">暂无记录</td></tr>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div class="nav">
|
<div class="nav">
|
||||||
<a href="/admin/dashboard.php" class="nav-item<?php echo $current_page === 'dashboard' ? ' active' : ''; ?>">首页</a>
|
<a href="/admin/dashboard.php" class="nav-item<?php echo $current_page === 'dashboard' ? ' active' : ''; ?>">首页</a>
|
||||||
<a href="/admin/students.php" class="nav-item<?php echo $current_page === 'students' ? ' active' : ''; ?>">学生管理</a>
|
<a href="/admin/students.php" class="nav-item<?php echo $current_page === 'students' ? ' active' : ''; ?>">学生管理</a>
|
||||||
<?php if ($role === '班主任' || $role === '班长' || $role === '劳动委员'): ?>
|
<?php if ($role === '班主任' || $role === '班长' || $role === '劳动委员' || $role === '志愿委员'): ?>
|
||||||
<a href="/admin/conduct.php" class="nav-item<?php echo $current_page === 'conduct' ? ' active' : ''; ?>">操行分管理</a>
|
<a href="/admin/conduct.php" class="nav-item<?php echo $current_page === 'conduct' ? ' active' : ''; ?>">操行分管理</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php if ($role === '班主任' || $role === '学习委员'): ?>
|
<?php if ($role === '班主任' || $role === '学习委员'): ?>
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ CREATE TABLE `users` (
|
|||||||
CREATE TABLE `admin_roles` (
|
CREATE TABLE `admin_roles` (
|
||||||
`admin_role_id` INT PRIMARY KEY AUTO_INCREMENT,
|
`admin_role_id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
`user_id` INT NOT NULL,
|
`user_id` INT NOT NULL,
|
||||||
`role_type` ENUM('班主任', '班长', '学习委员', '考勤委员', '劳动委员') NOT NULL,
|
`role_type` ENUM('班主任', '班长', '学习委员', '考勤委员', '劳动委员', '志愿委员') NOT NULL,
|
||||||
`subject_id` INT DEFAULT NULL,
|
`subject_id` INT DEFAULT NULL,
|
||||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`user_id`) ON DELETE CASCADE,
|
FOREIGN KEY (`user_id`) REFERENCES `users`(`user_id`) ON DELETE CASCADE,
|
||||||
|
|||||||
Reference in New Issue
Block a user