Bladeren bron

Merge branch 'master' of http://git.dayaedu.com/lex/orchestra-app

mo 2 jaren geleden
bovenliggende
commit
fa9ecf999d
100 gewijzigde bestanden met toevoegingen van 1606 en 513 verwijderingen
  1. 22 0
      package-lock.json
  2. 2 0
      package.json
  3. 3 0
      public/project/css/initiation.css
  4. 3 0
      public/project/css/preRegister.css
  5. 29 37
      public/project/initiation.html
  6. 28 34
      public/project/preRegister.html
  7. 14 14
      public/project/schoolRegister.html
  8. 18 2
      src/router/routes-common.ts
  9. 0 8
      src/router/routes-school.ts
  10. 5 3
      src/school/approval-manage/course-adjust.tsx
  11. 10 24
      src/school/companion-teacher/companion-teacher-register.tsx
  12. 17 3
      src/school/companion-teacher/index.tsx
  13. 16 3
      src/school/manage-teacher/index.tsx
  14. 9 16
      src/school/manage-teacher/manage-teacher-register.tsx
  15. 1 0
      src/school/orchestra/index.tsx
  16. 6 0
      src/school/orchestra/modal/teacher-list.tsx
  17. 2 2
      src/school/school-detail/eidt-school.tsx
  18. 7 2
      src/school/train-planning/component/course-preview/index.tsx
  19. 2 2
      src/school/train-planning/component/train-content/index.tsx
  20. 70 60
      src/school/train-planning/modal/practice-class/index.tsx
  21. 4 4
      src/school/train-planning/modal/timer/index.tsx
  22. BIN
      src/student/download/images/download_bg.png
  23. BIN
      src/student/download/images/manage-center.png
  24. BIN
      src/student/download/images/manage_bg.png
  25. BIN
      src/student/download/images/student-center.png
  26. BIN
      src/student/download/images/student_bg.png
  27. BIN
      src/student/download/images/teacher-center.png
  28. BIN
      src/student/download/images/teacher_bg.png
  29. 0 1
      src/student/download/index.tsx
  30. BIN
      src/student/member-center/images/member-1.png
  31. BIN
      src/student/member-center/images/member-2.png
  32. BIN
      src/student/member-center/images/member-3.png
  33. 9 3
      src/student/member-center/index.module.less
  34. 10 2
      src/student/member-center/index.tsx
  35. 17 2
      src/student/music-group/goods-detail/index.module.less
  36. 11 0
      src/student/music-group/goods-detail/index.tsx
  37. 39 2
      src/student/music-group/layout/login.tsx
  38. 4 2
      src/student/music-group/member-bao/index.tsx
  39. 40 24
      src/student/music-group/pre-apply/component/order.tsx
  40. 82 37
      src/student/music-group/pre-apply/component/payment.tsx
  41. BIN
      src/student/music-group/pre-apply/images/member_bao-1.png
  42. BIN
      src/student/music-group/pre-apply/images/member_bao-2.png
  43. BIN
      src/student/music-group/pre-apply/images/member_bao-3.png
  44. 39 4
      src/student/music-group/pre-apply/index.module.less
  45. 57 28
      src/student/music-group/pre-apply/index.tsx
  46. 35 48
      src/student/music-group/pre-apply/order-detail.tsx
  47. 2 11
      src/student/music-group/shop-address/address-operation.tsx
  48. 30 8
      src/student/my-orchestra/apply-withdrawal.tsx
  49. 1 1
      src/student/payment-result/index.tsx
  50. 0 0
      src/teacher/screen-projection/guide.module.less
  51. 4 3
      src/views/courseList/index.tsx
  52. 12 0
      src/views/coursewarePlay/component/musicScore.module.less
  53. 37 11
      src/views/coursewarePlay/component/musicScore.tsx
  54. 2 2
      src/views/coursewarePlay/component/points.tsx
  55. BIN
      src/views/coursewarePlay/image/icon-load.gif
  56. 42 5
      src/views/coursewarePlay/index.module.less
  57. 32 11
      src/views/coursewarePlay/index.tsx
  58. 87 0
      src/views/coursewarePlay/playRecordTime.tsx
  59. 78 0
      src/views/guide/components/andoird-guide.module.less
  60. 187 0
      src/views/guide/components/android-guide.tsx
  61. 84 0
      src/views/guide/components/ios-guide.module.less
  62. 150 0
      src/views/guide/components/ios-guide.tsx
  63. 15 0
      src/views/guide/guide.tsx
  64. BIN
      src/views/guide/images/1.png
  65. BIN
      src/views/guide/images/10.png
  66. BIN
      src/views/guide/images/11.png
  67. BIN
      src/views/guide/images/12.png
  68. BIN
      src/views/guide/images/13.png
  69. BIN
      src/views/guide/images/14.png
  70. BIN
      src/views/guide/images/2.png
  71. BIN
      src/views/guide/images/3.png
  72. BIN
      src/views/guide/images/4.png
  73. BIN
      src/views/guide/images/5.png
  74. BIN
      src/views/guide/images/6.png
  75. BIN
      src/views/guide/images/7.png
  76. BIN
      src/views/guide/images/8.png
  77. BIN
      src/views/guide/images/9.png
  78. BIN
      src/views/guide/images/guide.png
  79. BIN
      src/views/guide/images/icon-img.png
  80. BIN
      src/views/guide/images/icon-music.png
  81. BIN
      src/views/guide/images/icon-video.png
  82. 5 0
      src/views/guide/images/index.ts
  83. 14 9
      src/views/information/help-center/detail.tsx
  84. 4 2
      src/views/information/help-center/index.tsx
  85. 36 28
      src/views/unit-test/examination-mode/index.tsx
  86. BIN
      src/views/unit-test/images/exam-pass-bg-p.png
  87. BIN
      src/views/unit-test/images/icon-pass-check.png
  88. 2 2
      src/views/unit-test/index.tsx
  89. 19 0
      src/views/unit-test/model/anser-title/index.module.less
  90. 16 2
      src/views/unit-test/model/anser-title/index.tsx
  91. 1 1
      src/views/unit-test/model/answer-analysis/index.module.less
  92. 26 13
      src/views/unit-test/model/answer-list/index.tsx
  93. 14 0
      src/views/unit-test/model/choice-question/index.module.less
  94. 26 11
      src/views/unit-test/model/choice-question/index.tsx
  95. 1 1
      src/views/unit-test/model/drag-question/index.module.less
  96. 14 5
      src/views/unit-test/model/drag-question/index.tsx
  97. 7 3
      src/views/unit-test/model/error-mode/index.tsx
  98. 14 7
      src/views/unit-test/model/keep-look-question/index.tsx
  99. 26 10
      src/views/unit-test/model/play-question/index.tsx
  100. 7 0
      src/views/unit-test/model/result-finish/index.module.less

+ 22 - 0
package-lock.json

@@ -18,6 +18,8 @@
         "countup.js": "^2.3.2",
         "dayjs": "^1.10.7",
         "echarts": "^5.3.3",
+        "eventemitter3": "^5.0.0",
+        "howler": "^2.2.3",
         "html-to-image": "^1.9.0",
         "html2canvas": "^1.4.1",
         "loaders.css": "^0.1.2",
@@ -4750,6 +4752,11 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/eventemitter3": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.0.tgz",
+      "integrity": "sha512-riuVbElZZNXLeLEoprfNYoDSwTBRR44X3mnhdI1YcnENpWTCsTTVZ2zFuqQcpoyqPQIUXdiPEU0ECAq0KQRaHg=="
+    },
     "node_modules/execa": {
       "version": "5.1.1",
       "resolved": "https://registry.npmmirror.com/execa/-/execa-5.1.1.tgz",
@@ -5366,6 +5373,11 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/howler": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmmirror.com/howler/-/howler-2.2.3.tgz",
+      "integrity": "sha512-QM0FFkw0LRX1PR8pNzJVAY25JhIWvbKMBFM4gqk+QdV+kPXOhleWGCB6AiAF/goGjIHK2e/nIElplvjQwhr0jg=="
+    },
     "node_modules/html-tags": {
       "version": "3.1.0",
       "resolved": "https://registry.npmmirror.com/html-tags/-/html-tags-3.1.0.tgz",
@@ -13091,6 +13103,11 @@
       "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
       "dev": true
     },
+    "eventemitter3": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.0.tgz",
+      "integrity": "sha512-riuVbElZZNXLeLEoprfNYoDSwTBRR44X3mnhdI1YcnENpWTCsTTVZ2zFuqQcpoyqPQIUXdiPEU0ECAq0KQRaHg=="
+    },
     "execa": {
       "version": "5.1.1",
       "resolved": "https://registry.npmmirror.com/execa/-/execa-5.1.1.tgz",
@@ -13517,6 +13534,11 @@
         "parse-passwd": "^1.0.0"
       }
     },
