Browse Source

Merge branch 'iteration-create' into dev

liushengqiang 2 năm trước cách đây
mục cha
commit
baa9ef45a1

+ 1 - 1
index.html

@@ -35,7 +35,7 @@
   <!-- windows phone 点击无高光 -->
   <meta name="msapplication-tap-highlight" content="no" />
   <meta name="referrer" content="no-referrer" />
-  <title>学生端</title>
+  <title>音乐数字课堂</title>
   <script src="/flexible.js" charset="UTF-8"></script>
 </head>
 

BIN
src/components/the-vip/icon_bg.png


BIN
src/components/the-vip/icon_btn.png


BIN
src/components/the-vip/icon_close.png


BIN
src/components/the-vip/icon_title.png


+ 54 - 0
src/components/the-vip/index.module.less

@@ -0,0 +1,54 @@
+.container {
+    position: relative;
+    width: 335px;
+    height: 298px;
+    background: url('./icon_bg.png') no-repeat;
+    background-size: 100%;
+    display: flex;
+    flex-direction: column;
+    padding-top: 56px;
+}
+
+.close {
+    position: absolute;
+    right: 0;
+    top: 30px;
+    width: 30px;
+    height: 30px;
+}
+
+.title {
+    margin-left: 14px;
+    width: 131px;
+    display: block;
+}
+
+.content {
+    position: relative;
+    padding: 40px 20px 20px 20px;
+    font-size: 16px;
+    font-weight: 400;
+    color: #333333;
+    line-height: 22px;
+    z-index: 10;
+}
+
+.btns {
+    position: absolute;
+    bottom: 18px;
+    width: 50%;
+    left: 50%;
+    transform: translateX(-50%);
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    font-size: 18px;
+    color: #777;
+    line-height: 26px;
+    text-align: center;
+
+    img {
+        width: 100%;
+        margin-bottom: 12px;
+    }
+}

+ 35 - 0
src/components/the-vip/index.tsx

@@ -0,0 +1,35 @@
+import { defineComponent } from 'vue';
+import icon_bg from './icon_bg.png';
+import icon_title from './icon_title.png';
+import icon_btn from './icon_btn.png';
+import icon_close from './icon_close.png';
+import styles from './index.module.less';
+
+export default defineComponent({
+  name: 'TheVip',
+  emits: ['close'],
+  setup(props, { emit }) {
+    return () => (
+      <div class={styles.container}>
+        <img
+          class={styles.close}
+          src={icon_close}
+          onClick={() => emit('close')}
+        />
+        <img class={styles.title} src={icon_title} />
+        <div class={styles.content}>
+          您还未领取<span style={{ color: '#FF5A56' }}>“小酷AI”</span>
+          哦,如需继续使用,请领取~
+        </div>
+        <div class={styles.btns}>
+          <img
+            class={styles.btn}
+            src={icon_btn}
+            onClick={() => emit('close', true)}
+          />
+          <div onClick={() => emit('close')}>暂不领取</div>
+        </div>
+      </div>
+    );
+  }
+});

+ 0 - 7
src/router/router-root.ts

@@ -30,13 +30,6 @@ export default [
       title: '数字化乐器学练工具'
     }
   },
-  {
-    path: '/courseware-play',
-    component: () => import('@/views/courseware-play/index'),
-    meta: {
-      title: '课件播放'
-    }
-  },
 
   {
     path: '/payment-result',

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

@@ -156,6 +156,14 @@ export default [
         meta: {
           title: '小酷AI'
         }
+      },
+
+      {
+        path: '/courseware-play',
+        component: () => import('@/views/courseware-play/index'),
+        meta: {
+          title: '课件播放'
+        }
       }
     ]
   },

+ 56 - 28
src/views/co-ai/index.tsx

@@ -15,6 +15,7 @@ import {
   List,
   Loading,
   NoticeBar,
+  Popup,
   showLoadingToast,
   showToast
 } from 'vant';
@@ -35,6 +36,7 @@ import { state } from '@/state';
 import MEmpty from '@/components/m-empty';
 import Coaiguide from '@/custom-plugins/guide-page/coai-guide'
 import { usePageVisibility } from '@vant/use';
