<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智能课程表管理系统</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.fade-in { animation: fadeIn 0.5s ease-in; }
.slide-down { animation: slideDown 0.3s ease-out; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideDown { from { transform: translateY(-10px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
.course-card:hover { transform: translateY(-2px); transition: all 0.3s ease; }
</style>
</head>
<body class="bg-gradient-to-br from-blue-50 to-indigo-100 min-h-screen">
<!-- 导航栏 -->
<nav class="bg-white shadow-lg sticky top-0 z-10">
<div class="container mx-auto px-4 py-3 flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fas fa-calendar-alt text-indigo-600 text-2xl"></i>
<h1 class="text-xl font-bold text-gray-800">智能课程表</h1>
</div>
<div class="flex space-x-4">
<button id="settingsBtn" class="bg-indigo-100 hover:bg-indigo-200 text-indigo-700 px-4 py-2 rounded-lg transition">
<i class="fas fa-cog mr-2"></i>设置
</button>
<button id="addCourseBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg transition">
<i class="fas fa-plus mr-2"></i>添加课程
</button>
</div>
</div>
</nav>
<div class="container mx-auto px-4 py-8">
<!-- 控制面板 -->
<div class="bg-white rounded-xl shadow-md p-6 mb-8 slide-down">
<div class="flex flex-wrap gap-4 items-center">
<div class="flex items-center space-x-2">
<span class="text-gray-700 font-medium">学期:</span>
<select id="semesterSelect" class="border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500">
<option value="2024-spring">2024学年春季学期</option>
<option value="2024-autumn">2024学年秋季学期</option>
</select>
</div>
<div class="flex items-center space-x-2">
<span class="text-gray-700 font-medium">视图:</span>
<select id="viewSelect" class="border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500">
<option value="weekly">周视图</option>
<option value="daily">日视图</option>
</select>
</div>
<div class="flex-1"></div>
<div class="relative">
<input type="text" id="searchInput" placeholder="搜索课程..." class="border border-gray-300 rounded-lg pl-10 pr-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500 w-64">
<i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
</div>
</div>
</div>
<!-- 课程表主体 -->
<div class="bg-white rounded-xl shadow-md overflow-hidden fade-in">
<div class="overflow-x-auto">
<table class="w-full">
<thead>
<tr class="bg-indigo-50">
<th class="py-4 px-6 text-left font-semibold text-indigo-800">时间/星期</th>
<th class="py-4 px-6 text-center font-semibold text-indigo-800">星期一</th>
<th class="py-4 px-6 text-center font-semibold text-indigo-800">星期二</th>
<th class="py-4 px-6 text-center font-semibold text-indigo-800">星期三</th>
<th class="py-4 px-6 text-center font-semibold text-indigo-800">星期四</th>
<th class="py-4 px-6 text-center font-semibold text-indigo-800">星期五</th>
<th class="py-4 px-6 text-center font-semibold text-indigo-800">星期六</th>
<th class="py-4 px-6 text-center font-semibold text-indigo-800">星期日</th>
</tr>
</thead>
<tbody id="scheduleBody" class="divide-y divide-gray-200">
<!-- 课程表内容将通过JavaScript动态生成 -->
</tbody>
</table>
</div>
</div>
<!-- 课程统计 -->
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mt-8">
<div class="bg-white rounded-xl shadow-md p-6 text-center">
<div class="text-3xl font-bold text-indigo-600" id="totalCourses">0</div>
<div class="text-gray-600 mt-2">总课程数</div>
</div>
<div class="bg-white rounded-xl shadow-md p-6 text-center">
<div class="text-3xl font-bold text-green-600" id="weekHours">0</div>
<div class="text-gray-600 mt-2">周学时</div>
</div>
<div class="bg-white rounded-xl shadow-md p-6 text-center">
<div class="text-3xl font-bold text-blue-600" id="currentWeek">第1周</div>
<div class="text-gray-600 mt-2">当前周次</div>
</div>
<div class="bg-white rounded-xl shadow-md p-6 text-center">
<div class="text-3xl font-bold text-purple-600" id="todayCourses">0</div>
<div class="text-gray-600 mt-2">今日课程</div>
</div>
</div>
</div>
<!-- 添加课程模态框 -->
<div id="addCourseModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-20 hidden">
<div class="bg-white rounded-xl shadow-2xl p-6 w-full max-w-md slide-down">
<div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-bold text-gray-800">添加课程</h2>
<button id="closeModal" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times text-xl"></i>
</button>
</div>
<form id="courseForm" class="space-y-4">
<div>
<label class="block text-gray-700 mb-2">课程名称</label>
<input type="text" id="courseName" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500" required>
</div>
<div>
<label class="block text-gray-700 mb-2">授课教师</label>
<input type="text" id="courseTeacher" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500">
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-gray-700 mb-2">星期</label>
<select id="courseDay" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500">
<option value="1">星期一</option>
<option value="2">星期二</option>
<option value="3">星期三</option>
<option value="4">星期四</option>
<option value="5">星期五</option>
<option value="6">星期六</option>
<option value="7">星期日</option>
</select>
</div>
<div>
<label class="block text-gray-700 mb-2">节次</label>
<select id="coursePeriod" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500">
<option value="1">第1-2节</option>
<option value="2">第3-4节</option>
<option value="3">第5-6节</option>
<option value="4">第7-8节</option>
<option value="5">第9-10节</option>
<option value="6">第11-12节</option>
</select>
</div>
</div>
<div>
<label class="block text-gray-700 mb-2">上课地点</label>
<input type="text" id="courseLocation" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500">
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-gray-700 mb-2">起始周</label>
<input type="number" id="startWeek" min="1" max="20" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500" value="1">
</div>
<div>
<label class="block text-gray-700 mb-2">结束周</label>
<input type="number" id="endWeek" min="1" max="20" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500" value="16">
</div>
</div>
<div class="flex justify-end space-x-3 pt-4">
<button type="button" id="cancelCourse" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 transition">取消</button>
<button type="submit" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition">保存课程</button>
</div>
</form>
</div>
</div>
<!-- 设置面板 -->
<div id="settingsPanel" class="fixed right-0 top-0 h-full w-80 bg-white shadow-2xl transform translate-x-full transition-transform z-30">
<div class="p-6">
<div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-bold text-gray-800">系统设置</h2>
<button id="closeSettings" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times text-xl"></i>
</button>
</div>
<div class="space-y-6">
<div>
<h3 class="font-medium text-gray-700 mb-3">时间设置</h3>
<div class="space-y-3">
<div>
<label class="block text-sm text-gray-600 mb-1">上午开始时间</label>
<input type="time" id="morningStart" class="w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500" value="08:00">
</div>
<div>
<label class="block text-sm text-gray-600 mb-1">下午开始时间</label>
<input type="time" id="afternoonStart" class="w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500" value="14:00">
</div>
</div>
</div>
<div>
<h3 class="font-medium text-gray-700 mb-3">显示设置</h3>
<div class="space-y-2">
<label class="flex items-center">
<input type="checkbox" id="showWeekends" class="rounded text-indigo-600 focus:ring-indigo-500 mr-2">
<span class="text-gray-600">显示周末</span>
</label>
<label class="flex items-center">
<input type="checkbox" id="showColors" class="rounded text-indigo-600 focus:ring-indigo-500 mr-2" checked>
<span class="text-gray-600">显示课程颜色</span>
</label>
</div>
</div>
<div class="pt-4">
<button id="saveSettings" class="w-full bg-indigo-600 text-white py-2 rounded-lg hover:bg-indigo-700 transition">保存设置</button>
</div>
</div>
</div>
</div>
<script>
// 课程表应用主逻辑
class CourseSchedule {
constructor() {
this.courses = this.loadCourses();
this.settings = this.loadSettings();
this.currentWeek = this.calculateCurrentWeek();
this.init();
}
init() {
this.renderSchedule();
this.setupEventListeners();
this.updateStatistics();
}
// 加载课程数据
loadCourses() {
const saved = localStorage.getItem('courseSchedule');
return saved ? JSON.parse(saved) : [];
}
// 加载设置
loadSettings() {
const saved = localStorage.getItem('courseSettings');
const defaultSettings = {
morningStart: '08:00',
afternoonStart: '14:00',
showWeekends: true,
showColors: true
};
return saved ? JSON.parse(saved) : defaultSettings;
}
// 计算当前周次
calculateCurrentWeek() {
// 简单实现:假设学期从9月1日开始
const semesterStart = new Date(new Date().getFullYear(), 8, 1); // 9月1日
const now = new Date();
const diffTime = Math.abs(now - semesterStart);
const diffWeeks = Math.ceil(diffTime / (1000 * 60 * 60 * 24 * 7));
return Math.min(Math.max(diffWeeks, 1), 20);
}
// 渲染课程表
renderSchedule() {
const scheduleBody = document.getElementById('scheduleBody');
scheduleBody.innerHTML = '';
// 时间段定义
const timeSlots = [
{ period: 1, time: '08:00-09:40', label: '第1-2节' },
{ period: 2, time: '10:00-11:40', label: '第3-4节' },
{ period: 3, time: '14:00-15:40', label: '第5-6节' },
{ period: 4, time: '16:00-17:40', label: '第7-8节' },
{ period: 5, time: '19:00-20:40', label: '第9-10节' }
];
timeSlots.forEach(slot => {
const row = document.createElement('tr');
row.className = 'hover:bg-gray-50 transition';
// 时间单元格
const timeCell = document.createElement('td');
timeCell.className = 'py-4 px-6 border-r border-gray-200';
timeCell.innerHTML = `
<div class="font-medium text-gray-800">${slot.label}</div>
<div class="text-sm text-gray-500">${slot.time}</div>
`;
row.appendChild(timeCell);
// 星期单元格
for (let day = 1; day <= 7; day++) {
if (day > 5 && !this.settings.showWeekends) continue;
const cell = document.createElement('td');
cell.className = 'py-2 px-4 align-top';
cell.setAttribute('data-day', day);
cell.setAttribute('data-period', slot.period);
const course = this.findCourse(day, slot.period);
if (course) {
const isCurrentWeek = this.currentWeek >= course.startWeek && this.currentWeek <= course.endWeek;
const bgColor = this.settings.showColors ? this.getCourseColor(course.name) : 'bg-gray-100';
cell.innerHTML = `
<div class="course-card ${bgColor} ${isCurrentWeek ? 'opacity-100' : 'opacity-60'} rounded-lg p-3 text-white cursor-pointer transition shadow-sm" data-id="${course.id}">
<div class="font-medium text-sm">${course.name}</div>
<div class="text-xs opacity-90 mt-1">${course.teacher || '教师'}</div>
<div class="text-xs opacity-90">${course.location || '地点'}</div>
${!isCurrentWeek ? '<div class="text-xs opacity-80 mt-1">非本周课程</div>' : ''}
</div>
`;
}
row.appendChild(cell);
}
scheduleBody.appendChild(row);
});
}
// 查找课程
findCourse(day, period) {
return this.courses.find(course =>
course.day === day && course.period === period
);
}
// 获取课程颜色(基于课程名称生成)
getCourseColor(courseName) {
const colors = [
'bg-gradient-to-r from-blue-500 to-blue-600',
'bg-gradient-to-r from-green-500 to-green-600',
'bg-gradient-to-r from-purple-500 to-purple-600',
'bg-gradient-to-r from-red-500 to-red-600',
'bg-gradient-to-r from-yellow-500 to-yellow-600',
'bg-gradient-to-r from-indigo-500 to-indigo-600',
'bg-gradient-to-r from-pink-500 to-pink-600'
];
let hash = 0;
for (let i = 0; i < courseName.length; i++) {
hash = courseName.charCodeAt(i) + ((hash << 5) - hash);
}
return colors[Math.abs(hash) % colors.length];
}
// 添加课程
addCourse(courseData) {
const newCourse = {
id: Date.now().toString(),
...courseData
};
this.courses.push(newCourse);
this.saveCourses();
this.renderSchedule();
this.updateStatistics();
}
// 删除课程
deleteCourse(courseId) {
this.courses = this.courses.filter(course => course.id !== courseId);
this.saveCourses();
this.renderSchedule();
this.updateStatistics();
}
// 保存课程
saveCourses() {
localStorage.setItem('courseSchedule', JSON.stringify(this.courses));
}
// 保存设置
saveSettings() {
localStorage.setItem('courseSettings', JSON.stringify(this.settings));
}
// 更新统计信息
updateStatistics() {
document.getElementById('totalCourses').textContent = this.courses.length;
const weekHours = this.courses.filter(course =>
this.currentWeek >= course.startWeek && this.currentWeek <= course.endWeek
).length * 2; // 假设每节课2学时
document.getElementById('weekHours').textContent = weekHours;
document.getElementById('currentWeek').textContent = `第${this.currentWeek}周`;
const today = new Date().getDay();
const todayCourses = this.courses.filter(course =>
course.day === (today === 0 ? 7 : today) &&
this.currentWeek >= course.startWeek && this.currentWeek <= course.endWeek
).length;
document.getElementById('todayCourses').textContent = todayCourses;
}
// 设置事件监听
setupEventListeners() {
// 添加课程按钮
document.getElementById('addCourseBtn').addEventListener('click', () => {
document.getElementById('addCourseModal').classList.remove('hidden');
});
// 关闭模态框
document.getElementById('closeModal').addEventListener('click', () => {
document.getElementById('addCourseModal').classList.add('hidden');
});
document.getElementById('cancelCourse').addEventListener('click', () => {
document.getElementById('addCourseModal').classList.add('hidden');
});
// 提交课程表单
document.getElementById('courseForm').addEventListener('submit', (e) => {
e.preventDefault();
const courseData = {
name: document.getElementById('courseName').value,
teacher: document.getElementById('courseTeacher').value,
day: parseInt(document.getElementById('courseDay').value),
period: parseInt(document.getElementById('coursePeriod').value),
location: document.getElementById('courseLocation').value,
startWeek: parseInt(document.getElementById('startWeek').value),
endWeek: parseInt(document.getElementById('endWeek').value)
};
this.addCourse(courseData);
document.getElementById('addCourseModal').classList.add('hidden');
document.getElementById('courseForm').reset();
});
// 设置面板
document.getElementById('settingsBtn').addEventListener('click', () => {
document.getElementById('settingsPanel').classList.remove('translate-x-full');
});
document.getElementById('closeSettings').addEventListener('click', () => {
document.getElementById('settingsPanel').classList.add('translate-x-full');
});
// 保存设置
document.getElementById('saveSettings').addEventListener('click', () => {
this.settings.morningStart = document.getElementById('morningStart').value;
this.settings.afternoonStart = document.getElementById('afternoonStart').value;
this.settings.showWeekends = document.getElementById('showWeekends').checked;
this.settings.showColors = document.getElementById('showColors').checked;
this.saveSettings();
this.renderSchedule();
document.getElementById('settingsPanel').classList.add('translate-x-full');
});
// 搜索功能
document.getElementById('searchInput').addEventListener('input', (e) => {
const searchTerm = e.target.value.toLowerCase();
// 实现搜索高亮逻辑
});
// 点击课程卡片显示详情
document.addEventListener('click', (e) => {
const courseCard = e.target.closest('.course-card');
if (courseCard) {
const courseId = courseCard.getAttribute('data-id');
const course = this.courses.find(c => c.id === courseId);
if (course) {
if (confirm(`是否删除课程 "${course.name}"?`)) {
this.deleteCourse(courseId);
}
}
}
});
}
}
// 初始化应用
document.addEventListener('DOMContentLoaded', () => {
new CourseSchedule();
});
</script>
</body>
</html>
<code_end>