Forráskód Böngészése

完成了教师端我的批改页面的初步开发

Jiang Pengyu 1 éve
szülő
commit
944976c54b
1 módosított fájl, 1163 hozzáadás és 138 törlés
  1. 1163 138
      src/views/CorrectPage/CoursePage.vue

+ 1163 - 138
src/views/CorrectPage/CoursePage.vue

@@ -4,170 +4,596 @@
   Created Date: 2024-7-25
 -->
 <template>
-  <el-card class="course-card-contain" shadow="never">
-    <div class="title">
-      <span>课程列表</span>
+  <div class="course-page">
+    <!-- 左侧菜单栏 -->
+    <div class="left-sidebar">
+      <!-- EAI平台装饰栏 -->
+      <div class="platform-header">
+        <div class="platform-name">EAI专业英语平台</div>
+      </div>
+      
+      <!-- 搜索框 -->
+      <div class="search-section">
+        <div class="search-input-container" @click="openSearchDialog">
+          <el-icon class="search-icon"><Search /></el-icon>
+          <input type="text" placeholder="搜索" class="search-input" readonly />
+        </div>
+      </div>
+      
+      <!-- 菜单列表 -->
+      <div class="menu-section">
+        <div class="menu-item" v-for="course in courseList" :key="course.id">
+          <div class="course-header" @click="toggleCourse(course.id)">
+            <el-icon class="expand-icon" :class="{ 'expanded': course.expanded }">
+              <ArrowDown v-if="course.expanded" />
+              <ArrowRight v-else />
+            </el-icon>
+            <el-icon class="course-icon"><Document /></el-icon>
+            <span class="course-name">{{ course.name }}</span>
+          </div>
+          
+          <!-- 作业子菜单 -->
+          <div class="assignment-list" v-if="course.expanded">
+            <div 
+              class="assignment-item" 
+              v-for="assignment in course.assignments" 
+              :key="assignment.id"
+              :class="{ 'active': assignment.active }"
+              @click="selectAssignment(assignment.id)"
+            >
+              <el-icon class="assignment-icon" :class="{ 'active-icon': assignment.active }">
+                <Document />
+              </el-icon>
+              <span class="assignment-name">{{ assignment.name }}</span>
+            </div>
+          </div>
+        </div>
+      </div>
     </div>
