iGuwan-homework/src/views/dashboard/HomeworkView.vue

1278 lines
31 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>