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