-
-    <el-button :icon="Refresh" circle @click="doRefresh"></el-button>
-    <el-input v-model="courseName" placeholder="请输入课程名称" clearable class="search-input"/>
-    <el-button color="#597D3B" @click="handleSearch">
-      <el-icon style="margin-right: 3px"><Search/></el-icon>
-      查询
-    </el-button>
-
-    <el-table :data="pageInfo.records" style="width: 100%; max-height: 70vh" height="100%" :row-style="{height: '30px'}" show-overflow-tooltip>
-      <template #empty>
-        暂无课程
-      </template>
-      <el-table-column type="index"/>
-      <el-table-column prop="courseName" label="课程名称" width="280"/>
-      <el-table-column prop="description" label="描述" width="420"/>
-      <el-table-column prop="endTime" label="截止时间" sortable/>
-<!--      <el-table-column prop="endTime" label="状态" sortable/>-->
-      <el-table-column label="操作">
-        <template #default="scope">
-          <el-button @click="handleCorrect(scope.row.courseId, scope.row.courseName)" style="margin-right: 0; margin-left: 0;padding-left: 10px; padding-right: 10px" color="#597D3B">
-            <el-icon style="margin-right: 3px" ><ZoomIn/></el-icon>
-            批改作业
-          </el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-
-    <el-pagination
-        small
-        style="font-size: 16px;margin-top: 10px;margin-left: 450px"
-        :page-sizes="[5, 10, 15]"
-        @current-change="handleCurrentChange"
-        @size-change="handleSizeChange"
-        :current-page="queryInfo.pageNow"
-        :page-size="queryInfo.pageSize"
-        layout="total, sizes, prev, pager, next, jumper"
-        :total="pageInfo.total">
-    </el-pagination>
-
-  </el-card>
-
+    
+    <!-- 右侧内容区域 -->
+    <div class="right-content">
+      <!-- 当没有选中作业时显示空白状态 -->
+      <div v-if="!selectedAssignment" class="empty-state">
+        <div class="empty-content">
+          <el-icon class="empty-icon"><Document /></el-icon>
+          <div class="empty-text">请选择一个作业开始批改</div>
+        </div>
+      </div>
+      
+      <!-- 当选中作业时显示内容 -->
+      <div v-else class="assignment-content">
+        <!-- 右上角数据看板按钮 -->
+        <div class="top-actions">
+          <el-button type="primary" class="dashboard-button">数据看板</el-button>
+        </div>
+        
+        <!-- 统计卡片区域 -->
+        <div class="stats-container">
+          <div class="stats-card">
+            <div class="stats-icon user-icon">
+              <el-icon><User /></el-icon>
+            </div>
+            <div class="stats-content">
+              <div class="stats-label">作业总人数</div>
+              <div class="stats-value">32</div>
+            </div>
+          </div>
+          
+          <div class="stats-card">
+            <div class="stats-icon completed-icon">
+              <el-icon><CircleCheck /></el-icon>
+            </div>
+            <div class="stats-content">
+              <div class="stats-label">已批改人数</div>
+              <div class="stats-value">10</div>
+            </div>
+          </div>
+          
+          <div class="stats-card">
+            <div class="stats-icon pending-icon">
+              <el-icon><Document /></el-icon>
+            </div>
+            <div class="stats-content">
+              <div class="stats-label">已提交未批改人数</div>
+              <div class="stats-value">12</div>
+            </div>
+          </div>
+          
+          <div class="stats-card">
+            <div class="stats-icon not-submitted-icon">
+              <el-icon><WarningFilled /></el-icon>
+            </div>
+            <div class="stats-content">
+              <div class="stats-label">未提交人数</div>
+              <div class="stats-value">10</div>
+            </div>
+          </div>
+        </div>
+        
+        <div class="assignment-body">
+          <!-- 课程作业标题 -->
+          <div class="assignment-title-section">
+            <h3 class="assignment-full-title">{{ selectedAssignment.courseName }}:{{ selectedAssignment.name }}</h3>
+          </div>
+          
+          <!-- 搜索筛选栏 -->
+          <div class="filter-section">
+            <div class="filter-controls">
+              <el-icon class="reset-icon" @click="resetFilters"><Refresh /></el-icon>
+              <div class="search-input-wrapper">
+                <input 
+                  type="text" 
+                  placeholder="请输入内容" 
+                  class="filter-search-input" 
+                  v-model="filterQuery"
+                />
+              </div>
+              <el-select v-model="statusFilter" placeholder="状态" class="filter-select">
+                <el-option label="全部" value=""></el-option>
+                <el-option label="未提交" value="未提交"></el-option>
+                <el-option label="已提交未批改" value="已提交未批改"></el-option>
+                <el-option label="已批改" value="已批改"></el-option>
+              </el-select>
+              <el-select v-model="classFilter" placeholder="班级" class="filter-select">
+                <el-option label="全部" value=""></el-option>
+                <el-option label="软工一班" value="软工一班"></el-option>
+                <el-option label="软工二班" value="软工二班"></el-option>
+                <el-option label="计科一班" value="计科一班"></el-option>
+                <el-option label="计科二班" value="计科二班"></el-option>
+                <el-option label="信息与计算科学(强基计划)" value="信息与计算科学(强基计划)"></el-option>
+              </el-select>
+              <el-button type="primary" class="search-button">搜索</el-button>
+            </div>
+          </div>
+          
+          <!-- 学生作业表格 -->
+          <div class="table-section">
+            <el-table :data="filteredStudentList" class="student-table" stripe>
+              <el-table-column prop="status" label="状态" width="290" align="left">
+                <template #default="scope">
+                  <span :class="getStatusClass(scope.row.status)" class="status-badge">
+                    {{ scope.row.status }}
+                  </span>
+                </template>
+              </el-table-column>
+              <el-table-column prop="name" label="学生姓名" width="290"></el-table-column>
+              <el-table-column prop="className" label="所属班级" width="290"></el-table-column>
+              <el-table-column prop="score" label="得分" width="290">
+                <template #header>
+                  <div class="score-header" @click="toggleSort">
+                    <span>得分</span>
+                    <el-icon class="sort-icon" :class="getSortIconClass()">
+                      <Sort />
+                    </el-icon>
+                  </div>
+                </template>
+                <template #default="scope">
+                  <span :class="getScoreClass(scope.row)" class="score-badge">
+                    {{ getScoreDisplay(scope.row) }}
+                  </span>
+                </template>
+              </el-table-column>
+              <el-table-column label="操作" width="200">
+                <template #default="scope">
+                  <el-button 
+                    type="primary" 
+                    size="small" 
+                    class="action-button"
+                    @click="handleCorrect(scope.row)"
+                  >
+                    <el-icon><View /></el-icon>
+                    批改
+                  </el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+          
+          <div class="example-pagination-block">
+              <el-pagination
+                v-model:current-page="currentPage"
+                :page-size="pageSize"
+                layout="total, prev, pager, next"
+                :total="total"
+                @current-change="handleCurrentChange"
+              />
+          </div>
+        </div>
+      </div>
+    </div>
+    
+    <!-- 搜索弹窗 -->
+    <el-dialog
+      v-model="searchDialogVisible"
+      title="搜索课程和作业"
+      width="50%"
+      :before-close="handleCloseSearchDialog"
+      class="search-dialog"
+    >
+      <div class="search-dialog-container">
+        <!-- 搜索框部分 -->
+        <div class="dialog-search-section">
+          <div class="dialog-search-input-container">
+            <el-icon class="dialog-search-icon"><Search /></el-icon>
+            <input 
+              type="text" 
+              placeholder="输入课程或作业名称..." 
+              class="dialog-search-input" 
+              v-model="searchQuery"
+              @input="performSearch"
+              ref="dialogSearchInput"
+            />
+          </div>
+        </div>
+        
+        <!-- 搜索结果部分 -->
+        <div class="search-results-section">
+          <div v-if="searchResults.length === 0" class="no-results">
+            <span>{{ searchQuery ? '没有找到相关结果' : '请输入搜索内容' }}</span>
+          </div>
+          <div v-else class="search-results-list">
+            <div 
+              v-for="result in searchResults" 
+              :key="result.id" 
+              class="search-result-item"
+              @click="handleSearchResultClick(result)"
+            >
+              <el-icon class="result-icon" v-if="result.type === 'course'">
+                <Document />
+              </el-icon>
+              <el-icon class="result-icon assignment-result-icon" v-else>
+                <Document />
+              </el-icon>
+              <div class="result-content">
+                <div class="result-title">{{ result.name }}</div>
+                <div class="result-path" v-if="result.type === 'assignment'">
+                  课程: {{ result.courseName }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </el-dialog>
+  </div>
 </template>
 
 <script lang="ts" setup>
   import useApis from "@/apis";
   import {useStore} from "@/store";
-  import {inject, onMounted, reactive, ref} from "vue";
-  import type {CourseVO} from "@/types/vo";
-  import {Refresh, Search, ZoomIn} from "@element-plus/icons-vue";
-  import router from "@/router";
-  import type {CourseDTO} from "@/types/dto";
+  import {inject, ref, reactive, computed} from "vue";
+  import {Refresh, Search, Document, ArrowDown, ArrowRight, User, CircleCheck, WarningFilled, View, Sort} from "@element-plus/icons-vue";
   import "./CoursePage.scss"
-  import type {CourseQuery} from "@/types/query";
-  import {useFormatDate} from "@/hooks/useFormatDate";
 
   const apis = useApis()
   const store = useStore()
   const doRefresh:Function = inject("reload")
-  const {formatDate} = useFormatDate()
-
-  const queryInfo = reactive({
-    pageNow: 1,
-    pageSize: 10,
-  })
-
-  let pageInfo = reactive<{
-    records: CourseVO[],
-    current: number,// 当前页码
-    size: number, // 分页大小
-    pages: number, // 总页数
-    total: number
-  }>({
-    records: null,
-    current: null,
-    size: null,
-    pages: null,
-    total: null,
-  })
-
-  const query = reactive<CourseQuery>({
-    courseId:null,
-    teacherId:store.user.id,
-    studentId:null,
-    courseName:null,
-    semester:null,
-    teacherPid:Number(store.user.pid)
-  })
 
   let courseName = ref('')
+  const selectedAssignment = ref(null)
+  
+  // 假数据 - 课程和作业列表
+  const courseList = reactive([
+    {
+      id: 1,
+      name: '课程1',
+      expanded: true,
+      assignments: [
+        { id: 1, name: '作业1', active: false },
+        { id: 2, name: '作业2', active: false },
+        { id: 3, name: '作业3', active: false }
+      ]
+    },
+    {
+      id: 2,
+      name: '课程2',
+      expanded: false,
+      assignments: [
+        { id: 4, name: '作业1', active: false },
+        { id: 5, name: '作业2', active: false }
+      ]
+    },
+    {
+      id: 3,
+      name: '课程3',
+      expanded: false,
+      assignments: [
+        { id: 6, name: '作业1', active: false },
+        { id: 7, name: '作业2', active: false },
+        { id: 8, name: '作业3', active: false }
+      ]
+    },
+    {
+      id: 4,
+      name: '课程4',
+      expanded: false,
+      assignments: [
+        { id: 9, name: '作业1', active: false }
+      ]
+    }
+  ])
+  
   const handleSearch = () => {
-    Object.assign(query, {
-      courseId:null,
-      teacherId:store.user.id,
-      studentId:null,
-      courseName:courseName.value,
-      semester:null,
-    })
-    fetchData(query)
+    // TODO: 实现搜索功能
   }
-
-  /*
-  路由跳转到作业界面
-   */
-  const handleCorrect = (courseId:number, courseName:string) => {
-    router.replace({
-      path:`/home/myCorrect/assignment`,
-      query: {
-        courseId: courseId,
-      }
+  
+  // 切换课程展开/收起
+  const toggleCourse = (courseId: number) => {
+    const course = courseList.find(c => c.id === courseId)
+    if (course) {
+      course.expanded = !course.expanded
+    }
+  }
+  
+  // 选择作业
+  const selectAssignment = (assignmentId: number) => {
+    // 清除所有作业的active状态
+    courseList.forEach(course => {
+      course.assignments.forEach(assignment => {
+        assignment.active = false
+      })
     })
-    .then(() => {
-      window.location.reload() // 强制刷新页面
+    
+    // 设置选中的作业为active
+    courseList.forEach(course => {
+      const assignment = course.assignments.find(a => a.id === assignmentId)
+      if (assignment) {
+        assignment.active = true
+        // 设置选中的作业信息
+        selectedAssignment.value = {
+          id: assignment.id,
+          name: assignment.name,
+          courseName: course.name
+        }
+      }
     })
   }
+  
+  // 搜索弹窗相关逻辑
+  const searchDialogVisible = ref(false)
+  const searchQuery = ref('')
+  const searchResults = ref([])
+  const dialogSearchInput = ref(null)
+  
+  // 筛选相关逻辑
+  const filterQuery = ref('')
+  const statusFilter = ref('')
+  const classFilter = ref('')
+  
+  // 排序相关逻辑
+  const sortOrder = ref(0) // 0: 原始顺序, 1: 高到低, 2: 低到高
+  
+  // 学生数据模拟
+  const studentList = reactive([
+    { id: 1, name: 'student0', className: '软工一班', status: '未提交', score: null },
+    { id: 2, name: 'student1', className: '软工二班', status: '已提交未批改', score: null },
+    { id: 3, name: 'student2', className: '计科一班', status: '已批改', score: 58 },
+    { id: 4, name: 'student3', className: '计科二班', status: '未提交', score: null },
+    { id: 5, name: 'student4', className: '信息与计算科学(强基计划)', status: '已提交未批改', score: null },
+    { id: 6, name: 'student5', className: '软工一班', status: '已批改', score: 77 },
+    { id: 7, name: 'student6', className: '软工二班', status: '已批改', score: 72 },
+    { id: 8, name: 'student7', className: '计科一班', status: '已批改', score: 89 },
+    { id: 9, name: 'student8', className: '计科二班', status: '已批改', score: 93 },
+    { id: 10, name: 'student9', className: '信息与计算科学(强基计划)', status: '已批改', score: 100 },
+    { id: 11, name: 'student10', className: '信息与计算科学(强基计划)', status: '未提交', score: null },
+    { id: 12, name: 'student11', className: '信息与计算科学(强基计划)', status: '未提交', score: null },
+    { id: 13, name: 'student12', className: '信息与计算科学(强基计划)', status: '已提交未批改', score: null }
+  ])
+  
+  // 当前页码
+  const currentPage = ref(1)
+  // 每页显示条数
+  const pageSize = 10
 
-  const fetchData = (query: CourseQuery) => {
-    apis.getAllCourse(query, queryInfo.pageNow, queryInfo.pageSize)
-        .then((res: any) => {
-          let data = res.data.data
-          Object.assign(pageInfo, {...data})
-          processData()
-        })
-        .catch((err: any) => {
-          console.error(err);
-        })
-        .finally(() => {
-        });
-  }
+  // 计算筛选后的学生列表(包含分页)
+  const filteredStudentList = computed(() => {
+    let filtered = [...studentList]
+    
+    // 筛选逻辑
+    if (filterQuery.value) {
+      filtered = filtered.filter(student => 
+        student.name.toLowerCase().includes(filterQuery.value.toLowerCase())
+      )
+    }
+    
+    if (statusFilter.value) {
+      filtered = filtered.filter(student => student.status === statusFilter.value)
+    }
+    
+    if (classFilter.value) {
+      filtered = filtered.filter(student => student.className === classFilter.value)
+    }
+    
+    // 排序逻辑
+    if (sortOrder.value === 1) {
+      // 高到低排序
+      filtered.sort((a, b) => {
+        const scoreA = getScoreForSort(a)
+        const scoreB = getScoreForSort(b)
+        return scoreB - scoreA
+      })
+    } else if (sortOrder.value === 2) {
+      // 低到高排序
+      filtered.sort((a, b) => {
+        const scoreA = getScoreForSort(a)
+        const scoreB = getScoreForSort(b)
+        return scoreA - scoreB
+      })
+    }
+    // sortOrder.value === 0 时保持原始顺序
+
+    // 计算总页数
+    totalPages.value = Math.ceil(filtered.length / pageSize)
+    
+    // 分页逻辑
+    const startIndex = (currentPage.value - 1) * pageSize
+    const endIndex = startIndex + pageSize
+    return filtered.slice(startIndex, endIndex)
+  })
+
+  // 总页数
+  const totalPages = ref(1)
 
-  const processData = () => {
-    for(let i = 0; i < pageInfo.records.length; i++){
-      pageInfo.records[i].endTime = formatDate(pageInfo.records[i].endTime)
+  // 总条目数
+  const total = computed(() => {
+    let filtered = [...studentList]
+    if (filterQuery.value) {
+      filtered = filtered.filter(student => 
+        student.name.toLowerCase().includes(filterQuery.value.toLowerCase())
+      )
     }
+    if (statusFilter.value) {
+      filtered = filtered.filter(student => student.status === statusFilter.value)
+    }
+    if (classFilter.value) {
+      filtered = filtered.filter(student => student.className === classFilter.value)
+    }
+    return filtered.length
+  })
+  
+  // 重置筛选条件
+  const resetFilters = () => {
+    filterQuery.value = ''
+    statusFilter.value = ''
+    classFilter.value = ''
+    sortOrder.value = 0
+    currentPage.value = 1 // 重置页码
   }
 
-  const handleCurrentChange =(index:number)=>{
-    queryInfo.pageNow=index;
-    fetchData(query);
+  // 处理页码改变
+  const handleCurrentChange = (val: number) => {
+    currentPage.value = val
   }
-  const handleSizeChange = (pageSize: number) => {
-    queryInfo.pageSize = pageSize
-    fetchData(query)
+  
+  // 获取用于排序的分数值
+  const getScoreForSort = (student) => {
+    if (student.status === '已批改' && student.score !== null) {
+      return student.score
+    } else if (student.status === '已提交未批改') {
+      return -1 // 未批改排在未提交前面
+    } else {
+      return -2 // 未提交排在最后
+    }
   }
+  
+  // 切换排序状态
+  const toggleSort = () => {
+    sortOrder.value = (sortOrder.value + 1) % 3
+  }
+  
+  // 获取排序图标样式
+  const getSortIconClass = () => {
+    return {
+      'sort-asc': sortOrder.value === 2,
+      'sort-desc': sortOrder.value === 1,
+      'sort-default': sortOrder.value === 0
+    }
+  }
+  
+  // 获取状态样式类
+  const getStatusClass = (status) => {
+    return `status-${status.replace(/[^a-zA-Z0-9]/g, '')}`
+  }
+  
+  // 获取分数样式类
+  const getScoreClass = (row) => {
+    if (row.status === '未提交') return 'score-not-submitted'
+    if (row.status === '已提交未批改') return 'score-not-graded'
+    if (row.score !== null) {
+      return row.score < 60 ? 'score-low' : 'score-high'
+    }
+    return ''
+  }
+  
+  // 获取分数显示内容
+  const getScoreDisplay = (row) => {
+    if (row.status === '未提交') return '未提交'
+    if (row.status === '已提交未批改') return '未批改'
+    return row.score !== null ? row.score : '未批改'
+  }
+  
+  // 处理批改操作
+  const handleCorrect = (row) => {
+    console.log('批改学生作业:', row)
+  }
+  
 
-  onMounted(() => {
-    fetchData(query)
-  })
-
-  // TODO:状态选择
-  let state = ref(null)
-  const stateOptions = [
-    {
-      value: 0,
-      label: "已结课"
-    },
-    {
-      value: 1,
-      label: "未结课"
-    },
-  ]
+  
+  const openSearchDialog = () => {
+    searchDialogVisible.value = true
+    // 延迟聚焦,确保对话框渲染完成
+    setTimeout(() => {
+      if (dialogSearchInput.value) {
+        dialogSearchInput.value.focus()
+      }
+    }, 100)
+  }
+  
+  const handleCloseSearchDialog = (done) => {
+    searchQuery.value = ''
+    searchResults.value = []
+    done()
+  }
+  
+  const performSearch = () => {
+    const query = searchQuery.value.trim().toLowerCase()
+    if (!query) {
+      searchResults.value = []
+      return
+    }
+    
+    const results = []
+    
+    // 搜索课程和作业
+    courseList.forEach(course => {
+      // 搜索课程
+      if (course.name.toLowerCase().includes(query)) {
+        results.push({
+          id: course.id,
+          name: course.name,
+          type: 'course'
+        })
+      }
+      
+      // 搜索作业
+      course.assignments.forEach(assignment => {
+        if (assignment.name.toLowerCase().includes(query)) {
+          results.push({
+            id: assignment.id,
+            name: assignment.name,
+            courseName: course.name,
+            type: 'assignment'
+          })
+        }
+      })
+    })
+    
+    searchResults.value = results
+  }
+  
+  const handleSearchResultClick = (result) => {
+    if (result.type === 'course') {
+      // 展开对应的课程
+      const course = courseList.find(c => c.id === result.id)
+      if (course) {
+        course.expanded = true
+      }
+    } else {
+      // 选中对应的作业并展开对应课程
+      courseList.forEach(course => {
+        const assignment = course.assignments.find(a => a.id === result.id)
+        if (assignment) {
+          course.expanded = true
+        }
+      })
+      selectAssignment(result.id)
+    }
+    // 关闭弹窗
+    searchDialogVisible.value = false
+    searchQuery.value = ''
+    searchResults.value = []
+  }
 </script>
 
 <script lang="ts">
@@ -175,3 +601,602 @@ export default {
   name: "CoursePage"
 }
 </script>
+<style scoped>
+.course-page {
+  display: flex;
+  height: 95vh;
+  background-color: #f5f5f5;
+  font-family: "Noto Sans SC", sans-serif;
+}
+
+.left-sidebar {
+  width: 320px;
+  background-color: white;
+  border-right: 1px solid #e8e8e8;
+  display: flex;
+  flex-direction: column;
+  height: 100vh;
+}
+
+.platform-header {
+  height: 60px;
+  background-color: #F0F2F5;
+  border-bottom: 1px solid #e8e8e8;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 0 20px;
+}
+
+.platform-name {
+  color: #606266;
+  font-size: 24px;
+  font-weight: 400;
+  font-family: "Noto Sans SC", sans-serif;
+}
+
+.search-section {
+  padding: 16px 20px;
+  border-bottom: 1px solid #e8e8e8;
+  background-color: #F0F2F5;
+}
+
+.search-input-container {
+  position: relative;
+  display: flex;
+  align-items: center;
+  font-family: "Noto Sans SC", sans-serif;
+}
+
+.search-icon {
+  position: absolute;
+  left: 12px;
+  color: #999;
+  font-size: 16px;
+}
+
+.search-input {
+  width: 100%;
+  height: 36px;
+  padding: 0 12px 0 36px;
+  border: 1px solid #d9d9d9;
+  border-radius: 6px;
+  font-size: 14px;
+  outline: none;
+  background-color: #FFFFFF;
+  font-family: "Noto Sans SC", sans-serif;
+}
+
+.search-input:focus {
+  border-color: #1890ff;
+  background-color: white;
+}
+
+.menu-section {
+  flex: 1;
+  overflow-y: auto;
+  padding: 0;
+  height: calc(100vh - 120px);
+}
+
+.menu-item {
+  margin-bottom: 0px;
+}
+
+.course-header {
+  display: flex;
+  align-items: center;
+  padding: 12px 20px;
+  cursor: pointer;
+  transition: background-color 0.2s;
+  font-family: "Noto Sans SC", sans-serif;
+  background-color: #F0F2F5;
+  color: #606266;
+}
+
+.course-header:hover {
+  background-color: #FFFFFF;
+}
+
+.expand-icon {
+  font-size: 12px;
+  color: #666;
+  margin-right: 8px;
+  transition: transform 0.2s;
+}
+
+.expand-icon.expanded {
+  transform: rotate(0deg);
+}
+
+.course-icon {
+  font-size: 16px;
+  color: #666;
+  margin-right: 8px;
+}
+
+.course-name {
+  font-size: 14px;
+  color: #606266;
+  font-weight: 500;
+  font-family: "Noto Sans SC", sans-serif;
+}
+
+.assignment-list {
+  background-color: #fafafa;
+}
+
+.assignment-item {
+  display: flex;
+  align-items: center;
+  padding: 8px 20px 8px 48px;
+  cursor: pointer;
+  transition: background-color 0.2s;
+  font-family: "Noto Sans SC", sans-serif;
+  background-color: #F0F2F5;
+  color: #606266;
+}
+
+.assignment-item:hover {
+  background-color: #FFFFFF;
+}
+
+.assignment-item.active {
+  background-color: rgba(112, 187, 219, 0.50);
+  border-radius: 10px;
+  opacity: 0.8;
+}
+
+.assignment-icon {
+  font-size: 14px;
+  color: #606266;
+  margin-right: 8px;
+}
+
+.assignment-icon.active-icon {
+  color: #435FE9;
+}
+
+.assignment-name {
+  font-size: 13px;
+  font-weight: 500;
+  color: #606266;
+  font-family: "Noto Sans SC", sans-serif;
+}
+
+.assignment-item.active .assignment-name {
+  color: #435FE9;
+  font-weight: 500;
+}
+
+.right-content {
+  flex: 1;
+  background-color: white;
+  padding: 20px;
+  height: 100vh;
+}
+
+/* 空白状态样式 */
+.empty-state {
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.empty-content {
+  text-align: center;
+  color: #999;
+}
+
+.empty-icon {
+  font-size: 64px;
+  color: #d9d9d9;
+  margin-bottom: 16px;
+}
+
+.empty-text {
+  font-size: 16px;
+  font-family: "Noto Sans SC", sans-serif;
+}
+
+  /* 作业内容样式 */
+  .assignment-content {
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+  }
+  
+  /* 右上角按钮样式 */
+  .top-actions {
+    display: flex;
+    justify-content: flex-end;
+    margin-bottom: 10px;
+  }
+  
+  .dashboard-button {
+    background-color: #4A90C4;
+    border-color: #4A90C4;
+    border-radius: 4px;
+    padding: 6px 12px;
+    font-size: 12px;
+    font-family: "Noto Sans SC", sans-serif;
+  }
+  
+  /* 统计卡片区域样式 */
+  .stats-container {
+    display: flex;
+    justify-content: space-around;
+    align-items: center;
+    margin-bottom: 5px;
+    padding: 0;
+    gap: 16px;
+  }
+  
+  .stats-card {
+    display: flex;
+    align-items: center;
+    background: white;
+    border-radius: 8px;
+    padding: 16px;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    min-width: 180px;
+    max-width: 220px;
+  }
+  
+  .stats-icon {
+    width: 48px;
+    height: 48px;
+    border-radius: 8px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-right: 12px;
+    font-size: 24px;
+    color: white;
+  }
+  
+  .user-icon {
+    background-color: #70BBD9;
+  }
+  
+  .completed-icon {
+    background-color: #90D7B4;
+  }
+  
+  .pending-icon {
+    background-color: #B8B8B8;
+  }
+  
+  .not-submitted-icon {
+    background-color: #F5A658;
+  }
+  
+  .stats-content {
+    flex: 1;
+  }
+  
+  .stats-label {
+    font-size: 14px;
+    color: #666;
+    margin-bottom: 4px;
+    font-family: "Noto Sans SC", sans-serif;
+  }
+  
+  .stats-value {
+    font-size: 24px;
+    font-weight: 600;
+    color: #333;
+    font-family: "Noto Sans SC", sans-serif;
+  }
+  
+
+  
+  .assignment-body {
+    flex: 1;
+    padding: 20px 0;
+  }
+  
+  /* 作业标题区域 */
+  .assignment-title-section {
+    margin-bottom: 20px;
+  }
+  
+  .assignment-full-title {
+    font-size: 18px;
+    font-weight: 600;
+    color: #333;
+    margin: 0;
+    font-family: "Noto Sans SC", sans-serif;
+  }
+  
+  /* 筛选区域样式 */
+  .filter-section {
+    margin-bottom: 20px;
+  }
+  
+  .filter-controls {
+    display: flex;
+    align-items: center;
+    gap: 12px;
+  }
+  
+  .reset-icon {
+    font-size: 18px;
+    color: #666;
+    cursor: pointer;
+    padding: 8px;
+    border-radius: 4px;
+    transition: background-color 0.2s;
+  }
+  
+  .reset-icon:hover {
+    background-color: #f5f5f5;
+  }
+  
+  .search-input-wrapper {
+    flex: 1;
+    max-width: 300px;
+  }
+  
+  .filter-search-input {
+    width: 90%;
+    height: 32px;
+    padding: 0 12px;
+    border: 1px solid #d9d9d9;
+    border-radius: 4px;
+    font-size: 14px;
+    outline: none;
+    font-family: "Noto Sans SC", sans-serif;
+  }
+  
+  .filter-search-input:focus {
+    border-color: #4A90C4;
+  }
+  
+  .filter-select {
+    width: 120px;
+  }
+  
+  .search-button {
+    background-color: #4A90C4;
+    border-color: #4A90C4;
+    font-family: "Noto Sans SC", sans-serif;
+  }
+  
+  /* 表格区域样式 */
+  .table-section {
+    margin-bottom: 20px;
+  }
+  
+  .student-table {
+    width: 100%;
+    font-family: "Noto Sans SC", sans-serif;
+  }
+  
+  /* 状态标签样式 */
+  .status-badge {
+    padding: 4px 8px;
+    border-radius: 4px;
+    font-size: 12px;
+    font-weight: 500;
+    display: inline-block;
+    width: 100%;
+    text-align: left;
+    font-family: "Noto Sans SC", sans-serif;
+  }
+  
+  /* 状态列单元格左对齐 */
+  .student-table .el-table__cell {
+    text-align: left !important;
+  }
+  
+  .student-table .el-table__header-wrapper .el-table__cell {
+    text-align: left !important;
+  }
+  
+  .status-未提交 {
+    background-color: #F4A261;
+    color: white;
+  }
+  
+  .status-已提交未批改 {
+    background-color: #D9D9D9;
+    color: #666;
+  }
+  
+  .status-已批改 {
+    background-color: #7ADBB0;
+    color: white;
+  }
+  
+  /* 分数标签样式 */
+  .score-badge {
+    padding: 4px 8px;
+    border-radius: 4px;
+    font-size: 12px;
+    font-weight: 500;
+    display: inline-block;
+    min-width: 60px;
+    text-align: center;
+    font-family: "Noto Sans SC", sans-serif;
+  }
+  
+  .score-not-submitted {
+    background-color: #F4A261;
+    color: white;
+  }
+  
+  .score-not-graded {
+    background-color: #D9D9D9;
+    color: #666;
+  }
+  
+  .score-low {
+    background-color: #F0C05A;
+    color: white;
+  }
+  
+  .score-high {
+    background-color: #7ADBB0;
+    color: white;
+  }
+  
+  /* 操作按钮样式 */
+  .action-button {
+    background-color: #4A90C4;
+    border-color: #4A90C4;
+    padding: 4px 8px;
+    font-size: 12px;
+    font-family: "Noto Sans SC", sans-serif;
+  }
+  
+  /* 排序头部样式 */
+  .score-header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    cursor: pointer;
+    user-select: none;
+    font-family: "Noto Sans SC", sans-serif;
+  }
+  
+  .sort-icon {
+    font-size: 14px;
+    color: #999;
+    transition: color 0.2s;
+  }
+  
+  .sort-icon.sort-asc {
+    color: #4A90C4;
+    transform: rotate(0deg);
+  }
+  
+  .sort-icon.sort-desc {
+    color: #4A90C4;
+    transform: rotate(180deg);
+  }
+  
+  .sort-icon.sort-default {
+    color: #999;
+  }
+  
+  .score-header:hover .sort-icon {
+    color: #4A90C4;
+  }
+  
+
+
+/* 搜索弹窗样式 */
+.search-dialog-container {
+  display: flex;
+  flex-direction: column;
+  height: 60vh;
+}
+
+.dialog-search-section {
+  padding-bottom: 16px;
+  border-bottom: 1px solid #e8e8e8;
+  margin-bottom: 16px;
+}
+
+.dialog-search-input-container {
+  position: relative;
+  display: flex;
+  align-items: center;
+  font-family: "Noto Sans SC", sans-serif;
+}
+
+.dialog-search-icon {
+  position: absolute;
+  left: 12px;
+  color: #999;
+  font-size: 18px;
+}
+
+.dialog-search-input {
+  width: 100%;
+  height: 40px;
+  padding: 0 12px 0 40px;
+  border: 1px solid #d9d9d9;
+  border-radius: 6px;
+  font-size: 16px;
+  outline: none;
+  background-color: #FFFFFF;
+  font-family: "Noto Sans SC", sans-serif;
+}
+
+.dialog-search-input:focus {
+  border-color: #1890ff;
+}
+
+.search-results-section {
+  flex: 1;
+  overflow-y: auto;
+}
+
+.no-results {
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: #999;
+  font-size: 14px;
+  font-family: "Noto Sans SC", sans-serif;
+}
+
+.search-results-list {
+  height: 100%;
+  overflow-y: auto;
+}
+
+.search-result-item {
+  display: flex;
+  align-items: center;
+  padding: 12px 16px;
+  cursor: pointer;
+  border-bottom: 1px solid #e8e8e8;
+  transition: background-color 0.2s;
+  font-family: "Noto Sans SC", sans-serif;
+}
+
+.search-result-item:hover {
+  background-color: #F0F2F5;
+}
+
+.result-icon {
+  font-size: 18px;
+  color: #606266;
+  margin-right: 12px;
+}
+
+.assignment-result-icon {
+  font-size: 16px;
+  margin-left: 16px;
+}
+
+.result-content {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+}
+
+.result-title {
+  font-size: 14px;
+  font-weight: 500;
+  color: #606266;
+  font-family: "Noto Sans SC", sans-serif;
+}
+
+.result-path {
+  font-size: 12px;
+  color: #999;
+  margin-top: 4px;
+  font-family: "Noto Sans SC", sans-serif;
+}
+
+.example-pagination-block {
+  margin-top: 10px;
+}
+</style>
+