Browse Source

Merge branch 'share-member' into ponline

lex 2 years ago
parent
commit
118a5a82b3
64 changed files with 1280 additions and 297 deletions
  1. 0 0
      dist/assets/create-legacy.108e9d2b.js
  2. 2 1
      dist/assets/create-legacy.5ba2ea4d.js
  3. 0 0
      dist/assets/create.352af18b.js
  4. 0 0
      dist/assets/create.5537fcd9.js
  5. 0 0
      dist/assets/create.6e398a80.js
  6. 0 0
      dist/assets/create.7b3c399e.js
  7. 0 0
      dist/assets/index-legacy.7bb0ecbc.js
  8. 0 0
      dist/assets/index-legacy.82045dfd.js
  9. 0 0
      dist/assets/index.c4c66929.js
  10. 0 0
      dist/assets/index.cc9754dd.js
  11. 0 0
      dist/assets/index.f97b1fce.js
  12. 0 0
      dist/assets/polyfills-legacy.cb5a1590.js
  13. 0 1
      dist/assets/teacher-home-legacy.bf8431ea.js
  14. 0 0
      dist/assets/teacher-home.45757138.js
  15. 0 0
      dist/assets/teacher-legacy.8a1884d2.js
  16. 0 0
      dist/assets/teacher.58cfa149.js
  17. 3 3
      dist/index.html
  18. 3 3
      dist/teacher.html
  19. 45 0
      src/business-components/course-video-item/index.module.less
  20. 86 33
      src/business-components/course-video-item/index.tsx
  21. 21 6
      src/business-components/user-detail/index.module.less
  22. 19 1
      src/business-components/user-detail/index.tsx
  23. 5 0
      src/components/col-popup/index.tsx
  24. 3 4
      src/components/col-upload-video/index.tsx
  25. 4 4
      src/components/col-upload/index.tsx
  26. 6 2
      src/router/index-student.ts
  27. 7 2
      src/router/index-teacher.ts
  28. 25 1
      src/state.ts
  29. 16 1
      src/student/live-class/live-detail.tsx
  30. 2 2
      src/student/teacher-dependent/model/teacher-header.tsx
  31. 49 15
      src/student/video-class/video-class-detail.tsx
  32. 62 14
      src/student/video-class/video-detail.tsx
  33. 13 6
      src/teacher/live-class/create.tsx
  34. 1 5
      src/teacher/music/upload/index.tsx
  35. 3 3
      src/teacher/share-page/share-music/index.tsx
  36. 23 11
      src/teacher/share-page/share-video/index.tsx
  37. 9 0
      src/teacher/video-class/class-content.module.less
  38. 78 1
      src/teacher/video-class/class-content.tsx
  39. 6 0
      src/teacher/video-class/class-info.tsx
  40. 39 13
      src/teacher/video-class/create-submit.tsx
  41. 27 22
      src/teacher/video-class/create.module.less
  42. 18 2
      src/teacher/video-class/create.tsx
  43. 2 0
      src/teacher/video-class/createState.tsx
  44. 22 0
      src/teacher/video-class/model/music-album/index.module.less
  45. 207 0
      src/teacher/video-class/model/music-album/index.tsx
  46. 49 15
      src/teacher/video-class/video-class-detail.tsx
  47. 89 26
      src/teacher/video-class/video-detail.tsx
  48. 16 7
      src/views/music/album-detail/index.tsx
  49. BIN
      src/views/music/component/images/icon_music_active.png
  50. 5 1
      src/views/music/component/music-grid/index.tsx
  51. 13 3
      src/views/music/component/song/index.tsx
  52. 13 6
      src/views/music/list/index.tsx
  53. 13 6
      src/views/music/list/list.tsx
  54. 4 2
      src/views/music/look-album-list/index.tsx
  55. 36 16
      src/views/music/music-detail/index.tsx
  56. 0 28
      src/views/music/music.ts
  57. 23 3
      src/views/music/personal/album-my.tsx
  58. 13 6
      src/views/music/personal/collection.tsx
  59. 9 2
      src/views/music/personal/index.tsx
  60. 33 7
      src/views/music/personal/personal.tsx
  61. 13 6
      src/views/music/personal/practice.tsx
  62. 13 6
      src/views/music/songbook/list.tsx
  63. 31 1
      src/views/order-detail/order-video/index.module.less
  64. 101 0
      src/views/order-detail/order-video/index.tsx

File diff suppressed because it is too large
+ 0 - 0
dist/assets/create-legacy.108e9d2b.js


File diff suppressed because it is too large
+ 2 - 1
dist/assets/create-legacy.5ba2ea4d.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/create.352af18b.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/create.5537fcd9.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/create.6e398a80.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/create.7b3c399e.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/index-legacy.7bb0ecbc.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/index-legacy.82045dfd.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/index.c4c66929.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/index.cc9754dd.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/index.f97b1fce.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/polyfills-legacy.cb5a1590.js


File diff suppressed because it is too large
+ 0 - 1
dist/assets/teacher-home-legacy.bf8431ea.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/teacher-home.45757138.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/teacher-legacy.8a1884d2.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/teacher.58cfa149.js


+ 3 - 3
dist/index.html

@@ -35,7 +35,7 @@
     <meta name="msapplication-tap-highlight" content="no" />
     <title>酷乐秀</title>
     <script src="./flexible.js" charset="UTF-8"></script>
-    <script type="module" crossorigin src="./assets/index.a6a2e45b.js"></script>
+    <script type="module" crossorigin src="./assets/index.f97b1fce.js"></script>
     <link rel="modulepreload" href="./assets/vendor.ff5bdeff.js">
     <link rel="modulepreload" href="./assets/index.5e69971c.js">
     <link rel="stylesheet" href="./assets/vendor.68261ebd.css">
@@ -49,7 +49,7 @@
     
     <!-- <script type="module" src="/src/teacher/main.ts"></script> -->
     <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
-    <script nomodule id="vite-legacy-polyfill" src="./assets/polyfills-legacy.30fe173d.js"></script>
-    <script nomodule id="vite-legacy-entry" data-src="./assets/index-legacy.d68c00cc.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+    <script nomodule id="vite-legacy-polyfill" src="./assets/polyfills-legacy.cb5a1590.js"></script>
+    <script nomodule id="vite-legacy-entry" data-src="./assets/index-legacy.82045dfd.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
   </body>
 </html>

+ 3 - 3
dist/teacher.html

@@ -35,7 +35,7 @@
     <meta name="msapplication-tap-highlight" content="no" />
     <title>酷乐秀</title>
     <script src="./flexible.js" charset="UTF-8"></script>
-    <script type="module" crossorigin src="./assets/teacher.2efed979.js"></script>
+    <script type="module" crossorigin src="./assets/teacher.58cfa149.js"></script>
     <link rel="modulepreload" href="./assets/vendor.ff5bdeff.js">
     <link rel="modulepreload" href="./assets/index.5e69971c.js">
     <link rel="stylesheet" href="./assets/index.2dcec38a.css">
@@ -48,7 +48,7 @@
     <div id="app"></div>
     
     <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
-    <script nomodule id="vite-legacy-polyfill" src="./assets/polyfills-legacy.30fe173d.js"></script>
-    <script nomodule id="vite-legacy-entry" data-src="./assets/teacher-legacy.457b3f67.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+    <script nomodule id="vite-legacy-polyfill" src="./assets/polyfills-legacy.cb5a1590.js"></script>
+    <script nomodule id="vite-legacy-entry" data-src="./assets/teacher-legacy.8a1884d2.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
   </body>
 </html>

+ 45 - 0
src/business-components/course-video-item/index.module.less

@@ -70,3 +70,48 @@
     width: 20px !important;
   }
 }
+
+.CourseVideoItem {
+  padding-bottom: 12px !important;
+}
+
+.infoVideo {
+  margin-top: 10px;
+  padding: 8px 10px;
+  border-radius: 6px;
+  font-size: 13px;
+  line-height: 1.4;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  & > div {
+    display: flex;
+    align-items: center;
+  }
+  img {
+    width: 16px;
+    height: 16px;
+  }
+  span {
+    padding-left: 8px;
+    max-width: 240px;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+  }
+
+  .song {
+    border-radius: 8px 0 8px 0;
+    padding: 0 6px;
+  }
+
+  &.albumInfo {
+    background: #e0f7f3;
+    color: #2dc7aa;
+  }
+
+  &.musicInfo {
+    background: #ffefe0;
+    color: #ff8900;
+  }
+}

+ 86 - 33
src/business-components/course-video-item/index.tsx

@@ -1,8 +1,10 @@
 import { defineComponent, PropType } from 'vue'
 import styles from './index.module.less'
-import { Cell, Icon, Image } from 'vant'
+import { Cell, Icon, Image, Tag } from 'vant'
 import videoStop from '@common/images/icon_video_stop.png'
 import bars from '@common/svg/bars.svg'
