瀏覽代碼

教师端假数据完成

stupig-zcx 1 年之前
父節點
當前提交
59af067752

+ 1 - 1
package-lock.json

@@ -2152,7 +2152,7 @@
     },
     "node_modules/echarts": {
       "version": "5.6.0",
-      "resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.6.0.tgz",
+      "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz",
       "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==",
       "dependencies": {
         "tslib": "2.3.0",

+ 1 - 0
src/assets/chevron-right.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#b8b8b8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>

+ 1 - 0
src/assets/search.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#606266" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>

+ 23 - 1
src/router/index.ts

@@ -137,6 +137,11 @@ const router = createRouter({
           name: 'myCorrectWithAssignmentId',
           component: () => import("@/views/CorrectPage/CorrectAssignmentPage.vue")
         },
+        {
+          path: 'studentDetail',
+          name: 'studentDetail',
+          component: () => import("@/views/ClassPage/StudentDetail.vue")
+        },
         {
           path: 'courseClass/:courseId',
           name: 'courseClass',
@@ -145,7 +150,24 @@ const router = createRouter({
         {
           path: 'classDetail',
           name: 'classDetail',
-          component: () => import("@/views/ClassPage/ClassDetail.vue")
+          component: () => import("@/views/ClassPage/ClassDetail.vue"),
+          children:[
+            {
+              path: "",
+              name:"classDetail",
+              redirect: "/home/classDetail/student"
+            },
+            {
+              path: 'student',
+              name: 'classStudent',
+              component: () => import("@/views/ClassPage/ClassStudent.vue")
+            },
+            {
+              path: 'homework',
+              name: 'classHomework',
+              component: () => import("@/views/ClassPage/ClassHomework.vue")
+            },
+          ]
         },
       ]
     },

+ 1 - 0
src/types/vo.ts

@@ -154,4 +154,5 @@ export interface ClassStudentVO {
     stuName: string;
     stateCode: number;
     stateDesc: string;
+    studentId: number;
 }

+ 93 - 78
src/views/ClassPage/ClassDetail.vue

@@ -2,31 +2,53 @@
     <div class="course-class" v-show="DataLoading">
         <classHeader>{{Coursedata.courseName}}:{{ Classdata.className }}</classHeader>
         <div class="content">
-            <classTable></classTable>
+            <router-view></router-view>
+            <!-- <classTable></classTable> -->
+        </div>
+        <!-- <classDetailFooter :classId=classId :courseId=courseId :flag=true></classDetailFooter> -->
+        <div class="class-footer">
+            <button 
+                :class="{'active':choose,'unactive':!choose,'inhover':(!choose && hoverid===1)}"
+                :disabled="choose"
+                @click="{choose = true;$router.replace(`/home/classDetail/student?classId=${classId}&courseId=${courseId}`);}"
+                @mouseenter="hoverid = 1"
+                @mouseleave="hoverid = 0"
+            >
+            班级学生管理
+            </button>
+            <button 
+                :class="{'active':!choose,'unactive':choose,'inhover':(choose && hoverid===2)}"
+                :disabled="!choose"
+                @click="{choose = false;$router.replace(`/home/classDetail/homework?classId=${classId}&courseId=${courseId}`);}"
+                @mouseenter="hoverid = 2"
+                @mouseleave="hoverid = 0"
+            >
+            班级作业管理
+            </button>
         </div>
-        <classDetailFooter></classDetailFooter>
     </div>
 </template>
 
 <script setup lang="ts">
 import {onMounted, reactive, ref, computed} from 'vue';
-import { useRoute } from 'vue-router';
+import { useRoute, useRouter } from 'vue-router';
 import classHeader from './components/classHeader.vue';
-import classTable from './components/classTable.vue';
-import classDetailFooter from './components/classDetailFooter.vue';
-import type {CourseDetailVO, ClassVO, ClassStudentVO} from "@/types/vo";
+import type {CourseDetailVO, ClassVO} from "@/types/vo";
+import { useStore } from "@/store"
 import useApis from "@/apis";
 
+const store = useStore()
 const route = useRoute()
+const router = useRouter()
 const apis = useApis()
 const classId = +route.query.classId;
 const courseId = +route.query.courseId;
 
+const choose = ref(true)
+let hoverid = ref(0) // 0 没有 1 学生 2 作业 
+
 const CourseDataLoading = ref(false)
 const ClassDataLoading = ref(false)
-const StudentsDataLoading = ref(false)
-
-const Studentsdata = reactive<ClassStudentVO[]>([])
 
 const Coursedata = reactive<CourseDetailVO>({
   courseId: null,
@@ -50,6 +72,11 @@ const Classdata = reactive<ClassVO>({
   teacherId: null,
 })
 
+const identify = () => {
+    if(store.user.role === "STUDENT"){
+        router.push('/404')
+    }
+}
 const getClass = () => {
     console.log("classId:",classId);
     Classdata.classId = classId
@@ -73,66 +100,24 @@ const getCourse = () => {
         console.error(err);
       })
 }
-const getStudents = () => {
-    console.log(classId);
-    
-    const newData = [
-    {
-        "officialNumber": 522025320092,
-        "stuName": "关谷神奇",
-        "stateCode": 0,
-        "stateDesc": "未加入班级"
-    },
-    {
-        "officialNumber": 522025312092,
-        "stuName": "唐悠悠",
-        "stateCode": 0,
-        "stateDesc": "未加入班级"
-    },
-    {
-        "officialNumber": 1231232,
-        "stuName": "曾小贤",
-        "stateCode": 0,
-        "stateDesc": "未加入班级"
-    },
-    {
-        "officialNumber": 123123123123,
-        "stuName": "陈美嘉",
-        "stateCode": 0,
-        "stateDesc": "未加入班级"
-    },
-    {
-        "officialNumber": 123132132,
-        "stuName": "胡一菲",
-        "stateCode": 0,
-        "stateDesc": "未加入班级"
-    },
-    {
-        "officialNumber": 12312132,
-        "stuName": "张伟",
-        "stateCode": 0,
-        "stateDesc": "未加入班级"
-    },
-    {
-        "officialNumber": 12312312312,
-        "stuName": "吕子乔",
-        "stateCode": 0,
-        "stateDesc": "未加入班级"
-    }
-    ]
-    newData.forEach(item => Studentsdata.push(item))
-    StudentsDataLoading.value = true
+const setchoose = () => {
+    const currentPath = route.path
+    const parts = currentPath.split('/')
+    if(parts[parts.length-1]=="homework")
+        choose.value=false
+    else
+        choose.value=true
 }
-
 const DataLoading = computed(() => {
-  return CourseDataLoading.value && ClassDataLoading.value && StudentsDataLoading.value
+  return CourseDataLoading.value && ClassDataLoading.value
 })
 
 
 onMounted(() => {
+    identify()
+    setchoose()
     getClass()
     getCourse()
-    getStudents()
 })
 </script>
 
@@ -148,26 +133,56 @@ export default {
     height: 65vh;
     background-color: #fff;
     border-radius: 15px;
-    flex-shrink: 0;
     margin: 0 auto;
     margin-top: 4.6vh;
     border-bottom: 1px solid #70bbdb;
     padding:  7vh 5.5vw;
-}
-.content {
-    height: 50vh;
-    width: 100%;
-    /* border:1px solid; */
-    margin: 0 auto;
-    margin-bottom: 10vh;
-    display: flex;
-    align-items: center;
-    flex-direction: row;
-    flex-wrap: wrap;
-    justify-content: start;
-    padding: 10px;
-    gap: 3.6vw;
-    overflow: auto;
-    border: 1px solid blueviolet;
+    .content {
+        height: 55vh;
+        width: 100%;
+        /* border:1px solid; */
+        margin: 0 auto;
+        display: flex;
+        align-items: center;
+        flex-direction: row;
+        flex-wrap: wrap;
+        justify-content: start;
+        padding: 10px;
+        gap: 3.6vw;
+    }
+    .class-footer {
+        width: '100%';
+        height: 7.5vh;
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        justify-content: center;
+        gap: 250px;
+        .active {
+            font-size: 24px;
+            font-weight: 600;
+            color: #fff;
+            border-radius: 50px;
+            padding: 2px 10px;
+            background-color: #70bbdb;
+            border:none;
+            border-bottom: 5px solid #4FA3C5;
+        }
+        .unactive {
+            font-size: 24px;
+            font-weight: 600;
+            color: #fff;
+            border-radius: 50px;
+            padding: 2px 10px;
+            background-color: rgb(112, 187, 219, 0.5);
+            border:none;
+            border-bottom: 5px solid #4FA3C5;
+            box-shadow: -5px 7px 7px 0 rgba(0, 0, 0, 0.25);
+        }
+        .inhover{
+            box-shadow: -10px 7px 20px #70bbdb;
+            border-bottom: 5px solid rgb(112, 187, 219, 0.5);
+        }
+    }
 }
 </style>

+ 661 - 0
src/views/ClassPage/ClassHomework.vue

@@ -0,0 +1,661 @@
+<template>
+    <div class="main">
+        <div class="search">
+            <img src="@/assets/search.svg" width="20px" height="20px"></img> 
+            <div class="searchInput">
+                <input type="text" v-model.trim="searchInput" placeholder="输入姓名或学号">
+                <div class="fix">
+                    <span>搜索</span>
+                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#b8b8b8" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
+                </div>
+            </div>
+            <div class="Myselect">
+                <select id="selectHomework" v-model="TheHomework" @change="changeHomework"> 
+                    <option value="无">选择作业</option>
+                    <option v-for="item in Homeworksdata" :value="item">{{item}}</option>
+                </select>
+                <div class="show">
+                        {{ ShowTheHomework }}
+                </div>
+            </div>
+            <div class="Myselect">
+                <select id="selectSort" v-model="TheSort" :disabled="!isTable"> 
+                    <option value="无">排序方式</option>
+                    <option v-for="item in sortMethods" :value="item">{{item}}</option>
+                </select>
+                <div class="show">
+                        {{ ShowTheSort }}
+                </div>
+            </div>
+            <div class="toggle">
+                <button class="left"
+                        :class="{'active':isTable,'unactive':!isTable}"
+                        @click="isTable=true"
+                >table</button>
+                <button class="right"
+                        :class="{'active':!isTable,'unactive':isTable}"
+                        @click="isTable=false"
+                >统计图</button>
+            </div>
+        </div>
+        <div class="content">
+            <div class="Loading" v-show="!DataLoading">Loading...</div>
+            <div class="half-table" v-show="DataLoading">
+                <classTable v-if="isTable">
+                <template #head>
+                    <tr>
+                        <th>序号</th>
+                        <th>学生姓名</th>
+                        <th>学号</th>
+                        <th>成绩</th>
+                    </tr>
+                </template>
+                <template #body>
+                    <tr v-for="(item,index) in showData.slice(0,5)" :key="index+item.officialNumber">
+                        <template v-if="item.officialNumber!==0">
+                            <td>{{ (currentPage-1)*10+index+1 }}</td>
+                            <td
+                                @click="$router.push(`/home/studentDetail?classId=${classId}&courseId=${courseId}&stuId=${item.studentId}`)"
+                                @mouseenter="hoverStuId=item.studentId"
+                                @mouseleave="hoverStuId=-1"
+                                :class="{Gethover:hoverStuId===item.studentId,Blue:true}"
+                                >{{ item.stuName }}</td>
+                            <td>{{ item.officialNumber }}</td>
+                            <td>
+                                <div class="highScore" v-if="item.score>=80"> {{ item.score }}</div>
+                                <div class="midScore" v-else-if="item.score>=60"> {{ item.score }}</div>
+                                <div class="lowScore" v-else-if="item.score>0"> {{ item.score }}</div>
+                                <div class="uncorrected" v-else-if="item.state==='未批改'"> 未批改</div>
+                                <div class="unsubmitted" v-else-if="item.state==='未提交'"> 未提交</div>             
+                            </td>
+                        </template>
+                        <template v-else>
+                            <td>&nbsp;</td>
+                            <td>&nbsp;</td>
+                            <td>&nbsp;</td>
+                            <td>&nbsp;</td>
+                        </template>
+                    </tr>
+                </template>
+                </classTable>
+                <div ref="chartRef1" class="chart" v-else></div>
+            </div>
+            <div class="half-table" v-show="DataLoading">
+                <classTable v-if="isTable">
+                <template #head>
+                    <tr>
+                        <th>序号</th>
+                        <th>学生姓名</th>
+                        <th>学号</th>
+                        <th>成绩</th>
+                    </tr>
+                </template>
+                <template #body>
+                    <tr v-for="(item,index) in showData.slice(5,10)" :key="index+item.officialNumber">
+                        <template v-if="item.officialNumber!==0">
+                            <td>{{ (currentPage-1)*10+index+6 }}</td>
+                            <td
+                                @click="$router.push(`/home/studentDetail?classId=${classId}&courseId=${courseId}&stuId=${item.studentId}`)"
+                                @mouseenter="hoverStuId=item.studentId"
+                                @mouseleave="hoverStuId=-1"
+                                :class="{Gethover:hoverStuId===item.studentId,Blue:true}"
+                                >{{ item.stuName }}</td>
+                            <td>{{ item.officialNumber }}</td>
+                            <td>
+                                <div class="highScore" v-if="item.score>=80"> {{ item.score }}</div>
+                                <div class="midScore" v-else-if="item.score>=60"> {{ item.score }}</div>
+                                <div class="lowScore" v-else-if="item.score>0"> {{ item.score }}</div>
+                                <div class="uncorrected" v-else-if="item.state==='未批改'"> 未批改</div>
+                                <div class="unsubmitted" v-else-if="item.state==='未提交'"> 未提交</div>                
+                            </td>
+                        </template>
+                        <template v-else>
+                            <td>&nbsp;</td>
+                            <td>&nbsp;</td>
+                            <td>&nbsp;</td>
+                            <td>&nbsp;</td>
+                        </template>
+                    </tr>
+                </template>
+                </classTable>
+                <div ref="chartRef2" class="chart chart2" v-else></div>
+            </div>
+        </div>
+        <div class="pages" v-show="DataLoading && isTable">
+            <el-pagination
+                v-model:current-page="currentPage"
+                :page-size="10"
+                :pager-count="5"
+                layout="total, prev, pager, next"
+                :total="searchData.length"
+            />
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+import classTable from './components/classTable.vue';
+import {onMounted, ref, computed, watch, nextTick } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import { useStore } from "@/store"
+import * as echarts from 'echarts'
+import useApis from "@/apis";
+
+const store = useStore()
+const route = useRoute()
+const router = useRouter()
+const classId = +route.query.classId;
+const courseId = +route.query.courseId;
+
+const currentPage = ref(1)
+const searchInput = ref("")
+const TheHomework = ref("无")
+const ShowTheHomework = ref("第一次作业")
+const TheSort = ref("无")
+const ShowTheSort = ref("默认")
+const hoverStuId = ref(-1)
+
+const StudentsDataLoading = ref(false)
+const HomeworkDataLoading = ref(false)
+const isTable = ref(true)
+
+const Studentsdata = ref([])
+const Homeworksdata = ref([])
+
+
+const sortMethods = ["默认","成绩从低到高","成绩从高到低","未批改优先","未提交优先"]
+
+
+const chartRef1 = ref(null)
+const chartRef2 = ref(null)
+const setChart = () => {
+
+    const chartInstance = echarts.init(chartRef1.value)
+    const chartInstance2 = echarts.init(chartRef2.value)
+    let excellentnum=0, goodnum=0 , failnum=0 , uncorrectednum=0 , unsubmittednum=0
+    Studentsdata.value.forEach((item)=>{
+        if(item.state === "未提交"){
+            unsubmittednum++
+        }
+        else if(item.state === "未批改"){
+            uncorrectednum++
+        }
+        else if(item.score<60){
+            failnum++
+        }
+        else if(item.score<80){
+            goodnum++
+        }
+        else{
+            excellentnum++
+        }
+    })
+    
+    const option = {
+        title: {
+        text: ShowTheHomework.value+'详情',
+        // subtext: '纯属虚构',
+        left: 'center'
+        },
+        tooltip: {
+        trigger: 'item',
+        formatter: '{b}: {d}%'
+        },
+        legend: {
+        orient: 'vertical',
+        left: 'left'
+        },
+        series: [
+        {
+            name: '作业组成',
+            type: 'pie',
+            radius: '50%',
+            data: [
+                { value: excellentnum, name: '优秀', itemStyle: { color: '#7ADBB0' } },
+                { value: goodnum, name: '良好', itemStyle: { color: '#F0C05A' } },
+                { value: failnum, name: '不及格', itemStyle: { color: '#F4A261' } },
+                { value: unsubmittednum, name: '未提交', itemStyle: { color: '#C45C4A' } },
+                { value: uncorrectednum, name: '未批改', itemStyle: { color: '#D9D9D9' } }
+            ],
+            emphasis: {
+            itemStyle: {
+                shadowBlur: 10,
+                shadowOffsetX: 0,
+                shadowColor: 'rgba(0, 0, 0, 0.5)'
+            }
+            }
+        }
+        ]
+    }
+    const option2 = {
+        title: {
+        text: ShowTheHomework.value+'详情',
+        // subtext: '纯属虚构',
+        left: 'center'
+        },
+        tooltip: {
+        trigger: 'axis',
+        axisPointer: {
+            type: 'shadow' // 悬停时显示阴影效果
+        },
+        formatter: '{b}: {c}'
+        },
+        xAxis: {
+            type: 'category',
+            data: ['优秀', '良好', '不及格', '未提交', '未批改']
+        },
+        yAxis: {
+            type: 'value',
+            name: '人数'
+        },
+        series: [
+        {
+            name: '作业组成',
+            type: 'bar',
+            radius: '50%',
+            data: [
+                { value: excellentnum, name: '优秀', itemStyle: { color: '#7ADBB0' } },
+                { value: goodnum, name: '良好', itemStyle: { color: '#F0C05A' } },
+                { value: failnum, name: '不及格', itemStyle: { color: '#F4A261' } },
+                { value: unsubmittednum, name: '未提交', itemStyle: { color: '#C45C4A' } },
+                { value: uncorrectednum, name: '未批改', itemStyle: { color: '#D9D9D9' } }
+            ],
+            barWidth: '40%',
+            emphasis: {
+            itemStyle: {
+                shadowBlur: 10,
+                shadowOffsetX: 0,
+                shadowColor: 'rgba(0, 0, 0, 0.5)'
+            }
+            }
+        }
+        ]
+    }
+
+    chartInstance.setOption(option)
+    chartInstance2.setOption(option2)
+}
+
+
+const identify = () => {
+    if(store.user.role === "STUDENT"){
+        router.push('/404')
+    }
+}
+const getStudents = () => {
+    StudentsDataLoading.value=false
+    setTimeout(()=>{
+    console.log("classID:",classId);
+    console.log("作业:",ShowTheHomework);
+    const newData = [
+    {
+        "officialNumber": 522025320092,
+        "stuName": "关谷神奇",
+        "state": "已提交",
+        "score": 88,
+        "studentId": 1
+
+    },
+    {
+        "officialNumber": 522025312092,
+        "stuName": "唐悠悠",
+        "state": "已提交",
+        "score": 92,
+        "studentId": 2
+    },
+    {
+        "officialNumber": 1231232,
+        "stuName": "曾小贤",
+        "state": "未提交",
+        "score": 0,
+        "studentId": 3
+    },
+    {
+        "officialNumber": 123123123123,
+        "stuName": "陈美嘉",
+        "state": "已提交",
+        "score": 59,
+        "studentId": 4
+    },
+    {
+        "officialNumber": 123132435132,
+        "stuName": "胡一菲",
+        "state": "已提交",
+        "score": 100,
+        "studentId": 5
+    },
+    {
+        "officialNumber": 123442,
+        "stuName": "张伟",
+        "state": "未批改",
+        "score": 0,
+        "studentId": 6
+    },
+    {
+        "officialNumber": 1231231662,
+        "stuName": "吕子乔",
+        "state": "已提交",
+        "score": 57,
+        "studentId": 7
+    },
+    {
+        "officialNumber": 12399312312,
+        "stuName": "展播",
+        "state": "已提交",
+        "score": 93,
+        "studentId": 8
+    },
+    {
+        "officialNumber": 123993112,
+        "stuName": "婉瑜",
+        "state": "已提交",
+        "score": 79,
+        "studentId": 9
+    },
+    {
+        "officialNumber": 22321452,
+        "stuName": "秦羽墨",
+        "state": "已提交",
+        "score": 64,
+        "studentId": 10
+    },
+    {
+        "officialNumber": 223214522,
+        "stuName": "吕小布",
+        "state": "已提交",
+        "score": 58,
+        "studentId": 11
+    }
+    ]
+    Studentsdata.value = newData
+    StudentsDataLoading.value = true
+},1000)
+}
+const getHomeworks = () => {
+    console.log(courseId,classId);
+    const t = ["第一次作业","第二次作业","第三次作业","期中作业","第五次作业","第六次作业","期末考试"] 
+    t.forEach(item => Homeworksdata.value.push(item))
+    HomeworkDataLoading.value = true
+}
+const changeHomework = () => {
+    console.log(ShowTheHomework.value)
+    getStudents()
+}
+
+const searchData = computed(()=>{
+    if(searchInput.value===""){
+        return Studentsdata.value
+    }
+    else{
+        return Studentsdata.value.filter(student => {
+          return (
+            student.stuName.includes(searchInput.value) ||
+            student.officialNumber.toString().includes(searchInput.value)
+          )
+        })
+    }
+})
+
+
+const showData = computed(() => {
+    const showdata = searchData.value.slice((currentPage.value-1)*10,currentPage.value*10)
+    while(showdata.length<10){
+        showdata.push(    {
+        "officialNumber": 0,
+        "stuName": "",
+        "stateCode": -1,
+        "stateDesc": "",
+        "studentId": -1
+        })
+    }
+    return showdata
+})
+
+const DataLoading = computed(() => {
+  return StudentsDataLoading.value && HomeworkDataLoading.value
+})
+
+watch(TheHomework, () => {
+    nextTick(() => {
+        // console.log(ShowTheHomework.value,TheHomework.value);
+        if(TheHomework.value != "无"){
+            ShowTheHomework.value = TheHomework.value
+            TheHomework.value = "无"
+        }
+        // console.log(ShowTheHomework.value,TheHomework.value);
+    });
+});
+watch(TheSort, () => {
+    nextTick(() => {
+        // console.log(ShowTheSort.value,TheSort.value);
+        if(TheSort.value != "无"){
+            ShowTheSort.value = TheSort.value
+            TheSort.value = "无"
+        }
+        // console.log(ShowTheSort.value,TheSort.value);
+    });
+});
+watch(ShowTheSort,(newData) =>{
+    if(newData==="未批改优先"){
+        Studentsdata.value = Studentsdata.value.sort((a,b)=>{
+            return a.state === "未批改" ? -1 : b.state === "未批改" ? 1 : 0;
+        })
+        console.log("未批改已排序");
+        console.log(Studentsdata.value);
+        
+    }
+    else if(newData==="未提交优先"){
+        Studentsdata.value = Studentsdata.value.sort((a,b)=>{
+            return a.state === "未提交" ? -1 : b.state === "未提交" ? 1 : 0;
+        })
+    }
+    else if(newData==="成绩从低到高"){
+        Studentsdata.value = Studentsdata.value.sort((a,b)=>{
+            if (a.state === "已提交" && b.state !== "已提交") return -1;
+            if (a.state !== "已提交" && b.state === "已提交") return 1;
+            return a.score - b.score;
+        })
+    }
+    else if(newData==="成绩从高到低"){
+        Studentsdata.value = Studentsdata.value.sort((a,b)=>{
+            if (a.state === "已提交" && b.state !== "已提交") return -1;
+            if (a.state !== "已提交" && b.state === "已提交") return 1;
+            return b.score - a.score;
+        })
+    }
+})
+watch(isTable, (newVal) => {
+    if(newVal === false){
+        nextTick(()=>{
+            console.log('chartRef1 dom:', chartRef1.value)
+            setChart()
+        })
+    }
+})
+onMounted(() => {
+    console.log(store.user.role)
+    // console.log('chartRef dom:', chartRef.value)
+    getStudents()
+    getHomeworks()
+    // setChart()
+})
+</script>
+
+<style scoped>
+.main{
+    display: flex;
+    flex-direction: column;
+    width: 100%;
+    height: 100%;
+    .search{
+    height: 50px;
+    width: 100%;
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-start;
+    align-items: center;
+    margin-top: 20px;
+    .searchInput{
+        height: 100%;
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        margin-left: 20px;
+        input{
+            border: 2px solid #e4e7ed;
+            border-right: none;
+            height: 27px;
+            border-radius: 7px 0 0 7px;
+            padding: 0 10px;
+            color: #606266;
+        }
+        input::placeholder {
+            color:#c2c4c9;
+        }
+        .fix{
+            background-color: #f5f7fa;
+            padding: 2px 10px;
+            color:#b8b8b8;
+            font-weight: 600;
+            border: 2px solid #e4e7ed;
+            border-radius: 0 7px 7px 0;
+        }
+    }
+    .Myselect{
+        margin-left: 15px;
+        display: flex;
+        flex-direction: row;
+        select {
+            border: none;
+            background-color: #4a90c4;
+            font-size: 14px;
+            font-weight: 600;
+            color:#fff;
+            padding: 3px 10px;
+            padding-right: 0;
+            border-radius: 5px 0 0 5px;
+            max-width: 100px;
+        }
+        select:focus {
+            outline: none;
+            border: none;
+            background-color: #FFF;
+            border: 3px solid #4a90c4;
+            border-right: 0;
+            color:#4a90c4;
+        }
+        .show{
+            width: fit-content;
+            color: #4a90c4;
+            border: 3px solid #4a90c4;
+            font-weight: 600;
+            padding-left: 6px;
+            padding-right: 5px;
+            border-radius: 0 5px 5px 0;
+        }
+    }
+    .toggle{
+        margin-left: 20px;
+        .left{
+            border: 3px solid #4A90C4;
+            border-radius: 20px 0 0 20px;
+            border-right: 0;
+            padding: 2px 7px;
+            font-weight: 700;
+            cursor: pointer;
+        }
+        .right{
+            border: 3px solid #4A90C4;
+            border-radius: 0 20px 20px 0;
+            padding: 2px 7px;
+            font-weight: 700;
+            cursor: pointer;
+        }
+        .unactive{
+            color: #70BBDB;
+            background-color: #fff;
+        }
+        .active{
+            color: #fff;
+            background-color:#4A90C4;
+        }
+    }
+}
+.content{
+    width: 100%;
+    flex-grow: 1;
+    display: flex;
+    flex-direction: row;
+    gap: 40px;
+    .half-table{
+        width: 50%;
+        height: 100%;
+        .highScore{
+            padding: 2px 10px;
+            background-color: #7ADBB0;   
+            color: #fff;
+            border-radius: 20px;
+            width: fit-content;
+            margin: auto;
+        }
+        .midScore{
+            padding: 2px 10px;
+            background-color: #F0C05A;   
+            color: #fff;
+            border-radius: 20px;
+            width: fit-content;
+            margin: auto;
+        }
+        .lowScore{
+            padding: 2px 10px;
+            background-color: #F4A261;   
+            color: #fff;
+            border-radius: 20px;
+            width: fit-content;
+            margin: auto;
+        }
+        .unsubmitted{
+            padding: 2px 10px;
+            background-color: #C45C4A;   
+            color: #fff;
+            border-radius: 20px;
+            width: fit-content;
+            margin: auto;
+        }
+        .uncorrected{
+            padding: 2px 10px;
+            background-color: #D9D9D9;   
+            color: #fff;
+            border-radius: 20px;
+            width: fit-content;
+            margin: auto;
+        }
+        .chart{
+            margin-top: 70px;
+            margin-left: 30px;
+            height: 300px;
+            width: 100%;
+        }
+        .chart2{
+            margin-left: 0;
+            margin-right: 30px;
+            padding-bottom: 50px;
+        }
+    }
+    .Loading{
+        font-size: 40px;
+        color: #70bbdb;
+        font-weight: 700;
+        height: 100%;
+        width: 100%;
+        text-align: center;
+        align-content: center;
+    }
+}
+.pages{
+    height: 30px;
+    margin-top: 10px;
+}
+}
+</style>

+ 479 - 0
src/views/ClassPage/ClassStudent.vue

@@ -0,0 +1,479 @@
+<template>
+    <div class="main">
+        <div class="search">
+            <img src="@/assets/search.svg" width="20px" height="20px"></img> 
+            <div class="searchInput">
+                <input type="text" v-model.trim="searchInput" placeholder="输入姓名或学号">
+                <div class="fix">
+                    <span>搜索</span>
+                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#b8b8b8" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
+                </div>
+            </div>
+
+            <button @click="visible_add=true"> 添加学生 </button>
+        </div>
+        <div class="content">
+            <div class="Loading" v-show="!DataLoading">Loading...</div>
+            <classTable v-show="DataLoading">
+                <template #head>
+                    <tr>
+                        <th>序号</th>
+                        <th>学生姓名</th>
+                        <th>学号</th>
+                        <th>是否加入班级</th>
+                        <th></th>
+                    </tr>
+                </template>
+                <template #body>
+                    <tr v-for="(item,index) in showData" :key="index+item.officialNumber">
+                        <template v-if="item.officialNumber!==0">
+                            <td>{{ (currentPage-1)*5+index+1 }}</td>
+                            <td  
+                                @click="$router.push(`/home/studentDetail?classId=${classId}&courseId=${courseId}&stuId=${item.studentId}`)"
+                                @mouseenter="hoverStuId=item.studentId"
+                                @mouseleave="hoverStuId=-1"
+                                :class="{Gethover:hoverStuId===item.studentId,Blue:true}"
+                                >{{ item.stuName }}</td>
+                            <td>{{ item.officialNumber }}</td>
+                            <td>
+                                <div class="added" v-if="item.stateCode===1">已加入 </div>
+                                <div class="notadd" v-else> 未加入</div>                        
+                            </td>
+                            <td><button class="Del" @click="handleDelete(item.officialNumber)">DEL</button></td>
+                        </template>
+                        <template v-else>
+                            <td>&nbsp;</td>
+                            <td>&nbsp;</td>
+                            <td>&nbsp;</td>
+                            <td>&nbsp;</td>
+                            <td>&nbsp;</td>
+                        </template>
+                    </tr>
+                </template>
+            </classTable>
+        </div>
+        <div class="pages">
+            <el-pagination
+                v-model:current-page="currentPage"
+                :page-size="5"
+                :pager-count="5"
+                layout="total, prev, pager, next"
+                :total="searchData.length"
+            />
+        </div>
+    </div>
+
+    <div v-if="visible_del" class="modal-mask" @click.self="isloading || (visible_del=false)" >
+        <div class="modal-container">
+            <div class="modal-header">
+                <h2>{{isloading?"删除中...":"你确定要删除 "+deleteName+":"+deleteId+" 吗?"}}</h2>
+            </div>
+            <div class="modal-footer">
+                <button class="yes-button" @click.stop="DeleteStudent" :disabled="isloading">确定</button>
+                <button class="no-button" @click.stop="visible_del=false;" :disabled="isloading">取消</button>
+            </div>
+        </div>
+    </div>
+
+    <div v-if="visible_add" class="modal-mask" @click.self="isloading_add || (visible_add=false)" >
+        <div class="modal-container">
+            <div class="add1" v-show="!isloading_add">
+                <h2>学生姓名:</h2> <input type="text" v-model.trim="addStudentName" ></input>
+            </div>
+            <div class="add1" v-show="!isloading_add">
+                <h2>学生学号:</h2> <input type="text" v-model.trim="addOfficalNumber" ></input>
+            </div>
+            <div class="add1" v-show="isloading_add" 
+            :style="{'height': '66%', 'margin-left':'210px'}">
+                <h2>上传中...</h2>
+            </div>
+            <div class="modal-footer add2">
+                <button class="yes-button" @click.stop="AddStudent" :disabled="isloading_add">确定</button>
+                <button class="no-button" @click.stop="visible_add=false" :disabled="isloading_add">取消</button>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+import classTable from './components/classTable.vue';
+import {onMounted, reactive, ref, computed} from 'vue';
+import { useRoute } from 'vue-router';
+import type {ClassStudentVO} from "@/types/vo";
+import useApis from "@/apis";
+import { log } from 'node:console';
+import { color } from 'echarts';
+
+const route = useRoute()
+const classId = +route.query.classId;
+const courseId = +route.query.courseId;
+
+const currentPage = ref(1)
+const searchInput = ref("")
+const visible_add = ref(false)
+const visible_del = ref(false)
+const isloading = ref(false)
+const isloading_add = ref(false)
+const addStudentName = ref("")
+const addOfficalNumber = ref("")
+const deleteId = ref(-1)
+const deleteName = ref("")
+const hoverStuId = ref(-1)
+
+const StudentsDataLoading = ref(false)
+
+const Studentsdata = reactive<ClassStudentVO[]>([])
+
+const handleDelete = (sid) => {
+    visible_del.value = true
+    deleteId.value = sid
+    deleteName.value = Studentsdata.find((item)=>{
+        return item.officialNumber === sid
+    }).stuName
+}
+const DeleteStudent = () =>{
+    isloading.value = true
+    console.log(deleteId.value);
+    // 删除学生
+    setTimeout(()=>{
+        visible_del.value=false
+        isloading.value = false
+    }, 1000)
+}
+const AddStudent = () => {
+    isloading_add.value = true
+    console.log(addStudentName.value)
+    console.log(+addOfficalNumber.value)
+    console.log(classId);
+    setTimeout(()=>{
+        isloading_add.value = false
+        visible_add.value=false
+        addStudentName.value = ""
+        addOfficalNumber.value = "" 
+    }, 1000)
+}
+
+const getStudents = () => {
+    setTimeout(()=>{
+    console.log(classId);
+    
+    const newData = [
+    {
+        "officialNumber": 522025320092,
+        "stuName": "关谷神奇",
+        "stateCode": 0,
+        "stateDesc": "未加入班级",
+        "studentId": 1
+    },
+    {
+        "officialNumber": 522025312092,
+        "stuName": "唐悠悠",
+        "stateCode": 1,
+        "stateDesc": "加入班级",
+        "studentId": 2
+    },
+    {
+        "officialNumber": 1231232,
+        "stuName": "曾小贤",
+        "stateCode": 1,
+        "stateDesc": "加入班级",
+        "studentId": 3
+    },
+    {
+        "officialNumber": 123123123123,
+        "stuName": "陈美嘉",
+        "stateCode": 0,
+        "stateDesc": "未加入班级",
+        "studentId": 4
+    },
+    {
+        "officialNumber": 123132435132,
+        "stuName": "胡一菲",
+        "stateCode": 1,
+        "stateDesc": "加入班级",
+        "studentId": 5
+    },
+    {
+        "officialNumber": 123442,
+        "stuName": "张伟",
+        "stateCode": 1,
+        "stateDesc": "1加入班级",
+        "studentId": 6
+    },
+    {
+        "officialNumber": 1231231662,
+        "stuName": "吕子乔",
+        "stateCode": 0,
+        "stateDesc": "未加入班级",
+        "studentId": 7
+    },
+    {
+        "officialNumber": 12399312312,
+        "stuName": "展播",
+        "stateCode": 1,
+        "stateDesc": "加入班级",
+        "studentId": 8
+    },
+    {
+        "officialNumber": 123993112,
+        "stuName": "婉瑜",
+        "stateCode": 1,
+        "stateDesc": "加入班级",
+        "studentId": 9
+    },
+    {
+        "officialNumber": 22321452,
+        "stuName": "秦羽墨",
+        "stateCode": 1,
+        "stateDesc": "加入班级",
+        "studentId": 10
+    },
+    {
+        "officialNumber": 223214522,
+        "stuName": "吕小布",
+        "stateCode": 0,
+        "stateDesc": "未加入班级",
+        "studentId": 11
+    }
+    ]
+    newData.forEach(item => Studentsdata.push(item))
+    StudentsDataLoading.value = true
+    },1000)
+}
+
+const searchData = computed(()=>{
+    if(searchInput.value===""){
+        return Studentsdata
+    }
+    else{
+        return Studentsdata.filter(student => {
+          return (
+            student.stuName.includes(searchInput.value) ||
+            student.officialNumber.toString().includes(searchInput.value)
+          )
+        })
+    }
+})
+
+
+const showData = computed(() => {
+    const showdata = searchData.value.slice((currentPage.value-1)*5,currentPage.value*5)
+    while(showdata.length<5){
+        showdata.push(    {
+        "officialNumber": 0,
+        "stuName": "",
+        "stateCode": -1,
+        "stateDesc": "",
+        "studentId": -1
+        })
+    }
+    return showdata
+})
+const DataLoading = computed(() => {
+  return StudentsDataLoading.value
+})
+
+onMounted(() => {
+    getStudents()
+})
+</script>
+
+<style scoped>
+.main{
+    display: flex;
+    flex-direction: column;
+    width: 100%;
+    height: 100%;
+}
+.search{
+    height: 50px;
+    width: 100%;
+    margin-top: 20px;
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-start;
+    align-items: center;
+    .searchInput{
+        height: 100%;
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        margin-left: 20px;
+        input{
+            border: 2px solid #e4e7ed;
+            border-right: none;
+            height: 27px;
+            border-radius: 7px 0 0 7px;
+            padding: 0 10px;
+            color: #606266;
+        }
+        input::placeholder {
+            color:#c2c4c9;
+        }
+        .fix{
+            background-color: #f5f7fa;
+            padding: 2px 10px;
+            color:#b8b8b8;
+            font-weight: 600;
+            border: 2px solid #e4e7ed;
+            border-radius: 0 7px 7px 0;
+        }
+        
+    }
+    button{
+        background-color: #4a90c4;
+        font-size: 14px;
+        font-weight: 700;
+        border: none;
+        padding: 4px 10px;
+        color: #fff;
+        margin-left: 30px;
+        border-radius: 5px;
+        cursor: pointer;
+    }
+}
+.content{
+    width: 100%;
+    flex-grow: 1;
+    .Loading{
+        font-size: 40px;
+        color: #70bbdb;
+        font-weight: 700;
+        height: 100%;
+        text-align: center;
+        align-content: center;
+    }
+}
+.Del{
+    font-size: 14px;
+    padding: 1px 12px;
+    background-color: #c45c4a;
+    color: #fff;
+    border: none;
+    border-radius: 20px;
+    cursor: pointer;
+}
+.pages{
+    height: 30px;
+    margin-top: 10px;
+}
+.added{
+    color: #fff;
+    background-color: #7adbb0;
+    width: 62px;
+    height: 20px;
+    margin: auto;
+    border-radius: 20px;
+    font-weight: 600;
+}
+.notadd{
+    color: #fff;
+    background-color: #d9d9d9;
+    width: 62px;
+    height: 20px;
+    margin: auto;
+    border-radius: 20px;
+    font-weight: 600;
+}
+
+.modal-mask {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0, 0, 0, 0.5);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    z-index: 9999;
+    .modal-container {
+        border-radius: 30px;
+        border: 7px solid #70BBDB;
+        background: #FFF;
+        box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.25);
+        width: 35vw;
+        height: 25vh;
+        display: flex;
+        flex-direction: column;
+        overflow: hidden;
+        .modal-header {
+            padding: 16px 20px;
+            height: 50%;
+            display: flex;
+            flex-direction: row;
+            justify-content: center;
+            align-items: center;
+            color:#70bbdb
+        }
+        .modal-footer {
+            padding: 12px 20px;
+            height: 50%;
+            display: flex;
+            flex-direction: row;
+            justify-content: center;
+            align-items: center;
+            gap: 50px;
+            .yes-button{
+                background-color: #c45c4a;
+                color: #fff;
+                border: 0;
+                padding: 3px 25px;
+                font-size: 22px;
+                font-weight: 600;
+                border-radius: 20px;
+                margin-right: 20px;
+            }
+            .no-button{
+                background-color: #4a90c4;
+                color: #fff;
+                border: 0;
+                padding: 3px 25px;
+                font-size: 22px;
+                font-weight: 600;
+                border-radius: 20px;
+                margin-right: 20px;
+            }
+            button{
+                cursor: pointer;
+            }
+            button:disabled{
+                background-color: #d9d9d9;
+            }
+        }
+        .add1 {
+            height: 33%;
+            display: flex;
+            flex-direction: row;
+            justify-content: start;
+            align-items: center;
+            color:#70bbdb;
+            margin-left: 80px;
+            input,select {
+                border: none;
+                border-bottom: 3px solid #70bbdb;
+                font-size: 16px;
+                font-weight: 600;
+                color:#70bbdb
+            }
+            input::placeholder {
+                color:#b2d7e7
+            }
+            input:focus,select:focus {
+                outline: none;
+                border: none;
+                outline: 5px solid #70bbdb;
+            }
+            span{
+                font-size: 16px;
+                font-weight: 600;
+                margin: 0 15px;
+            }
+        }
+        .add2 {
+            height: 33%;
+        }
+    }   
+}
+</style>

+ 11 - 2
src/views/ClassPage/CourseClass.vue

@@ -93,12 +93,15 @@
 
 <script setup lang="ts">
 import {onMounted, reactive, ref, computed } from 'vue';
-import { useRoute } from 'vue-router';
+import { useRoute, useRouter } from 'vue-router';
+import { useStore } from "@/store"
 import classHeader from './components/classHeader.vue';
 import type {CourseDetailVO, ClassVO} from "@/types/vo";
 import useApis from "@/apis";
 
 const route = useRoute()
+const store = useStore()
+const router = useRouter()
 const apis = useApis()
 const courseId = +route.params.courseId;
 
@@ -154,9 +157,14 @@ const AddClass = () =>{
         visible_add.value=false
         addClassName.value = ""
         addClassDay.value = ""
-    addClassClock.value = ""     
+        addClassClock.value = ""     
     }, 1000)
 }
+const identify = () => {
+    if(store.user.role === "STUDENT"){
+        router.push('/404')
+    }
+}
 const getClass = () => {
     console.log(courseId);
     const newData = [
@@ -213,6 +221,7 @@ const DataLoading = computed(() => {
 })
 
 onMounted(() => {
+    identify()
     getClass()
     getCourse()
 })

+ 491 - 0
src/views/ClassPage/StudentDetail.vue

@@ -0,0 +1,491 @@
+<template>
+    <div class="course-class" v-show="DataLoading">
+        <classHeader>{{Studentdata.stuName}}:{{ Studentdata.officialNumber }}</classHeader>
+        <div class="content">
+            <div class="search">
+                <img src="@/assets/search.svg" width="20px" height="20px"></img> 
+                <div class="searchInput">
+                    <input type="text" v-model.trim="searchInput" placeholder="输入姓名或学号">
+                    <div class="fix">
+                        <span>搜索</span>
+                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#b8b8b8" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
+                    </div>
+                </div>
+                <div class="Myselect">
+                    <select id="selectSort" v-model="TheSort" > 
+                        <option value="无">排序方式</option>
+                        <option v-for="item in sortMethods" :value="item">{{item}}</option>
+                    </select>
+                    <div class="show">
+                            {{ ShowTheSort }}
+                    </div>
+                </div>
+            </div>
+            <div class="table">
+                <div class="table-half left-half">
+                    <classTable>
+                        <template #head>
+                            <tr>
+                                <th>序号</th>
+                                <th>作业列表</th>
+                                <th>成绩</th>
+                            </tr>
+                        </template>
+                        <template #body>
+                            <tr v-for="(item,index) in showData.slice(0,5)" :key="index+item.homeworkName">
+                                <template v-if="item.state!==''">
+                                    <td>{{ (currentPage-1)*10+index+1 }}</td>
+                                    <td>{{ item.homeworkName }}</td>
+                                    <td>
+                                        <div class="highScore" v-if="item.score>=80"> {{ item.score }}</div>
+                                        <div class="midScore" v-else-if="item.score>=60"> {{ item.score }}</div>
+                                        <div class="lowScore" v-else-if="item.score>0"> {{ item.score }}</div>
+                                        <div class="uncorrected" v-else-if="item.state==='未批改'"> 未批改</div>
+                                        <div class="unsubmitted" v-else-if="item.state==='未提交'"> 未提交</div>      
+                                    </td>
+                                </template>
+                                <template v-else>
+                                    <td>&nbsp;</td>
+                                    <td>&nbsp;</td>
+                                    <td>&nbsp;</td>
+                                </template>
+                            </tr>
+                        </template>
+                    </classTable>
+                </div>
+                <div class="table-half right-half">
+                    <classTable>
+                        <template #head>
+                            <tr>
+                                <th>序号</th>
+                                <th>作业列表</th>
+                                <th>成绩</th>
+                            </tr>
+                        </template>
+                        <template #body>
+                            <tr v-for="(item,index) in showData.slice(5,10)" :key="index+item.homeworkName">
+                                <template v-if="item.state!==''">
+                                    <td>{{ (currentPage-1)*10+index+6 }}</td>
+                                    <td>{{ item.homeworkName }}</td>
+                                    <td>
+                                        <div class="highScore" v-if="item.score>=80"> {{ item.score }}</div>
+                                        <div class="midScore" v-else-if="item.score>=60"> {{ item.score }}</div>
+                                        <div class="lowScore" v-else-if="item.score>0"> {{ item.score }}</div>
+                                        <div class="uncorrected" v-else-if="item.state==='未批改'"> 未批改</div>
+                                        <div class="unsubmitted" v-else-if="item.state==='未提交'"> 未提交</div>      
+                                    </td>
+                                </template>
+                                <template v-else>
+                                    <td>&nbsp;</td>
+                                    <td>&nbsp;</td>
+                                    <td>&nbsp;</td>
+                                </template>
+                            </tr>
+                        </template>
+                    </classTable>
+                </div>
+            </div>
+            <div class="pages">
+                <el-pagination
+                    v-model:current-page="currentPage"
+                    :page-size="10"
+                    :pager-count="5"
+                    layout="total, prev, pager, next"
+                    :total="searchData.length"
+                />
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+import classTable from './components/classTable.vue';
+import {onMounted, reactive, ref, computed, watch, nextTick} from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import { useStore } from "@/store"
+import classHeader from './components/classHeader.vue';
+import type {CourseDetailVO, ClassVO, ClassStudentVO} from "@/types/vo";
+import useApis from "@/apis";
+
+const route = useRoute()
+const store = useStore()
+const router = useRouter()
+const apis = useApis()
+const classId = +route.query.classId
+const courseId = +route.query.courseId
+const studentId = +route.query.stuId
+
+const currentPage = ref(1)
+const searchInput = ref("")
+const TheSort = ref("无")
+const ShowTheSort = ref("默认")
+
+const StudentdataLoading = ref(false)
+// const CourseDataLoading = ref(false)
+// const ClassDataLoading = ref(false)
+
+// const Coursedata = reactive<CourseDetailVO>({
+//   courseId: null,
+//   courseName: '',
+//   teacherIds: [],
+//   teacherNames: [],
+//   courseImages: [''],
+//   targetGrade: '',
+//   startTime: '',
+//   endTime: '',
+//   createTime: '',
+//   description: '',
+// })
+
+// const Classdata = reactive<ClassVO>({
+//   classId: null,
+//   className: '',
+//   courseId: null,
+//   stuNumber: null,
+//   classTime: '',
+//   teacherId: null,
+// })
+const sortMethods = ["默认","成绩从低到高","成绩从高到低","未批改优先","未提交优先"]
+const Studentdata = ref({
+    "officialNumber": 522025312092,
+    "stuName": "张伟",
+    "studentId": studentId,
+    "homeworkData": [
+        {
+            "homeworkName":"第一次作业",
+            "state": "已提交",
+            "score": 88
+        },
+        {
+            "homeworkName":"第二次作业",
+            "state": "已提交",
+            "score": 91
+        },
+        {
+            "homeworkName":"第三次作业",
+            "state": "已提交",
+            "score": 94
+        },
+        {
+            "homeworkName":"期中作业",
+            "state": "已提交",
+            "score": 59
+        },
+        {
+            "homeworkName":"第五次作业",
+            "state": "已提交",
+            "score": 79
+        },
+        {
+            "homeworkName":"第六次作业",
+            "state": "未提交",
+            "score": 0
+        },
+        {
+            "homeworkName":"期末考试",
+            "state": "未批改",
+            "score": 0
+        }
+    ]
+})
+
+const identify = () => {
+    if(store.user.role === "STUDENT"){
+        router.push('/404')
+    }
+}
+const getStudent = () => {
+    StudentdataLoading.value = false
+    console.log(courseId)
+    console.log(studentId)
+    StudentdataLoading.value = true
+}
+// const getClass = () => {
+//     console.log("classId:",classId)
+//     Classdata.classId = classId
+//     Classdata.courseId = courseId
+//     Classdata.className = "读写1班"
+//     Classdata.stuNumber = 30
+//     Classdata.classTime = "Mon 10:10"
+//     Classdata.teacherId = 4
+
+//     ClassDataLoading.value = true
+// }
+
+// const getCourse = () => {
+//   // 获取课程信息
+//   apis.getCourseByCourseId(courseId)
+//       .then((res: any) => {
+//         let data = res.data.data.records[0]
+//         Object.assign(Coursedata, {...data})
+//         CourseDataLoading.value = true
+//       })
+//       .catch((err: any) => {
+//         console.error(err);
+//       })
+// }
+
+const DataLoading = computed(() => {
+//   return CourseDataLoading.value && ClassDataLoading.value
+    return StudentdataLoading
+})
+const searchData = computed(()=>{
+    if(searchInput.value===""){
+        return Studentdata.value.homeworkData
+    }
+    else{
+        return Studentdata.value.homeworkData.filter(student => {
+          return (
+            student.homeworkName.includes(searchInput.value)
+          )
+        })
+    }
+})
+const showData = computed(() => {
+    const showdata = searchData.value.slice((currentPage.value-1)*10,currentPage.value*10)
+    while(showdata.length<10){
+        showdata.push(    {
+        "homeworkName": "",
+        "state": "",
+        "score": 0
+        })
+    }
+    return showdata
+})
+watch(TheSort, () => {
+    nextTick(() => {
+        // console.log(ShowTheSort.value,TheSort.value);
+        if(TheSort.value != "无"){
+            ShowTheSort.value = TheSort.value
+            TheSort.value = "无"
+        }
+        // console.log(ShowTheSort.value,TheSort.value);
+    });
+});
+watch(ShowTheSort,(newData) =>{
+    if(newData==="未批改优先"){
+        Studentdata.value.homeworkData = Studentdata.value.homeworkData.sort((a,b)=>{
+            return a.state === "未批改" ? -1 : b.state === "未批改" ? 1 : 0;
+        })
+    }
+    else if(newData==="未提交优先"){
+        Studentdata.value.homeworkData = Studentdata.value.homeworkData.sort((a,b)=>{
+            return a.state === "未提交" ? -1 : b.state === "未提交" ? 1 : 0;
+        })
+    }
+    else if(newData==="成绩从低到高"){
+        Studentdata.value.homeworkData = Studentdata.value.homeworkData.sort((a,b)=>{
+            if (a.state === "已提交" && b.state !== "已提交") return -1;
+            if (a.state !== "已提交" && b.state === "已提交") return 1;
+            return a.score - b.score;
+        })
+    }
+    else if(newData==="成绩从高到低"){
+        Studentdata.value.homeworkData = Studentdata.value.homeworkData.sort((a,b)=>{
+            if (a.state === "已提交" && b.state !== "已提交") return -1;
+            if (a.state !== "已提交" && b.state === "已提交") return 1;
+            return b.score - a.score;
+        })
+    }
+})
+
+onMounted(() => {
+    identify()
+    // getClass()
+    // getCourse()
+    getStudent()
+})
+</script>
+
+<script lang="ts">
+export default {
+  name: "ClassDetail"
+}
+</script>
+
+<style scoped>
+.course-class {
+    width: 66vw;
+    height: 65vh;
+    background-color: #fff;
+    border-radius: 15px;
+    margin: 0 auto;
+    margin-top: 4.6vh;
+    border-bottom: 1px solid #70bbdb;
+    padding:  7vh 5.5vw;
+    .content {
+        height: 55vh;
+        width: 100%;
+        /* border:1px solid; */
+        margin: 0 auto;
+        display: flex;
+        flex-direction: column;
+        justify-content: start;
+        padding: 10px;
+        .search{
+            height: 50px;
+            width: 100%;
+            display: flex;
+            flex-direction: row;
+            justify-content: flex-start;
+            align-items: center;
+            margin-top: 20px;
+            .searchInput{
+                height: 100%;
+                display: flex;
+                flex-direction: row;
+                justify-content: flex-start;
+                align-items: center;
+                margin-left: 20px;
+                input{
+                    border: 2px solid #e4e7ed;
+                    border-right: none;
+                    height: 27px;
+                    border-radius: 7px 0 0 7px;
+                    padding: 0 10px;
+                    color: #606266;
+                }
+                input::placeholder {
+                    color:#c2c4c9;
+                }
+                .fix{
+                    background-color: #f5f7fa;
+                    padding: 2px 10px;
+                    color:#b8b8b8;
+                    font-weight: 600;
+                    border: 2px solid #e4e7ed;
+                    border-radius: 0 7px 7px 0;
+                }
+            }
+            .Myselect{
+                margin-left: 15px;
+                display: flex;
+                flex-direction: row;
+                select {
+                    border: none;
+                    background-color: #4a90c4;
+                    font-size: 14px;
+                    font-weight: 600;
+                    color:#fff;
+                    padding: 3px 10px;
+                    padding-right: 0;
+                    border-radius: 5px 0 0 5px;
+                    max-width: 100px;
+                }
+                select:focus {
+                    outline: none;
+                    border: none;
+                    background-color: #FFF;
+                    border: 3px solid #4a90c4;
+                    border-right: 0;
+                    color:#4a90c4;
+                }
+                .show{
+                    width: fit-content;
+                    color: #4a90c4;
+                    border: 3px solid #4a90c4;
+                    font-weight: 600;
+                    padding-left: 6px;
+                    padding-right: 5px;
+                    border-radius: 0 5px 5px 0;
+                }
+            }
+            .toggle{
+                margin-left: 20px;
+                .left{
+                    border: 3px solid #4A90C4;
+                    border-radius: 20px 0 0 20px;
+                    border-right: 0;
+                    padding: 2px 7px;
+                    font-weight: 700;
+                    cursor: pointer;
+                }
+                .right{
+                    border: 3px solid #4A90C4;
+                    border-radius: 0 20px 20px 0;
+                    padding: 2px 7px;
+                    font-weight: 700;
+                    cursor: pointer;
+                }
+                .unactive{
+                    color: #70BBDB;
+                    background-color: #fff;
+                }
+                .active{
+                    color: #fff;
+                    background-color:#4A90C4;
+                }
+            }
+        }
+        .table{
+            flex-grow: 1;
+            width: 100%;
+            display: flex;
+            flex-direction: row;
+            margin-top: 20px;
+            .table-half{
+                width: 50%;
+                height: 100%;
+                border: 5px solid #70bbdb;
+                padding: 15px;
+                padding-top: 0;
+                td{
+                    height:45px;
+                }
+                .highScore{
+                    padding: 2px 10px;
+                    background-color: #7ADBB0;   
+                    color: #fff;
+                    border-radius: 20px;
+                    width: fit-content;
+                    margin: auto;
+                }
+                .midScore{
+                    padding: 2px 10px;
+                    background-color: #F0C05A;   
+                    color: #fff;
+                    border-radius: 20px;
+                    width: fit-content;
+                    margin: auto;
+                }
+                .lowScore{
+                    padding: 2px 10px;
+                    background-color: #F4A261;   
+                    color: #fff;
+                    border-radius: 20px;
+                    width: fit-content;
+                    margin: auto;
+                }
+                .unsubmitted{
+                    padding: 2px 10px;
+                    background-color: #C45C4A;   
+                    color: #fff;
+                    border-radius: 20px;
+                    width: fit-content;
+                    margin: auto;
+                }
+                .uncorrected{
+                    padding: 2px 10px;
+                    background-color: #D9D9D9;   
+                    color: #fff;
+                    border-radius: 20px;
+                    width: fit-content;
+                    margin: auto;
+                }
+            }
+            .left-half{
+                border-right: 0;
+                border-radius: 10px 0 0 10px;
+            }
+            .right-half{
+                border-left: 5px solid #B9DDF5;
+                border-radius: 0 10px 10px 0;
+            }
+        }
+        .pages{
+            height: 30px;
+            margin-top: 40px;
+        }
+    }
+}
+</style>

+ 0 - 29
src/views/ClassPage/components/classDetailFooter.vue

@@ -1,29 +0,0 @@
-<template>
-    <div class="class-footer">
-        <div>班级学生管理</div>
-        <div>班级作业管理</div>
-    </div>
-</template>
-
-<script setup lang="ts">
-import { ArrowLeftBold } from '@element-plus/icons-vue'
-</script>
-
-<script lang="ts">
-export default {
-  name: "classDetailFooter"
-}
-</script>
-
-<style scoped>
-.class-footer {
-    width: '100%';
-    height: 10vh;
-    display: flex;
-    flex-direction: row;
-    align-items: center;
-    justify-content: center;
-    gap: 100px;
-}
-
-</style>

+ 1 - 1
src/views/ClassPage/components/classHeader.vue

@@ -23,7 +23,7 @@ export default {
 <style scoped>
 .class-header {
     width: '100%';
-    height: 10vh;
+    height: 7.5vh;
     display: flex;
     flex-direction: row;
     align-items: center;

+ 31 - 4
src/views/ClassPage/components/classTable.vue

@@ -1,5 +1,9 @@
 <template>
-    <div class="class-table">
+    <div class="class-table-zcx">
+        <table>
+            <slot name="head"></slot>
+            <slot name="body"></slot>
+        </table>
     </div>
 </template>
 
@@ -13,11 +17,34 @@ export default {
 }
 </script>
 
-<style scoped>
-.class-table {
+<style>
+.class-table-zcx {
     width: 100%;
     height: 100%;
     background-color: #fff;
-    border: 1px solid #70bbdb;
+    table{
+      width: 100%;
+      height: 100%;
+      th{
+        font-size: 16px;
+        font-weight: 700;
+        color: #70bbdb;
+        border: none;
+        border-bottom: 3px solid #70bbdb;
+      }
+      td{
+        font-size: 14px;
+        color: #606266;
+        border: none;
+        border-bottom: 2px solid #e4e7ed;
+        text-align: center;
+      }
+      .Gethover {
+        background-color: #f0f2f5;
+      }
+      .Blue {
+        color: #4a90c4;
+      }
+    }
 }
 </style>