stupig-zcx 1 ano atrás
pai
commit
0a873e9866

+ 2 - 2
src/apis/axios.config.ts

@@ -1,9 +1,9 @@
 import axios from "axios";
 
 // const BASEURL = 'http://47.111.23.171:8081'
-// const BASEURL = 'http://localhost:8082'
+const BASEURL = 'http://localhost:8082'
 // const BASEURL = 'http://8.130.126.86:8080'
-const BASEURL = 'https://air-nju.seec.seecoder.cn/'
+// const BASEURL = 'https://air-nju.seec.seecoder.cn/'
 
 const axiosInstance = axios.create({
     baseURL: BASEURL,

+ 1 - 0
src/assets/add.svg

@@ -0,0 +1 @@
+<svg role="img" xmlns="http://www.w3.org/2000/svg" width="48px" height="48px" viewBox="0 0 24 24" aria-labelledby="addIconTitle" stroke="#4a90c4" stroke-width="2.5" stroke-linecap="square" stroke-linejoin="miter" fill="none" color="#4a90c4"> <title id="addIconTitle">Add</title> <path d="M17 12L7 12M12 17L12 7"/> <circle cx="12" cy="12" r="10"/> </svg>

+ 1 - 0
src/assets/people.svg

@@ -0,0 +1 @@
+<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" aria-labelledby="peopleIconTitle" stroke="#4a90c4" stroke-width="3" stroke-linecap="square" stroke-linejoin="miter" fill="none" color="#4a90c4"> <title id="peopleIconTitle">People</title> <path d="M1 18C1 15.75 4 15.75 5.5 14.25 6.25 13.5 4 13.5 4 9.75 4 7.25025 4.99975 6 7 6 9.00025 6 10 7.25025 10 9.75 10 13.5 7.75 13.5 8.5 14.25 10 15.75 13 15.75 13 18M12.7918114 15.7266684C13.2840551 15.548266 13.6874862 15.3832994 14.0021045 15.2317685 14.552776 14.9665463 15.0840574 14.6659426 15.5 14.25 16.25 13.5 14 13.5 14 9.75 14 7.25025 14.99975 6 17 6 19.00025 6 20 7.25025 20 9.75 20 13.5 17.75 13.5 18.5 14.25 20 15.75 23 15.75 23 18"/> <path stroke-linecap="round" d="M12,16 C12.3662741,15.8763472 12.6302112,15.7852366 12.7918114,15.7266684"/> </svg>

+ 1 - 0
src/assets/time.svg

@@ -0,0 +1 @@
+<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" aria-labelledby="timeIconTitle" stroke="#4a90c4" stroke-width="3" stroke-linecap="square" stroke-linejoin="miter" fill="none" color="#4a90c4"> <title id="timeIconTitle">Time</title> <circle cx="12" cy="12" r="10"/> <polyline points="12 5 12 12 16 16"/> </svg>

+ 25 - 15
src/router/index.ts

@@ -16,24 +16,24 @@ const router = createRouter({
     },
 
     // 登录与注册
-    {
-      path: "/",
-      redirect: () => {
-        window.location.href = "https://p-nju.seec.seecoder.cn/login?from=https://air-nju.seec.seecoder.cn";
-        // window.location.href = "http://localhost:8000/login?from=http://localhost:4000";
-        // {本地门户首页地址}?from={本地eai首页地址}
-        return "/"; // 占位返回值,实际不会执行
-    },
-    },
     // {
     //   path: "/",
-    //   redirect: "/login"
+    //   redirect: () => {
+    //     window.location.href = "https://p-nju.seec.seecoder.cn/login?from=https://air-nju.seec.seecoder.cn";
+    //     // window.location.href = "http://localhost:8000/login?from=http://localhost:4000";
+    //     // {本地门户首页地址}?from={本地eai首页地址}
+    //     return "/"; // 占位返回值,实际不会执行
     // },
-    // {
-    //   path: '/login',
-    //   name: 'login',
-    //   component: () => import('../views/LoginPage/LoginPage.vue')
     // },
+    {
+      path: "/",
+      redirect: "/login"
+    },
+    {
+      path: '/login',
+      name: 'login',
+      component: () => import('../views/LoginPage/LoginPage.vue')
+    },
     {
       path: '/register',
       name: 'register',
@@ -137,6 +137,16 @@ const router = createRouter({
           name: 'myCorrectWithAssignmentId',
           component: () => import("@/views/CorrectPage/CorrectAssignmentPage.vue")
         },
+        {
+          path: 'courseClass/:courseId',
+          name: 'courseClass',
+          component: () => import("@/views/ClassPage/CourseClass.vue")
+        },
+        {
+          path: 'classDetail',
+          name: 'classDetail',
+          component: () => import("@/views/ClassPage/ClassDetail.vue")
+        },
       ]
     },
 
@@ -195,7 +205,7 @@ const router = createRouter({
  */
   router.beforeEach(async (to) => {
     const store = useStore();
-    const publicPaths = [ '/register', '/passwordChange', '/admin/login'];
+    const publicPaths = [ '/register', '/passwordChange', '/admin/login', '/login'];
     // 1. 检查URL中的token
     const urlToken = new URLSearchParams(window.location.search).get('token');
     if (urlToken) {

+ 15 - 0
src/types/vo.ts

@@ -139,4 +139,19 @@ export interface CourseDetailVO {
     createTime: string;
     description: string;
 }
+//班级模块
+export interface ClassVO {
+    classId: number;
+    className: string;
+    classTime: string;
+    teacherId: number;
+    courseId: number;
+    stuNumber: number;
+}
 
+export interface ClassStudentVO {
+    officialNumber: number;
+    stuName: string;
+    stateCode: number;
+    stateDesc: string;
+}

+ 173 - 0
src/views/ClassPage/ClassDetail.vue

@@ -0,0 +1,173 @@
+<template>
+    <div class="course-class" v-show="DataLoading">
+        <classHeader>{{Coursedata.courseName}}:{{ Classdata.className }}</classHeader>
+        <div class="content">
+            <classTable></classTable>
+        </div>
+        <classDetailFooter></classDetailFooter>
+    </div>
+</template>
+
+<script setup lang="ts">
+import {onMounted, reactive, ref, computed} from 'vue';
+import { useRoute } 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 useApis from "@/apis";
+
+const route = useRoute()
+const apis = useApis()
+const classId = +route.query.classId;
+const courseId = +route.query.courseId;
+
+const CourseDataLoading = ref(false)
+const ClassDataLoading = ref(false)
+const StudentsDataLoading = ref(false)
+
+const Studentsdata = reactive<ClassStudentVO[]>([])
+
+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 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 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 DataLoading = computed(() => {
+  return CourseDataLoading.value && ClassDataLoading.value && StudentsDataLoading.value
+})
+
+
+onMounted(() => {
+    getClass()
+    getCourse()
+    getStudents()
+})
+</script>
+
+<script lang="ts">
+export default {
+  name: "ClassDetail"
+}
+</script>
+
+<style scoped>
+.course-class {
+    width: 66vw;
+    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;
+}
+</style>

+ 430 - 0
src/views/ClassPage/CourseClass.vue

@@ -0,0 +1,430 @@
+<template>
+    <div class="course-class" v-show="DataLoading">
+        <classHeader>{{Coursedata.courseName}}</classHeader>
+        <div class="content scroll">
+            <a v-for="(item) in data" :key="item.classId" 
+                class="content-item" 
+                @mouseenter="activeId=item.classId" 
+                @mouseleave="activeId=-1" 
+                :class="{'shadow_unactive':item.classId!==activeId,'shadow_active':item.classId===activeId}"
+                @click="{$event.preventDefault();$router.push(`/home/classDetail?classId=${item.classId}&courseId=${item.courseId}`)}"
+            >
+                <h2>{{ item.className }}</h2>
+                <div class="svg-text">
+                    <img src="@/assets/people.svg" width="24px" height="24px"></img> 
+                    <span>:</span>
+                    <span>{{ item.stuNumber }}</span>
+                </div>
+                <div class="svg-text">
+                    <img src="@/assets/time.svg" width="24px" height="24px"></img> 
+                    <span>:</span>
+                    <span>{{ item.classTime }}</span>
+                </div>
+                <div class="del">
+                    <button :disabled="item.stuNumber!==0"
+                            @click.stop="handleDelete(item.classId)"
+                            :title="item.stuNumber!==0 ? '仍有学生剩余无法直接删除班级' : ''"
+                    >
+                     Del
+                    </button>
+                </div>
+            </a>
+            <a class="plus"
+                @mouseenter="activeId=-2" 
+                @mouseleave="activeId=-1" 
+                @click="visible_add=true"
+                :class="{'shadow_unactive':-2!==activeId,'shadow_active':-2===activeId}">
+                <img src="@/assets/add.svg"></img> 
+            </a>
+        </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+"吗?"}}</h2>
+            </div>
+            <div class="modal-footer">
+                <button class="yes-button" @click.stop="DeleteClass" :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="addClassName" placeholder="班级名称建议小于6个字"></input>
+            </div>
+            <div class="add1" v-show="isloading_add" 
+            :style="{'height': '66%', 'margin-left':'210px'}">
+                <h2>上传中...</h2>
+            </div>
+            <div class="add1" v-show="!isloading_add">
+                <h2>上课时间:</h2>
+                <select id="addWeekdays" v-model="addClassDay">
+                    <option value="">Weekdays</option>
+                    <option value="Mon">Mon</option>
+                    <option value="Tue">Tue</option>
+                    <option value="Wed">Wed</option>
+                    <option value="Thu">Thu</option>
+                    <option value="Tue">Fri</option>
+                    <option value="Wed">Sat</option>
+                    <option value="Thu">Sun</option>
+                </select>
+                <span>-</span>
+                <select id="addTime" v-model="addClassClock">
+                    <option value="">Time</option>
+                    <option value="08:00">08:00</option>
+                    <option value="10:10">10:10</option>
+                    <option value="14:00">14:00</option>
+                    <option value="16:10">16:10</option> 
+                </select>
+            </div>
+            <div class="modal-footer add2">
+                <button class="yes-button" @click.stop="AddClass" :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 {onMounted, reactive, ref, computed } from 'vue';
+import { useRoute } from 'vue-router';
+import classHeader from './components/classHeader.vue';
+import type {CourseDetailVO, ClassVO} from "@/types/vo";
+import useApis from "@/apis";
+
+const route = useRoute()
+const apis = useApis()
+const courseId = +route.params.courseId;
+
+const data = reactive<ClassVO[]>([])
+const Coursedata = reactive<CourseDetailVO>({
+  courseId: null,
+  courseName: '',
+  teacherIds: [],
+  teacherNames: [],
+  courseImages: [''],
+  targetGrade: '',
+  startTime: '',
+  endTime: '',
+  createTime: '',
+  description: '',
+})
+let activeId = ref(-1)
+let isloading = ref(false)
+let isloading_add = ref(false)
+let visible_del = ref(false)
+let visible_add = ref(false)
+let deleteName = ref("")
+let deleteId = ref(-1)
+let addClassName = ref("")
+let addClassDay = ref("")
+let addClassClock = ref("")
+
+let CourseDataLoading = ref(false)
+let ClassDataLoading = ref(false)
+
+const handleDelete = (cid) => {
+    visible_del.value = true
+    deleteId.value = cid
+    deleteName.value = data.find((item)=>{
+        return item.classId === cid
+    }).className
+}
+const DeleteClass = () =>{
+    isloading.value = true
+    console.log(deleteId.value);
+    // 删除班级
+    setTimeout(()=>{
+        visible_del.value=false
+        isloading.value = false
+    }, 1000)
+}
+const AddClass = () =>{
+    isloading_add.value = true
+    console.log(addClassName.value)
+    console.log(addClassDay.value +" "+ addClassClock.value)
+    setTimeout(()=>{
+        isloading_add.value = false
+        visible_add.value=false
+        addClassName.value = ""
+        addClassDay.value = ""
+    addClassClock.value = ""     
+    }, 1000)
+}
+const getClass = () => {
+    console.log(courseId);
+    const newData = [
+    {       
+        "classId": 7,
+        "className": "读写1班",
+        "courseId": 10,
+        "stuNumber": 30,
+        "classTime": "Mon 10:10",
+        "teacherId": 4
+    },
+    {
+        "classId": 8,
+        "className": "读写二班",
+        "courseId": 10,
+        "stuNumber": 0,
+        "classTime": "Fri 08:00",
+        "teacherId": 4
+    },
+    {
+        "classId": 9,
+        "className": "读写3班",
+        "courseId": 10,
+        "stuNumber": 33,
+        "classTime": "周一上午十点",
+        "teacherId": 4        
+    },
+    {
+        "classId": 10,
+        "className": "读写4班",
+        "courseId": 10,
+        "stuNumber": 0,
+        "classTime": "Mon 08:00",
+        "teacherId": 4        
+    }
+    ]
+    newData.forEach(item => data.push(item))
+    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
+})
+
+onMounted(() => {
+    getClass()
+    getCourse()
+})
+</script>
+
+<script lang="ts">
+export default {
+  name: "CourseClass"
+}
+</script>
+
+<style scoped>
+.course-class {
+    width: 66vw;
+    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-top: 30px;
+    margin-bottom: 10vh;
+    display: flex;
+    align-items: center;
+    flex-direction: row;
+    flex-wrap: wrap;
+    justify-content: start;
+    padding: 10px;
+    gap: 30px;
+    overflow: auto;
+    .content-item{
+        width: 160px;
+        height: 260px;
+        border-radius: 25px;
+        border: 20px solid #70bbdb; 
+        cursor: pointer;
+        transition: all 0.3s ease;
+        margin-left: 20px;
+        margin-bottom: 20px;
+        h2 {
+            color: #4a90c4;
+            margin-left: 15px;
+            margin-right: 15px;
+            margin-top: 25px;
+            white-space: nowrap;      /* 强制不换行 */
+            overflow: hidden;        /* 隐藏超出部分 */
+            text-overflow: ellipsis;
+        }
+        .svg-text{
+            display: flex;
+            align-items: center;
+            font-size: 22px;
+            color:#4a90c4;
+            font-weight: 600;
+            margin:20px 15px;
+            span {
+                margin-left: 10px;
+            }
+        }
+        .del{
+            display: flex;
+            flex-direction: row;
+            justify-content: end;
+            button{
+                background-color: #c45c4a;
+                color: #fff;
+                border: 0;
+                padding: 3px 10px;
+                font-size: 22px;
+                font-weight: 600;
+                border-radius: 20px;
+                margin-right: 20px;
+            }
+            button:disabled{
+                background-color: #d9d9d9;
+            }
+        }
+    }
+    a:active{
+        box-shadow: none;
+        border: 25px solid #4a90c4; 
+    }
+    .plus{
+        width: 160px;
+        height: 260px;
+        border-radius: 25px;
+        border: 20px solid #70bbdb; 
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        cursor: pointer;
+        transition: all 0.3s ease;
+        margin-left: 30px;
+        margin-bottom: 20px;
+    }
+}
+.shadow_unactive{
+    box-shadow: -20px 20px 20px 0 rgba(0, 0, 0, 0.25);
+}
+.shadow_active{
+    box-shadow: -20px 20px 20px 0 #B9DDF5;
+}
+.scroll{
+    scrollbar-width: thin;
+    scrollbar-color: rgba(0, 123, 255, 0.2) transparent;
+}
+
+.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>

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

@@ -0,0 +1,29 @@
+<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>

+ 51 - 0
src/views/ClassPage/components/classHeader.vue

@@ -0,0 +1,51 @@
+<template>
+    <div class="class-header">
+        <div class="title title_border">
+            <slot></slot>
+        </div>
+        <div class="title" @click="$router.go(-1)" style="padding-right: 4.1vw;cursor: pointer;">
+            <el-icon style="vertical-align: bottom; margin-right: 6px;"><ArrowLeftBold/></el-icon>
+            返回
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { ArrowLeftBold } from '@element-plus/icons-vue'
+</script>
+
+<script lang="ts">
+export default {
+  name: "classHeader"
+}
+</script>
+
+<style scoped>
+.class-header {
+    width: '100%';
+    height: 10vh;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: space-between;
+    padding-left: 0.5vw;
+    margin-top: -15px;
+}
+.title{
+    /* 字体设置 一级标题 */
+    color:#70BBDB;
+    font-family: Inter;
+    font-size: 28px;
+    font-style: normal;
+    font-weight: 700;
+    line-height: 24px;
+    height:28px;
+    padding: 10px;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+}
+.title_border{
+    border-bottom: 5px solid #4FA3C5;
+}
+</style>

+ 23 - 0
src/views/ClassPage/components/classTable.vue

@@ -0,0 +1,23 @@
+<template>
+    <div class="class-table">
+    </div>
+</template>
+
+<script setup lang="ts">
+
+</script>
+
+<script lang="ts">
+export default {
+  name: "classTable"
+}
+</script>
+
+<style scoped>
+.class-table {
+    width: 100%;
+    height: 100%;
+    background-color: #fff;
+    border: 1px solid #70bbdb;
+}
+</style>

+ 2 - 1
src/views/CourseSquare/component/CourseDetails/index.vue

@@ -32,6 +32,7 @@
           </template>
           <template v-if="showEdit && role == 'teachers'">
             <el-button color="#597d3b" @click="visible = true; fileList[0] = {name: '壁纸', url: newCourseInfo.courseImages[0]}">编辑课程</el-button>
+            <el-button color="#4a90c4" style="color: #fff" @click="$router.push(`/home/courseClass/${courseId}`)">班级管理</el-button>
           </template>
         </div>
       </div>
@@ -123,7 +124,7 @@ import {
   type UploadFiles, type UploadFile, type FormRules, type FormInstance
 } from 'element-plus';
 import './index.scss'
-import type {CourseDetailVO, CourseVO, IAssignment, IAssignmentTableColumn, IAssignmentTableItem} from "@/types/vo";
+import type {CourseDetailVO, CourseVO, IAssignment, IAssignmentTableColumn, IAssignmentTableItem, ClassVO} from "@/types/vo";
 import {useRoute} from "vue-router";
 import useApis from "@/apis";
 import CourseHomeworkTable from "@/views/CourseSquare/component/CourseDetails/component/CourseHomeworkTable.vue";