Sfoglia il codice sorgente

Merge branch 'iteration-20240701-classroom'

lex 10 mesi fa
parent
commit
40fc1d276f

+ 39 - 38
.eslintrc.js

@@ -1,38 +1,39 @@
-module.exports = {
-   root: true,
-   env: {
-      node: true
-   },
-   extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/typescript/recommended", "plugin:prettier/recommended"],
-   parserOptions: {
-      ecmaVersion: 2020
-   },
-   //配置
-   rules: {
-      "prettier/prettier": "error",
-      "no-debugger": process.env.NODE_ENV == "production" ? 2 : 1,
-      "no-unreachable": process.env.NODE_ENV == "production" ? 2 : 1, //return 警告不报错
-      "no-undef": "off", // 没有声明的变量
-      "vue/no-v-html": "off",
-      "no-irregular-whitespace": "off",
-      "vue/html-self-closing": [
-         "error",
-         {
-            html: {
-               void: "always",
-               normal: "never",
-               component: "always"
-            },
-            svg: "always",
-            math: "always"
-         }
-      ],
-      "vue/multi-word-component-names": "off", // 关闭驼峰命名
-      /* ts相关 */
-      "@typescript-eslint/no-empty-function": "off", // 可以为空函数
-      "@typescript-eslint/explicit-module-boundary-types": "off", //函数不需要返回类型也可以
-      "@typescript-eslint/no-explicit-any": "off", //可以为any
-      "@typescript-eslint/no-non-null-assertion": "off", //! 非空断言
-      "@typescript-eslint/no-this-alias": "off" //忽略this关键字
-   }
-}
+module.exports = {
+   root: true,
+   env: {
+      node: true
+   },
+   extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/typescript/recommended", "plugin:prettier/recommended"],
+   parserOptions: {
+      ecmaVersion: 2020
+   },
+   //配置
+   rules: {
+      // "prettier/prettier": "error",
+      "prettier/prettier": ["error", { endOfLine: "auto" }],
+      "no-debugger": process.env.NODE_ENV == "production" ? 2 : 1,
+      "no-unreachable": process.env.NODE_ENV == "production" ? 2 : 1, //return 警告不报错
+      "no-undef": "off", // 没有声明的变量
+      "vue/no-v-html": "off",
+      "no-irregular-whitespace": "off",
+      "vue/html-self-closing": [
+         "error",
+         {
+            html: {
+               void: "always",
+               normal: "never",
+               component: "always"
+            },
+            svg: "always",
+            math: "always"
+         }
+      ],
+      "vue/multi-word-component-names": "off", // 关闭驼峰命名
+      /* ts相关 */
+      "@typescript-eslint/no-empty-function": "off", // 可以为空函数
+      "@typescript-eslint/explicit-module-boundary-types": "off", //函数不需要返回类型也可以
+      "@typescript-eslint/no-explicit-any": "off", //可以为any
+      "@typescript-eslint/no-non-null-assertion": "off", //! 非空断言
+      "@typescript-eslint/no-this-alias": "off" //忽略this关键字
+   }
+}

+ 127 - 109
src/plugin/modalFrame/modalFrame.scss

@@ -1,109 +1,127 @@
-.bounceModalFrame-enter-active {
-   animation: bounce-in 0.2s;
-   .animationBox {
-      animation: bounce-in-box 0.2s;
-   }
-}
-
-.bounceModalFrame-leave-active {
-   animation: bounce-out 0.2s;
-   .animationBox {
-      animation: bounce-out-box 0.2s;
-   }
-}
-
-@keyframes bounce-in {
-   0% {
-      opacity: 0;
-   }
-   100% {
-      opacity: 1;
-   }
-}
-@keyframes bounce-out {
-   0% {
-      opacity: 1;
-   }
-   100% {
-      opacity: 0;
-   }
-}
-
-@keyframes bounce-in-box {
-   0% {
-      transform: translate(0, -30px);
-   }
-   100% {
-      transform: translate(0, 0);
-   }
-}
-@keyframes bounce-out-box {
-   0% {
-      transform: translate(0, 0);
-   }
-   100% {
-      transform: translate(0, -30px);
-   }
-}
-.h-modalFrame {
-   --modalFrameTitHeight: 40px;
-   --modalFrameBtnHeight: 50px;
-   position: fixed;
-   top: 0;
-   left: 0;
-   width: 100%;
-   height: 100%;
-   z-index: 1234567;
-   background-color: $overlay-color-lighter;
-   .animationBox {
-      width: 100%;
-      height: 100%;
-   }
-   .modalFrameBox {
-      background-color: $bg-color;
-      box-shadow: $box-shadow-light;
-      border-radius: 4px;
-      /*modalFrameTitle*/
-      .modalFrameTitle {
-         display: flex;
-         justify-content: space-between;
-         align-items: center;
-         padding: 0 20px;
-         width: 100%;
-         height: var(--modalFrameTitHeight);
-         border-bottom: 1px solid $border-color-lighter;
-         font-size: $font-size-medium;
-         color: $text-color-primary;
-         cursor: move;
-         &.noMove {
-            cursor: auto;
-         }
-         .icon {
-            font-size: 24px;
-            color: $text-color-regular;
-            cursor: pointer;
-            &:hover {
-               opacity: $opacity-hover;
-            }
-         }
-      }
-      /*frameBox*/
-      .frameBox {
-         width: 100%;
-         height: calc(100% - (var(--modalFrameTitHeight) + var(--modalFrameBtnHeight)));
-         overflow: hidden;
-      }
-      .frameBox.frameBtnNone {
-         height: calc(100% - var(--modalFrameTitHeight));
-      }
-      /*frameBtn*/
-      .frameBtn {
-         padding: 0 20px;
-         width: 100%;
-         height: var(--modalFrameBtnHeight);
-         display: flex;
-         justify-content: flex-end;
-         align-items: center;
-      }
-   }
-}
+.bounceModalFrame-enter-active {
+   animation: bounce-in 0.2s;
+
+   .animationBox {
+      animation: bounce-in-box 0.2s;
+   }
+}
+
+.bounceModalFrame-leave-active {
+   animation: bounce-out 0.2s;
+
+   .animationBox {
+      animation: bounce-out-box 0.2s;
+   }
+}
+
+@keyframes bounce-in {
+   0% {
+      opacity: 0;
+   }
+
+   100% {
+      opacity: 1;
+   }
+}
+
+@keyframes bounce-out {
+   0% {
+      opacity: 1;
+   }
+
+   100% {
+      opacity: 0;
+   }
+}
+
+@keyframes bounce-in-box {
+   0% {
+      transform: translate(0, -30px);
+   }
+
+   100% {
+      transform: translate(0, 0);
+   }
+}
+
+@keyframes bounce-out-box {
+   0% {
+      transform: translate(0, 0);
+   }
+
+   100% {
+      transform: translate(0, -30px);
+   }
+}
+
+.h-modalFrame {
+   --modalFrameTitHeight: 40px;
+   --modalFrameBtnHeight: 50px;
+   position: fixed;
+   top: 0;
+   left: 0;
+   width: 100%;
+   height: 100%;
+   z-index: 1234567;
+   background-color: $overlay-color-lighter;
+
+   .animationBox {
+      width: 100%;
+      height: 100%;
+   }
+
+   .modalFrameBox {
+      background-color: $bg-color;
+      box-shadow: $box-shadow-light;
+      border-radius: 4px;
+
+      /*modalFrameTitle*/
+      .modalFrameTitle {
+         display: flex;
+         justify-content: space-between;
+         align-items: center;
+         padding: 0 20px;
+         width: 100%;
+         height: var(--modalFrameTitHeight);
+         border-bottom: 1px solid $border-color-lighter;
+         font-size: $font-size-medium;
+         color: $text-color-primary;
+         cursor: move;
+
+         &.noMove {
+            cursor: auto;
+         }
+
+         .icon {
+            font-size: 24px;
+            color: $text-color-regular;
+            cursor: pointer;
+
+            &:hover {
+               opacity: $opacity-hover;
+            }
+         }
+      }
+
+      /*frameBox*/
+      .frameBox {
+         width: 100%;
+         height: calc(100% - (var(--modalFrameTitHeight) + var(--modalFrameBtnHeight)));
+         overflow: hidden;
+      }
+
+      .frameBox.frameBtnNone {
+         height: calc(100% - var(--modalFrameTitHeight));
+      }
+
+      /*frameBtn*/
+      .frameBtn {
+         padding: 0 20px;
+         width: 100%;
+         height: var(--modalFrameBtnHeight);
+         display: flex;
+         justify-content: flex-end;
+         align-items: center;
+      }
+   }
+}

+ 331 - 317
src/views/curriculum/components/curriculumList/curriculumList_gym.vue

