v0.2测试

This commit is contained in:
2026-04-10 14:18:07 +08:00
parent 6102774585
commit 9d89e62b63
19 changed files with 461 additions and 995 deletions

View File

@@ -9,8 +9,8 @@
# 版权所有 © Sea Network Technology Studio
# ===========================================
# 后端API地址
API_BASE_URL=https://api.your-domain.com
# 后端API地址,修改为实际地址
API_BASE_URL=https://your-api-domain.com
# API超时时间
API_TIMEOUT=30

View File

@@ -17,24 +17,29 @@ if (!isset($_SESSION['user_id']) || $_SESSION['user_type'] !== 'admin') {
exit();
}
$page_title = '管理员管理';
$role = $_SESSION['role'] ?? '';
if ($role !== '班主任') {
header('Location: /admin/dashboard.php');
exit();
}
$page_title = '管理员管理';
include __DIR__ . '/../includes/header.php';
?>
<div class="nav">
<a href="/admin/dashboard.php" class="nav-item">首页</a>
<a href="/admin/students.php" class="nav-item">学生管理</a>
<?php if ($role === '班主任' || $role === '班长'): ?>
<a href="/admin/conduct.php" class="nav-item">操行分管理</a>
<?php endif; ?>
<?php if ($role === '班主任' || $role === '学习委员'): ?>
<a href="/admin/homework.php" class="nav-item">作业管理</a>
<a href="/admin/attendance.php" class="nav-item">考勤管理</a>
<a href="/admin/subjects.php" class="nav-item">科目管理</a>
<?php endif; ?>
<?php if ($role === '班主任' || $role === '考勤委员'): ?>
<a href="/admin/attendance.php" class="nav-item">考勤管理</a>
<?php endif; ?>
<a href="/admin/admins.php" class="nav-item active">管理员管理</a>
<a href="/admin/history.php" class="nav-item">历史记录</a>
<a href="/admin/password.php" class="nav-item">修改密码</a>
@@ -45,15 +50,10 @@ include __DIR__ . '/../includes/header.php';
<div class="action-bar">
<button class="btn btn-primary" onclick="showAddAdminModal()">添加管理员</button>
</div>
<div class="table-wrapper">
<table class="table">
<thead>
<tr>
<th>用户名</th>
<th>姓名</th>
<th>角色</th>
</tr>
<tr><th>用户名</th><th>姓名</th><th>角色</th><th>关联科目</th></tr>
</thead>
<tbody id="adminList"></tbody>
</table>
@@ -87,7 +87,7 @@ include __DIR__ . '/../includes/header.php';
<select id="adminRole" required>
<option value="">请选择角色</option>
<option value="班长">班长</option>
<option value="科代表">科代表</option>
<option value="学习委员">学习委员</option>
<option value="考勤委员">考勤委员</option>
<option value="劳动委员">劳动委员</option>
</select>
@@ -110,15 +110,52 @@ async function loadAdmins() {
<td>${escapeHtml(admin.username)}</td>
<td>${escapeHtml(admin.real_name)}</td>
<td>${escapeHtml(admin.role_type)}</td>
<td>${admin.subject_name || '-'}</td>
</tr>`;
});
if (res.data.admins.length === 0) {
html = '<tr><td colspan="3" style="text-align:center;">暂无管理员</td></tr>';
html = '<tr><td colspan="4" style="text-align:center;">暂无管理员</td></tr>';
}
document.getElementById('adminList').innerHTML = html;
}
}
function showAddAdminModal() {
document.getElementById('addAdminModal').style.display = 'flex';
document.getElementById('addAdminForm')?.reset();
}
async function submitAddAdmin() {
const username = document.getElementById('adminUsername').value.trim();
const realName = document.getElementById('adminRealName').value.trim();
const password = document.getElementById('adminPassword').value;
const roleType = document.getElementById('adminRole').value;
if (!username || !realName || !roleType) {
showToast('请填写完整信息', 'warning');
return;
}
const res = await apiPost('/api/admin/add', {
username: username,
real_name: realName,
password: password || undefined,
role_type: roleType
});
if (res && res.success) {
let msg = `管理员 ${res.data.username} 添加成功`;
if (res.data.password) msg += `,密码: ${res.data.password}`;
showToast(msg);
closeModal('addAdminModal');
loadAdmins();
} else {
showToast(res?.message || '添加失败', 'error');
}
}
function closeModal(modalId) {
const modal = document.getElementById(modalId);
if (modal) modal.style.display = 'none';
}
loadAdmins();
</script>
<script src="/assets/js/admin.js"></script>

View File

@@ -28,14 +28,14 @@ include __DIR__ . '/../includes/header.php';
<?php if ($role === '班主任' || $role === '班长'): ?>
<a href="/admin/conduct.php" class="nav-item">操行分管理</a>
<?php endif; ?>
<?php if ($role === '班主任' || $role === '科代表'): ?>
<?php if ($role === '班主任' || $role === '学习委员'): ?>
<a href="/admin/homework.php" class="nav-item">作业管理</a>
<a href="/admin/subjects.php" class="nav-item">科目管理</a>
<?php endif; ?>
<?php if ($role === '班主任' || $role === '考勤委员'): ?>
<a href="/admin/attendance.php" class="nav-item">考勤管理</a>
<?php endif; ?>
<?php if ($role === '班主任'): ?>
<a href="/admin/subjects.php" class="nav-item">科目管理</a>
<a href="/admin/admins.php" class="nav-item">管理员管理</a>
<?php endif; ?>
<a href="/admin/history.php" class="nav-item">历史记录</a>
@@ -65,18 +65,16 @@ include __DIR__ . '/../includes/header.php';
<script>
async function loadDashboard() {
// 加载学生统计
const studentsRes = await apiGet('/api/admin/students');
if (studentsRes && studentsRes.success) {
document.getElementById('dashboardStats').innerHTML = `
<div class="stat-card">
<div class="stat-label">班级学生数</div>
<div class="stat-label">学生数</div>
<div class="stat-value">${studentsRes.data.total || 0}</div>
</div>
`;
}
// 快捷操作按钮
let quickActions = '';
if ('<?php echo $role; ?>' === '班主任' || '<?php echo $role; ?>' === '班长') {
quickActions += '<button class="btn btn-primary" onclick="location.href=\'/admin/conduct.php\'">操行分管理</button>';
@@ -86,19 +84,16 @@ async function loadDashboard() {
}
document.getElementById('quickActions').innerHTML = quickActions || '<p>暂无快捷操作</p>';
// 加载排行榜
const rankingRes = await apiGet('/api/student/ranking', { limit: 10 });
if (rankingRes && rankingRes.success) {
let html = '';
rankingRes.data.ranking.forEach((student, index) => {
html += `
<tr>
<td>${index + 1}</td>
<td>${escapeHtml(student.student_no)}</td>
<td>${escapeHtml(student.name)}</td>
<td>${student.total_points}</td>
</tr>
`;
html += `<tr>
<td>${index + 1}</td>
<td>${escapeHtml(student.student_no)}</td>
<td>${escapeHtml(student.name)}</td>
<td>${student.total_points}</td>
</tr>`;
});
if (rankingRes.data.ranking.length === 0) {
html = '<tr><td colspan="4" style="text-align:center;">暂无数据</td></tr>';

View File

@@ -17,25 +17,32 @@ if (!isset($_SESSION['user_id']) || $_SESSION['user_type'] !== 'admin') {
exit();
}
$page_title = '科目管理';
$role = $_SESSION['role'] ?? '';
if ($role !== '班主任') {
if (!in_array($role, ['班主任', '学习委员'])) {
header('Location: /admin/dashboard.php');
exit();
}
$page_title = '科目管理';
include __DIR__ . '/../includes/header.php';
?>
<div class="nav">
<a href="/admin/dashboard.php" class="nav-item">首页</a>
<a href="/admin/students.php" class="nav-item">学生管理</a>
<?php if ($role === '班主任' || $role === '班长'): ?>
<a href="/admin/conduct.php" class="nav-item">操行分管理</a>
<?php endif; ?>
<?php if ($role === '班主任' || $role === '学习委员'): ?>
<a href="/admin/homework.php" class="nav-item">作业管理</a>
<a href="/admin/attendance.php" class="nav-item">考勤管理</a>
<a href="/admin/subjects.php" class="nav-item active">科目管理</a>
<?php endif; ?>
<?php if ($role === '班主任' || $role === '考勤委员'): ?>
<a href="/admin/attendance.php" class="nav-item">考勤管理</a>
<?php endif; ?>
<?php if ($role === '班主任'): ?>
<a href="/admin/admins.php" class="nav-item">管理员管理</a>
<?php endif; ?>
<a href="/admin/history.php" class="nav-item">历史记录</a>
<a href="/admin/password.php" class="nav-item">修改密码</a>
</div>
@@ -138,10 +145,7 @@ async function loadSubjects() {
}
async function toggleSubject(subjectId, enable) {
const res = await apiPut(`/api/subject/update/${subjectId}`, {
is_active: enable
});
const res = await apiPut(`/api/subject/update/${subjectId}`, { is_active: enable });
if (res && res.success) {
showToast(enable ? '科目已启用' : '科目已禁用');
loadSubjects();
@@ -150,6 +154,36 @@ async function toggleSubject(subjectId, enable) {
}
}
function showAddSubjectModal() {
document.getElementById('addSubjectModal').style.display = 'flex';
document.getElementById('addSubjectForm')?.reset();
}
async function submitAddSubject() {
const subjectName = document.getElementById('subjectName').value.trim();
const subjectCode = document.getElementById('subjectCode').value.trim();
if (!subjectName) {
showToast('请填写科目名称', 'warning');
return;
}
const res = await apiPost('/api/subject/create', {
subject_name: subjectName,
subject_code: subjectCode
});
if (res && res.success) {
showToast('科目添加成功');
closeModal('addSubjectModal');
loadSubjects();
} else {
showToast(res?.message || '添加失败', 'error');
}
}
function closeModal(modalId) {
const modal = document.getElementById(modalId);
if (modal) modal.style.display = 'none';
}
loadSubjects();
</script>
<script src="/assets/js/admin.js"></script>

View File

@@ -9,8 +9,8 @@
* 版权所有 © Sea Network Technology Studio
*/
// API基础地址
const API_BASE_URL = window.API_BASE_URL || 'http://localhost:8000';
// API 使用相对路径,由 Nginx 反向代理 /api/ 到后端
const API_BASE_URL = '';
const JWT_STORAGE_KEY = 'class_system_token';
const USER_STORAGE_KEY = 'class_system_user';
@@ -54,23 +54,24 @@ function checkAuth() {
// API请求封装
async function apiRequest(url, options = {}) {
const token = getToken();
const headers = {
'Content-Type': 'application/json',
...options.headers
};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
// 确保 url 以 /api/ 开头
const fullUrl = url.startsWith('/api/') ? url : `/api${url}`;
const config = {
...options,
headers
};
try {
const response = await fetch(`${API_BASE_URL}${url}`, config);
const response = await fetch(fullUrl, config);
const data = await response.json();
if (response.status === 401) {
@@ -78,7 +79,6 @@ async function apiRequest(url, options = {}) {
window.location.href = '/index.php';
return null;
}
return data;
} catch (error) {
console.error('API请求错误:', error);
@@ -121,7 +121,6 @@ function showToast(message, type = 'success') {
toast.className = `toast toast-${type}`;
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(() => {
toast.remove();
}, 3000);
@@ -156,10 +155,8 @@ function getStatusBadge(status, type = 'homework') {
'leave': '请假'
}
};
const texts = statusMap[type] || statusMap.homework;
const text = texts[status] || status;
let className = 'status-badge ';
switch (status) {
case 'submitted':
@@ -179,7 +176,6 @@ function getStatusBadge(status, type = 'homework') {
default:
className += 'status-not_submitted';
}
return `<span class="${className}">${text}</span>`;
}
@@ -216,7 +212,6 @@ async function changePassword(newPassword) {
old_password: newPassword,
new_password: newPassword
});
if (res && res.success) {
showToast('密码修改成功,请重新登录');
setTimeout(() => logout(), 1500);
@@ -226,17 +221,25 @@ async function changePassword(newPassword) {
}
}
// HTML转义
function escapeHtml(str) {
if (!str) return '';
return str.replace(/[&<>]/g, function(m) {
if (m === '&') return '&amp;';
if (m === '<') return '&lt;';
if (m === '>') return '&gt;';
return m;
});
}
// 页面加载时初始化
document.addEventListener('DOMContentLoaded', () => {
loadUserInfo();
const logoutBtn = document.getElementById('logoutBtn');
if (logoutBtn) {
logoutBtn.addEventListener('click', logout);
}
// 学生端检查强制修改密码
if (window.location.pathname.includes('/student/')) {
if (window.location.pathname.includes('/student/') || window.location.pathname.includes('/parent/')) {
checkNeedChangePassword();
}
});

View File

@@ -10,44 +10,72 @@
* 版权所有 © Sea Network Technology Studio
*/
// 加载环境变量
// 读取.env文件
$envFile = __DIR__ . '/.env';
if (file_exists($envFile)) {
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
if (strpos(trim($line), '#') === 0) {
continue;
}
if (strpos($line, '=') !== false) {
list($key, $value) = explode('=', $line, 2);
putenv(trim($key) . '=' . trim($value));
}
$config = [];
if (!file_exists($envFile)) {
die('错误: 配置文件 .env 不存在,请复制 .env.example 并修改配置');
}
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if ($lines === false) {
die('错误: 无法读取配置文件 .env');
}
foreach ($lines as $line) {
$line = trim($line);
// 跳过注释行
if (strpos($line, '#') === 0 || empty($line)) {
continue;
}
// 解析 KEY=VALUE
if (strpos($line, '=') !== false) {
$parts = explode('=', $line, 2);
$key = trim($parts[0]);
$value = trim($parts[1]);
// 去除可能的引号
$value = trim($value, '"\'');
$config[$key] = $value;
}
}
// 检查必要配置是否存在
$requiredKeys = ['API_BASE_URL', 'API_TIMEOUT', 'JWT_STORAGE_KEY', 'USER_STORAGE_KEY', 'SITE_NAME', 'SESSION_TIMEOUT'];
$missingKeys = [];
foreach ($requiredKeys as $key) {
if (!isset($config[$key]) || $config[$key] === '') {
$missingKeys[] = $key;
}
}
if (!empty($missingKeys)) {
die('错误: 配置文件 .env 缺少必要配置项: ' . implode(', ', $missingKeys));
}
// 定义常量
define('API_BASE_URL', getenv('API_BASE_URL') ?: 'http://localhost:8000');
define('API_TIMEOUT', (int)(getenv('API_TIMEOUT') ?: 30));
define('JWT_STORAGE_KEY', getenv('JWT_STORAGE_KEY') ?: 'class_system_token');
define('USER_STORAGE_KEY', getenv('USER_STORAGE_KEY') ?: 'class_system_user');
define('SITE_NAME', getenv('SITE_NAME') ?: '班级操行分管理系统');
define('SESSION_TIMEOUT', (int)(getenv('SESSION_TIMEOUT') ?: 30));
define('API_BASE_URL', '''');
define('API_TIMEOUT', (int)$config['API_TIMEOUT']);
define('JWT_STORAGE_KEY', $config['JWT_STORAGE_KEY']);
define('USER_STORAGE_KEY', $config['USER_STORAGE_KEY']);
define('SITE_NAME', $config['SITE_NAME']);
define('SESSION_TIMEOUT', (int)$config['SESSION_TIMEOUT']);
// 会话配置
ini_set('session.cookie_httponly', 1);
ini_set('session.use_only_cookies', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.cookie_samesite', 'Lax');
ini_set('session.cookie_domain', '.sea-studio.top');
ini_set('session.gc_maxlifetime', 7200);
session_name('CLASS_SESSION');
session_start();
// 时区设置
date_default_timezone_set('Asia/Shanghai');
// 错误报告(生产环境关闭
if (getenv('APP_ENV') === 'production') {
error_reporting(0);
ini_set('display_errors', 0);
} else {
error_reporting(E_ALL);
ini_set('display_errors', 1);
}
?>
// 生产环境关闭错误显示
error_reporting(0);
ini_set('display_errors', 0);

View File

@@ -1,6 +1,6 @@
<?php
/**
* 班级操行分管理系统 - 家长端
* 班级操行分管理系统 - 家长端
*
* 开发者: Canglan
* 联系方式: admin@sea-studio.top
@@ -12,261 +12,58 @@
require_once __DIR__ . '/../config.php';
// 检查登录状态
if (!isset($_SESSION['user_id']) || $_SESSION['user_type'] !== 'parent') {
header('Location: /index.php');
exit();
}
$student_id = $_SESSION['student_id'];
$page_title = '首页';
include __DIR__ . '/../includes/header.php';
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo SITE_NAME; ?> - 家长端</title>
<link rel="stylesheet" href="/assets/css/style.css">
<style>
.child-info {
text-align: center;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 12px;
color: white;
margin-bottom: 20px;
}
.child-name {
font-size: 24px;
font-weight: bold;
margin-bottom: 8px;
}
.child-no {
font-size: 14px;
opacity: 0.9;
}
.conduct-score {
text-align: center;
padding: 30px;
}
.score-number {
font-size: 72px;
font-weight: bold;
color: #667eea;
}
</style>
</head>
<body>
<div class="header">
<h1><?php echo SITE_NAME; ?> - 家长端</h1>
<div class="header-info">
<span class="user-name" id="userName"></span>
<button class="btn-logout" id="logoutBtn">退出登录</button>
<div class="nav">
<a href="/parent/dashboard.php" class="nav-item active">首页</a>
<a href="/parent/attendance.php" class="nav-item">考勤记录</a>
</div>
<div class="container">
<div class="child-info">
<div class="child-name" id="childName">--</div>
<div class="child-no" id="childNo">--</div>
</div>
<div class="card">
<div class="conduct-score">
<div class="score-number" id="totalPoints">--</div>
<div class="score-label">当前操行分</div>
</div>
</div>
</div>
<div class="nav">
<button class="nav-item active" data-page="dashboard">首页</button>
<button class="nav-item" data-page="homework">作业情况</button>
<button class="nav-item" data-page="attendance">考勤记录</button>
</div>
<style>
.child-info {
text-align: center;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 12px;
color: white;
margin-bottom: 20px;
}
.child-name { font-size: 24px; font-weight: bold; margin-bottom: 8px; }
.child-no { font-size: 14px; opacity: 0.9; }
.score-number { font-size: 72px; font-weight: bold; color: #667eea; text-align: center; }
</style>
<div class="container" id="pageContainer">
<!-- 首页内容 -->
<div id="page-dashboard" class="page-content">
<div class="child-info" id="childInfo">
<div class="child-name" id="childName">--</div>
<div class="child-no" id="childNo">--</div>
</div>
<div class="card">
<div class="conduct-score">
<div class="score-number" id="totalPoints">--</div>
<div class="score-label">当前操行分</div>
</div>
</div>
</div>
<script>
async function loadDashboard() {
const res = await apiGet('/api/parent/child/conduct');
if (res && res.success) {
document.getElementById('childName').textContent = res.data.student_name;
document.getElementById('childNo').textContent = res.data.student_no;
document.getElementById('totalPoints').textContent = res.data.total_points;
}
}
loadDashboard();
</script>
<script src="/assets/js/parent.js"></script>
<!-- 作业情况页 -->
<div id="page-homework" class="page-content" style="display: none;">
<div class="card">
<div class="card-title">作业列表</div>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>科目</th>
<th>作业标题</th>
<th>截止日期</th>
<th>状态</th>
<th>备注</th>
</tr>
</thead>
<tbody id="homeworkList"></tbody>
</table>
</div>
</div>
</div>
<!-- 考勤记录页 -->
<div id="page-attendance" class="page-content" style="display: none;">
<div class="stats-grid">
<div class="stat-card">
<div class="stat-label">出勤</div>
<div class="stat-value" id="attPresent">0</div>
</div>
<div class="stat-card">
<div class="stat-label">缺勤</div>
<div class="stat-value" id="attAbsent">0</div>
</div>
<div class="stat-card">
<div class="stat-label">迟到</div>
<div class="stat-value" id="attLate">0</div>
</div>
<div class="stat-card">
<div class="stat-label">请假</div>
<div class="stat-value" id="attLeave">0</div>
</div>
</div>
<div class="card">
<div class="card-title">考勤记录明细</div>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>日期</th>
<th>状态</th>
<th>原因</th>
</tr>
</thead>
<tbody id="attendanceList"></tbody>
</table>
</div>
</div>
</div>
</div>
<script>
const API_BASE_URL = '<?php echo API_BASE_URL; ?>';
const STUDENT_ID = <?php echo $student_id ?: 0; ?>;
// 页面切换
function showPage(pageName) {
document.querySelectorAll('.page-content').forEach(page => {
page.style.display = 'none';
});
document.getElementById(`page-${pageName}`).style.display = 'block';
document.querySelectorAll('.nav-item').forEach(item => {
item.classList.remove('active');
if (item.dataset.page === pageName) {
item.classList.add('active');
}
});
switch(pageName) {
case 'dashboard':
loadDashboard();
break;
case 'homework':
loadHomework();
break;
case 'attendance':
loadAttendance();
break;
}
}
// 加载首页
async function loadDashboard() {
try {
// 获取子女信息
const childRes = await apiGet(`/api/parent/child/conduct`);
if (childRes && childRes.success) {
document.getElementById('childName').textContent = childRes.data.student_name;
document.getElementById('childNo').textContent = childRes.data.student_no;
document.getElementById('totalPoints').textContent = childRes.data.total_points;
}
} catch (error) {
console.error('加载首页失败:', error);
}
}
// 加载作业
async function loadHomework() {
try {
const res = await apiGet(`/api/parent/child/homework`);
if (res && res.success) {
let html = '';
res.data.homework.forEach(hw => {
html += `
<tr>
<td>${hw.subject}</td>
<td>${hw.title}</td>
<td>${hw.deadline}</td>
<td>${getStatusBadge(hw.status, 'homework')}</td>
<td>${hw.comments || '-'}</td>
</tr>
`;
});
if (res.data.homework.length === 0) {
html = '<tr><td colspan="5" style="text-align:center;">暂无作业</td></tr>';
}
document.getElementById('homeworkList').innerHTML = html;
}
} catch (error) {
console.error('加载作业失败:', error);
}
}
// 加载考勤
async function loadAttendance() {
try {
const res = await apiGet(`/api/parent/child/attendance`);
if (res && res.success) {
const records = res.data.records;
let present = 0, absent = 0, late = 0, leave = 0;
let html = '';
records.forEach(record => {
html += `
<tr>
<td>${record.date}</td>
<td>${getStatusBadge(record.status, 'attendance')}</td>
<td>${record.reason || '-'}</td>
</tr>
`;
switch(record.status) {
case 'present': present++; break;
case 'absent': absent++; break;
case 'late': late++; break;
case 'leave': leave++; break;
}
});
document.getElementById('attPresent').textContent = present;
document.getElementById('attAbsent').textContent = absent;
document.getElementById('attLate').textContent = late;
document.getElementById('attLeave').textContent = leave;
if (records.length === 0) {
html = '<tr><td colspan="3" style="text-align:center;">暂无考勤记录</td></tr>';
}
document.getElementById('attendanceList').innerHTML = html;
}
} catch (error) {
console.error('加载考勤失败:', error);
}
}
// 初始化
document.querySelectorAll('.nav-item').forEach(btn => {
btn.addEventListener('click', () => {
showPage(btn.dataset.page);
});
});
loadDashboard();
</script>
<script src="/assets/js/common.js"></script>
</body>
</html>
<?php include __DIR__ . '/../includes/footer.php'; ?>

View File

@@ -1,66 +0,0 @@
<?php
/**
* 班级操行分管理系统 - 家长端作业情况
*
* 开发者: Canglan
* 联系方式: admin@sea-studio.top
* 版权归属: Sea Network Technology Studio
* 许可证: MIT License
*
* 版权所有 © Sea Network Technology Studio
*/
require_once __DIR__ . '/../config.php';
if (!isset($_SESSION['user_id']) || $_SESSION['user_type'] !== 'parent') {
header('Location: /index.php');
exit();
}
$page_title = '作业情况';
include __DIR__ . '/../includes/header.php';
?>
<div class="nav">
<a href="/parent/dashboard.php" class="nav-item">首页</a>
<a href="/parent/homework.php" class="nav-item active">作业情况</a>
<a href="/parent/attendance.php" class="nav-item">考勤记录</a>
</div>
<div class="container">
<div class="card">
<div class="card-title">作业列表</div>
<div class="table-wrapper">
<table class="table">
<thead><tr><th>科目</th><th>作业标题</th><th>截止日期</th><th>状态</th><th>备注</th></tr></thead>
<tbody id="homeworkList"></tbody>
</table>
</div>
</div>
</div>
<script>
async function loadHomework() {
const res = await apiGet('/api/parent/child/homework');
if (res && res.success) {
let html = '';
res.data.homework.forEach(hw => {
html += `<tr>
<td>${escapeHtml(hw.subject)}</td>
<td>${escapeHtml(hw.title)}</td>
<td>${hw.deadline}</td>
<td>${getStatusBadge(hw.status, 'homework')}</td>
<td>${escapeHtml(hw.comments || '-')}</td>
</tr>`;
});
if (res.data.homework.length === 0) {
html = '<tr><td colspan="5" style="text-align:center;">暂无作业</td></tr>';
}
document.getElementById('homeworkList').innerHTML = html;
}
}
loadHomework();
</script>
<script src="/assets/js/parent.js"></script>
<?php include __DIR__ . '/../includes/footer.php'; ?>