+import iconAlbum from '@views/music/component/images/icon_album_active.png'
+import iconMusic from '@views/music/component/images/icon_music_active.png'
 
 /**
  * @description: 课程视频列表项
@@ -19,6 +21,12 @@ interface IDetail {
   index?: number
 }
 
+interface IInfos {
+  relationMusicAlbum: string
+  musicAlbumName: string
+  musicAlbumId: string | number
+}
+
 export default defineComponent({
   name: 'CourseVideoItem',
   props: {
@@ -26,6 +34,12 @@ export default defineComponent({
       type: Object as PropType<IDetail>,
       required: true
     },
+    musicAlbumInfos: {
+      type: Array as PropType<IInfos[]>,
+      default: () => {
+        return []
+      }
+    },
     border: {
       type: Boolean,
       default: false
@@ -34,6 +48,10 @@ export default defineComponent({
       type: Function as PropType<(detail: IDetail) => void>,
       default: () => {}
     },
+    onMusicAlbumDetail: {
+      type: Function as PropType<(detail: IDetail) => void>,
+      default: () => {}
+    },
     playId: {
       // 播放视屏编号
       type: Number,
@@ -42,42 +60,77 @@ export default defineComponent({
   },
   render() {
     return (
-      <Cell
-        class={styles.videoSection}
-        border={this.border}
-        onClick={() => this.onPlay(this.detail)}
-        v-slots={{
-          icon: () => (
-            <div class={styles.videoImg}>
-              <Image src={this.detail.imgUrl} fit="cover" />
-              {this.detail.id === this.playId ? (
-                <div class={styles.living}>
-                  <Image src={bars} class={styles.animation} />
-                  <span>播放中</span>
-                </div>
+      <div class={styles.CourseVideoItem}>
+        <Cell
+          class={styles.videoSection}
+          border={this.border}
+          onClick={() => this.onPlay(this.detail)}
+          v-slots={{
+            icon: () => (
+              <div class={styles.videoImg}>
+                <Image src={this.detail.imgUrl} fit="cover" />
+                {this.detail.id === this.playId ? (
+                  <div class={styles.living}>
+                    <Image src={bars} class={styles.animation} />
+                    <span>播放中</span>
+                  </div>
+                ) : (
+                  <Icon class={styles.videoStop} name={videoStop} size={26} />
+                )}
+              </div>
+            ),
+            title: () => (
+              <div class={[styles.videoTitle, 'videoSmall']}>
+                <p
+                  class={[
+                    styles.videoTitleText,
+                    'van-ellipsis',
+                    this.detail.id === this.playId && styles.active
+                  ]}
+                >
+                  {this.detail.title}
+                </p>
+                <p class={[styles.videoTitleContent, 'van-multi-ellipsis--l2']}>
+                  {this.detail.content}
+                </p>
+              </div>
+            )
+          }}
+        ></Cell>
+        {this.musicAlbumInfos.map((info: any) => (
+          <div
+            class={[
+              styles.infoVideo,
+              info.relationMusicAlbum === 'ALBUM'
+                ? styles.albumInfo
+                : styles.musicInfo
+            ]}
+            onClick={() => this.onMusicAlbumDetail(info)}
+          >
+            <div>
+              <img
+                src={
+                  info.relationMusicAlbum === 'ALBUM' ? iconAlbum : iconMusic
+                }
+              />
+              {info.relationMusicAlbum === 'ALBUM' ? (
+                <span>专辑:{info.musicAlbumName}</span>
               ) : (
-                <Icon class={styles.videoStop} name={videoStop} size={26} />
+                <span>曲目:{info.musicAlbumName}</span>
               )}
             </div>
-          ),
-          title: () => (
-            <div class={[styles.videoTitle, 'videoSmall']}>
-              <p
-                class={[
-                  styles.videoTitleText,
-                  'van-ellipsis',
-                  this.detail.id === this.playId && styles.active
-                ]}
-              >
-                {this.detail.title}
-              </p>
-              <p class={[styles.videoTitleContent, 'van-multi-ellipsis--l2']}>
-                {this.detail.content}
-              </p>
+
+            <div>
+              {info.useRelationType === 'GIFT' && (
+                <Tag type="primary" class={styles.song}>
+                  赠送
+                </Tag>
+              )}
+              <Icon name="arrow" />
             </div>
-          )
-        }}
-      ></Cell>
+          </div>
+        ))}
+      </div>
     )
   }
 })

+ 21 - 6
src/business-components/user-detail/index.module.less

@@ -31,7 +31,7 @@
       white-space: nowrap;
       text-overflow: ellipsis;
       overflow: hidden;
-      .userHonor{
+      .userHonor {
         width: 39px;
         height: 16px;
         margin-top: 4px;
@@ -49,7 +49,7 @@
     .buyNumInfo {
       font-size: 14px;
       line-height: 20px;
-      color: #FF802C;
+      color: #ff802c;
       .iconBuy {
         margin-right: 5px;
       }
@@ -60,12 +60,12 @@
       font-weight: 600;
       color: var(--van-primary);
       line-height: 20px;
-      color: #FA6400;
-      .infoPrice{
+      color: #fa6400;
+      .infoPrice {
         font-size: 16px;
         font-weight: bold;
       }
-      .infoNum{
+      .infoNum {
         font-size: 14px;
         color: #999;
         font-weight: 400;
@@ -99,8 +99,23 @@
       }
     }
   }
+
+  .buyTips {
+    font-size: 12px;
+    color: #ff8900;
+    padding: 3px 10px !important;
+    background: #ffefe0;
+    border-radius: 6px;
+    margin: 0 14px 12px;
+    width: auto;
+    span {
+      line-height: 21px;
+      color: #ff8900;
+    }
+  }
 }
-.iconTeacher{
+
+.iconTeacher {
   margin-top: 3px;
   margin-right: 6px;
   width: 39px;

+ 19 - 1
src/business-components/user-detail/index.tsx

@@ -18,6 +18,7 @@ import IconJiaozi from '@common/images/icon-jiaozi.png'
  * @param {type} lessonDesc 课程描述
  * @param {type} lessonNum 课程数
  * @param {type} lessonName 课程名称
+ * @param {type} relationType 赠送类型
  */
 interface UserType {
   headUrl: string
@@ -31,6 +32,7 @@ interface UserType {
   lessonCoverUrl: string
   lessonName: string
   auditVersion: number
+  relationType?: string
 }
 
 export default defineComponent({
@@ -51,6 +53,11 @@ export default defineComponent({
     border: {
       type: Boolean,
       default: false
+    },
+    onUserDetail: {
+      // 点击用户头像等信息
+      type: Function,
+      default: (item: any) => {}
     }
   },
   render() {
@@ -97,7 +104,12 @@ export default defineComponent({
                 />
               ),
               title: () => (
-                <div class={styles.name}>
+                <div
+                  class={styles.name}
+                  onClick={() => {
+                    this.onUserDetail(this.userInfo)
+                  }}
+                >
                   <div class={styles.username}>
                     {this.userInfo.username || `游客${this.userInfo.id || ''}`}
                     <div>
@@ -139,6 +151,12 @@ export default defineComponent({
               )
             }}
           ></Cell>
+          {this.userInfo.relationType === 'GIFT' && (
+            <Cell
+              class={styles.buyTips}
+              value={'注:购买本课程即可赠送相关曲目或专辑终生使用权限~'}
+            ></Cell>
+          )}
         </CellGroup>
       </div>
     )

+ 5 - 0
src/components/col-popup/index.tsx

@@ -20,6 +20,10 @@ export default defineComponent({
     position: {
       type: String as PropType<PopupPosition>,
       default: 'bottom'
+    },
+    zIndex: {
+      type: Number,
+      default: 2018
     }
   },
   data() {
@@ -83,6 +87,7 @@ export default defineComponent({
         transitionAppear={true}
         position={this.position}
         style={{ height: this.height }}
+        zIndex={this.zIndex}
         onClosed={() => {
           if (this.destroy) {
             this.isDestroy = true

+ 3 - 4
src/components/col-upload-video/index.tsx

@@ -8,7 +8,7 @@ import umiRequest from 'umi-request'
 import iconUploader from '@common/images/icon_uploader_video.png'
 import iconUploadPoster from '@common/images/icon_upload_poster.png'
 import { postMessage } from '@/helpers/native-message'
-import { state } from '@/state'
+import { getOssUploadUrl, state } from '@/state'
 
 export default defineComponent({
   name: 'ColUploadVideo',
@@ -96,12 +96,11 @@ export default defineComponent({
           formData.append(key, obj[key])
         }
         formData.append('file', file.file)
-        await umiRequest(state.ossUploadUrl + this.bucket, {
+        await umiRequest(getOssUploadUrl(this.bucket), {
           method: 'POST',
           data: formData
         })
-        console.log(state.ossUploadUrl + this.bucket + '/' + key)
-        const uploadUrl = state.ossUploadUrl + this.bucket + '/' + key
+        const uploadUrl = getOssUploadUrl(this.bucket) + key
         Toast.clear()
         this.$emit('update:modelValue', uploadUrl)
         // this.onUploadChange(uploadUrl)

+ 4 - 4
src/components/col-upload/index.tsx

@@ -7,7 +7,7 @@ import { postMessage } from '@/helpers/native-message'
 import umiRequest from 'umi-request'
 import iconUploader from '@common/images/icon_uploader.png'
 import request from '@/helpers/request'
-import { state } from '@/state'
+import { getOssUploadUrl, state } from '@/state'
 
 export default defineComponent({
   name: 'col-upload',
@@ -143,12 +143,12 @@ export default defineComponent({
           formData.append(key, obj[key])
         }
         formData.append('file', file, fileName)
-        await umiRequest(state.ossUploadUrl + this.bucket, {
+        await umiRequest(getOssUploadUrl(this.bucket), {
           method: 'POST',
           data: formData
         })
-        console.log(state.ossUploadUrl + this.bucket + '/' + key)
-        const uploadUrl = state.ossUploadUrl + this.bucket + '/' + key
+        console.log(getOssUploadUrl(this.bucket) + key)
+        const uploadUrl = getOssUploadUrl(this.bucket) + key
         Toast.clear()
         this.$emit('update:modelValue', uploadUrl)
         this.onUploadChange(uploadUrl)

+ 6 - 2
src/router/index-student.ts

@@ -52,8 +52,12 @@ router.onError(error => {
         confirmButtonColor: 'var(--van-primary)'
       }).then(() => {
         // on close
-        location.hash = targetPath
-        window.location.reload()
+        if (browser().isApp) {
+          postMessage({ api: 'back' })
+        } else {
+          location.hash = targetPath
+          window.location.reload()
+        }
       })
     }
   }

+ 7 - 2
src/router/index-teacher.ts

@@ -1,3 +1,4 @@
+import { browser } from '@/helpers/utils'
 import { Dialog } from 'vant'
 import { createRouter, createWebHashHistory, Router } from 'vue-router'
 import routes from './routes-teacher'
@@ -32,8 +33,12 @@ router.onError(error => {
         confirmButtonColor: 'var(--van-primary)'
       }).then(() => {
         // on close
-        location.hash = targetPath
-        window.location.reload()
+        if (browser().isApp) {
+          postMessage({ api: 'back' })
+        } else {
+          location.hash = targetPath
+          window.location.reload()
+        }
       })
     }
   }

+ 25 - 1
src/state.ts

@@ -1,5 +1,6 @@
 import { reactive } from 'vue'
-import { setAuth } from './helpers/utils'
+import { browser, setAuth } from './helpers/utils'
+import { postMessage } from './helpers/native-message'
 
 type status = 'init' | 'login' | 'logout' | 'error'
 
@@ -16,6 +17,12 @@ export const state = reactive({
   openLiveStatus: false as boolean // 是否开通直播
 })
 
+// 预览上传到oss的地址
+export const getOssUploadUrl = (bucket: string) => {
+  const tmpBucket = bucket || 'daya'
+  return `https://${tmpBucket}.ks3-cn-beijing.ksyuncs.com/`
+}
+
 export const setLoginInit = () => {
   state.user.status = 'init'
   state.user.data = null
@@ -35,3 +42,20 @@ export const setLoginError = () => {
   state.user.status = 'error'
   state.user.data = null
 }
+
+// 用于处理跳转地址,如果是在app内,则打开一个新的webview, 否则跳转连接
+export const openDefaultWebView = (url?: string, callBack?: any) => {
+  if (browser().isApp) {
+    postMessage({
+      api: 'openWebView',
+      content: {
+        url,
+        orientation: 1,
+        isHideTitle: false
+      }
+    })
+  } else {
+    callBack && callBack()
+  }
+
+}

+ 16 - 1
src/student/live-class/live-detail.tsx

@@ -15,6 +15,7 @@ import ColShare from '@/components/col-share'
 import LiveItem from '@/views/live-class/live-item'
 import iconShare from '@/views/shop-mall/images/icon-share.svg'
 import { state } from '@/state'
+import { browser } from '@/helpers/utils'
 interface IProps {
   courseTime: string
   coursePlan: string
@@ -270,7 +271,21 @@ export default defineComponent({
             )
           }}
         />
-        <UserDetail userInfo={this.userInfo} showBuy={false} />
+        <UserDetail
+          userInfo={this.userInfo}
+          showBuy={false}
+          onUserDetail={(item: any) => {
+            if (state.platformType === 'STUDENT' && browser().isApp) {
+              this.$router.push({
+                path: '/teacherHome',
+                query: {
+                  teacherId: item.id,
+                  tabs: 'live'
+                }
+              })
+            }
+          }}
+        />
         <SectionDetail border>
           <p class={styles.introduction}>{this.userInfo.lessonDesc}</p>
         </SectionDetail>

+ 2 - 2
src/student/teacher-dependent/model/teacher-header.tsx

@@ -189,8 +189,8 @@ export default defineComponent({
                       api: 'joinChatGroup',
                       content: {
                         type: 'single', // single 单人 multi 多人
-                        // id: this.userInfo.imUserId
-                        id: this.teacherId
+                        id: this.userInfo.imUserId
+                        // id: this.teacherId
                       }
                     })
                   }}

+ 49 - 15
src/student/video-class/video-class-detail.tsx

@@ -34,6 +34,8 @@ export default defineComponent({
       tabIndex: 1,
       title: '',
       lessonPrice: 0,
+      useRelationType: '',
+      alreadyBuy: false,
       detailList: [],
       posterUrl: '',
       srcUrl: '',
@@ -84,6 +86,8 @@ export default defineComponent({
       const result = res.data || {}
       this.title = result.lessonGroup.lessonName
       this.lessonPrice = result.lessonGroup.lessonPrice
+      this.useRelationType = result.lessonGroup.relationType
+      this.alreadyBuy = result.alreadyBuy
       this.detailList = result.detailList || []
       this.trySee = !result.alreadyBuy
       this.detailList.forEach((item: any, index: number) => {
@@ -238,21 +242,51 @@ export default defineComponent({
               }}
             >
               <SectionDetail title="课程列表" icon="courseList" border>
-                {this.detailList.map((item: any, index: number) => (
-                  <CourseVideoItem
-                    class={'mb12'}
-                    playId={Number(this.classId)}
-                    detail={{
-                      id: item.id,
-                      title: item.videoTitle,
-                      content: item.videoContent,
-                      imgUrl: item.coverUrl,
-                      videoUrl: item.videoUrl,
-                      index: index + 1
-                    }}
-                    onPlay={this.onPlay}
-                  />
-                ))}
+                {this.detailList.map((item: any, index: number) => {
+                  const musicAlbumInfos = item.musicAlbumInfos || []
+                  const temp = musicAlbumInfos.map((info: any) => {
+                    return {
+                      relationMusicAlbum: info.relationType,
+                      musicAlbumName: info.name,
+                      musicAlbumId: info.musicAlbumId,
+                      status: info.status,
+                      useRelationType: this.useRelationType
+                    }
+                  })
+                  return (
+                    <CourseVideoItem
+                      musicAlbumInfos={temp}
+                      playId={Number(this.classId)}
+                      detail={{
+                        id: item.id,
+                        title: item.videoTitle,
+                        content: item.videoContent,
+                        imgUrl: item.coverUrl,
+                        videoUrl: item.videoUrl,
+                        index: index + 1
+                      }}
+                      onPlay={this.onPlay}
+                      onMusicAlbumDetail={(item: any) => {
+                        if (!this.alreadyBuy && !item.status) {
+                          Toast('数据正在更新,请稍后再试')
+                          return
+                        }
+                        if (item.relationMusicAlbum === 'MUSIC') {
+                          this.$router.push({
+                            path: '/music-detail',
+                            query: {
+                              id: item.musicAlbumId
+                            }
+                          })
+                        } else if (item.relationMusicAlbum === 'ALBUM') {
+                          this.$router.push({
+                            path: '/music-album-detail/' + item.musicAlbumId
+                          })
+                        }
+                      }}
+                    />
+                  )
+                })}
               </SectionDetail>
             </div>
           </Tab>

+ 62 - 14
src/student/video-class/video-detail.tsx

@@ -1,7 +1,7 @@
 import CourseVideoItem from '@/business-components/course-video-item'
 import SectionDetail from '@/business-components/section-detail'
 import UserDetail from '@/business-components/user-detail'
-import { Sticky, Button, Dialog, Popup } from 'vant'
+import { Sticky, Button, Dialog, Popup, Toast } from 'vant'
 import { defineComponent } from 'vue'
 import styles from './video-detail.module.less'
 import request from '@/helpers/request'
@@ -13,6 +13,7 @@ import iconShare from '@/views/shop-mall/images/icon-share.svg'
 import ColShare from '@/components/col-share'
 import LiveItem from '@/views/live-class/live-item'
 import { state } from '@/state'
+import { browser } from '@/helpers/utils'
 export default defineComponent({
   name: 'VideoDetail',
   data() {
@@ -61,6 +62,7 @@ export default defineComponent({
           lessonName: lessonGroup.lessonName,
           lessonDesc: lessonGroup.lessonDesc,
           lessonPrice: lessonGroup.lessonPrice,
+          relationType: lessonGroup.relationType,
           teacherId: lessonGroup.teacherId,
           lessonCoverUrl: lessonGroup.lessonCoverUrl,
           auditVersion: lessonGroup.auditVersion,
@@ -100,6 +102,7 @@ export default defineComponent({
             teacherName: userInfo.username || `游客${userInfo.teacherId || ''}`,
             teacherId: userInfo.teacherId,
             avatar: userInfo.headUrl,
+            relationType: this.userInfo.relationType,
             courseInfo: this.detailList,
             recomUserId: this.recomUserId
           }
@@ -179,7 +182,21 @@ export default defineComponent({
             )
           }}
         />
-        <UserDetail userInfo={this.userInfo} />
+        <UserDetail
+          userInfo={this.userInfo}
+          onUserDetail={(item: any) => {
+            console.log(item)
+            if (browser().isApp && state.platformType === 'STUDENT') {
+              this.$router.push({
+                path: '/teacherHome',
+                query: {
+                  teacherId: item.teacherId,
+                  tabs: 'video'
+                }
+              })
+            }
+          }}
+        />
         <SectionDetail border={false}>
           <p class={styles.introduction}>{this.userInfo.lessonDesc}</p>
         </SectionDetail>
@@ -190,18 +207,49 @@ export default defineComponent({
           class="mb12"
           border={false}
         >
-          {this.detailList.map((item: any) => (
-            <CourseVideoItem
-              class={['mb12', styles.videoItem]}
-              detail={{
-                id: item.id,
-                title: item.videoTitle,
-                content: item.videoContent,
-                imgUrl: item.coverUrl
-              }}
-              onPlay={this.onPlay}
-            />
-          ))}
+          {this.detailList.map((item: any) => {
+            const musicAlbumInfos = item.musicAlbumInfos || []
+            const temp = musicAlbumInfos.map((info: any) => {
+              return {
+                relationMusicAlbum: info.relationType,
+                musicAlbumName: info.name,
+                musicAlbumId: info.musicAlbumId,
+                status: info.status, // 是否上架
+                useRelationType: this.userInfo.relationType
+              }
+            })
+            return (
+              <CourseVideoItem
+                musicAlbumInfos={temp}
+                class={[styles.videoItem]}
+                detail={{
+                  id: item.id,
+                  title: item.videoTitle,
+                  content: item.videoContent,
+                  imgUrl: item.coverUrl
+                }}
+                onPlay={this.onPlay}
+                onMusicAlbumDetail={(item: any) => {
+                  if (!this.userInfo.alreadyBuy && !item.status) {
+                    Toast('数据正在更新,请稍后再试')
+                    return
+                  }
+                  if (item.relationMusicAlbum === 'MUSIC') {
+                    this.$router.push({
+                      path: '/music-detail',
+                      query: {
+                        id: item.musicAlbumId
+                      }
+                    })
+                  } else if (item.relationMusicAlbum === 'ALBUM') {
+                    this.$router.push({
+                      path: '/music-album-detail/' + item.musicAlbumId
+                    })
+                  }
+                }}
+              />
+            )
+          })}
         </SectionDetail>
 
         {this.userInfo.id && !this.userInfo.alreadyBuy && (

+ 13 - 6
src/teacher/live-class/create.tsx

@@ -48,19 +48,26 @@ export default defineComponent({
     }
     this.getLiveClassDetail()
   },
-  methods:{
-     // 获取直播课详情
-    async getLiveClassDetail(){
+  methods: {
+    // 获取直播课详情
+    async getLiveClassDetail() {
       const groupId = this.$route.query.groupId
       if (!groupId) return
-      const res = await request.get(`/api-teacher/courseGroup/queryLiveCourseInfo?groupId=${groupId}`)
+      const res = await request.get(
+        `/api-teacher/courseGroup/queryLiveCourseInfo?groupId=${groupId}`
+      )
       console.log(res, createState)
-      if (res.code == 200){
+      if (res.code == 200) {
         const data = res.data
         createState.live.courseGroupId = data.courseGroupId
         createState.live.teacherId = data.teacherId
         createState.live.name = data.courseGroupName
-        createState.live.subjectId = (createState.subjectList.find((n:any) => n.name === data.subjectName) as any)?.id || ''
+        createState.live.subjectId =
+          (
+            createState.subjectList.find(
+              (n: any) => n.name === data.subjectName
+            ) as any
+          )?.id || ''
         createState.live.courseIntroduce = data.courseIntroduce
         createState.live.courseNum = data.courseNum
         createState.live.singleMins = data.singleCourseMinutes

+ 1 - 5
src/teacher/music/upload/index.tsx

@@ -277,11 +277,7 @@ export default defineComponent({
         xmlFileUrl: this.xmlFileUrl,
         canEvaluate: Number(this.canEvaluate),
         chargeType: this.chargeType === 0 ? 'FREE' : 'CHARGE',
-        paymentType: this.paymentType
-          ? this.paymentType
-          : this.chargeType === 0
-          ? 'FREE'
-          : 'CHARGE',
+        paymentType: this.chargeType === 0 ? 'FREE' : 'CHARGE',
         exquisiteFlag: this.exquisiteFlag,
         composer: this.composer,
         musicPrice: this.chargeType === 0 ? 0 : this.musicPrice, // 当选择免费时,重置金额为0

+ 3 - 3
src/teacher/share-page/share-music/index.tsx

@@ -27,7 +27,7 @@ import styles from './index.module.less'
 import { useRect } from '@vant/use'
 import { Vue3Lottie } from 'vue3-lottie'
 import { getRandomKey } from '@/views/music/music'
-import { state } from '@/state'
+import { getOssUploadUrl, state } from '@/state'
 import { useEventTracking } from '@/helpers/hooks'
 import ColSticky from '@/components/col-sticky'
 import { browser, moneyFormat } from '@/helpers/utils'
@@ -185,13 +185,13 @@ export default defineComponent({
         const files = base64ToBlob(file)
 
         formData.append('file', files, fileName)
-        const ossUploadUrl = 'https://ks3-cn-beijing.ksyuncs.com/cloud-coach'
+        const ossUploadUrl = getOssUploadUrl('cloud-coach')
         await umiRequest(ossUploadUrl, {
           method: 'POST',
           data: formData
         })
         Toast.clear()
-        const imgurl = ossUploadUrl + '/' + keyTime
+        const imgurl = getOssUploadUrl('cloud-coach') + keyTime
 
         await request.post(state.platformApi + '/open/music/sheet/img', {
           data: { musicSheetId: musicDetail.value.id, musicImg: imgurl }

+ 23 - 11
src/teacher/share-page/share-video/index.tsx

@@ -97,6 +97,7 @@ export default defineComponent({
         lessonName: lessonGroup.lessonName,
         lessonDesc: lessonGroup.lessonDesc,
         lessonPrice: lessonGroup.lessonPrice,
+        relationType: lessonGroup.relationType,
         lessonCoverUrl: lessonGroup.lessonCoverUrl
       }
 
@@ -149,17 +150,28 @@ export default defineComponent({
           icon="courseList"
           contentStyle={{ paddingTop: '0' }}
         >
-          {this.detailList.map((item: any) => (
-            <CourseVideoItem
-              class={'mb12'}
-              detail={{
-                id: item.id,
-                title: item.videoTitle,
-                content: item.videoContent,
-                imgUrl: item.coverUrl
-              }}
-            />
-          ))}
+          {this.detailList.map((item: any) => {
+            const musicAlbumInfos = item.musicAlbumInfos || []
+            const temp = musicAlbumInfos.map((info: any) => {
+              return {
+                relationMusicAlbum: info.relationType,
+                musicAlbumName: info.name,
+                musicAlbumId: info.musicAlbumId,
+                useRelationType: this.userInfo.relationType
+              }
+            })
+            return (
+              <CourseVideoItem
+                musicAlbumInfos={temp}
+                detail={{
+                  id: item.id,
+                  title: item.videoTitle,
+                  content: item.videoContent,
+                  imgUrl: item.coverUrl
+                }}
+              />
+            )
+          })}
         </SectionDetail>
 
         <ColSticky position="bottom">

+ 9 - 0
src/teacher/video-class/class-content.module.less

@@ -50,4 +50,13 @@
       }
     }
   }
+
+  .createVideoTips {
+    font-size: 13px;
+    color: #ff6f00;
+    background: #ffe9d5;
+    border-radius: 10px;
+    padding: 9px 11px;
+    margin: 0 14px;
+  }
 }

+ 78 - 1
src/teacher/video-class/class-content.tsx

@@ -1,5 +1,6 @@
 import ColField from '@/components/col-field'
 import ColFieldGroup from '@/components/col-field-group'
+import ColPopup from '@/components/col-popup'
 import ColUpload from '@/components/col-upload'
 import ColUploadVideo from '@/components/col-upload-video'
 import {
@@ -16,13 +17,16 @@ import {
 import { defineComponent } from 'vue'
 import styles from './class-content.module.less'
 import { createState } from './createState'
+import MusicAlbum from './model/music-album'
 
 export default defineComponent({
   name: 'ClassContent',
   data() {
     return {
       url: '',
-      checked: null
+      checked: null,
+      musicStatus: false,
+      selectItem: {} as any // 选中的课程
     }
   },
   methods: {
@@ -35,6 +39,7 @@ export default defineComponent({
         videoContent: '',
         videoUrl: '',
         coverUrl: '',
+        relationList: [],
         posterUrl: '' // 视频封面图
       })
     },
@@ -48,6 +53,14 @@ export default defineComponent({
       }).then(() => {
         createState.lessonList.splice(index, 1)
       })
+    },
+    getName(item: any) {
+      const relation =
+        item.relationList.length > 0 ? item.relationList[0] : null
+      return relation
+        ? (relation.relationMusicAlbum === 'ALBUM' ? '专辑:' : '曲目:') +
+            relation.musicAlbumName
+        : ''
     }
   },
   render() {
@@ -57,6 +70,9 @@ export default defineComponent({
         onSubmit={this.onSubmit}
         scrollToError
       >
+        <div class={styles.createVideoTips}>
+          您可为每个视频关联曲目或专辑作为本课程教学内容推荐
+        </div>
         {createState.lessonList.map((item: any, index: number) => (
           <>
             <div class={styles.titleSection}>
@@ -143,6 +159,37 @@ export default defineComponent({
                   </Col>
                 </Row>
               </ColField>
+              {/* <van-icon name="clear" /> */}
+              <ColField title="关联曲目或专辑">
+                <Field
+                  modelValue={
+                    item.relationList.length > 0 &&
+                    item.relationList[0].musicAlbumId
+                      ? this.getName(item)
+                      : ''
+                  }
+                  readonly
+                  isLink
+                  clickable={false}
+                  clearable
+                  rightIcon={
+                    item.relationList.length > 0 &&
+                    item.relationList[0].musicAlbumId
+                      ? 'clear'
+                      : ''
+                  }
+                  onClick-right-icon={(e: MouseEvent) => {
+                    e.stopPropagation()
+                    item.relationList[0].musicAlbumId = 0
+                    item.relationList[0].musicAlbumName = ''
+                  }}
+                  onClick={() => {
+                    this.selectItem = item
+                    this.musicStatus = true
+                  }}
+                  placeholder="请选择关联曲目或专辑"
+                />
+              </ColField>
             </ColFieldGroup>
           </>
         ))}
@@ -174,6 +221,36 @@ export default defineComponent({
             </Button>
           </div>
         </Sticky>
+
+        <ColPopup v-model={this.musicStatus} zIndex={999999}>
+          <MusicAlbum
+            subjectId={createState.lessonGroup.lessonSubject}
+            onSelect={(item: any) => {
+              this.musicStatus = false
+              if (this.selectItem.relationList.length > 0) {
+                this.selectItem.relationList[0].musicAlbumId = item.id
+                this.selectItem.relationList[0].musicAlbumName =
+                  item.selectType === 'ALBUM'
+                    ? item.albumName
+                    : item.musicSheetName
+                this.selectItem.relationList[0].relationMusicAlbum =
+                  item.selectType
+              } else {
+                this.selectItem.relationList = [
+                  {
+                    musicAlbumId: item.id,
+                    musicAlbumName:
+                      item.selectType === 'ALBUM'
+                        ? item.albumName
+                        : item.musicSheetName,
+                    relationMusicAlbum: item.selectType,
+                    useRelationType: 'RECOMMEND'
+                  }
+                ]
+              }
+            }}
+          />
+        </ColPopup>
       </Form>
     )
   }

+ 6 - 0
src/teacher/video-class/class-info.tsx

@@ -90,6 +90,12 @@ export default defineComponent({
   },
   methods: {
     onChoice(id: number) {
+      // 切换声部,初始化专辑,曲目选择
+      if (id != createState.lessonGroup.lessonSubject) {
+        createState.lessonList.forEach((element: any) => {
+          element.relationList = []
+        })
+      }
       createState.lessonGroup.lessonSubject = id
       this.subjectStatus = false
     },

+ 39 - 13
src/teacher/video-class/create-submit.tsx

@@ -25,18 +25,34 @@ export default defineComponent({
         lessonCoverUrl:
           videoDetail.lessonCoverTemplateUrl || videoDetail.lessonCoverUrl,
         lessonNum: createState.lessonList.length,
-        auditVersion:0
+        auditVersion: 0
       }
     },
     lessonList() {
+      const lessonList = createState.lessonList || []
+      lessonList.forEach((item: any) => {
+        const relationList = item.relationList
+        const temp = [] as any
+        relationList.forEach((relation: any) => {
+          // 判断是否有选择专辑或曲目
+          if (relation.musicAlbumId) {
+            temp.push(relation)
+          }
+        })
+        item.relationList = temp
+      })
       return createState.lessonList || []
+    },
+    groupId() {
+      const query = this.$route.query
+      return query.groupId || ''
     }
   },
   methods: {
     async onSubmit() {
       try {
         const videoDetail = createState.lessonGroup
-        let params = {
+        const params = {
           lessonList: this.lessonList,
           lessonGroup: {
             ...videoDetail,
@@ -70,16 +86,26 @@ export default defineComponent({
         </SectionDetail>
 
         <SectionDetail title="课程列表" icon="courseList" class="mb12">
-          {this.lessonList.map((item: any) => (
-            <CourseVideoItem
-              class={'mb12'}
-              detail={{
-                title: item.videoTitle,
-                content: item.videoContent,
-                imgUrl: item.coverUrl
-              }}
-            />
-          ))}
+          {this.lessonList.map((item: any) => {
+            const relationList = item.relationList || []
+            const temp = relationList.map((relation: any) => {
+              return {
+                relationMusicAlbum: relation.relationMusicAlbum,
+                musicAlbumName: relation.musicAlbumName,
+                musicAlbumId: relation.musicAlbumId
+              }
+            })
+            return (
+              <CourseVideoItem
+                musicAlbumInfos={temp}
+                detail={{
+                  title: item.videoTitle,
+                  content: item.videoContent,
+                  imgUrl: item.coverUrl
+                }}
+              />
+            )
+          })}
         </SectionDetail>
 
         <Sticky offsetBottom={0} position="bottom">
@@ -96,7 +122,7 @@ export default defineComponent({
               返回编辑
             </Button>
             <Button block round type="primary" onClick={this.onSubmit}>
-              创建完成
+              {this.groupId ? '修改完成' : '创建完成'}
             </Button>
           </div>
         </Sticky>

+ 27 - 22
src/teacher/video-class/create.module.less

@@ -10,32 +10,37 @@
     }
   }
   :global {
-    .van-grid {
-      padding-left: 14px;
-      padding-bottom: 12px;
-      background-color: #f6f8f9;
+    // .van-grid {
+    // }
 
-      .van-grid-item {
-        padding-right: 14px;
+    .van-sticky--fixed {
+      box-shadow: 10px 10px 10px var(--box-shadow-color);
+    }
+  }
+}
 
-        &:first-child {
-          padding-right: 10px;
-        }
-      }
-      .van-grid-item__content {
-        padding-top: 7px;
-        padding-bottom: 7px;
-        border-radius: 10px;
-        overflow: hidden;
-      }
-      .van-badge__wrapper {
-        display: flex;
-        align-items: center;
+.gridColumn {
+  padding-left: 14px;
+  padding-bottom: 12px;
+  background-color: #f6f8f9;
+
+  :global {
+    .van-grid-item {
+      padding-right: 14px;
+
+      &:first-child {
+        padding-right: 10px;
       }
     }
-
-    .van-sticky--fixed {
-      box-shadow: 10px 10px 10px var(--box-shadow-color);
+    .van-grid-item__content {
+      padding-top: 7px;
+      padding-bottom: 7px;
+      border-radius: 10px;
+      overflow: hidden;
+    }
+    .van-badge__wrapper {
+      display: flex;
+      align-items: center;
     }
   }
 }

+ 18 - 2
src/teacher/video-class/create.tsx

@@ -39,11 +39,12 @@ export default defineComponent({
         lessonDesc,
         lessonSubject,
         lessonName,
+        relationType,
         id,
         ...group
       } = result.lessonGroup
       // 判断模板图片是否在模板列表中,如果不在则是用户自己上传的图片
-      let statusUrl = createState.templateList.includes(lessonCoverUrl)
+      const statusUrl = createState.templateList.includes(lessonCoverUrl)
         ? true
         : false
       createState.lessonGroup = {
@@ -52,22 +53,36 @@ export default defineComponent({
         lessonSubject: lessonSubject,
         lessonDesc: lessonDesc,
         lessonPrice: lessonPrice,
+        relationType: 'RECOMMEND',
         lessonCoverTemplateUrl: statusUrl ? lessonCoverUrl : '',
         lessonCoverUrl: statusUrl ? '' : lessonCoverUrl
       }
       createState.lessonList = []
       result.detailList &&
         result.detailList.forEach((item: any) => {
+          const tempInfo = item.musicAlbumInfos || []
+          const relationList = tempInfo.map((info: any) => {
+            return {
+              relationMusicAlbum: info.relationType,
+              musicAlbumName: info.name,
+              musicAlbumId: info.musicAlbumId,
+              relationId: info.id,
+              useRelationType: 'RECOMMEND'
+            }
+          })
           createState.lessonList.push({
             videoTitle: item.videoTitle,
             videoContent: item.videoContent,
             videoUrl: item.videoUrl,
             coverUrl: item.coverUrl,
+            relationList,
             posterUrl: item.posterUrl // 视频封面图
           })
         })
       createState.loadingStatus = false
-    } catch {}
+    } catch {
+      //
+    }
     if (
       createState.lessonGroup.lessonCoverUrl &&
       !createState.templateList.includes(createState.lessonGroup.lessonCoverUrl)
@@ -100,6 +115,7 @@ export default defineComponent({
               style={{ paddingTop: '15px' }}
               direction="horizontal"
               columnNum="2"
+              class={styles.gridColumn}
             >
               <GridItem
                 v-slots={{

+ 2 - 0
src/teacher/video-class/createState.tsx

@@ -31,6 +31,7 @@ export const createState = reactive({
     lessonDesc: '',
     lessonPrice: null as any,
     lessonCoverUrl: '',
+    relationType: 'RECOMMEND',
     lessonCoverTemplateUrl: ''
   },
   lessonList: [
@@ -39,6 +40,7 @@ export const createState = reactive({
       videoContent: '',
       videoUrl: '',
       coverUrl: '',
+      relationList: [] as any,
       posterUrl: '' // 视频封面图
     }
   ]

+ 22 - 0
src/teacher/video-class/model/music-album/index.module.less

@@ -0,0 +1,22 @@
+.musicAlbum {
+  background-color: #f8f9fc;
+  min-height: 100vh;
+
+  --van-tab-font-size: 17px;
+}
+
+.musicSong {
+  margin: 16px 14px;
+  border-radius: 10px;
+
+  .musicName {
+    max-width: 180px !important;
+  }
+  .author {
+    max-width: 140px !important;
+  }
+}
+
+.musicGrid {
+  margin: 16px 12px;
+}

+ 207 - 0
src/teacher/video-class/model/music-album/index.tsx

@@ -0,0 +1,207 @@
+import ColResult from '@/components/col-result'
+import ColSearch from '@/components/col-search'
+import request from '@/helpers/request'
+import { state } from '@/state'
+import MusicGrid from '@/views/music/component/music-grid'
+import Song from '@/views/music/component/song'
+import { Cell, List, Sticky, Tab, Tabs } from 'vant'
+import { defineComponent, PropType } from 'vue'
+import styles from './index.module.less'
+
+export default defineComponent({
+  name: 'music-album',
+  props: {
+    subjectId: {
+      type: Number,
+      required: true
+    },
+    onSelect: {
+      type: Function,
+      default: (item: any) => {}
+    }
+  },
+  data() {
+    return {
+      tabVal: 'music',
+      dataShow: true, // 判断是否有数据
+      lockLoading: false,
+      musicState: {
+        loading: false,
+        finished: false
+      },
+      musicList: [] as any,
+      musicParams: {
+        myself: false,
+        auditStatus: 'PASS',
+        page: 1,
+        rows: 20,
+        idAndName: '',
+        subjectIds: this.subjectId
+      },
+      albumState: {
+        loading: false,
+        finished: false
+      },
+      albumList: [] as any,
+      albumParams: {
+        page: 1,
+        rows: 20,
+        idAndName: '',
+        subjectIds: this.subjectId
+      }
+    }
+  },
+  async mounted() {
+    await this.getMusicList()
+  },
+  methods: {
+    onSearch(value: string) {
+      this.musicParams.idAndName = value
+      this.albumParams.idAndName = value
+      if (this.tabVal === 'music') {
+        this.musicParams.page = 1
+        this.musicList = []
+        this.getMusicList()
+      } else if (this.tabVal === 'album') {
+        this.albumParams.page = 1
+        this.albumList = []
+        this.getAlbumList()
+      }
+    },
+    async getMusicList() {
+      try {
+        if (this.lockLoading) return
+        this.lockLoading = true
+        this.dataShow = true
+        const res = await request.post(
+          `${state.platformApi}/music/sheet/list`,
+          {
+            data: {
+              ...this.musicParams
+            }
+          }
+        )
+        this.lockLoading = false
+        this.musicState.loading = false
+        const result = res.data || {}
+        this.musicList = this.musicList.concat(result.rows || [])
+        this.musicState.finished = result.pageNo >= result.totalPage
+        this.musicParams.page = result.pageNo + 1
+        this.dataShow = this.musicList.length > 0
+      } catch {
+        this.dataShow = false
+        this.musicState.finished = true
+        this.lockLoading = false
+      }
+    },
+    async getAlbumList() {
+      try {
+        if (this.lockLoading) return
+        this.lockLoading = true
+        this.dataShow = true
+        const res = await request.post(
+          `${state.platformApi}/music/album/list`,
+          {
+            data: {
+              ...this.albumParams
+            }
+          }
+        )
+        this.lockLoading = false
+        this.albumState.loading = false
+        const result = res.data || {}
+        this.albumList = this.albumList.concat(result.rows || [])
+        this.albumState.finished = result.pageNo >= result.totalPage
+        this.albumParams.page = result.pageNo + 1
+        this.dataShow = this.albumList.length > 0
+      } catch {
+        this.dataShow = false
+        this.albumState.finished = true
+        this.lockLoading = false
+      }
+    }
+  },
+  render() {
+    return (
+      <div class={styles.musicAlbum}>
+        <Sticky position="top" offsetTop={0}>
+          <ColSearch
+            onSearch={this.onSearch}
+            placeholder="请输入曲目或专辑名称"
+          />
+          <Tabs
+            v-model:active={this.tabVal}
+            color="var(--van-primary)"
+            lineWidth={25}
+            onChange={index => {
+              if (index === 'music') {
+                this.musicParams.page = 1
+                this.musicList = []
+                this.getMusicList()
+              } else if (index === 'album') {
+                this.albumParams.page = 1
+                this.albumList = []
+                this.getAlbumList()
+              }
+            }}
+          >
+            <Tab title="曲目" name="music"></Tab>
+            <Tab title="专辑" name="album"></Tab>
+          </Tabs>
+        </Sticky>
+        <div class={styles.container}>
+          {this.dataShow && this.tabVal === 'music' && (
+            <List
+              v-model:loading={this.musicState.loading}
+              finished={this.musicState.finished}
+              finishedText=" "
+              onLoad={this.getMusicList}
+              immediateCheck={false}
+            >
+              <div class={styles.musicSong}>
+                <Song
+                  list={this.musicList}
+                  musicNameClass={styles.musicName}
+                  authorClass={styles.author}
+                  showPlay={false}
+                  onDetail={(item: any) => {
+                    this.onSelect({
+                      selectType: 'MUSIC',
+                      ...item
+                    })
+                  }}
+                ></Song>
+              </div>
+            </List>
+          )}
+
+          {this.dataShow && this.tabVal === 'album' && (
+            <List
+              v-model:loading={this.albumState.loading}
+              finished={this.albumState.finished}
+              finishedText=" "
+              onLoad={this.getAlbumList}
+              immediateCheck={false}
+            >
+              <div class={styles.musicGrid}>
+                <MusicGrid
+                  list={this.albumList}
+                  onGoto={(n: any) => {
+                    this.onSelect({
+                      selectType: 'ALBUM',
+                      ...n
+                    })
+                  }}
+                />
+              </div>
+            </List>
+          )}
+
+          {!this.dataShow && (
+            <ColResult btnStatus={false} classImgSize="SMALL" tips="暂无数据" />
+          )}
+        </div>
+      </div>
+    )
+  }
+})

+ 49 - 15
src/teacher/video-class/video-class-detail.tsx

@@ -34,6 +34,8 @@ export default defineComponent({
       tabIndex: 1,
       title: '',
       lessonPrice: 0,
+      useRelationType: '',
+      alreadyBuy: false,
       currentClassIndex: 1,
       detailList: [],
       posterUrl: '',
@@ -78,7 +80,9 @@ export default defineComponent({
       )
       const result = res.data || {}
       this.title = result.lessonGroup.lessonName
+      this.useRelationType = result.lessonGroup.relationType
       this.lessonPrice = result.lessonGroup.lessonPrice
+      this.alreadyBuy = result.alreadyBuy
       this.detailList = result.detailList || []
 
       if (state.user.data?.userId !== result.lessonGroup.teacherId) {
@@ -237,21 +241,51 @@ export default defineComponent({
           <Tab title="目录" name={1}>
             <div style={{ height: 'calc(100vh - 320px)', overflowY: 'auto' }}>
               <SectionDetail title="课程列表" icon="courseList">
-                {this.detailList.map((item: any, index: number) => (
-                  <CourseVideoItem
-                    class={'mb12'}
-                    playId={Number(this.classId)}
-                    detail={{
-                      id: item.id,
-                      title: item.videoTitle,
-                      content: item.videoContent,
-                      imgUrl: item.coverUrl,
-                      videoUrl: item.videoUrl,
-                      index: index + 1
-                    }}
-                    onPlay={this.onPlay}
-                  />
-                ))}
+                {this.detailList.map((item: any, index: number) => {
+                  const musicAlbumInfos = item.musicAlbumInfos || []
+                  const temp = musicAlbumInfos.map((info: any) => {
+                    return {
+                      relationMusicAlbum: info.relationType,
+                      musicAlbumName: info.name,
+                      musicAlbumId: info.musicAlbumId,
+                      status: info.status,
+                      useRelationType: this.useRelationType
+                    }
+                  })
+                  return (
+                    <CourseVideoItem
+                      musicAlbumInfos={temp}
+                      playId={Number(this.classId)}
+                      detail={{
+                        id: item.id,
+                        title: item.videoTitle,
+                        content: item.videoContent,
+                        imgUrl: item.coverUrl,
+                        videoUrl: item.videoUrl,
+                        index: index + 1
+                      }}
+                      onPlay={this.onPlay}
+                      onMusicAlbumDetail={(item: any) => {
+                        if (!this.alreadyBuy && !item.status) {
+                          Toast('数据正在更新,请稍后再试')
+                          return
+                        }
+                        if (item.relationMusicAlbum === 'MUSIC') {
+                          this.$router.push({
+                            path: '/music-detail',
+                            query: {
+                              id: item.musicAlbumId
+                            }
+                          })
+                        } else if (item.relationMusicAlbum === 'ALBUM') {
+                          this.$router.push({
+                            path: '/music-album-detail/' + item.musicAlbumId
+                          })
+                        }
+                      }}
+                    />
+                  )
+                })}
               </SectionDetail>
             </div>
           </Tab>

+ 89 - 26
src/teacher/video-class/video-detail.tsx

@@ -19,6 +19,7 @@ export default defineComponent({
     return {
       userInfo: {} as any,
       detailList: [],
+      musicAlbumInfos: [], // 关联曲目或专辑"
       buyUserList: [], // 购买学生数
       dataShow: true, // 判断是否有数据
       loading: false,
@@ -60,10 +61,12 @@ export default defineComponent({
         lessonDesc: result.lessonGroup.lessonDesc,
         lessonPrice: result.lessonGroup.lessonPrice,
         lessonCoverUrl: result.lessonGroup.lessonCoverUrl,
+        relationType: result.lessonGroup.relationType,
         lessonSubjectName: result.lessonGroup.lessonSubjectName,
         auditVersion: result.lessonGroup.auditVersion,
         isDegree: result.degreeFlag ? true : false,
-        isTeacher: result.teacherFlag ? true : false
+        isTeacher: result.teacherFlag ? true : false,
+        alreadyBuy: result.alreadyBuy
       }
 
       this.shelvesFlag = result.lessonGroup.shelvesFlag
@@ -72,7 +75,7 @@ export default defineComponent({
       // shareVideo?recomUserId=56&groupId=124
       this.shareUrl = `${location.origin}/teacher#/shareVideo?recomUserId=${state.user.data?.userId}&groupId=${this.params.videoLessonGroupId}`
 
-      this.getList()
+      !this.myself && this.getList()
     } catch (e) {
       console.log(e)
     }
@@ -145,18 +148,48 @@ export default defineComponent({
 
         {this.myself ? (
           <SectionDetail title="课程列表" icon="courseList" border={true}>
-            {this.detailList.map((item: any) => (
-              <CourseVideoItem
-                class={'mb12'}
-                detail={{
-                  id: item.id,
-                  title: item.videoTitle,
-                  content: item.videoContent,
-                  imgUrl: item.coverUrl
-                }}
-                onPlay={this.onPlay}
-              />
-            ))}
+            {this.detailList.map((item: any) => {
+              const musicAlbumInfos = item.musicAlbumInfos || []
+              const temp = musicAlbumInfos.map((info: any) => {
+                return {
+                  relationMusicAlbum: info.relationType,
+                  musicAlbumName: info.name,
+                  musicAlbumId: info.musicAlbumId,
+                  status: info.status,
+                  useRelationType: this.userInfo.relationType
+                }
+              })
+              return (
+                <CourseVideoItem
+                  musicAlbumInfos={temp}
+                  detail={{
+                    id: item.id,
+                    title: item.videoTitle,
+                    content: item.videoContent,
+                    imgUrl: item.coverUrl
+                  }}
+                  onPlay={this.onPlay}
+                  onMusicAlbumDetail={(item: any) => {
+                    if (!this.userInfo.alreadyBuy && !item.status) {
+                      Toast('数据正在更新,请稍后再试')
+                      return
+                    }
+                    if (item.relationMusicAlbum === 'MUSIC') {
+                      this.$router.push({
+                        path: '/music-detail',
+                        query: {
+                          id: item.musicAlbumId
+                        }
+                      })
+                    } else if (item.relationMusicAlbum === 'ALBUM') {
+                      this.$router.push({
+                        path: '/music-album-detail/' + item.musicAlbumId
+                      })
+                    }
+                  }}
+                />
+              )
+            })}
           </SectionDetail>
         ) : (
           <SectionDetail
@@ -167,18 +200,48 @@ export default defineComponent({
           >
             <Tabs color="var(--van-primary)" lineWidth={20} sticky>
               <Tab title="课程" titleClass="van-hairline--bottom">
-                {this.detailList.map((item: any) => (
-                  <CourseVideoItem
-                    class={'mb12'}
-                    detail={{
-                      id: item.id,
-                      title: item.videoTitle,
-                      content: item.videoContent,
-                      imgUrl: item.coverUrl
-                    }}
-                    onPlay={this.onPlay}
-                  />
-                ))}
+                {this.detailList.map((item: any) => {
+                  const musicAlbumInfos = item.musicAlbumInfos || []
+                  const temp = musicAlbumInfos.map((info: any) => {
+                    return {
+                      relationMusicAlbum: info.relationType,
+                      musicAlbumName: info.name,
+                      musicAlbumId: info.musicAlbumId,
+                      status: info.status,
+                      useRelationType: this.userInfo.relationType
+                    }
+                  })
+                  return (
+                    <CourseVideoItem
+                      musicAlbumInfos={temp}
+                      detail={{
+                        id: item.id,
+                        title: item.videoTitle,
+                        content: item.videoContent,
+                        imgUrl: item.coverUrl
+                      }}
+                      onPlay={this.onPlay}
+                      onMusicAlbumDetail={(item: any) => {
+                        if (!this.userInfo.alreadyBuy && !item.status) {
+                          Toast('数据正在更新,请稍后再试')
+                          return
+                        }
+                        if (item.relationMusicAlbum === 'MUSIC') {
+                          this.$router.push({
+                            path: '/music-detail',
+                            query: {
+                              id: item.musicAlbumId
+                            }
+                          })
+                        } else if (item.relationMusicAlbum === 'ALBUM') {
+                          this.$router.push({
+                            path: '/music-album-detail/' + item.musicAlbumId
+                          })
+                        }
+                      }}
+                    />
+                  )
+                })}
               </Tab>
               <Tab title="学员列表" titleClass="van-hairline--bottom">
                 {this.dataShow ? (

+ 16 - 7
src/views/music/album-detail/index.tsx

@@ -20,7 +20,7 @@ import styles from './index.module.less'
 import { useRect } from '@vant/use'
 import { useEventListener, useWindowScroll } from '@vueuse/core'
 import { getRandomKey, musicBuy } from '../music'
-import { state } from '@/state'
+import { openDefaultWebView, state } from '@/state'
 import IconPan from './pan.png'
 import oStart from './oStart.png'
 import iStart from './iStart.png'
@@ -344,12 +344,21 @@ export default defineComponent({
                 list={rows.value}
                 onDetail={(item: any) => {
                   if (onItemClick === noop || !onItemClick) {
-                    router.push({
-                      path: '/music-detail',
-                      query: {
-                        id: item.id,
-                        albumId: route.params.id
-                      }
+                    const url =
+                      location.origin +
+                      location.pathname +
+                      '#/music-detail?id=' +
+                      item.id +
+                      '&albumId=' +
+                      route.params.id
+                    openDefaultWebView(url, () => {
+                      router.push({
+                        path: '/music-detail',
+                        query: {
+                          id: item.id,
+                          albumId: route.params.id
+                        }
+                      })
                     })
                   } else {
                     onItemClick(item)

BIN
src/views/music/component/images/icon_music_active.png


+ 5 - 1
src/views/music/component/music-grid/index.tsx

@@ -6,6 +6,10 @@ import IconXin from '../images/icon-xin.png'
 export default defineComponent({
   name: 'TheMusicGrid',
   props: {
+    isHiddenTag: {
+      type: Boolean,
+      default: false
+    },
     list: {
       type: Array as any,
       default: () => []
@@ -20,7 +24,7 @@ export default defineComponent({
             <GridItem>
               <div class={styles.item} onClick={() => emit('goto', n)}>
                 <div class={styles.imgWrap}>
-                  {n.paymentType === 'CHARGE' && (
+                  {n.paymentType === 'CHARGE' && !props.isHiddenTag && (
                     <span class={styles.albumType}>付费</span>
                   )}
                   <Image

+ 13 - 3
src/views/music/component/song/index.tsx

@@ -23,6 +23,12 @@ export default defineComponent({
     showPlay: {
       type: Boolean,
       default: true
+    },
+    musicNameClass: {
+      type: String as PropType<unknown>
+    },
+    authorClass: {
+      type: String as PropType<unknown>
     }
   },
   emits: ['detail'],
@@ -74,10 +80,14 @@ export default defineComponent({
                     />
                   )}
 
-                  <span class={[styles.title, 'van-ellipsis']}>
+                  <span
+                    class={[styles.title, props.musicNameClass, 'van-ellipsis']}
+                  >
                     {n.musicSheetName}
                   </span>
-                  <span class={[styles.singer, 'van-ellipsis']}>
+                  <span
+                    class={[styles.singer, props.authorClass, 'van-ellipsis']}
+                  >
                     -{n.composer}
                   </span>
                 </div>
@@ -88,7 +98,7 @@ export default defineComponent({
                       class={styles.collection}
                     />
                   )}
-                  <span class={styles.name}>
+                  <span class={[styles.name]}>
                     {n.addName ? `上传者:${n.addName}` : `作曲:${n.composer}`}
                   </span>
                   <div class={styles.tags}>

+ 13 - 6
src/views/music/list/index.tsx

@@ -8,7 +8,7 @@ import { useRoute, useRouter } from 'vue-router'
 import ColResult from '@/components/col-result'
 import styles from './index.module.less'
 import { getRandomKey } from '../music'
-import { state as baseState } from '@/state'
+import { openDefaultWebView, state as baseState } from '@/state'
 import SelectSubject from '../search/select-subject'
 import { SubjectEnum, useSubjectId } from '@/helpers/hooks'
 import Song from '../component/song'
@@ -307,11 +307,18 @@ export default defineComponent({
                   list={data.value.rows}
                   onDetail={(item: any) => {
                     if (onItemClick === noop) {
-                      router.push({
-                        path: '/music-detail',
-                        query: {
-                          id: item.id
-                        }
+                      const url =
+                        location.origin +
+                        location.pathname +
+                        '#/music-detail?id=' +
+                        item.id
+                      openDefaultWebView(url, () => {
+                        router.push({
+                          path: '/music-detail',
+                          query: {
+                            id: item.id
+                          }
+                        })
                       })
                     } else {
                       onItemClick?.(item)

+ 13 - 6
src/views/music/list/list.tsx

@@ -1,7 +1,7 @@
 import ColResult from '@/components/col-result'
 import { SubjectEnum, useSubjectId } from '@/helpers/hooks'
 import request from '@/helpers/request'
-import { state } from '@/state'
+import { openDefaultWebView, state } from '@/state'
 import { List } from 'vant'
 import { defineComponent, reactive, ref } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
@@ -107,11 +107,18 @@ export default defineComponent({
               list={data.value.rows}
               onDetail={(item: any) => {
                 if (onItemClick === noop) {
-                  router.push({
-                    path: '/music-detail',
-                    query: {
-                      id: item.id
-                    }
+                  const url =
+                    location.origin +
+                    location.pathname +
+                    '#/music-detail?id=' +
+                    item.id
+                  openDefaultWebView(url, () => {
+                    router.push({
+                      path: '/music-detail',
+                      query: {
+                        id: item.id
+                      }
+                    })
                   })
                 } else {
                   onItemClick?.(item)

+ 4 - 2
src/views/music/look-album-list/index.tsx

@@ -7,7 +7,8 @@ export default defineComponent({
   data() {
     const query = this.$route.query
     return {
-      id: query.id
+      id: query.id,
+      musicSubject: query.musicSubject
     }
   },
   render() {
@@ -16,7 +17,8 @@ export default defineComponent({
         <Album
           hideSearch={true}
           defauleParams={{
-            musicId: this.id
+            musicId: this.id,
+            subjectIds: this.musicSubject
           }}
         />
       </>

+ 36 - 16
src/views/music/music-detail/index.tsx

@@ -27,10 +27,10 @@ import styles from './index.module.less'
 import { useRect } from '@vant/use'
 import { Vue3Lottie } from 'vue3-lottie'
 import { getRandomKey, musicBuy } from '../music'
-import { state } from '@/state'
+import { getOssUploadUrl, state } from '@/state'
 import { useEventTracking } from '@/helpers/hooks'
 import ColSticky from '@/components/col-sticky'
-import { moneyFormat } from '@/helpers/utils'
+import { browser, moneyFormat } from '@/helpers/utils'
 import { orderStatus } from '@/views/order-detail/orderStatus'
 import iconShare from '@/views/music/album/icon_share.svg'
 import iconAlbum from '@/views/music/component/images/icon_album.png'
@@ -70,6 +70,7 @@ export default defineComponent({
     const footers = ref(null)
     const heightInfo = ref<any>('0')
     const musicDetail = ref<any>(null)
+    const audioFileUrl = ref('')
     const showImg = ref<string>('')
     const accompanyUrl = ref<string>('')
 
@@ -100,6 +101,12 @@ export default defineComponent({
             state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student'
         })
         musicDetail.value = res.data
+
+        // 取原音,如果有多个则默认第一个
+        const background = res.data.background
+        audioFileUrl.value =
+          background && background.length > 0 ? background[0].audioFileUrl : ''
+
         showImg.value = res.data.musicImg || ''
 
         if (!showImg.value) {
@@ -138,9 +145,7 @@ export default defineComponent({
       try {
         const formData = new FormData()
         const fileName =
-          new Date().getTime() +
-          musicDetail.value?.musicSheetName.replace(/ /gi, '_') +
-          '.png'
+          new Date().getTime() + Math.ceil(Math.random() * 1000) + '.png'
         const keyTime = new Date().getTime() + fileName
         const obj = {
           filename: fileName,
@@ -178,13 +183,13 @@ export default defineComponent({
         const files = base64ToBlob(file)
 
         formData.append('file', files, fileName)
-        const ossUploadUrl = 'https://ks3-cn-beijing.ksyuncs.com/cloud-coach'
+        const ossUploadUrl = getOssUploadUrl('cloud-coach')
         await umiRequest(ossUploadUrl, {
           method: 'POST',
           data: formData
         })
         Toast.clear()
-        const imgurl = ossUploadUrl + '/' + keyTime
+        const imgurl = getOssUploadUrl('cloud-coach') + keyTime
 
         await request.post(state.platformApi + '/open/music/sheet/img', {
           data: { musicSheetId: musicDetail.value.id, musicImg: imgurl }
@@ -257,7 +262,7 @@ export default defineComponent({
       heightInfo.value = height + footer.height
 
       // 初始化音频
-      if (musicDetail.value?.audioFileUrl) {
+      if (audioFileUrl.value) {
         initAudio()
       }
     })
@@ -542,7 +547,7 @@ export default defineComponent({
               <iframe
                 id="containerPrint"
                 ref="print"
-                style="width: 100%;page-break-after:always; height: 0"
+                style="width: 540px;page-break-after:always; height: 0;"
                 src={accompanyUrl.value}
               />
               <p class={styles.musicTitle}>
@@ -561,7 +566,7 @@ export default defineComponent({
               )}
 
               <div class={styles.videoOperation}>
-                {musicDetail.value?.audioFileUrl && (
+                {audioFileUrl.value && (
                   <>
                     {!buyState.value.play && (
                       <div class={[styles.audition]}>
@@ -572,17 +577,31 @@ export default defineComponent({
 
                     <div class={[styles.audio, styles.collectCell]}>
                       <audio id="player" controls ref={audio}>
-                        <source
-                          src={musicDetail.value?.audioFileUrl}
-                          type="audio/mp3"
-                        />
+                        <source src={audioFileUrl.value} type="audio/mp3" />
                       </audio>
                     </div>
                   </>
                 )}
 
                 <div class={[styles.collect, styles.collectCell]}>
-                  <div class={[styles.userInfo]}>
+                  <div
+                    class={[styles.userInfo]}
+                    onClick={() => {
+                      if (
+                        browser().isApp &&
+                        musicDetail.value?.sourceType === 'TEACHER' &&
+                        state.platformType === 'STUDENT'
+                      ) {
+                        router.push({
+                          path: '/teacherHome',
+                          query: {
+                            teacherId: musicDetail.value?.userId,
+                            tabs: 'music'
+                          }
+                        })
+                      }
+                    }}
+                  >
                     <img src={musicDetail.value?.userAvatar || iconTeacher} />
                     <span>{musicDetail.value?.userName}</span>
                   </div>
@@ -610,7 +629,8 @@ export default defineComponent({
                 router.push({
                   path: '/look-album-list',
                   query: {
-                    id: musicDetail.value?.id
+                    id: musicDetail.value?.id,
+                    musicSubject: musicDetail.value?.musicSubject
                   }
                 })
               }}

+ 0 - 28
src/views/music/music.ts

@@ -34,32 +34,4 @@ export const musicBuy = (item: any, callBack?: any, moreQuery = {}) => {
       isOpenLight: true
     }
   })
-  return
-  // play :0 不能看,1 能看
-  const path =
-    !item.play && item.chargeType === 'VIP' ? '/memberCenter' : '/orderDetail'
-  if (!item.play && item.chargeType === 'VIP') {
-    Dialog.confirm({
-      title: '提示',
-      message: '您还不是会员,是否加入会员?',
-      confirmButtonColor: 'var(--van-primary)'
-    }).then(() => {
-      callBack && callBack(path)
-    })
-    return
-  } else if (!item.play && item.chargeType === 'CHARGE') {
-    orderStatus.orderObject.orderType = 'MUSIC'
-    orderStatus.orderObject.orderName = item.musicSheetName
-    orderStatus.orderObject.orderDesc = item.musicSheetName
-    orderStatus.orderObject.actualPrice = item.musicPrice
-    orderStatus.orderObject.orderList = [
-      {
-        orderType: 'MUSIC',
-        goodsName: item.musicSheetName,
-        actualPrice: item.musicPrice,
-        ...item
-      }
-    ]
-    callBack && callBack(path)
-  }
 }

+ 23 - 3
src/views/music/personal/album-my.tsx

@@ -1,4 +1,4 @@
-import { defineComponent, reactive, ref } from 'vue'
+import { defineComponent, reactive, ref, watch } from 'vue'
 import { List } from 'vant'
 import request from '@/helpers/request'
 import Item from '../album/item'
@@ -10,11 +10,18 @@ import styles from './index.module.less'
 
 export default defineComponent({
   name: 'MusicList',
-  setup() {
+  props: {
+    gift: {
+      type: Number,
+      default: 0
+    }
+  },
+  setup(props) {
     const route = useRoute()
     const router = useRouter()
     const params = reactive({
-      page: 1
+      page: 1,
+      gift: props.gift
     })
     const rows = ref<any>([])
     const data = ref<any>(null)
@@ -44,6 +51,18 @@ export default defineComponent({
       loading.value = false
     }
 
+    watch(
+      () => props.gift,
+      gift => {
+        isError.value = false
+        rows.value = []
+        params.page = 1
+        finished.value = false
+        params.gift = gift
+        FetchList()
+      }
+    )
+
     return () => (
       <List
         loading={loading.value}
@@ -55,6 +74,7 @@ export default defineComponent({
         {rows.value.length ? (
           <div class={styles.musicGrid}>
             <MusicGrid
+              isHiddenTag
               list={data.value.rows}
               onGoto={(n: any) => {
                 router.push({

+ 13 - 6
src/views/music/personal/collection.tsx

@@ -3,7 +3,7 @@ import { List } from 'vant'
 import request from '@/helpers/request'
 import { useRoute, useRouter } from 'vue-router'
 import ColResult from '@/components/col-result'
-import { state } from '@/state'
+import { openDefaultWebView, state } from '@/state'
 import styles from './index.module.less'
 import Song from '../component/song'
 
@@ -72,11 +72,18 @@ export default defineComponent({
             <Song
               list={rows.value}
               onDetail={(item: any) => {
-                router.push({
-                  path: '/music-detail',
-                  query: {
-                    id: item.id
-                  }
+                const url =
+                  location.origin +
+                  location.pathname +
+                  '#/music-detail?id=' +
+                  item.id
+                openDefaultWebView(url, () => {
+                  router.push({
+                    path: '/music-detail',
+                    query: {
+                      id: item.id
+                    }
+                  })
                 })
               }}
             />

+ 9 - 2
src/views/music/personal/index.tsx

@@ -47,16 +47,23 @@ export default defineComponent({
             <Tab title="我的专辑" name="personal-album"></Tab>
             <Tab title="收藏单曲" name="collection"></Tab>
             <Tab title="收藏专辑" name="album"></Tab>
+            <Tab title="赠送单曲" name="personal-gift"></Tab>
+            <Tab title="赠送专辑" name="album-gift"></Tab>
           </Tabs>
-          {activeTab.value === 'personal' && (
+          {(activeTab.value === 'personal' ||
+            activeTab.value === 'personal-gift') && (
             <Personal
               ref={personal}
+              gift={activeTab.value === 'personal-gift' ? 1 : 0}
               onFavorite={() => {
                 practice.value?.reload?.()
               }}
             />
           )}
-          {activeTab.value === 'personal-album' && <AlbumMy />}
+          {(activeTab.value === 'personal-album' ||
+            activeTab.value === 'album-gift') && (
+            <AlbumMy gift={activeTab.value === 'album-gift' ? 1 : 0} />
+          )}
           {activeTab.value === 'collection' && (
             <Collection
               ref={collection}

+ 33 - 7
src/views/music/personal/personal.tsx

@@ -1,21 +1,29 @@
-import { defineComponent, reactive, ref } from 'vue'
+import { defineComponent, reactive, ref, watch } from 'vue'
 import { List } from 'vant'
 import request from '@/helpers/request'
 import { useRoute, useRouter } from 'vue-router'
 import ColResult from '@/components/col-result'
-import { state } from '@/state'
+import { openDefaultWebView, state } from '@/state'
 import styles from './index.module.less'
 import Song from '../component/song'
+import { number } from 'echarts/core'
 
 export default defineComponent({
   name: 'MusicList',
   emits: ['favorite'],
+  props: {
+    gift: {
+      type: Number,
+      default: 0
+    }
+  },
   setup(props, { expose, emit }) {
     const route = useRoute()
     const router = useRouter()
     const params = reactive({
       search: (route.query.search as string) || '',
       musicTagIds: route.query.tagids || '',
+      gift: props.gift,
       page: 1
     })
     const data = ref<any>(null)
@@ -48,6 +56,17 @@ export default defineComponent({
       loading.value = false
     }
 
+    watch(
+      () => props.gift,
+      gift => {
+        isError.value = false
+        rows.value = []
+        params.page = 1
+        finished.value = false
+        params.gift = gift
+        FetchList()
+      }
+    )
     expose({
       reset: () => {
         isError.value = false
@@ -72,11 +91,18 @@ export default defineComponent({
             <Song
               list={rows.value}
               onDetail={(item: any) => {
-                router.push({
-                  path: '/music-detail',
-                  query: {
-                    id: item.id
-                  }
+                const url =
+                  location.origin +
+                  location.pathname +
+                  '#/music-detail?id=' +
+                  item.id
+                openDefaultWebView(url, () => {
+                  router.push({
+                    path: '/music-detail',
+                    query: {
+                      id: item.id
+                    }
+                  })
                 })
               }}
             />

+ 13 - 6
src/views/music/personal/practice.tsx

@@ -3,7 +3,7 @@ import { useAsyncState } from '@vueuse/core'
 import { defineComponent, ref } from 'vue'
 import { Cell, Skeleton } from 'vant'
 import Item from '../list/item'
-import { state } from '@/state'
+import { openDefaultWebView, state } from '@/state'
 import styles from './index.module.less'
 import Song from '../component/song'
 import { useRouter } from 'vue-router'
@@ -47,11 +47,18 @@ export default defineComponent({
             <Song
               list={list}
               onDetail={(item: any) => {
-                router.push({
-                  path: '/music-detail',
-                  query: {
-                    id: item.id
-                  }
+                const url =
+                  location.origin +
+                  location.pathname +
+                  '#/music-detail?id=' +
+                  item.id
+                openDefaultWebView(url, () => {
+                  router.push({
+                    path: '/music-detail',
+                    query: {
+                      id: item.id
+                    }
+                  })
                 })
               }}
             />

+ 13 - 6
src/views/music/songbook/list.tsx

@@ -9,7 +9,7 @@ import ColResult from '@/components/col-result'
 // import { state as tempState } from '@/state'
 import { SubjectEnum, useSubjectId } from '@/helpers/hooks'
 import Song from '../component/song'
-import { state } from '@/state'
+import { openDefaultWebView, state } from '@/state'
 
 export default defineComponent({
   name: 'Songbook',
@@ -101,11 +101,18 @@ export default defineComponent({
               <Song
                 list={data.value.rows}
                 onDetail={(item: any) => {
-                  router.push({
-                    path: '/music-detail',
-                    query: {
-                      id: item.id
-                    }
+                  const url =
+                    location.origin +
+                    location.pathname +
+                    '#/music-detail?id=' +
+                    item.id
+                  openDefaultWebView(url, () => {
+                    router.push({
+                      path: '/music-detail',
+                      query: {
+                        id: item.id
+                      }
+                    })
                   })
                 }}
               />

+ 31 - 1
src/views/order-detail/order-video/index.module.less

@@ -11,10 +11,14 @@
     vertical-align: middle;
   }
   .title {
-    font-size: 16px;
+    font-size: 14px;
     font-weight: 500;
     color: #333333;
   }
+  .titleSong {
+    font-size: 14px;
+    color: #ff802c;
+  }
 
   .teacher {
     margin-left: 5px;
@@ -51,6 +55,16 @@
       color: var(--van-primary);
     }
   }
+
+  .line {
+    margin-right: 6px;
+    display: inline-block;
+    width: 4px;
+    height: 14px;
+    background: #2dc7aa;
+    border-radius: 2px;
+    vertical-align: middle;
+  }
   :global {
     .van-cell-group {
       margin-bottom: 10px;
@@ -58,4 +72,20 @@
       overflow: hidden;
     }
   }
+
+  .img {
+    width: 56px;
+    height: 56px;
+    border-radius: 8px;
+    overflow: hidden;
+    margin-right: 12px;
+  }
+  .titleClass {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+  }
+  .labelClass {
+    max-width: 200px;
+  }
 }

+ 101 - 0
src/views/order-detail/order-video/index.tsx

@@ -15,8 +15,44 @@ export default defineComponent({
       default: {}
     }
   },
+  computed: {
+    album() {
+      const courseInfo = this.item.courseInfo || []
+      const albumList = [] as any
+      courseInfo.map((course: any) => {
+        course.musicAlbumInfos &&
+          course.musicAlbumInfos.map((info: any) => {
+            if (info.relationType === 'ALBUM') {
+              const index = albumList.findIndex(
+                (album: any) => album.musicAlbumId === info.musicAlbumId
+              )
+              index === -1 && albumList.push(info)
+            }
+          })
+      })
+
+      return this.item.relationType === 'GIFT' ? [...albumList] : []
+    },
+    music() {
+      const courseInfo = this.item.courseInfo || []
+      const albumList = [] as any
+      courseInfo.map((course: any) => {
+        course.musicAlbumInfos &&
+          course.musicAlbumInfos.map((info: any) => {
+            if (info.relationType === 'MUSIC') {
+              const index = albumList.findIndex(
+                (album: any) => album.musicAlbumId === info.musicAlbumId
+              )
+              index === -1 && albumList.push(info)
+            }
+          })
+      })
+      return this.item.relationType === 'GIFT' ? [...albumList] : []
+    }
+  },
   render() {
     const item = this.item
+    console.log(item)
     return (
       <div class={styles.videoOrder}>
         <CellGroup border={false}>
@@ -51,6 +87,71 @@ export default defineComponent({
             }}
           />
         </CellGroup>
+
+        {this.album.length > 0 && (
+          <CellGroup border={false}>
+            <Cell
+              center
+              v-slots={{
+                title: () => (
+                  <div
+                    class={[styles.title, 'van-ellipsis']}
+                    style={{ display: 'flex', alignItems: 'center' }}
+                  >
+                    <span class={styles.line}></span>
+                    附带专辑
+                  </div>
+                ),
+                value: () => <span class={styles.titleSong}>· 赠送</span>
+              }}
+            />
+
+            {this.album.map((album: any) => (
+              <Cell
+                center
+                v-slots={{
+                  icon: () => <Image src={album.cover} class={styles.img} />
+                }}
+                title={album.name}
+                titleClass={styles.titleClass}
+                label={album.remark || ''}
+                labelClass={[styles.labelClass, 'van-ellipsis']}
+              />
+            ))}
+          </CellGroup>
+        )}
+        {this.music.length > 0 && (
+          <CellGroup border={false}>
+            <Cell
+              center
+              v-slots={{
+                title: () => (
+                  <div
+                    class={[styles.title, 'van-ellipsis']}
+                    style={{ display: 'flex', alignItems: 'center' }}
+                  >
+                    <span class={styles.line}></span>
+                    附带乐谱
+                  </div>
+                ),
+                value: () => <span class={styles.titleSong}>· 赠送</span>
+              }}
+            />
+
+            {this.music.map((album: any) => (
+              <Cell
+                center
+                v-slots={{
+                  icon: () => <Image src={album.cover} class={styles.img} />
+                }}
+                title={album.name}
+                titleClass={styles.titleClass}
+                label={'作者:' + (album.remark || '')}
+                labelClass={[styles.labelClass, 'van-ellipsis']}
+              />
+            ))}
+          </CellGroup>
+        )}
       </div>
     )
   }

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