Просмотр исходного кода

基本完成第二个页面的开发工作

Jiang Pengyu 1 год назад
Родитель
Сommit
d3fb3fcd64

+ 22 - 3
src/layout/Header/Header.vue

@@ -53,7 +53,7 @@
 <script setup lang="ts">
 import {User} from "@element-plus/icons-vue";
 import router from "../../router/index.js";
-import { onMounted, ref } from "vue";
+import { onMounted, ref, watch } from "vue";
 import './index.scss';
 import { useStore } from "@/store";
 import emitter from "@/utils/emitter";
@@ -93,20 +93,39 @@ const handleCommand = (command: string) => {
 const route = useRoute();
 let activePage = ref('');
 
-onMounted(() => {
+// 更新活跃页面状态的函数
+const updateActivePage = () => {
   let path = route.path.split('/')[1];
   if (path == "profile") {
     activePage.value = null;
+    return;
   }
 
   if (route.path.split('/')[1] == "home") {
     path = route.path.split('/')[2].charAt(0).toUpperCase() + route.path.split('/')[2].slice(1);
-    if (path === 'Assignment') {
+    if (path === 'Assignment' || path === 'MyHomework') {
       activePage.value = 'MyWork';
+    } else if (path === 'MyCorrect') {
+      // 处理 myCorrect 路径,需要检查第三级路径
+      const thirdPath = route.path.split('/')[3];
+      if (thirdPath === 'course' || thirdPath === 'assignment') {
+        activePage.value = 'MyWork';
+      } else {
+        activePage.value = path;
+      }
     } else {
       activePage.value = path;
     }
   }
+};
+
+// 监听路由变化
+watch(() => route.path, () => {
+  updateActivePage();
+}, { immediate: true });
+
+onMounted(() => {
+  updateActivePage();
 });
 </script>
 

+ 4 - 4
src/views/HomeworkPage/component/HomeworkDetail.vue

@@ -23,8 +23,8 @@
         <div class="item">
           <el-link type="primary" @click="downloadFile(data.descriptionFile, `${data.assignmentName}-描述文件`)">相关文件下载</el-link>
           <div class="button-container">
-            <el-button style="margin-left: 550px" color="#597D3B" @click="handleBack">返回</el-button>
-            <el-button color="#597D3B" @click="handleStart()" :disabled="new Date() > new Date(data.endTime)">
+            <el-button style="margin-left: 550px; color: #FFFFFF;" color="#7EB5E1" @click="handleBack">返回</el-button>
+            <el-button style="color: #FFFFFF;" color="#7ADBB0" @click="handleStart()" :disabled="new Date() > new Date(data.endTime)">
               开始{{ data.type }}
             </el-button>
           </div>
@@ -131,8 +131,8 @@ const fetchData = () => {
 }
 
 const handleBack = () => {
-   // 跳转到目标页面
-   router.go(-1)
+   // 跳转到我的作业页面
+   router.push('/home/myHomework')
 }
 
 onMounted(() => {

+ 630 - 122
src/views/HomeworkPage/index.vue

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