+    "howler": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmmirror.com/howler/-/howler-2.2.3.tgz",
+      "integrity": "sha512-QM0FFkw0LRX1PR8pNzJVAY25JhIWvbKMBFM4gqk+QdV+kPXOhleWGCB6AiAF/goGjIHK2e/nIElplvjQwhr0jg=="
+    },
     "html-tags": {
       "version": "3.1.0",
       "resolved": "https://registry.npmmirror.com/html-tags/-/html-tags-3.1.0.tgz",

+ 2 - 0
package.json

@@ -30,6 +30,8 @@
     "countup.js": "^2.3.2",
     "dayjs": "^1.10.7",
     "echarts": "^5.3.3",
+    "eventemitter3": "^5.0.0",
+    "howler": "^2.2.3",
     "html-to-image": "^1.9.0",
     "html2canvas": "^1.4.1",
     "loaders.css": "^0.1.2",

+ 3 - 0
public/project/css/initiation.css

@@ -37,6 +37,9 @@ span {
   font-size: 16px;
   font-weight: 500;
 }
+.van-field--disabled .van-field__label {
+  color: #333;
+}
 
 .van-cell--required::before {
   left: 15px;

+ 3 - 0
public/project/css/preRegister.css

@@ -37,6 +37,9 @@ span {
   font-size: 16px;
   font-weight: 500;
 }
+.van-field--disabled .van-field__label {
+  color: #333;
+}
 
 .van-cell--required::before {
   left: 15px;

+ 29 - 37
public/project/initiation.html

@@ -188,35 +188,34 @@
     <van-form validate-first scroll-to-error @submit="onSubmit" ref='form' class="form">
       <div class="top-tips">科学的教育与关爱,足以改变世界。我们希望,学生的未来会因您和我们的共同努力而更加光辉灿烂!</div>
       <van-cell-group inset class="cell-group">
-        <van-field required type="tel" @blur='checkchangePhone' maxlength="11" minlength="11" label="联系电话(直接监护人)"
+        <van-field type="tel" @blur='checkchangePhone' maxlength="11" minlength="11" label="联系电话(直接监护人)"
           v-model="stu.phone" name="phone" :rules="[{ pattern, message: '输入监护人手机号码有误' }]" placeholder="请输入监护人手机号码">
         </van-field>
-        <van-field required label="学员姓名" :rules="[{ validator, message }]" name="username" v-model="stu.username"
-          placeholder="请填写学员真实姓名" :disabled='checkPhone'></van-field>
-        <van-field required label="性别" name="sex" :disabled='checkPhone'
-          :rules="[{ required: true, message: '请选择性别' }]">
+        <van-field label="学员姓名" :rules="[{ validator, message }]" name="username" v-model="stu.username"
+          placeholder="请填写学员真实姓名"></van-field>
+        <van-field label="性别" name="sex" :rules="[{ required: true, message: '请选择性别' }]">
           <template #input>
-            <van-radio-group v-model="stu.sex" :disabled='checkPhone' checked-color="#FF8057" direction="horizontal">
-              <van-tag size="large" type="primary" :color="!(stu.sex === 1) || checkPhone ? '#EAEAEA' : '#FF8057'"
-                :text-color="!(stu.sex === 1) || checkPhone ? '#AAA' : '#FFF'" class="radioSection" round>
+            <van-radio-group v-model="stu.sex" checked-color="#FF8057" direction="horizontal">
+              <van-tag size="large" type="primary" :color="!(stu.sex === 1) ? '#EAEAEA' : '#FF8057'"
+                :text-color="!(stu.sex === 1) ? '#AAA' : '#FFF'" class="radioSection" round>
                 <van-radio class="radioItem" :name="1"></van-radio>男生
               </van-tag>
-              <van-tag size="large" type="primary" :color="!(stu.sex === 0) || checkPhone ? '#EAEAEA' : '#FF8057'"
-                :text-color="!(stu.sex === 0) || checkPhone ? '#AAA' : '#FFF'" class="radioSection" round>
+              <van-tag size="large" type="primary" :color="!(stu.sex === 0) ? '#EAEAEA' : '#FF8057'"
+                :text-color="!(stu.sex === 0) ? '#AAA' : '#FFF'" class="radioSection" round>
                 <van-radio class="radioItem" :name="0"></van-radio>女生
               </van-tag>
             </van-radio-group>
           </template>
         </van-field>
-        <van-field required label="在读年级" :disabled='checkPhone' v-model="stu.currentGrade" readonly name="currentGrade"
+        <van-field label="在读年级" v-model="stu.currentGrade" readonly name="currentGrade"
           :rules="[{ required: true, message: '请选择在读年级', trigger: 'onChange' }]" @click="() => showPicker = true"
-          placeholder="请选择在读年级" clickable>
+          placeholder="请选择在读年级">
           <template #right-icon>
             <van-icon name="arrow" :color="checkPhone ? '#aaa' : '#323233'" size="16"></van-icon>
           </template>
         </van-field>
         <van-field v-show="false" v-model="stu.currentGradeNum" name="currentGradeNum" readonly></van-field>
-        <van-field required label="所在班级" :disabled='checkPhone' v-model="stu.currentClass" readonly name="currentClass"
+        <van-field label="所在班级" v-model="stu.currentClass" readonly name="currentClass"
           :rules="[{ required: true, message: '请选择所在班级', trigger: 'onChange' }]" @click="() => classPicker = true"
           placeholder="请选择所在班级">
           <template #right-icon>
@@ -224,48 +223,41 @@
           </template>
         </van-field>
 
-        <van-field required label="孩子是否有学习过乐器" :disabled='checkPhone' name="musicalInstrumentsLearning"
+        <van-field label="孩子是否有学习过乐器" name="musicalInstrumentsLearning"
           :rules="[{ required: true, message: '请选择孩子是否有学习过乐器' }]">
           <template #input>
-            <van-radio-group v-model="stu.hasLearningExperience" :disabled='checkPhone' checked-color="#FF8057"
-              direction="horizontal">
-              <van-tag size="large" type="primary"
-                :color="!(stu.hasLearningExperience === 1) || checkPhone ? '#EAEAEA' : '#FF8057'"
-                :text-color="!(stu.hasLearningExperience === 1) || checkPhone ? '#AAA' : '#FFF'" class="radioSection"
-                round>
+            <van-radio-group v-model="stu.hasLearningExperience" checked-color="#FF8057" direction="horizontal">
+              <van-tag size="large" type="primary" :color="!(stu.hasLearningExperience === 1) ? '#EAEAEA' : '#FF8057'"
+                :text-color="!(stu.hasLearningExperience === 1) ? '#AAA' : '#FFF'" class="radioSection" round>
                 <van-radio class="radioItem" :name="1"></van-radio>是
               </van-tag>
-              <van-tag size="large" type="primary"
-                :color="!(stu.hasLearningExperience === 0) || checkPhone ? '#EAEAEA' : '#FF8057'"
-                :text-color="!(stu.hasLearningExperience === 0) || checkPhone ? '#AAA' : '#FFF'" class="radioSection"
+              <van-tag size="large" type="primary" :color="!(stu.hasLearningExperience === 0) ? '#EAEAEA' : '#FF8057'"
+                :text-color="!(stu.hasLearningExperience === 0) ? '#AAA' : '#FFF'" class="radioSection"
                 @click="() => stu.learningSubjectName = ''" round>
                 <van-radio class="radioItem" :name="0"></van-radio>否
               </van-tag>
             </van-radio-group>
           </template>
         </van-field>
-        <van-field label="所学乐器" :disabled='checkPhone' v-if="stu.hasLearningExperience==1" name="learningSubjectName"
-          v-model="stu.learningSubjectName" placeholder="请选择所学乐器"></van-field>
-        <van-field required label="是否报名参加管乐团家长会了解相关情况" :disabled='checkPhone' name="joinParentMeeting"
+        <van-field label="所学乐器" v-if="stu.hasLearningExperience==1" name="learningSubjectName"
+          v-model="stu.learningSubjectName" placeholder="(非必填)请选择所学乐器"></van-field>
+        <van-field label="是否报名参加管乐团家长会了解相关情况" name="joinParentMeeting"
           :rules="[{ required: true, message: '请选择是否报名参加管乐团家长会了解相关情况' }]">
           <template #input>
-            <van-radio-group v-model="stu.joinParentMeeting" :disabled='checkPhone' checked-color="#FF8057"
-              direction="horizontal">
-              <van-tag size="large" type="primary"
-                :color="!(stu.joinParentMeeting === 1) || checkPhone ? '#EAEAEA' : '#FF8057'"
-                :text-color="!(stu.joinParentMeeting === 1) || checkPhone ? '#AAA' : '#FFF'" class="radioSection" round>
+            <van-radio-group v-model="stu.joinParentMeeting" checked-color="#FF8057" direction="horizontal">
+              <van-tag size="large" type="primary" :color="!(stu.joinParentMeeting === 1) ? '#EAEAEA' : '#FF8057'"
+                :text-color="!(stu.joinParentMeeting === 1) ? '#AAA' : '#FFF'" class="radioSection" round>
                 <van-radio class="radioItem" :name="1"></van-radio>是
               </van-tag>
-              <van-tag size="large" type="primary"
-                :color="!(stu.joinParentMeeting === 0) || checkPhone ? '#EAEAEA' : '#FF8057'"
-                :text-color="!(stu.joinParentMeeting === 0) || checkPhone ? '#AAA' : '#FFF'" class="radioSection" round>
+              <van-tag size="large" type="primary" :color="!(stu.joinParentMeeting === 0) ? '#EAEAEA' : '#FF8057'"
+                :text-color="!(stu.joinParentMeeting === 0) ? '#AAA' : '#FFF'" class="radioSection" round>
                 <van-radio class="radioItem" :name="0"></van-radio>否
               </van-tag>
             </van-radio-group>
           </template>
         </van-field>
-        <van-field :border="true" label="您对校管乐团的组建有什么建议" :disabled='checkPhone' type="textarea" rows="3"
-          name="personalSuggestion" v-model="stu.personalSuggestion" placeholder="请填写您的建议内容">
+        <van-field :border="true" label="您对校管乐团的组建有什么建议" type="textarea" rows="3" name="personalSuggestion"
+          v-model="stu.personalSuggestion" placeholder="(非必填)请填写您的建议内容">
         </van-field>
       </van-cell-group>
 
@@ -325,7 +317,7 @@
           pickerType: null, // 下拉类型
           stu: {
             username: null, // 姓名
-            sex: null, // 性别
+            sex: 1, // 性别
             phone: null, // 电话
             currentGrade: '', // 年级
             currentGradeNum: null, // 年级编号

+ 28 - 34
public/project/preRegister.html

@@ -188,34 +188,33 @@
     <van-form validate-first scroll-to-error @submit="onSubmit" ref='form' class="form">
       <div class="top-tips">科学的教育与关爱,足以改变世界。我们希望,学生的未来会因您和我们的共同努力而更加光辉灿烂!</div>
       <van-cell-group inset class="cell-group">
-        <van-field required type="tel" @blur='checkchangePhone' maxlength="11" minlength="11" label="联系电话(直接监护人)"
+        <van-field type="tel" @blur='checkchangePhone' maxlength="11" minlength="11" label="联系电话(直接监护人)"
           v-model="stu.phone" name="phone" :rules="[{ pattern, message: '输入监护人手机号码有误' }]" placeholder="请输入监护人手机号码">
         </van-field>
-        <van-field required label="学员姓名" :rules="[{ validator, message }]" name="username" v-model="stu.username"
-          placeholder="请填写学员真实姓名" :disabled='checkPhone'></van-field>
-        <van-field required label="性别" name="sex" :disabled='checkPhone'
-          :rules="[{ required: true, message: '请选择性别' }]">
+        <van-field label="学员姓名" :rules="[{ validator, message }]" name="username" v-model="stu.username"
+          placeholder="请填写学员真实姓名"></van-field>
+        <van-field label="性别" name="sex" :rules="[{ required: true, message: '请选择性别' }]">
           <template #input>
-            <van-radio-group v-model="stu.sex" :disabled='checkPhone' checked-color="#9A64FF" direction="horizontal">
-              <van-tag size="large" type="primary" :color="!(stu.sex === 1) || checkPhone ? '#EAEAEA' : '#64A9FF'"
-                :text-color="!(stu.sex === 1) || checkPhone ? '#AAA' : '#FFF'" class="radioSection" round>
+            <van-radio-group v-model="stu.sex" checked-color="#9A64FF" direction="horizontal">
+              <van-tag size="large" type="primary" :color="!(stu.sex === 1) ? '#EAEAEA' : '#64A9FF'"
+                :text-color="!(stu.sex === 1) ? '#AAA' : '#FFF'" class="radioSection" round>
                 <van-radio class="radioItem" :name="1"></van-radio>男生
               </van-tag>
-              <van-tag size="large" type="primary" :color="!(stu.sex === 0)  || checkPhone? '#EAEAEA' : '#64A9FF'"
-                :text-color="!(stu.sex === 0)  || checkPhone? '#AAA' : '#FFF'" class="radioSection" round>
+              <van-tag size="large" type="primary" :color="!(stu.sex === 0) ? '#EAEAEA' : '#64A9FF'"
+                :text-color="!(stu.sex === 0) ? '#AAA' : '#FFF'" class="radioSection" round>
                 <van-radio class="radioItem" :name="0"></van-radio>女生
               </van-tag>
             </van-radio-group>
           </template>
         </van-field>
-        <van-field required label="在读年级" :disabled='checkPhone' v-model="stu.currentGrade" readonly name="currentGrade"
+        <van-field label="在读年级" v-model="stu.currentGrade" readonly name="currentGrade"
           :rules="[{ required: true, message: '请选择在读年级', trigger: 'onChange' }]" @click="pickerChange"
-          placeholder="请选择在读年级" clickable>
+          placeholder="请选择在读年级">
           <template #right-icon>
             <van-icon name="arrow" :color="checkPhone ? '#aaa' : '#323233'" size="16"></van-icon>
           </template>
         </van-field>
-        <van-field required label="所在班级" :disabled='checkPhone' v-model="stu.currentClass" readonly name="currentClass"
+        <van-field label="所在班级" v-model="stu.currentClass" readonly name="currentClass"
           :rules="[{ required: true, message: '请选择所在班级', trigger: 'onChange' }]" @click="pickerChange1"
           placeholder="请选择所在班级">
           <template #right-icon>
@@ -225,50 +224,46 @@
       </van-cell-group>
 
       <van-cell-group inset class="cell-group">
-        <van-field required label="选报声部" :disabled='checkPhone' v-model="stu.registerSubjectId" readonly
-          name="registerSubjectId" :rules="[{ required: true, message: '请选择选报声部', trigger: 'onChange' }]"
-          @click="pickerChange2" placeholder="请选择选报声部">
+        <van-field label="选报声部" v-model="stu.registerSubjectId" readonly name="registerSubjectId"
+          :rules="[{ required: true, message: '请选择选报声部', trigger: 'onChange' }]" @click="pickerChange2"
+          placeholder="请选择选报声部">
           <template #right-icon>
             <van-icon name="arrow" :color="checkPhone ? '#aaa' : '#323233'" size="16"></van-icon>
           </template>
         </van-field>
 
-        <van-field required label="乐器准备方式" :disabled='checkPhone' name="instrumentsPrepareMode"
-          :rules="[{ required: true, message: '请选择乐器准备方式' }]">
+        <van-field label="乐器准备方式" name="instrumentsPrepareMode" :rules="[{ required: true, message: '请选择乐器准备方式' }]">
           <template #input>
-            <van-radio-group v-model="stu.instrumentsPrepareMode" :disabled='checkPhone' checked-color="#9A64FF"
-              direction="horizontal">
+            <van-radio-group v-model="stu.instrumentsPrepareMode" checked-color="#9A64FF" direction="horizontal">
               <van-tag size="large" type="primary"
-                :color="!(stu.instrumentsPrepareMode === 'GROUP_PURCHASE')  || checkPhone ? '#EAEAEA' : '#64A9FF'"
-                :text-color="!(stu.instrumentsPrepareMode === 'GROUP_PURCHASE') || checkPhone ? '#AAA' : '#FFF'"
-                class="radioSection" round>
+                :color="!(stu.instrumentsPrepareMode === 'GROUP_PURCHASE')  ? '#EAEAEA' : '#64A9FF'"
+                :text-color="!(stu.instrumentsPrepareMode === 'GROUP_PURCHASE') ? '#AAA' : '#FFF'" class="radioSection"
+                round>
                 <van-radio class="radioItem" name="GROUP_PURCHASE"></van-radio>团购
               </van-tag>
               <van-tag size="large" type="primary"
-                :color="!(stu.instrumentsPrepareMode === 'ONESELF') || checkPhone ? '#EAEAEA' : '#64A9FF'"
-                :text-color="!(stu.instrumentsPrepareMode === 'ONESELF') || checkPhone ? '#AAA' : '#FFF'"
-                class="radioSection" round>
+                :color="!(stu.instrumentsPrepareMode === 'ONESELF') ? '#EAEAEA' : '#64A9FF'"
+                :text-color="!(stu.instrumentsPrepareMode === 'ONESELF') ? '#AAA' : '#FFF'" class="radioSection" round>
                 <van-radio class="radioItem" name="ONESELF"></van-radio>自备
               </van-tag>
             </van-radio-group>
           </template>
         </van-field>
 
-        <van-field required label="乐团学习系统准备方式" :disabled='checkPhone' name="learningSystemPrepareMode"
+        <van-field label="乐团学习系统准备方式" name="learningSystemPrepareMode"
           :rules="[{ required: true, message: '请选择乐团学习系统准备方式' }]">
           <template #input>
-            <van-radio-group v-model="stu.learningSystemPrepareMode" :disabled='checkPhone' checked-color="#9A64FF"
-              direction="horizontal">
+            <van-radio-group v-model="stu.learningSystemPrepareMode" checked-color="#9A64FF" direction="horizontal">
               <!-- :color="checkPhone ? '#ccc': '#9A64FF'" -->
               <van-tag size="large" type="primary"
-                :color="!(stu.learningSystemPrepareMode === 'GROUP_PURCHASE') || checkPhone ? '#EAEAEA' : '#64A9FF'"
-                :text-color="!(stu.learningSystemPrepareMode === 'GROUP_PURCHASE') || checkPhone ? '#AAA' : '#FFF'"
+                :color="!(stu.learningSystemPrepareMode === 'GROUP_PURCHASE') ? '#EAEAEA' : '#64A9FF'"
+                :text-color="!(stu.learningSystemPrepareMode === 'GROUP_PURCHASE') ? '#AAA' : '#FFF'"
                 class="radioSection" round>
                 <van-radio class="radioItem" name="GROUP_PURCHASE"></van-radio>团购
               </van-tag>
               <van-tag size="large" type="primary"
-                :color="!(stu.learningSystemPrepareMode === 'ONESELF') || checkPhone ? '#EAEAEA' : '#64A9FF'"
-                :text-color="!(stu.learningSystemPrepareMode === 'ONESELF') || checkPhone ? '#AAA' : '#FFF'"
+                :color="!(stu.learningSystemPrepareMode === 'ONESELF') ? '#EAEAEA' : '#64A9FF'"
+                :text-color="!(stu.learningSystemPrepareMode === 'ONESELF') ? '#AAA' : '#FFF'"
                 :color="checkPhone ? '#ccc': '#9A64FF'" class="radioSection" round>
                 <van-radio class="radioItem" name="ONESELF"></van-radio>自备
               </van-tag>
@@ -455,7 +450,6 @@
               }
             })
 
-            // console.log(userDetail.data.code)
             if (userDetail.data.code === 200 && userDetail.data.data) {
               var detail = userDetail.data.data
               var grade = this.currentGrade.find(item => item.value == detail.currentGrade)

+ 14 - 14
public/project/schoolRegister.html

@@ -45,18 +45,18 @@
 
       <div class="cell_title">学校信息</div>
       <van-cell-group inset class="cell-group">
-        <van-field required label="学校全称" v-model="forms.name" :rules="[{ required: true, message: '请填写学校全称' }]"
-          name="name" placeholder="请填写学校全称" maxlength="50">
+        <van-field label="学校全称" v-model="forms.name" :rules="[{ required: true, message: '请填写学校全称' }]" name="name"
+          placeholder="请填写学校全称" maxlength="50">
         </van-field>
 
-        <van-field required label="所在城市" v-model="forms.cityCodeName" readonly name="cityCodeName" @click="onSelectCity"
+        <van-field label="所在城市" v-model="forms.cityCodeName" readonly name="cityCodeName" @click="onSelectCity"
           :rules="[{ required: true, message: '请选择所在城市', trigger: 'onChange' }]" placeholder="请选择所在城市">
           <template #right-icon>
             <van-icon name="arrow" :color="checkPhone ? '#aaa' : '#323233'" size="16"></van-icon>
           </template>
         </van-field>
 
-        <van-field required label="办学性质" name="schoolNature" :rules="[{ required: true, message: '请选择办学性质' }]">
+        <van-field label="办学性质" name="schoolNature" :rules="[{ required: true, message: '请选择办学性质' }]">
           <template #input>
             <van-radio-group checked-color="#64A9FF" v-model="forms.schoolNature" direction="horizontal">
               <van-tag size="large" type="primary" :color="!(forms.schoolNature === 'PUBLIC') ? '#EAEAEA' : '#64A9FF'"
@@ -71,7 +71,7 @@
           </template>
         </van-field>
 
-        <van-field required label="学年制" name="schoolSystem" :rules="[{ required: true, message: '请选择学年制' }]">
+        <van-field label="学年制" name="schoolSystem" :rules="[{ required: true, message: '请选择学年制' }]">
           <template #input>
             <van-radio-group checked-color="#64A9FF" v-model="forms.schoolSystem" direction="horizontal">
               <van-tag size="large" type="primary"
@@ -89,24 +89,24 @@
         </van-field>
 
         <van-field label="邮箱地址" v-model="forms.email" :rules="[{validator: validatorEmail}]" name="email"
-          placeholder="请输入学校邮箱地址">
+          placeholder="(非必填)请输入学校邮箱地址">
         </van-field>
       </van-cell-group>
 
       <div class="cell_title">负责人</div>
       <van-cell-group inset class="cell-group">
-        <van-field required label="负责人姓名" v-model="forms.emergencyContact" maxlength="20"
-          :rules="[{ required: true, message: '请输入负责人姓名' }]" :maxlength="20" name="emergencyContact"
+        <van-field label="负责人姓名" v-model="forms.emergencyContact" maxlength="5"
+          :rules="[{ required: true, message: '请输入负责人姓名' }]" :maxlength="5" name="emergencyContact"
           placeholder="请输入负责人姓名">
         </van-field>
 
-        <van-field required type="tel" v-model="forms.emergencyContactPhone" maxlength="11" minlength="11"
-          label="负责人手机号" name="emergencyContactPhone"
+        <van-field type="tel" v-model="forms.emergencyContactPhone" maxlength="11" minlength="11" label="负责人手机号"
+          name="emergencyContactPhone"
           :rules="[{ required: true, message: '请输入负责人手机号' },{ pattern, message: '输入负责人手机号有误' }]"
           placeholder="请输入负责人手机号码">
         </van-field>
 
-        <van-field required label="在校职位" v-model="forms.emergencyContactPosition" maxlength="20"
+        <van-field label="在校职位" v-model="forms.emergencyContactPosition" maxlength="20"
           :rules="[{ required: true, message: '请输入负责人在校职位' }]" name="emergencyContactPosition" placeholder="请输入负责人在校职位">
         </van-field>
       </van-cell-group>
@@ -114,18 +114,18 @@
 
       <div class="cell_title">乐团管理老师</div>
       <van-cell-group inset class="cell-group">
-        <van-field required label="管理老师姓名" v-model="forms.educationalAdministrationUsername" maxlength="20"
+        <van-field label="管理老师姓名" v-model="forms.educationalAdministrationUsername" maxlength="5"
           :rules="[{ required: true, message: '请输入管理老师姓名' }]" name="educationalAdministrationUsername"
           placeholder="请输入管理老师姓名">
         </van-field>
 
-        <van-field required type="tel" v-model="forms.educationalAdministrationPhone" maxlength="11" minlength="11"
+        <van-field type="tel" v-model="forms.educationalAdministrationPhone" maxlength="11" minlength="11"
           label="管理老师手机号" name="educationalAdministrationPhone"
           :rules="[{ required: true, message: '请输入管理老师手机号' },{ pattern, message: '输入管理老师手机号有误' }]"
           placeholder="请输入管理老师手机号">
         </van-field>
 
-        <van-field required label="在校职位" v-model="forms.educationalAdministrationPosition" maxlength="20"
+        <van-field label="在校职位" v-model="forms.educationalAdministrationPosition" maxlength="20"
           :rules="[{ required: true, message: '请输入乐团管理老师在校职位' }]" name="educationalAdministrationPosition"
           placeholder="请输入乐团管理老师在校职位">
         </van-field>

+ 18 - 2
src/router/routes-common.ts

@@ -124,7 +124,7 @@ export const router: RouteRecordRaw[] = [
     name: 'practice-mode',
     component: () => import('@/views/unit-test/practice-mode'),
     meta: {
-      title: '测试模式'
+      title: '练习模式'
     }
   },
   {
@@ -134,7 +134,15 @@ export const router: RouteRecordRaw[] = [
     meta: {
       title: '测试详情'
     }
-  }
+  },
+  {
+    path: '/approval-manage-subsidy',
+    name: 'approval-manage-subsidy',
+    component: () => import('@/school/approval-manage/subsidy/index'),
+    meta: {
+      title: '补助确认'
+    }
+  },
 ]
 
 // 不需要登录的路由
@@ -180,6 +188,14 @@ export const rootRouter = [
     }
   },
   {
+    path: '/guide',
+    name: 'guide',
+    component: () => import('@/views/guide/guide'),
+    meta: {
+      title: '投屏帮助'
+    }
+  },
+  {
     path: '/:pathMatch(.*)*',
     component: () => import('@/views/404'),
     meta: {

+ 0 - 8
src/router/routes-school.ts

@@ -303,14 +303,6 @@ export default [
         }
       },
       {
-        path: '/approval-manage-subsidy',
-        name: 'approval-manage-subsidy',
-        component: () => import('@/school/approval-manage/subsidy/index'),
-        meta: {
-          title: '补助确认'
-        }
-      },
-      {
         path: '/subsidy-exercise-detail',
         name: 'subsidy-exercise-detail',
         component: () => import('@/school/approval-manage/subsidy/exercise-detail'),

+ 5 - 3
src/school/approval-manage/course-adjust.tsx

@@ -114,7 +114,7 @@ export default defineComponent({
     const reset = async () => {
       // await getDetail()
       // await getList()
-      if (browser().iPhone && !state.cacheId && state.isBack != 'true') {
+      if (browser().isApp && !state.cacheId && state.isBack != 'true') {
         // setTimeout(() => {
         postMessage({ api: 'back' })
         // }, 1000)
@@ -289,9 +289,11 @@ export default defineComponent({
                   forms.classDate = ''
                   forms.startTime = ''
                   forms.endTime = ''
+                  forms.teacherId = val.id
+                  forms.teacherName = val.nickname
+                  state.calendarDate = ''
+                  getList()
                 }
-                forms.teacherId = val.id
-                forms.teacherName = val.nickname
               }}
             />
           </OPopup>

+ 10 - 24
src/school/companion-teacher/companion-teacher-register.tsx

@@ -91,8 +91,6 @@ export default defineComponent({
         showToast('请阅读并同意协议')
         return
       }
-      console.log(state.forms, '///222')
-      return
       state.btnLoading = true
       try {
         const forms = state.forms
@@ -206,7 +204,9 @@ export default defineComponent({
         const res = await request.post('/api-school/open/schoolTeacherStudent/queryQrCodeStatus', {
           data: {
             schoolId: state.id,
-            qrCodeEffectiveStartTime: state.t ? dayjs(state.t).format('YYYY-MM-DD HH:mm:ss') : null
+            qrCodeEffectiveStartTime: state.t
+              ? dayjs(Number(state.t)).format('YYYY-MM-DD HH:mm:ss')
+              : null
           }
         })
         if (res.code === 999) {
@@ -217,6 +217,7 @@ export default defineComponent({
             confirmButtonColor: '#ff8057'
           })
           state.qrCodeStatus = true
+          state.qrCodeMessage = res.message
         }
       } catch (e: any) {
         //
@@ -356,7 +357,6 @@ export default defineComponent({
         <Form validateFirst scrollToError onSubmit={onSubmit} ref={formRef} class={styles.form}>
           <CellGroup inset class={styles['cell-group']}>
             <Field
-              required
               label="手机号码"
               v-model={state.forms.phone}
               rules={[
@@ -369,19 +369,21 @@ export default defineComponent({
               onBlur={checkchangePhone}
               type="tel"
             ></Field>
+            <div class={styles.phoneTips}>
+              <Icon name="warning" size="16" />
+              提示:手机号码将成为您管乐团老师端登录账号
+            </div>
             <Field
-              required
               label="真实姓名"
               v-model={state.forms.realName}
               rules={[{ required: true, message: '请填写真实姓名' }]}
               name="realName"
               placeholder="请填写真实姓名"
-              maxlength="50"
+              maxlength="5"
               disabled={state.checkPhone}
             ></Field>
 
             <Field
-              required
               label="身份证号码"
               v-model={state.forms.idCardNo}
               rules={[
@@ -398,12 +400,7 @@ export default defineComponent({
               disabled={state.checkPhone}
             ></Field>
 
-            <Field
-              required
-              label="性别"
-              name="gender"
-              rules={[{ required: true, message: '请选择性别' }]}
-            >
+            <Field label="性别" name="gender" rules={[{ required: true, message: '请选择性别' }]}>
               {{
                 input: () => (
                   <RadioGroup
@@ -438,7 +435,6 @@ export default defineComponent({
             </Field>
 
             <Field
-              required
               label="身份证照片正面"
               v-model={state.forms.idcardFrontImg}
               readonly
@@ -458,7 +454,6 @@ export default defineComponent({
               }}
             </Field>
             <Field
-              required
               label="身份证照片反面"
               v-model={state.forms.idcardBackImg}
               readonly
@@ -479,7 +474,6 @@ export default defineComponent({
             </Field>
 
             <Field
-              required
               label="学历"
               v-model={state.forms.educationBackground}
               readonly
@@ -500,7 +494,6 @@ export default defineComponent({
             </Field>
 
             <Field
-              required
               label="毕业学校"
               disabled={state.checkPhone}
               v-model={state.forms.graduateSchool}
@@ -510,7 +503,6 @@ export default defineComponent({
             ></Field>
 
             <Field
-              required
               label="所在城市"
               v-model={state.forms.cityCodeName}
               readonly
@@ -531,7 +523,6 @@ export default defineComponent({
             </Field>
 
             <Field
-              required
               label="声部(可多选)"
               v-model={state.forms.showSubjectIds}
               readonly
@@ -578,7 +569,6 @@ export default defineComponent({
               }}
             </Field>
             <Field
-              required
               label="验证码"
               v-model={state.forms.smsValidCode}
               name="smsValidCode"
@@ -615,10 +605,6 @@ export default defineComponent({
                   )
               }}
             </Field>
-            <div class={styles.phoneTips}>
-              <Icon name="warning" size="16" />
-              提示:手机号码将成为您管乐团老师端登录账号
-            </div>
           </CellGroup>
 
           <div class={styles.protocol}>

+ 17 - 3
src/school/companion-teacher/index.tsx

@@ -37,6 +37,7 @@ import { postMessage, promisefiyPostMessage } from '@/helpers/native-message'
 import html2canvas from 'html2canvas'
 import { forms } from '../train-planning/create'
 import OFullRefresh from '@/components/o-full-refresh'
+import { format } from 'path'
 
 export default defineComponent({
   name: 'companion-teacher',
@@ -68,7 +69,8 @@ export default defineComponent({
         page: 1,
         rows: 20
       },
-      selectItem: {} as any
+      selectItem: {} as any,
+      paramValue: '2'
     })
 
     const getSubjects = async () => {
@@ -272,10 +274,22 @@ export default defineComponent({
       }
     }
 
-    onMounted(() => {
+    onMounted(async () => {
       getDetail(state.user.data.id)
       getSubjects()
       getList()
+
+      try {
+        const { data } = await request.get('/api-school/open/paramConfig/queryByParamName', {
+          requestType: 'form',
+          params: {
+            paramName: 'qr_code_expire_hours'
+          }
+        })
+        form.paramValue = data.paramValue
+      } catch {
+        //
+      }
     })
     return () => (
       <>
@@ -432,7 +446,7 @@ export default defineComponent({
                 <div style={{ textAlign: 'center' }}>
                   <span class={styles.codeBtnText}>扫描上方二维码完成资料填写</span>
                 </div>
-                <div class={styles.codeTips}>二维码将在小时后失效,请及时登记</div>
+                <div class={styles.codeTips}>二维码将在{form.paramValue}小时后失效,请及时登记</div>
               </div>
             </div>
             <div class={styles.codeBottom}>

+ 16 - 3
src/school/manage-teacher/index.tsx

@@ -56,7 +56,8 @@ export default defineComponent({
         page: 1,
         rows: 20
       },
-      isClick: false
+      isClick: false,
+      paramValue: '2'
     })
 
     // 获取当前用户所在的学校
@@ -230,11 +231,23 @@ export default defineComponent({
       }
     }
 
-    onMounted(() => {
+    onMounted(async () => {
       // console.log(state.user.data.id, '1212')
       getDetail(state.user.data.id)
 
       getList()
+
+      try {
+        const { data } = await request.get('/api-school/open/paramConfig/queryByParamName', {
+          requestType: 'form',
+          params: {
+            paramName: 'qr_code_expire_hours'
+          }
+        })
+        form.paramValue = data.paramValue
+      } catch {
+        //
+      }
     })
     return () => (
       <>
@@ -347,7 +360,7 @@ export default defineComponent({
                 <div style={{ textAlign: 'center' }}>
                   <span class={styles.codeBtnText}>扫描上方二维码完成资料填写</span>
                 </div>
-                <div class={styles.codeTips}>二维码将在小时后失效,请及时登记</div>
+                <div class={styles.codeTips}>二维码将在{form.paramValue}小时后失效,请及时登记</div>
               </div>
             </div>
             <div class={styles.codeBottom}>

+ 9 - 16
src/school/manage-teacher/manage-teacher-register.tsx

@@ -132,7 +132,9 @@ export default defineComponent({
         const res = await request.post('/api-school/open/schoolTeacherStudent/queryQrCodeStatus', {
           data: {
             schoolId: state.id,
-            qrCodeEffectiveStartTime: state.t ? dayjs(state.t).format('YYYY-MM-DD HH:mm:ss') : null
+            qrCodeEffectiveStartTime: state.t
+              ? dayjs(Number(state.t)).format('YYYY-MM-DD HH:mm:ss')
+              : null
           }
         })
         if (res.code === 999) {
@@ -216,17 +218,15 @@ export default defineComponent({
         <Form validateFirst scrollToError onSubmit={onSubmit} ref="form" class={styles.form}>
           <CellGroup inset class={styles['cell-group']}>
             <Field
-              required
               label="真实姓名"
               v-model={state.forms.realName}
               rules={[{ required: true, message: '请填写真实姓名' }]}
               name="realName"
               placeholder="请填写真实姓名"
-              maxlength="50"
+              maxlength="5"
             ></Field>
 
             <Field
-              required
               label="手机号码"
               v-model={state.forms.phone}
               rules={[
@@ -238,9 +238,12 @@ export default defineComponent({
               maxlength={11}
               type="tel"
             ></Field>
+            <div class={styles.phoneTips}>
+              <Icon name="warning" size="16" />
+              提示:手机号码将成为您管乐团管理端登录账号
+            </div>
 
             <Field
-              required
               label="身份证号码"
               v-model={state.forms.idCardNo}
               rules={[
@@ -255,12 +258,7 @@ export default defineComponent({
               placeholder="请输入身份证号码"
             ></Field>
 
-            <Field
-              required
-              label="性别"
-              name="gender"
-              rules={[{ required: true, message: '请选择性别' }]}
-            >
+            <Field label="性别" name="gender" rules={[{ required: true, message: '请选择性别' }]}>
               {{
                 input: () => (
                   <RadioGroup
@@ -293,7 +291,6 @@ export default defineComponent({
               }}
             </Field>
             <Field
-              required
               label="验证码"
               v-model={state.forms.smsValidCode}
               name="smsValidCode"
@@ -322,10 +319,6 @@ export default defineComponent({
                   )
               }}
             </Field>
-            <div class={styles.phoneTips}>
-              <Icon name="warning" size="16" />
-              提示:手机号码将成为您管乐团管理端登录账号
-            </div>
           </CellGroup>
 
           <div class={styles.protocol}>

+ 1 - 0
src/school/orchestra/index.tsx

@@ -32,6 +32,7 @@ export default defineComponent({
       },
       params: {
         type: null,
+        status: 'DONE',
         page: 1,
         rows: 20
       }

+ 6 - 0
src/school/orchestra/modal/teacher-list.tsx

@@ -119,6 +119,12 @@ export default defineComponent({
         onSearch()
       }
     )
+    watch(
+      () => props.removeTeacherId,
+      () => {
+        onSearch()
+      }
+    )
 
     onMounted(() => {
       getList()

+ 2 - 2
src/school/school-detail/eidt-school.tsx

@@ -202,7 +202,7 @@ export default defineComponent({
                 rows={3}
                 v-model={forms.email}
                 maxlength={50}
-                placeholder="邮箱"
+                placeholder="请输入邮箱"
               >
                 {{ label: () => <p class={styles.addP}>邮箱</p> }}
               </Field>
@@ -211,7 +211,7 @@ export default defineComponent({
                 rows={3}
                 v-model={forms.emergencyContact}
                 maxlength={50}
-                placeholder="负责人"
+                placeholder="请输入负责人姓名"
               >
                 {{ label: () => <p class={styles.addP}>负责人</p> }}
               </Field>

+ 7 - 2
src/school/train-planning/component/course-preview/index.tsx

@@ -178,12 +178,17 @@ export default defineComponent({
             message: res.message,
             confirmButtonColor: '#ff8057'
           }).then(() => {
+            // 原生班级调整伴学老师时
+            // if (state.type === 'native') {
+            //   postMessage({ api: 'back', content: {} })
+            // } else {
             router.back()
+            // }
           })
           return
         }
         setTimeout(() => {
-          showToast(state.type === 'change' ? '调整成功' : '排课成功')
+          showToast(state.type === 'change' || state.type === 'native' ? '调整成功' : '排课成功')
         }, 100)
         setTimeout(() => {
           state.isClick = false
@@ -375,7 +380,7 @@ export default defineComponent({
         <OSticky position="bottom">
           <div class={'btnGroup'}>
             <Button round block type="primary" onClick={onSubmit} disabled={state.isClick}>
-              {state.type === 'change' ? '确认调整' : '确认排课'}
+              {state.type === 'change' || state.type === 'native' ? '确认调整' : '确认排课'}
             </Button>
           </div>
         </OSticky>

+ 2 - 2
src/school/train-planning/component/train-content/index.tsx

@@ -41,14 +41,14 @@ export default defineComponent({
         SINGLE: 60,
         MUSIC_THEORY: 60,
         INSTRUMENTAL_ENSEMBLE: 60
-      }
+      },
+      disabled: false // 判断是否有班级
     })
     const getClasses = async () => {
       try {
         const { data } = await request.get(
           '/api-school/orchestra/trainingContent/' + state.user.data.school.id
         )
-        console.log(data)
         base.contentList = data || []
       } catch {
         //

+ 70 - 60
src/school/train-planning/modal/practice-class/index.tsx

@@ -180,68 +180,78 @@ export default defineComponent({
             immediateCheck={false}
           >
             <CheckboxGroup class={[styles.gridContainer, styles.gridClass]} v-model={forms.check}>
-              {forms.list.map((item: any) => (
-                <CellGroup
-                  class={styles.classCellGroup}
-                  onClick={() => {
-                    if (item.teacherId) {
-                      onSelect(item.id)
-                    }
-                  }}
-                  border={false}
-                >
-                  <Cell center titleStyle={{ flex: '0 auto' }} valueClass={styles.classCheckbox}>
-                    {{
-                      icon: () => <Image src={iconTeacher} class={styles.img} />,
-                      title: () => (
-                        <div class={styles.content}>
-                          <div class={styles.teacherName}>
-                            {item.teacherName ? (
-                              <div class={[styles.name, styles.maxWidth, 'van-ellipsis']}>
-                                {item.teacherName}
+              {forms.list.map(
+                (item: any) =>
+                  item.preStudentNum > 0 && (
+                    <CellGroup
+                      class={styles.classCellGroup}
+                      onClick={() => {
+                        if (item.teacherId) {
+                          onSelect(item.id)
+                        }
+                      }}
+                      border={false}
+                    >
+                      <Cell
+                        center
+                        titleStyle={{ flex: '0 auto' }}
+                        valueClass={styles.classCheckbox}
+                      >
+                        {{
+                          icon: () => <Image src={iconTeacher} class={styles.img} />,
+                          title: () => (
+                            <div class={styles.content}>
+                              <div class={styles.teacherName}>
+                                {item.teacherName ? (
+                                  <div class={[styles.name, styles.maxWidth, 'van-ellipsis']}>
+                                    {item.teacherName}
+                                  </div>
+                                ) : (
+                                  <div
+                                    class={[styles.name, 'van-ellipsis']}
+                                    style={{ color: 'red' }}
+                                  >
+                                    暂未设置伴学指导
+                                  </div>
+                                )}
+                                <Tag type="primary">{item.name}</Tag>
                               </div>
-                            ) : (
-                              <div class={[styles.name, 'van-ellipsis']} style={{ color: 'red' }}>
-                                暂未设置伴学指导
+                              <div class={[styles.orchestraName, 'van-ellipsis']}>
+                                {item.orchestraName}
                               </div>
-                            )}
-                            <Tag type="primary">{item.name}</Tag>
-                          </div>
-                          <div class={[styles.orchestraName, 'van-ellipsis']}>
-                            {item.orchestraName}
-                          </div>
-                        </div>
-                      ),
-                      value: () => (
-                        <Checkbox
-                          name={item.id}
-                          ref={(el: any) => (forms.checkboxRefs[item.id] = el)}
-                          disabled={item.teacherId ? false : true}
-                          onClick={(e: any) => {
-                            e.stopPropagation()
-                          }}
-                        ></Checkbox>
-                      )
-                    }}
-                  </Cell>
-                  <Grid border={false} columnNum={3}>
-                    <GridItem>
-                      <p class={styles.title}>{item.preStudentNum}</p>
-                      <p class={styles.name}>学生人数</p>
-                    </GridItem>
-                    <GridItem>
-                      <p class={[styles.title]}>
-                        {item.courseScheduleNum - item.completeCourseScheduleNum}
-                      </p>
-                      <p class={styles.name}>剩余课时</p>
-                    </GridItem>
-                    <GridItem>
-                      <p class={styles.title}>{item.courseScheduleNum}</p>
-                      <p class={styles.name}>总课时</p>
-                    </GridItem>
-                  </Grid>
-                </CellGroup>
-              ))}
+                            </div>
+                          ),
+                          value: () => (
+                            <Checkbox
+                              name={item.id}
+                              ref={(el: any) => (forms.checkboxRefs[item.id] = el)}
+                              disabled={item.teacherId ? false : true}
+                              onClick={(e: any) => {
+                                e.stopPropagation()
+                              }}
+                            ></Checkbox>
+                          )
+                        }}
+                      </Cell>
+                      <Grid border={false} columnNum={3}>
+                        <GridItem>
+                          <p class={styles.title}>{item.preStudentNum}</p>
+                          <p class={styles.name}>学生人数</p>
+                        </GridItem>
+                        <GridItem>
+                          <p class={[styles.title]}>
+                            {item.courseScheduleNum - item.completeCourseScheduleNum}
+                          </p>
+                          <p class={styles.name}>剩余课时</p>
+                        </GridItem>
+                        <GridItem>
+                          <p class={styles.title}>{item.courseScheduleNum}</p>
+                          <p class={styles.name}>总课时</p>
+                        </GridItem>
+                      </Grid>
+                    </CellGroup>
+                  )
+              )}
             </CheckboxGroup>
           </List>
         ) : (

+ 4 - 4
src/school/train-planning/modal/timer/index.tsx

@@ -194,20 +194,20 @@ export default defineComponent({
           {state.useTimer.map((item: any) => (
             <Cell
               center
-              value={`${dayjs(item.startTime).format('HH:mm')}~${dayjs(item.endTime).format(
+              title={`${dayjs(item.startTime).format('HH:mm')}~${dayjs(item.endTime).format(
                 'HH:mm'
               )}`}
-              title="可排课时间段"
+              value="可排课时间段"
             ></Cell>
           ))}
 
           {state.usedTimer.map((item: any) => (
             <Cell
               center
-              title={`${dayjs(item.startTime).format('HH:mm')}~${dayjs(item.endTime).format(
+              value={`${dayjs(item.startTime).format('HH:mm')}~${dayjs(item.endTime).format(
                 'HH:mm'
               )}`}
-              value="冲突时间"
+              title="冲突时间"
               class={styles.noTime}
             ></Cell>
           ))}

BIN
src/student/download/images/download_bg.png


BIN
src/student/download/images/manage-center.png


BIN
src/student/download/images/manage_bg.png


BIN
src/student/download/images/student-center.png


BIN
src/student/download/images/student_bg.png


BIN
src/student/download/images/teacher-center.png


BIN
src/student/download/images/teacher_bg.png


+ 0 - 1
src/student/download/index.tsx

@@ -7,7 +7,6 @@ import { browser } from '@/helpers/utils'
 import student from './images/student-center.png'
 import teacher from './images/teacher-center.png'
 import manage from './images/manage-center.png'
-import OSticky from '@/components/o-sticky'
 
 // 唤起前缀
 // BandMusicTeam:// 管乐团

BIN
src/student/member-center/images/member-1.png


BIN
src/student/member-center/images/member-2.png


BIN
src/student/member-center/images/member-3.png


+ 9 - 3
src/student/member-center/index.module.less

@@ -86,6 +86,13 @@
     }
   }
 
+  .memberImgs {
+    img {
+      margin-bottom: 6px;
+      width: 100%;
+    }
+  }
+
   .intro {
     background: url('./images/tip_bg.png') no-repeat center;
     background-size: contain;
@@ -156,7 +163,6 @@
     box-sizing: content-box;
     padding-top: 16px;
     padding-bottom: 10px;
-    margin-bottom: 10px;
   }
   .system-item {
     display: flex;
@@ -169,7 +175,7 @@
     box-sizing: border-box;
     background: #ffffff;
     border-radius: 12px;
-    border: 1px solid #e5e5e5;
+    // border: 1px solid #e5e5e5;
     .title {
       font-weight: 500;
       font-size: 14px;
@@ -211,7 +217,7 @@
       // background: linear-gradient(215deg, #ffe7c4 0%, rgba(250, 211, 156, 0.21) 100%);
       background: url('./images/vip_bg.png') no-repeat center center;
       background-size: cover;
-      border: 1px solid #b1652e;
+      // border: 1px solid #b1652e;
       position: relative;
       .title {
         color: #814014;

+ 10 - 2
src/student/member-center/index.tsx

@@ -12,6 +12,9 @@ import dayjs from 'dayjs'
 import { memberType } from '@/constant'
 import { moneyFormat } from '@/helpers/utils'
 import OHeader from '@/components/o-header'
+import member1 from './images/member-1.png'
+import member2 from './images/member-2.png'
+import member3 from './images/member-3.png'
 
 export const getAssetsHomeFile = (fileName: string) => {
   const path = `./images/${fileName}`
@@ -252,8 +255,13 @@ export default defineComponent({
               </div>
             </div>
           </div>
+          <div class={styles.memberImgs}>
+            <img src={member1} />
+            <img src={member2} />
+            <img src={member3} />
+          </div>
 
-          <div class={[styles.intro]}>
+          {/* <div class={[styles.intro]}>
             <p>
               团练宝会员使用包括平台提供教材的所有训练乐谱,并专享“乐器练习云教练”八大核心功能,孩子在家就能轻松完成乐器自主规范练习。
             </p>
@@ -270,7 +278,7 @@ export default defineComponent({
                 </div>
               ))}
             </div>
-          </div>
+          </div> */}
         </div>
         <div class={styles.btnGroup}>
           <div class={styles.priceSection}>

+ 17 - 2
src/student/music-group/goods-detail/index.module.less

@@ -19,10 +19,25 @@
   padding: 8px 0;
   :global {
     .van-cell {
-      padding-top: 5px;
-      padding-bottom: 5px;
+      padding: 5px 16px;
     }
   }
+
+  .sectionTips {
+    margin: 6px 16px;
+    display: flex;
+    align-items: center;
+    font-size: 14px;
+    color: #ff4e19;
+    padding: 5px 6px;
+    background: #ffebdd;
+    border-radius: 6px;
+  }
+  .iconGives {
+    width: 32px;
+    height: 18px;
+    margin-right: 8px;
+  }
 }
 
 .priceGroup {

+ 11 - 0
src/student/music-group/goods-detail/index.tsx

@@ -3,6 +3,7 @@ import { moneyFormat } from '@/helpers/utils'
 import { Swipe, SwipeItem, Image, CellGroup, Cell, showImagePreview } from 'vant'
 import { defineComponent } from 'vue'
 import styles from './index.module.less'
+import iconGives from '../pre-apply/images/icon-gives.png'
 
 export default defineComponent({
   name: 'goods-detail',
@@ -11,6 +12,10 @@ export default defineComponent({
       type: Number,
       default: 0
     },
+    goodsInfo: {
+      type: Object,
+      default: () => ({})
+    },
     id: {
       type: String,
       defualt: ''
@@ -200,6 +205,12 @@ export default defineComponent({
             title={product.name}
             titleClass={[styles.goodsName, 'van-ellipsis']}
           />
+          {this.goodsInfo.showFree && (
+            <div class={styles.sectionTips}>
+              <Image src={iconGives} class={styles.iconGives} />
+              赠价值{this.goodsInfo.originalPrice}元乐器维保服务一年
+            </div>
+          )}
         </CellGroup>
 
         {this.detailMobileHtml && (

+ 39 - 2
src/student/music-group/layout/login.tsx

@@ -1,5 +1,16 @@
 import { defineComponent } from 'vue'
-import { CellGroup, Field, Button, CountDown, Row, Col, showToast, Popup } from 'vant'
+import {
+  CellGroup,
+  Field,
+  Button,
+  CountDown,
+  Row,
+  Col,
+  showToast,
+  Popup,
+  showDialog,
+  closeToast
+} from 'vant'
 import ImgCode from '@/components/o-img-code'
 import { checkPhone } from '@/helpers/validate'
 import { setLogin, state } from '@/state'
@@ -23,8 +34,10 @@ export default defineComponent({
       // countDownRef: null as any, // 倒计时实例
       imgCodeStatus: false,
       showPopup: false,
+      showPopupMessage: '请使用微信打开',
       wxAppId: '', //
       code: '', // 授权code码
+      orchestraInfo: {} as any,
 
       // 是否开启微信登录(测试使用)默认为false
       testIsWeixin: false
@@ -45,13 +58,33 @@ export default defineComponent({
     if (!browser().weixin && !this.testIsWeixin) {
       this.showPopup = true
     }
+
+    this.getDetails()
   },
   methods: {
+    async getDetails() {
+      try {
+        const id = this.$route.query.id
+        if (!id) return
+        const { data } = await request.get(
+          '/api-student/open/orchestra/detail/' + this.$route.query.id
+        )
+        this.orchestraInfo = data || {}
+
+        if (!data.canSignUp) {
+          this.showPopup = true
+          this.showPopupMessage = '乐团建设中,请稍等'
+        }
+      } catch {
+        //
+      }
+    },
     async getAppIdAndCode(url?: string) {
       try {
         const { data } = await request.get('/api-student/open/paramConfig/wechatAppId')
         // 判断是否有微信appId
         if (data) {
+          closeToast()
           this.goAuth(data, url)
         }
       } catch {
@@ -101,6 +134,10 @@ export default defineComponent({
     },
     async onLogin() {
       try {
+        if (!this.orchestraInfo.canSignUp) {
+          this.showPopup = true
+          this.showPopupMessage = '乐团建设中,请稍等'
+        }
         // let res: any
         const forms: any = {
           username: this.username,
@@ -236,7 +273,7 @@ export default defineComponent({
         >
           <div class={styles.popupContainer}>
             <p class={styles.title}>温馨提示</p>
-            <p class={styles.popupTips}>请使用微信打开</p>
+            <p class={styles.popupTips}>{this.showPopupMessage}</p>
           </div>
         </Popup>
       </div>

+ 4 - 2
src/student/music-group/member-bao/index.tsx

@@ -2,15 +2,17 @@ import { Image } from 'vant'
 import { defineComponent } from 'vue'
 import bg1 from '../pre-apply/images/member_bao-1.png'
 import bg2 from '../pre-apply/images/member_bao-2.png'
+import bg3 from '../pre-apply/images/member_bao-3.png'
 
 export default defineComponent({
   name: 'member-bao',
   setup() {
     return () => (
-      <>
+      <div style={{ lineHeight: '0' }}>
         <Image src={bg1} />
         <Image src={bg2} />
-      </>
+        <Image src={bg3} />
+      </div>
     )
   }
 })

+ 40 - 24
src/student/music-group/pre-apply/component/order.tsx

@@ -187,28 +187,45 @@ export default defineComponent({
                       : ''
                   }
                 ></Cell>
-                <Cell border={false} class={styles.imgGroup}>
+                <Cell border={false} class={styles.imgGroup} center>
                   {{
                     title: () => (
-                      <Grid border={false}>
-                        {item.goodsInfos &&
-                          item.goodsInfos.map((goods: any) => (
-                            <GridItem>
-                              <Image class={styles.img} src={goods.goodsUrl} />
-                            </GridItem>
-                          ))}
-                      </Grid>
+                      <div class={styles.orderPriceInfo}>
+                        <Grid border={false} columnNum={3}>
+                          {item.goodsInfos &&
+                            item.goodsInfos.map(
+                              (goods: any, index: number) =>
+                                index < 3 && (
+                                  <GridItem>
+                                    <Image class={styles.img} src={goods.goodsUrl} />
+                                  </GridItem>
+                                )
+                            )}
+                        </Grid>
+                        <div class={styles.orderPriceNum}>
+                          <div class={styles.opNums}>
+                            <span>¥</span>
+                            {moneyFormat(item.currentPrice)}
+                          </div>
+                          <div class={styles.opBuyLength}>
+                            共{(item.goodsInfos && item.goodsInfos.length) || 0}件
+                          </div>
+                        </div>
+                      </div>
                     )
                   }}
                 </Cell>
-                <Cell class={styles.btnGroup} center>
-                  {{
-                    title: () => (
-                      <span class={styles.btnPrice}>¥{moneyFormat(item.currentPrice)}</span>
-                    ),
-                    value: () => (
-                      <div class={styles.btns}>
-                        {/* {item.status === 'WAIT_PAY' && (
+                {item.refundable && (
+                  <Cell class={styles.btnGroup} center>
+                    {{
+                      title: () => (
+                        <span class={styles.btnPrice}>
+                          {/* ¥{moneyFormat(item.currentPrice)} */}
+                        </span>
+                      ),
+                      value: () => (
+                        <div class={styles.btns}>
+                          {/* {item.status === 'WAIT_PAY' && (
                           <>
                             <Button round plain color="#AAAAAA">
                               修改订单
@@ -218,8 +235,7 @@ export default defineComponent({
                             </Button>
                           </>
                         )} */}
-                        {/* 订单成功 订单金额大于0 */}
-                        {item.refundable && (
+                          {/* 订单成功 订单金额大于0 */}
                           <Button
                             round
                             plain
@@ -232,11 +248,11 @@ export default defineComponent({
                           >
                             申请退款
                           </Button>
-                        )}
-                      </div>
-                    )
-                  }}
-                </Cell>
+                        </div>
+                      )
+                    }}
+                  </Cell>
+                )}
               </CellGroup>
             ))}
           </List>

+ 82 - 37
src/student/music-group/pre-apply/component/payment.tsx

@@ -23,6 +23,7 @@ import { CountUp } from 'countup.js'
 import OPopup from '@/components/o-popup'
 import MemberBao from '../../member-bao'
 import GoodsDetail from '../../goods-detail'
+import ODialog from '@/components/o-dialog'
 
 export default defineComponent({
   name: 'payment',
@@ -46,7 +47,11 @@ export default defineComponent({
       memberBaoStatus: false, // 团练宝详情状态
       goodsStatus: false, //
       selectGoodsId: null as any,
-      currentPrice: 0
+      currentPrice: 0,
+      selectGoodsInfo: {} as any,
+      dialogStatus: false,
+      dialogMessage: '',
+      dialogConfig: {} as any
     })
 
     // 查询未支付订单
@@ -55,29 +60,9 @@ export default defineComponent({
         const { data } = await request.get('/api-student/userPaymentOrder/unpaid')
         // 判断是否有待支付订单
         if (data.id) {
-          showConfirmDialog({
-            message: '您有待支付的订单,是否继续支付',
-            cancelButtonText: '取消订单',
-            confirmButtonText: '继续支付'
-          })
-            .then(() => {
-              const paymentConfig = data.paymentConfig
-              router.push({
-                path: '/orderDetail',
-                query: {
-                  pm: 1, // h5乐团报名
-                  config: JSON.stringify(paymentConfig.paymentConfig),
-                  orderNo: paymentConfig.orderNo
-                }
-              })
-            })
-            .catch(async () => {
-              try {
-                await request.post('/api-student/userPaymentOrder/cancelPayment/' + data.orderNo)
-              } catch {
-                //
-              }
-            })
+          state.dialogMessage = '您有待支付的订单,是否继续支付'
+          state.dialogStatus = true
+          state.dialogConfig = data
         }
       } catch {
         //
@@ -285,7 +270,6 @@ export default defineComponent({
             2、所有参与乐团的学生免费赠送选报声部教材,教材随乐器一同发放,若您自备乐器,则需承担教材运费。
           </p>
         </div>
-
         <CheckboxGroup
           v-model={state.check}
           style={{ paddingBottom: '20px' }}
@@ -331,11 +315,24 @@ export default defineComponent({
                             e.stopPropagation()
                             state.selectGoodsId = state.goodsInfo.goodsId
                             state.currentPrice = state.goodsInfo.currentPrice
+                            state.selectGoodsInfo = {
+                              showFree: true,
+                              originalPrice: state.repaireInfo.originalPrice
+                            }
                             state.goodsStatus = true
                           }}
                         />
                         <div class={styles.sectionContent}>
-                          <h2>{state.goodsInfo.goodsName}</h2>
+                          <h2
+                            onClick={(e: any) => {
+                              e.stopPropagation()
+                              state.selectGoodsId = state.goodsInfo.goodsId
+                              state.currentPrice = state.goodsInfo.currentPrice
+                              state.goodsStatus = true
+                            }}
+                          >
+                            {state.goodsInfo.goodsName}
+                          </h2>
                           <Tag
                             color="linear-gradient(135deg, #FF8C4A 0%, #FF531C 100%)"
                             textColor="#fff"
@@ -355,7 +352,7 @@ export default defineComponent({
                       <div class={styles.extra}>
                         <div class={styles.sectionPrice}>
                           <p class={styles.price}>
-                            新团特惠
+                            团购价
                             <span class={styles.numFont}>
                               <span class={styles.numPrefix}>¥</span>
                               {moneyFormat(state.goodsInfo.currentPrice)}
@@ -428,11 +425,22 @@ export default defineComponent({
                             e.stopPropagation()
                             state.selectGoodsId = state.textBookInfo.goodsId
                             state.currentPrice = state.textBookInfo.currentPrice
+                            state.selectGoodsInfo = {}
                             state.goodsStatus = true
                           }}
                         />
                         <div class={styles.sectionContent}>
-                          <h2>{state.textBookInfo.goodsName}</h2>
+                          <h2
+                            onClick={(e: any) => {
+                              e.stopPropagation()
+                              state.selectGoodsId = state.textBookInfo.goodsId
+                              state.currentPrice = state.textBookInfo.currentPrice
+                              state.selectGoodsInfo = {}
+                              state.goodsStatus = true
+                            }}
+                          >
+                            {state.textBookInfo.goodsName}
+                          </h2>
                           <Tag
                             color="linear-gradient(135deg, #FF8C4A 0%, #FF531C 100%)"
                             textColor="#fff"
@@ -452,7 +460,7 @@ export default defineComponent({
                       <div class={styles.extra}>
                         <div class={styles.sectionPrice}>
                           <p class={styles.price}>
-                            新团特惠
+                            团购价
                             <span
                               class={[
                                 state.textBookInfo.currentPrice > 0 ? styles.numFont : styles.free
@@ -522,7 +530,14 @@ export default defineComponent({
                           }}
                         />
                         <div class={styles.sectionContent}>
-                          <h2>{state.vipInfo.goodsName}</h2>
+                          <h2
+                            onClick={(e: any) => {
+                              e.stopPropagation()
+                              state.memberBaoStatus = true
+                            }}
+                          >
+                            {state.vipInfo.goodsName}
+                          </h2>
                           <Tag
                             color="linear-gradient(135deg, #FF8C4A 0%, #FF531C 100%)"
                             textColor="#fff"
@@ -542,7 +557,7 @@ export default defineComponent({
                       <div class={styles.extra}>
                         <div class={styles.sectionPrice}>
                           <p class={styles.price}>
-                            新团特惠
+                            团购价
                             <span class={styles.numFont}>
                               <span class={styles.numPrefix}>¥</span>
                               {moneyFormat(state.vipInfo.currentPrice)}
@@ -563,7 +578,6 @@ export default defineComponent({
             </>
           )}
         </CheckboxGroup>
-
         <OSticky position="bottom" background="white">
           <div class={styles.paymentContainer}>
             <div class={styles.payemntPrice}>
@@ -575,8 +589,9 @@ export default defineComponent({
                 </span>
               </p>
               <p class={styles.allPrice}>
-                总原价:
-                <del class={styles.numFont}>¥{moneyFormat(state.orderInfo.originalPrice)}</del>
+                <del class={styles.numFont}>
+                  总原价:¥{moneyFormat(state.orderInfo.originalPrice)}
+                </del>
               </p>
             </div>
             <div class={styles.paymentBtn}>
@@ -590,16 +605,46 @@ export default defineComponent({
             </div>
           </div>
         </OSticky>
-
         <OPopup v-model:modelValue={state.memberBaoStatus} position="right">
           <MemberBao />
         </OPopup>
-
         <OPopup v-model:modelValue={state.goodsStatus} position="right" destroy>
           {state.goodsStatus && (
-            <GoodsDetail id={state.selectGoodsId} groupPrice={state.currentPrice} />
+            <GoodsDetail
+              id={state.selectGoodsId}
+              groupPrice={state.currentPrice}
+              goodsInfo={state.selectGoodsInfo}
+            />
           )}
         </OPopup>
+        <ODialog
+          title="提示"
+          v-model:show={state.dialogStatus}
+          message={state.dialogMessage}
+          confirmButtonText="继续支付"
+          cancelButtonText="取消订单"
+          showCancelButton
+          onConfirm={() => {
+            const paymentConfig = state.dialogConfig.paymentConfig
+            router.push({
+              path: '/orderDetail',
+              query: {
+                pm: 1, // h5乐团报名
+                config: JSON.stringify(paymentConfig.paymentConfig),
+                orderNo: paymentConfig.orderNo
+              }
+            })
+          }}
+          onCancel={async () => {
+            try {
+              await request.post(
+                '/api-student/userPaymentOrder/cancelPayment/' + state.dialogConfig.orderNo
+              )
+            } catch {
+              //
+            }
+          }}
+        />
       </>
     )
   }

BIN
src/student/music-group/pre-apply/images/member_bao-1.png


BIN
src/student/music-group/pre-apply/images/member_bao-2.png


BIN
src/student/music-group/pre-apply/images/member_bao-3.png


+ 39 - 4
src/student/music-group/pre-apply/index.module.less

@@ -112,6 +112,7 @@
   background: #ffffff;
   border-radius: 10px;
   padding: 12px 14px;
+  margin-bottom: 12px;
   font-size: 14px;
   color: #777;
   line-height: 20px;
@@ -245,7 +246,7 @@
 }
 .section {
   display: flex;
-  align-items: center;
+  // align-items: center;
 
   .img {
     width: 88px;
@@ -300,10 +301,10 @@
 }
 
 .imgGroup {
-  padding: 15px 0 18px;
+  padding: 15px 12px 18px 6px !important;
   .img {
-    width: 75px;
-    height: 75px;
+    width: 70px;
+    height: 70px;
     border-radius: 6px;
     overflow: hidden;
   }
@@ -313,11 +314,45 @@
       padding: 0;
     }
   }
+
+  .orderPriceInfo {
+    display: flex;
+    align-content: center;
+
+    & > div {
+      flex: 1 auto;
+    }
+
+    .orderPriceNum {
+      flex: 0 auto;
+      width: 100px;
+      text-align: right;
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      .opNums {
+        span {
+          font-size: 12px;
+        }
+        font-size: 16px;
+        font-family: DINA;
+        font-weight: bold;
+        color: #333333;
+        line-height: 14px;
+      }
+      .opBuyLength {
+        font-size: 13px;
+        color: #777777;
+        line-height: 18px;
+      }
+    }
+  }
 }
 
 .btnGroup {
   padding-top: 0;
   .btnPrice {
+    font-family: DINA;
     font-size: 22px;
     font-weight: bold;
     color: #ff4e19;

+ 57 - 28
src/student/music-group/pre-apply/index.tsx

@@ -10,6 +10,7 @@ import { useRoute, useRouter } from 'vue-router'
 import { setLogout } from '@/state'
 import request from '@/helpers/request'
 import { browser, getUrlCode } from '@/helpers/utils'
+import ODialog from '@/components/o-dialog'
 
 export default defineComponent({
   name: 'pre-apply',
@@ -24,6 +25,8 @@ export default defineComponent({
       register: true, // 是否注册
       // showPopup: false,
       code: '' as any,
+      dialogStatus: false,
+      dialogMessage: '',
 
       // 是否开启微信登录(测试使用)默认为false
       testIsWeixin: false
@@ -73,40 +76,44 @@ export default defineComponent({
         // 判断乐团报名,只有 乐团报名 乐团交付 已交付才可以报名
         const oStatus = data.status // 乐团状态
         if (oStatus !== 'REGISTER' && oStatus !== 'DOING' && oStatus !== 'DONE') {
-          showDialog({
-            title: '提示',
-            message: '乐团建设中,请稍等'
-          }).then(() => {
-            setLogout()
+          // showDialog({
+          //   title: '提示',
+          //   message: '乐团建设中,请稍等'
+          // }).then(() => {
+          //   setLogout()
 
-            const query = {
-              returnUrl: route.path,
-              ...route.query
-            } as any
-            router.replace({
-              path: '/loginMusic',
-              query: query
-            })
-          })
+          //   const query = {
+          //     returnUrl: route.path,
+          //     ...route.query
+          //   } as any
+          //   router.replace({
+          //     path: '/loginMusic',
+          //     query: query
+          //   })
+          // })
+          state.dialogMessage = '乐团建设中,请稍等'
+          state.dialogStatus = true
           return
         }
 
         // 判断乐团
         if (data.registerOrchestra >= 1) {
-          showDialog({
-            title: '提示',
-            message: '您已在其它乐团'
-          }).then(() => {
-            setLogout()
-            const query = {
-              returnUrl: route.path,
-              ...route.query
-            } as any
-            router.replace({
-              path: '/loginMusic',
-              query: query
-            })
-          })
+          // showDialog({
+          //   title: '提示',
+          //   message: '您已在其它乐团'
+          // }).then(() => {
+          //   setLogout()
+          //   const query = {
+          //     returnUrl: route.path,
+          //     ...route.query
+          //   } as any
+          //   router.replace({
+          //     path: '/loginMusic',
+          //     query: query
+          //   })
+          // })
+          state.dialogMessage = '您已在其它乐团'
+          state.dialogStatus = true
           return
         }
 
@@ -123,6 +130,10 @@ export default defineComponent({
         //     }
         //   }
         // }
+
+        // nextTick(() => {
+        //   state.tabValue = 'order'
+        // })
       } catch {
         //
       }
@@ -238,6 +249,24 @@ export default defineComponent({
             <p class={styles.popupTips}>请使用微信打开</p>
           </div>
         </Popup> */}
+
+        <ODialog
+          title="提示"
+          v-model:show={state.dialogStatus}
+          message={state.dialogMessage}
+          confirmButtonText="确定"
+          onConfirm={() => {
+            setLogout()
+            const query = {
+              returnUrl: route.path,
+              ...route.query
+            } as any
+            router.replace({
+              path: '/loginMusic',
+              query: query
+            })
+          }}
+        />
       </div>
     )
   }

+ 35 - 48
src/student/music-group/pre-apply/order-detail.tsx

@@ -16,6 +16,8 @@ import UserAuth from './component/user-auth'
 import qs from 'query-string'
 import MemberBao from '../member-bao'
 import GoodsDetail from '../goods-detail'
+import ODialog from '@/components/o-dialog'
+import { orderStatus } from '@/constant'
 
 export default defineComponent({
   name: 'order-detail',
@@ -40,7 +42,9 @@ export default defineComponent({
       memberBaoStatus: false, // 团练宝详情状态
       goodsStatus: false, //
       selectGoodsId: null as any,
-      currentPrice: 0
+      currentPrice: 0,
+      dialogStatus: false,
+      dialogMessage: ''
     })
 
     const orderType = computed(() => {
@@ -92,17 +96,19 @@ export default defineComponent({
         // REFUNDED: '已退款'
         if (data.status !== 'WAIT_PAY' && data.status !== 'PAYING') {
           // status
-          showConfirmDialog({
-            message: '订单处理中,请稍等',
-            showCancelButton: false
-          }).then(() => {
-            router.replace({
-              path: '/payment-result',
-              query: {
-                orderNo: state.orderNo
-              }
-            })
-          })
+          state.dialogStatus = true
+          state.dialogMessage = '订单' + orderStatus[data.status]
+          // showConfirmDialog({
+          //   message: '订单处理中,请稍等',
+          //   showCancelButton: false
+          // }).then(() => {
+          //   router.replace({
+          //     path: '/payment-result',
+          //     query: {
+          //       orderNo: state.orderNo
+          //     }
+          //   })
+          // })
         }
       } catch {
         //
@@ -113,18 +119,6 @@ export default defineComponent({
       const config: any = state.config
       state.pay_channel = val.pay_channel
       if (val.payCode === 'payResult') {
-        // router.push({
-        //   path: '/payResult',
-        //   query: {
-        //     pay_channel: val.pay_channel,
-        //     wxAppId: config.wxAppId,
-        //     body: config.body,
-        //     price: config.price,
-        //     orderNo: config.merOrderNo,
-        //     userId: config.userId
-        //   }
-        // })
-
         window.location.href =
           window.location.origin +
           '/orchestra-student/#/payResult?' +
@@ -260,18 +254,7 @@ export default defineComponent({
         const { data } = await request.get('/api-student/userPaymentOrder/detail/' + state.orderNo)
         console.log(data)
         state.pay_channel = data.paymentChannel
-        if (data.status === 'PAID') {
-          // showConfirmDialog({
-          //   message: '该订单已支付成功',
-          //   showCancelButton: false
-          // }).then(() => {
-          //   router.replace({
-          //     path: '/payment-result',
-          //     query: {
-          //       orderNo: state.orderNo
-          //     }
-          //   })
-          // })
+        if (data.status !== 'WAIT_PAY' && data.status !== 'PAYING') {
           router.replace({
             path: '/payment-result',
             query: {
@@ -315,18 +298,7 @@ export default defineComponent({
         })
         console.log(data)
         state.pay_channel = data.paymentChannel
-        if (data.status === 'PAID') {
-          // showConfirmDialog({
-          //   message: '该订单已支付成功',
-          //   showCancelButton: false
-          // }).then(() => {
-          //   router.replace({
-          //     path: '/payment-result',
-          //     query: {
-          //       orderNo: state.orderNo
-          //     }
-          //   })
-          // })
+        if (data.status !== 'WAIT_PAY' && data.status !== 'PAYING') {
           router.replace({
             path: '/payment-result',
             query: {
@@ -559,6 +531,21 @@ export default defineComponent({
             <GoodsDetail id={state.selectGoodsId} groupPrice={state.currentPrice} />
           )}
         </OPopup>
+
+        <ODialog
+          title="提示"
+          v-model:show={state.dialogStatus}
+          message={state.dialogMessage}
+          confirmButtonText="确定"
+          onConfirm={() => {
+            router.replace({
+              path: '/payment-result',
+              query: {
+                orderNo: state.orderNo
+              }
+            })
+          }}
+        />
       </>
     )
   }

+ 2 - 11
src/student/music-group/shop-address/address-operation.tsx

@@ -69,28 +69,19 @@ export default defineComponent({
               ...params
             }
           })
-          setTimeout(() => {
-            showToast('修改成功')
-          }, 100)
         } else {
           await request.post('/api-student/userReceiveAddress/save', {
             data: {
               ...params
             }
           })
-          setTimeout(() => {
-            showToast('添加成功')
-          }, 100)
         }
 
-        setTimeout(() => {
-          state.isClick = false
-          router.back()
-        }, 1100)
+        state.isClick = false
+        router.back()
       } catch (e: any) {
         //
         state.isClick = false
-        console.log(e)
       }
     }
 

+ 30 - 8
src/student/my-orchestra/apply-withdrawal.tsx

@@ -20,6 +20,7 @@ export default defineComponent({
     })
     const forms = reactive({
       status: false,
+      statusMember: false,
       reason: '',
       id: route.query.id,
       dataInfo: {} as any,
@@ -40,7 +41,22 @@ export default defineComponent({
         showToast('请输入退团原因')
         return
       }
-      forms.status = true
+
+      try {
+        const { data } = await request.post('/api-student/student/hasWaitActivateVipOrder', {
+          requestType: 'form',
+          data: {
+            orchestraId: forms.id
+          }
+        })
+        if (data) {
+          forms.statusMember = true
+        } else {
+          forms.status = true
+        }
+      } catch {
+        //
+      }
     }
 
     //
@@ -56,12 +72,7 @@ export default defineComponent({
         })
 
         forms.isClick = false
-        setTimeout(() => {
-          showToast('申请成功')
-        }, 100)
-        setTimeout(() => {
-          router.replace('/my-orchestra')
-        }, 1100)
+        router.replace('/my-orchestra')
       } catch {
         //
         forms.isClick = false
@@ -128,7 +139,18 @@ export default defineComponent({
           confirmButtonText="确定"
           cancelButtonText="取消"
           showCancelButton
-          onConfirm={() => onConfirm()}
+          onConfirm={onConfirm}
+        ></ODialog>
+
+        <ODialog
+          v-model:show={forms.statusMember}
+          title="提示"
+          message={'您有待激活的团练宝订单,是否继续退团?'}
+          messageAlign="left"
+          confirmButtonText="继续"
+          cancelButtonText="取消"
+          showCancelButton
+          onConfirm={onConfirm}
         ></ODialog>
       </div>
     )

+ 1 - 1
src/student/payment-result/index.tsx

@@ -166,7 +166,7 @@ export default defineComponent({
                     </Tag>
                   </div>
                 ),
-                value: () => <span>x 1</span>
+                value: () => <span>{goods.goodsType === 'VIP' ? '6个月' : 'x 1'}</span>
               }}
             </Cell>
           ))}

+ 0 - 0
src/teacher/screen-projection/guide.module.less


+ 4 - 3
src/views/courseList/index.tsx

@@ -73,7 +73,7 @@ export default defineComponent({
         if (browserInfo.isStudent || route.query.isdev) {
           try {
             await showConfirmDialog({
-              message: '当前课程没有缓存是否缓存'
+              message: '当前课程没有缓存,是否缓存?'
             })
           } catch (error) {
             gotoPlay(item)
@@ -90,7 +90,8 @@ export default defineComponent({
       router.push({
         path: '/coursewarePlay',
         query: {
-          id: item.lessonCoursewareDetailId
+          id: item.lessonCoursewareDetailId,
+          source: 'my-course'
         }
       })
     }
@@ -174,7 +175,7 @@ export default defineComponent({
                   <img src={iconCourse} class={styles.cover} />
                   <div class={styles.title}>
                     <div>{item.coursewareDetailName}</div>
-                    {route.query.code !== 'select' && <div class={styles.subtitle}>已使用 {item.useNum} 次</div>}
+                    {!browserInfo.isStudent && <div class={styles.subtitle}>已使用 {item.useNum} 次</div>}
                   </div>
                   {route.query.code !== 'select' ? (
                     <>

+ 12 - 0
src/views/coursewarePlay/component/musicScore.module.less

@@ -18,3 +18,15 @@
     bottom: 0;
   }
 }
+.errorModel {
+  position: absolute;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  background: #000;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  overflow: hidden;
+}

+ 37 - 11
src/views/coursewarePlay/component/musicScore.tsx

@@ -1,6 +1,7 @@
-import { defineComponent, ref, nextTick } from 'vue'
+import { defineComponent, ref, nextTick, onMounted, watch } from 'vue'
 import styles from './musicScore.module.less'
 import qs from 'query-string'
+import OEmpty from '@/components/o-empty'
 
 export default defineComponent({
   name: 'musicScore',
@@ -13,6 +14,8 @@ export default defineComponent({
   emits: ['setIframe'],
   setup(props, { emit }) {
     const iframeRef = ref()
+    const renderError = ref(false)
+    const renderSuccess = ref(false)
     const Authorization = sessionStorage.getItem('Authorization') || ''
     const origin = /(localhost|192)/.test(location.host)
       ? 'https://ponline.colexiu.com' //'http://localhost:3000' ////
@@ -24,18 +27,41 @@ export default defineComponent({
       Authorization: Authorization
     })
     let src = `${origin}/orchestra-music-score/?` + query
-    console.log('src', src)
+    const checkView = () => {
+      fetch(src)
+        .then(() => {
+          renderSuccess.value = true
+          renderError.value = false
+        })
+        .catch((err) => {
+          renderError.value = true
+        })
+    }
+    watch(props.music, () => {
+      if (renderSuccess.value) return
+      renderError.value = false
+      if (props.music.display) {
+        checkView()
+      }
+    })
+
     return () => (
       <div class={styles.musicScore}>
-        <iframe
-          ref={iframeRef}
-          onLoad={() => {
-            emit('setIframe', iframeRef.value)
-          }}
-          class={[styles.container, 'musicIframe']}
-          frameborder="0"
-          src={src}
-        ></iframe>
+        {renderError.value ? (
+          <div class={styles.errorModel}>
+            <OEmpty type="network" tips="请检查网络环境" />
+          </div>
+        ) : (
+          <iframe
+            ref={iframeRef}
+            onLoad={(e: Event) => {
+              emit('setIframe', iframeRef.value)
+            }}
+            class={[styles.container, 'musicIframe']}
+            frameborder="0"
+            src={src}
+          ></iframe>
+        )}
       </div>
     )
   }

+ 2 - 2
src/views/coursewarePlay/component/points.tsx

@@ -2,7 +2,7 @@ import { defineComponent, reactive, watch } from 'vue'
 import styles from './point.module.less'
 import iconMulv from '../image/icon-mulv.svg'
 import iconArrow from '../image/icon-arrow.svg'
-import iconZhibo from '../image/icon-zhibo.svg'
+import iconZhibo from '../image/icon-load.gif'
 import { Collapse, CollapseItem, Icon } from 'vant'
 export default defineComponent({
   name: 'points',
@@ -68,7 +68,7 @@ export default defineComponent({
                                   })
                                 }}
                               >
-                                {n.name}
+                                <span style={{width: '80%'}} class="van-ellipsis">{n.name}</span>
                                 <Icon name={iconZhibo} />
                               </div>
                             )

BIN
src/views/coursewarePlay/image/icon-load.gif


+ 42 - 5
src/views/coursewarePlay/index.module.less

@@ -36,8 +36,8 @@
   align-items: center;
   z-index: 10;
   padding: 4px 10px 4px 15px;
-  :global{
-    .van-icon{
+  :global {
+    .van-icon {
       margin-right: 8px;
     }
   }
@@ -214,14 +214,51 @@
   }
 }
 
-.loadWrap{
+.loadWrap {
   position: absolute;
   left: 0;
   top: 0;
   right: 0;
   bottom: 0;
-  background: linear-gradient(45deg, #21232A, #111218);
+  background: linear-gradient(45deg, #21232a, #111218);
   display: flex;
   justify-content: center;
   align-items: center;
-}
+}
+.playRecordTimeWrap{
+  position: fixed;
+  top: 0;
+}
+.playRecordTime {
+  position: fixed;
+  top: 33px;
+  left: 16px;
+  background: rgba(0, 0, 0, 0.4);
+  border-radius: 20px;
+  font-size: 6px;
+  padding: 6px;
+  display: flex;
+  align-items: center;
+  color: #fff;
+  .timeLoad {
+    width: 5px;
+    height: 5px;
+    background: #ff4e19;
+    border: .5px solid #ffffff;
+    border-radius: 50%;
+    margin-right: 3px;
+    animation: loadFade 1s ease-in-out infinite;
+  }
+}
+
+@keyframes loadFade {
+  0%{
+    opacity: 0;
+  }
+  50%{
+    opacity: .5;
+  }
+  100%{
+    opacity: 1;
+  }
+}

+ 32 - 11
src/views/coursewarePlay/index.tsx

@@ -24,7 +24,7 @@ import styles from './index.module.less'
 import 'plyr/dist/plyr.css'
 import request from '@/helpers/request'
 import { state } from '@/state'
-import { useRoute } from 'vue-router'
+import { useRoute, useRouter } from 'vue-router'
 import { listenerMessage, postMessage, promisefiyPostMessage } from '@/helpers/native-message'
 import MusicScore from './component/musicScore'
 import iconMenu from './image/icon-menu.svg'
@@ -41,6 +41,7 @@ import { browser, getSecondRPM } from '@/helpers/utils'
 import { Vue3Lottie } from 'vue3-lottie'
 import playLoadData from './datas/data.json'
 import { usePageVisibility } from '@vant/use'
+import PlayRecordTime from './playRecordTime'
 
 export default defineComponent({
   name: 'CoursewarePlay',
@@ -75,6 +76,13 @@ export default defineComponent({
       }
     }
     const handleInit = (type = 0) => {
+      postMessage({
+        api: 'courseLoading',
+        content: {
+          show: true,
+          type: 'fullscreen'
+        }
+      })
       //设置容器16:9
       setContainer()
       // 横屏
@@ -106,6 +114,7 @@ export default defineComponent({
     })
 
     const route = useRoute()
+    const router = useRouter()
     const headeRef = ref()
     const data = reactive({
       detail: null,
@@ -192,7 +201,8 @@ export default defineComponent({
             iframeRef: null,
             tabName: item.name,
             isLast: j === itemLength, // 当前知识点
-            autoPlay: false //加载完成是否自动播放
+            autoPlay: false, //加载完成是否自动播放
+            display: false
           })
         }
       }
@@ -212,9 +222,19 @@ export default defineComponent({
         popupData.activeIndex = popupData.firstIndex
         item.autoPlay = true
         item.muted = true
+        item.display = true
       }
       // console.log('🚀 ~ list', list)
       data.itemList = list
+      setTimeout(() => {
+        postMessage({
+          api: 'courseLoading',
+          content: {
+            show: false,
+            type: 'fullscreen'
+          }
+        })
+      }, 300)
     }
     const getDetail = async () => {
       try {
@@ -245,9 +265,9 @@ export default defineComponent({
     }
     // ifram事件处理
     const iframeHandle = (ev: MessageEvent) => {
-      // console.log(ev.data)
       if (ev.data?.api === 'headerTogge') {
-        activeData.model = !activeData.model
+        // console.log("🚀 ~ ev.data", ev.data)
+        activeData.model = ev.data.show || (ev.data.playState == 'play' ? true : false)
       }
     }
 
@@ -258,6 +278,9 @@ export default defineComponent({
     })
     // 返回
     const goback = () => {
+      if (route.query.source == 'my-course') {
+        router.back()
+      }
       postMessage({ api: 'goBack' })
     }
 
@@ -271,11 +294,6 @@ export default defineComponent({
       itemActive: '',
       itemName: ''
     })
-    // 设置当前的激活状态
-    const setActiveData = (val: any, oldVal: any) => {
-      handleStop()
-    }
-    watch(() => popupData.activeIndex, setActiveData)
 
     /**停止所有的播放 */
     const handleStop = () => {
@@ -297,6 +315,7 @@ export default defineComponent({
         // 停止曲谱的播放
         if (item.type === 'SONG') {
           item.iframeRef?.contentWindow?.postMessage({ api: 'setPlayState' }, '*')
+          item.display = false
         }
       }
     }
@@ -304,7 +323,6 @@ export default defineComponent({
     const toggleMaterial = () => {
       const index = data.itemList.findIndex((n: any) => n.id == popupData.itemActive)
       if (index > -1) {
-        popupData.activeIndex = index
         swipeRef.value?.swipeTo(index, {
           immediate: true
         })
@@ -323,6 +341,7 @@ export default defineComponent({
       console.log('轮播切换')
       popupData.activeIndex = val
       const item = data.itemList[val]
+      handleStop()
       if (item) {
         popupData.tabActive = item.knowledgePointId
         popupData.itemActive = item.id
@@ -330,6 +349,7 @@ export default defineComponent({
         popupData.tabName = item.tabName
         if (item.type == 'SONG') {
           activeData.model = true
+          item.display = true
         }
         if (item.type === 'VIDEO') {
           // console.log("🚀 ~ item", item)
@@ -596,7 +616,7 @@ export default defineComponent({
 
           <Transition name="top">
             {activeData.model && (
-              <div class={styles.headerContainer} ref={headeRef}>
+              <div id="coursePlayHeader" class={styles.headerContainer} ref={headeRef}>
                 <div class={styles.backBtn} onClick={() => goback()}>
                   <Icon name={iconBack} />
                   返回
@@ -688,6 +708,7 @@ export default defineComponent({
             />
           </Popup>
         </div>
+        <PlayRecordTime list={data.itemList} />
       </div>
     )
   }

+ 87 - 0
src/views/coursewarePlay/playRecordTime.tsx

@@ -0,0 +1,87 @@
+import request from '@/helpers/request'
+import { getSecondRPM } from '@/helpers/utils'
+import { state } from '@/state'
+import { usePageVisibility } from '@vant/use'
+import { computed, defineComponent, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
+import { useRoute } from 'vue-router'
+import styles from './index.module.less'
+
+export default defineComponent({
+  name: 'playRecordTime',
+  props: {
+    list: {
+      type: Array,
+      default: () => []
+    }
+  },
+  setup(props) {
+    const pageVisibility = usePageVisibility()
+
+    watch(pageVisibility, (value) => {
+      console.log("🚀 ~ value", value)
+      if (value == 'hidden') {
+        clearInterval(timerRecord.value)
+        handleRecord()
+      } else {
+        // 页面显示
+        handleStartInterval()
+      }
+    })
+    const route = useRoute()
+    const saveModel = reactive({
+      /**当前时长 */
+      currentTime: 0,
+      /**记录的开始时间 */
+      startTime: 0,
+      timer: null as any
+    })
+    /** 建议学习总时长 */
+    const total = computed(() => {
+      const _total = props.list.reduce(
+        (_total: number, item: any) => _total + item.adviseStudyTimeSecond,
+        0
+      )
+      return _total
+    })
+
+    const handleRecord = () => {
+      saveModel.currentTime++
+      const playTime = saveModel.currentTime - saveModel.startTime
+      // 1分钟记录1次
+      if (playTime >= 60) {
+        saveModel.startTime = saveModel.currentTime
+        request.post(`${state.platformApi}/courseSchedule/coursewarePlayTime`, {
+          params: {
+            courseScheduleId: route.query.courseId,
+            playTime
+          },
+          hideLoading: true
+        })
+      }
+    }
+    const timerRecord = ref()
+    const handleStartInterval = () => {
+      clearInterval(timerRecord.value)
+      timerRecord.value = setInterval(handleRecord, 1000)
+    }
+    onMounted(() => {
+      handleStartInterval()
+    })
+    onUnmounted(() => {
+      clearInterval(timerRecord.value)
+    })
+    return () => (
+      <div
+        class={styles.playRecordTimeWrap}
+        style={{ display: saveModel.currentTime > total.value ? 'none' : '' }}
+      >
+        <div class={styles.playRecordTime}>
+          <div class={styles.timeLoad}></div>
+          <div>
+            {getSecondRPM(saveModel.currentTime)} / {getSecondRPM(total.value)}
+          </div>
+        </div>
+      </div>
+    )
+  }
+})

+ 78 - 0
src/views/guide/components/andoird-guide.module.less

@@ -0,0 +1,78 @@
+.topTitle {
+  position: relative;
+  h2 {
+    font-weight: bold;
+    color: #00201c;
+    line-height: 18px;
+    font-size: 17px;
+    padding-left: 22px;
+    color: #00201c;
+    position: relative;
+    z-index: 20;
+  }
+}
+.wrap {
+  box-sizing: border-box;
+  padding: 37px 0;
+  background-color: #fff;
+
+  .wrapInfo {
+    padding: 0 22px;
+    section {
+      margin-top: 30px;
+      margin-bottom: 50px;
+      .bigP {
+        font-weight: bold;
+        color: #00201c;
+        font-size: 16px;
+        line-height: 20px;
+      }
+      p {
+        font-size: 13px;
+        line-height: 20px;
+        margin-bottom: 20px;
+      }
+    }
+    h3 {
+      font-weight: bold;
+      color: #00201c;
+      font-size: 16px;
+      line-height: 20px;
+    }
+    .blod {
+      font-weight: bold;
+    }
+    .red {
+      color: #ff0000;
+    }
+  }
+}
+
+.dot {
+  position: absolute;
+  width: 10px;
+  height: 17px;
+  background: #00c2b5;
+  opacity: 0.53;
+  border-radius: 1px;
+  top: -7px;
+  left: 0;
+}
+.little {
+  display: inline-block;
+  width: 4px;
+  height: 4px;
+  background: #00c2b5;
+  opacity: 0.53;
+  right: 0;
+}
+.imgWrap {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-around;
+  align-items: center;
+  .img {
+    margin-bottom: 20px;
+    width: 190px;
+  }
+}

+ 187 - 0
src/views/guide/components/android-guide.tsx

@@ -0,0 +1,187 @@
+import { defineComponent } from 'vue'
+import { getImage } from '../images'
+import styles from './andoird-guide.module.less'
+
+export const getAssetsHomeFile = getImage
+
+const infoMsg = {
+  meizu: {
+    img1: getAssetsHomeFile('4.png'),
+    img2: getAssetsHomeFile('5.png'),
+    img3: getAssetsHomeFile('6.png'),
+    title1: '打开“设置”页面,点击“更多连接方式”按钮:',
+    title2: '点击“投射屏幕”',
+    title3:
+      '打开“投射屏幕”开关,即可看到可以投屏的设备列表,选择您的设备进行连接。'
+  },
+  xiaomi: {
+    img1: getAssetsHomeFile('7.png'),
+    img2: getAssetsHomeFile('8.png'),
+    img3: getAssetsHomeFile('9.png'),
+    title1: '打开“设置”页面,点击“连接与共享”按钮:',
+    title2: '点击“投屏”:',
+    title3:
+      '打开“打开投屏”开关,即可看到可以投屏的设备列表,选择您的设备进行连接。'
+  },
+  vivo: {
+    img1: getAssetsHomeFile('12.png'),
+    img2: getAssetsHomeFile('13.png'),
+    img3: getAssetsHomeFile('14.png'),
+    title1: '打开“设置”页面,点击“其他网络与连接”按钮:',
+    title2: '点击“手机投屏”:',
+    title3:
+      '打开“手机投屏”开关,即可看到可以投屏的设备列表,选择您的设备进行连接。'
+  },
+  huawei: {
+    img1: getAssetsHomeFile('1.png'),
+    img2: getAssetsHomeFile('2.png'),
+    img3: getAssetsHomeFile('3.png'),
+    title1: '打开“设置”页面,点击“更多连接”按钮:',
+    title2: '点击“手机投屏”:',
+    title3:
+      '打开“无线投屏”开关,即可看到可以投屏的设备列表,选择您的设备进行连接。'
+  }
+}
+export default defineComponent({
+  name: 'adnroid-guide',
+  data() {
+    return {
+      brand: 'huawei'
+    }
+  },
+  mounted() {
+    var ua = navigator.userAgent.split('(')[1].split(')')[0]
+    this.brand = ''
+    var phone = [/MZ/gi, /mi/gi, /vivo/gi]
+    if (phone[0].test(ua)) {
+      this.brand = 'meizu'
+    } else if (phone[1].test(ua)) {
+      this.brand = 'xiaomi'
+    } else if (phone[2].test(ua)) {
+      this.brand = 'vivo'
+    } else {
+      this.brand = 'huawei'
+    }
+  },
+  render() {
+    return (
+      <div class={styles.wrap}>
+        <div class={styles.topTitle}>
+          <h2>通过镜像方式显示手机或平板上的内容</h2>
+        </div>
+        <section>
+          <img style={{ width: '100%' }} src={getAssetsHomeFile('guide.png')} />
+        </section>
+        <div class={styles.wrapInfo}>
+          <section>
+            <h3>第1步</h3>
+            <p>将您的手机或平板连接到您智能电视机所在的同一无线局域网。</p>
+            <h3>第2步</h3>
+            <p>{infoMsg[this.brand]['title1']}</p>
+            <div class={styles.imgWrap}>
+              <img
+                class={styles.img}
+                src={infoMsg[this.brand]['img1']}
+                alt=""
+              />
+            </div>
+
+            <h3>第3步</h3>
+            <p>{infoMsg[this.brand]['title2']}</p>
+            <div class={styles.imgWrap}>
+              <img
+                class={styles.img}
+                src={infoMsg[this.brand]['img2']}
+                alt=""
+              />
+            </div>
+
+            <h3>第4步</h3>
+            <p>{infoMsg[this.brand]['title3']}</p>
+            <div class={styles.imgWrap}>
+              <img
+                class={styles.img}
+                src={infoMsg[this.brand]['img3']}
+                alt=""
+              />
+            </div>
+          </section>
+          <section>
+            <p class={[styles.blod, styles.bigP]}>如果音乐意外停止:</p>
+            <p>
+              如果在这台设备上使用语音助手或进行其他任务,则可能会导致所有音频设备停止播放音乐
+            </p>
+            <p class={[styles.blod, styles.bigP]}>
+              如果您看到视频但听不到声音:
+            </p>
+            <p>
+              如果您听不到任何声音,则请确保手机设备和电视机/听筒的音量都已调高,而且没有静音。
+            </p>
+            <p>
+              请检查响铃/静音开关。如果开关设为静音,您会看到一条橙色的线。切换开关以开启响铃。
+            </p>
+            <p class={[styles.blod, styles.bigP]}>如果内容中断或网络卡顿:</p>
+            <p>
+              如果 Wi-Fi
+              信号欠佳或受到附近设备(例如,微波炉或婴儿监视器)的干扰尝试完成以下步骤:
+            </p>
+            <p>移开或关闭其他可能造成干扰的设备。</p>
+            <p>
+              如果您正尝试使用“隔空播放”将内容流化到智能电视,请尝试使用以太网线缆(而不是通过
+              Wi-Fi)将智能电视直接连接到路由器。
+            </p>
+            <p class={(styles.blod, styles.red)}>
+              *当您锁定设备、将其置于睡眠模式或切换到其他应用时,“隔空播放”连接可能会中断。
+            </p>
+          </section>
+          <section>
+            <p class={[styles.blod, styles.bigP]}>
+              如果“隔空播放”或屏幕镜像在您的设备上无法使用:
+            </p>
+            <p>1.确保您的设备都已开机且彼此距离较近。</p>
+            <p>2.请重新启动您要与“隔空播放”或屏幕镜像配合使用的设备。</p>
+            <p>3.以上方式尝试了仍无法搜到要使用的智能电视:</p>
+            <p class={(styles.blod, styles.red)}>
+              将您的设备连接到同一个 Wi-Fi 网络
+            </p>
+            <p>
+              首先需要确认电视与手机是否连接了同一个Wi-Fi
+              ,电视可以插网线,但必须是同一个路由器的,如果不确认,就把电视网线拔了改为连接Wi-Fi
+              。
+            </p>
+            <p class={[styles.blod, styles.bigP]}>
+              如果同一个Wi-Fi 也无法搜索到需要投屏的设备:
+            </p>
+            <p>
+              原因1·可能电视本身没有投屏功能(如果以前投屏过,也是可以判断为电视是支持投屏的。)
+            </p>
+            <p>A.是不是智能电视?</p>
+            <p>B.能不能自己安装软件?</p>
+            <p>C.是不是安卓系统?</p>
+            <p>D.能不能连接WiFi?</p>
+            <p>请确认以上四点。一般16年以后买的电视,99%都已经是智能电视了</p>
+          </section>
+          <section>
+            <p class={[styles.blod, styles.bigP]}>
+              如果是智能电视或者智能投影仪,但是没有投屏功能怎么办?
+            </p>
+            <p>
+              解决办法:自己安装一个投屏软件进去(幕享、傲软投屏、乐播投屏......)。相当于更新了电视投屏功能。也能解决这个问题。
+            </p>
+            <p>如果是老电视,老投影仪,老机顶盒怎么办?</p>
+            <p>这个也不是没有办法,电视最值钱的就是屏幕了。</p>
+            <p>
+              所以屏幕我们不要浪费了,继续使用,此时我们通过互联网机顶盒,从机顶盒应用商店安装投屏软件,也同样可以
+              进行投屏。
+            </p>
+            <p>a.是不是智能机顶盒?</p>
+            <p>b.能不能自己安装软件?</p>
+            <p>
+              c.是不是安卓系统?买回来之后利用HDMI线连接老电视,再从机顶盒应用商店下载投屏软件,就可以使用投屏了。
+            </p>
+          </section>
+        </div>
+      </div>
+    )
+  }
+})

+ 84 - 0
src/views/guide/components/ios-guide.module.less

@@ -0,0 +1,84 @@
+.marginB33 {
+  margin-bottom: 33px;
+  h2 {
+    padding-left: 0 !important;
+  }
+}
+.wrap {
+  box-sizing: border-box;
+  padding: 37px 0;
+  background-color: #fff;
+
+  .topTitle {
+    position: relative;
+    h2 {
+      font-weight: bold;
+      color: #00201c;
+      line-height: 18px;
+      font-size: 17px;
+      padding-left: 22px;
+      color: #00201c;
+      position: relative;
+      z-index: 20;
+    }
+  }
+  .wrapInfo {
+    padding: 0 22px;
+    section {
+      // margin-top: 0.3rem;
+      margin-bottom: 45px;
+      .bigP {
+        font-weight: bold;
+        color: #00201c;
+        font-size: 16px;
+        line-height: 20px;
+      }
+      p {
+        font-size: 13px;
+        line-height: 20px;
+        margin-bottom: 20px;
+      }
+    }
+    h3 {
+      font-weight: bold;
+      color: #00201c;
+      font-size: 16px;
+      line-height: 20px;
+    }
+    .blod {
+      font-weight: bold;
+    }
+    .red {
+      color: #ff0000;
+    }
+  }
+}
+
+.dot {
+  position: absolute;
+  width: 10px;
+  height: 17px;
+  background: #00c2b5;
+  opacity: 0.53;
+  border-radius: 1px;
+  top: -7px;
+  left: 0;
+}
+.little {
+  display: inline-block;
+  width: 4px;
+  height: 4px;
+  background: #00c2b5;
+  opacity: 0.53;
+  right: 0;
+}
+.imgWrap {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-around;
+  align-items: center;
+  .img {
+    margin-bottom: 20px;
+    width: 190px;
+  }
+}

+ 150 - 0
src/views/guide/components/ios-guide.tsx

@@ -0,0 +1,150 @@
+import { defineComponent } from 'vue'
+import { getImage } from '../images'
+import styles from './ios-guide.module.less'
+
+export const getAssetsHomeFile = getImage
+
+export default defineComponent({
+  name: 'ios-guide',
+  render() {
+    return (
+      <div class={styles.wrap}>
+        <div class={styles.topTitle}>
+          <h2>通过镜像方式显示 iPhone或iPad上的内容</h2>
+        </div>
+
+        <img style={{ width: '100%' }} src={getAssetsHomeFile('guide.png')} />
+
+        <div class={styles.wrapInfo}>
+          <section>
+            <h3>第1步</h3>
+            <p>
+              通过镜像方式显示 iPhone或iPad上的内容将您的 iPhone或iPad
+              连接到您的 Apple TV 或兼容“隔空播放
+              2”的智能电视机所在的同一无线局域网。
+            </p>
+            <h3>第2步</h3>
+            <p>
+              打开“控制中心”:
+              <br />
+              在 iPhone X 或更新机型或者装有 iPadOS 13 或更高版本的 iPad
+              上:从屏幕右上角向下轻扫。
+              <br />在 iPhone 8 或更早机型或者 iOS 11
+              或更低版本上:从屏幕底部边缘向上轻扫。
+            </p>
+            <h3>第3步</h3>
+            <p>轻点 “屏幕镜像”。(iOS 11 之前版本:AirPlay 镜像)</p>
+            <h3>第4步</h3>
+            <p>从列表中选择您的 Apple TV 或兼容“隔空播放 2”的智能电视机</p>
+            <h3>第5步</h3>
+            <p>
+              如果电视机屏幕上出现“隔空播放”密码,请在 iOS 或 iPadOS
+              设备上输入这个密码。
+            </p>
+            <h3>第6步</h3>
+            <p>
+              要停止镜像您的 iOS 或 iPadOS
+              设备,请打开“控制中心”,轻点“屏幕镜像”,然后轻点“停止镜像”。
+            </p>
+          </section>
+          <div class={[styles.topTitle, styles.marginB33]}>
+            <h2>iOS 10控制中心图片:</h2>
+          </div>
+          <section>
+            <img
+              src={getAssetsHomeFile('11.png')}
+              style={{ width: '100%' }}
+              alt=""
+            />
+          </section>
+          <div class={[styles.topTitle, styles.marginB33]}>
+            <h2>iOS 10之后版本控制中心图片:</h2>
+          </div>
+          <section>
+            <img
+              src={getAssetsHomeFile('10.png')}
+              style={{ width: '100%' }}
+              alt=""
+            />
+          </section>
+          <section>
+            <p class={[styles.blod, styles.bigP]}>如果音乐意外停止:</p>
+            <p>
+              如果在这台设备上使用 Siri
+              或进行其他任务,则可能会导致所有音频设备停止播放音乐
+            </p>
+            <p class={[styles.blod, styles.bigP]}>
+              如果您看到视频但听不到声音:
+            </p>
+            <p>
+              如果您听不到任何声音,则请确保 iOS
+              设备和电视机/听筒的音量都已调高,而且没有静音。
+            </p>
+            <p>
+              请检查响铃/静音开关。如果开关设为静音,您会看到一条橙色的线。切换开关以开启响铃。
+            </p>
+            <p class={[styles.blod, styles.bigP]}>如果内容中断或网络卡顿:</p>
+            <p>
+              如果 Wi-Fi
+              信号欠佳或受到附近设备(例如,微波炉或婴儿监视器)的干扰尝试完成以下步骤:
+            </p>
+            <p>移开或关闭其他可能造成干扰的设备。</p>
+            <p>
+              如果您正尝试使用“隔空播放”将内容流化到智能电视,请尝试使用以太网线缆(而不是通过
+              Wi-Fi)将智能电视直接连接到路由器。
+            </p>
+            <p class={[styles.blod, styles.red]}>
+              *当您锁定设备、将其置于睡眠模式或切换到其他应用时,“隔空播放”连接可能会中断。
+            </p>
+          </section>
+          <section>
+            <p class={[styles.blod, styles.bigP]}>
+              如果“隔空播放”或屏幕镜像在您的设备上无法使用:
+            </p>
+            <p>1.确保您的设备都已开机且彼此距离较近。</p>
+            <p>2.请重新启动您要与“隔空播放”或屏幕镜像配合使用的设备。</p>
+            <p>3.以上方式尝试了仍无法搜到要使用的智能电视:</p>
+            <p class={[styles.blod, styles.red]}>
+              将您的设备连接到同一个 Wi-Fi 网络
+            </p>
+            <p>
+              首先需要确认电视与手机是否连接了同一个Wi-Fi
+              ,电视可以插网线,但必须是同一个路由器的,如果不确认,就把电视网线拔了改为连接Wi-Fi
+              。
+            </p>
+            <p class={[styles.blod, styles.bigP]}>
+              如果同一个Wi-Fi 也无法搜索到需要投屏的设备:
+            </p>
+            <p>
+              原因1·可能电视本身没有投屏功能(如果以前投屏过,也是可以判断为电视是支持投屏的。)
+            </p>
+            <p>A.是不是智能电视?</p>
+            <p>B.能不能自己安装软件?</p>
+            <p>C.是不是安卓系统?</p>
+            <p>D.能不能连接WiFi?</p>
+            <p>请确认以上四点。一般16年以后买的电视,99%都已经是智能电视了</p>
+          </section>
+          <section>
+            <p class={[styles.blod, styles.bigP]}>
+              如果是智能电视或者智能投影仪,但是没有投屏功能怎么办?
+            </p>
+            <p>
+              解决办法:自己安装一个投屏软件进去(幕享、傲软投屏、乐播投屏......)。相当于更新了电视投屏功能。也能解决这个问题。
+            </p>
+            <p>如果是老电视,老投影仪,老机顶盒怎么办?</p>
+            <p>这个也不是没有办法,电视最值钱的就是屏幕了。</p>
+            <p>
+              所以屏幕我们不要浪费了,继续使用,此时我们通过互联网机顶盒,从机顶盒应用商店安装投屏软件,也同样可以
+              进行投屏。
+            </p>
+            <p>a.是不是智能机顶盒?</p>
+            <p>b.能不能自己安装软件?</p>
+            <p>
+              c.是不是安卓系统?买回来之后利用HDMI线连接老电视,再从机顶盒应用商店下载投屏软件,就可以使用投屏了。
+            </p>
+          </section>
+        </div>
+      </div>
+    )
+  }
+})

+ 15 - 0
src/views/guide/guide.tsx

@@ -0,0 +1,15 @@
+import { defineComponent } from 'vue'
+import IosGuide from './components/ios-guide'
+import AndroidGuide from './components/android-guide'
+
+export default defineComponent({
+  name: 'guide',
+  data() {
+    return {
+      client: 'ios'
+    }
+  },
+  render() {
+    return <>{this.client === 'ios' ? <IosGuide /> : <AndroidGuide />}</>
+  }
+})

BIN
src/views/guide/images/1.png


BIN
src/views/guide/images/10.png


BIN
src/views/guide/images/11.png


BIN
src/views/guide/images/12.png


BIN
src/views/guide/images/13.png


BIN
src/views/guide/images/14.png


BIN
src/views/guide/images/2.png


BIN
src/views/guide/images/3.png


BIN
src/views/guide/images/4.png


BIN
src/views/guide/images/5.png


BIN
src/views/guide/images/6.png


BIN
src/views/guide/images/7.png


BIN
src/views/guide/images/8.png


BIN
src/views/guide/images/9.png


BIN
src/views/guide/images/guide.png


BIN
src/views/guide/images/icon-img.png


BIN
src/views/guide/images/icon-music.png


BIN
src/views/guide/images/icon-video.png


+ 5 - 0
src/views/guide/images/index.ts

@@ -0,0 +1,5 @@
+const modules = import.meta.globEager(`../images/**`)
+export const getImage = (name: string) => {
+    // console.log("🚀 ~ modules", modules[`../images/${name}`]?.default)
+    return modules[`../images/${name}`]?.default || ''
+}

+ 14 - 9
src/views/information/help-center/detail.tsx

@@ -1,13 +1,15 @@
 import request from '@/helpers/request'
 import { state } from '@/state'
+import { NavBar } from 'vant'
 import { defineComponent, onMounted, ref } from 'vue'
-import { useRoute } from 'vue-router'
+import { useRoute, useRouter } from 'vue-router'
 import styles from '../information-detail.module.less'
 
 export default defineComponent({
   name: 'notice-detail',
   setup() {
     const route = useRoute()
+    const router = useRouter()
     const detail = ref<any>({})
 
     const getDetails = async () => {
@@ -25,15 +27,18 @@ export default defineComponent({
       getDetails()
     })
     return () => (
-      <div class={styles.detail}>
-        <div class={styles.title}>{detail.value.title}</div>
-        <div class={styles.who}>
-          <span>管乐团</span>
-          {detail.value.createTime}
-        </div>
+      <>
+        {route.query.source == 'music' ? <NavBar leftArrow leftText="返回" border={false} onClickLeft={() => router.back()} /> : null}
+        <div class={styles.detail}>
+          <div class={styles.title}>{detail.value.title}</div>
+          <div class={styles.who}>
+            <span>管乐团</span>
+            {detail.value.createTime}
+          </div>
 
-        <div class={styles.content} v-html={detail.value.content}></div>
-      </div>
+          <div class={styles.content} v-html={detail.value.content}></div>
+        </div>
+      </>
     )
   }
 })

+ 4 - 2
src/views/information/help-center/index.tsx

@@ -6,12 +6,13 @@ import { forms } from '@/school/train-planning/create'
 import { state } from '@/state'
 import { Cell, CellGroup, List } from 'vant'
 import { defineComponent, onMounted, reactive } from 'vue'
-import { useRouter } from 'vue-router'
+import { useRoute, useRouter } from 'vue-router'
 import styles from './index.module.less'
 
 export default defineComponent({
   name: 'help-center',
   setup() {
+    const route = useRoute()
     const router = useRouter()
     const form = reactive({
       isClick: false,
@@ -94,7 +95,8 @@ export default defineComponent({
                   router.push({
                     path: 'help-detail',
                     query: {
-                      id: item.id
+                      id: item.id,
+                      source: route.query.source
                     }
                   })
                 }}

+ 36 - 28
src/views/unit-test/examination-mode/index.tsx

@@ -6,6 +6,7 @@ import {
   Icon,
   Image,
   Popup,
+  showDialog,
   Swipe,
   SwipeItem,
   Tag
@@ -104,10 +105,8 @@ export default defineComponent({
     const formatUserAnswers = (item: any, userAnswer: any) => {
       // 判断是否有结果
       if (!userAnswer) return []
-      const answers = JSON.parse(userAnswer) || []
-
-      const questionItem = answers.find((child: any) => child.questionId === item.id)
-      return questionItem ? questionItem.details : []
+      const answers = userAnswer || []
+      return answers[item.id] ? answers[item.id] : []
     }
 
     /**
@@ -119,8 +118,8 @@ export default defineComponent({
         setTimeout(() => {
           const currentItemDom: Element =
             document.querySelectorAll('.swipe-item-question')[state.currentIndex]
-          console.log(currentItemDom, state.currentIndex)
           const rect = useRect(currentItemDom)
+
           state.swipeHeight = rect.height
         }, 100)
       })
@@ -142,10 +141,6 @@ export default defineComponent({
               details: question.userAnswer
             })
           }
-
-          // if (index === state.currentIndex) {
-          //   currentResult = question.userAnswer && question.userAnswer.length > 0 ? true : false
-          // }
         })
 
         // 判断是否是最后一题
@@ -155,12 +150,6 @@ export default defineComponent({
           return
         }
 
-        // 判断是否答题了 - 由于连线题
-        // if (!currentResult) {
-        //   swipeRef.value?.next()
-        //   return
-        // }
-
         state.nextStatus = true
         await request.post('/api-student/studentUnitExamination/submitAnswer', {
           hideLoading: true,
@@ -224,16 +213,36 @@ export default defineComponent({
       }
     }
 
-    onMounted(() => {
-      getExamDetails()
+    // 拦截
+    const onBack = () => {
+      showDialog({
+        title: '提示',
+        message: '您考试还未提交,是否退出?',
+        theme: 'round-button',
+        confirmButtonColor: '#ff8057'
+      }).then(() => {
+        onAfter()
+        router.back()
+      })
+    }
+
+    const onAfter = () => {
+      window.removeEventListener('popstate', onBack, false)
+    }
+
+    onMounted(async () => {
+      await getExamDetails()
 
       // 初始化高度
       resizeSwipeItemHeight()
+
+      window.history.pushState(null, '', document.URL)
+      window.addEventListener('popstate', onBack, false)
     })
 
     return () => (
       <div class={styles.unitDetail}>
-        <Cell center class={styles.unitSection}>
+        <Cell center class={styles.unitSection} border={false}>
           {{
             title: () => <div class={styles.unitTitle}>{state.examDetail.unitExaminationName}</div>,
             label: () => (
@@ -268,6 +277,7 @@ export default defineComponent({
           duration={300}
           touchable={false}
           height={state.swipeHeight}
+          style={{ marginBottom: '12px' }}
           lazyRender
           onChange={(index: number) => {
             state.currentIndex = index
@@ -275,14 +285,9 @@ export default defineComponent({
           }}
         >
           {state.questionList.map((item: any, index: number) => (
-            // item.questionTypeCode === QuestionType.PLAY && (
+            // item.questionTypeCode === QuestionType.LINK && (
             //   <SwipeItem>
-            //     <PlayQuestion
-            //       v-model:value={item.userAnswer}
-            //       data={item}
-            //       index={index + 1}
-            //       unitId={state.id as any}
-            //     />
+            //     <KeepLookQuestion v-model:value={item.userAnswer} data={item} index={index + 1} />
             //   </SwipeItem>
             // )
             <SwipeItem>
@@ -377,15 +382,18 @@ export default defineComponent({
           <ResultFinish
             status={state.resultStatusType as any}
             result={state.resultInfo}
-            confirmButtonText="我知道了"
-            cancelButtonText="去练习"
+            confirmButtonText="去练习"
+            cancelButtonText="我知道了"
             onClose={() => {
               state.visiableResult = false
+              onAfter()
+              router.back()
               router.back()
             }}
             onConform={() => {
-              console.log('Success')
               state.visiableResult = false
+              onAfter()
+              router.back()
               router.back()
             }}
           />

BIN
src/views/unit-test/images/exam-pass-bg-p.png


BIN
src/views/unit-test/images/icon-pass-check.png


+ 2 - 2
src/views/unit-test/index.tsx

@@ -250,8 +250,7 @@ export default defineComponent({
                               router.push({
                                 path: '/test-exercise',
                                 query: {
-                                  id: item.unitExaminationId,
-                                  name: item.name
+                                  id: item.unitExaminationId
                                 }
                               })
                             }}
@@ -267,6 +266,7 @@ export default defineComponent({
                               type="primary"
                               round
                               block
+                              disabled={dayjs().isAfter(dayjs(item.expiryDate))}
                               onClick={() => onUnitTestStart(item)}
                             >
                               {item.status === 'C_ING' ? '继续测验' : '开始测验'}

+ 19 - 0
src/views/unit-test/model/anser-title/index.module.less

@@ -24,3 +24,22 @@
 .unitTitleImg {
   width: 100%;
 }
+
+.unitTitleRate {
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  padding-top: 15px;
+  padding-bottom: 15px;
+  font-size: 16px;
+  font-weight: 500;
+  color: #333333;
+  line-height: 26px;
+  .icon {
+    font-size: 16px;
+    margin-right: 6px;
+  }
+  .rate {
+    color: #4991eb;
+  }
+}

+ 16 - 2
src/views/unit-test/model/anser-title/index.tsx

@@ -1,7 +1,8 @@
-import { Tag, Image } from 'vant'
+import { Tag, Image, Icon } from 'vant'
 import { computed, defineComponent } from 'vue'
 import { QuestionType, QuestionTypeName } from '../../unit'
 import styles from './index.module.less'
+import iconPassCheck from '../../images/icon-pass-check.png'
 
 export default defineComponent({
   name: 'answer-title',
@@ -27,6 +28,10 @@ export default defineComponent({
     extra: {
       type: Object,
       default: () => ({})
+    },
+    showRate: {
+      type: Boolean,
+      default: false
     }
   },
   setup(props) {
@@ -52,11 +57,20 @@ export default defineComponent({
           {props.index}、{props.name} <span class={styles.unitScore}>({props.score || 0}分)</span>
           <Tag type="primary">{answerTypeName.value}</Tag>
         </div>
+        {props.showRate && (
+          <div class={styles.unitTitleRate}>
+            <Icon name={iconPassCheck} class={styles.icon} />
+            正确率:
+            <span class={styles.rate}>{props.extra.rightRate || 0}%</span>
+          </div>
+        )}
         {props.extra.questionDetail || mediaUrls.value ? (
           <div class={styles.unitDetail}>
             <div v-html={props.extra.questionDetail}></div>
             {mediaUrls.value &&
-              mediaUrls.value.map((url: any) => <Image class={styles.unitTitleImg} src={url} />)}
+              mediaUrls.value.map(
+                (url: any) => url && <Image class={styles.unitTitleImg} src={url} />
+              )}
           </div>
         ) : (
           ''

+ 1 - 1
src/views/unit-test/model/answer-analysis/index.module.less

@@ -6,6 +6,7 @@
     font-size: 16px;
     font-weight: 600;
     color: #333333;
+    padding-bottom: 20px;
 
     .aImg {
       font-size: 18px;
@@ -19,7 +20,6 @@
     color: #f44541;
   }
   .analysisTitle {
-    padding-top: 20px;
     padding-bottom: 10px;
   }
   .analysisMessage {

+ 26 - 13
src/views/unit-test/model/answer-list/index.tsx

@@ -9,9 +9,13 @@ export default defineComponent({
       type: Array,
       default: () => []
     },
-    look: {
-      type: Boolean,
-      default: false
+    index: {
+      type: Number,
+      default: 0
+    },
+    lookType: {
+      type: String as PropType<'ANSWER' | 'RESULT' | 'CLICK'>,
+      default: 'ANSWER'
     },
     statusList: {
       type: Array,
@@ -48,16 +52,20 @@ export default defineComponent({
       return result
     }
 
+    console.log(props.answerResult, 'props.answerResult')
+
     return () => (
       <div class={styles.anserList}>
-        <div class={styles.status}>
-          {props.statusList.map((item: any) => (
-            <span>
-              <i style={{ backgroundColor: item.color }}></i>
-              {item.text}
-            </span>
-          ))}
-        </div>
+        {props.statusList.length > 0 && (
+          <div class={styles.status}>
+            {props.statusList.map((item: any) => (
+              <span>
+                <i style={{ backgroundColor: item.color }}></i>
+                {item.text}
+              </span>
+            ))}
+          </div>
+        )}
 
         <div
           style={{
@@ -72,8 +80,13 @@ export default defineComponent({
                 {/* 判断是否答题了 */}
                 <span
                   class={[
-                    item.userAnswer && item.userAnswer.length > 0 && styles.answered,
-                    props.look && (formatUserResult(item.id) ? styles.yes : styles.no)
+                    props.lookType === 'ANSWER' &&
+                      item.userAnswer &&
+                      item.userAnswer.length > 0 &&
+                      styles.answered,
+                    props.lookType === 'RESULT' &&
+                      (formatUserResult(item.id) ? styles.yes : styles.no),
+                    props.lookType === 'CLICK' && index === props.index && styles.answered
                   ]}
                 >
                   {index + 1}

+ 14 - 0
src/views/unit-test/model/choice-question/index.module.less

@@ -18,6 +18,7 @@
     padding: 15px 12px;
     display: flex;
     align-items: center;
+    justify-content: space-between;
     font-size: 16px;
     font-weight: 500;
     color: #333333;
@@ -32,9 +33,22 @@
         }
       }
     }
+    .valueAudio {
+      width: 170px;
+    }
   }
   .active {
     background-color: #ffebdd;
     color: #f67146;
   }
+
+  .answerContent {
+    display: flex;
+    align-items: center;
+  }
+  .answerChoice {
+    font-size: 16px;
+    font-weight: 500;
+    line-height: 26px;
+  }
 }

+ 26 - 11
src/views/unit-test/model/choice-question/index.tsx

@@ -3,6 +3,7 @@ import { computed, defineComponent, PropType, reactive } from 'vue'
 import { AnswerType, labelOptions, QuestionType } from '../../unit'
 import AnserTitle from '../anser-title'
 import AnswerAnalysis from '../answer-analysis'
+import UnitAudio from '../unit-audio'
 import styles from './index.module.less'
 
 // 单选题 - 多选题
@@ -30,6 +31,10 @@ export default defineComponent({
       type: Boolean,
       default: false
     },
+    showRate: {
+      tyep: Boolean,
+      default: false
+    },
     showAnalysis: {
       // 是否显示解析
       type: Boolean,
@@ -52,7 +57,7 @@ export default defineComponent({
       const result = {
         answerId: item.examinationQuestionAnswerId,
         answer: item.questionAnswer,
-        extra: item.questionExtra
+        answerExtra: item.questionExtra
       }
       if (props.type === 'checkbox') {
         const tempIndex = value.findIndex(
@@ -88,11 +93,13 @@ export default defineComponent({
           <AnserTitle
             index={props.index}
             name={props.data.name}
+            showRate={props.showRate}
             score={props.data.totalScore}
             answerType={props.type === 'radio' ? QuestionType.RADIO : QuestionType.CHECKBOX}
             extra={{
               questionDetail: props.data.questionDetail,
-              mediaUrls: props.data.mediaUrls
+              mediaUrls: props.data.mediaUrls,
+              rightRate: props.data.rightRate
             }}
           />
 
@@ -102,15 +109,23 @@ export default defineComponent({
                 class={[styles.unitAnswer, item.checked && styles.active]}
                 onClick={() => onSelect(item)}
               >
-                <span class={styles.option}>{labelOptions[index + 1]}.</span>
-                {item.questionAnswerTypeCode === AnswerType.IMAGE && (
-                  <div class={styles.value}>
-                    <Image src={item.questionAnswer} />
-                  </div>
-                )}
-                {item.questionAnswerTypeCode === AnswerType.TXT && (
-                  <div class={styles.value}>{item.questionAnswer}</div>
-                )}
+                <div class={styles.answerContent}>
+                  <span class={styles.option}>{labelOptions[index + 1]}.</span>
+                  {item.questionAnswerTypeCode === AnswerType.IMAGE && (
+                    <div class={styles.value}>
+                      <Image src={item.questionAnswer} />
+                    </div>
+                  )}
+                  {item.questionAnswerTypeCode === AnswerType.TXT && (
+                    <div class={styles.value}>{item.questionAnswer}</div>
+                  )}
+                  {item.questionAnswerTypeCode === AnswerType.AUDIO && (
+                    <div class={styles.value}>
+                      <UnitAudio src={item.questionAnswer} class={styles.valueAudio} />
+                    </div>
+                  )}
+                </div>
+                {props.showRate && <div class={styles.answerChoice}>{item.selectRate}%人选择</div>}
               </div>
             ))}
           </div>

+ 1 - 1
src/views/unit-test/model/drag-question/index.module.less

@@ -10,7 +10,7 @@
 }
 
 .unitAnswers {
-  padding-bottom: 30px;
+  // padding-bottom: 30px;
   :global {
     .sortable-ghost {
       opacity: 0.5;

+ 14 - 5
src/views/unit-test/model/drag-question/index.tsx

@@ -30,6 +30,11 @@ export default defineComponent({
       type: Boolean,
       default: false
     },
+    showRate: {
+      // 是否显示答题的正确率
+      type: Boolean,
+      default: false
+    },
     showAnalysis: {
       // 是否显示解析
       type: Boolean,
@@ -88,7 +93,7 @@ export default defineComponent({
         result.push({
           answerId: item.index,
           answer: item.leftValue,
-          extra: rightOption.rightValue
+          answerExtra: rightOption.rightValue
         })
       })
       emit('update:value', result)
@@ -102,16 +107,18 @@ export default defineComponent({
           const rightOption = answers.find(
             (child: any) => answer.answerId === child.examinationQuestionAnswerId
           )
-          const rightValue = answers.find((child: any) => answer.extra === child.questionExtra)
+          const rightValue = answers.find(
+            (child: any) => answer.answerExtra === child.questionExtra
+          )
           const tmp = {
             index: answer.answerId, // 左边的值
             leftValue: answer.answer, // 左边的值
-            rightValue: answer.extra, // 右边的值
+            rightValue: answer.answerExtra, // 右边的值
             leftType: rightOption.questionAnswerTypeCode || 'TXT', // 左边类型
             rightType: rightOption.questionExtraTypeCode || 'TXT', // 右边类型
             rightIndex: rightValue ? rightValue.examinationQuestionAnswerId : ''
           }
-
+          console.log(tmp, '1212')
           state.options.push(tmp)
         })
       } else {
@@ -127,7 +134,7 @@ export default defineComponent({
           resultValue.push({
             answerId: answer.examinationQuestionAnswerId,
             answer: answer.questionAnswer,
-            extra: answer.questionExtra
+            answerExtra: answer.questionExtra
           })
           state.options.push(tmp)
         })
@@ -147,9 +154,11 @@ export default defineComponent({
           <AnserTitle
             index={props.index}
             name={props.data.name}
+            showRate={props.showRate}
             score={props.data.totalScore}
             answerType={QuestionType.SORT}
             extra={{
+              rightRate: props.data.rightRate,
               questionDetail: props.data.questionDetail,
               mediaUrls: props.data.mediaUrls
             }}

+ 7 - 3
src/views/unit-test/model/error-mode/index.tsx

@@ -9,6 +9,10 @@ export default defineComponent({
     confirmButtonText: {
       type: String,
       default: '我知道了'
+    },
+    answerAnalysis: {
+      type: String,
+      default: ''
     }
   },
   emits: ['close', 'conform'],
@@ -20,14 +24,14 @@ export default defineComponent({
           回答错误!
         </div>
 
-        <div class={styles.result}>
+        {/* <div class={styles.result}>
           正确答案: <span class={styles.yes}>A</span>
           您选择: <span class={styles.no}>B</span>
-        </div>
+        </div> */}
 
         <div class={styles.resultContent}>
           <span>答案解析:</span>
-          八分音符,从拍号中可以了解这一段乐谱为4/4拍,每小节4拍,红框小节中共有8个音符共同组成4拍,每个音符半拍,所以是八分音符。
+          {props.answerAnalysis}
         </div>
 
         <Button

+ 14 - 7
src/views/unit-test/model/keep-look-question/index.tsx

@@ -28,6 +28,10 @@ export default defineComponent({
       type: Boolean,
       default: false
     },
+    showRate: {
+      type: Boolean,
+      default: false
+    },
     showAnalysis: {
       // 是否显示解析
       type: Boolean,
@@ -290,7 +294,7 @@ export default defineComponent({
         result.push({
           answerId: leftOption.index,
           answer: leftOption.leftValue,
-          extra: rightOption.rightValue
+          answerExtra: rightOption.rightValue
         })
       })
       emit('update:value', result)
@@ -299,6 +303,7 @@ export default defineComponent({
     const initOptions = () => {
       const answers = props.data.answers || []
       const userAnswer = props.data.userAnswer || [] // 用户填写的答案
+      // console.log(answers, '111')
       answers.forEach((answer: any) => {
         const tmp = {
           index: answer.examinationQuestionAnswerId, // 左边的值
@@ -316,8 +321,8 @@ export default defineComponent({
       })
 
       // 反显答案-初始化数据
+      // console.log(userAnswer)
       userAnswer.forEach((user: any) => {
-        console.log(user)
         const temps: any = {
           startPoint: { x: 0, y: 0 },
           endPoint: { x: 0, y: 0 },
@@ -332,7 +337,8 @@ export default defineComponent({
             temps.leftIndex = option.index
           }
           // 右边状态
-          if (option.rightValue === user.extra) {
+          // console.log(option, user, '----')
+          if (option.rightValue === user.answerExtra) {
             option.right = true
             option.leftLocked = true
             temps.rightIndex = option.index
@@ -349,10 +355,9 @@ export default defineComponent({
           const leftObj: any = useRect(document.getElementById(draw.leftIndex + '-left') as any)
           leftObj.index = draw.leftIndex
           state.selectItem[0] = leftObj
-          const rightObj: any = useRect(document.getElementById(draw.leftIndex + '-right') as any)
+          const rightObj: any = useRect(document.getElementById(draw.rightIndex + '-right') as any)
           rightObj.index = draw.rightIndex
           state.selectItem[1] = rightObj
-
           const postion = calcPoint()
           draw.endPoint = postion.endPoint
           draw.startPoint = postion.startPoint
@@ -360,7 +365,7 @@ export default defineComponent({
         })
         setTimeout(() => {
           renderDrawLine(canvasRef.value)
-        }, 60)
+        }, 100)
       })
     }
 
@@ -383,10 +388,12 @@ export default defineComponent({
             index={props.index}
             name={props.data.name}
             score={props.data.totalScore}
+            showRate={props.showRate}
             answerType={QuestionType.LINK}
             extra={{
               questionDetail: props.data.questionDetail,
-              mediaUrls: props.data.mediaUrls
+              mediaUrls: props.data.mediaUrls,
+              rightRate: props.data.rightRate
             }}
           />
 

+ 26 - 10
src/views/unit-test/model/play-question/index.tsx

@@ -40,6 +40,10 @@ export default defineComponent({
       type: Boolean,
       default: false
     },
+    showRate: {
+      type: Boolean,
+      default: false
+    },
     showAnalysis: {
       // 是否显示解析
       type: Boolean,
@@ -78,7 +82,7 @@ export default defineComponent({
       postMessage({
         api: 'openAccompanyWebView',
         content: {
-          url: `https://ponline.colexiu.com/orchestra-music-score/?id=${info.musicSheetId}&modelType=evaluation&unitId=${props.unitId}`,
+          url: `https://ponline.colexiu.com/orchestra-music-score/?id=${info.musicSheetId}&modelType=evaluation&unitId=${props.unitId}&questionId=${props.data.id}`,
           // url: `${location.origin}/orchestra-music-score/?id=${info.musicSheetId}&modelType=evaluation&unitId=${props.unitId}`,
           orientation: 0,
           isHideTitle: true,
@@ -94,7 +98,9 @@ export default defineComponent({
             const content = res.content
             if (content.value) {
               const result = content.value ? JSON.parse(content.value) : {}
-              if (result.unitId === props.unitId) {
+              console.log('🚀 ~ listenerMessage ~ result', result, props.data.questionId)
+
+              if (result.questionId === props.data.id) {
                 const tempScore = result.score || 0
                 // 跟上一次分数对比
                 if (state.score < tempScore) {
@@ -106,7 +112,7 @@ export default defineComponent({
                 {
                   answerId: answer[0].examinationQuestionId,
                   answer: state.score,
-                  extra: ''
+                  answerExtra: ''
                 }
               ])
             }
@@ -128,10 +134,12 @@ export default defineComponent({
             index={props.index}
             name={props.data.name}
             score={props.data.totalScore}
+            showRate={props.showRate}
             answerType={QuestionType.PLAY}
             extra={{
               questionDetail: props.data.questionDetail,
-              mediaUrls: ''
+              mediaUrls: '',
+              rightRate: props.data.rightRate
             }}
           />
 
@@ -146,7 +154,13 @@ export default defineComponent({
                   icon: () => <Image class={styles.img} src={iconSong} />,
                   title: () => <>{questionExtendsInfo.value.musicName}</>,
                   value: () => (
-                    <Button round class={styles.playBtn} type="primary" onClick={onEvaluation}>
+                    <Button
+                      round
+                      class={styles.playBtn}
+                      type="primary"
+                      onClick={onEvaluation}
+                      disabled={props.readOnly}
+                    >
                       点击评测
                       <Icon name="play" />
                     </Button>
@@ -155,11 +169,13 @@ export default defineComponent({
               </Cell>
             )}
 
-            <div class={['van-hairline--top', styles.unitScoreNum]}>
-              <div class={styles.score}>{state.score}</div>
-              <div class={styles.scoreTitle}>评测分数</div>
-              <div class={styles.scoreTips}>多次评测取完整评测的最高分数</div>
-            </div>
+            {!props.readOnly && (
+              <div class={['van-hairline--top', styles.unitScoreNum]}>
+                <div class={styles.score}>{state.score}</div>
+                <div class={styles.scoreTitle}>评测分数</div>
+                <div class={styles.scoreTips}>多次评测取完整评测的最高分数</div>
+              </div>
+            )}
           </div>
         </div>
         {props.showAnalysis && (

+ 7 - 0
src/views/unit-test/model/result-finish/index.module.less

@@ -46,6 +46,13 @@
     height: 413px;
   }
 }
+.finishPractice {
+  .finishContainer {
+    background: url('../../images/exam-pass-bg-p.png') no-repeat top center;
+    background-size: contain;
+    height: 513px;
+  }
+}
 
 .finishBtnGroup {
   margin-top: 30px;

Some files were not shown because too many files changed in this diff