+import TheVip from '@/components/the-vip';
 export default defineComponent({
   name: 'co-ai',
   setup() {
@@ -71,7 +73,8 @@ export default defineComponent({
         top: '',
         width: '',
         height: ''
-      }
+      },
+      showVip: false
     });
     const downRef = ref();
     // 返回
@@ -80,8 +83,13 @@ export default defineComponent({
     };
     /** 去云教练 */
     const handleGoto = () => {
-      let src = `${location.origin}/instrument?id=${data.musics[data.musicIndex]?.id
-        }`;
+      if (!state.user.data?.vipMember) {
+        data.showVip = true;
+        return;
+      }
+      let src = `${location.origin}/instrument?id=${
+        data.musics[data.musicIndex]?.id
+      }`;
       console.log(src);
       postMessage({
         api: 'openAccompanyWebView',
@@ -240,30 +248,29 @@ export default defineComponent({
               })}
             </div>
             <div class={styles.center}>
-              <div class={styles.centerSearch}>
-                <div id="coai-0">
-                  <MSearch
-
-                    class={["searchNotice", data.searchNoticeShow ? styles.searchNoticeShow : '']}
-                    shape="round"
-                    background="transparent"
-                    clearable={false}
-                    placeholder="请输入关键字"
-                    onFocus={() => (data.searchNoticeShow = false)}
-                    onBlur={(val) => {
-                      musicForms.keyword = val;
-                      requestAnimationFrame(() => {
-                        requestAnimationFrame(() => {
-                          data.searchNoticeShow = true;
-                        });
-                      });
-                    }}
-                    onSearch={val => {
-                      musicForms.keyword = val;
-                      handleReset();
-                    }}
-                  />
-                </div></div>
+              <MSearch
+                class={[
+                  'searchNotice',
+                  data.searchNoticeShow ? styles.searchNoticeShow : ''
+                ]}
+                shape="round"
+                background="transparent"
+                clearable={false}
+                placeholder="请输入关键字"
+                onFocus={() => (data.searchNoticeShow = false)}
+                onBlur={val => {
+                  musicForms.keyword = val;
+                  requestAnimationFrame(() => {
+                    requestAnimationFrame(() => {
+                      data.searchNoticeShow = true;
+                    });
+                  });
+                }}
+                onSearch={val => {
+                  musicForms.keyword = val;
+                  handleReset();
+                }}
+              />
               <div class={styles.musicContent}>
                 {data.musics.map((item: any, index: number) => {
                   return (
@@ -323,7 +330,8 @@ export default defineComponent({
               {data.isShowJianpu ? (
                 <>
                   <TransitionGroup name="van-fade">
-                    {data.musics[data.musicIndex]?.musicSvg?.split(',')
+                    {data.musics[data.musicIndex]?.musicSvg
+                      ?.split(',')
                       .map((item: any, index: number) => {
                         return (
                           <img
@@ -383,6 +391,26 @@ export default defineComponent({
         )}
 
         <Coaiguide ></Coaiguide>
+        <Popup
+          class="popup-custom van-scale"
+          transition="van-scale"
+          closeOnClickOverlay={false}
+          v-model:show={data.showVip}>
+          <TheVip
+            onClose={val => {
+              if (val) {
+                postMessage({
+                  api: 'openWebView',
+                  content: {
+                    url: `${location.origin}${location.pathname}#/member-center`,
+                    orientation: 1,
+                  }
+                });
+              }
+              data.showVip = false;
+            }}
+          />
+        </Popup>
       </div>
     );
   }

+ 52 - 57
src/views/courseware-list/index.tsx

@@ -23,7 +23,7 @@ import TheFavorite from '@/components/the-favorite';
 import { useRouter } from 'vue-router';
 import TheBook from './component/book';
 import { postMessage } from '@/helpers/native-message';
-import CoursewareList from '@/custom-plugins/guide-page/courseware-list'
+import CoursewareList from '@/custom-plugins/guide-page/courseware-list';
 import './jquery.min.1.7.js';
 import './turn.js';
 import MEmpty from '@/components/m-empty';
@@ -59,7 +59,7 @@ export default defineComponent({
     const forms = reactive({
       currentGradeNum: 0,
       page: 1,
-      rows: 10,
+      rows: 999,
       type: 'COURSEWARE'
     });
     const _actions = computed(() => {
@@ -76,7 +76,7 @@ export default defineComponent({
       forms.currentGradeNum = index;
       handleChange();
     };
-const isShowGuide = ref(false)
+    const isShowGuide = ref(false);
     const data = reactive({
       list: [] as any[],
       loading: false,
@@ -96,15 +96,13 @@ const isShowGuide = ref(false)
       });
       if (res?.code === 200 && Array.isArray(res?.data?.rows)) {
         data.list = res.data.rows.map((item: any) => {
-          const type = BOOK_DATA.bookTypes[item.bookType];
-          item.name = `${item.name}(${type})`;
           item.load = false;
           item.key = Date.now() + item.id;
           return item;
         });
       }
       data.loading = false;
-      isShowGuide.value = true
+      isShowGuide.value = true;
     };
     const getFavoriteList = async () => {
       data.loading = true;
@@ -117,9 +115,9 @@ const isShowGuide = ref(false)
       });
       if (res?.code === 200 && Array.isArray(res?.data?.rows)) {
         data.list = res.data.rows.map((item: any) => {
-          const type = BOOK_DATA.bookTypes[item.bookType];
-          item.name = `${item.name}(${type})`;
+          item.name = `${item.name}`;
           item.load = false;
+          item.favoriteFlag = true;
           item.key = Date.now() + item.id;
           return item;
         });
@@ -136,7 +134,6 @@ const isShowGuide = ref(false)
       }
     };
     const handleChange = () => {
-      forms.page = 1;
       getData();
     };
     onMounted(() => {
@@ -152,6 +149,7 @@ const isShowGuide = ref(false)
         await api_lessonCoursewareFavoriteRemove({
           lessonCoursewareId: item.id
         });
+        getData();
       }
     };
 
@@ -206,10 +204,12 @@ const isShowGuide = ref(false)
             class={styles.tabs}
             v-model:active={data.tab}
             onChange={() => handleChange()}>
-            <Tab title="全部教材"   name="all"></Tab>
-            <Tab  name="favorite" v-slots={{
-              title:() => (<div id='courseware-2'>我的收藏</div>)
-            }}></Tab>
+            <Tab title="全部教材" name="all"></Tab>
+            <Tab
+              name="favorite"
+              v-slots={{
+                title: () => <div id="courseware-2">我的收藏</div>
+              }}></Tab>
           </Tabs>
           <Popover
             v-model:show={popoverShow.value}
@@ -218,7 +218,11 @@ const isShowGuide = ref(false)
             onSelect={onSelect}>
             {{
               reference: () => (
-                <Button class={styles.downBtn} round size="small" {...{id:'courseware-3'}} >
+                <Button
+                  class={styles.downBtn}
+                  round
+                  size="small"
+                  {...{ id: 'courseware-3' }}>
                   {BOOK_DATA.grades[forms.currentGradeNum].text}{' '}
                   {/* <img class={styles.icon} src={icon_arrow} /> */}
                   <svg
@@ -280,55 +284,47 @@ const isShowGuide = ref(false)
                   ]}
                   key={item.key}
                   onClick={() => handleOpen(item)}>
-                    {/* courseware- */}
-                    {index==0?<NImage
-                    data-id={item.id}
-                    {...{id:'courseware-0'}}
-
-                    class={[styles.cover, item.load ? styles.loaded : '']}
-                    objectFit="cover"
-                    src={item.coverImg}
-                    onLoad={() => {
-                      item.load = true;
-                    }}
-                    onError={() => {
-                      item.load = true;
-                    }}
-                  />:        <NImage
-                  data-id={item.id}
-                  class={[styles.cover, item.load ? styles.loaded : '']}
-                  objectFit="cover"
-                  src={item.coverImg}
-                  onLoad={() => {
-                    item.load = true;
-                  }}
-                  onError={() => {
-                    item.load = true;
-                  }}
-                />}
+                  {/* courseware- */}
+                  {index == 0 ? (
+                    <NImage
+                      data-id={item.id}
+                      {...{ id: 'courseware-0' }}
+                      class={[styles.cover, item.load ? styles.loaded : '']}
+                      objectFit="cover"
+                      src={item.coverImg}
+                      onLoad={() => {
+                        item.load = true;
+                      }}
+                      onError={() => {
+                        item.load = true;
+                      }}
+                    />
+                  ) : (
+                    <NImage
+                      data-id={item.id}
+                      class={[styles.cover, item.load ? styles.loaded : '']}
+                      objectFit="cover"
+                      src={item.coverImg}
+                      onLoad={() => {
+                        item.load = true;
+                      }}
+                      onError={() => {
+                        item.load = true;
+                      }}
+                    />
+                  )}
 
                   <div class={styles.name}>{item.name}</div>
-                  {index==0? <div
-                   id='courseware-1'
+                  <div
+                    id={index === 0 ? 'courseware-1' : ''}
                     class={styles.favoriteBtn}
                     onClick={(e: Event) => {
                       e.stopPropagation();
-                      if (data.tab !== 'all') return;
                       item.favoriteFlag = !item.favoriteFlag;
                       dubounce(() => handleFavorite(item));
                     }}>
-                    <TheFavorite isFavorite={data.tab !== 'all' ? true : item.favoriteFlag} />
-                  </div>: <div
-                    class={styles.favoriteBtn}
-                    onClick={(e: Event) => {
-                      e.stopPropagation();
-                      if (data.tab !== 'all') return;
-                      item.favoriteFlag = !item.favoriteFlag;
-                      dubounce(() => handleFavorite(item));
-                    }}>
-                    <TheFavorite isFavorite={data.tab !== 'all' ? true : item.favoriteFlag} />
-                  </div>}
-
+                    <TheFavorite isFavorite={item.favoriteFlag} />
+                  </div>
                 </div>
               );
             })}
@@ -347,8 +343,7 @@ const isShowGuide = ref(false)
             data.showBook = false;
           }}
         />
-        {isShowGuide.value? <CoursewareList></CoursewareList>:null}
-
+        {isShowGuide.value ? <CoursewareList></CoursewareList> : null}
       </div>
     );
   }

+ 29 - 1
src/views/courseware-play/component/musicScore.tsx

@@ -3,12 +3,14 @@ import styles from './musicScore.module.less';
 import qs from 'query-string';
 import iconStart from '../image/icon-start.svg';
 import { listenerMessage, postMessage } from '@/helpers/native-message';
-import { Loading, Skeleton } from 'vant';
+import { Loading, Popup, Skeleton } from 'vant';
 import { usePageVisibility } from '@vant/use';
 import { useRoute } from 'vue-router';
 import { browser } from '@/helpers/utils';
 import { storage } from '@/helpers/storage';
 import { ACCESS_TOKEN } from '@/store/mutation-types';
+import TheVip from '@/components/the-vip';
+import { state } from '@/state';
 
 export default defineComponent({
   name: 'musicScore',
@@ -65,6 +67,7 @@ export default defineComponent({
     const isLoaded = ref(false);
     const renderError = ref(false);
     const renderSuccess = ref(false);
+    const showVip = ref(false);
     const Authorization = storage.get(ACCESS_TOKEN);
     const origin = /(localhost|192)/.test(location.host)
       ? 'https://test.lexiaoya.cn'
@@ -97,6 +100,10 @@ export default defineComponent({
 
     // 去云教练完整版
     const gotoAccomany = () => {
+      if (!state.user.data?.vipMember) {
+        showVip.value = true;
+        return;
+      }
       if (isLoading.value) return;
       if (!browserInfo.ios) {
         isLoading.value = true;
@@ -162,6 +169,27 @@ export default defineComponent({
         <div class={styles.skeletonWrap}>
           <Skeleton class={styles.skeleton} row={8} />
         </div>
+        <Popup
+          teleport="body"
+          class="popup-custom van-scale"
+          transition="van-scale"
+          closeOnClickOverlay={false}
+          v-model:show={showVip.value}>
+          <TheVip
+            onClose={val => {
+              if (val) {
+                postMessage({
+                  api: 'openWebView',
+                  content: {
+                    url: `${location.origin}${location.pathname}#/member-center`,
+                    orientation: 1
+                  }
+                });
+              }
+              showVip.value = false;
+            }}
+          />
+        </Popup>
       </div>
     );
   }

+ 5 - 3
src/views/knowledge-library/error-question-mode/index.tsx

@@ -143,6 +143,8 @@ export default defineComponent({
         });
         state.visiableInfo.graspItem.grasp = true;
 
+        eventUnit.emit('unitAudioStop');
+
         // 只有一道题
         if (state.questionList.length === 1) {
           onAfter();
@@ -304,7 +306,8 @@ export default defineComponent({
         router.back();
       } else if (state.visiableInfo.operationType === 'BACK') {
         state.visiableInfo.show = false;
-        onAfter();
+        window.history.pushState(null, '', document.URL);
+        window.addEventListener('popstate', onBack, false);
       } else if (state.visiableInfo.operationType === 'CONTINUE') {
         onResultPopup();
       } else if (state.visiableInfo.operationType === 'GRASP') {
@@ -316,8 +319,7 @@ export default defineComponent({
       if (operationType === 'RESULT') {
       } else if (operationType === 'BACK') {
         state.visiableInfo.show = false;
-        window.history.pushState(null, '', document.URL);
-        window.addEventListener('popstate', onBack, false);
+        onAfter();
       } else if (operationType === 'CONTINUE' || operationType === 'GRASP') {
         state.visiableInfo.show = false;
       }

+ 4 - 0
src/views/knowledge-library/model/result-finish/index.module.less

@@ -19,6 +19,8 @@
   font-weight: bold;
   color: #0F75BB;
   line-height: 24px;
+  max-width: 286px;
+  margin: 0 auto;
 
   span {
     position: relative;
@@ -47,6 +49,8 @@
   font-size: 14px;
   color: #333333;
   line-height: 20px;
+  max-width: 286px;
+  margin: 0 auto;
 }
 
 .finishFail {

+ 3 - 0
src/views/school-register/index.module.less

@@ -209,4 +209,7 @@
       text-align: left !important;
     }
   }
+}
+.sendBtn {
+  width: 80Px;
 }

+ 51 - 25
src/views/school-register/index.tsx

@@ -46,11 +46,7 @@ export default defineComponent({
       cityCode: '', // 所属城市
       provinceCode: '', // 所属省份
       schoolNature: 'PUBLIC' as 'PUBLIC' | 'PRIVATE' | string, // 学校性质
-      schoolType: 'PRIMARY_JUNIOR' as
-        | 'PRIMARY'
-        | 'JUNIOR'
-        | 'PRIMARY_JUNIOR'
-        | string, // 学校类型
+      schoolType: 'PRIMARY' as 'PRIMARY' | 'JUNIOR' | 'PRIMARY_JUNIOR' | string, // 学校类型
       gradeYear: 'SIX_YEAR_SYSTEM' as
         | 'FIVE_YEAR_SYSTEM'
         | 'SIX_YEAR_SYSTEM'
@@ -111,30 +107,24 @@ export default defineComponent({
     });
     /** 发送验证码 */
     const onSendSms = async () => {
-      try {
-        await api_openSendSms({
-          clientId: 'cooleshow-student',
-          type: 'REGISTER',
-          mobile: forms.educationalAdministrationPhone
-        });
-        onCountDown();
-        showToast('验证码已发送');
-      } catch {
-        data.sendMsg = '重新发送';
-      }
+      if (data.sendMsg.includes('s')) return;
+      onCountDown();
+      showToast('验证码已发送');
     };
     const onCountDown = () => {
-      data.sendMsg = '30s';
-      let count = 30;
-      setInterval(() => {
+      data.sendMsg = '60s';
+      let count = 60;
+      let timer = setInterval(() => {
         count--;
-        data.sendMsg = `${count}s后重新发送`;
+        data.sendMsg = `${count}s`;
         if (count <= 0) {
           data.sendMsg = '重新发送';
+          clearInterval(timer);
         }
       }, 1000);
     };
     const handleSubmit = async () => {
+      forms.name = forms.name.trim();
       const res = await api_schoolAdd({ ...forms });
       if (res?.code === 200) {
         data.success = true;
@@ -206,21 +196,27 @@ export default defineComponent({
                     }}
                   </Field>
 
-                  <Field center border label="学年制">
+                  <Field center border label="学校类型" labelWidth="70px">
                     {{
                       input: () => (
                         <>
-                          {formOptions.grades.map(item => {
+                          {formOptions.types.map(item => {
                             return (
                               <Button
                                 class={styles.radio}
                                 size="small"
                                 color={
-                                  item.value === forms.gradeYear
+                                  item.value === forms.schoolType
                                     ? '#198CFE'
                                     : ''
                                 }
-                                onClick={() => (forms.gradeYear = item.value)}>
+                                onClick={() => {
+                                  forms.schoolType = item.value;
+                                  forms.gradeYear =
+                                    item.value === 'PRIMARY_JUNIOR'
+                                      ? 'NINE_YEAR_SYSTEM'
+                                      : 'SIX_YEAR_SYSTEM';
+                                }}>
                                 {item.label}
                               </Button>
                             );
@@ -229,6 +225,34 @@ export default defineComponent({
                       )
                     }}
                   </Field>
+
+                  {forms.schoolType === 'PRIMARY_JUNIOR' ? null : (
+                    <Field center border label="学年制">
+                      {{
+                        input: () => (
+                          <>
+                            {formOptions.grades.map(item => {
+                              return (
+                                <Button
+                                  class={styles.radio}
+                                  size="small"
+                                  color={
+                                    item.value === forms.gradeYear
+                                      ? '#198CFE'
+                                      : ''
+                                  }
+                                  onClick={() =>
+                                    (forms.gradeYear = item.value)
+                                  }>
+                                  {item.label}
+                                </Button>
+                              );
+                            })}
+                          </>
+                        )
+                      }}
+                    </Field>
+                  )}
                 </CellGroup>
 
                 <CellGroup class={styles.group}>
@@ -319,6 +343,8 @@ export default defineComponent({
                     {{
                       button: () => (
                         <Button
+                          disabled={data.sendMsg.includes('s')}
+                          class={styles.sendBtn}
                           size="small"
                           type="primary"
                           color="#198CFE"
@@ -344,7 +370,7 @@ export default defineComponent({
                   </Field>
                   <div style={{ padding: '10px 16px' }}>
                     <div class={styles.tips}>
-                      负责人即为该学校酷乐秀课堂乐器老师端管理员,手机号即为酷乐秀课堂乐器老师端账号,默认密码为:ktyq+手机号后四位
+                      负责人即为该学校音乐数字课堂老师端管理员,手机号即为音乐数字课堂老师端账号,默认密码为:yyszkt+手机号后四位
                     </div>
                   </div>
                 </CellGroup>

+ 1 - 1
src/views/student-register/index.tsx

@@ -512,7 +512,7 @@ export default defineComponent({
         />
 
         {/* 是否在微信中打开 */}
-        {/* <OWxTip /> */}
+        <OWxTip />
       </div>
     );
   }

+ 1 - 3
src/views/student-register/register-modal/index.tsx

@@ -190,9 +190,7 @@ export default defineComponent({
               label: () => (
                 <div>
                   联系方式(直接监护人)
-                  <p class={styles.tips}>
-                    手机号是数字化器乐学练工具的唯一登录账户
-                  </p>
+                  <p class={styles.tips}>手机号是音乐数字课堂的唯一登录账户</p>
                 </div>
               )
             }}

+ 3 - 8
src/views/teaher-register/index.tsx

@@ -102,11 +102,6 @@ export default defineComponent({
     const onCodeSend = async (code: string) => {
       if (data.sendMsg.includes('s')) return;
       try {
-        await api_openSendSms({
-          clientId: 'cooleshow-student',
-          type: 'REGISTER',
-          mobile: forms.phone
-        });
         onCountDown();
         showToast({
           message: '验证码发送成功',
@@ -207,7 +202,7 @@ export default defineComponent({
                   v-model={forms.phone}
                 />
                 <div class={styles.tips}>
-                  该手机号码即为酷乐秀课堂乐器老师端登录账号
+                  该手机号码即为音乐数字课堂老师端登录账号
                 </div>
                 <Field
                   class={styles.inputCode}
@@ -248,7 +243,7 @@ export default defineComponent({
                     )
                   }}
                 </Field>
-                <div class={styles.xieyiWrap}>
+                {/* <div class={styles.xieyiWrap}>
                   <Checkbox v-model={data.checked}>
                     <div class={styles.xieyi}>
                       <span>我已阅读并同意</span>
@@ -270,7 +265,7 @@ export default defineComponent({
                       <span>注册协议</span>
                     </div>
                   </Checkbox>
-                </div>
+                </div> */}
                 <div class={styles.submit}>
                   <Button block native-type="submit">
                     注册