Browse Source

课表完成

黄琪勇 1 year ago
parent
commit
f98a5e911e

+ 103 - 4
src/api/curriculum.api.ts

@@ -2,21 +2,69 @@ import { httpAxios_gym, httpAxios_gyt } from "@/api/ApiInstance"
 
 /** 管乐迷 */
 
-// 首页课程
-export const queryLessonCourseware_gym = (type: string) => {
+// 获取课程详情
+export const getCurrentCourseDetail_gym = (id: string) => {
+   return httpAxios_gym.axioseRquest({
+      method: "get",
+      url: "/api-teacher/teacherCourseSchedule/getCurrentCourseDetail",
+      params: {
+         courseID: id
+      }
+   })
+}
+// 获取课件详情 详情展示用
+export const getLessonCourseDetail_gym = (id: string) => {
+   return httpAxios_gym.axioseRquest({
+      method: "get",
+      url: "/api-teacher/lessonCourseware/getLessonCourseDetail/" + id
+   })
+}
+
+//获取课程列表
+export const queryLessonCourseware_gym = () => {
    return httpAxios_gym.axioseRquest({
       method: "post",
       url: "/api-teacher/lessonCourseware/queryLessonCourseware",
       data: {
          query: {
-            subjectId: type,
             page: 1,
             rows: 9999
          }
       }
    })
 }
-
+// 课程详情列表
+export const getLessonCoursewareCourseList_gym = (id: string) => {
+   return httpAxios_gym.axioseRquest({
+      method: "get",
+      url: "/api-teacher/lessonCourseware/getLessonCoursewareCourseList/" + id
+   })
+}
+// 设置课件
+export const setCoursewareDetail_gym = (id: string, courseId: string) => {
+   return httpAxios_gym.axioseRquest({
+      method: "get",
+      url: `/api-teacher/teacher/configCourseware`,
+      params: {
+         courseId,
+         coursewareDetailId: id
+      }
+   })
+}
+// 获取当月所有的课程日期 month=2024-04
+export const getCourseScheduleDateByMonth_gym = (date: string) => {
+   return httpAxios_gym.axioseRquest({
+      method: "get",
+      url: `/api-teacher/teacherCourseSchedule/getCourseScheduleDateByMonth?month=${date}`
+   })
+}
+// 获取当天的课程列表 date=2024-04-03
+export const getCourseSchedulesWithDate_gym = (date: string) => {
+   return httpAxios_gym.axioseRquest({
+      method: "get",
+      url: `/api-teacher/teacherCourseSchedule/getCourseSchedulesWithDate?date=${date}`
+   })
+}
 /**
  * 管乐团
  */
@@ -28,3 +76,54 @@ export const getCourseScheduleDetail_gyt = (id: string) => {
       url: "/api-teacher/courseSchedule/detail/" + id
    })
 }
+// 获取课程能选择的课件列表
+export const getCourseware_gyt = (id: string) => {
+   return httpAxios_gyt.axioseRquest({
+      method: "post",
+      url: "/api-teacher/courseSchedule/getCourseware/" + id
+   })
+}
+
+// 获取课件详情 配置课件用
+export const getCoursewareDetail_gyt = (id: string, courseId: string) => {
+   return httpAxios_gyt.axioseRquest({
+      method: "post",
+      url: `/api-teacher/courseSchedule/getCoursewareDetail?courseScheduleId=${courseId}&coursewareId=${id}`
+   })
+}
+// 设置课件
+export const setCoursewareDetail_gyt = (id: string, courseId: string) => {
+   return httpAxios_gyt.axioseRquest({
+      method: "post",
+      url: `/api-teacher/courseSchedule/setCoursewareDetail?courseScheduleId=${courseId}&coursewareDetailId=${id}`
+   })
+}
+
+// 获取课件详情 详情展示用
+export const getLessonCoursewareDetail_gyt = (id: string) => {
+   return httpAxios_gyt.axioseRquest({
+      method: "get",
+      url: "/api-teacher/lessonCoursewareDetail/detail/" + id
+   })
+}
+
+// 获取当月所有的课程日期 month=2024-04
+export const getCourseScheduleDateByMonth_gyt = (date: string) => {
+   return httpAxios_gyt.axioseRquest({
+      method: "post",
+      url: `/api-teacher/courseSchedule/calendar`,
+      data: {
+         classMonth: date
+      }
+   })
+}
+// 获取当天的课程列表 date=2024-04-03
+export const getCourseSchedulesWithDate_gyt = (date: string) => {
+   return httpAxios_gyt.axioseRquest({
+      method: "post",
+      url: `/api-teacher/courseSchedule/page`,
+      data: {
+         classDate: date
+      }
+   })
+}

+ 57 - 31
src/components/myCalendar/myCalendar.vue

@@ -18,7 +18,7 @@
       <template #date-cell="{ data }">
          <div class="dayCon" @click.stop>
             <div v-if="data.type === 'current-month'" class="dayBox" @click.stop="handleClickDate(data)">
-               <div class="daytit">
+               <div class="daytit" :class="isMarkClass(data.day)">
                   {{ format() === data.day ? "今" : format(data.day, "d") }}
                </div>
             </div>
@@ -30,24 +30,43 @@
 
 <script setup lang="ts">
 import { format } from "@/libs/tools"
-import { ref, computed } from "vue"
+import { ref, computed, watch } from "vue"
 import type { CalendarDateType, CalendarInstance } from "element-plus"
 import { useLocale } from "element-plus"
 import dayjs from "dayjs"
 
 const props = defineProps<{
    modelValue: Date
+   dayMarks?: string[]
 }>()
+
 const emits = defineEmits<{
    (e: "update:modelValue", value: Date): void
+   (e: "monthChange", value: Date): void
 }>()
 
 const isNowMonth = computed(() => {
    return dateData.value.getMonth() === props.modelValue.getMonth() && dateData.value.getFullYear() === props.modelValue.getFullYear()
 })
-
+const isMarkClass = (date: string) => {
+   if (!props.dayMarks) {
+      return ""
+   }
+   const index = props.dayMarks.findIndex(day => {
+      return format(day) === format(date)
+   })
+   if (index === -1) {
+      return ""
+   }
+   return new Date(date.replace(/-/g, "/")) < new Date(format(new Date(), "yyyy/mm/dd")) ? "old" : "new"
+}
 const { lang } = useLocale()
 const dateData = ref(props.modelValue)
