|
|
@@ -4,92 +4,170 @@
|
|
|
Created Date: 2024-7-3
|
|
|
-->
|
|
|
<template>
|
|
|
- <el-card style="margin: 10px auto 0;height: 100%; width: 80%" shadow="never">
|
|
|
- <el-button :icon="Refresh" circle @click="doRefresh"></el-button>
|
|
|
- <el-select
|
|
|
- v-model="state"
|
|
|
- placeholder="状态"
|
|
|
- size="default"
|
|
|
- style="width: 150px; margin-left: 10px;"
|
|
|
- @change="handleSearch"
|
|
|
- >
|
|
|
- <el-option
|
|
|
- v-for="item in stateOptions"
|
|
|
- :key="item.value"
|
|
|
- :label="item.label"
|
|
|
- :value="item.value"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- <el-input v-model="assignmentName" placeholder="请输入作业名称" clearable style="width: 180px;"/>
|
|
|
- <el-button @click="handleSearch" color="#597D3B">
|
|
|
- <el-icon style="margin-right: 3px" ><Search/></el-icon>
|
|
|
- 查询
|
|
|
- </el-button>
|
|
|
-
|
|
|
- <el-table :data="pageInfo.tableData" style="width: 100%" height="100%" show-overflow-tooltip>
|
|
|
- <template #empty>
|
|
|
- 暂无作业
|
|
|
- </template>
|
|
|
- <el-table-column type="index"/>
|
|
|
- <el-table-column prop="assignmentName" label="课程名称" width="400"/>
|
|
|
- <el-table-column prop="type" label="类型" width="100"/>
|
|
|
-<!-- <el-table-column prop="description" label="描述" width="400"/>-->
|
|
|
- <el-table-column prop="endTime" label="截止时间" sortable/>
|
|
|
- <el-table-column prop="status" label="状态" sortable>
|
|
|
- <template #default="{row}">
|
|
|
- <el-tag v-if="row.status === AssignmentStatus.NOT_STARTED" type="info">未发布</el-tag>
|
|
|
- <el-tag v-else-if="row.status === AssignmentStatus.PROCEEDING" type="success">进行中</el-tag>
|
|
|
- <el-tag v-else-if="row.status === AssignmentStatus.FINISHED" type="danger">已截止</el-tag>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="操作" width="100">
|
|
|
- <template #default="scope">
|
|
|
- <el-button @click="handleShowDetail(scope.row.assignmentId)" style="margin-right: 0; margin-left: 0;padding-left: 10px; padding-right: 10px" color="#597D3B">
|
|
|
- <el-icon style="margin-right: 3px"><ZoomIn/></el-icon>
|
|
|
- 详情
|
|
|
+ <div class="homework-page">
|
|
|
+ <!-- 左侧课程菜单栏 -->
|
|
|
+ <div class="left-sidebar">
|
|
|
+ <div class="course-list">
|
|
|
+ <div
|
|
|
+ v-for="course in courseList"
|
|
|
+ :key="course.courseId"
|
|
|
+ class="course-item"
|
|
|
+ :class="{ 'active': selectedCourseId === course.courseId }"
|
|
|
+ @click="selectCourse(course.courseId)"
|
|
|
+ >
|
|
|
+ <div class="course-name">{{ course.courseName }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 右侧内容区域 -->
|
|
|
+ <div class="right-content">
|
|
|
+ <!-- 空白状态 -->
|
|
|
+ <div v-if="!selectedCourseId" class="empty-state">
|
|
|
+ <div class="empty-content">
|
|
|
+ <div class="empty-text">请选择一门课程查看作业</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 作业内容区域 -->
|
|
|
+ <div v-else class="assignment-content">
|
|
|
+ <!-- 作业列表标题 -->
|
|
|
+ <h2 class="assignment-title">作业列表</h2>
|
|
|
+
|
|
|
+ <!-- 搜索框 -->
|
|
|
+ <div class="search-section">
|
|
|
+ <el-input
|
|
|
+ v-model="searchQuery"
|
|
|
+ placeholder="Please enter"
|
|
|
+ class="search-input"
|
|
|
+ @input="handleSearch"
|
|
|
+ >
|
|
|
+ <template #suffix>
|
|
|
+ <el-icon class="search-icon"><Search /></el-icon>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ <el-button class="reset-btn" @click="resetSearch">Reset</el-button>
|
|
|
+ <el-button class="query-btn" @click="handleSearch">Query</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 筛选栏 -->
|
|
|
+ <div class="filter-section">
|
|
|
+ <el-button
|
|
|
+ v-for="status in statusFilters"
|
|
|
+ :key="status.value"
|
|
|
+ :class="['filter-btn', { 'active': selectedStatus === status.value }]"
|
|
|
+ @click="selectStatus(status.value)"
|
|
|
+ >
|
|
|
+ {{ status.label }}
|
|
|
</el-button>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="查看" width="150">
|
|
|
- <template #default="scope">
|
|
|
- <el-button @click="viewCorrection(scope.row.assignmentId,store.user.id,scope.row.type, scope.row.assignmentName)" style="margin-right: 0; margin-left: 0;padding-left: 10px; padding-right: 10px" color="#597D3B">
|
|
|
- <el-icon style="margin-right: 3px"><ZoomIn/></el-icon>
|
|
|
- 批改结果
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 第二个筛选栏 -->
|
|
|
+ <div class="filter-section">
|
|
|
+ <el-button
|
|
|
+ v-for="status in secondStatusFilters"
|
|
|
+ :key="status.value"
|
|
|
+ :class="['filter-btn', { 'active': selectedSecondStatus === status.value }]"
|
|
|
+ @click="selectSecondStatus(status.value)"
|
|
|
+ >
|
|
|
+ {{ status.label }}
|
|
|
</el-button>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
-
|
|
|
- <el-pagination
|
|
|
- small
|
|
|
- style="font-size: 16px;margin-top: 10px;margin-left: 450px"
|
|
|
- @current-change="handleCurrentChange"
|
|
|
- @size-change="handleSizeChange"
|
|
|
- :page-sizes="[5, 10, 15]"
|
|
|
- :current-page="pageInfo.pages"
|
|
|
- :page-size="pageInfo.size"
|
|
|
- layout="total, sizes, prev, pager, next, jumper"
|
|
|
- :total="pageInfo.total">
|
|
|
- </el-pagination>
|
|
|
- </el-card>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 作业卡片列表 -->
|
|
|
+ <div class="assignment-cards">
|
|
|
+ <div
|
|
|
+ v-for="assignment in filteredAssignments"
|
|
|
+ :key="assignment.assignmentId"
|
|
|
+ class="assignment-card"
|
|
|
+ >
|
|
|
+ <div class="card-header">
|
|
|
+ <div class="status-indicator" :class="getStatusClass(assignment)"></div>
|
|
|
+ <div class="status-text">{{ getStatusText(assignment) }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="card-content">
|
|
|
+ <h3 class="assignment-name">{{ assignment.assignmentName }}</h3>
|
|
|
+ <div class="assignment-type">{{ assignment.type }}</div>
|
|
|
+ <div class="assignment-time">截止时间: {{ assignment.endTime }}</div>
|
|
|
+ <div class="assignment-second-status">
|
|
|
+ <el-icon class="status-icon-check" v-if="getSecondStatusText(assignment) === '已批改'" ><Check /></el-icon>
|
|
|
+ <el-icon class="status-icon-calendar" v-if="getSecondStatusText(assignment) === '已提交'" ><Calendar /></el-icon>
|
|
|
+ <el-icon class="status-icon-close" v-if="getSecondStatusText(assignment) === '未完成'" ><Close /></el-icon>
|
|
|
+ <span class="status-text" :class="getSecondStatusClass(assignment)">
|
|
|
+ {{ getSecondStatusText(assignment) }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="card-actions">
|
|
|
+ <el-button class="detail-btn" @click="handleShowDetail(assignment.assignmentId)">
|
|
|
+ <el-icon><ZoomIn /></el-icon>
|
|
|
+ 详情
|
|
|
+ </el-button>
|
|
|
+ <el-button class="result-btn" @click="viewCorrection(assignment.assignmentId, store.user.id, assignment.type, assignment.assignmentName)">
|
|
|
+ <el-icon><ZoomIn /></el-icon>
|
|
|
+ 批改结果
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
- import {Refresh, ZoomIn, Search} from "@element-plus/icons-vue";
|
|
|
- import {inject, onMounted, reactive, ref} from "vue";
|
|
|
+ import {ZoomIn, Search} from "@element-plus/icons-vue";
|
|
|
+ import {Calendar,Check,Close} from "@element-plus/icons-vue";
|
|
|
+ import {onMounted, reactive, ref, computed} from "vue";
|
|
|
import useApis from "@/apis";
|
|
|
import {useStore} from "@/store";
|
|
|
import type {CourseVO, IAssignment} from "@/types/vo";
|
|
|
import router from "@/router";
|
|
|
- import {AssignmentStatus} from "@/types/enums";
|
|
|
+
|
|
|
import {useFormatDate} from "@/hooks/useFormatDate";
|
|
|
|
|
|
const apis = useApis()
|
|
|
const store = useStore()
|
|
|
- const doRefresh:Function = inject("reload")
|
|
|
const {formatDate} = useFormatDate()
|
|
|
const role:'teachers' | 'student' = store.user.role === 'STUDENT' ? 'student':'teachers';
|
|
|
|
|
|
+ // 课程列表
|
|
|
+ const courseList = ref<CourseVO[]>([])
|
|
|
+
|
|
|
+ // 选中的课程ID
|
|
|
+ const selectedCourseId = ref<number | null>(null)
|
|
|
+
|
|
|
+ // 搜索查询
|
|
|
+ const searchQuery = ref('')
|
|
|
+
|
|
|
+ // 选中的状态
|
|
|
+ const selectedStatus = ref('全部')
|
|
|
+
|
|
|
+ // 状态筛选选项
|
|
|
+ const statusFilters = [
|
|
|
+ { label: '全部', value: '全部' },
|
|
|
+ { label: '未发布', value: '未发布' },
|
|
|
+ { label: '进行中', value: '进行中' },
|
|
|
+ { label: '已截止', value: '已截止' }
|
|
|
+ ]
|
|
|
+
|
|
|
+ // 选中的第二个状态
|
|
|
+ const selectedSecondStatus = ref('全部')
|
|
|
+
|
|
|
+ // 第二个状态筛选选项
|
|
|
+ const secondStatusFilters = [
|
|
|
+ { label: '全部', value: '全部' },
|
|
|
+ { label: '已批改', value: '已批改' },
|
|
|
+ { label: '已提交', value: '已提交' },
|
|
|
+ { label: '未完成', value: '未完成' }
|
|
|
+ ]
|
|
|
+
|
|
|
+ // 当前课程的作业列表
|
|
|
+ const currentCourseAssignments = ref<IAssignment[]>([])
|
|
|
+
|
|
|
+ // 所有作业数据
|
|
|
+ const allAssignments = ref<IAssignment[]>([])
|
|
|
+
|
|
|
// 获取的所有作业
|
|
|
let homeworkList = reactive<{
|
|
|
tableData: IAssignment[]
|
|
|
@@ -138,22 +216,7 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- const handleCurrentChange = (pageNum: number) => {
|
|
|
- Object.assign(pageInfo, {
|
|
|
- tableData: getSlice(pageNum, pageInfo.size),
|
|
|
- size: pageInfo.size,
|
|
|
- pages: pageNum,
|
|
|
- total: processedHomeworkList.tableData.length,
|
|
|
- })
|
|
|
- }
|
|
|
- const handleSizeChange = (pageSize: number) => {
|
|
|
- Object.assign(pageInfo, {
|
|
|
- tableData: getSlice(1, pageSize),
|
|
|
- size: pageSize,
|
|
|
- pages: 1,
|
|
|
- total: processedHomeworkList.tableData.length,
|
|
|
- })
|
|
|
- }
|
|
|
+
|
|
|
|
|
|
|
|
|
const fetchData = () => {
|
|
|
@@ -164,9 +227,10 @@
|
|
|
let total = res.data.data.total;
|
|
|
apis.getCourseByStudentId(1, total)
|
|
|
.then((res: any) => {
|
|
|
- let data:CourseVO[] = res.data.data.records
|
|
|
- for(let i = 0; i < data.length; i++){
|
|
|
- fetchHomeworkListByCourseId(data[i].courseId)
|
|
|
+ courseList.value = res.data.data.records
|
|
|
+ // 为每个课程获取作业数据
|
|
|
+ for(let i = 0; i < courseList.value.length; i++){
|
|
|
+ fetchHomeworkListByCourseId(courseList.value[i].courseId)
|
|
|
}
|
|
|
})
|
|
|
})
|
|
|
@@ -177,15 +241,153 @@
|
|
|
let total = res.data.data.total;
|
|
|
apis.getCourseByTeacherId(1, total)
|
|
|
.then((res: any) => {
|
|
|
- let data:CourseVO[] = res.data.data.records
|
|
|
- for(let i = 0; i < data.length; i++){
|
|
|
- fetchHomeworkListByCourseId(data[i].courseId)
|
|
|
+ courseList.value = res.data.data.records
|
|
|
+ // 为每个课程获取作业数据
|
|
|
+ for(let i = 0; i < courseList.value.length; i++){
|
|
|
+ fetchHomeworkListByCourseId(courseList.value[i].courseId)
|
|
|
}
|
|
|
})
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // 选择课程
|
|
|
+ const selectCourse = (courseId: number) => {
|
|
|
+ selectedCourseId.value = courseId
|
|
|
+ // 筛选当前课程的作业
|
|
|
+ currentCourseAssignments.value = allAssignments.value.filter(
|
|
|
+ assignment => assignment.courseId === courseId
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重置搜索
|
|
|
+ const resetSearch = () => {
|
|
|
+ searchQuery.value = ''
|
|
|
+ selectedStatus.value = '全部'
|
|
|
+ selectedSecondStatus.value = '全部'
|
|
|
+ }
|
|
|
+
|
|
|
+ // 选择状态
|
|
|
+ const selectStatus = (status: string) => {
|
|
|
+ selectedStatus.value = status
|
|
|
+ }
|
|
|
+
|
|
|
+ // 选择第二个状态
|
|
|
+ const selectSecondStatus = (status: string) => {
|
|
|
+ selectedSecondStatus.value = status
|
|
|
+ }
|
|
|
+
|
|
|
+ // 筛选后的作业列表
|
|
|
+ const filteredAssignments = computed(() => {
|
|
|
+ let filtered = [...currentCourseAssignments.value]
|
|
|
+
|
|
|
+ // 按搜索关键词筛选
|
|
|
+ if (searchQuery.value) {
|
|
|
+ filtered = filtered.filter(assignment =>
|
|
|
+ assignment.assignmentName.toLowerCase().includes(searchQuery.value.toLowerCase())
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ // 按状态筛选
|
|
|
+ if (selectedStatus.value !== '全部') {
|
|
|
+ filtered = filtered.filter(assignment => getActualStatus(assignment) === selectedStatus.value)
|
|
|
+ }
|
|
|
+
|
|
|
+ return filtered
|
|
|
+ })
|
|
|
+
|
|
|
+ // 获取作业的实际状态(基于开始时间和截止时间)
|
|
|
+ const getActualStatus = (assignment: IAssignment) => {
|
|
|
+ const now = new Date()
|
|
|
+
|
|
|
+ // 确保能正确解析结束日期,支持多种格式
|
|
|
+ let endTime: Date
|
|
|
+
|
|
|
+ // 如果endTime是字符串,尝试解析
|
|
|
+ if (typeof assignment.endTime === 'string') {
|
|
|
+ // 处理 "YYYY-MM-DD HH:mm:ss" 格式
|
|
|
+ endTime = new Date(assignment.endTime.replace(' ', 'T'))
|
|
|
+ } else {
|
|
|
+ endTime = new Date(assignment.endTime)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查结束日期是否有效
|
|
|
+ if (isNaN(endTime.getTime())) {
|
|
|
+ console.warn('Invalid end date format:', assignment.endTime)
|
|
|
+ return '进行中' // 默认返回进行中
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析开始时间(如果存在)
|
|
|
+ let startTime: Date | null = null
|
|
|
+ if (assignment.startTime) {
|
|
|
+ if (typeof assignment.startTime === 'string') {
|
|
|
+ startTime = new Date(assignment.startTime.replace(' ', 'T'))
|
|
|
+ } else {
|
|
|
+ startTime = new Date(assignment.startTime)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查开始日期是否有效
|
|
|
+ if (isNaN(startTime.getTime())) {
|
|
|
+ console.warn('Invalid start date format:', assignment.startTime)
|
|
|
+ startTime = null
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断状态优先级:未发布 > 已截止 > 进行中
|
|
|
+ if (startTime && now < startTime) {
|
|
|
+ return '未发布'
|
|
|
+ } else if (now > endTime) {
|
|
|
+ return '已截止'
|
|
|
+ } else {
|
|
|
+ return '进行中'
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取状态样式类
|
|
|
+ const getStatusClass = (assignment: IAssignment) => {
|
|
|
+ const actualStatus = getActualStatus(assignment)
|
|
|
+ switch(actualStatus) {
|
|
|
+ case '未发布':
|
|
|
+ return 'status-unpublished'
|
|
|
+ case '进行中':
|
|
|
+ return 'status-proceeding'
|
|
|
+ case '已截止':
|
|
|
+ return 'status-finished'
|
|
|
+ default:
|
|
|
+ return 'status-unknown'
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取状态文本
|
|
|
+ const getStatusText = (assignment: IAssignment) => {
|
|
|
+ return getActualStatus(assignment)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成随机的提交状态(用于假数据)
|
|
|
+ const getRandomSubmissionStatus = () => {
|
|
|
+ const statuses = ['已批改', '已提交', '未完成']
|
|
|
+ return statuses[Math.floor(Math.random() * statuses.length)]
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取第二个状态的文本
|
|
|
+ const getSecondStatusText = (assignment: any) => {
|
|
|
+ return assignment.submissionStatus || '未完成'
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取第二个状态的样式类
|
|
|
+ const getSecondStatusClass = (assignment: any) => {
|
|
|
+ const status = assignment.submissionStatus || '未完成'
|
|
|
+ switch(status) {
|
|
|
+ case '已批改':
|
|
|
+ case '已提交':
|
|
|
+ return 'status-submitted'
|
|
|
+ case '未完成':
|
|
|
+ return 'status-incomplete'
|
|
|
+ default:
|
|
|
+ return 'status-incomplete'
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
const fetchHomeworkListByCourseId = (courseId:number) => {
|
|
|
apis.getAssignmentByCourseId(courseId)
|
|
|
.then((res: any) => {
|
|
|
@@ -195,7 +397,11 @@
|
|
|
let data = res.data.data.records
|
|
|
for(let i = 0; i < data.length; i++) {
|
|
|
data[i].endTime = formatDate(data[i].endTime)
|
|
|
+ data[i].courseId = courseId // 添加课程ID
|
|
|
+ // 添加假的第二个状态数据
|
|
|
+ data[i].submissionStatus = getRandomSubmissionStatus()
|
|
|
homeworkList.tableData.push(data[i])
|
|
|
+ allAssignments.value.push(data[i]) // 添加到所有作业数组
|
|
|
}
|
|
|
processedHomeworkList.tableData = homeworkList.tableData
|
|
|
Object.assign(pageInfo, {
|
|
|
@@ -208,21 +414,9 @@
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+ // 旧的handleSearch方法保留用于兼容性
|
|
|
const handleSearch = () => {
|
|
|
- processedHomeworkList.tableData = []
|
|
|
- for(let i = 0; i < homeworkList.tableData.length; i++){
|
|
|
- let assignmentItem = homeworkList.tableData[i]
|
|
|
- let input = true;
|
|
|
- if(state.value != null && state.value != assignmentItem.status) input = false;
|
|
|
- if(assignmentName.value != '' && !assignmentItem.assignmentName.includes(assignmentName.value)) input = false;
|
|
|
- if(input) processedHomeworkList.tableData.push(assignmentItem);
|
|
|
- Object.assign(pageInfo, {
|
|
|
- tableData: getSlice(pageInfo.pages, pageInfo.size),
|
|
|
- size: pageInfo.size,
|
|
|
- pages: pageInfo.pages,
|
|
|
- total: processedHomeworkList.tableData.length,
|
|
|
- })
|
|
|
- }
|
|
|
+ // 新版本中不需要实现,因为使用了响应式筛选
|
|
|
}
|
|
|
|
|
|
//用于分页展示,截取数据
|
|
|
@@ -234,23 +428,7 @@
|
|
|
fetchData()
|
|
|
})
|
|
|
|
|
|
- let state = ref(null)
|
|
|
- const stateOptions = [
|
|
|
- {
|
|
|
- value: AssignmentStatus.NOT_STARTED,
|
|
|
- label: "未发布"
|
|
|
- },
|
|
|
- {
|
|
|
- value: AssignmentStatus.PROCEEDING,
|
|
|
- label: "进行中"
|
|
|
- },
|
|
|
- {
|
|
|
- value: AssignmentStatus.FINISHED,
|
|
|
- label: "已截止"
|
|
|
- },
|
|
|
- ]
|
|
|
|
|
|
- let assignmentName = ref('')
|
|
|
|
|
|
</script>
|
|
|
|
|
|
@@ -259,3 +437,333 @@ export default {
|
|
|
name: "HomeworkPage"
|
|
|
}
|
|
|
</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.homework-page {
|
|
|
+ display: flex;
|
|
|
+ height: 95.5vh;
|
|
|
+ font-family: "Noto Sans SC", sans-serif;
|
|
|
+}
|
|
|
+
|
|
|
+/* 左侧菜单栏 */
|
|
|
+.left-sidebar {
|
|
|
+ width: 250px;
|
|
|
+ min-width: 250px;
|
|
|
+ max-width: 250px;
|
|
|
+ background: linear-gradient(180deg, #89CDF1 0%, #1890FF 100%);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.course-list {
|
|
|
+ padding: 20px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.course-item {
|
|
|
+ padding: 15px 25px;
|
|
|
+ color: white;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ border-left: 4px solid transparent;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.course-item:hover {
|
|
|
+ background-color: rgba(255, 255, 255, 0.1);
|
|
|
+ border-left-color: white;
|
|
|
+}
|
|
|
+
|
|
|
+.course-item.active {
|
|
|
+ background-color: rgba(255, 255, 255, 0.2);
|
|
|
+ border-left-color: white;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.course-name {
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+}
|
|
|
+
|
|
|
+/* 右侧内容区域 */
|
|
|
+.right-content {
|
|
|
+ flex: 1;
|
|
|
+ background-color: white;
|
|
|
+ padding: 30px;
|
|
|
+ overflow-y: auto;
|
|
|
+}
|
|
|
+
|
|
|
+/* 空白状态 */
|
|
|
+.empty-state {
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.empty-content {
|
|
|
+ text-align: center;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+.empty-text {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+/* 作业内容区域 */
|
|
|
+.assignment-content {
|
|
|
+ max-width: 1200px;
|
|
|
+}
|
|
|
+
|
|
|
+.assignment-title {
|
|
|
+ font-size: 24px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #2c3e50;
|
|
|
+ margin-bottom: 0px;
|
|
|
+ margin-top: 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* 搜索区域 */
|
|
|
+.search-section {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 15px;
|
|
|
+ margin-bottom: 0px;
|
|
|
+ padding: 20px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.search-input {
|
|
|
+ flex: 1;
|
|
|
+ max-width: 400px;
|
|
|
+}
|
|
|
+
|
|
|
+.reset-btn, .query-btn {
|
|
|
+ padding: 8px 20px;
|
|
|
+ border-radius: 6px;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.reset-btn {
|
|
|
+ background-color: #f5f5f5;
|
|
|
+ border-color: #d9d9d9;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.query-btn {
|
|
|
+ background-color: #1890ff;
|
|
|
+ border-color: #1890ff;
|
|
|
+ color: white;
|
|
|
+}
|
|
|
+
|
|
|
+/* 筛选区域 */
|
|
|
+.filter-section {
|
|
|
+ display: flex;
|
|
|
+ gap: 10px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.filter-btn {
|
|
|
+ padding: 8px 16px;
|
|
|
+ border: 1px solid #d9d9d9;
|
|
|
+ background-color: white;
|
|
|
+ color: #666;
|
|
|
+ border-radius: 6px;
|
|
|
+ font-weight: 500;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.filter-btn:hover {
|
|
|
+ border-color: #1890ff;
|
|
|
+ color: #1890ff;
|
|
|
+}
|
|
|
+
|
|
|
+.filter-btn.active {
|
|
|
+ background-color: #1890ff;
|
|
|
+ border-color: #1890ff;
|
|
|
+ color: white;
|
|
|
+}
|
|
|
+
|
|
|
+/* 作业卡片区域 */
|
|
|
+.assignment-cards {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
|
|
|
+ row-gap: 20px; /* 上下行间距 */
|
|
|
+ column-gap: 70px; /* 左右列间距 */
|
|
|
+}
|
|
|
+
|
|
|
+.assignment-card {
|
|
|
+ background: white;
|
|
|
+ border-radius: 12px;
|
|
|
+ padding: 20px;
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ border: 1px solid #f0f0f0;
|
|
|
+ min-height: 220px;
|
|
|
+}
|
|
|
+
|
|
|
+.assignment-card:hover {
|
|
|
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
|
|
+ transform: translateY(-2px);
|
|
|
+}
|
|
|
+
|
|
|
+.card-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.status-indicator {
|
|
|
+ width: 12px;
|
|
|
+ height: 12px;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-right: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.status-indicator.status-unpublished {
|
|
|
+ background-color: #F0C05A;
|
|
|
+}
|
|
|
+
|
|
|
+.status-indicator.status-proceeding {
|
|
|
+ background-color: #52c41a;
|
|
|
+}
|
|
|
+
|
|
|
+.status-indicator.status-finished {
|
|
|
+ background-color: #ff4d4f;
|
|
|
+}
|
|
|
+
|
|
|
+.status-indicator.status-not-started {
|
|
|
+ background-color: #faad14;
|
|
|
+}
|
|
|
+
|
|
|
+.status-indicator.status-unknown {
|
|
|
+ background-color: #d9d9d9;
|
|
|
+}
|
|
|
+
|
|
|
+.status-text {
|
|
|
+ font-size: 14px;
|
|
|
+ height: 20px;
|
|
|
+ color: #666;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.card-content {
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.assignment-name {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #2c3e50;
|
|
|
+ margin: 0 0 8px 0;
|
|
|
+ line-height: 1.4;
|
|
|
+ height: 44.8px; /* 固定高度:16px * 1.4 * 2 = 44.8px (两行) */
|
|
|
+ overflow: hidden;
|
|
|
+ display: -webkit-box;
|
|
|
+ -webkit-line-clamp: 2;
|
|
|
+ line-clamp: 2;
|
|
|
+ -webkit-box-orient: vertical;
|
|
|
+}
|
|
|
+
|
|
|
+.assignment-type {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #1890ff;
|
|
|
+ background-color: #e6f7ff;
|
|
|
+ padding: 2px 8px;
|
|
|
+ border-radius: 4px;
|
|
|
+ display: inline-block;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.assignment-time {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #666;
|
|
|
+ margin-bottom: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.assignment-second-status {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 16px;
|
|
|
+ margin-bottom: 0px;
|
|
|
+}
|
|
|
+
|
|
|
+.assignment-second-status .status-icon-check {
|
|
|
+ margin-right: 10px;
|
|
|
+ color: #6AA67D;
|
|
|
+ font-size: 20px;
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.assignment-second-status .status-icon-calendar {
|
|
|
+ margin-right: 10px;
|
|
|
+ color: #6AA67D;
|
|
|
+ font-size: 20px;
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.assignment-second-status .status-icon-close {
|
|
|
+ margin-right: 10px;
|
|
|
+ color: #C45C4A;
|
|
|
+ font-size: 20px;
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.assignment-second-status .status-text.status-submitted {
|
|
|
+ color: #6AA67D;
|
|
|
+}
|
|
|
+
|
|
|
+.assignment-second-status .status-text.status-incomplete {
|
|
|
+ color: #C45C4A;
|
|
|
+}
|
|
|
+
|
|
|
+.card-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-btn, .result-btn {
|
|
|
+ padding: 6px 12px;
|
|
|
+ font-size: 12px;
|
|
|
+ border-radius: 6px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 4px;
|
|
|
+ width: 80px;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-btn {
|
|
|
+ background-color: #f0f0f0;
|
|
|
+ border-color: #d9d9d9;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.result-btn {
|
|
|
+ background-color: #1890ff;
|
|
|
+ border-color: #1890ff;
|
|
|
+ color: white;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-btn:hover {
|
|
|
+ background-color: #e6e6e6;
|
|
|
+}
|
|
|
+
|
|
|
+.result-btn:hover {
|
|
|
+ background-color: #40a9ff;
|
|
|
+}
|
|
|
+</style>
|