@@ -1,317 +1,331 @@
-<!--
-* @FileDescription: 管乐迷课表list
-* @Author: 黄琪勇
-* @Date:2024-03-29 15:29:06
--->
-<template>
-   <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">
-               {{ item.classDate && format(item.classDate) }} {{ item.startClassTime && format(item.startClassTime, "hh:ii") }}-{{
-                  item.endClassTime && format(item.endClassTime, "hh:ii")
-               }}
-            </div>
-         </div>
-         <div class="operateBox">
-            <template v-if="item.status === 'UNDERWAY' && !item.coursewareDetailId && item.teachMode !== 'ONLINE'">
-               <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="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="`${classNameType[item.type as keyof typeof classNameType]}·${item.name}`" />
-            </div>
-         </div>
-         <div class="rightCon">
-            <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>
-            <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>
-      <div class="endCon">
-         <div class="addressCon">
-            <div class="adressBox">
-               <div>上课地点:</div>
-               <div class="adress">
-                  <ellipsisScroll :title="item.teachMode === 'ONLINE' ? '网络教室' : item.schoolName" />
-               </div>
-            </div>
-            <div class="adressBox">
-               <div>上课学生:</div>
-               <div class="adress">
-                  <ellipsisScroll :title="item.studentNames" />
-               </div>
-            </div>
-         </div>
-         <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>
-      </div>
-   </div>
-</template>
-
-<script setup lang="ts">
-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(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>
-
-<style lang="scss" scoped>
-.curriculumList_gym {
-   background: #ffffff;
-   border-radius: 35px;
-   padding: 0 30px;
-   margin-bottom: 18px;
-   cursor: pointer;
-   &:last-child {
-      margin-bottom: 0;
-   }
-   .head {
-      padding: 20px 0 16px 0;
-      border-bottom: 1px solid #eaeaea;
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      .timeBox {
-         display: flex;
-         align-items: center;
-         .timeImg {
-            width: 24px;
-            height: 24px;
-         }
-         .time {
-            margin-left: 6px;
-            font-weight: 500;
-            font-size: 22px;
-            color: #777777;
-         }
-      }
-      .operateBox {
-         display: flex;
-         align-items: center;
-         .dangerImg {
-            width: 22px;
-            height: 22px;
-         }
-         .operateBtn {
-            margin-left: 8px;
-            font-weight: 500;
-            font-size: 20px;
-            color: #f44541;
-            cursor: pointer;
-            &:hover {
-               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 {
-      margin-top: 30px;
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      .leftCon {
-         flex-grow: 1;
-         display: flex;
-         align-items: center;
-         overflow: hidden;
-         .xxImg {
-            flex-shrink: 0;
-            width: 46px;
-            height: 24px;
-         }
-         .typeImg {
-            flex-shrink: 0;
-            margin-left: 6px;
-            width: 55px;
-            height: 24px;
-         }
-         .className {
-            flex-grow: 1;
-            overflow: hidden;
-            margin-left: 6px;
-            font-weight: 600;
-            font-size: 24px;
-            color: #333333;
-         }
-      }
-      .rightCon {
-         display: flex;
-         align-items: center;
-         flex-shrink: 0;
-         & > img {
-            width: 22px;
-            height: 22px;
-         }
-         & > div {
-            margin-left: 6px;
-            font-weight: 500;
-            font-size: 20px;
-            color: #aaaaaa;
-            &.signIn,
-            &.signOut {
-               color: #01c199;
-            }
-            &.abnormalSignIn,
-            &.abnormalSignOut {
-               color: #ff0000;
-            }
-         }
-         .qtImg {
-            margin-left: 34px;
-         }
-      }
-   }
-   .endCon {
-      margin-top: 26px;
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      padding-bottom: 22px;
-      .addressCon {
-         flex-grow: 1;
-         overflow: hidden;
-         padding-right: 56px;
-         & > div {
-            font-weight: 500;
-            font-size: 16px;
-            color: #777777;
-         }
-         & > div:nth-child(2) {
-            margin-top: 16px;
-         }
-         .adressBox {
-            display: flex;
-            align-items: center;
-            & > div:nth-child(1) {
-               flex-shrink: 0;
-            }
-            .adress {
-               flex-grow: 1;
-               overflow: hidden;
-            }
-         }
-      }
-      .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;
-         cursor: pointer;
-         &:hover {
-            opacity: $opacity-hover;
-         }
-         & > div {
-            font-weight: 500;
-            font-size: 20px;
-            color: #f67146;
-         }
-         .jtImg {
-            margin-left: 6px;
-            width: 6px;
-            height: 13px;
-         }
-      }
-   }
-}
-</style>
+<!--
+* @FileDescription: 管乐迷课表list
+* @Author: 黄琪勇
+* @Date:2024-03-29 15:29:06
+-->
+<template>
+   <div
+      class="curriculumList_gym"
+      v-for="item in props.curriculumData"
+      :key="item.id"
+      @click="handleClickDetail(item.id, item.teachMode, item.coursewareEnable)"
+   >
+      <div class="head">
+         <div class="timeBox">
+            <img class="timeImg" src="@/img/curriculum/sj.png" />
+            <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 class="operateBox">
+            <template v-if="item.status === 'UNDERWAY' && !item.coursewareDetailId && item.teachMode !== 'ONLINE'">
+               <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="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="`${classNameType[item.type as keyof typeof classNameType]}·${item.name}`" />
+            </div>
+         </div>
+         <div class="rightCon">
+            <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>
+            <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>
+      <div class="endCon">
+         <div class="addressCon">
+            <div class="adressBox">
+               <div>上课地点:</div>
+               <div class="adress">
+                  <ellipsisScroll :title="item.teachMode === 'ONLINE' ? '网络教室' : item.schoolName" />
+               </div>
+            </div>
+            <div class="adressBox">
+               <div>上课学生:</div>
+               <div class="adress">
+                  <ellipsisScroll :title="item.studentNames" />
+               </div>
+            </div>
+         </div>
+         <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, item.coursewareEnable)">
+            <div>查看详情</div>
+            <img class="jtImg" src="@/img/curriculum/jt.png" />
+         </div>
+      </div>
+   </div>
+</template>
+
+<script setup lang="ts">
+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"
+import useDialogConfirm from "@/hooks/useDialogConfirm"
+
+const props = defineProps<{
+   curriculumData: any[]
+}>()
+const emits = defineEmits<{
+   (e: "update"): void
+}>()
+
+//查看详情
+function handleClickDetail(id: string, teachMode: string, coursewareEnable: boolean) {
+   if (isONLINE_gym(teachMode)) {
+      return
+   }
+   if (!coursewareEnable) {
+      useDialogConfirm({
+         headImg: require("@/img/curriculum/ts4.png"),
+         text: `该资源已失效`,
+         btnShow: [true]
+      })
+      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>
+
+<style lang="scss" scoped>
+.curriculumList_gym {
+   background: #ffffff;
+   border-radius: 35px;
+   padding: 0 30px;
+   margin-bottom: 18px;
+   cursor: pointer;
+   &:last-child {
+      margin-bottom: 0;
+   }
+   .head {
+      padding: 20px 0 16px 0;
+      border-bottom: 1px solid #eaeaea;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      .timeBox {
+         display: flex;
+         align-items: center;
+         .timeImg {
+            width: 24px;
+            height: 24px;
+         }
+         .time {
+            margin-left: 6px;
+            font-weight: 500;
+            font-size: 22px;
+            color: #777777;
+         }
+      }
+      .operateBox {
+         display: flex;
+         align-items: center;
+         .dangerImg {
+            width: 22px;
+            height: 22px;
+         }
+         .operateBtn {
+            margin-left: 8px;
+            font-weight: 500;
+            font-size: 20px;
+            color: #f44541;
+            cursor: pointer;
+            &:hover {
+               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 {
+      margin-top: 30px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      .leftCon {
+         flex-grow: 1;
+         display: flex;
+         align-items: center;
+         overflow: hidden;
+         .xxImg {
+            flex-shrink: 0;
+            width: 46px;
+            height: 24px;
+         }
+         .typeImg {
+            flex-shrink: 0;
+            margin-left: 6px;
+            width: 55px;
+            height: 24px;
+         }
+         .className {
+            flex-grow: 1;
+            overflow: hidden;
+            margin-left: 6px;
+            font-weight: 600;
+            font-size: 24px;
+            color: #333333;
+         }
+      }
+      .rightCon {
+         display: flex;
+         align-items: center;
+         flex-shrink: 0;
+         & > img {
+            width: 22px;
+            height: 22px;
+         }
+         & > div {
+            margin-left: 6px;
+            font-weight: 500;
+            font-size: 20px;
+            color: #aaaaaa;
+            &.signIn,
+            &.signOut {
+               color: #01c199;
+            }
+            &.abnormalSignIn,
+            &.abnormalSignOut {
+               color: #ff0000;
+            }
+         }
+         .qtImg {
+            margin-left: 34px;
+         }
+      }
+   }
+   .endCon {
+      margin-top: 26px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding-bottom: 22px;
+      .addressCon {
+         flex-grow: 1;
+         overflow: hidden;
+         padding-right: 56px;
+         & > div {
+            font-weight: 500;
+            font-size: 16px;
+            color: #777777;
+         }
+         & > div:nth-child(2) {
+            margin-top: 16px;
+         }
+         .adressBox {
+            display: flex;
+            align-items: center;
+            & > div:nth-child(1) {
+               flex-shrink: 0;
+            }
+            .adress {
+               flex-grow: 1;
+               overflow: hidden;
+            }
+         }
+      }
+      .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;
+         cursor: pointer;
+         &:hover {
+            opacity: $opacity-hover;
+         }
+         & > div {
+            font-weight: 500;
+            font-size: 20px;
+            color: #f67146;
+         }
+         .jtImg {
+            margin-left: 6px;
+            width: 6px;
+            height: 13px;
+         }
+      }
+   }
+}
+</style>

+ 250 - 241
src/views/curriculum/components/curriculumList/curriculumList_gyt.vue

@@ -1,241 +1,250 @@
-<!--
-* @FileDescription: 管乐团课表list
-* @Author: 黄琪勇
-* @Date:2024-03-29 15:29:06
--->
-<template>
-   <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">{{ item.classDate && format(item.classDate) }}</div>
-         </div>
-         <div class="operateBox">
-            <template v-if="item.coursewareFlag && !item.lessonCoursewareId && item.status !== 'COMPLETE'">
-               <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">{{ item.startTime && format(item.startTime, "hh:ii") }}-{{ item.endTime && format(item.endTime, "hh:ii") }}</div>
-         <div class="rightCon">
-            <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"><ellipsisScroll :title="`${item.className}-${item.teacherName}`" /></div>
-            <div><ellipsisScroll :title="item.orchestraName" /></div>
-         </div>
-         <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>
-      </div>
-   </div>
-</template>
-
-<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 {
-   background: #ffffff;
-   border-radius: 35px;
-   padding: 0 30px;
-   margin-bottom: 18px;
-   cursor: pointer;
-   &:last-child {
-      margin-bottom: 0;
-   }
-   .head {
-      padding: 20px 0 16px 0;
-      border-bottom: 1px solid #eaeaea;
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      .timeBox {
-         display: flex;
-         align-items: center;
-         .timeImg {
-            width: 24px;
-            height: 24px;
-         }
-         .time {
-            margin-left: 6px;
-            font-weight: 500;
-            font-size: 22px;
-            color: #777777;
-         }
-      }
-      .operateBox {
-         display: flex;
-         align-items: center;
-         .dangerImg {
-            width: 22px;
-            height: 22px;
-         }
-         .operateBtn {
-            margin-left: 8px;
-            font-weight: 500;
-            font-size: 20px;
-            color: #f44541;
-            cursor: pointer;
-            &:hover {
-               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 {
-      margin-top: 24px;
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      .leftCon {
-         flex-grow: 1;
-         font-family: DINAlternate, DINAlternate;
-         font-weight: bold;
-         font-size: 38px;
-         color: #333333;
-         overflow: hidden;
-      }
-      .rightCon {
-         display: flex;
-         align-items: center;
-         flex-shrink: 0;
-         & > img {
-            width: 22px;
-            height: 22px;
-         }
-         & > div {
-            margin-left: 6px;
-            font-weight: 500;
-            font-size: 20px;
-            color: #aaaaaa;
-            &.signIn,
-            &.signOut {
-               color: #01c199;
-            }
-         }
-         .qtImg {
-            margin-left: 34px;
-         }
-      }
-   }
-   .endCon {
-      margin-top: 18px;
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      padding-bottom: 22px;
-      .addressCon {
-         flex-grow: 1;
-         overflow: hidden;
-         & > div {
-            font-weight: 500;
-            font-size: 16px;
-            color: #777777;
-         }
-         & > div:nth-child(2) {
-            margin-right: 116px;
-            overflow: hidden;
-            margin-top: 12px;
-         }
-         .adressBox {
-            margin-right: 56px;
-            overflow: hidden;
-            font-weight: 600;
-            font-size: 20px;
-            color: #333333;
-         }
-      }
-      .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;
-         cursor: pointer;
-         &:hover {
-            opacity: $opacity-hover;
-         }
-         & > div {
-            font-weight: 500;
-            font-size: 20px;
-            color: #f67146;
-         }
-         .jtImg {
-            margin-left: 6px;
-            width: 6px;
-            height: 13px;
-         }
-      }
-   }
-}
-</style>
+<!--
+* @FileDescription: 管乐团课表list
+* @Author: 黄琪勇
+* @Date:2024-03-29 15:29:06
+-->
+<template>
+   <div class="curriculumList_gyt" v-for="item in props.curriculumData" :key="item.id" @click="handleClickDetail(item.id, item)">
+      <div class="head">
+         <div class="timeBox">
+            <img class="timeImg" src="@/img/curriculum/sj.png" />
+            <div class="time">{{ item.classDate && format(item.classDate) }}</div>
+         </div>
+         <div class="operateBox">
+            <template v-if="item.coursewareFlag && !item.lessonCoursewareId && item.status !== 'COMPLETE'">
+               <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">{{ item.startTime && format(item.startTime, "hh:ii") }}-{{ item.endTime && format(item.endTime, "hh:ii") }}</div>
+         <div class="rightCon">
+            <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"><ellipsisScroll :title="`${item.className}-${item.teacherName}`" /></div>
+            <div><ellipsisScroll :title="item.orchestraName" /></div>
+         </div>
+         <div class="btnGoClass" v-if="item.status === 'ING'" @click.stop="handleStartClass(item.id)">开始上课</div>
+         <div class="btnDetail" v-else @click.stop="handleClickDetail(item.id, item)">
+            <div>查看详情</div>
+            <img class="jtImg" src="@/img/curriculum/jt.png" />
+         </div>
+      </div>
+   </div>
+</template>
+
+<script setup lang="ts">
+import useDialogConfirm from "@/hooks/useDialogConfirm"
+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, item: any) {
+   if (!item.applyStatus && item.status !== "ING") {
+      useDialogConfirm({
+         headImg: require("@/img/curriculum/ts4.png"),
+         text: `该资源已失效`,
+         btnShow: [true]
+      })
+      return
+   }
+   useCurriculumDetail(id)
+}
+// 配置课表
+function handleSetUpCourseware(id: string) {
+   useSetUpCourseware(id, () => {
+      emits("update")
+   })
+}
+</script>
+
+<style lang="scss" scoped>
+.curriculumList_gyt {
+   background: #ffffff;
+   border-radius: 35px;
+   padding: 0 30px;
+   margin-bottom: 18px;
+   cursor: pointer;
+   &:last-child {
+      margin-bottom: 0;
+   }
+   .head {
+      padding: 20px 0 16px 0;
+      border-bottom: 1px solid #eaeaea;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      .timeBox {
+         display: flex;
+         align-items: center;
+         .timeImg {
+            width: 24px;
+            height: 24px;
+         }
+         .time {
+            margin-left: 6px;
+            font-weight: 500;
+            font-size: 22px;
+            color: #777777;
+         }
+      }
+      .operateBox {
+         display: flex;
+         align-items: center;
+         .dangerImg {
+            width: 22px;
+            height: 22px;
+         }
+         .operateBtn {
+            margin-left: 8px;
+            font-weight: 500;
+            font-size: 20px;
+            color: #f44541;
+            cursor: pointer;
+            &:hover {
+               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 {
+      margin-top: 24px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      .leftCon {
+         flex-grow: 1;
+         font-family: DINAlternate, DINAlternate;
+         font-weight: bold;
+         font-size: 38px;
+         color: #333333;
+         overflow: hidden;
+      }
+      .rightCon {
+         display: flex;
+         align-items: center;
+         flex-shrink: 0;
+         & > img {
+            width: 22px;
+            height: 22px;
+         }
+         & > div {
+            margin-left: 6px;
+            font-weight: 500;
+            font-size: 20px;
+            color: #aaaaaa;
+            &.signIn,
+            &.signOut {
+               color: #01c199;
+            }
+         }
+         .qtImg {
+            margin-left: 34px;
+         }
+      }
+   }
+   .endCon {
+      margin-top: 18px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding-bottom: 22px;
+      .addressCon {
+         flex-grow: 1;
+         overflow: hidden;
+         & > div {
+            font-weight: 500;
+            font-size: 16px;
+            color: #777777;
+         }
+         & > div:nth-child(2) {
+            margin-right: 116px;
+            overflow: hidden;
+            margin-top: 12px;
+         }
+         .adressBox {
+            margin-right: 56px;
+            overflow: hidden;
+            font-weight: 600;
+            font-size: 20px;
+            color: #333333;
+         }
+      }
+      .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;
+         cursor: pointer;
+         &:hover {
+            opacity: $opacity-hover;
+         }
+         & > div {
+            font-weight: 500;
+            font-size: 20px;
+            color: #f67146;
+         }
+         .jtImg {
+            margin-left: 6px;
+            width: 6px;
+            height: 13px;
+         }
+      }
+   }
+}
+</style>

+ 409 - 409
src/views/curriculum/curriculumDetail.vue

@@ -1,409 +1,409 @@
-<!--
-* @FileDescription: 课程详情
-* @Author: 黄琪勇
-* @Date:2024-04-01 16:27:48
--->
-<template>
-   <div class="curriculumDetail">
-      <div class="close" @click="close"></div>
-      <div v-loading="loading" class="curriculumDetailCon">
-         <img class="imgMid" src="@/img/curriculum/mid.png" />
-         <div class="curriculumDetailBox">
-            <div class="teachingObjectives">
-               <div class="head">
-                  <div class="leftTit">
-                     <img src="@/img/curriculum/jxmb.png" />
-                     <div>教学目标</div>
-                  </div>
-                  <div v-if="coursewareShow" 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 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>
-         <div class="curriculumDetailBox">
-            <div class="knowledgePoints">
-               <div class="head">
-                  <div class="points">
-                     <img src="@/img/curriculum/zsd.png" />
-                     <div>知识点</div>
-                  </div>
-               </div>
-               <div class="content">
-                  <ElScrollbar class="elScrollbar">
-                     <courseCollapse :courseList="curriculumDetailData.pointList" @handleClick="handleCourseClick" />
-                  </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" 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 { useSetUpCourseware } from "./index"
-import {
-   getCourseScheduleDetail_gyt,
-   getLessonCoursewareDetail_gyt,
-   getCurrentCourseDetail_gym,
-   getLessonCourseDetail_gym
-} from "@/api/curriculum.api"
-import { httpAjaxErrMsg } from "@/plugin/httpAjax"
-import { ref, shallowRef, computed } from "vue"
-import { handleStartClass_gyt, handleStartClass_gym, isONLINE_gym } from "./hooks/useStartClass"
-import userStore from "@/store/modules/user"
-import router from "@/router"
-
-const userStoreHook = userStore()
-const props = defineProps<{
-   modalData: {
-      id: string
-   }
-}>()
-const emits = defineEmits<{
-   (e: "onClose"): void
-}>()
-
-function close() {
-   emits("onClose")
-}
-const loading = ref(false)
-const statusVal = ref("") //课程状态 ING 和 UNDERWAY 代表可以上课
-const teachModeVal = ref("") //课程类型 ONLINE课的时候提示去app
-const coursewareFlagVal = ref(false) // 管乐团能否配置课件 coursewareFlag字段为true并且不是结束就能配置
-const coursewareShow = computed(() => {
-   if (userStoreHook.roles === "GYM") {
-      return statusVal.value === "UNDERWAY"
-   } else {
-      return coursewareFlagVal.value && statusVal.value !== "COMPLETE"
-   }
-})
-const curriculumDetailData = shallowRef<{
-   pointList: any[]
-   targetDesc: string
-   id: string
-}>({
-   pointList: [],
-   targetDesc: "",
-   id: ""
-})
-
-getCurriculumDetailData()
-function getCurriculumDetailData() {
-   userStoreHook.roles === "GYM" ? getCurriculumDetailData_gym() : getCurriculumDetailData_gyt()
-}
-/* 处理管乐迷 */
-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
-                  }
-               }
-            })
-         } else {
-            loading.value = false
-         }
-      } 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, coursewareFlag } = res.data || {}
-         statusVal.value = status
-         coursewareFlagVal.value = coursewareFlag
-         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
-         }
-      } 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) {
-   useSetUpCourseware(id, () => {
-      //选择课件成功后的回调
-      // 刷新数据
-      getCurriculumDetailData()
-   })
-}
-function handleCourseClick(item: any) {
-   const url = router.resolve({
-      name: "coursewarePlay",
-      params: { id: curriculumDetailData.value.id },
-      query: {
-         materialId: item.id
-      }
-   }).href
-   window.open(url, "_blank")
-}
-</script>
-
-<style lang="scss" scoped>
-.curriculumDetail {
-   width: 100%;
-   height: 100%;
-   padding: 20px 20px 30px 20px;
-   display: flex;
-   flex-direction: column;
-   .close {
-      position: absolute;
-      top: -9px;
-      right: -9px;
-      width: 47px;
-      height: 49px;
-      cursor: pointer;
-      background: url("@/img/useDialogConfirm/close.png") no-repeat;
-      background-size: cover;
-      z-index: 1;
-      &:hover {
-         background: url("@/img/useDialogConfirm/closeHover.png") no-repeat;
-         background-size: cover;
-      }
-   }
-   .curriculumDetailCon {
-      flex-grow: 1;
-      overflow: hidden;
-      display: flex;
-      position: relative;
-      & > :deep(.el-loading-mask) {
-         border-radius: 35px;
-      }
-      .imgMid {
-         width: 62px;
-         height: 470px;
-         position: absolute;
-         left: 50%;
-         top: 50%;
-         transform: translate(-50%, -50%);
-         z-index: 1;
-      }
-      .curriculumDetailBox {
-         width: 50%;
-         height: 100%;
-         background: #fff2e1;
-         border-radius: 35px;
-         padding: 10px;
-         overflow: hidden;
-         &:nth-child(3) {
-            margin-left: 10px;
-         }
-         .teachingObjectives,
-         .knowledgePoints {
-            width: 100%;
-            height: 100%;
-            background: #ffffff;
-            border-radius: 35px;
-            .content {
-               position: relative;
-               padding-top: 18px;
-               padding-left: 18px;
-               height: calc(100% - 57px);
-               & > :deep(.elScrollbar) {
-                  .el-scrollbar__view {
-                     width: 100%;
-                  }
-                  .el-scrollbar__wrap {
-                     overflow-x: hidden;
-                  }
-               }
-               &:deep(.empty) {
-                  position: absolute;
-                  top: 50%;
-                  left: 50%;
-                  transform: translate(-50%, -50%);
-                  .el-empty__image {
-                     width: 278px;
-                  }
-               }
-            }
-         }
-         .teachingObjectives {
-            padding: 16px 16px 20px;
-            .head {
-               width: 100%;
-               height: 57px;
-               background: #fff2e1;
-               border-radius: 12px;
-               display: flex;
-               justify-content: space-between;
-               align-items: center;
-               padding: 0 18px;
-               .leftTit {
-                  display: flex;
-                  align-items: center;
-                  & > img {
-                     width: 27px;
-                     height: 27px;
-                  }
-                  & > div {
-                     margin-left: 8px;
-                     font-weight: 500;
-                     font-size: 24px;
-                     color: #333333;
-                  }
-               }
-               .rightBtn {
-                  display: flex;
-                  align-items: center;
-                  cursor: pointer;
-                  &:hover {
-                     opacity: $opacity-hover;
-                  }
-                  & > img {
-                     margin-left: 4px;
-                     width: 10px;
-                     height: 17px;
-                  }
-                  & > div {
-                     margin-left: 8px;
-                     font-weight: 500;
-                     font-size: 20px;
-                     color: #f67146;
-                  }
-               }
-            }
-            .title {
-               line-height: 34px;
-               font-weight: 400;
-               font-size: 18px;
-               color: #333333;
-            }
-         }
-         .knowledgePoints {
-            padding: 16px 0 20px 16px;
-            .head {
-               margin-right: 33px;
-               height: 57px;
-               background: #fff2e1;
-               border-radius: 12px;
-               display: flex;
-               align-items: center;
-               padding: 0 18px;
-               .points {
-                  display: flex;
-                  align-items: center;
-                  & > img {
-                     width: 28px;
-                     height: 27px;
-                  }
-                  & > div {
-                     margin-left: 8px;
-                     font-weight: 500;
-                     font-size: 24px;
-                     color: #333333;
-                  }
-               }
-            }
-            .content {
-               & > :deep(.elScrollbar) {
-                  .el-scrollbar__view {
-                     padding-right: 33px;
-                  }
-               }
-            }
-         }
-      }
-   }
-   .curriculumStart {
-      flex-shrink: 0;
-      padding-top: 20px;
-      display: flex;
-      justify-content: center;
-      .startBtn {
-         width: 363px;
-         height: 68px;
-         background: linear-gradient(180deg, #ffffff 0%, #ffdbc1 100%);
-         box-shadow: 4px 6px 0px 0px rgba(236, 102, 52, 0.45), inset 0px -8px 3px 0px rgba(254, 163, 138, 0.46);
-         border-radius: 41px;
-         font-weight: 500;
-         font-size: 24px;
-         color: #f67146;
-         line-height: 68px;
-         text-align: center;
-         cursor: pointer;
-         &:hover {
-            opacity: $opacity-hover;
-         }
-      }
-   }
-}
-</style>
-<style lang="scss">
-.h-modalFrame.curriculumDetail {
-   /* prettier-ignore */
-   --modalFrameTitHeight: 0PX;
-   .modalFrameBox {
-      background: linear-gradient(180deg, #ffdd5d 0%, #ffb93b 100%);
-      border-radius: 57px;
-      box-shadow: none;
-      .modalFrameTitle {
-         display: none;
-      }
-   }
-}
-</style>
+<!--
+* @FileDescription: 课程详情
+* @Author: 黄琪勇
+* @Date:2024-04-01 16:27:48
+-->
+<template>
+   <div class="curriculumDetail">
+      <div class="close" @click="close"></div>
+      <div v-loading="loading" class="curriculumDetailCon">
+         <img class="imgMid" src="@/img/curriculum/mid.png" />
+         <div class="curriculumDetailBox">
+            <div class="teachingObjectives">
+               <div class="head">
+                  <div class="leftTit">
+                     <img src="@/img/curriculum/jxmb.png" />
+                     <div>教学目标</div>
+                  </div>
+                  <div v-if="coursewareShow" 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 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>
+         <div class="curriculumDetailBox">
+            <div class="knowledgePoints">
+               <div class="head">
+                  <div class="points">
+                     <img src="@/img/curriculum/zsd.png" />
+                     <div>知识点</div>
+                  </div>
+               </div>
+               <div class="content">
+                  <ElScrollbar class="elScrollbar">
+                     <courseCollapse :courseList="curriculumDetailData.pointList" @handleClick="handleCourseClick" />
+                  </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" 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 { useSetUpCourseware } from "./index"
+import {
+   getCourseScheduleDetail_gyt,
+   getLessonCoursewareDetail_gyt,
+   getCurrentCourseDetail_gym,
+   getLessonCourseDetail_gym
+} from "@/api/curriculum.api"
+import { httpAjaxErrMsg } from "@/plugin/httpAjax"
+import { ref, shallowRef, computed } from "vue"
+import { handleStartClass_gyt, handleStartClass_gym, isONLINE_gym } from "./hooks/useStartClass"
+import userStore from "@/store/modules/user"
+import router from "@/router"
+
+const userStoreHook = userStore()
+const props = defineProps<{
+   modalData: {
+      id: string
+   }
+}>()
+const emits = defineEmits<{
+   (e: "onClose"): void
+}>()
+
+function close() {
+   emits("onClose")
+}
+const loading = ref(false)
+const statusVal = ref("") //课程状态 ING 和 UNDERWAY 代表可以上课
+const teachModeVal = ref("") //课程类型 ONLINE课的时候提示去app
+const coursewareFlagVal = ref(false) // 管乐团能否配置课件 coursewareFlag字段为true并且不是结束就能配置
+const coursewareShow = computed(() => {
+   if (userStoreHook.roles === "GYM") {
+      return statusVal.value === "UNDERWAY"
+   } else {
+      return coursewareFlagVal.value && statusVal.value !== "COMPLETE"
+   }
+})
+const curriculumDetailData = shallowRef<{
+   pointList: any[]
+   targetDesc: string
+   id: string
+}>({
+   pointList: [],
+   targetDesc: "",
+   id: ""
+})
+
+getCurriculumDetailData()
+function getCurriculumDetailData() {
+   userStoreHook.roles === "GYM" ? getCurriculumDetailData_gym() : getCurriculumDetailData_gyt()
+}
+/* 处理管乐迷 */
+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
+                  }
+               }
+            })
+         } else {
+            loading.value = false
+         }
+      } 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, coursewareFlag } = res.data || {}
+         statusVal.value = status
+         coursewareFlagVal.value = coursewareFlag
+         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
+         }
+      } 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) {
+   useSetUpCourseware(id, () => {
+      //选择课件成功后的回调
+      // 刷新数据
+      getCurriculumDetailData()
+   })
+}
+function handleCourseClick(item: any) {
+   const url = router.resolve({
+      name: "coursewarePlay",
+      params: { id: curriculumDetailData.value.id },
+      query: {
+         materialId: item.id
+      }
+   }).href
+   window.open(url, "_blank")
+}
+</script>
+
+<style lang="scss" scoped>
+.curriculumDetail {
+   width: 100%;
+   height: 100%;
+   padding: 20px 20px 30px 20px;
+   display: flex;
+   flex-direction: column;
+   .close {
+      position: absolute;
+      top: -9px;
+      right: -9px;
+      width: 47px;
+      height: 49px;
+      cursor: pointer;
+      background: url("@/img/useDialogConfirm/close.png") no-repeat;
+      background-size: cover;
+      z-index: 1;
+      &:hover {
+         background: url("@/img/useDialogConfirm/closeHover.png") no-repeat;
+         background-size: cover;
+      }
+   }
+   .curriculumDetailCon {
+      flex-grow: 1;
+      overflow: hidden;
+      display: flex;
+      position: relative;
+      & > :deep(.el-loading-mask) {
+         border-radius: 35px;
+      }
+      .imgMid {
+         width: 62px;
+         height: 470px;
+         position: absolute;
+         left: 50%;
+         top: 50%;
+         transform: translate(-50%, -50%);
+         z-index: 1;
+      }
+      .curriculumDetailBox {
+         width: 50%;
+         height: 100%;
+         background: #fff2e1;
+         border-radius: 35px;
+         padding: 10px;
+         overflow: hidden;
+         &:nth-child(3) {
+            margin-left: 10px;
+         }
+         .teachingObjectives,
+         .knowledgePoints {
+            width: 100%;
+            height: 100%;
+            background: #ffffff;
+            border-radius: 35px;
+            .content {
+               position: relative;
+               padding-top: 18px;
+               padding-left: 18px;
+               height: calc(100% - 57px);
+               & > :deep(.elScrollbar) {
+                  .el-scrollbar__view {
+                     width: 100%;
+                  }
+                  .el-scrollbar__wrap {
+                     overflow-x: hidden;
+                  }
+               }
+               &:deep(.empty) {
+                  position: absolute;
+                  top: 50%;
+                  left: 50%;
+                  transform: translate(-50%, -50%);
+                  .el-empty__image {
+                     width: 278px;
+                  }
+               }
+            }
+         }
+         .teachingObjectives {
+            padding: 16px 16px 20px;
+            .head {
+               width: 100%;
+               height: 57px;
+               background: #fff2e1;
+               border-radius: 12px;
+               display: flex;
+               justify-content: space-between;
+               align-items: center;
+               padding: 0 18px;
+               .leftTit {
+                  display: flex;
+                  align-items: center;
+                  & > img {
+                     width: 27px;
+                     height: 27px;
+                  }
+                  & > div {
+                     margin-left: 8px;
+                     font-weight: 500;
+                     font-size: 24px;
+                     color: #333333;
+                  }
+               }
+               .rightBtn {
+                  display: flex;
+                  align-items: center;
+                  cursor: pointer;
+                  &:hover {
+                     opacity: $opacity-hover;
+                  }
+                  & > img {
+                     margin-left: 4px;
+                     width: 10px;
+                     height: 17px;
+                  }
+                  & > div {
+                     margin-left: 8px;
+                     font-weight: 500;
+                     font-size: 20px;
+                     color: #f67146;
+                  }
+               }
+            }
+            .title {
+               line-height: 34px;
+               font-weight: 400;
+               font-size: 18px;
+               color: #333333;
+            }
+         }
+         .knowledgePoints {
+            padding: 16px 0 20px 16px;
+            .head {
+               margin-right: 33px;
+               height: 57px;
+               background: #fff2e1;
+               border-radius: 12px;
+               display: flex;
+               align-items: center;
+               padding: 0 18px;
+               .points {
+                  display: flex;
+                  align-items: center;
+                  & > img {
+                     width: 28px;
+                     height: 27px;
+                  }
+                  & > div {
+                     margin-left: 8px;
+                     font-weight: 500;
+                     font-size: 24px;
+                     color: #333333;
+                  }
+               }
+            }
+            .content {
+               & > :deep(.elScrollbar) {
+                  .el-scrollbar__view {
+                     padding-right: 33px;
+                  }
+               }
+            }
+         }
+      }
+   }
+   .curriculumStart {
+      flex-shrink: 0;
+      padding-top: 20px;
+      display: flex;
+      justify-content: center;
+      .startBtn {
+         width: 363px;
+         height: 68px;
+         background: linear-gradient(180deg, #ffffff 0%, #ffdbc1 100%);
+         box-shadow: 4px 6px 0px 0px rgba(236, 102, 52, 0.45), inset 0px -8px 3px 0px rgba(254, 163, 138, 0.46);
+         border-radius: 41px;
+         font-weight: 500;
+         font-size: 24px;
+         color: #f67146;
+         line-height: 68px;
+         text-align: center;
+         cursor: pointer;
+         &:hover {
+            opacity: $opacity-hover;
+         }
+      }
+   }
+}
+</style>
+<style lang="scss">
+.h-modalFrame.curriculumDetail {
+   /* prettier-ignore */
+   --modalFrameTitHeight: 0PX;
+   .modalFrameBox {
+      background: linear-gradient(180deg, #ffdd5d 0%, #ffb93b 100%);
+      border-radius: 57px;
+      box-shadow: none;
+      .modalFrameTitle {
+         display: none;
+      }
+   }
+}
+</style>

+ 131 - 112
src/views/curriculum/hooks/useStartClass.ts

@@ -1,112 +1,131 @@
-import { getCourseScheduleDetail_gyt } from "@/api/curriculum.api"
-import { getRecentCourseSchedule_gym } from "@/api/homePage.api"
-import { httpAjaxLoadingErrMsg } from "@/plugin/httpAjax"
-import useDialogConfirm from "@/hooks/useDialogConfirm"
-import { format } from "@/libs/tools"
-import router from "@/router"
-
-/* 管乐迷 开始上课 */
-export function handleStartClass_gym(id: string) {
-   httpAjaxLoadingErrMsg(getRecentCourseSchedule_gym, id).then(res => {
-      if (res.code === 200) {
-         const { signInStatusEnum, isCallNames, coursewareDetailId, startClassTime, endClassTime, status } = res.data
-         if (status === "OVER") {
-            useDialogConfirm({
-               headImg: require("@/img/curriculum/ts4.png"),
-               text: `该课程已结束`,
-               btnShow: [true]
-            })
-            return
-         }
-         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
-         }
-         handlePaly(coursewareDetailId, id)
-      }
-   })
-}
-// 管乐迷是否为线上课
-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) {
-   httpAjaxLoadingErrMsg(getCourseScheduleDetail_gyt, id).then(res => {
-      if (res.code === 200) {
-         const { signIn, rollCall, lessonCoursewareDetailId, startTime, endTime, status, needSignIn } = res.data
-         if (status === "COMPLETE") {
-            useDialogConfirm({
-               headImg: require("@/img/curriculum/ts4.png"),
-               text: `该课程已结束`,
-               btnShow: [true]
-            })
-            return
-         }
-         if (!signIn && needSignIn) {
-            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 (!lessonCoursewareDetailId) {
-            useDialogConfirm({
-               headImg: require("@/img/curriculum/ts3.png"),
-               text: `该课程未配置课件,请配置课件。`,
-               btnShow: [true]
-            })
-            return
-         }
-         handlePaly(lessonCoursewareDetailId, id)
-      }
-   })
-}
-
-function handlePaly(coursewareDetailId: string, coursewareId: string) {
-   const url = router.resolve({
-      name: "coursewarePlay",
-      params: { id: coursewareDetailId },
-      query: {
-         modeId: coursewareId
-      }
-   }).href
-   window.open(url, "_blank")
-}
+import { getCourseScheduleDetail_gyt } from "@/api/curriculum.api"
+import { getRecentCourseSchedule_gym } from "@/api/homePage.api"
+import { httpAjaxLoadingErrMsg } from "@/plugin/httpAjax"
+import useDialogConfirm from "@/hooks/useDialogConfirm"
+import { format } from "@/libs/tools"
+import router from "@/router"
+
+/* 管乐迷 开始上课 */
+export function handleStartClass_gym(id: string) {
+   httpAjaxLoadingErrMsg(getRecentCourseSchedule_gym, id).then(res => {
+      if (res.code === 200) {
+         const { signInStatusEnum, isCallNames, coursewareDetailId, startClassTime, endClassTime, status, coursewareEnable } = res.data
+         if (status === "OVER") {
+            useDialogConfirm({
+               headImg: require("@/img/curriculum/ts4.png"),
+               text: `该课程已结束`,
+               btnShow: [true]
+            })
+            return
+         }
+         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
+         }
+
+         if (!coursewareEnable) {
+            useDialogConfirm({
+               headImg: require("@/img/curriculum/ts4.png"),
+               text: `该资源已失效`,
+               btnShow: [true]
+            })
+            return
+         }
+         handlePaly(coursewareDetailId, id)
+      }
+   })
+}
+// 管乐迷是否为线上课
+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) {
+   httpAjaxLoadingErrMsg(getCourseScheduleDetail_gyt, id).then(res => {
+      if (res.code === 200) {
+         const { signIn, rollCall, lessonCoursewareDetailId, startTime, endTime, status, needSignIn, applyStatus } = res.data
+         if (status === "COMPLETE") {
+            useDialogConfirm({
+               headImg: require("@/img/curriculum/ts4.png"),
+               text: `该课程已结束`,
+               btnShow: [true]
+            })
+            return
+         }
+         if (!signIn && needSignIn) {
+            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 (!lessonCoursewareDetailId) {
+            useDialogConfirm({
+               headImg: require("@/img/curriculum/ts3.png"),
+               text: `该课程未配置课件,请配置课件。`,
+               btnShow: [true]
+            })
+            return
+         }
+
+         if (!applyStatus && status !== "ING") {
+            useDialogConfirm({
+               headImg: require("@/img/curriculum/ts4.png"),
+               text: `该资源已失效`,
+               btnShow: [true]
+            })
+            return
+         }
+
+         handlePaly(lessonCoursewareDetailId, id)
+      }
+   })
+}
+
+function handlePaly(coursewareDetailId: string, coursewareId: string) {
+   const url = router.resolve({
+      name: "coursewarePlay",
+      params: { id: coursewareDetailId },
+      query: {
+         modeId: coursewareId
+      }
+   }).href
+   window.open(url, "_blank")
+}

+ 308 - 299
src/views/homePage/components/curriculum/curriculum_gym.vue

@@ -1,299 +1,308 @@
-<!--
-* @FileDescription: 管乐迷课表
-* @Author: 黄琪勇
-* @Date:2024-03-29 17:31:26
--->
-<template>
-   <div class="curriculum_gym">
-      <div class="head">
-         <div class="timeBox">
-            <img class="timeImg" src="@/img/curriculum/sj.png" />
-            <div class="time">{{ classData.classDate && format(classData.classDate) }}</div>
-         </div>
-         <div class="operateBox">
-            <template v-if="classData.status === 'UNDERWAY' && !classData.coursewareDetailId && props.classData.teachMode !== 'ONLINE'">
-               <img class="dangerImg" src="@/img/curriculum/jg.png" />
-               <div class="operateBtn" @click="handleSetUpCourseware(classData.id)">配置课件</div>
-            </template>
-            <template v-else-if="classData.status === 'NOT_START'">
-               <div class="noStart">未开始</div>
-            </template>
-            <template v-else-if="classData.status === 'UNDERWAY'">
-               <div class="ing">进行中</div>
-            </template>
-            <template v-else>
-               <div class="end">已结束</div>
-            </template>
-         </div>
-      </div>
-      <div class="timeTitBox">
-         {{ classData.startClassTime && format(classData.startClassTime, "hh:ii") }}-{{
-            classData.endClassTime && format(classData.endClassTime, "hh:ii")
-         }}
-      </div>
-      <div class="classNameBox">
-         <img class="xxImg" :src="classData.teachMode === 'ONLINE' ? require('@/img/curriculum/xs.png') : require('@/img/curriculum/xx.png')" />
-         <img class="typeImg" :src="require(`@/img/curriculum/${classImgType[classData.type as keyof typeof classImgType]}.png`)" />
-         <div class="className">
-            <ellipsisScroll :title="`${classNameType[classData.type as keyof typeof classNameType]}·${classData.name}`" />
-         </div>
-      </div>
-      <div class="addressCon">
-         <div class="adressBox">
-            <div>上课地点:</div>
-            <div class="adress">
-               <ellipsisScroll :title="classData.teachMode === 'ONLINE' ? '网络教室' : classData.schoolName" />
-            </div>
-         </div>
-         <div class="adressBox">
-            <div>上课学生:</div>
-            <div class="adress">
-               <ellipsisScroll :title="classData.studentNames" />
-            </div>
-         </div>
-      </div>
-      <div class="stateBox">
-         <div>
-            <img
-               :src="
-                  classData.signInStatusEnum === 1
-                     ? require('@/img/curriculum/qd1.png')
-                     : classData.signInStatusEnum === 0
-                     ? require('@/img/curriculum/qd2.png')
-                     : require('@/img/curriculum/qd.png')
-               "
-            />
-            <div :class="[classData.signInStatusEnum === 1 ? 'signIn' : classData.signInStatusEnum === 0 && 'abnormalSignIn']">
-               {{ classData.signInStatusEnum === 1 ? "正常签到" : classData.signInStatusEnum === 0 ? "异常签到" : "未签到" }}
-            </div>
-         </div>
-         <div>
-            <img
-               :src="
-                  classData.signOutStatusEnum === 1
-                     ? require('@/img/curriculum/qt1.png')
-                     : classData.signOutStatusEnum === 0
-                     ? require('@/img/curriculum/qt2.png')
-                     : require('@/img/curriculum/qt.png')
-               "
-            />
-            <div :class="[classData.signOutStatusEnum === 1 ? 'signOut' : classData.signOutStatusEnum === 0 && 'abnormalSignOut']">
-               {{ classData.signOutStatusEnum === 1 ? "正常签退" : classData.signOutStatusEnum === 0 ? "异常签退" : "未签退" }}
-            </div>
-         </div>
-      </div>
-      <div class="btnCon">
-         <div class="btnDetail" @click="handleClickDetail(classData.id)">查看详情</div>
-         <div class="btnGoClass" v-if="classData.status === 'UNDERWAY'" @click="handleStartClass(classData.id)">开始上课</div>
-      </div>
-   </div>
-</template>
-
-<script setup lang="ts">
-import { format } from "@/libs/tools"
-import { useCurriculumDetail, useSetUpCourseware } from "@/views/curriculum"
-import { handleStartClass_gym, isONLINE_gym } from "@/views/curriculum/hooks/useStartClass"
-import { classImgType, classNameType } from "@/views/curriculum/type"
-
-const props = defineProps<{
-   classData: Record<string, any>
-}>()
-const emits = defineEmits<{
-   (e: "update"): void
-}>()
-
-// 开始上课
-function handleStartClass(id: string) {
-   if (isONLINE_gym(props.classData.teachMode)) {
-      return
-   }
-   handleStartClass_gym(id)
-}
-
-//查看详情
-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>
-
-<style lang="scss" scoped>
-.curriculum_gym {
-   padding: 0 30px;
-   .head {
-      padding-top: 25px;
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      .timeBox {
-         display: flex;
-         align-items: center;
-         .timeImg {
-            width: 28px;
-            height: 28px;
-         }
-         .time {
-            margin-left: 8px;
-            font-weight: 500;
-            font-size: 24px;
-            color: #777777;
-         }
-      }
-      .operateBox {
-         display: flex;
-         align-items: center;
-         .dangerImg {
-            width: 24px;
-            height: 24px;
-         }
-         .operateBtn {
-            margin-left: 10px;
-            font-weight: 500;
-            font-size: 24px;
-            color: #f44541;
-            cursor: pointer;
-            &:hover {
-               opacity: $opacity-hover;
-            }
-         }
-         .noStart {
-            font-weight: 500;
-            font-size: 24px;
-            color: #777777;
-         }
-         .ing {
-            font-weight: 500;
-            font-size: 24px;
-            color: #f67146;
-         }
-         .end {
-            font-weight: 500;
-            font-size: 24px;
-            color: #aaaaaa;
-         }
-      }
-   }
-   .timeTitBox {
-      text-align: center;
-      margin-top: 68px;
-      font-family: DINAlternate, DINAlternate;
-      font-weight: bold;
-      font-size: 52px;
-      color: #f67146;
-   }
-   .classNameBox {
-      margin-top: 46px;
-      width: 100%;
-      display: flex;
-      align-items: center;
-      .xxImg {
-         flex-shrink: 0;
-         width: 46px;
-         height: 24px;
-      }
-      .typeImg {
-         flex-shrink: 0;
-         margin-left: 6px;
-         width: 55px;
-         height: 24px;
-      }
-      .className {
-         flex-grow: 1;
-         overflow: hidden;
-         margin-left: 6px;
-         font-weight: 600;
-         font-size: 24px;
-         color: #333333;
-      }
-   }
-   .addressCon {
-      margin-top: 16px;
-      width: 100%;
-      & > div {
-         font-weight: 500;
-         font-size: 18px;
-         color: #777777;
-      }
-      & > div:nth-child(2) {
-         margin-top: 14px;
-      }
-      .adressBox {
-         display: flex;
-         align-items: center;
-         & > div:nth-child(1) {
-            flex-shrink: 0;
-         }
-         .adress {
-            overflow: hidden;
-         }
-      }
-   }
-   .stateBox {
-      margin-top: 48px;
-      display: flex;
-      justify-content: space-between;
-      & > div {
-         width: 216px;
-         height: 65px;
-         background: #f2f2f2;
-         border-radius: 18px;
-         display: flex;
-         justify-content: center;
-         align-items: center;
-         & > img {
-            width: 27px;
-            height: 27px;
-         }
-         & > div {
-            margin-left: 6px;
-            font-weight: 500;
-            font-size: 22px;
-            color: #aaaaaa;
-            &.signIn,
-            &.signOut {
-               color: #01c199;
-            }
-            &.abnormalSignIn,
-            &.abnormalSignOut {
-               color: #ff0000;
-            }
-         }
-      }
-   }
-   .btnCon {
-      margin-top: 58px;
-      display: flex;
-      .btnGoClass,
-      .btnDetail {
-         flex-grow: 1;
-         height: 74px;
-         background: linear-gradient(180deg, #ffffff 0%, #ffdbc1 100%);
-         box-shadow: 4px 5px 0px 0px rgba(236, 102, 52, 0.45), inset 0px -7px 3px 0px rgba(254, 163, 138, 0.46);
-         border-radius: 37px;
-         font-weight: 500;
-         font-size: 24px;
-         color: #f67146;
-         line-height: 74px;
-         text-align: center;
-         cursor: pointer;
-         &:hover {
-            opacity: $opacity-hover;
-         }
-      }
-      .btnGoClass {
-         margin-left: 20px;
-      }
-   }
-}
-</style>
+<!--
+* @FileDescription: 管乐迷课表
+* @Author: 黄琪勇
+* @Date:2024-03-29 17:31:26
+-->
+<template>
+   <div class="curriculum_gym">
+      <div class="head">
+         <div class="timeBox">
+            <img class="timeImg" src="@/img/curriculum/sj.png" />
+            <div class="time">{{ classData.classDate && format(classData.classDate) }}</div>
+         </div>
+         <div class="operateBox">
+            <template v-if="classData.status === 'UNDERWAY' && !classData.coursewareDetailId && props.classData.teachMode !== 'ONLINE'">
+               <img class="dangerImg" src="@/img/curriculum/jg.png" />
+               <div class="operateBtn" @click="handleSetUpCourseware(classData.id)">配置课件</div>
+            </template>
+            <template v-else-if="classData.status === 'NOT_START'">
+               <div class="noStart">未开始</div>
+            </template>
+            <template v-else-if="classData.status === 'UNDERWAY'">
+               <div class="ing">进行中</div>
+            </template>
+            <template v-else>
+               <div class="end">已结束</div>
+            </template>
+         </div>
+      </div>
+      <div class="timeTitBox">
+         {{ classData.startClassTime && format(classData.startClassTime, "hh:ii") }}-{{
+            classData.endClassTime && format(classData.endClassTime, "hh:ii")
+         }}
+      </div>
+      <div class="classNameBox">
+         <img class="xxImg" :src="classData.teachMode === 'ONLINE' ? require('@/img/curriculum/xs.png') : require('@/img/curriculum/xx.png')" />
+         <img class="typeImg" :src="require(`@/img/curriculum/${classImgType[classData.type as keyof typeof classImgType]}.png`)" />
+         <div class="className">
+            <ellipsisScroll :title="`${classNameType[classData.type as keyof typeof classNameType]}·${classData.name}`" />
+         </div>
+      </div>
+      <div class="addressCon">
+         <div class="adressBox">
+            <div>上课地点:</div>
+            <div class="adress">
+               <ellipsisScroll :title="classData.teachMode === 'ONLINE' ? '网络教室' : classData.schoolName" />
+            </div>
+         </div>
+         <div class="adressBox">
+            <div>上课学生:</div>
+            <div class="adress">
+               <ellipsisScroll :title="classData.studentNames" />
+            </div>
+         </div>
+      </div>
+      <div class="stateBox">
+         <div>
+            <img
+               :src="
+                  classData.signInStatusEnum === 1
+                     ? require('@/img/curriculum/qd1.png')
+                     : classData.signInStatusEnum === 0
+                     ? require('@/img/curriculum/qd2.png')
+                     : require('@/img/curriculum/qd.png')
+               "
+            />
+            <div :class="[classData.signInStatusEnum === 1 ? 'signIn' : classData.signInStatusEnum === 0 && 'abnormalSignIn']">
+               {{ classData.signInStatusEnum === 1 ? "正常签到" : classData.signInStatusEnum === 0 ? "异常签到" : "未签到" }}
+            </div>
+         </div>
+         <div>
+            <img
+               :src="
+                  classData.signOutStatusEnum === 1
+                     ? require('@/img/curriculum/qt1.png')
+                     : classData.signOutStatusEnum === 0
+                     ? require('@/img/curriculum/qt2.png')
+                     : require('@/img/curriculum/qt.png')
+               "
+            />
+            <div :class="[classData.signOutStatusEnum === 1 ? 'signOut' : classData.signOutStatusEnum === 0 && 'abnormalSignOut']">
+               {{ classData.signOutStatusEnum === 1 ? "正常签退" : classData.signOutStatusEnum === 0 ? "异常签退" : "未签退" }}
+            </div>
+         </div>
+      </div>
+      <div class="btnCon">
+         <div class="btnDetail" @click="handleClickDetail(classData.id, classData.coursewareEnable)">查看详情</div>
+         <div class="btnGoClass" v-if="classData.status === 'UNDERWAY'" @click="handleStartClass(classData.id)">开始上课</div>
+      </div>
+   </div>
+</template>
+
+<script setup lang="ts">
+import useDialogConfirm from "@/hooks/useDialogConfirm"
+import { format } from "@/libs/tools"
+import { useCurriculumDetail, useSetUpCourseware } from "@/views/curriculum"
+import { handleStartClass_gym, isONLINE_gym } from "@/views/curriculum/hooks/useStartClass"
+import { classImgType, classNameType } from "@/views/curriculum/type"
+
+const props = defineProps<{
+   classData: Record<string, any>
+}>()
+const emits = defineEmits<{
+   (e: "update"): void
+}>()
+
+// 开始上课
+function handleStartClass(id: string) {
+   if (isONLINE_gym(props.classData.teachMode)) {
+      return
+   }
+   handleStartClass_gym(id)
+}
+
+//查看详情
+function handleClickDetail(id: string, coursewareEnable: boolean) {
+   if (isONLINE_gym(props.classData.teachMode)) {
+      return
+   }
+   if (!coursewareEnable) {
+      useDialogConfirm({
+         headImg: require("@/img/curriculum/ts4.png"),
+         text: `该资源已失效`,
+         btnShow: [true]
+      })
+      return
+   }
+   useCurriculumDetail(id)
+}
+// 配置课表
+function handleSetUpCourseware(id: string) {
+   if (isONLINE_gym(props.classData.teachMode)) {
+      return
+   }
+   useSetUpCourseware(id, () => {
+      emits("update")
+   })
+}
+</script>
+
+<style lang="scss" scoped>
+.curriculum_gym {
+   padding: 0 30px;
+   .head {
+      padding-top: 25px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      .timeBox {
+         display: flex;
+         align-items: center;
+         .timeImg {
+            width: 28px;
+            height: 28px;
+         }
+         .time {
+            margin-left: 8px;
+            font-weight: 500;
+            font-size: 24px;
+            color: #777777;
+         }
+      }
+      .operateBox {
+         display: flex;
+         align-items: center;
+         .dangerImg {
+            width: 24px;
+            height: 24px;
+         }
+         .operateBtn {
+            margin-left: 10px;
+            font-weight: 500;
+            font-size: 24px;
+            color: #f44541;
+            cursor: pointer;
+            &:hover {
+               opacity: $opacity-hover;
+            }
+         }
+         .noStart {
+            font-weight: 500;
+            font-size: 24px;
+            color: #777777;
+         }
+         .ing {
+            font-weight: 500;
+            font-size: 24px;
+            color: #f67146;
+         }
+         .end {
+            font-weight: 500;
+            font-size: 24px;
+            color: #aaaaaa;
+         }
+      }
+   }
+   .timeTitBox {
+      text-align: center;
+      margin-top: 68px;
+      font-family: DINAlternate, DINAlternate;
+      font-weight: bold;
+      font-size: 52px;
+      color: #f67146;
+   }
+   .classNameBox {
+      margin-top: 46px;
+      width: 100%;
+      display: flex;
+      align-items: center;
+      .xxImg {
+         flex-shrink: 0;
+         width: 46px;
+         height: 24px;
+      }
+      .typeImg {
+         flex-shrink: 0;
+         margin-left: 6px;
+         width: 55px;
+         height: 24px;
+      }
+      .className {
+         flex-grow: 1;
+         overflow: hidden;
+         margin-left: 6px;
+         font-weight: 600;
+         font-size: 24px;
+         color: #333333;
+      }
+   }
+   .addressCon {
+      margin-top: 16px;
+      width: 100%;
+      & > div {
+         font-weight: 500;
+         font-size: 18px;
+         color: #777777;
+      }
+      & > div:nth-child(2) {
+         margin-top: 14px;
+      }
+      .adressBox {
+         display: flex;
+         align-items: center;
+         & > div:nth-child(1) {
+            flex-shrink: 0;
+         }
+         .adress {
+            overflow: hidden;
+         }
+      }
+   }
+   .stateBox {
+      margin-top: 48px;
+      display: flex;
+      justify-content: space-between;
+      & > div {
+         width: 216px;
+         height: 65px;
+         background: #f2f2f2;
+         border-radius: 18px;
+         display: flex;
+         justify-content: center;
+         align-items: center;
+         & > img {
+            width: 27px;
+            height: 27px;
+         }
+         & > div {
+            margin-left: 6px;
+            font-weight: 500;
+            font-size: 22px;
+            color: #aaaaaa;
+            &.signIn,
+            &.signOut {
+               color: #01c199;
+            }
+            &.abnormalSignIn,
+            &.abnormalSignOut {
+               color: #ff0000;
+            }
+         }
+      }
+   }
+   .btnCon {
+      margin-top: 58px;
+      display: flex;
+      .btnGoClass,
+      .btnDetail {
+         flex-grow: 1;
+         height: 74px;
+         background: linear-gradient(180deg, #ffffff 0%, #ffdbc1 100%);
+         box-shadow: 4px 5px 0px 0px rgba(236, 102, 52, 0.45), inset 0px -7px 3px 0px rgba(254, 163, 138, 0.46);
+         border-radius: 37px;
+         font-weight: 500;
+         font-size: 24px;
+         color: #f67146;
+         line-height: 74px;
+         text-align: center;
+         cursor: pointer;
+         &:hover {
+            opacity: $opacity-hover;
+         }
+      }
+      .btnGoClass {
+         margin-left: 20px;
+      }
+   }
+}
+</style>

+ 224 - 215
src/views/homePage/components/curriculum/curriculum_gyt.vue

@@ -1,215 +1,224 @@
-<!--
-* @FileDescription: 管乐团课表
-* @Author: 黄琪勇
-* @Date:2024-03-29 17:31:26
--->
-<template>
-   <div class="curriculum_gyt">
-      <div class="head">
-         <div class="timeBox">
-            <img class="timeImg" src="@/img/curriculum/sj.png" />
-            <div class="time">{{ classData.classDate && format(classData.classDate) }}</div>
-         </div>
-         <div class="operateBox">
-            <template v-if="classData.coursewareFlag && !classData.lessonCoursewareId && classData.status !== 'COMPLETE'">
-               <img class="dangerImg" src="@/img/curriculum/jg.png" />
-               <div class="operateBtn" @click="handleSetUpCourseware(classData.id)">配置课件</div>
-            </template>
-            <template v-else-if="classData.status === 'NOT_START'">
-               <div class="noStart">未开始</div>
-            </template>
-            <template v-else-if="classData.status === 'ING'">
-               <div class="ing">进行中</div>
-            </template>
-            <template v-else>
-               <div class="end">已结束</div>
-            </template>
-         </div>
-      </div>
-      <div class="timeTitBox">
-         {{ classData.startTime && format(classData.startTime, "hh:ii") }}-{{ classData.endTime && format(classData.endTime, "hh:ii") }}
-      </div>
-      <div class="nameTitBox">
-         <ellipsisScroll :title="`${classData.className}-${classData.teacherName}`" />
-      </div>
-      <div class="schoolTitBox">
-         <ellipsisScroll :title="'·' + classData.orchestraName + '·'" />
-      </div>
-      <div class="stateBox">
-         <div>
-            <img :src="classData.signIn ? require('@/img/curriculum/qd1.png') : require('@/img/curriculum/qd.png')" />
-            <div :class="{ signIn: classData.signIn }">{{ classData.signIn ? "已签到" : "未签到" }}</div>
-         </div>
-         <div>
-            <img :src="classData.signOut ? require('@/img/curriculum/qt1.png') : require('@/img/curriculum/qt.png')" />
-            <div :class="{ signOut: classData.signOut }">{{ classData.signOut ? "已签退" : "未签退" }}</div>
-         </div>
-      </div>
-      <div class="btnCon">
-         <div class="btnDetail" @click="handleClickDetail(classData.id)">查看详情</div>
-         <div class="btnGoClass" v-if="classData.status === 'ING'" @click="handleStartClass(classData.id)">开始上课</div>
-      </div>
-   </div>
-</template>
-
-<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
-}>()
-defineProps<{
-   classData: Record<string, 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>
-.curriculum_gyt {
-   padding: 0 30px;
-   .head {
-      padding-top: 25px;
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      .timeBox {
-         display: flex;
-         align-items: center;
-         .timeImg {
-            width: 28px;
-            height: 28px;
-         }
-         .time {
-            margin-left: 8px;
-            font-weight: 500;
-            font-size: 24px;
-            color: #777777;
-         }
-      }
-      .operateBox {
-         display: flex;
-         align-items: center;
-         .dangerImg {
-            width: 24px;
-            height: 24px;
-         }
-         .operateBtn {
-            margin-left: 10px;
-            font-weight: 500;
-            font-size: 24px;
-            color: #f44541;
-            cursor: pointer;
-            &:hover {
-               opacity: $opacity-hover;
-            }
-         }
-         .noStart {
-            font-weight: 500;
-            font-size: 24px;
-            color: #777777;
-         }
-         .ing {
-            font-weight: 500;
-            font-size: 24px;
-            color: #f67146;
-         }
-         .end {
-            font-weight: 500;
-            font-size: 24px;
-            color: #aaaaaa;
-         }
-      }
-   }
-   .timeTitBox {
-      text-align: center;
-      margin-top: 68px;
-      font-family: DINAlternate, DINAlternate;
-      font-weight: bold;
-      font-size: 52px;
-      color: #f67146;
-   }
-   .nameTitBox {
-      margin: 34px 30px 0;
-      font-weight: 600;
-      font-size: 25px;
-      color: #333333;
-      text-align: center;
-      overflow: hidden;
-   }
-   .schoolTitBox {
-      margin: 32px 38px 0;
-      font-weight: 500;
-      font-size: 22px;
-      color: #777777;
-      text-align: center;
-      overflow: hidden;
-   }
-   .stateBox {
-      margin-top: 76px;
-      display: flex;
-      justify-content: space-between;
-      & > div {
-         width: 216px;
-         height: 65px;
-         background: #f2f2f2;
-         border-radius: 18px;
-         display: flex;
-         justify-content: center;
-         align-items: center;
-         & > img {
-            width: 27px;
-            height: 27px;
-         }
-         & > div {
-            margin-left: 6px;
-            font-weight: 500;
-            font-size: 22px;
-            color: #aaaaaa;
-            &.signIn,
-            &.signOut {
-               color: #01c199;
-            }
-         }
-      }
-   }
-   .btnCon {
-      margin-top: 58px;
-      display: flex;
-      .btnGoClass,
-      .btnDetail {
-         flex-grow: 1;
-         height: 74px;
-         background: linear-gradient(180deg, #ffffff 0%, #ffdbc1 100%);
-         box-shadow: 4px 5px 0px 0px rgba(236, 102, 52, 0.45), inset 0px -7px 3px 0px rgba(254, 163, 138, 0.46);
-         border-radius: 37px;
-         font-weight: 500;
-         font-size: 24px;
-         color: #f67146;
-         line-height: 74px;
-         text-align: center;
-         cursor: pointer;
-         &:hover {
-            opacity: $opacity-hover;
-         }
-      }
-      .btnGoClass {
-         margin-left: 20px;
-      }
-   }
-}
-</style>
+<!--
+* @FileDescription: 管乐团课表
+* @Author: 黄琪勇
+* @Date:2024-03-29 17:31:26
+-->
+<template>
+   <div class="curriculum_gyt">
+      <div class="head">
+         <div class="timeBox">
+            <img class="timeImg" src="@/img/curriculum/sj.png" />
+            <div class="time">{{ classData.classDate && format(classData.classDate) }}</div>
+         </div>
+         <div class="operateBox">
+            <template v-if="classData.coursewareFlag && !classData.lessonCoursewareId && classData.status !== 'COMPLETE'">
+               <img class="dangerImg" src="@/img/curriculum/jg.png" />
+               <div class="operateBtn" @click="handleSetUpCourseware(classData.id)">配置课件</div>
+            </template>
+            <template v-else-if="classData.status === 'NOT_START'">
+               <div class="noStart">未开始</div>
+            </template>
+            <template v-else-if="classData.status === 'ING'">
+               <div class="ing">进行中</div>
+            </template>
+            <template v-else>
+               <div class="end">已结束</div>
+            </template>
+         </div>
+      </div>
+      <div class="timeTitBox">
+         {{ classData.startTime && format(classData.startTime, "hh:ii") }}-{{ classData.endTime && format(classData.endTime, "hh:ii") }}
+      </div>
+      <div class="nameTitBox">
+         <ellipsisScroll :title="`${classData.className}-${classData.teacherName}`" />
+      </div>
+      <div class="schoolTitBox">
+         <ellipsisScroll :title="'·' + classData.orchestraName + '·'" />
+      </div>
+      <div class="stateBox">
+         <div>
+            <img :src="classData.signIn ? require('@/img/curriculum/qd1.png') : require('@/img/curriculum/qd.png')" />
+            <div :class="{ signIn: classData.signIn }">{{ classData.signIn ? "已签到" : "未签到" }}</div>
+         </div>
+         <div>
+            <img :src="classData.signOut ? require('@/img/curriculum/qt1.png') : require('@/img/curriculum/qt.png')" />
+            <div :class="{ signOut: classData.signOut }">{{ classData.signOut ? "已签退" : "未签退" }}</div>
+         </div>
+      </div>
+      <div class="btnCon">
+         <div class="btnDetail" @click="handleClickDetail(classData.id, classData)">查看详情</div>
+         <div class="btnGoClass" v-if="classData.status === 'ING'" @click="handleStartClass(classData.id)">开始上课</div>
+      </div>
+   </div>
+</template>
+
+<script setup lang="ts">
+import useDialogConfirm from "@/hooks/useDialogConfirm"
+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
+}>()
+defineProps<{
+   classData: Record<string, any>
+}>()
+
+// 开始上课
+function handleStartClass(id: string) {
+   handleStartClass_gyt(id)
+}
+//查看详情
+function handleClickDetail(id: string, classData: any) {
+   if (!classData.applyStatus && classData.status !== "ING") {
+      useDialogConfirm({
+         headImg: require("@/img/curriculum/ts4.png"),
+         text: `该资源已失效`,
+         btnShow: [true]
+      })
+      return
+   }
+   useCurriculumDetail(id)
+}
+// 配置课表
+function handleSetUpCourseware(id: string) {
+   useSetUpCourseware(id, () => {
+      emits("update")
+   })
+}
+</script>
+
+<style lang="scss" scoped>
+.curriculum_gyt {
+   padding: 0 30px;
+   .head {
+      padding-top: 25px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      .timeBox {
+         display: flex;
+         align-items: center;
+         .timeImg {
+            width: 28px;
+            height: 28px;
+         }
+         .time {
+            margin-left: 8px;
+            font-weight: 500;
+            font-size: 24px;
+            color: #777777;
+         }
+      }
+      .operateBox {
+         display: flex;
+         align-items: center;
+         .dangerImg {
+            width: 24px;
+            height: 24px;
+         }
+         .operateBtn {
+            margin-left: 10px;
+            font-weight: 500;
+            font-size: 24px;
+            color: #f44541;
+            cursor: pointer;
+            &:hover {
+               opacity: $opacity-hover;
+            }
+         }
+         .noStart {
+            font-weight: 500;
+            font-size: 24px;
+            color: #777777;
+         }
+         .ing {
+            font-weight: 500;
+            font-size: 24px;
+            color: #f67146;
+         }
+         .end {
+            font-weight: 500;
+            font-size: 24px;
+            color: #aaaaaa;
+         }
+      }
+   }
+   .timeTitBox {
+      text-align: center;
+      margin-top: 68px;
+      font-family: DINAlternate, DINAlternate;
+      font-weight: bold;
+      font-size: 52px;
+      color: #f67146;
+   }
+   .nameTitBox {
+      margin: 34px 30px 0;
+      font-weight: 600;
+      font-size: 25px;
+      color: #333333;
+      text-align: center;
+      overflow: hidden;
+   }
+   .schoolTitBox {
+      margin: 32px 38px 0;
+      font-weight: 500;
+      font-size: 22px;
+      color: #777777;
+      text-align: center;
+      overflow: hidden;
+   }
+   .stateBox {
+      margin-top: 76px;
+      display: flex;
+      justify-content: space-between;
+      & > div {
+         width: 216px;
+         height: 65px;
+         background: #f2f2f2;
+         border-radius: 18px;
+         display: flex;
+         justify-content: center;
+         align-items: center;
+         & > img {
+            width: 27px;
+            height: 27px;
+         }
+         & > div {
+            margin-left: 6px;
+            font-weight: 500;
+            font-size: 22px;
+            color: #aaaaaa;
+            &.signIn,
+            &.signOut {
+               color: #01c199;
+            }
+         }
+      }
+   }
+   .btnCon {
+      margin-top: 58px;
+      display: flex;
+      .btnGoClass,
+      .btnDetail {
+         flex-grow: 1;
+         height: 74px;
+         background: linear-gradient(180deg, #ffffff 0%, #ffdbc1 100%);
+         box-shadow: 4px 5px 0px 0px rgba(236, 102, 52, 0.45), inset 0px -7px 3px 0px rgba(254, 163, 138, 0.46);
+         border-radius: 37px;
+         font-weight: 500;
+         font-size: 24px;
+         color: #f67146;
+         line-height: 74px;
+         text-align: center;
+         cursor: pointer;
+         &:hover {
+            opacity: $opacity-hover;
+         }
+      }
+      .btnGoClass {
+         margin-left: 20px;
+      }
+   }
+}
+</style>

+ 358 - 358
src/views/homePage/homePage.vue

@@ -1,358 +1,358 @@
-<!--
-* @FileDescription: 首页
-* @Author: 黄琪勇
-* @Date:2024-03-29 17:20:39
--->
-<template>
-   <navContainer class="homePageNav" :headImg="headImg" :navs="navs">
-      <div class="homePage">
-         <ElScrollbar class="elScrollbar">
-            <div class="classTypes">
-               <div
-                  class="classType"
-                  v-for="item in userStoreHook.roles === 'GYM' ? classTypes_gym : classTypes_gyt"
-                  :key="item.name"
-                  @click="handleRouter(item.url)"
-               >
-                  <img :src="item.img" />
-                  <div>{{ item.name }}</div>
-               </div>
-            </div>
-            <div class="courseBoard" :class="{ isEmpty: isEmptyClassData && !classDataLoading }">
-               <div class="details">
-                  <div class="head">
-                     <div class="leftCon">
-                        <div class="line"></div>
-                        <div class="title">下次课程</div>
-                     </div>
-                     <img class="rightRouter" @click="handleRouterCurriculum" src="@/img/homePage/back.png" />
-                  </div>
-                  <el-skeleton class="elSkeleton" :loading="classDataLoading">
-                     <template #template>
-                        <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 class="elSkeletonBtnCon">
-                           <el-skeleton-item class="elSkeletonItem" variant="button" />
-                           <el-skeleton-item class="elSkeletonItem" variant="button" />
-                        </div>
-                        <el-skeleton-item class="elSkeletonItem" variant="button" />
-                     </template>
-                     <template #default>
-                        <component
-                           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>
-                  </el-skeleton>
-               </div>
-            </div>
-         </ElScrollbar>
-      </div>
-   </navContainer>
-</template>
-<script setup lang="ts">
-import navContainer from "@/businessComponents/navContainer"
-import { useRouter } from "vue-router"
-import { ref, computed } from "vue"
-import useDialogConfirm from "@/hooks/useDialogConfirm"
-import userStore from "@/store/modules/user"
-import curriculum_gym from "./components/curriculum/curriculum_gym.vue"
-import curriculum_gyt from "./components/curriculum/curriculum_gyt.vue"
-import { getRemind_gyt, getRecentCourseSchedule_gym } from "@/api/homePage.api"
-import { httpAjax } from "@/plugin/httpAjax"
-import { format } from "@/libs/tools"
-
-const userStoreHook = userStore()
-const router = useRouter()
-
-const headImg = {
-   img: require("@/img/homePage/home.png")
-}
-const navs = [
-   {
-      name: "主页"
-   }
-]
-const classTypes_gym = [
-   {
-      img: require("@/img/homePage/kb.png"),
-      name: "课表",
-      url: "/curriculum"
-   },
-   {
-      img: require("@/img/homePage/xl.png"),
-      name: "训练",
-      url: ""
-   },
-   {
-      img: require("@/img/homePage/jdcp.png"),
-      name: "进度测评",
-      url: ""
-   },
-   {
-      img: require("@/img/homePage/xltj.png"),
-      name: "训练统计",
-      url: ""
-   },
-   {
-      img: require("@/img/homePage/yjl.png"),
-      name: "云练习",
-      url: ""
-   },
-   {
-      img: require("@/img/homePage/yjc.png"),
-      name: "云课堂",
-      url: "/cloudTextbooks"
-   }
-]
-const classTypes_gyt = [
-   {
-      img: require("@/img/homePage/kb.png"),
-      name: "课表",
-      url: "/curriculum"
-   },
-   {
-      img: require("@/img/homePage/xl.png"),
-      name: "课后作业",
-      url: ""
-   },
-   {
-      img: require("@/img/homePage/jdzc.png"),
-      name: "阶段自测",
-      url: ""
-   },
-   {
-      img: require("@/img/homePage/xltj.png"),
-      name: "练习情况",
-      url: ""
-   },
-   {
-      img: require("@/img/homePage/yjl.png"),
-      name: "云练习",
-      url: ""
-   },
-   {
-      img: require("@/img/homePage/yjc.png"),
-      name: "云课堂",
-      url: "/cloudTextbooks"
-   }
-]
-
-/* 下次课程信息 */
-const classData = ref<Record<string, any>>({})
-const classDataLoading = ref(true)
-const isEmptyClassData = computed(() => {
-   return !Object.keys(classData.value).length
-})
-handleClassData()
-function handleClassData() {
-   if (userStoreHook.roles === "GYM") {
-      classDataLoading.value = true
-      httpAjax(getRecentCourseSchedule_gym).then(res => {
-         classDataLoading.value = false
-         if (res.code === 200) {
-            classData.value = res.data || {}
-         }
-      })
-   } else {
-      classDataLoading.value = true
-      httpAjax(getRemind_gyt).then(res => {
-         classDataLoading.value = false
-         if (res.code === 200) {
-            classData.value = res.data || {}
-         }
-      })
-   }
-}
-
-function handleRouter(url?: string) {
-   url
-      ? router.push(url)
-      : useDialogConfirm({
-           headImg: require("@/img/homePage/ts.png"),
-           text: "该功能暂未开放,请敬请期待哦~",
-           btnShow: [true]
-        })
-}
-function handleRouterCurriculum() {
-   router.push({
-      path: "/curriculum",
-      query: {
-         date: classData.value.classDate ? format(classData.value.classDate) : ""
-      }
-   })
-}
-</script>
-<style lang="scss" scoped>
-.homePageNav.navContainer {
-   &:deep(.navCon) {
-      .navImg {
-         margin-left: 50px;
-         > img {
-            width: 91px;
-            height: 92px;
-            top: 70%;
-         }
-      }
-      .nav {
-         font-size: 28px;
-         font-family: AlimamaFangYuanTiVF, AlimamaFangYuanTiVF;
-         &:last-child {
-            margin-right: 30px;
-         }
-      }
-   }
-}
-.homePage {
-   width: 100%;
-   height: 100%;
-   & > :deep(.elScrollbar) {
-      .el-scrollbar__view {
-         width: 100%;
-         display: flex;
-         padding: 50px 50px 0;
-      }
-      .el-scrollbar__wrap {
-         overflow-x: hidden;
-      }
-   }
-   .classTypes {
-      flex-grow: 1;
-      display: flex;
-      flex-wrap: wrap;
-      justify-content: space-between;
-      height: 729px;
-      align-content: space-between;
-      .classType {
-         background: #feffff;
-         box-shadow: 0px 2px 14px 0 #f1e3cc;
-         border-radius: 34px;
-         width: 360px;
-         height: 350px;
-         display: flex;
-         justify-content: center;
-         align-items: center;
-         flex-direction: column;
-         cursor: pointer;
-         padding: 44px 53px;
-         &:hover {
-            transform: scale(1.02);
-            box-shadow: 0px 2px 14px 0px #e4d7c2;
-         }
-         > div {
-            margin-top: 10px;
-            font-family: AlimamaFangYuanTiVF, AlimamaFangYuanTiVF;
-            font-weight: bold;
-            font-size: 28px;
-            color: #393939;
-         }
-         > img {
-            width: 100%;
-         }
-      }
-   }
-   .courseBoard {
-      flex-shrink: 0;
-      margin-left: 50px;
-      margin-top: -35px;
-      width: 572px;
-      height: 764px;
-      background: url("@/img/homePage/bg1.png") no-repeat;
-      background-size: 100% 100%;
-      position: relative;
-      &.isEmpty {
-         background: url("@/img/homePage/bg.png") no-repeat;
-         background-size: 100% 100%;
-      }
-      .details {
-         width: 100%;
-         position: absolute;
-         top: 88px;
-         left: 0;
-         padding: 0 30px;
-         .head {
-            height: 81px;
-            display: flex;
-            justify-content: space-between;
-            align-items: center;
-            padding: 0 30px;
-            .leftCon {
-               display: flex;
-               align-items: center;
-               .line {
-                  width: 8px;
-                  height: 28px;
-                  background: linear-gradient(180deg, #ffcb35 0%, #fea60a 100%), #ff6a67;
-                  border-radius: 7px;
-               }
-               .title {
-                  margin-left: 12px;
-                  font-family: AlimamaFangYuanTiVF, AlimamaFangYuanTiVF;
-                  font-weight: bold;
-                  font-size: 28px;
-                  color: #994d1c;
-               }
-            }
-            .rightRouter {
-               width: 38px;
-               height: 38px;
-               cursor: pointer;
-               &:hover {
-                  opacity: $opacity-hover;
-               }
-            }
-         }
-         .elSkeleton {
-            padding: 0 30px;
-            display: flex;
-            flex-direction: column;
-            align-items: center;
-            > .elSkeletonItem {
-               &:nth-child(1) {
-                  margin-top: 25px;
-                  height: 34px;
-               }
-               &:nth-child(2) {
-                  width: 50%;
-                  margin-top: 58px;
-                  height: 60px;
-               }
-               &:nth-child(3) {
-                  margin-top: 34px;
-               }
-               &:nth-child(4) {
-                  margin-top: 34px;
-               }
-               &:nth-child(6) {
-                  width: 100%;
-                  height: 74px;
-                  margin-top: 58px;
-               }
-            }
-            .elSkeletonBtnCon {
-               width: 100%;
-               margin-top: 76px;
-               display: flex;
-               justify-content: space-between;
-               > .elSkeletonItem {
-                  width: 216px;
-                  height: 65px;
-               }
-            }
-         }
-         :deep(.empty) {
-            margin-top: 114px;
-            padding: 0;
-            .el-empty__image {
-               width: 360px;
-            }
-         }
-      }
-   }
-}
-</style>
+<!--
+* @FileDescription: 首页
+* @Author: 黄琪勇
+* @Date:2024-03-29 17:20:39
+-->
+<template>
+   <navContainer class="homePageNav" :headImg="headImg" :navs="navs">
+      <div class="homePage">
+         <ElScrollbar class="elScrollbar">
+            <div class="classTypes">
+               <div
+                  class="classType"
+                  v-for="item in userStoreHook.roles === 'GYM' ? classTypes_gym : classTypes_gyt"
+                  :key="item.name"
+                  @click="handleRouter(item.url)"
+               >
+                  <img :src="item.img" />
+                  <div>{{ item.name }}</div>
+               </div>
+            </div>
+            <div class="courseBoard" :class="{ isEmpty: isEmptyClassData && !classDataLoading }">
+               <div class="details">
+                  <div class="head">
+                     <div class="leftCon">
+                        <div class="line"></div>
+                        <div class="title">下次课程</div>
+                     </div>
+                     <img class="rightRouter" @click="handleRouterCurriculum" src="@/img/homePage/back.png" />
+                  </div>
+                  <el-skeleton class="elSkeleton" :loading="classDataLoading">
+                     <template #template>
+                        <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 class="elSkeletonBtnCon">
+                           <el-skeleton-item class="elSkeletonItem" variant="button" />
+                           <el-skeleton-item class="elSkeletonItem" variant="button" />
+                        </div>
+                        <el-skeleton-item class="elSkeletonItem" variant="button" />
+                     </template>
+                     <template #default>
+                        <component
+                           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>
+                  </el-skeleton>
+               </div>
+            </div>
+         </ElScrollbar>
+      </div>
+   </navContainer>
+</template>
+<script setup lang="ts">
+import navContainer from "@/businessComponents/navContainer"
+import { useRouter } from "vue-router"
+import { ref, computed } from "vue"
+import useDialogConfirm from "@/hooks/useDialogConfirm"
+import userStore from "@/store/modules/user"
+import curriculum_gym from "./components/curriculum/curriculum_gym.vue"
+import curriculum_gyt from "./components/curriculum/curriculum_gyt.vue"
+import { getRemind_gyt, getRecentCourseSchedule_gym } from "@/api/homePage.api"
+import { httpAjax } from "@/plugin/httpAjax"
+import { format } from "@/libs/tools"
+
+const userStoreHook = userStore()
+const router = useRouter()
+
+const headImg = {
+   img: require("@/img/homePage/home.png")
+}
+const navs = [
+   {
+      name: "主页"
+   }
+]
+const classTypes_gym = [
+   {
+      img: require("@/img/homePage/kb.png"),
+      name: "课表",
+      url: "/curriculum"
+   },
+   {
+      img: require("@/img/homePage/xl.png"),
+      name: "训练",
+      url: ""
+   },
+   {
+      img: require("@/img/homePage/jdcp.png"),
+      name: "进度测评",
+      url: ""
+   },
+   {
+      img: require("@/img/homePage/xltj.png"),
+      name: "训练统计",
+      url: ""
+   },
+   {
+      img: require("@/img/homePage/yjl.png"),
+      name: "云练习",
+      url: ""
+   },
+   {
+      img: require("@/img/homePage/yjc.png"),
+      name: "云课堂",
+      url: "/cloudTextbooks"
+   }
+]
+const classTypes_gyt = [
+   {
+      img: require("@/img/homePage/kb.png"),
+      name: "课表",
+      url: "/curriculum"
+   },
+   {
+      img: require("@/img/homePage/xl.png"),
+      name: "课后作业",
+      url: ""
+   },
+   {
+      img: require("@/img/homePage/jdzc.png"),
+      name: "阶段自测",
+      url: ""
+   },
+   {
+      img: require("@/img/homePage/xltj.png"),
+      name: "练习情况",
+      url: ""
+   },
+   {
+      img: require("@/img/homePage/yjl.png"),
+      name: "云练习",
+      url: ""
+   },
+   {
+      img: require("@/img/homePage/yjc.png"),
+      name: "云课堂",
+      url: "/cloudTextbooks"
+   }
+]
+
+/* 下次课程信息 */
+const classData = ref<Record<string, any>>({})
+const classDataLoading = ref(true)
+const isEmptyClassData = computed(() => {
+   return !Object.keys(classData.value).length
+})
+handleClassData()
+function handleClassData() {
+   if (userStoreHook.roles === "GYM") {
+      classDataLoading.value = true
+      httpAjax(getRecentCourseSchedule_gym).then(res => {
+         classDataLoading.value = false
+         if (res.code === 200) {
+            classData.value = res.data || {}
+         }
+      })
+   } else {
+      classDataLoading.value = true
+      httpAjax(getRemind_gyt).then(res => {
+         classDataLoading.value = false
+         if (res.code === 200) {
+            classData.value = res.data || {}
+         }
+      })
+   }
+}
+
+function handleRouter(url?: string) {
+   url
+      ? router.push(url)
+      : useDialogConfirm({
+           headImg: require("@/img/homePage/ts.png"),
+           text: "该功能暂未开放,请敬请期待哦~",
+           btnShow: [true]
+        })
+}
+function handleRouterCurriculum() {
+   router.push({
+      path: "/curriculum",
+      query: {
+         date: classData.value.classDate ? format(classData.value.classDate) : ""
+      }
+   })
+}
+</script>
+<style lang="scss" scoped>
+.homePageNav.navContainer {
+   &:deep(.navCon) {
+      .navImg {
+         margin-left: 50px;
+         > img {
+            width: 91px;
+            height: 92px;
+            top: 70%;
+         }
+      }
+      .nav {
+         font-size: 28px;
+         font-family: AlimamaFangYuanTiVF, AlimamaFangYuanTiVF;
+         &:last-child {
+            margin-right: 30px;
+         }
+      }
+   }
+}
+.homePage {
+   width: 100%;
+   height: 100%;
+   & > :deep(.elScrollbar) {
+      .el-scrollbar__view {
+         width: 100%;
+         display: flex;
+         padding: 50px 50px 0;
+      }
+      .el-scrollbar__wrap {
+         overflow-x: hidden;
+      }
+   }
+   .classTypes {
+      flex-grow: 1;
+      display: flex;
+      flex-wrap: wrap;
+      justify-content: space-between;
+      height: 729px;
+      align-content: space-between;
+      .classType {
+         background: #feffff;
+         box-shadow: 0px 2px 14px 0 #f1e3cc;
+         border-radius: 34px;
+         width: 360px;
+         height: 350px;
+         display: flex;
+         justify-content: center;
+         align-items: center;
+         flex-direction: column;
+         cursor: pointer;
+         padding: 44px 53px;
+         &:hover {
+            transform: scale(1.02);
+            box-shadow: 0px 2px 14px 0px #e4d7c2;
+         }
+         > div {
+            margin-top: 10px;
+            font-family: AlimamaFangYuanTiVF, AlimamaFangYuanTiVF;
+            font-weight: bold;
+            font-size: 28px;
+            color: #393939;
+         }
+         > img {
+            width: 100%;
+         }
+      }
+   }
+   .courseBoard {
+      flex-shrink: 0;
+      margin-left: 50px;
+      margin-top: -35px;
+      width: 572px;
+      height: 764px;
+      background: url("@/img/homePage/bg1.png") no-repeat;
+      background-size: 100% 100%;
+      position: relative;
+      &.isEmpty {
+         background: url("@/img/homePage/bg.png") no-repeat;
+         background-size: 100% 100%;
+      }
+      .details {
+         width: 100%;
+         position: absolute;
+         top: 88px;
+         left: 0;
+         padding: 0 30px;
+         .head {
+            height: 81px;
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 0 30px;
+            .leftCon {
+               display: flex;
+               align-items: center;
+               .line {
+                  width: 8px;
+                  height: 28px;
+                  background: linear-gradient(180deg, #ffcb35 0%, #fea60a 100%), #ff6a67;
+                  border-radius: 7px;
+               }
+               .title {
+                  margin-left: 12px;
+                  font-family: AlimamaFangYuanTiVF, AlimamaFangYuanTiVF;
+                  font-weight: bold;
+                  font-size: 28px;
+                  color: #994d1c;
+               }
+            }
+            .rightRouter {
+               width: 38px;
+               height: 38px;
+               cursor: pointer;
+               &:hover {
+                  opacity: $opacity-hover;
+               }
+            }
+         }
+         .elSkeleton {
+            padding: 0 30px;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            > .elSkeletonItem {
+               &:nth-child(1) {
+                  margin-top: 25px;
+                  height: 34px;
+               }
+               &:nth-child(2) {
+                  width: 50%;
+                  margin-top: 58px;
+                  height: 60px;
+               }
+               &:nth-child(3) {
+                  margin-top: 34px;
+               }
+               &:nth-child(4) {
+                  margin-top: 34px;
+               }
+               &:nth-child(6) {
+                  width: 100%;
+                  height: 74px;
+                  margin-top: 58px;
+               }
+            }
+            .elSkeletonBtnCon {
+               width: 100%;
+               margin-top: 76px;
+               display: flex;
+               justify-content: space-between;
+               > .elSkeletonItem {
+                  width: 216px;
+                  height: 65px;
+               }
+            }
+         }
+         :deep(.empty) {
+            margin-top: 114px;
+            padding: 0;
+            .el-empty__image {
+               width: 360px;
+            }
+         }
+      }
+   }
+}
+</style>

+ 49 - 49
vue.config.js

@@ -1,49 +1,49 @@
-const { defineConfig } = require("@vue/cli-service")
-module.exports = defineConfig({
-   transpileDependencies: true,
-   productionSourceMap: false,
-   css: {
-      loaderOptions: {
-         //全局变量
-         sass: {
-            additionalData: `@use "@/assets/variables.scss" as *;`
-         },
-         postcss: {
-            postcssOptions: {
-               plugins: [
-                  require("postcss-pxtorem")({
-                     rootValue: 18, // 换算的基数
-                     selectorBlackList: ["-nopx"], // 忽略转换正则匹配项 列入一些ui库, ['.el'] 就是忽略elementUI库
-                     propList: ["*"],
-                     exclude: file => {
-                        if (file.includes("coursewarePlay")) {
-                           return true
-                        }
-                        if (file.includes("normalize")) {
-                           return true
-                        }
-                        return false
-                     }
-                  })
-               ]
-            }
-         }
-      }
-   },
-   devServer: {
-      proxy: {
-         "/gym": {
-            target: "https://dev.dayaedu.com",
-            pathRewrite: {
-               "^/gym": ""
-            }
-         },
-         "/gyt": {
-            target: "https://dev.lexiaoya.cn",
-            pathRewrite: {
-               "^/gyt": ""
-            }
-         }
-      }
-   }
-})
+const { defineConfig } = require("@vue/cli-service")
+module.exports = defineConfig({
+   transpileDependencies: true,
+   productionSourceMap: false,
+   css: {
+      loaderOptions: {
+         //全局变量
+         sass: {
+            additionalData: `@use "@/assets/variables.scss" as *;`
+         },
+         postcss: {
+            postcssOptions: {
+               plugins: [
+                  require("postcss-pxtorem")({
+                     rootValue: 18, // 换算的基数
+                     selectorBlackList: ["-nopx"], // 忽略转换正则匹配项 列入一些ui库, ['.el'] 就是忽略elementUI库
+                     propList: ["*"],
+                     exclude: file => {
+                        if (file.includes("coursewarePlay")) {
+                           return true
+                        }
+                        if (file.includes("normalize")) {
+                           return true
+                        }
+                        return false
+                     }
+                  })
+               ]
+            }
+         }
+      }
+   },
+   devServer: {
+      proxy: {
+         "/gym": {
+            target: "https://dev.gym.lexiaoya.cn",
+            pathRewrite: {
+               "^/gym": ""
+            }
+         },
+         "/gyt": {
+            target: "https://dev.lexiaoya.cn",
+            pathRewrite: {
+               "^/gyt": ""
+            }
+         }
+      }
+   }
+})