+watch(dateData, (newVal, oldVal) => {
+   if (newVal.getMonth() !== oldVal.getMonth()) {
+      emits("monthChange", newVal)
+   }
+})
 
 const calendarDom = ref<CalendarInstance>()
 const selectDate = (val: CalendarDateType) => {
@@ -172,46 +191,53 @@ function handleClickDate(data: { type: "prev-month" | "current-month" | "next-mo
          .nobg {
             height: var(--el-calendar-cell-width);
          }
-      }
-      &.is-today .el-calendar-day .dayCon .dayBox {
-         background-image: url("./img//jiao.png");
-         background-size: 100% 100%;
-         background-color: #fff7ed;
          .daytit {
             font-weight: 600;
             font-size: 28px;
             position: relative;
-            &::after {
-               content: "";
-               position: absolute;
-               width: 8px;
-               height: 8px;
-               border-radius: 50%;
-               bottom: -14px;
-               left: 50%;
-               transform: translateX(-50%);
-               background-color: #ff8057;
+            &.old {
+               &::after {
+                  content: "";
+                  position: absolute;
+                  width: 8px;
+                  height: 8px;
+                  border-radius: 50%;
+                  bottom: -14px;
+                  left: 50%;
+                  transform: translateX(-50%);
+                  background-color: #aaaaaa;
+               }
+            }
+            &.new {
+               &::after {
+                  content: "";
+                  position: absolute;
+                  width: 8px;
+                  height: 8px;
+                  border-radius: 50%;
+                  bottom: -14px;
+                  left: 50%;
+                  transform: translateX(-50%);
+                  background-color: #ff8057;
+               }
             }
          }
       }
+      &.is-today .el-calendar-day .dayCon .dayBox {
+         background-image: url("./img//jiao.png");
+         background-size: 100% 100%;
+         background-color: #fff7ed;
+      }
    }
    &.isNowMonth .el-calendar-table td.is-selected .el-calendar-day .dayCon .dayBox {
       background: linear-gradient(45deg, #ffa357 0%, #ff6736 100%), #fff7ed;
       color: #ffffff;
       .daytit {
-         font-weight: 600;
-         font-size: 28px;
-         position: relative;
-         &::after {
-            content: "";
-            position: absolute;
-            width: 8px;
-            height: 8px;
-            border-radius: 50%;
-            bottom: -14px;
-            left: 50%;
-            transform: translateX(-50%);
-            background-color: #fff;
+         &.old,
+         &.new {
+            &::after {
+               background-color: #fff;
+            }
          }
       }
    }

BIN
src/img/curriculum/ts4.png


+ 5 - 3
src/plugin/modalFrame/index.ts

@@ -5,9 +5,11 @@ import zhCn from "element-plus/es/locale/lang/zh-cn"
 
 export const modalFrameSet = new Set<App<Element>>()
 export function closeAllModalFrame() {
-   ;[...modalFrameSet].map(modalFrameItem => {
-      modalFrameItem && modalFrameSet.delete(modalFrameItem)
-      modalFrameItem?.unmount()
+   modalFrameSet.forEach(modalFrameItem => {
+      if (modalFrameItem) {
+         modalFrameSet.delete(modalFrameItem)
+         modalFrameItem.unmount()
+      }
    })
 }
 

+ 1 - 1
src/views/cloudTextbooks/useData.ts

@@ -144,7 +144,7 @@ export const useDataDetailList = () => {
                   name: item.coursewareDetailName,
                   id: item.lessonCoursewareDetailId,
                   useNum: item.useNum,
-                  lockFlag: item.lockFlag
+                  lockFlag: false // 云教材默认不锁
                }
             })
             listData.value = chunkArray(chunkArray(data, 7), 2)

+ 79 - 11
src/views/curriculum/chooseCourseware.vue

@@ -31,7 +31,7 @@
                      <div class="name">{{ item.name }}</div>
                      <div class="text" v-if="item.useNum ?? false">已使用{{ item.useNum }}次</div>
                   </div>
-                  <div class="play" :class="{ disabled: item.lockFlag }" @click="item.lockFlag === true">选择</div>
+                  <div class="play" :class="{ disabled: item.lockFlag }" @click="item.lockFlag === true || chooseCourseware(item.id)">选择</div>
                </div>
             </div>
          </div>
@@ -41,6 +41,9 @@
 
 <script setup lang="ts">
 import { ref, shallowRef, computed } from "vue"
+import userStore from "@/store/modules/user"
+import { httpAjaxErrMsg, httpAjaxLoadingErrMsg } from "@/plugin/httpAjax"
+import { getCoursewareDetail_gyt, setCoursewareDetail_gyt, getLessonCoursewareCourseList_gym, setCoursewareDetail_gym } from "@/api/curriculum.api"
 
 type listDetail = {
    name: string
@@ -49,28 +52,93 @@ type listDetail = {
    lockFlag?: boolean
 }[]
 type listDetailType = [listDetail, listDetail]
-const listData = shallowRef<listDetail[][]>([])
-const pageNum = ref<number>(0)
-const loading = ref(false)
-const listDetailData = computed<listDetailType>(() => {
-   const data = listData.value[pageNum.value] || []
-   return [data[0] || [], data[1] || []]
-})
-function handlePage(type: "next" | "prev") {
-   type === "next" ? pageNum.value++ : pageNum.value--
-}
+
+const userStoreHook = userStore()
 const props = defineProps<{
    modalData: {
       id: string
+      courseId: string
    }
 }>()
 const emits = defineEmits<{
    (e: "onClose"): void
+   (e: "onOk"): void
 }>()
 
 function close() {
    emits("onClose")
 }
+const listData = shallowRef<listDetail[][]>([])
+const pageNum = ref<number>(0)
+const loading = ref(false)
+const listDetailData = computed<listDetailType>(() => {
+   const data = listData.value[pageNum.value] || []
+   return [data[0] || [], data[1] || []]
+})
+
+handleGetDetailList(props.modalData.id)
+function handleGetDetailList(id: string) {
+   userStoreHook.roles === "GYM" ? handleGetDetaList_gym(id) : handleGetDetailList_gyt(id, props.modalData.courseId)
+}
+function handlePage(type: "next" | "prev") {
+   type === "next" ? pageNum.value++ : pageNum.value--
+}
+// 获取管乐迷
+function handleGetDetaList_gym(id: string) {
+   loading.value = true
+   httpAjaxErrMsg(getLessonCoursewareCourseList_gym, id).then(res => {
+      loading.value = false
+      if (res.code === 200) {
+         const data = (res.data || []).map((item: any) => {
+            return {
+               name: item.coursewareDetailName,
+               id: item.coursewareDetailId
+            }
+         })
+         listData.value = chunkArray(chunkArray(data, 7), 2)
+      }
+   })
+}
+// 获取管乐团
+function handleGetDetailList_gyt(id: string, courseId: string) {
+   loading.value = true
+   httpAjaxErrMsg(getCoursewareDetail_gyt, id, courseId).then(res => {
+      loading.value = false
+      if (res.code === 200) {
+         const data = (res.data || []).map((item: any) => {
+            return {
+               name: item.coursewareDetailName,
+               id: item.lessonCoursewareDetailId,
+               useNum: item.useNum,
+               lockFlag: !item.unlock // unlock为true 就是不锁,所以这里取反
+            }
+         })
+         listData.value = chunkArray(chunkArray(data, 7), 2)
+      }
+   })
+}
+function chunkArray(array: any[], size: number) {
+   const result = []
+   for (let i = 0; i < array.length; i += size) {
+      result.push(array.slice(i, i + size))
+   }
+   return result
+}
+function chooseCourseware(id: string) {
+   if (userStoreHook.roles === "GYM") {
+      httpAjaxLoadingErrMsg(setCoursewareDetail_gym, id, props.modalData.courseId).then(res => {
+         if (res.code === 200) {
+            emits("onOk")
+         }
+      })
+   } else {
+      httpAjaxLoadingErrMsg(setCoursewareDetail_gyt, id, props.modalData.courseId).then(res => {
+         if (res.code === 200) {
+            emits("onOk")
+         }
+      })
+   }
+}
 </script>
 
 <style lang="scss" scoped>

+ 3 - 8
src/views/curriculum/components/courseCollapse/courseCollapse.vue

@@ -35,7 +35,7 @@
             <template v-if="item.materialList">
                <div class="courseList" v-for="i in item.materialList" :key="i.id">
                   <div class="courseTitleCon">
-                     <img :src="require(`@/img/curriculum/${i.type}.png`)" />
+                     <img :src="require(`@/img/curriculum/${i.typeCode || i.type}.png`)" />
                      <div class="ellipsisBox">
                         <ellipsisScroll :title="i.name" />
                      </div>
@@ -55,6 +55,7 @@ import ellipsisScroll from "@/components/ellipsisScroll"
 type materialListType = {
    id: string
    type: string
+   typeCode?: string
    name: string
 }
 type courseListType = {
@@ -67,7 +68,7 @@ type courseListType = {
 const props = withDefaults(
    defineProps<{
       courseList: courseListType
-      titleType: "default" | "round"
+      titleType?: "default" | "round"
    }>(),
    {
       titleType: "default"
@@ -166,12 +167,6 @@ const props = withDefaults(
          height: 68px;
          border-bottom: 1px solid #f2f2f2;
          cursor: pointer;
-         &:hover {
-            .iconArrow,
-            .courseTitleCon > img {
-               opacity: $opacity-hover;
-            }
-         }
          &:last-child {
             border-bottom: initial;
          }

+ 122 - 150
src/views/curriculum/components/curriculumList/curriculumList_gym.vue

@@ -4,169 +4,85 @@
 * @Date:2024-03-29 15:29:06
 -->
 <template>
-   <div class="curriculumList_gym">
+   <div class="curriculumList_gym" v-for="item in props.curriculumData" :key="item.id" @click="handleClickDetail(item.id, item.teachMode)">
       <div class="head">
          <div class="timeBox">
             <img class="timeImg" src="@/img/curriculum/sj.png" />
-            <div class="time">2024-01-27 15:00-15:30</div>
-         </div>
-         <div class="operateBox">
-            <img class="dangerImg" src="@/img/curriculum/jg.png" />
-            <div class="operateBtn">配置课件</div>
-         </div>
-      </div>
-      <div class="curriculumName">
-         <div class="leftCon">
-            <img class="xxImg" src="@/img/curriculum/xx.png" />
-            <img class="typeImg" src="@/img/curriculum/Band.png" />
-            <div class="className">
-               <ellipsisScroll :title="'乐团课·单簧管进阶提高体验课'" />
-            </div>
-         </div>
-         <div class="rightCon">
-            <img src="@/img/curriculum/qd.png" />
-            <div>签到</div>
-            <img class="qtImg" src="@/img/curriculum/qt.png" />
-            <div>签退</div>
-         </div>
-      </div>
-      <div class="endCon">
-         <div class="addressCon">
-            <div class="adressBox">
-               <div>上课学生:</div>
-               <div class="adress">
-                  <ellipsisScroll :title="'武汉市红领巾小学'" />
-               </div>
+            <div class="time">
+               {{ item.classDate && format(item.classDate) }} {{ item.startClassTime && format(item.startClassTime, "hh:ii") }}-{{
+                  item.endClassTime && format(item.endClassTime, "hh:ii")
+               }}
             </div>
-            <div>上课学生:陈琪</div>
-         </div>
-         <div class="operate" @click="handleClickDetail">
-            <div>查看详情</div>
-            <img class="jtImg" src="@/img/curriculum/jt.png" />
-         </div>
-      </div>
-   </div>
-   <div class="curriculumList_gym">
-      <div class="head">
-         <div class="timeBox">
-            <img class="timeImg" src="@/img/curriculum/sj.png" />
-            <div class="time">2024-01-27 15:00-15:30</div>
          </div>
          <div class="operateBox">
-            <img class="dangerImg" src="@/img/curriculum/jg.png" />
-            <div class="operateBtn">配置课件</div>
+            <template v-if="item.status === 'UNDERWAY' && !item.coursewareDetailId">
+               <img class="dangerImg" src="@/img/curriculum/jg.png" />
+               <div class="operateBtn" @click.stop="handleSetUpCourseware(item.id, item.teachMode)">配置课件</div>
+            </template>
+            <template v-else-if="item.status === 'NOT_START'">
+               <div class="noStart">未开始</div>
+            </template>
+            <template v-else-if="item.status === 'UNDERWAY'">
+               <div class="ing">进行中</div>
+            </template>
+            <template v-else>
+               <div class="end">已结束</div>
+            </template>
          </div>
       </div>
       <div class="curriculumName">
          <div class="leftCon">
-            <img class="xxImg" src="@/img/curriculum/xx.png" />
-            <img class="typeImg" src="@/img/curriculum/Band.png" />
+            <img class="xxImg" :src="item.teachMode === 'ONLINE' ? require('@/img/curriculum/xs.png') : require('@/img/curriculum/xx.png')" />
+            <img class="typeImg" :src="require(`@/img/curriculum/${classImgType[item.type as keyof typeof classImgType]}.png`)" />
             <div class="className">
-               <ellipsisScroll :title="'乐团课·单簧管进阶提高体验课'" />
+               <ellipsisScroll :title="`${classNameType[item.type as keyof typeof classNameType]}·${item.name}`" />
             </div>
          </div>
          <div class="rightCon">
-            <img src="@/img/curriculum/qd.png" />
-            <div>签到</div>
-            <img class="qtImg" src="@/img/curriculum/qt.png" />
-            <div>签退</div>
-         </div>
-      </div>
-      <div class="endCon">
-         <div class="addressCon">
-            <div class="adressBox">
-               <div>上课学生:</div>
-               <div class="adress">
-                  <ellipsisScroll :title="'武汉市红领巾小学'" />
-               </div>
+            <img
+               :src="
+                  item.signInStatusEnum === 1
+                     ? require('@/img/curriculum/qd1.png')
+                     : item.signInStatusEnum === 0
+                     ? require('@/img/curriculum/qd2.png')
+                     : require('@/img/curriculum/qd.png')
+               "
+            />
+            <div :class="[item.signInStatusEnum === 1 ? 'signIn' : item.signInStatusEnum === 0 && 'abnormalSignIn']">
+               {{ item.signInStatusEnum === 1 ? "正常签到" : item.signInStatusEnum === 0 ? "异常签到" : "未签到" }}
             </div>
-            <div>上课学生:陈琪</div>
-         </div>
-         <div class="operate">
-            <div>查看详情</div>
-            <img class="jtImg" src="@/img/curriculum/jt.png" />
-         </div>
-      </div>
-   </div>
-   <div class="curriculumList_gym">
-      <div class="head">
-         <div class="timeBox">
-            <img class="timeImg" src="@/img/curriculum/sj.png" />
-            <div class="time">2024-01-27 15:00-15:30</div>
-         </div>
-         <div class="operateBox">
-            <img class="dangerImg" src="@/img/curriculum/jg.png" />
-            <div class="operateBtn">配置课件</div>
-         </div>
-      </div>
-      <div class="curriculumName">
-         <div class="leftCon">
-            <img class="xxImg" src="@/img/curriculum/xx.png" />
-            <img class="typeImg" src="@/img/curriculum/Band.png" />
-            <div class="className">
-               <ellipsisScroll :title="'乐团课·单簧管进阶提高体验课'" />
+            <img
+               class="qtImg"
+               :src="
+                  item.signOutStatusEnum === 1
+                     ? require('@/img/curriculum/qt1.png')
+                     : item.signOutStatusEnum === 0
+                     ? require('@/img/curriculum/qt2.png')
+                     : require('@/img/curriculum/qt.png')
+               "
+            />
+            <div :class="[item.signOutStatusEnum === 1 ? 'signOut' : item.signOutStatusEnum === 0 && 'abnormalSignOut']">
+               {{ item.signOutStatusEnum === 1 ? "正常签退" : item.signOutStatusEnum === 0 ? "异常签退" : "未签退" }}
             </div>
          </div>
-         <div class="rightCon">
-            <img src="@/img/curriculum/qd.png" />
-            <div>签到</div>
-            <img class="qtImg" src="@/img/curriculum/qt.png" />
-            <div>签退</div>
-         </div>
       </div>
       <div class="endCon">
          <div class="addressCon">
             <div class="adressBox">
-               <div>上课学生:</div>
+               <div>上课地点:</div>
                <div class="adress">
-                  <ellipsisScroll :title="'武汉市红领巾小学'" />
+                  <ellipsisScroll :title="item.teachMode === 'ONLINE' ? '网络教室' : item.schoolName" />
                </div>
             </div>
-            <div>上课学生:陈琪</div>
-         </div>
-         <div class="operate">
-            <div>查看详情</div>
-            <img class="jtImg" src="@/img/curriculum/jt.png" />
-         </div>
-      </div>
-   </div>
-   <div class="curriculumList_gym">
-      <div class="head">
-         <div class="timeBox">
-            <img class="timeImg" src="@/img/curriculum/sj.png" />
-            <div class="time">2024-01-27 15:00-15:30</div>
-         </div>
-         <div class="operateBox">
-            <img class="dangerImg" src="@/img/curriculum/jg.png" />
-            <div class="operateBtn">配置课件</div>
-         </div>
-      </div>
-      <div class="curriculumName">
-         <div class="leftCon">
-            <img class="xxImg" src="@/img/curriculum/xx.png" />
-            <img class="typeImg" src="@/img/curriculum/Band.png" />
-            <div class="className">
-               <ellipsisScroll :title="'乐团课·单簧管进阶提高体验课'" />
-            </div>
-         </div>
-         <div class="rightCon">
-            <img src="@/img/curriculum/qd.png" />
-            <div>签到</div>
-            <img class="qtImg" src="@/img/curriculum/qt.png" />
-            <div>签退</div>
-         </div>
-      </div>
-      <div class="endCon">
-         <div class="addressCon">
             <div class="adressBox">
                <div>上课学生:</div>
                <div class="adress">
-                  <ellipsisScroll :title="'武汉市红领巾小学'" />
+                  <ellipsisScroll :title="item.studentNames" />
                </div>
             </div>
-            <div>上课学生:陈琪</div>
          </div>
-         <div class="operate">
+         <div class="btnGoClass" v-if="item.status === 'UNDERWAY'" @click.stop="handleStartClass(item.id, item.teachMode)">开始上课</div>
+         <div class="btnDetail" v-else @click.stop="handleClickDetail(item.id, item.teachMode)">
             <div>查看详情</div>
             <img class="jtImg" src="@/img/curriculum/jt.png" />
          </div>
@@ -175,21 +91,39 @@
 </template>
 
 <script setup lang="ts">
-import modalFrame from "@/plugin/modalFrame"
-import curriculumDetail from "../../curriculumDetail.vue"
+import { format } from "@/libs/tools"
+import { useCurriculumDetail, useSetUpCourseware } from "../../index"
+import { handleStartClass_gym, isONLINE_gym } from "@/views/curriculum/hooks/useStartClass"
+import { classImgType, classNameType } from "@/views/curriculum/type"
+
+const props = defineProps<{
+   curriculumData: any[]
+}>()
+const emits = defineEmits<{
+   (e: "update"): void
+}>()
 
-function handleClickDetail() {
-   //点击跳转详情
-   modalFrame({
-      template: curriculumDetail,
-      width: 989,
-      height: 760,
-      btnShow: [],
-      modalData: {
-         id: "123"
-      },
-      maskClose: true,
-      className: "curriculumDetail"
+//查看详情
+function handleClickDetail(id: string, teachMode: string) {
+   if (isONLINE_gym(teachMode)) {
+      return
+   }
+   useCurriculumDetail(id)
+}
+// 开始上课
+function handleStartClass(id: string, teachMode: string) {
+   if (isONLINE_gym(teachMode)) {
+      return
+   }
+   handleStartClass_gym(id)
+}
+// 配置课表
+function handleSetUpCourseware(id: string, teachMode: string) {
+   if (isONLINE_gym(teachMode)) {
+      return
+   }
+   useSetUpCourseware(id, () => {
+      emits("update")
    })
 }
 </script>
@@ -240,6 +174,21 @@ function handleClickDetail() {
                opacity: $opacity-hover;
             }
          }
+         .noStart {
+            font-weight: 500;
+            font-size: 20px;
+            color: #777777;
+         }
+         .ing {
+            font-weight: 500;
+            font-size: 20px;
+            color: #f67146;
+         }
+         .end {
+            font-weight: 500;
+            font-size: 20px;
+            color: #aaaaaa;
+         }
       }
    }
    .curriculumName {
@@ -251,6 +200,7 @@ function handleClickDetail() {
          flex-grow: 1;
          display: flex;
          align-items: center;
+         overflow: hidden;
          .xxImg {
             flex-shrink: 0;
             width: 46px;
@@ -269,7 +219,6 @@ function handleClickDetail() {
             font-weight: 600;
             font-size: 24px;
             color: #333333;
-            max-width: 520px;
          }
       }
       .rightCon {
@@ -285,6 +234,14 @@ function handleClickDetail() {
             font-weight: 500;
             font-size: 20px;
             color: #aaaaaa;
+            &.signIn,
+            &.signOut {
+               color: #01c199;
+            }
+            &.abnormalSignIn,
+            &.abnormalSignOut {
+               color: #ff0000;
+            }
          }
          .qtImg {
             margin-left: 34px;
@@ -299,6 +256,7 @@ function handleClickDetail() {
       padding-bottom: 22px;
       .addressCon {
          flex-grow: 1;
+         overflow: hidden;
          & > div {
             font-weight: 500;
             font-size: 16px;
@@ -314,12 +272,26 @@ function handleClickDetail() {
                flex-shrink: 0;
             }
             .adress {
-               max-width: 620px;
+               flex-grow: 1;
                overflow: hidden;
             }
          }
       }
-      .operate {
+      .btnGoClass {
+         flex-shrink: 0;
+         font-weight: 500;
+         font-size: 20px;
+         color: #ffffff;
+         padding: 11px 14px;
+         background: #ff8057;
+         border-radius: 21px;
+         text-align: center;
+         cursor: pointer;
+         &:hover {
+            opacity: $opacity-hover;
+         }
+      }
+      .btnDetail {
          flex-shrink: 0;
          display: flex;
          align-items: center;

+ 80 - 107
src/views/curriculum/components/curriculumList/curriculumList_gyt.vue

@@ -4,125 +4,44 @@
 * @Date:2024-03-29 15:29:06
 -->
 <template>
-   <div class="curriculumList_gyt">
+   <div class="curriculumList_gyt" v-for="item in props.curriculumData" :key="item.id" @click="handleClickDetail(item.id)">
       <div class="head">
          <div class="timeBox">
             <img class="timeImg" src="@/img/curriculum/sj.png" />
-            <div class="time">2024-01-27</div>
+            <div class="time">{{ item.classDate && format(item.classDate) }}</div>
          </div>
          <div class="operateBox">
-            <img class="dangerImg" src="@/img/curriculum/jg.png" />
-            <div class="operateBtn">配置课件</div>
+            <template v-if="item.status === 'ING' && !item.lessonCoursewareId">
+               <img class="dangerImg" src="@/img/curriculum/jg.png" />
+               <div class="operateBtn" @click.stop="handleSetUpCourseware(item.id)">配置课件</div>
+            </template>
+            <template v-else-if="item.status === 'NOT_START'">
+               <div class="noStart">未开始</div>
+            </template>
+            <template v-else-if="item.status === 'ING'">
+               <div class="ing">进行中</div>
+            </template>
+            <template v-else>
+               <div class="end">已结束</div>
+            </template>
          </div>
       </div>
       <div class="curriculumName">
-         <div class="leftCon">14:00-15:30</div>
+         <div class="leftCon">{{ item.startTime && format(item.startTime, "hh:ii") }}-{{ item.endTime && format(item.endTime, "hh:ii") }}</div>
          <div class="rightCon">
-            <img src="@/img/curriculum/qd.png" />
-            <div>签到</div>
-            <img class="qtImg" src="@/img/curriculum/qt.png" />
-            <div>签退</div>
+            <img :src="item.signIn ? require('@/img/curriculum/qd1.png') : require('@/img/curriculum/qd.png')" />
+            <div :class="{ signIn: item.signIn }">{{ item.signIn ? "正常签到" : "未签到" }}</div>
+            <img class="qtImg" :src="item.signOut ? require('@/img/curriculum/qt1.png') : require('@/img/curriculum/qt.png')" />
+            <div :class="{ signOut: item.signOut }">{{ item.signOut ? "正常签退" : "未签退" }}</div>
          </div>
       </div>
       <div class="endCon">
          <div class="addressCon">
-            <div class="adressBox">长笛班-张老师</div>
-            <div>武汉小学2022标准团</div>
+            <div class="adressBox"><ellipsisScroll :title="`${item.className}-${item.teacherName}`" /></div>
+            <div><ellipsisScroll :title="item.orchestraName" /></div>
          </div>
-         <div class="operate">
-            <div>查看详情</div>
-            <img class="jtImg" src="@/img/curriculum/jt.png" />
-         </div>
-      </div>
-   </div>
-   <div class="curriculumList_gyt">
-      <div class="head">
-         <div class="timeBox">
-            <img class="timeImg" src="@/img/curriculum/sj.png" />
-            <div class="time">2024-01-27</div>
-         </div>
-         <div class="operateBox">
-            <img class="dangerImg" src="@/img/curriculum/jg.png" />
-            <div class="operateBtn">配置课件</div>
-         </div>
-      </div>
-      <div class="curriculumName">
-         <div class="leftCon">14:00-15:30</div>
-         <div class="rightCon">
-            <img src="@/img/curriculum/qd.png" />
-            <div>签到</div>
-            <img class="qtImg" src="@/img/curriculum/qt.png" />
-            <div>签退</div>
-         </div>
-      </div>
-      <div class="endCon">
-         <div class="addressCon">
-            <div class="adressBox">长笛班-张老师</div>
-            <div>武汉小学2022标准团</div>
-         </div>
-         <div class="operate">
-            <div>查看详情</div>
-            <img class="jtImg" src="@/img/curriculum/jt.png" />
-         </div>
-      </div>
-   </div>
-   <div class="curriculumList_gyt">
-      <div class="head">
-         <div class="timeBox">
-            <img class="timeImg" src="@/img/curriculum/sj.png" />
-            <div class="time">2024-01-27</div>
-         </div>
-         <div class="operateBox">
-            <img class="dangerImg" src="@/img/curriculum/jg.png" />
-            <div class="operateBtn">配置课件</div>
-         </div>
-      </div>
-      <div class="curriculumName">
-         <div class="leftCon">14:00-15:30</div>
-         <div class="rightCon">
-            <img src="@/img/curriculum/qd.png" />
-            <div>签到</div>
-            <img class="qtImg" src="@/img/curriculum/qt.png" />
-            <div>签退</div>
-         </div>
-      </div>
-      <div class="endCon">
-         <div class="addressCon">
-            <div class="adressBox">长笛班-张老师</div>
-            <div>武汉小学2022标准团</div>
-         </div>
-         <div class="operate">
-            <div>查看详情</div>
-            <img class="jtImg" src="@/img/curriculum/jt.png" />
-         </div>
-      </div>
-   </div>
-   <div class="curriculumList_gyt">
-      <div class="head">
-         <div class="timeBox">
-            <img class="timeImg" src="@/img/curriculum/sj.png" />
-            <div class="time">2024-01-27</div>
-         </div>
-         <div class="operateBox">
-            <img class="dangerImg" src="@/img/curriculum/jg.png" />
-            <div class="operateBtn">配置课件</div>
-         </div>
-      </div>
-      <div class="curriculumName">
-         <div class="leftCon">14:00-15:30</div>
-         <div class="rightCon">
-            <img src="@/img/curriculum/qd.png" />
-            <div>签到</div>
-            <img class="qtImg" src="@/img/curriculum/qt.png" />
-            <div>签退</div>
-         </div>
-      </div>
-      <div class="endCon">
-         <div class="addressCon">
-            <div class="adressBox">长笛班-张老师</div>
-            <div>武汉小学2022标准团</div>
-         </div>
-         <div class="operate">
+         <div class="btnGoClass" v-if="item.status === 'ING'" @click.stop="handleStartClass(item.id)">开始上课</div>
+         <div class="btnDetail" v-else @click.stop="handleClickDetail(item.id)">
             <div>查看详情</div>
             <img class="jtImg" src="@/img/curriculum/jt.png" />
          </div>
@@ -130,7 +49,32 @@
    </div>
 </template>
 
-<script setup lang="ts"></script>
+<script setup lang="ts">
+import { format } from "@/libs/tools"
+import { useCurriculumDetail, useSetUpCourseware } from "@/views/curriculum"
+import { handleStartClass_gyt } from "@/views/curriculum/hooks/useStartClass"
+
+const emits = defineEmits<{
+   (e: "update"): void
+}>()
+const props = defineProps<{
+   curriculumData: any[]
+}>()
+// 开始上课
+function handleStartClass(id: string) {
+   handleStartClass_gyt(id)
+}
+//查看详情
+function handleClickDetail(id: string) {
+   useCurriculumDetail(id)
+}
+// 配置课表
+function handleSetUpCourseware(id: string) {
+   useSetUpCourseware(id, () => {
+      emits("update")
+   })
+}
+</script>
 
 <style lang="scss" scoped>
 .curriculumList_gyt {
@@ -178,6 +122,21 @@
                opacity: $opacity-hover;
             }
          }
+         .noStart {
+            font-weight: 500;
+            font-size: 20px;
+            color: #777777;
+         }
+         .ing {
+            font-weight: 500;
+            font-size: 20px;
+            color: #f67146;
+         }
+         .end {
+            font-weight: 500;
+            font-size: 20px;
+            color: #aaaaaa;
+         }
       }
    }
    .curriculumName {
@@ -233,7 +192,21 @@
             color: #333333;
          }
       }
-      .operate {
+      .btnGoClass {
+         flex-shrink: 0;
+         font-weight: 500;
+         font-size: 20px;
+         color: #ffffff;
+         padding: 11px 14px;
+         background: #ff8057;
+         border-radius: 21px;
+         text-align: center;
+         cursor: pointer;
+         &:hover {
+            opacity: $opacity-hover;
+         }
+      }
+      .btnDetail {
          flex-shrink: 0;
          display: flex;
          align-items: center;

+ 124 - 8
src/views/curriculum/curriculum.vue

@@ -7,11 +7,33 @@
    <navContainer :navs="navs">
       <div class="curriculum">
          <ElScrollbar class="elScrollbar">
-            <div class="calendarCon"><myCalendar v-model="value" /></div>
+            <div class="calendarCon"><myCalendar v-model="dateValue" @monthChange="handleMonthChange" :dayMarks="curriculumByMonth" /></div>
             <div class="curriculumCon">
-               <ElScrollbar class="listElScrollbar">
-                  <component :is="userStoreHook.roles === 'GYM' ? curriculumList_gym : curriculumList_gyt" />
-               </ElScrollbar>
+               <el-skeleton class="elSkeleton" :loading="loading" :count="3">
+                  <template #template>
+                     <div class="elSkeletonCon">
+                        <el-skeleton-item class="elSkeletonItem" variant="p" />
+                        <el-skeleton-item class="elSkeletonItem" variant="p" />
+                        <el-skeleton-item class="elSkeletonItem" variant="h1" />
+                        <el-skeleton-item class="elSkeletonItem" variant="h1" />
+                     </div>
+                  </template>
+                  <template #default>
+                     <ElScrollbar v-if="curriculumByDay.length" class="listElScrollbar">
+                        <component
+                           @update="handleDayChange(dateValue)"
+                           :curriculumData="curriculumByDay"
+                           :is="userStoreHook.roles === 'GYM' ? curriculumList_gym : curriculumList_gyt"
+                        />
+                     </ElScrollbar>
+                     <el-empty
+                        v-if="!curriculumByDay.length"
+                        class="empty"
+                        :image="require('@/img/layout/empty1.png')"
+                        description="您还没有待上课程哦~"
+                     />
+                  </template>
+               </el-skeleton>
             </div>
          </ElScrollbar>
       </div>
@@ -21,11 +43,18 @@
 <script setup lang="ts">
 import { format } from "@/libs/tools"
 import myCalendar from "@/components/myCalendar"
-import { ref, watchEffect } from "vue"
+import { ref, shallowRef, watch } from "vue"
 import navContainer from "@/businessComponents/navContainer"
 import userStore from "@/store/modules/user"
 import curriculumList_gym from "./components/curriculumList/curriculumList_gym.vue"
 import curriculumList_gyt from "./components/curriculumList/curriculumList_gyt.vue"
+import {
+   getCourseScheduleDateByMonth_gym,
+   getCourseSchedulesWithDate_gym,
+   getCourseScheduleDateByMonth_gyt,
+   getCourseSchedulesWithDate_gyt
+} from "@/api/curriculum.api"
+import { httpAjaxErrMsg, httpAjax } from "@/plugin/httpAjax"
 
 const userStoreHook = userStore()
 const navs = [
@@ -37,10 +66,57 @@ const navs = [
       name: "课表"
    }
 ]
-const value = ref(new Date())
-watchEffect(() => {
-   console.log(format(value.value))
+
+const curriculumByMonth = shallowRef<string[]>([])
+const curriculumByDay = shallowRef<any[]>([])
+const dateValue = ref(new Date())
+const loading = ref(false)
+watch(dateValue, () => {
+   handleDayChange(dateValue.value)
 })
+
+handleMonthChange(dateValue.value)
+handleDayChange(dateValue.value)
+function handleMonthChange(date: Date) {
+   getCurriculumByMonth(format(date, "yyyy-mm"))
+}
+function handleDayChange(date: Date) {
+   getCurriculumByDay(format(date, "yyyy-mm-dd"))
+}
+function getCurriculumByDay(day: string) {
+   if (userStoreHook.roles === "GYM") {
+      loading.value = true
+      httpAjaxErrMsg(getCourseSchedulesWithDate_gym, day).then(res => {
+         loading.value = false
+         if (res.code === 200) {
+            curriculumByDay.value = res.data?.rows || []
+         }
+      })
+   } else {
+      loading.value = true
+      httpAjaxErrMsg(getCourseSchedulesWithDate_gyt, day).then(res => {
+         loading.value = false
+         if (res.code === 200) {
+            curriculumByDay.value = res.data?.rows || []
+         }
+      })
+   }
+}
+function getCurriculumByMonth(month: string) {
+   if (userStoreHook.roles === "GYM") {
+      httpAjax(getCourseScheduleDateByMonth_gym, month).then(res => {
+         if (res.code === 200) {
+            curriculumByMonth.value = res.data || []
+         }
+      })
+   } else {
+      httpAjax(getCourseScheduleDateByMonth_gyt, month).then(res => {
+         if (res.code === 200) {
+            curriculumByMonth.value = res.data || []
+         }
+      })
+   }
+}
 </script>
 
 <style lang="scss" scoped>
@@ -72,6 +148,7 @@ watchEffect(() => {
    .curriculumCon {
       margin-left: 26px;
       flex-grow: 1;
+      overflow: hidden;
       height: 729px;
       background: linear-gradient(180deg, #ffd783 0%, #ffebc1 100%);
       border-radius: 42px;
@@ -89,6 +166,45 @@ watchEffect(() => {
             right: 0;
          }
       }
+      & > :deep(.empty) {
+         height: 100%;
+         background: #ffffff;
+         border-radius: 35px;
+         padding: 0;
+         margin: 0 23px 0 37px;
+         .el-empty__image {
+            width: 360px;
+         }
+      }
+      .elSkeleton {
+         padding: 0 23px 0 37px;
+         .elSkeletonCon {
+            background: #ffffff;
+            border-radius: 35px;
+            padding: 20px 30px;
+            margin-bottom: 18px;
+            &:last-child {
+               margin-bottom: 0;
+            }
+            > .elSkeletonItem {
+               &:nth-child(1) {
+                  height: 30px;
+               }
+               &:nth-child(2) {
+                  margin-top: 16px;
+                  height: 45px;
+               }
+               &:nth-child(3) {
+                  margin-top: 14px;
+                  height: 28px;
+               }
+               &:nth-child(4) {
+                  margin-top: 4px;
+                  height: 22px;
+               }
+            }
+         }
+      }
    }
 }
 </style>

+ 124 - 69
src/views/curriculum/curriculumDetail.vue

@@ -6,7 +6,7 @@
 <template>
    <div class="curriculumDetail">
       <div class="close" @click="close"></div>
-      <div class="curriculumDetailCon">
+      <div v-loading="loading" class="curriculumDetailCon">
          <img class="imgMid" src="@/img/curriculum/mid.png" />
          <div class="curriculumDetailBox">
             <div class="teachingObjectives">
@@ -15,15 +15,21 @@
                      <img src="@/img/curriculum/jxmb.png" />
                      <div>教学目标</div>
                   </div>
-                  <div class="rightBtn" @click="handleSetUpCourseware(props.modalData.id)">
-                     <div>更换课件</div>
+                  <div v-if="['ING', 'UNDERWAY'].includes(statusVal)" class="rightBtn" @click="handleSetUpCourseware(props.modalData.id)">
+                     <div>{{ curriculumDetailData.id ? "更换课件" : "配置课件" }}</div>
                      <img src="@/img/curriculum/jt1.png" />
                   </div>
                </div>
                <div class="content">
                   <ElScrollbar class="elScrollbar">
-                     <div class="title" v-for="tit in title.split('\n')" :key="tit">{{ tit }}</div>
+                     <div class="title" v-for="tit in curriculumDetailData.targetDesc.split('\n')" :key="tit">{{ tit }}</div>
                   </ElScrollbar>
+                  <el-empty
+                     v-if="!curriculumDetailData.targetDesc && !loading"
+                     class="empty"
+                     :image="require('@/img/layout/empty.png')"
+                     description="暂无教学目标"
+                  />
                </div>
             </div>
          </div>
@@ -37,23 +43,39 @@
                </div>
                <div class="content">
                   <ElScrollbar class="elScrollbar">
-                     <courseCollapse :courseList="data" />
+                     <courseCollapse :courseList="curriculumDetailData.pointList" />
                   </ElScrollbar>
+                  <el-empty
+                     v-if="!curriculumDetailData.pointList.length && !loading"
+                     class="empty"
+                     :image="require('@/img/layout/empty.png')"
+                     description="暂无知识点"
+                  />
                </div>
             </div>
          </div>
       </div>
-      <div class="curriculumStart">
-         <div class="startBtn">开始上课</div>
+      <div class="curriculumStart" v-if="['ING', 'UNDERWAY'].includes(statusVal) && !loading">
+         <div class="startBtn" @click="handleStartClass(modalData.id)">开始上课</div>
       </div>
    </div>
 </template>
 
 <script setup lang="ts">
 import courseCollapse from "./components/courseCollapse"
-import modalFrame from "@/plugin/modalFrame"
-import setUpCourseware from "./setUpCourseware.vue"
+import { useSetUpCourseware } from "./index"
+import {
+   getCourseScheduleDetail_gyt,
+   getLessonCoursewareDetail_gyt,
+   getCurrentCourseDetail_gym,
+   getLessonCourseDetail_gym
+} from "@/api/curriculum.api"
+import { httpAjaxErrMsg } from "@/plugin/httpAjax"
+import { ref, shallowRef } from "vue"
+import { handleStartClass_gyt, handleStartClass_gym, isONLINE_gym } from "./hooks/useStartClass"
+import userStore from "@/store/modules/user"
 
+const userStoreHook = userStore()
 const props = defineProps<{
    modalData: {
       id: string
@@ -66,74 +88,97 @@ const emits = defineEmits<{
 function close() {
    emits("onClose")
 }
-
-const title =
-   "乐理:认识五线谱,音符时值,谱号等等\n律动:节奏感受\n节奏:节奏练习1\n课堂纪律\n乐器安装于拆卸\n乐器持拿\n乐器介绍\n腹式呼吸:腹部控制,慢吸慢吐,快吸快吐\n嘴型练习:四个步骤\n唇振练习:嘴型+气息"
-
-type materialListType = {
+const loading = ref(false)
+const statusVal = ref("") //课程状态 ING 和 UNDERWAY 代表可以上课
+const teachModeVal = ref("") //课程类型 ONLINE课的时候提示去app
+const curriculumDetailData = shallowRef<{
+   pointList: any[]
+   targetDesc: string
    id: string
-   type: string
-   name: string
+}>({
+   pointList: [],
+   targetDesc: "",
+   id: ""
+})
+
+getCurriculumDetailData()
+function getCurriculumDetailData() {
+   userStoreHook.roles === "GYM" ? getCurriculumDetailData_gym() : getCurriculumDetailData_gyt()
 }
-type courseListType = {
-   id: string
-   name: string
-   materialList: materialListType[] | null
-   children: courseListType | null
-}[]
-const data: courseListType = [
-   {
-      id: "2",
-      name: "乐理第222",
-      materialList: null,
-      children: [
-         {
-            id: "3",
-            name: "五线谱",
-            materialList: [
-               {
-                  id: "2-1",
-                  type: "VIDEO",
-                  name: "第二课啊"
-               },
-               {
-                  id: "3-1",
-                  type: "VIDEO",
-                  name: "第二课啊"
+/* 处理管乐迷 */
+function getCurriculumDetailData_gym() {
+   loading.value = true
+   httpAjaxErrMsg(getCurrentCourseDetail_gym, props.modalData.id).then(res => {
+      if (res.code === 200) {
+         const { coursewareDetailId, courseStatus, teachMode } = res.data || {}
+         statusVal.value = courseStatus
+         teachModeVal.value = teachMode
+         if (coursewareDetailId) {
+            httpAjaxErrMsg(getLessonCourseDetail_gym, coursewareDetailId).then(resData => {
+               loading.value = false
+               if (resData.code === 200) {
+                  const { lessonTargetDesc, id, knowledgePointList } = resData.data || {}
+                  curriculumDetailData.value = {
+                     pointList: knowledgePointList || [],
+                     targetDesc: lessonTargetDesc,
+                     id
+                  }
                }
-            ],
-            children: null
+            })
+         } else {
+            loading.value = false
          }
-      ]
-   },
-   {
-      id: "1",
-      name: "乐理第一课前言",
-      materialList: [
-         {
-            id: "1-1",
-            type: "VIDEO",
-            name: "第一课啊"
+      } else {
+         loading.value = false
+      }
+   })
+}
+/* 处理管乐团 */
+function getCurriculumDetailData_gyt() {
+   loading.value = true
+   httpAjaxErrMsg(getCourseScheduleDetail_gyt, props.modalData.id).then(res => {
+      if (res.code === 200) {
+         const { lessonCoursewareDetailId, status } = res.data || {}
+         statusVal.value = status
+         if (lessonCoursewareDetailId) {
+            httpAjaxErrMsg(getLessonCoursewareDetail_gyt, lessonCoursewareDetailId).then(resData => {
+               loading.value = false
+               if (resData.code === 200) {
+                  const { lessonTargetDesc, id, knowledgePointList } = resData.data || {}
+                  curriculumDetailData.value = {
+                     pointList: knowledgePointList || [],
+                     targetDesc: lessonTargetDesc,
+                     id
+                  }
+               }
+            })
+         } else {
+            loading.value = false
          }
-      ],
-      children: null
+      } else {
+         loading.value = false
+      }
+   })
+}
+
+// 开始上课
+function handleStartClass(id: string) {
+   if (userStoreHook.roles === "GYM") {
+      if (isONLINE_gym(teachModeVal.value)) {
+         return
+      }
+      handleStartClass_gym(id)
+   } else {
+      handleStartClass_gyt(id)
    }
-]
+}
 
-/**
- * 选择更换课件
- */
+// 选择更换课件
 function handleSetUpCourseware(id: string) {
-   modalFrame({
-      template: setUpCourseware,
-      width: 924,
-      height: 452,
-      btnShow: [],
-      modalData: {
-         id
-      },
-      maskClose: true,
-      className: "setUpCourseware"
+   useSetUpCourseware(id, () => {
+      //选择课件成功后的回调
+      // 刷新数据
+      getCurriculumDetailData()
    })
 }
 </script>
@@ -190,6 +235,7 @@ function handleSetUpCourseware(id: string) {
             background: #ffffff;
             border-radius: 35px;
             .content {
+               position: relative;
                padding-top: 18px;
                height: calc(100% - 57px);
                & > :deep(.elScrollbar) {
@@ -204,6 +250,15 @@ function handleSetUpCourseware(id: string) {
                      right: 0;
                   }
                }
+               &:deep(.empty) {
+                  position: absolute;
+                  top: 50%;
+                  left: 50%;
+                  transform: translate(-50%, -50%);
+                  .el-empty__image {
+                     width: 278px;
+                  }
+               }
             }
          }
          .teachingObjectives {

+ 84 - 0
src/views/curriculum/hooks/useStartClass.ts

@@ -0,0 +1,84 @@
+import { getCourseScheduleDetail_gyt } from "@/api/curriculum.api"
+import { getRecentCourseSchedule_gym } from "@/api/homePage.api"
+import { httpAjaxErrMsg } from "@/plugin/httpAjax"
+import useDialogConfirm from "@/hooks/useDialogConfirm"
+import { format } from "@/libs/tools"
+
+/* 管乐迷 开始上课 */
+export function handleStartClass_gym(id: string) {
+   httpAjaxErrMsg(getRecentCourseSchedule_gym, id).then(res => {
+      if (res.code === 200) {
+         const { signInStatusEnum, isCallNames, coursewareDetailId, startClassTime, endClassTime } = res.data
+         if (signInStatusEnum === 3) {
+            useDialogConfirm({
+               headImg: require("@/img/curriculum/ts2.png"),
+               text: `您当前${format(startClassTime, "hh:ii")}-${format(endClassTime, "hh:ii")}的课程暂未签到,为避免考勤异常,请到APP进行签到。`,
+               btnShow: [true]
+            })
+            return
+         }
+         if (!isCallNames) {
+            useDialogConfirm({
+               headImg: require("@/img/curriculum/ts1.png"),
+               text: `您当前${format(startClassTime, "hh:ii")}-${format(endClassTime, "hh:ii")}的课程暂未点名,请到APP进行点名。`,
+               btnShow: [true]
+            })
+            return
+         }
+         if (!coursewareDetailId) {
+            useDialogConfirm({
+               headImg: require("@/img/curriculum/ts3.png"),
+               text: `该课程未配置课件,请配置课件。`,
+               btnShow: [true]
+            })
+            return
+         }
+         alert("开始上课")
+      }
+   })
+}
+// 管乐迷是否为线上课
+export function isONLINE_gym(teachMode: string) {
+   if (teachMode === "ONLINE") {
+      useDialogConfirm({
+         headImg: require("@/img/curriculum/ts4.png"),
+         text: `线上课请在管乐迷老师端完成教学。`,
+         btnShow: [true]
+      })
+      return true
+   }
+   return false
+}
+/* 管乐团 开始上课 */
+export function handleStartClass_gyt(id: string) {
+   httpAjaxErrMsg(getCourseScheduleDetail_gyt, id).then(res => {
+      if (res.code === 200) {
+         const { signIn, rollCall, lessonCoursewareId, startTime, endTime } = res.data
+         if (!signIn) {
+            useDialogConfirm({
+               headImg: require("@/img/curriculum/ts2.png"),
+               text: `您当前${format(startTime, "hh:ii")}-${format(endTime, "hh:ii")}的课程暂未签到,为避免考勤异常,请到APP进行签到。`,
+               btnShow: [true]
+            })
+            return
+         }
+         if (!rollCall) {
+            useDialogConfirm({
+               headImg: require("@/img/curriculum/ts1.png"),
+               text: `您当前${format(startTime, "hh:ii")}-${format(endTime, "hh:ii")}的课程暂未点名,请到APP进行点名。`,
+               btnShow: [true]
+            })
+            return
+         }
+         if (!lessonCoursewareId) {
+            useDialogConfirm({
+               headImg: require("@/img/curriculum/ts3.png"),
+               text: `该课程未配置课件,请配置课件。`,
+               btnShow: [true]
+            })
+            return
+         }
+         alert("开始上课")
+      }
+   })
+}

+ 41 - 0
src/views/curriculum/index.ts

@@ -1,2 +1,43 @@
 import curriculum from "./curriculum.vue"
 export default curriculum
+
+import modalFrame from "@/plugin/modalFrame"
+import curriculumDetail from "./curriculumDetail.vue"
+import setUpCourseware from "./setUpCourseware.vue"
+/**
+ * 课表详情
+ */
+export const useCurriculumDetail = (id: string) => {
+   modalFrame({
+      template: curriculumDetail,
+      width: 989,
+      height: 760,
+      btnShow: [],
+      modalData: {
+         id
+      },
+      maskClose: true,
+      className: "curriculumDetail"
+   })
+}
+
+/**
+ * 课表配置课件
+ */
+export const useSetUpCourseware = (id: string, callBack: () => void) => {
+   modalFrame({
+      template: setUpCourseware,
+      width: 924,
+      height: 452,
+      btnShow: [],
+      modalData: {
+         id
+      },
+      maskClose: true,
+      className: "setUpCourseware",
+      onOk(vm) {
+         vm.remove()
+         callBack()
+      }
+   })
+}

+ 75 - 21
src/views/curriculum/setUpCourseware.vue

@@ -7,7 +7,7 @@
    <div class="setUpCourseware">
       <div class="close" @click="close"></div>
       <img class="headImg" src="@/img/curriculum/ts3.png" />
-      <ElScrollbar class="elScrollbar">
+      <ElScrollbar class="elScrollbar" v-loading="loading">
          <div class="cloudTextbooksBox">
             <div class="bookshelf" v-for="(list, index) in listData" :key="index">
                <div class="book" v-for="item in list" :key="item.id">
@@ -23,13 +23,19 @@
             </div>
          </div>
       </ElScrollbar>
+      <el-empty v-if="!listData.length && !loading" class="empty" :image="require('@/img/layout/empty.png')" description="暂无结果" />
    </div>
 </template>
 
 <script setup lang="ts">
 import modalFrame from "@/plugin/modalFrame"
 import chooseCourseware from "./chooseCourseware.vue"
+import { getCourseware_gyt, queryLessonCourseware_gym } from "@/api/curriculum.api"
+import { httpAjaxErrMsg } from "@/plugin/httpAjax"
+import { ref, shallowRef } from "vue"
+import userStore from "@/store/modules/user"
 
+const userStoreHook = userStore()
 const props = defineProps<{
    modalData: {
       id: string
@@ -37,42 +43,81 @@ const props = defineProps<{
 }>()
 const emits = defineEmits<{
    (e: "onClose"): void
+   (e: "onOk"): void
 }>()
 
 function close() {
    emits("onClose")
 }
 
-function handleClick(id: number) {
+const loading = ref(false)
+const listData = shallowRef<any[]>([])
+
+getlistData()
+function getlistData() {
+   userStoreHook.roles === "GYM" ? getlistData_gym() : getlistData_gyt()
+}
+function getlistData_gym() {
+   loading.value = true
+   httpAjaxErrMsg(queryLessonCourseware_gym).then(res => {
+      loading.value = false
+      if (res.code === 200) {
+         const data = (res.data?.rows || []).map((item: any) => {
+            return {
+               name: item.name,
+               type: item.subjectId,
+               img: item.cover,
+               id: item.lessonCoursewareId,
+               courseNum: item.courseNum
+            }
+         })
+         listData.value = chunkArray(data, 3)
+      }
+   })
+}
+function getlistData_gyt() {
+   loading.value = true
+   httpAjaxErrMsg(getCourseware_gyt, props.modalData.id).then(res => {
+      loading.value = false
+      if (res.code === 200) {
+         const data = (res.data || []).map((item: any) => {
+            return {
+               name: item.coursewareName,
+               img: item.coverImg,
+               id: item.lessonCoursewareId,
+               courseNum: item.coursewareNum
+            }
+         })
+         listData.value = chunkArray(data, 3)
+      }
+   })
+}
+function handleClick(id: string) {
    modalFrame({
       template: chooseCourseware,
       width: 1110,
       height: 675,
       btnShow: [],
       modalData: {
-         id
+         id,
+         courseId: props.modalData.id
       },
       maskClose: true,
-      className: "chooseCourseware"
+      className: "chooseCourseware",
+      onOk(vm) {
+         vm.remove()
+         emits("onOk")
+      }
    })
 }
-const listData = [
-   [
-      { name: "萨克斯 Level1", type: 5, img: "https://oss.dayaedu.com/gyt/courseware/1698395357707.png", id: 1000102, courseNum: 17 },
-      { name: "打击乐 Level1", type: 23, img: "https://oss.dayaedu.com/gyt/courseware/1698395328495.png", id: 1000101, courseNum: 17 },
-      { name: "单簧管 Level1", type: 4, img: "https://oss.dayaedu.com/gyt/courseware/1698395308069.png", id: 1000097, courseNum: 17 }
-   ],
-   [
-      { name: "上低音号 Level1", type: 15, img: "https://oss.dayaedu.com/gyt/courseware/1698395289499.png", id: 1000096, courseNum: 17 },
-      { name: "长号 Level1", type: 14, img: "https://oss.dayaedu.com/gyt/courseware/1698395272103.png", id: 1000095, courseNum: 17 },
-      { name: "圆号 Level1", type: 13, img: "https://oss.dayaedu.com/gyt/courseware/1698395254028.png", id: 1000093, courseNum: 17 }
-   ],
-   [
-      { name: "小号 Level1", type: 12, img: "https://oss.dayaedu.com/gyt/courseware/1698395236339.png", id: 1000092, courseNum: 17 },
-      { name: "长笛 Level1", type: 2, img: "https://oss.dayaedu.com/gyt/courseware/1698395178311.png", id: 1000091, courseNum: 17 },
-      { name: "乐理 Level1", type: 31, img: "https://oss.dayaedu.com/gyt/courseware/1698395130108.png", id: 1000071, courseNum: 16 }
-   ]
-]
+
+function chunkArray(array: any[], size: number) {
+   const result = []
+   for (let i = 0; i < array.length; i += size) {
+      result.push(array.slice(i, i + size))
+   }
+   return result
+}
 </script>
 
 <style lang="scss" scoped>
@@ -198,6 +243,15 @@ const listData = [
          }
       }
    }
+   &:deep(.empty) {
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      .el-empty__image {
+         width: 278px;
+      }
+   }
 }
 </style>
 <style lang="scss">

+ 36 - 0
src/views/curriculum/type.ts

@@ -0,0 +1,36 @@
+export enum classImgType { //Band:乐团课 vip:vip课 PRACTICE:网管课 DEMO:试听课 LIVE:直播课
+   SINGLE = "Band",
+   MIX = "Band",
+   HIGH = "Band",
+   COMPREHENSIVE = "Band",
+   ENLIGHTENMENT = "Band",
+   TRAINING = "Band",
+   TRAINING_SINGLE = "Band",
+   TRAINING_MIX = "Band",
+   CLASSROOM = "Band",
+   HIGH_ONLINE = "Band",
+   MUSIC_NETWORK = "Band",
+   VIP = "Vip",
+   COMM = "Vip",
+   PRACTICE = "PRACTICE",
+   DEMO = "DEMO",
+   LIVE = "LIVE"
+}
+export enum classNameType { //Band:乐团课 vip:vip课 PRACTICE:网管课 DEMO:试听课 LIVE:直播课
+   SINGLE = "乐团课",
+   MIX = "乐团课",
+   HIGH = "乐团课",
+   COMPREHENSIVE = "乐团课",
+   ENLIGHTENMENT = "乐团课",
+   TRAINING = "乐团课",
+   TRAINING_SINGLE = "乐团课",
+   TRAINING_MIX = "乐团课",
+   CLASSROOM = "乐团课",
+   HIGH_ONLINE = "乐团课",
+   MUSIC_NETWORK = "乐团课",
+   VIP = "VIP课",
+   COMM = "VIP课",
+   PRACTICE = "网管课",
+   DEMO = "试听课",
+   LIVE = "直播课"
+}

+ 30 - 71
src/views/homePage/components/curriculum/curriculum_gym.vue

@@ -13,7 +13,7 @@
          <div class="operateBox">
             <template v-if="classData.status === 'UNDERWAY' && !classData.coursewareDetailId">
                <img class="dangerImg" src="@/img/curriculum/jg.png" />
-               <div class="operateBtn">配置课件</div>
+               <div class="operateBtn" @click="handleSetUpCourseware(classData.id)">配置课件</div>
             </template>
             <template v-else-if="classData.status === 'NOT_START'">
                <div class="noStart">未开始</div>
@@ -83,7 +83,7 @@
          </div>
       </div>
       <div class="btnCon">
-         <div class="btnDetail">查看详情</div>
+         <div class="btnDetail" @click="handleClickDetail(classData.id)">查看详情</div>
          <div class="btnGoClass" v-if="classData.status === 'UNDERWAY'" @click="handleStartClass(classData.id)">开始上课</div>
       </div>
    </div>
@@ -91,80 +91,39 @@
 
 <script setup lang="ts">
 import { format } from "@/libs/tools"
-import { getRecentCourseSchedule_gym } from "@/api/homePage.api"
-import { httpAjaxErrMsg } from "@/plugin/httpAjax"
-import useDialogConfirm from "@/hooks/useDialogConfirm"
+import { useCurriculumDetail, useSetUpCourseware } from "@/views/curriculum"
+import { handleStartClass_gym, isONLINE_gym } from "@/views/curriculum/hooks/useStartClass"
+import { classImgType, classNameType } from "@/views/curriculum/type"
 
-defineProps<{
+const props = defineProps<{
    classData: Record<string, any>
 }>()
+const emits = defineEmits<{
+   (e: "update"): void
+}>()
 
-enum classImgType { //Band:乐团课 vip:vip课 PRACTICE:网管课 DEMO:试听课 LIVE:直播课
-   SINGLE = "Band",
-   MIX = "Band",
-   HIGH = "Band",
-   COMPREHENSIVE = "Band",
-   ENLIGHTENMENT = "Band",
-   TRAINING = "Band",
-   TRAINING_SINGLE = "Band",
-   TRAINING_MIX = "Band",
-   CLASSROOM = "Band",
-   HIGH_ONLINE = "Band",
-   MUSIC_NETWORK = "Band",
-   VIP = "Vip",
-   COMM = "Vip",
-   PRACTICE = "PRACTICE",
-   DEMO = "DEMO",
-   LIVE = "LIVE"
-}
-enum classNameType { //Band:乐团课 vip:vip课 PRACTICE:网管课 DEMO:试听课 LIVE:直播课
-   SINGLE = "乐团课",
-   MIX = "乐团课",
-   HIGH = "乐团课",
-   COMPREHENSIVE = "乐团课",
-   ENLIGHTENMENT = "乐团课",
-   TRAINING = "乐团课",
-   TRAINING_SINGLE = "乐团课",
-   TRAINING_MIX = "乐团课",
-   CLASSROOM = "乐团课",
-   HIGH_ONLINE = "乐团课",
-   MUSIC_NETWORK = "乐团课",
-   VIP = "VIP课",
-   COMM = "VIP课",
-   PRACTICE = "网管课",
-   DEMO = "试听课",
-   LIVE = "直播课"
+// 开始上课
+function handleStartClass(id: string) {
+   if (isONLINE_gym(props.classData.teachMode)) {
+      return
+   }
+   handleStartClass_gym(id)
 }
 
-function handleStartClass(id: string) {
-   httpAjaxErrMsg(getRecentCourseSchedule_gym, id).then(res => {
-      if (res.code === 200) {
-         const { signInStatusEnum, isCallNames, coursewareDetailId, startClassTime, endClassTime } = res.data
-         if (signInStatusEnum === 3) {
-            useDialogConfirm({
-               headImg: require("@/img/curriculum/ts2.png"),
-               text: `您当前${format(startClassTime, "hh:ii")}-${format(endClassTime, "hh:ii")}的课程暂未签到,为避免考勤异常,请到APP进行签到。`,
-               btnShow: [true]
-            })
-            return
-         }
-         if (!isCallNames) {
-            useDialogConfirm({
-               headImg: require("@/img/curriculum/ts1.png"),
-               text: `您当前${format(startClassTime, "hh:ii")}-${format(endClassTime, "hh:ii")}的课程暂未点名,请到APP进行点名。`,
-               btnShow: [true]
-            })
-            return
-         }
-         if (!coursewareDetailId) {
-            useDialogConfirm({
-               headImg: require("@/img/curriculum/ts3.png"),
-               text: `该课程未配置课件,请配置课件。`,
-               btnShow: [true]
-            })
-            return
-         }
-      }
+//查看详情
+function handleClickDetail(id: string) {
+   if (isONLINE_gym(props.classData.teachMode)) {
+      return
+   }
+   useCurriculumDetail(id)
+}
+// 配置课表
+function handleSetUpCourseware(id: string) {
+   if (isONLINE_gym(props.classData.teachMode)) {
+      return
+   }
+   useSetUpCourseware(id, () => {
+      emits("update")
    })
 }
 </script>
@@ -220,7 +179,7 @@ function handleStartClass(id: string) {
          }
          .end {
             font-weight: 500;
-            font-size: 20px;
+            font-size: 24px;
             color: #aaaaaa;
          }
       }

+ 19 - 35
src/views/homePage/components/curriculum/curriculum_gyt.vue

@@ -13,7 +13,7 @@
          <div class="operateBox">
             <template v-if="classData.status === 'ING' && !classData.lessonCoursewareId">
                <img class="dangerImg" src="@/img/curriculum/jg.png" />
-               <div class="operateBtn">配置课件</div>
+               <div class="operateBtn" @click="handleSetUpCourseware(classData.id)">配置课件</div>
             </template>
             <template v-else-if="classData.status === 'NOT_START'">
                <div class="noStart">未开始</div>
@@ -46,7 +46,7 @@
          </div>
       </div>
       <div class="btnCon">
-         <div class="btnDetail">查看详情</div>
+         <div class="btnDetail" @click="handleClickDetail(classData.id)">查看详情</div>
          <div class="btnGoClass" v-if="classData.status === 'ING'" @click="handleStartClass(classData.id)">开始上课</div>
       </div>
    </div>
@@ -54,43 +54,27 @@
 
 <script setup lang="ts">
 import { format } from "@/libs/tools"
-import { getCourseScheduleDetail_gyt } from "@/api/curriculum.api"
-import { httpAjaxErrMsg } from "@/plugin/httpAjax"
-import useDialogConfirm from "@/hooks/useDialogConfirm"
-
+import { useCurriculumDetail, useSetUpCourseware } from "@/views/curriculum"
+import { handleStartClass_gyt } from "@/views/curriculum/hooks/useStartClass"
+const emits = defineEmits<{
+   (e: "update"): void
+}>()
 defineProps<{
    classData: Record<string, any>
 }>()
 
+// 开始上课
 function handleStartClass(id: string) {
-   httpAjaxErrMsg(getCourseScheduleDetail_gyt, id).then(res => {
-      if (res.code === 200) {
-         const { signIn, rollCall, lessonCoursewareId, startTime, endTime } = res.data
-         if (!signIn) {
-            useDialogConfirm({
-               headImg: require("@/img/curriculum/ts2.png"),
-               text: `您当前${format(startTime, "hh:ii")}-${format(endTime, "hh:ii")}的课程暂未签到,为避免考勤异常,请到APP进行签到。`,
-               btnShow: [true]
-            })
-            return
-         }
-         if (!rollCall) {
-            useDialogConfirm({
-               headImg: require("@/img/curriculum/ts1.png"),
-               text: `您当前${format(startTime, "hh:ii")}-${format(endTime, "hh:ii")}的课程暂未点名,请到APP进行点名。`,
-               btnShow: [true]
-            })
-            return
-         }
-         if (!lessonCoursewareId) {
-            useDialogConfirm({
-               headImg: require("@/img/curriculum/ts3.png"),
-               text: `该课程未配置课件,请配置课件。`,
-               btnShow: [true]
-            })
-            return
-         }
-      }
+   handleStartClass_gyt(id)
+}
+//查看详情
+function handleClickDetail(id: string) {
+   useCurriculumDetail(id)
+}
+// 配置课表
+function handleSetUpCourseware(id: string) {
+   useSetUpCourseware(id, () => {
+      emits("update")
    })
 }
 </script>
@@ -146,7 +130,7 @@ function handleStartClass(id: string) {
          }
          .end {
             font-weight: 500;
-            font-size: 20px;
+            font-size: 24px;
             color: #aaaaaa;
          }
       }

+ 2 - 0
src/views/homePage/homePage.vue

@@ -44,6 +44,7 @@
                            v-if="!isEmptyClassData"
                            :classData="classData"
                            :is="userStoreHook.roles === 'GYM' ? curriculum_gym : curriculum_gyt"
+                           @update="handleClassData"
                         />
                         <el-empty v-else class="empty" :image="require('@/img/layout/empty1.png')" description="您还没有待上课程哦~" />
                      </template>
@@ -141,6 +142,7 @@ const classTypes_gyt = [
    }
 ]
 
+/* 下次课程信息 */
 const classData = ref<Record<string, any>>({})
 const classDataLoading = ref(true)
 const isEmptyClassData = computed(() => {