1278 lines
31 KiB
Vue
1278 lines
31 KiB
Vue
<template>
|
||
<div class="homework-view">
|
||
<!-- 背景动画 -->
|
||
<div class="background-animation">
|
||
<div class="floating-shape" v-for="i in 6" :key="i" :style="{
|
||
left: Math.random() * 100 + '%',
|
||
top: Math.random() * 100 + '%',
|
||
animationDelay: Math.random() * 2 + 's'
|
||
}"></div>
|
||
</div>
|
||
|
||
<div class="homework-container">
|
||
<!-- 页面头部 -->
|
||
<div class="page-header">
|
||
<div class="header-content">
|
||
<h1 class="page-title">📝 作业管理</h1>
|
||
<p class="page-subtitle">管理和完成您的学习作业</p>
|
||
</div>
|
||
<div class="header-actions">
|
||
<button class="btn btn-primary" @click="showCreateModal = true">
|
||
<i class="icon">➕</i>
|
||
创建作业
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 作业导航 -->
|
||
<div class="homework-nav">
|
||
<button class="nav-btn" :class="{ active: activeTab === 'pending' }" @click="activeTab = 'pending'">
|
||
<i class="nav-icon">⏳</i>
|
||
待完成 ({{ pendingHomework.length }})
|
||
</button>
|
||
<button class="nav-btn" :class="{ active: activeTab === 'submitted' }" @click="activeTab = 'submitted'">
|
||
<i class="nav-icon">✅</i>
|
||
已提交 ({{ submittedHomework.length }})
|
||
</button>
|
||
<button class="nav-btn" :class="{ active: activeTab === 'graded' }" @click="activeTab = 'graded'">
|
||
<i class="nav-icon">📊</i>
|
||
已批改 ({{ gradedHomework.length }})
|
||
</button>
|
||
<button class="nav-btn" :class="{ active: activeTab === 'overdue' }" @click="activeTab = 'overdue'">
|
||
<i class="nav-icon">⚠️</i>
|
||
已逾期 ({{ overdueHomework.length }})
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 搜索和筛选 -->
|
||
<div class="search-filter">
|
||
<div class="search-box">
|
||
<i class="search-icon">🔍</i>
|
||
<input type="text" v-model="searchQuery" placeholder="搜索作业...">
|
||
</div>
|
||
<div class="filter-options">
|
||
<select v-model="selectedSubject">
|
||
<option value="">所有科目</option>
|
||
<option v-for="subject in subjects" :key="subject" :value="subject">{{ subject }}</option>
|
||
</select>
|
||
<select v-model="selectedPriority">
|
||
<option value="">所有优先级</option>
|
||
<option value="高">高优先级</option>
|
||
<option value="中">中优先级</option>
|
||
<option value="低">低优先级</option>
|
||
</select>
|
||
<select v-model="sortBy">
|
||
<option value="dueDate">按截止时间</option>
|
||
<option value="createDate">按创建时间</option>
|
||
<option value="priority">按优先级</option>
|
||
<option value="subject">按科目</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 作业统计 -->
|
||
<div class="homework-stats">
|
||
<div class="stat-card">
|
||
<div class="stat-icon">📋</div>
|
||
<div class="stat-info">
|
||
<span class="stat-number">{{ totalHomework }}</span>
|
||
<span class="stat-label">总作业数</span>
|
||
</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-icon">✅</div>
|
||
<div class="stat-info">
|
||
<span class="stat-number">{{ completionRate }}%</span>
|
||
<span class="stat-label">完成率</span>
|
||
</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-icon">⭐</div>
|
||
<div class="stat-info">
|
||
<span class="stat-number">{{ averageScore }}</span>
|
||
<span class="stat-label">平均分</span>
|
||
</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-icon">⏰</div>
|
||
<div class="stat-info">
|
||
<span class="stat-number">{{ urgentCount }}</span>
|
||
<span class="stat-label">紧急作业</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 作业列表 -->
|
||
<div class="homework-list">
|
||
<div class="homework-item" v-for="homework in filteredHomework" :key="homework.id"
|
||
:class="{ urgent: isUrgent(homework.dueDate), overdue: isOverdue(homework.dueDate) }">
|
||
<div class="homework-header">
|
||
<div class="homework-info">
|
||
<h3 class="homework-title">{{ homework.title }}</h3>
|
||
<div class="homework-meta">
|
||
<span class="subject-tag" :style="{ backgroundColor: getSubjectColor(homework.subject) }">
|
||
{{ homework.subject }}
|
||
</span>
|
||
<span class="priority-tag" :class="homework.priority">
|
||
{{ homework.priority }}优先级
|
||
</span>
|
||
<span class="due-date">
|
||
📅 {{ formatDate(homework.dueDate) }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="homework-actions">
|
||
<button class="action-btn" @click="goToHomeworkDetail(homework)" title="查看详情">
|
||
👁️
|
||
</button>
|
||
<button class="action-btn" @click="editHomework(homework)" title="编辑">
|
||
✏️
|
||
</button>
|
||
<button class="action-btn delete" @click="deleteHomework(homework.id)" title="删除">
|
||
🗑️
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="homework-content">
|
||
<p class="homework-description">{{ homework.description }}</p>
|
||
<div class="homework-details">
|
||
<div class="detail-item">
|
||
<span class="detail-label">创建时间:</span>
|
||
<span class="detail-value">{{ formatDate(homework.createDate) }}</span>
|
||
</div>
|
||
<div class="detail-item" v-if="homework.teacher">
|
||
<span class="detail-label">布置老师:</span>
|
||
<span class="detail-value">{{ homework.teacher }}</span>
|
||
</div>
|
||
<div class="detail-item" v-if="homework.estimatedTime">
|
||
<span class="detail-label">预计时长:</span>
|
||
<span class="detail-value">{{ homework.estimatedTime }}分钟</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="homework-footer">
|
||
<div class="progress-info" v-if="homework.status === 'pending'">
|
||
<span class="progress-label">进度:</span>
|
||
<div class="progress-bar">
|
||
<div class="progress-fill" :style="{ width: homework.progress + '%' }"></div>
|
||
</div>
|
||
<span class="progress-text">{{ homework.progress }}%</span>
|
||
</div>
|
||
<div class="score-info" v-if="homework.score !== null">
|
||
<span class="score-label">得分:</span>
|
||
<span class="score-value" :class="getScoreClass(homework.score)">{{ homework.score }}/100</span>
|
||
</div>
|
||
<div class="homework-buttons">
|
||
<button class="btn btn-primary" v-if="homework.status === 'pending'" @click="startHomework(homework)">
|
||
{{ homework.progress > 0 ? '继续完成' : '开始作业' }}
|
||
</button>
|
||
<button class="btn btn-success" v-if="homework.status === 'submitted'" disabled>
|
||
已提交
|
||
</button>
|
||
<button class="btn btn-info" v-if="homework.status === 'graded'" @click="viewFeedback(homework)">
|
||
查看反馈
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 空状态 -->
|
||
<div class="empty-state" v-if="filteredHomework.length === 0">
|
||
<div class="empty-icon">📝</div>
|
||
<h3 class="empty-title">暂无作业</h3>
|
||
<p class="empty-description">当前筛选条件下没有找到作业</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 创建作业模态框 -->
|
||
<div class="modal-overlay" v-if="showCreateModal" @click="closeCreateModal">
|
||
<div class="modal-content" @click.stop>
|
||
<div class="modal-header">
|
||
<h3>创建新作业</h3>
|
||
<button class="close-btn" @click="closeCreateModal">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form @submit.prevent="createHomework">
|
||
<div class="form-group">
|
||
<label>作业标题</label>
|
||
<input type="text" v-model="newHomework.title" required placeholder="请输入作业标题">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>作业描述</label>
|
||
<textarea v-model="newHomework.description" rows="3" placeholder="请输入作业描述"></textarea>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label>科目</label>
|
||
<select v-model="newHomework.subject" required>
|
||
<option value="">选择科目</option>
|
||
<option v-for="subject in subjects" :key="subject" :value="subject">{{ subject }}</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>优先级</label>
|
||
<select v-model="newHomework.priority" required>
|
||
<option value="低">低优先级</option>
|
||
<option value="中">中优先级</option>
|
||
<option value="高">高优先级</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label>截止时间</label>
|
||
<input type="datetime-local" v-model="newHomework.dueDate" required>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>预计时长(分钟)</label>
|
||
<input type="number" v-model="newHomework.estimatedTime" min="1" placeholder="60">
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>布置老师</label>
|
||
<input type="text" v-model="newHomework.teacher" placeholder="请输入老师姓名">
|
||
</div>
|
||
<div class="form-actions">
|
||
<button type="button" class="btn btn-outline" @click="closeCreateModal">取消</button>
|
||
<button type="submit" class="btn btn-primary">创建作业</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 作业详情模态框 -->
|
||
<div class="modal-overlay" v-if="showDetailModal" @click="closeDetailModal">
|
||
<div class="modal-content large" @click.stop>
|
||
<div class="modal-header">
|
||
<h3>{{ selectedHomework?.title }}</h3>
|
||
<button class="close-btn" @click="closeDetailModal">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="homework-detail" v-if="selectedHomework">
|
||
<div class="detail-section">
|
||
<h4>作业信息</h4>
|
||
<div class="detail-grid">
|
||
<div class="detail-item">
|
||
<span class="detail-label">科目:</span>
|
||
<span class="detail-value">{{ selectedHomework.subject }}</span>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="detail-label">优先级:</span>
|
||
<span class="detail-value">{{ selectedHomework.priority }}优先级</span>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="detail-label">截止时间:</span>
|
||
<span class="detail-value">{{ formatDate(selectedHomework.dueDate) }}</span>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="detail-label">预计时长:</span>
|
||
<span class="detail-value">{{ selectedHomework.estimatedTime }}分钟</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>作业描述</h4>
|
||
<p class="homework-description">{{ selectedHomework.description }}</p>
|
||
</div>
|
||
<div class="detail-section" v-if="selectedHomework.feedback">
|
||
<h4>老师反馈</h4>
|
||
<div class="feedback-content">
|
||
<p>{{ selectedHomework.feedback }}</p>
|
||
<div class="feedback-score">
|
||
<span>得分: {{ selectedHomework.score }}/100</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, computed, onMounted } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
|
||
const router = useRouter()
|
||
|
||
// 响应式数据
|
||
const activeTab = ref('pending')
|
||
const searchQuery = ref('')
|
||
const selectedSubject = ref('')
|
||
const selectedPriority = ref('')
|
||
const sortBy = ref('dueDate')
|
||
const showCreateModal = ref(false)
|
||
const showDetailModal = ref(false)
|
||
const selectedHomework = ref(null)
|
||
|
||
const subjects = ['数学', '物理', '化学', '生物', '语文', '英语', '历史', '地理', '政治']
|
||
|
||
const newHomework = reactive({
|
||
title: '',
|
||
description: '',
|
||
subject: '',
|
||
priority: '中',
|
||
dueDate: '',
|
||
estimatedTime: 60,
|
||
teacher: ''
|
||
})
|
||
|
||
const homeworkList = ref([
|
||
{
|
||
id: 1,
|
||
title: '数学函数练习题',
|
||
description: '完成教材第5章函数相关的练习题,包括一次函数、二次函数和反比例函数的综合应用。',
|
||
subject: '数学',
|
||
priority: '高',
|
||
status: 'pending',
|
||
progress: 60,
|
||
dueDate: '2024-01-20T23:59',
|
||
createDate: '2024-01-15T10:00',
|
||
teacher: '李老师',
|
||
estimatedTime: 90,
|
||
score: null,
|
||
feedback: null
|
||
},
|
||
{
|
||
id: 2,
|
||
title: '物理力学实验报告',
|
||
description: '根据课堂实验,完成关于牛顿第二定律的实验报告,包括实验过程、数据分析和结论。',
|
||
subject: '物理',
|
||
priority: '中',
|
||
status: 'submitted',
|
||
progress: 100,
|
||
dueDate: '2024-01-18T23:59',
|
||
createDate: '2024-01-12T14:30',
|
||
teacher: '王老师',
|
||
estimatedTime: 120,
|
||
score: null,
|
||
feedback: null
|
||
},
|
||
{
|
||
id: 3,
|
||
title: '英语阅读理解练习',
|
||
description: '完成Unit 3的阅读理解练习,包括词汇理解、段落大意和主旨归纳。',
|
||
subject: '英语',
|
||
priority: '中',
|
||
status: 'graded',
|
||
progress: 100,
|
||
dueDate: '2024-01-15T23:59',
|
||
createDate: '2024-01-10T09:00',
|
||
teacher: '张老师',
|
||
estimatedTime: 45,
|
||
score: 85,
|
||
feedback: '阅读理解能力有所提升,但在词汇理解方面还需要加强练习。'
|
||
},
|
||
{
|
||
id: 4,
|
||
title: '化学方程式配平练习',
|
||
description: '练习化学方程式的配平方法,完成课后练习题1-20题。',
|
||
subject: '化学',
|
||
priority: '低',
|
||
status: 'overdue',
|
||
progress: 30,
|
||
dueDate: '2024-01-12T23:59',
|
||
createDate: '2024-01-08T16:00',
|
||
teacher: '陈老师',
|
||
estimatedTime: 60,
|
||
score: null,
|
||
feedback: null
|
||
},
|
||
{
|
||
id: 5,
|
||
title: '语文古诗词背诵',
|
||
description: '背诵《静夜思》、《春晓》、《登鹳雀楼》三首古诗,并理解其意境。',
|
||
subject: '语文',
|
||
priority: '高',
|
||
status: 'pending',
|
||
progress: 0,
|
||
dueDate: '2024-01-22T23:59',
|
||
createDate: '2024-01-16T11:00',
|
||
teacher: '刘老师',
|
||
estimatedTime: 30,
|
||
score: null,
|
||
feedback: null
|
||
}
|
||
])
|
||
|
||
// 计算属性
|
||
const pendingHomework = computed(() => homeworkList.value.filter(h => h.status === 'pending'))
|
||
const submittedHomework = computed(() => homeworkList.value.filter(h => h.status === 'submitted'))
|
||
const gradedHomework = computed(() => homeworkList.value.filter(h => h.status === 'graded'))
|
||
const overdueHomework = computed(() => homeworkList.value.filter(h => h.status === 'overdue'))
|
||
|
||
const currentHomework = computed(() => {
|
||
switch (activeTab.value) {
|
||
case 'pending': return pendingHomework.value
|
||
case 'submitted': return submittedHomework.value
|
||
case 'graded': return gradedHomework.value
|
||
case 'overdue': return overdueHomework.value
|
||
default: return []
|
||
}
|
||
})
|
||
|
||
const filteredHomework = computed(() => {
|
||
let filtered = currentHomework.value
|
||
|
||
// 搜索过滤
|
||
if (searchQuery.value) {
|
||
filtered = filtered.filter(h =>
|
||
h.title.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
|
||
h.description.toLowerCase().includes(searchQuery.value.toLowerCase())
|
||
)
|
||
}
|
||
|
||
// 科目过滤
|
||
if (selectedSubject.value) {
|
||
filtered = filtered.filter(h => h.subject === selectedSubject.value)
|
||
}
|
||
|
||
// 优先级过滤
|
||
if (selectedPriority.value) {
|
||
filtered = filtered.filter(h => h.priority === selectedPriority.value)
|
||
}
|
||
|
||
// 排序
|
||
filtered.sort((a, b) => {
|
||
switch (sortBy.value) {
|
||
case 'dueDate':
|
||
return new Date(a.dueDate) - new Date(b.dueDate)
|
||
case 'createDate':
|
||
return new Date(b.createDate) - new Date(a.createDate)
|
||
case 'priority':
|
||
const priorityOrder = { '高': 3, '中': 2, '低': 1 }
|
||
return priorityOrder[b.priority] - priorityOrder[a.priority]
|
||
case 'subject':
|
||
return a.subject.localeCompare(b.subject)
|
||
default:
|
||
return 0
|
||
}
|
||
})
|
||
|
||
return filtered
|
||
})
|
||
|
||
const totalHomework = computed(() => homeworkList.value.length)
|
||
const completionRate = computed(() => {
|
||
const completed = homeworkList.value.filter(h => h.status === 'graded' || h.status === 'submitted').length
|
||
return totalHomework.value > 0 ? Math.round((completed / totalHomework.value) * 100) : 0
|
||
})
|
||
const averageScore = computed(() => {
|
||
const gradedItems = homeworkList.value.filter(h => h.score !== null)
|
||
if (gradedItems.length === 0) return 0
|
||
const total = gradedItems.reduce((sum, h) => sum + h.score, 0)
|
||
return Math.round(total / gradedItems.length)
|
||
})
|
||
const urgentCount = computed(() => {
|
||
return homeworkList.value.filter(h => isUrgent(h.dueDate) && h.status === 'pending').length
|
||
})
|
||
|
||
// 方法
|
||
const isUrgent = (dueDate) => {
|
||
const now = new Date()
|
||
const due = new Date(dueDate)
|
||
const diffHours = (due - now) / (1000 * 60 * 60)
|
||
return diffHours <= 24 && diffHours > 0
|
||
}
|
||
|
||
const isOverdue = (dueDate) => {
|
||
const now = new Date()
|
||
const due = new Date(dueDate)
|
||
return due < now
|
||
}
|
||
|
||
const formatDate = (dateString) => {
|
||
const date = new Date(dateString)
|
||
return date.toLocaleString('zh-CN', {
|
||
year: 'numeric',
|
||
month: '2-digit',
|
||
day: '2-digit',
|
||
hour: '2-digit',
|
||
minute: '2-digit'
|
||
})
|
||
}
|
||
|
||
const getSubjectColor = (subject) => {
|
||
const colors = {
|
||
'数学': '#FF6B6B',
|
||
'物理': '#4ECDC4',
|
||
'化学': '#45B7D1',
|
||
'生物': '#96CEB4',
|
||
'语文': '#FFEAA7',
|
||
'英语': '#DDA0DD',
|
||
'历史': '#98D8C8',
|
||
'地理': '#F7DC6F',
|
||
'政治': '#BB8FCE'
|
||
}
|
||
return colors[subject] || '#95A5A6'
|
||
}
|
||
|
||
const getScoreClass = (score) => {
|
||
if (score >= 90) return 'excellent'
|
||
if (score >= 80) return 'good'
|
||
if (score >= 70) return 'average'
|
||
return 'poor'
|
||
}
|
||
|
||
const viewHomework = (homework) => {
|
||
selectedHomework.value = homework
|
||
showDetailModal.value = true
|
||
}
|
||
|
||
const goToHomeworkDetail = (homework) => {
|
||
// 跳转到作业详情页面
|
||
router.push(`/homework/${homework.id}`)
|
||
}
|
||
|
||
const editHomework = (homework) => {
|
||
// 编辑作业逻辑
|
||
console.log('编辑作业:', homework)
|
||
}
|
||
|
||
const deleteHomework = (id) => {
|
||
if (confirm('确定要删除这个作业吗?')) {
|
||
const index = homeworkList.value.findIndex(h => h.id === id)
|
||
if (index > -1) {
|
||
homeworkList.value.splice(index, 1)
|
||
}
|
||
}
|
||
}
|
||
|
||
const startHomework = (homework) => {
|
||
// 跳转到作业详情页面
|
||
router.push(`/homework/${homework.id}`)
|
||
}
|
||
|
||
const viewFeedback = (homework) => {
|
||
viewHomework(homework)
|
||
}
|
||
|
||
const createHomework = () => {
|
||
const homework = {
|
||
id: Date.now(),
|
||
...newHomework,
|
||
status: 'pending',
|
||
progress: 0,
|
||
createDate: new Date().toISOString(),
|
||
score: null,
|
||
feedback: null
|
||
}
|
||
|
||
homeworkList.value.push(homework)
|
||
closeCreateModal()
|
||
|
||
// 重置表单
|
||
Object.keys(newHomework).forEach(key => {
|
||
if (key === 'priority') {
|
||
newHomework[key] = '中'
|
||
} else if (key === 'estimatedTime') {
|
||
newHomework[key] = 60
|
||
} else {
|
||
newHomework[key] = ''
|
||
}
|
||
})
|
||
}
|
||
|
||
const closeCreateModal = () => {
|
||
showCreateModal.value = false
|
||
}
|
||
|
||
const closeDetailModal = () => {
|
||
showDetailModal.value = false
|
||
selectedHomework.value = null
|
||
}
|
||
|
||
// 页面加载动画
|
||
onMounted(() => {
|
||
const cards = document.querySelectorAll('.homework-item, .stat-card')
|
||
cards.forEach((card, index) => {
|
||
setTimeout(() => {
|
||
card.style.opacity = '1'
|
||
card.style.transform = 'translateY(0)'
|
||
}, index * 100)
|
||
})
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.homework-view {
|
||
min-height: 100vh;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
position: relative;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
.background-animation {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
pointer-events: none;
|
||
z-index: 1;
|
||
}
|
||
|
||
.floating-shape {
|
||
position: absolute;
|
||
width: 80px;
|
||
height: 80px;
|
||
background: rgba(255, 255, 255, 0.1);
|
||
border-radius: 50%;
|
||
animation: float 8s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes float {
|
||
0%, 100% { transform: translateY(0px) rotate(0deg); }
|
||
50% { transform: translateY(-30px) rotate(180deg); }
|
||
}
|
||
|
||
.homework-container {
|
||
position: relative;
|
||
z-index: 2;
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 2rem;
|
||
}
|
||
|
||
.page-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 2rem;
|
||
background: rgba(255, 255, 255, 0.95);
|
||
backdrop-filter: blur(10px);
|
||
border-radius: 15px;
|
||
padding: 1.5rem;
|
||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.header-content h1 {
|
||
font-size: 2rem;
|
||
font-weight: 700;
|
||
color: #333;
|
||
margin: 0 0 0.5rem 0;
|
||
}
|
||
|
||
.header-content p {
|
||
color: #666;
|
||
margin: 0;
|
||
}
|
||
|
||
.header-actions .btn {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.homework-nav {
|
||
display: flex;
|
||
gap: 1rem;
|
||
margin-bottom: 2rem;
|
||
background: rgba(255, 255, 255, 0.95);
|
||
backdrop-filter: blur(10px);
|
||
border-radius: 15px;
|
||
padding: 1rem;
|
||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.nav-btn {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 0.5rem;
|
||
padding: 1rem;
|
||
background: transparent;
|
||
border: 2px solid #e0e0e0;
|
||
border-radius: 10px;
|
||
color: #666;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.nav-btn:hover {
|
||
background: #f8f9fa;
|
||
border-color: #667eea;
|
||
}
|
||
|
||
.nav-btn.active {
|
||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||
border-color: #667eea;
|
||
color: white;
|
||
}
|
||
|
||
.nav-icon {
|
||
font-size: 1.2rem;
|
||
}
|
||
|
||
.search-filter {
|
||
display: flex;
|
||
gap: 1rem;
|
||
margin-bottom: 2rem;
|
||
background: rgba(255, 255, 255, 0.95);
|
||
backdrop-filter: blur(10px);
|
||
border-radius: 15px;
|
||
padding: 1.5rem;
|
||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.search-box {
|
||
flex: 1;
|
||
position: relative;
|
||
}
|
||
|
||
.search-icon {
|
||
position: absolute;
|
||
left: 1rem;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
color: #666;
|
||
}
|
||
|
||
.search-box input {
|
||
width: 100%;
|
||
padding: 0.75rem 1rem 0.75rem 3rem;
|
||
border: 2px solid #e0e0e0;
|
||
border-radius: 10px;
|
||
font-size: 1rem;
|
||
transition: border-color 0.3s ease;
|
||
}
|
||
|
||
.search-box input:focus {
|
||
outline: none;
|
||
border-color: #667eea;
|
||
}
|
||
|
||
.filter-options {
|
||
display: flex;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.filter-options select {
|
||
padding: 0.75rem;
|
||
border: 2px solid #e0e0e0;
|
||
border-radius: 10px;
|
||
background: white;
|
||
font-size: 1rem;
|
||
cursor: pointer;
|
||
transition: border-color 0.3s ease;
|
||
}
|
||
|
||
.filter-options select:focus {
|
||
outline: none;
|
||
border-color: #667eea;
|
||
}
|
||
|
||
.homework-stats {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
gap: 1rem;
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.stat-card {
|
||
background: rgba(255, 255, 255, 0.95);
|
||
backdrop-filter: blur(10px);
|
||
border-radius: 15px;
|
||
padding: 1.5rem;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 1rem;
|
||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||
opacity: 0;
|
||
transform: translateY(20px);
|
||
transition: all 0.5s ease;
|
||
}
|
||
|
||
.stat-icon {
|
||
width: 50px;
|
||
height: 50px;
|
||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 1.5rem;
|
||
color: white;
|
||
}
|
||
|
||
.stat-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.stat-number {
|
||
display: block;
|
||
font-size: 1.5rem;
|
||
font-weight: 700;
|
||
color: #333;
|
||
}
|
||
|
||
.stat-label {
|
||
color: #666;
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.homework-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.homework-item {
|
||
background: rgba(255, 255, 255, 0.95);
|
||
backdrop-filter: blur(10px);
|
||
border-radius: 15px;
|
||
padding: 1.5rem;
|
||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||
opacity: 0;
|
||
transform: translateY(20px);
|
||
transition: all 0.5s ease;
|
||
border-left: 4px solid #e0e0e0;
|
||
}
|
||
|
||
.homework-item.urgent {
|
||
border-left-color: #FF6B6B;
|
||
background: rgba(255, 107, 107, 0.05);
|
||
}
|
||
|
||
.homework-item.overdue {
|
||
border-left-color: #FF4757;
|
||
background: rgba(255, 71, 87, 0.05);
|
||
}
|
||
|
||
.homework-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.homework-title {
|
||
font-size: 1.2rem;
|
||
font-weight: 700;
|
||
color: #333;
|
||
margin: 0 0 0.5rem 0;
|
||
}
|
||
|
||
.homework-meta {
|
||
display: flex;
|
||
gap: 0.5rem;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.subject-tag {
|
||
padding: 0.25rem 0.75rem;
|
||
border-radius: 15px;
|
||
color: white;
|
||
font-size: 0.8rem;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.priority-tag {
|
||
padding: 0.25rem 0.75rem;
|
||
border-radius: 15px;
|
||
font-size: 0.8rem;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.priority-tag.高 {
|
||
background: #FF6B6B;
|
||
color: white;
|
||
}
|
||
|
||
.priority-tag.中 {
|
||
background: #FFD93D;
|
||
color: #333;
|
||
}
|
||
|
||
.priority-tag.低 {
|
||
background: #6BCF7F;
|
||
color: white;
|
||
}
|
||
|
||
.due-date {
|
||
color: #666;
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.homework-actions {
|
||
display: flex;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.action-btn {
|
||
width: 35px;
|
||
height: 35px;
|
||
border: none;
|
||
border-radius: 8px;
|
||
background: #f8f9fa;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.action-btn:hover {
|
||
background: #e9ecef;
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
.action-btn.delete:hover {
|
||
background: #FF6B6B;
|
||
color: white;
|
||
}
|
||
|
||
.homework-description {
|
||
color: #666;
|
||
line-height: 1.6;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.homework-details {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
gap: 0.5rem;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.detail-item {
|
||
display: flex;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.detail-label {
|
||
font-weight: 600;
|
||
color: #666;
|
||
min-width: 80px;
|
||
}
|
||
|
||
.detail-value {
|
||
color: #333;
|
||
}
|
||
|
||
.homework-footer {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
gap: 1rem;
|
||
padding-top: 1rem;
|
||
border-top: 1px solid #e0e0e0;
|
||
}
|
||
|
||
.progress-info {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 1rem;
|
||
flex: 1;
|
||
}
|
||
|
||
.progress-label {
|
||
font-weight: 600;
|
||
color: #666;
|
||
}
|
||
|
||
.progress-bar {
|
||
flex: 1;
|
||
height: 8px;
|
||
background: #e0e0e0;
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.progress-fill {
|
||
height: 100%;
|
||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||
border-radius: 4px;
|
||
transition: width 0.5s ease;
|
||
}
|
||
|
||
.progress-text {
|
||
font-weight: 600;
|
||
color: #667eea;
|
||
}
|
||
|
||
.score-info {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.score-label {
|
||
font-weight: 600;
|
||
color: #666;
|
||
}
|
||
|
||
.score-value {
|
||
font-weight: 700;
|
||
font-size: 1.1rem;
|
||
}
|
||
|
||
.score-value.excellent {
|
||
color: #4CAF50;
|
||
}
|
||
|
||
.score-value.good {
|
||
color: #2196F3;
|
||
}
|
||
|
||
.score-value.average {
|
||
color: #FF9800;
|
||
}
|
||
|
||
.score-value.poor {
|
||
color: #F44336;
|
||
}
|
||
|
||
.homework-buttons {
|
||
display: flex;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.btn {
|
||
padding: 0.5rem 1rem;
|
||
border: none;
|
||
border-radius: 8px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
text-decoration: none;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.btn-primary {
|
||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||
color: white;
|
||
}
|
||
|
||
.btn-primary:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
|
||
}
|
||
|
||
.btn-success {
|
||
background: #4CAF50;
|
||
color: white;
|
||
}
|
||
|
||
.btn-info {
|
||
background: #2196F3;
|
||
color: white;
|
||
}
|
||
|
||
.btn-outline {
|
||
background: transparent;
|
||
color: #667eea;
|
||
border: 2px solid #667eea;
|
||
}
|
||
|
||
.btn-outline:hover {
|
||
background: #667eea;
|
||
color: white;
|
||
}
|
||
|
||
.empty-state {
|
||
text-align: center;
|
||
padding: 3rem;
|
||
background: rgba(255, 255, 255, 0.95);
|
||
backdrop-filter: blur(10px);
|
||
border-radius: 15px;
|
||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.empty-icon {
|
||
font-size: 4rem;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.empty-title {
|
||
font-size: 1.5rem;
|
||
font-weight: 700;
|
||
color: #333;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.empty-description {
|
||
color: #666;
|
||
}
|
||
|
||
/* 模态框样式 */
|
||
.modal-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.modal-content {
|
||
background: white;
|
||
border-radius: 15px;
|
||
width: 90%;
|
||
max-width: 600px;
|
||
max-height: 90vh;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.modal-content.large {
|
||
max-width: 800px;
|
||
}
|
||
|
||
.modal-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 1.5rem;
|
||
border-bottom: 1px solid #e0e0e0;
|
||
}
|
||
|
||
.modal-header h3 {
|
||
margin: 0;
|
||
color: #333;
|
||
}
|
||
|
||
.close-btn {
|
||
background: none;
|
||
border: none;
|
||
font-size: 1.5rem;
|
||
cursor: pointer;
|
||
color: #666;
|
||
padding: 0;
|
||
width: 30px;
|
||
height: 30px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.modal-body {
|
||
padding: 1.5rem;
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.form-group label {
|
||
display: block;
|
||
margin-bottom: 0.5rem;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
|
||
.form-group input,
|
||
.form-group textarea,
|
||
.form-group select {
|
||
width: 100%;
|
||
padding: 0.75rem;
|
||
border: 2px solid #e0e0e0;
|
||
border-radius: 8px;
|
||
font-size: 1rem;
|
||
transition: border-color 0.3s ease;
|
||
}
|
||
|
||
.form-group input:focus,
|
||
.form-group textarea:focus,
|
||
.form-group select:focus {
|
||
outline: none;
|
||
border-color: #667eea;
|
||
}
|
||
|
||
.form-row {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.form-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 1rem;
|
||
margin-top: 1.5rem;
|
||
}
|
||
|
||
.homework-detail {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1.5rem;
|
||
}
|
||
|
||
.detail-section h4 {
|
||
margin: 0 0 1rem 0;
|
||
color: #333;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.detail-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 1rem;
|
||
}
|
||
|
||
.feedback-content {
|
||
background: #f8f9fa;
|
||
padding: 1rem;
|
||
border-radius: 8px;
|
||
border-left: 4px solid #667eea;
|
||
}
|
||
|
||
.feedback-score {
|
||
margin-top: 1rem;
|
||
font-weight: 600;
|
||
color: #667eea;
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 768px) {
|
||
.homework-container {
|
||
padding: 1rem;
|
||
}
|
||
|
||
.page-header {
|
||
flex-direction: column;
|
||
gap: 1rem;
|
||
text-align: center;
|
||
}
|
||
|
||
.homework-nav {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.search-filter {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.homework-stats {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.homework-header {
|
||
flex-direction: column;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.homework-footer {
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
}
|
||
|
||
.form-row {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.detail-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
</style> |