lex il y a 2 ans
Parent
commit
07c1102271
33 fichiers modifiés avec 1291 ajouts et 269 suppressions
  1. 33 0
      package-lock.json
  2. 1 0
      package.json
  3. 11 0
      src/components/col-search/index.module.less
  4. 6 2
      src/components/col-search/index.tsx
  5. 7 0
      src/router/routes-common.ts
  6. 7 7
      src/router/routes-teacher.ts
  7. 1 1
      src/student/layout/auth.module.less
  8. 3 0
      src/student/teacher-dependent/model/teacher-header.module.less
  9. 58 58
      src/student/teacher-dependent/teacher-follow.tsx
  10. 18 6
      src/views/music/album-detail/index.tsx
  11. 1 1
      src/views/music/album/icon_share.svg
  12. 43 0
      src/views/music/album/index.module.less
  13. 66 26
      src/views/music/album/index.tsx
  14. 3 3
      src/views/music/component/music-grid/index.module.less
  15. 1 1
      src/views/music/component/music-grid/index.tsx
  16. 3 3
      src/views/music/component/song/index.module.less
  17. 6 41
      src/views/music/component/song/index.tsx
  18. BIN
      src/views/music/list/icons/bgImg.png
  19. BIN
      src/views/music/list/icons/icon_search.png
  20. 79 2
      src/views/music/list/index.module.less
  21. 154 99
      src/views/music/list/index.tsx
  22. 0 0
      src/views/music/music-detail/animate/bigLoad.json
  23. 0 0
      src/views/music/music-detail/animate/kulexiuyunjiaolian.json
  24. BIN
      src/views/music/music-detail/images/icon_collect.png
  25. BIN
      src/views/music/music-detail/images/icon_collect_active.png
  26. BIN
      src/views/music/music-detail/images/icon_download.png
  27. 307 0
      src/views/music/music-detail/index.module.less
  28. 417 0
      src/views/music/music-detail/index.tsx
  29. 22 9
      src/views/music/personal/album-my.tsx
  30. 26 9
      src/views/music/personal/album.tsx
  31. 4 0
      src/views/music/personal/index.module.less
  32. 2 1
      src/views/order-detail/use-coupons/index.tsx
  33. 12 0
      yarn.lock

+ 33 - 0
package-lock.json

@@ -33,6 +33,7 @@
         "vue-cropper": "^1.0.3",
         "vue-echarts": "^6.2.3",
         "vue-router": "^4.0.12",
+        "vue3-lottie": "^2.3.0",
         "vuex": "^4.0.2"
       },
       "devDependencies": {
@@ -6556,6 +6557,11 @@
         "node": ">=8"
       }
     },
+    "node_modules/lottie-web": {
+      "version": "5.9.6",
+      "resolved": "https://registry.npmmirror.com/lottie-web/-/lottie-web-5.9.6.tgz",
+      "integrity": "sha512-JFs7KsHwflugH5qIXBpB4905yC1Sub2MZWtl/elvO/QC6qj1ApqbUZJyjzJseJUtVpgiDaXQLjBlIJGS7UUUXA=="
+    },
     "node_modules/lower-case": {
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/lower-case/-/lower-case-2.0.2.tgz",
@@ -9364,6 +9370,20 @@
         "typescript": "*"
       }
     },
+    "node_modules/vue3-lottie": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmmirror.com/vue3-lottie/-/vue3-lottie-2.3.0.tgz",
+      "integrity": "sha512-pThHpAIxxvk9c5lJXyCgrIAUIy/Xn/XLETqW2yA+VIg5B+phjQkdxkTvRG60pq3zOZ9su2hee+HZgT9tWA+8Fw==",
+      "dependencies": {
+        "lottie-web": "^5.8.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "peerDependencies": {
+        "vue": "^3.2"
+      }
+    },
     "node_modules/vuex": {
       "version": "4.0.2",
       "resolved": "https://registry.npmmirror.com/vuex/-/vuex-4.0.2.tgz",
@@ -14136,6 +14156,11 @@
         }
       }
     },
+    "lottie-web": {
+      "version": "5.9.6",
+      "resolved": "https://registry.npmmirror.com/lottie-web/-/lottie-web-5.9.6.tgz",
+      "integrity": "sha512-JFs7KsHwflugH5qIXBpB4905yC1Sub2MZWtl/elvO/QC6qj1ApqbUZJyjzJseJUtVpgiDaXQLjBlIJGS7UUUXA=="
+    },
     "lower-case": {
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/lower-case/-/lower-case-2.0.2.tgz",
@@ -16062,6 +16087,14 @@
         "vscode-vue-languageservice": "0.29.8"
       }
     },
+    "vue3-lottie": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmmirror.com/vue3-lottie/-/vue3-lottie-2.3.0.tgz",
+      "integrity": "sha512-pThHpAIxxvk9c5lJXyCgrIAUIy/Xn/XLETqW2yA+VIg5B+phjQkdxkTvRG60pq3zOZ9su2hee+HZgT9tWA+8Fw==",
+      "requires": {
+        "lottie-web": "^5.8.1"
+      }
+    },
     "vuex": {
       "version": "4.0.2",
       "resolved": "https://registry.npmmirror.com/vuex/-/vuex-4.0.2.tgz",

+ 1 - 0
package.json

@@ -45,6 +45,7 @@
     "vue-cropper": "^1.0.3",
     "vue-echarts": "^6.2.3",
     "vue-router": "^4.0.12",
+    "vue3-lottie": "^2.3.0",
     "vuex": "^4.0.2"
   },
   "devDependencies": {

+ 11 - 0
src/components/col-search/index.module.less

@@ -47,6 +47,17 @@
     }
   }
 
+  &.transparent {
+    :global {
+      .van-search__content {
+        background: rgba(255, 255, 255, 0.16);
+        input::placeholder {
+          color: #fff;
+        }
+      }
+    }
+  }
+
   .searchBtn {
     width: 56px;
     height: 28px;

+ 6 - 2
src/components/col-search/index.tsx

@@ -4,7 +4,7 @@ import styles from './index.module.less'
 import iconSearch from '@common/images/icon_search.png'
 import iconFilter from '@common/images/icon_filter.png'
 
-type inputBackground = 'default' | 'white'
+type inputBackground = 'default' | 'white' | 'transparent'
 
 export default defineComponent({
   name: 'ColSearch',
@@ -48,6 +48,10 @@ export default defineComponent({
     filterDot: {
       type: Boolean,
       default: false
+    },
+    leftIcon: {
+      type: String,
+      default: iconSearch
     }
   },
   emits: ['click'],
@@ -83,7 +87,7 @@ export default defineComponent({
           onClick={() => this.$emit('click')}
           v-slots={{
             left: () => this.$slots.left && this.$slots.left(),
-            'left-icon': () => <Icon name={iconSearch} size={16} />,
+            'left-icon': () => <Icon name={this.leftIcon} size={16} />,
             'right-icon': () => (
               <Button
                 class={styles.searchBtn}

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

@@ -160,6 +160,13 @@ export const router = [
     }
   },
   {
+    path: '/music-detail',
+    component: () => import('@/views/music/music-detail'),
+    meta: {
+      title: '曲谱详情'
+    }
+  },
+  {
     path: '/music-search',
     component: () => import('@/views/music/search'),
     meta: {

+ 7 - 7
src/router/routes-teacher.ts

@@ -99,13 +99,13 @@ export default [
           title: '修改曲谱'
         }
       },
-      {
-        path: '/music-list',
-        component: () => import('@/teacher/music/list/switch'),
-        meta: {
-          title: '曲谱列表'
-        }
-      },
+      // {
+      //   path: '/music-list',
+      //   component: () => import('@/teacher/music/list/switch'),
+      //   meta: {
+      //     title: '曲谱列表'
+      //   }
+      // },
       {
         path: '/review-list',
         component: () => import('@/teacher/review/list'),

+ 1 - 1
src/student/layout/auth.module.less

@@ -3,7 +3,7 @@
   display: flex;
   // padding-top: 20px;
   flex-direction: column;
-  min-height: calc(100vh - 20px);
+  min-height: calc(100vh);
   align-items: center;
   justify-content: center;
   .info {

+ 3 - 0
src/student/teacher-dependent/model/teacher-header.module.less

@@ -106,6 +106,9 @@
   align-items: center;
   justify-content: space-between;
 }
+.followFans {
+  padding-top: 10px !important;
+}
 
 .teacher-data {
   display: flex;

+ 58 - 58
src/student/teacher-dependent/teacher-follow.tsx

@@ -222,67 +222,12 @@ export default defineComponent({
                         <img src={IconJiaozi} />
                       )}
                     </div>
-                    <div class={styles.teacherHonor}>
-                      <div>勋章:</div>
-                      <div class={styles.teacherIcons}>
-                        <Image
-                          class={styles.iconOther}
-                          src={
-                            this.checkBadge('STYLE', item.teacher)
-                              ? getAssetsHomeFile('cert_active.png')
-                              : getAssetsHomeFile('cert_default.png')
-                          }
-                        />
-                        <Image
-                          class={styles.iconOther}
-                          src={
-                            this.checkBadge('VIDEO', item.teacher)
-                              ? getAssetsHomeFile('video_active.png')
-                              : getAssetsHomeFile('video_default.png')
-                          }
-                        />
-                        <Image
-                          class={styles.iconOther}
-                          src={
-                            this.checkBadge('LIVE', item.teacher)
-                              ? getAssetsHomeFile('live_active.png')
-                              : getAssetsHomeFile('live_default.png')
-                          }
-                        />
-                        <Image
-                          class={styles.iconOther}
-                          src={
-                            this.checkBadge('MUSIC', item.teacher)
-                              ? getAssetsHomeFile('music_active.png')
-                              : getAssetsHomeFile('music_default.png')
-                          }
-                        />
-                      </div>
-                      <div class={styles.score}>评分: </div>
-                      <div class={styles.level}>
-                        {item.starGrade ? (
-                          <Rate
-                            readonly
-                            modelValue={item.starGrade}
-                            iconPrefix="iconfont"
-                            color="#FFC459"
-                            void-icon="star_default"
-                            icon="star_active"
-                            size={15}
-                          />
-                        ) : (
-                          <span style={{ fontSize: '12px', color: '#999999' }}>
-                            暂无评分
-                          </span>
-                        )}
-                      </div>
-                    </div>
                     <div class={styles.piNameSubject}>
-                      <Image
+                      {/* <Image
                         class={styles.subjectSection}
                         src={getAssetsHomeFile('icon_subject.png')}
                         fit="contain"
-                      />
+                      /> */}
                       <div class={styles.subjectList}>
                         {this.getSubjectNameList(item.subjectName).map(
                           (item: any) => (
@@ -293,7 +238,62 @@ export default defineComponent({
                     </div>
                   </div>
                 </div>
-                <div class={styles['teacher-bottom']}>
+                <div class={styles.teacherHonor}>
+                  <div>勋章:</div>
+                  <div class={styles.teacherIcons}>
+                    <Image
+                      class={styles.iconOther}
+                      src={
+                        this.checkBadge('STYLE', item.teacher)
+                          ? getAssetsHomeFile('cert_active.png')
+                          : getAssetsHomeFile('cert_default.png')
+                      }
+                    />
+                    <Image
+                      class={styles.iconOther}
+                      src={
+                        this.checkBadge('VIDEO', item.teacher)
+                          ? getAssetsHomeFile('video_active.png')
+                          : getAssetsHomeFile('video_default.png')
+                      }
+                    />
+                    <Image
+                      class={styles.iconOther}
+                      src={
+                        this.checkBadge('LIVE', item.teacher)
+                          ? getAssetsHomeFile('live_active.png')
+                          : getAssetsHomeFile('live_default.png')
+                      }
+                    />
+                    <Image
+                      class={styles.iconOther}
+                      src={
+                        this.checkBadge('MUSIC', item.teacher)
+                          ? getAssetsHomeFile('music_active.png')
+                          : getAssetsHomeFile('music_default.png')
+                      }
+                    />
+                  </div>
+                  <div class={styles.score}>评分: </div>
+                  <div class={styles.level}>
+                    {item.starGrade ? (
+                      <Rate
+                        readonly
+                        modelValue={item.starGrade}
+                        iconPrefix="iconfont"
+                        color="#FFC459"
+                        void-icon="star_default"
+                        icon="star_active"
+                        size={15}
+                      />
+                    ) : (
+                      <span style={{ fontSize: '12px', color: '#999999' }}>
+                        暂无评分
+                      </span>
+                    )}
+                  </div>
+                </div>
+                <div class={[styles['teacher-bottom'], styles.followFans]}>
                   <div class={styles['teacher-data']}>
                     <div class={styles['teacher-data_item']}>
                       粉丝 <span>{item.fansNum || 0}</span>

+ 18 - 6
src/views/music/album-detail/index.tsx

@@ -25,7 +25,8 @@ import { useEventTracking } from '@/helpers/hooks'
 import ColSticky from '@/components/col-sticky'
 import { moneyFormat } from '@/helpers/utils'
 import { orderStatus } from '@/views/order-detail/orderStatus'
-import iconShare from './icon_share.png'
+import iconShare from '../album/icon_share.svg'
+import iconShare2 from '../album/icon_share2.svg'
 import ColShare from '@/components/col-share'
 
 const noop = () => {}
@@ -252,8 +253,16 @@ export default defineComponent({
               }}
               v-slots={{
                 right: () => (
-                  <div class={styles.shareBtn} onClick={onShare}>
-                    <Image src={iconShare} />
+                  <div
+                    class={styles.shareBtn}
+                    style={{
+                      color: color.value
+                    }}
+                    onClick={onShare}
+                  >
+                    <Image
+                      src={color.value === 'black' ? iconShare2 : iconShare}
+                    />
                     分享
                   </div>
                 )
@@ -325,9 +334,12 @@ export default defineComponent({
                 list={rows.value}
                 onDetail={(item: any) => {
                   if (onItemClick === noop || !onItemClick) {
-                    musicBuy(item, () => {}, {
-                      albumId: route.params.id,
-                      albumName: albumDetail.value?.albumName
+                    router.push({
+                      path: '/music-detail',
+                      query: {
+                        id: item.id,
+                        albumId: route.params.id
+                      }
                     })
                   } else {
                     onItemClick(item)

+ 1 - 1
src/views/music/album/icon_share.svg

@@ -6,7 +6,7 @@
             <g id="编组-5备份" transform="translate(14.000000, 151.000000)">
                 <g id="分享(专辑)" transform="translate(281.000000, 71.000000)">
                     <rect id="矩形" x="0" y="0" width="18" height="18"></rect>
-                    <g id="编组-5" transform="translate(1.960261, 2.294652)" stroke="#DEDEDE" stroke-linecap="round" stroke-width="1.4">
+                    <g id="编组-5" transform="translate(1.960261, 2.294652)" stroke="#fff" stroke-linecap="round" stroke-width="1.4">
                         <path d="M7,0.0980762114 C3.13400675,0.0980762114 0,3.23208296 0,7.09807621 C0,10.9640695 3.13400675,14.0980762 7,14.0980762 C10.8659932,14.0980762 14,10.9640695 14,7.09807621" id="路径"></path>
                         <path d="M13.0553063,2.25732549 C9.74159779,2.25732549 7.05530629,4.94361699 7.05530629,8.25732549" id="路径"></path>
                         <polyline id="路径" stroke-linejoin="round" transform="translate(11.366025, 2.732051) rotate(-330.000000) translate(-11.366025, -2.732051) " points="9.3660254 0.732050808 13.3660254 0.732050808 13.3660254 4.73205081"></polyline>

+ 43 - 0
src/views/music/album/index.module.less

@@ -17,3 +17,46 @@
     }
   }
 }
+.musicGrid {
+  margin: 16px 12px;
+}
+.tagTabs {
+  :global {
+    .van-tabs__nav {
+      background-color: transparent;
+      padding: 0;
+    }
+    .van-tab {
+      font-size: 16px;
+      font-weight: bold;
+    }
+    .van-tab--shrink {
+      padding: 0;
+      margin: 15px;
+    }
+    .van-tab--active {
+      &::after {
+        content: ' ';
+        display: inline-block;
+        width: 96%;
+        position: absolute;
+        height: 7px;
+        background: rgba(45, 199, 170, 0.5);
+        border-radius: 4px;
+        bottom: 0;
+        left: 2%;
+        transition: all ease 0.3s;
+      }
+      .van-tab__text {
+        z-index: 1;
+      }
+    }
+    .van-tabs__line {
+      height: 0;
+      // bottom: 30px;
+      // height: 7px;
+      // background: rgba(45, 199, 170, 0.5);
+      // border-radius: 4px;
+    }
+  }
+}

+ 66 - 26
src/views/music/album/index.tsx

@@ -1,15 +1,17 @@
 import { defineComponent, reactive, ref } from 'vue'
-import { Sticky, List, Popup, Icon } from 'vant'
+import { Sticky, List, Popup, Icon, Tabs, Tab } from 'vant'
 import Search from '@/components/col-search'
 import request from '@/helpers/request'
 import Item from './item'
 import SelectTag from '../search/select-tag'
-import { useRoute } from 'vue-router'
+import { useRoute, useRouter } from 'vue-router'
 import ColResult from '@/components/col-result'
 import styles from './index.module.less'
-import { state } from '@/state'
+import { state as baseState } from '@/state'
 import SelectSubject from '../search/select-subject'
 import { SubjectEnum, useSubjectId } from '@/helpers/hooks'
+import MusicGrid from '../component/music-grid'
+import { useAsyncState } from '@vueuse/core'
 
 export default defineComponent({
   name: 'Album',
@@ -24,10 +26,19 @@ export default defineComponent({
     }
   },
   setup({ hideSearch, defauleParams }, { expose }) {
+    const { isLoading, state } = useAsyncState(
+      request(baseState.platformApi + '/MusicTag/tree', {
+        params: {
+          type: 'ALBUM'
+        }
+      }),
+      null
+    )
+
     const subjects: any = useSubjectId(SubjectEnum.SEARCH)
     // 判断是否已有数据
     if (!subjects.id) {
-      const users = state.user.data
+      const users = baseState.user.data
       const subjectId = users.subjectId
         ? Number(users.subjectId.split(',')[0])
         : ''
@@ -45,18 +56,15 @@ export default defineComponent({
         )
       }
     }
-
+    const router = useRouter()
     const route = useRoute()
     const tempParams: any = {}
-    if (state.version) {
-      tempParams.version = state.version || '' // 处理ios审核版本
+    if (baseState.version) {
+      tempParams.version = baseState.version || '' // 处理ios审核版本
       tempParams.platform =
-        state.platformType === 'STUDENT' ? 'ios-student' : 'ios-teacher'
+        baseState.platformType === 'STUDENT' ? 'ios-student' : 'ios-teacher'
     }
-    // if (state.platformType === 'TEACHER') {
     tempParams.myself = false
-    // }
-    // console.log({ ...defauleParams })
     if (!hideSearch) {
       const getSubject: any = useSubjectId(SubjectEnum.SEARCH)
       tempParams.subjectIds = getSubject.id
@@ -90,7 +98,9 @@ export default defineComponent({
       try {
         const res = await request.post('/music/album/list', {
           prefix:
-            state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student',
+            baseState.platformType === 'TEACHER'
+              ? '/api-teacher'
+              : '/api-student',
           data: {
             ...params,
             idAndName: params.search
@@ -150,6 +160,7 @@ export default defineComponent({
     })
 
     return () => {
+      const tagList = ((state.value && state.value.data) as any) || []
       return (
         <>
           <List
@@ -165,10 +176,8 @@ export default defineComponent({
               <Sticky class={styles.sticky}>
                 <Search
                   modelValue={params.search}
-                  showAction
                   onSearch={onSearch}
-                  onFilter={() => (tagVisibility.value = true)}
-                  filterDot={!!params.albumTagIds}
+                  placeholder="请输入专辑名称 "
                   v-slots={{
                     left: () => (
                       <div
@@ -186,20 +195,51 @@ export default defineComponent({
                     )
                   }}
                 />
+                <Tabs
+                  shrink
+                  class={styles.tagTabs}
+                  lineHeight={0}
+                  onClick-tab={(obj: any) => {
+                    params.albumTagIds = obj.name
+                    data.value = null
+                    params.page = 1
+                    FetchList()
+                  }}
+                >
+                  <Tab title="全部" name=""></Tab>
+                  {tagList.map((tag: any) => (
+                    <Tab title={tag.name} name={tag.id}></Tab>
+                  ))}
+                </Tabs>
               </Sticky>
             )}
-            {data.value && data.value.rows.length
-              ? data.value.rows.map(item => <Item data={item} />)
-              : !loading.value && (
-                  <ColResult
-                    tips="暂无专辑"
-                    classImgSize="SMALL"
-                    btnStatus={false}
-                  />
-                )}
+            {data.value && data.value.rows.length ? (
+              <div class={styles.musicGrid}>
+                <MusicGrid
+                  list={data.value.rows}
+                  onGoto={(n: any) => {
+                    router.push({
+                      name: 'music-album-detail',
+                      params: {
+                        id: n.id
+                      }
+                    })
+                  }}
+                />
+              </div>
+            ) : (
+              // data.value.rows.map(item => <Item data={item} />)
+              !loading.value && (
+                <ColResult
+                  tips="暂无专辑"
+                  classImgSize="SMALL"
+                  btnStatus={false}
+                />
+              )
+            )}
           </List>
 
-          <Popup
+          {/* <Popup
             show={tagVisibility.value}
             round
             closeable
@@ -213,7 +253,7 @@ export default defineComponent({
               onConfirm={onComfirm}
               onCancel={() => {}}
             />
-          </Popup>
+          </Popup> */}
           <Popup
             show={subject.show}
             position="bottom"

+ 3 - 3
src/views/music/component/music-grid/index.module.less

@@ -8,12 +8,12 @@
     }
     .van-grid-item__content {
       display: block;
-      padding: 0 4px;
+      padding: 0 8px;
       background-color: transparent;
     }
   }
   .item {
-    margin-bottom: 15px;
+    margin-bottom: 14px;
     .title {
       font-size: 14px;
       color: #333;
@@ -32,7 +32,7 @@
   .imgWrap {
     position: relative;
     // height: 110px;
-    height: calc((100vw - 48px) / 3);
+    height: calc((100vw - 28px) / 3);
     border-radius: 10px;
     overflow: hidden;
     margin-bottom: 6px;

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

@@ -36,7 +36,7 @@ export default defineComponent({
                   </div>
                 </div>
                 <div class={styles.title}>{n.albumName}</div>
-                <div class={styles.des}>共{n.musicSheetCount}首</div>
+                {/* <div class={styles.des}>共{n.musicSheetCount}首</div> */}
               </div>
             </GridItem>
           ))}

+ 3 - 3
src/views/music/component/song/index.module.less

@@ -63,7 +63,7 @@
       font-size: 16px;
       font-weight: bold;
       color: #1a1a1a;
-      margin: 0 6px;
+      margin-right: 6px;
     }
     .singer {
       max-width: 50px;
@@ -198,12 +198,12 @@
 
 .exquisiteFlag {
   width: 14px;
-  margin-left: 5px;
+  margin-right: 5px;
   flex-shrink: 0;
 }
 .songAlbum {
   width: 15px;
   height: 15px;
-  margin-left: 5px;
+  margin-right: 5px;
   flex-shrink: 0;
 }

+ 6 - 41
src/views/music/component/song/index.tsx

@@ -22,10 +22,10 @@ export default defineComponent({
       type: Array as PropType<any[]>,
       default: () => []
     },
-    showMore: {
-      type: Boolean,
-      default: true
-    },
+    // showMore: {
+    //   type: Boolean,
+    //   default: true
+    // },
     showPlay: {
       type: Boolean,
       default: true
@@ -107,17 +107,6 @@ export default defineComponent({
             <div class={styles.item} onClick={() => emit('detail', n)}>
               <div class={styles.content}>
                 <div class={styles.top}>
-                  {n.paymentType.map(tag => (
-                    <Tag
-                      style={{ color: colors[tag].color }}
-                      class={styles.tag}
-                      type="success"
-                      plain
-                    >
-                      {colors[tag].text}
-                    </Tag>
-                  ))}
-
                   {n.exquisiteFlag === 1 && (
                     <Image
                       class={styles.exquisiteFlag}
@@ -159,7 +148,7 @@ export default defineComponent({
               <div class={styles.play}>
                 {props.showPlay && <Icon name={IconPlay} size={28} />}
 
-                {props.showMore && (
+                {/* {props.showMore && (
                   <span class={styles.moreSection}>
                     <Icon
                       name={IconMore}
@@ -171,7 +160,7 @@ export default defineComponent({
                       }}
                     />
                   </span>
-                )}
+                )} */}
               </div>
             </div>
           ))}
@@ -200,30 +189,6 @@ export default defineComponent({
                           display: 'flex'
                         }}
                       >
-                        {moreData?.value.paymentType.map(tag => (
-                          <Tag
-                            style={{
-                              color: colors[tag].color,
-                              marginRight: '6px'
-                            }}
-                            class={styles.tag}
-                            type="success"
-                            plain
-                          >
-                            {colors[tag].text}
-                          </Tag>
-                        ))}
-                        {/* <Tag
-                          style={{
-                            color: colors[moreData?.value.chargeType].color,
-                            marginRight: '6px'
-                          }}
-                          class={styles.tag}
-                          type="success"
-                          plain
-                        >
-                          {colors[moreData?.value.chargeType].text}
-                        </Tag> */}
                         <span style={{ paddingTop: '2px' }}>
                           {moreData?.value.composer}
                         </span>

BIN
src/views/music/list/icons/bgImg.png


BIN
src/views/music/list/icons/icon_search.png


+ 79 - 2
src/views/music/list/index.module.less

@@ -2,6 +2,13 @@
   :global(.van-sticky--fixed) {
     box-shadow: 10px 10px 10px var(--box-shadow-color);
   }
+
+  :global {
+    .van-sticky {
+      background: url('./icons/bgImg.png') no-repeat top center;
+      background-size: 100% 214px;
+    }
+  }
 }
 
 .listContainer {
@@ -28,6 +35,7 @@
 .label {
   margin-right: 8px;
   font-size: 14px;
+  color: #fff;
   :global {
     .van-list__loading,
     .van-list__finished-text,
@@ -47,6 +55,75 @@
   margin: 14px;
 }
 
-.swipeContainer {
-  // height: calc(100vh - 44px);
+.bgImg {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 214px;
+  // object-fit: cover;
+  z-index: -1;
+}
+
+.tagTabs {
+  :global {
+    .van-tabs__nav {
+      background-color: transparent;
+      padding: 0;
+    }
+    .van-tab {
+      font-size: 16px;
+      font-weight: bold;
+      color: #fff;
+    }
+    .van-tab--shrink {
+      padding: 0;
+      margin: 15px;
+    }
+    .van-tab--active {
+      color: #fff;
+      &::after {
+        content: ' ';
+        display: inline-block;
+        width: 96%;
+        position: absolute;
+        height: 7px;
+        background: #2dc7aa;
+        border-radius: 4px;
+        bottom: -2px;
+        left: 2%;
+        transition: all ease 0.3s;
+      }
+      .van-tab__text {
+        z-index: 1;
+      }
+    }
+    .van-tabs__line {
+      height: 0;
+      // bottom: 30px;
+      // height: 7px;
+      // background: rgba(45, 199, 170, 0.5);
+      // border-radius: 4px;
+    }
+  }
+}
+
+.fleg {
+  display: flex;
+  align-items: center;
+  font-size: 14px;
+  font-weight: 600;
+  span {
+    padding-top: 3px;
+  }
+  :global {
+    .van-switch {
+      margin-left: 9px;
+
+      background: rgba(255, 255, 255, 0.2);
+    }
+    .van-switch__node {
+      background: rgba(255, 255, 255, 0.51);
+    }
+  }
 }

+ 154 - 99
src/views/music/list/index.tsx

@@ -1,5 +1,5 @@
 import { defineComponent, nextTick, onMounted, reactive, ref } from 'vue'
-import { Sticky, List, Popup, Icon, Switch } from 'vant'
+import { Sticky, List, Popup, Icon, Switch, Tabs, Tab } from 'vant'
 import Search from '@/components/col-search'
 import request from '@/helpers/request'
 // import Item from './item'
@@ -8,12 +8,15 @@ import { useRoute, useRouter } from 'vue-router'
 import ColResult from '@/components/col-result'
 import styles from './index.module.less'
 import { getRandomKey, musicBuy } from '../music'
-import { state } from '@/state'
+import { state as baseState } from '@/state'
 import SelectSubject from '../search/select-subject'
 import { SubjectEnum, useSubjectId } from '@/helpers/hooks'
 import Song from '../component/song'
 import ColHeader from '@/components/col-header'
 import { useRect } from '@vant/use'
+import { useAsyncState } from '@vueuse/core'
+import bgImg from './icons/bgImg.png'
+import iconSearch from './icons/icon_search.png'
 
 const noop = () => {
   //
@@ -47,10 +50,19 @@ export default defineComponent({
     { hideSearch, defauleParams, onItemClick, teacherId, myself },
     { expose }
   ) {
+    const { isLoading, state } = useAsyncState(
+      request(baseState.platformApi + '/MusicTag/tree', {
+        params: {
+          type: 'MUSIC'
+        }
+      }),
+      null
+    )
+
     const subjects: any = useSubjectId(SubjectEnum.SEARCH)
     // 判断是否已有数据
     if (!subjects.id) {
-      const users = state.user.data
+      const users = baseState.user.data
       const subjectId = users.subjectId
         ? Number(users.subjectId.split(',')[0])
         : ''
@@ -73,10 +85,10 @@ export default defineComponent({
     const route = useRoute()
     // const router = useRouter()
     const tempParams: any = {}
-    if (state.version) {
-      tempParams.version = state.version || '' // 处理ios审核版本
+    if (baseState.version) {
+      tempParams.version = baseState.version || '' // 处理ios审核版本
       tempParams.platform =
-        state.platformType === 'STUDENT' ? 'ios-student' : 'ios-teacher'
+        baseState.platformType === 'STUDENT' ? 'ios-student' : 'ios-teacher'
     }
     // 判断是否在搜索页面用过
     if (!hideSearch) {
@@ -99,7 +111,7 @@ export default defineComponent({
     const tagVisibility = ref(false)
     const exquisiteFlag = ref(false)
     const apiSuffix = ref(
-      state.platformType === 'STUDENT' ? '/api-student' : '/api-teacher'
+      baseState.platformType === 'STUDENT' ? '/api-student' : '/api-teacher'
     )
 
     const onSearch = (value: string) => {
@@ -197,102 +209,145 @@ export default defineComponent({
       onComfirmSubject
     })
 
-    return () => (
-      <>
-        {!hideSearch && (
-          <Sticky class={styles.sticky}>
-            <Search
-              showAction
-              onSearch={onSearch}
-              onFilter={() => (tagVisibility.value = true)}
-              filterDot={!!params.musicTagIds}
-              v-slots={{
-                left: () => (
-                  <div
-                    class={styles.label}
-                    onClick={() => (subject.show = true)}
-                  >
-                    {subject.name}
-                    <Icon
-                      classPrefix="iconfont"
-                      name="down"
-                      size={12}
-                      color="#333"
-                    />
-                  </div>
-                )
-              }}
-            />
-          </Sticky>
-        )}
-        <List
-          loading={loading.value}
-          finished={finished.value}
-          finished-text={
-            data.value && data.value.rows.length ? '没有更多了' : ''
-          }
-          onLoad={FetchList}
-          error={isError.value}
-        >
-          {data.value && data.value.rows.length ? (
-            <div class={styles.alumnList}>
-              <Song
-                list={data.value.rows}
-                onDetail={(item: any) => {
-                  if (onItemClick === noop) {
-                    musicBuy(item)
-                  } else {
-                    onItemClick?.(item)
-                  }
+    return () => {
+      const tagList = ((state.value && state.value.data) as any) || []
+      return (
+        <>
+          {!hideSearch && (
+            <Sticky class={styles.sticky}>
+              <ColHeader
+                background="transparent"
+                isFixed={false}
+                border={false}
+                backIconColor="white"
+                color="#fff"
+                v-slots={{
+                  right: () => (
+                    <span
+                      class={styles.fleg}
+                      onClick={() => {
+                        exquisiteFlag.value != exquisiteFlag.value
+                        data.value = null
+                        params.page = 1
+                        FetchList()
+                      }}
+                    >
+                      <span>精品</span>
+                      <Switch v-model={exquisiteFlag.value} size="20px" />
+                    </span>
+                  )
                 }}
               />
-            </div>
-          ) : (
-            !loading.value && (
-              <ColResult
-                tips="暂无曲目"
-                classImgSize="SMALL"
-                btnStatus={false}
+              <Search
+                onSearch={onSearch}
+                background="transparent"
+                inputBackground="transparent"
+                leftIcon={iconSearch}
+                v-slots={{
+                  left: () => (
+                    <div
+                      class={styles.label}
+                      onClick={() => (subject.show = true)}
+                    >
+                      {subject.name}
+                      <Icon
+                        classPrefix="iconfont"
+                        name="down"
+                        size={12}
+                        color="#fff"
+                      />
+                    </div>
+                  )
+                }}
               />
-            )
+              <Tabs
+                shrink
+                class={styles.tagTabs}
+                lineHeight={0}
+                onClick-tab={(obj: any) => {
+                  params.albumTagIds = obj.name
+                  data.value = null
+                  params.page = 1
+                  FetchList()
+                }}
+              >
+                <Tab title="全部" name=""></Tab>
+                {tagList.map((tag: any) => (
+                  <Tab title={tag.name} name={tag.id}></Tab>
+                ))}
+              </Tabs>
+            </Sticky>
           )}
-        </List>
-        <Popup
-          show={tagVisibility.value}
-          round
-          closeable
-          position="bottom"
-          style={{ height: '60%' }}
-          teleport="body"
-          onUpdate:show={val => (tagVisibility.value = val)}
-        >
-          <SelectTag
-            exquisiteFlag
-            onConfirm={onComfirm}
-            onCancel={() => {
-              //
-            }}
-            defaultValue={route.query.tagids as string}
-          />
-        </Popup>
+          <img class={styles.bgImg} src={bgImg} />
+          <List
+            loading={loading.value}
+            finished={finished.value}
+            finished-text={
+              data.value && data.value.rows.length ? '没有更多了' : ''
+            }
+            onLoad={FetchList}
+            error={isError.value}
+          >
+            {data.value && data.value.rows.length ? (
+              <div class={styles.alumnList}>
+                <Song
+                  list={data.value.rows}
+                  onDetail={(item: any) => {
+                    if (onItemClick === noop) {
+                      musicBuy(item)
+                    } else {
+                      onItemClick?.(item)
+                    }
+                  }}
+                />
+              </div>
+            ) : (
+              !loading.value && (
+                <ColResult
+                  tips="暂无曲目"
+                  classImgSize="SMALL"
+                  btnStatus={false}
+                />
+              )
+            )}
+          </List>
+          <Popup
+            show={tagVisibility.value}
+            round
+            closeable
+            position="bottom"
+            style={{ height: '60%' }}
+            teleport="body"
+            onUpdate:show={val => (tagVisibility.value = val)}
+          >
+            <SelectTag
+              exquisiteFlag
+              onConfirm={onComfirm}
+              onCancel={() => {
+                //
+              }}
+              defaultValue={route.query.tagids as string}
+            />
+          </Popup>
 
-        {/* 声部弹框 */}
-        <Popup
-          show={subject.show}
-          position="bottom"
-          round
-          closeable
-          safe-area-inset-bottom
-          onClose={() => (subject.show = false)}
-          onClosed={() => (subject.show = false)}
-        >
-          <SelectSubject
-            type="MUSIC"
-            searchParams={subject}
-            onComfirm={onComfirmSubject}
-          />
-        </Popup>
-      </>
-    )
+          {/* 声部弹框 */}
+          <Popup
+            show={subject.show}
+            position="bottom"
+            round
+            closeable
+            safe-area-inset-bottom
+            onClose={() => (subject.show = false)}
+            onClosed={() => (subject.show = false)}
+          >
+            <SelectSubject
+              type="MUSIC"
+              searchParams={subject}
+              onComfirm={onComfirmSubject}
+            />
+          </Popup>
+        </>
+      )
+    }
   }
 })

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
src/views/music/music-detail/animate/bigLoad.json


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
src/views/music/music-detail/animate/kulexiuyunjiaolian.json


BIN
src/views/music/music-detail/images/icon_collect.png


BIN
src/views/music/music-detail/images/icon_collect_active.png


BIN
src/views/music/music-detail/images/icon_download.png


+ 307 - 0
src/views/music/music-detail/index.module.less

@@ -0,0 +1,307 @@
+.base > div {
+  background: url(./header-bg.png) no-repeat top center;
+  // background-attachment: fixed;
+}
+.detail {
+  overflow: hidden;
+  --van-nav-bar-background-color: transparent;
+  --van-nav-bar-icon-color: #fff;
+  --van-nav-bar-text-color: #fff;
+  --van-nav-bar-title-text-color: #fff;
+}
+.base {
+  :global(.van-sticky--fixed) {
+    box-shadow: 10px 10px 10px var(--box-shadow-color);
+  }
+}
+.shareBtn {
+  display: flex;
+  align-items: flex-start;
+  color: #fff;
+  font-size: 14px;
+  line-height: 20px !important;
+  :global(.van-image) {
+    width: 18px;
+    height: 18px;
+    margin-right: 6px;
+  }
+}
+
+.bgImg {
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 265px;
+  object-fit: cover;
+  filter: blur(10px);
+}
+.musicContent {
+  position: relative;
+  width: 100%;
+  height: 500px;
+  overflow: hidden;
+  &::after {
+    content: ' ';
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    background: linear-gradient(
+      180deg,
+      rgba(255, 255, 255, 0) 0%,
+      #ffffff 100%
+    );
+    height: 287px;
+  }
+  .musicTitle {
+    text-align: center;
+    font-size: 16px;
+  }
+  .musicImg {
+    width: 100%;
+  }
+  .finch {
+    width: 150px;
+    margin: 80px auto 0;
+  }
+  .finchLoad {
+    text-align: center;
+    color: #333;
+    font-size: 15px;
+    margin-top: 4px;
+  }
+  :global {
+    iframe {
+      visibility: hidden;
+      body {
+        ::-webkit-scrollbar-thumb {
+          background-color: #efeff0;
+          border: 1px solid transparent;
+          background-clip: padding-box;
+          border-radius: 5px;
+        }
+      }
+    }
+  }
+}
+
+.bg {
+  position: relative;
+  height: 100%;
+  padding: 16px;
+  z-index: 11;
+}
+.musicContainer {
+  position: relative;
+  // padding: 16px 0 0;
+  z-index: 12;
+  border-radius: 18px 18px 0 0;
+  background-color: #fff;
+  overflow-y: auto;
+}
+
+.shareMate {
+  position: relative;
+  margin-top: 50px;
+  display: flex;
+  flex: 1;
+  align-items: center;
+  padding: 11px 12px;
+  background: #ffffff;
+  border-radius: 10px;
+  // border: 1px solid #2dc7aa;
+  .icon {
+    width: 36px;
+    height: 36px;
+    border-radius: 10px;
+  }
+  .info {
+    margin-left: 14px;
+    flex: 1;
+    margin-right: 14px;
+    word-break: break-all;
+    > h4 {
+      color: var(--music-list-item-title-color);
+      font-size: 14px;
+      font-weight: 600;
+      width: 200px;
+    }
+    > p {
+      color: var(--music-list-item-mate-color);
+      line-height: 17px;
+    }
+  }
+
+  .tagDiscount {
+    position: absolute;
+    top: -26px;
+    left: 15px;
+    padding: 2px 10px 1px;
+    height: 23px;
+    background: linear-gradient(180deg, #ffb635 0%, #ff4e18 100%);
+    border-radius: 8px 8px 0px 0px;
+    font-size: 14px;
+    font-weight: 600;
+    color: #ffffff;
+    line-height: 20px;
+  }
+}
+
+.shareVip {
+  position: relative;
+  margin-top: 35px;
+  display: flex;
+  flex: 1;
+  align-items: center;
+  padding: 7px;
+  background: #ffffff;
+  border-radius: 10px;
+
+  .icon {
+    width: 72px;
+    height: 72px;
+    border-radius: 10px;
+  }
+  .info {
+    margin-left: 6px;
+    flex: 1;
+    word-break: break-all;
+    > h4 {
+      color: var(--music-list-item-title-color);
+      font-size: 16px;
+      font-weight: 600;
+    }
+    > p {
+      color: var(--music-list-item-mate-color);
+      line-height: 17px;
+    }
+  }
+}
+
+.tagDiscount {
+  position: absolute;
+  top: -23px;
+  left: 15px;
+  padding: 0 10px;
+  height: 23px;
+  background: linear-gradient(180deg, #ffb635 0%, #ff4e18 100%);
+  border-radius: 8px 8px 0px 0px;
+  font-size: 14px;
+  font-weight: 600;
+  color: #ffffff;
+  line-height: 24px;
+}
+.buttonDiscount {
+  position: absolute;
+  top: -23px;
+  right: 15px;
+  padding: 0 10px;
+  height: 23px;
+  background: linear-gradient(180deg, #ffb635 0%, #ff4e18 100%);
+  border-radius: 8px 8px 0px 0px;
+  font-size: 14px;
+  font-weight: 600;
+  color: #ffffff;
+  line-height: 24px;
+}
+
+.pImg {
+  width: 46px;
+  height: 46px;
+  border-radius: 10px;
+  overflow: hidden;
+  flex-shrink: 0;
+}
+.musicInfo {
+  padding-top: 23px !important;
+  padding-bottom: 23px !important;
+  margin-bottom: 10px;
+  .tag {
+    flex-shrink: 0;
+    // padding: 2px 4px 0;
+    border-radius: 4px;
+  }
+
+  .info {
+    margin-left: 14px;
+    flex: 1;
+    margin-right: 14px;
+    word-break: break-all;
+    > h4 {
+      font-size: 16px;
+      font-weight: bold;
+      color: #1a1a1a;
+      width: 200px;
+      padding-bottom: 3px;
+    }
+    > p {
+      font-size: 12px;
+      color: #999;
+      line-height: 17px;
+    }
+  }
+
+  .download {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    font-size: 12px;
+    img {
+      height: 24px;
+      width: 24px;
+    }
+  }
+
+  .exquisiteFlag {
+    width: 14px;
+    margin-left: 5px;
+    flex-shrink: 0;
+  }
+  .songAlbum {
+    width: 15px;
+    height: 15px;
+    margin-left: 5px;
+    flex-shrink: 0;
+  }
+}
+
+.colSticky {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  .priceSection {
+    font-size: 14px;
+    font-weight: 400;
+    color: #999999;
+    .price {
+      font-size: 22px;
+      font-weight: bold;
+      color: #ff4e19;
+      i {
+        font-style: normal;
+        font-size: 16px;
+      }
+    }
+  }
+}
+
+.buyBtn {
+  :global {
+    .van-button {
+      padding: 0 22px;
+      font-weight: 600;
+
+      & + .van-button {
+        margin-left: 12px;
+      }
+    }
+  }
+  .primry {
+    box-shadow: 0px 2px 7px 0px rgba(45, 199, 170, 0.25);
+  }
+  .member {
+    box-shadow: 0px 2px 7px 0px rgba(187, 156, 83, 0.25);
+  }
+}

+ 417 - 0
src/views/music/music-detail/index.tsx

@@ -0,0 +1,417 @@
+import {
+  computed,
+  defineComponent,
+  nextTick,
+  onMounted,
+  reactive,
+  ref
+} from 'vue'
+import { useRoute, useRouter } from 'vue-router'
+import request from '@/helpers/request'
+import ColHeader from '@/components/col-header'
+import { postMessage } from '@/helpers/native-message'
+import { Button, Cell, Dialog, Icon, Image, Popup, Tag } from 'vant'
+import styles from './index.module.less'
+// import Item from '../list/item'
+import { useRect } from '@vant/use'
+import { Vue3Lottie } from 'vue3-lottie'
+import { getRandomKey, musicBuy } from '../music'
+import { state } from '@/state'
+import { useEventTracking } from '@/helpers/hooks'
+import ColSticky from '@/components/col-sticky'
+import { moneyFormat } from '@/helpers/utils'
+import { orderStatus } from '@/views/order-detail/orderStatus'
+import iconShare from '@/views/music/album/icon_share.svg'
+import iconDownload from './images/icon_download.png'
+import AstronautJSON from './animate/bigLoad.json'
+import ColShare from '@/components/col-share'
+import iconCollect from './images/icon_collect.png'
+import iconCollectActive from './images/icon_collect_active.png'
+
+export const getAssetsHomeFile = (fileName: string) => {
+  const path = `../component/images/${fileName}`
+  const modules = import.meta.globEager('../component/images/*')
+  return modules[path].default
+}
+
+export default defineComponent({
+  name: 'MusicDetail',
+  setup() {
+    localStorage.setItem('behaviorId', getRandomKey())
+    const router = useRouter()
+    const route = useRoute()
+    const albumDetail = ref<any>(null)
+    const loading = ref(false)
+    const aId = Number(route.query.activityId) || 0
+    const studentActivityId = ref(aId)
+    const isError = ref(false)
+    const favorited = ref(0)
+    const albumFavoriteCount = ref(0)
+    const headers = ref(null)
+    const heightInfo = ref<any>('0')
+    const musicDetail = ref<any>(null)
+    const showImg = ref<string>('')
+
+    const colors: any = {
+      FREE: {
+        color: '#01B84F',
+        text: '免费'
+      },
+      VIP: {
+        color: '#CD863E',
+        text: '会员'
+      },
+      CHARGE: {
+        color: '#3591CE',
+        text: '点播'
+      }
+    }
+
+    const FetchList = async (id?: any) => {
+      if (loading.value) {
+        return
+      }
+      loading.value = true
+      isError.value = false
+      try {
+        const res = await request.get(`/music/sheet/detail/${route.query.id}`, {
+          prefix:
+            state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student'
+        })
+        musicDetail.value = res.data
+        showImg.value = res.data.musicImg || ''
+      } catch (error) {
+        isError.value = true
+      }
+      loading.value = false
+    }
+
+    const favoriteLoading = ref(false)
+
+    onMounted(() => {
+      FetchList()
+      const { height } = useRect(headers as any)
+      heightInfo.value = height
+    })
+
+    const toggleFavorite = async (id: number) => {
+      favoriteLoading.value = true
+      try {
+        await request.post('/music/album/favorite/' + id, {
+          prefix:
+            state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student'
+        })
+        favorited.value = favorited.value === 1 ? 0 : 1
+        albumFavoriteCount.value += favorited.value ? 1 : -1
+      } catch (error) {}
+      favoriteLoading.value = false
+    }
+
+    const onBuy = async () => {
+      const album = albumDetail.value
+      orderStatus.orderObject.orderType = 'ALBUM'
+      orderStatus.orderObject.orderName = album.albumName
+      orderStatus.orderObject.orderDesc = album.albumName
+      orderStatus.orderObject.actualPrice = album.albumPrice
+      orderStatus.orderObject.recomUserId = route.query.recomUserId || 0
+      orderStatus.orderObject.activityId = route.query.activityId || 0
+      orderStatus.orderObject.orderNo = ''
+      orderStatus.orderObject.orderList = [
+        {
+          orderType: 'ALBUM',
+          goodsName: album.albumName,
+          recomUserId: route.query.recomUserId || 0,
+          price: album.albumPrice,
+          ...album
+        }
+      ]
+
+      const res = await request.post('/api-student/userOrder/getPendingOrder', {
+        data: {
+          goodType: 'ALBUM',
+          bizId: album.id
+        }
+      })
+
+      const result = res.data
+      if (result) {
+        Dialog.confirm({
+          title: '提示',
+          message: '您有一个未支付的订单,是否继续支付?',
+          confirmButtonColor: '#269a93',
+          cancelButtonText: '取消订单',
+          confirmButtonText: '继续支付'
+        })
+          .then(async () => {
+            orderStatus.orderObject.orderNo = result.orderNo
+            orderStatus.orderObject.actualPrice = result.actualPrice
+            orderStatus.orderObject.discountPrice = result.discountPrice
+            routerTo()
+          })
+          .catch(() => {
+            Dialog.close()
+            // 只用取消订单,不用做其它处理
+            cancelPayment(result.orderNo)
+          })
+      } else {
+        routerTo()
+      }
+    }
+    const routerTo = () => {
+      const album = albumDetail.value
+      router.push({
+        path: '/orderDetail',
+        query: {
+          orderType: 'ALBUM',
+          album: album.id
+        }
+      })
+    }
+    const cancelPayment = async (orderNo: string) => {
+      try {
+        await request.post('/api-student/userOrder/orderCancel', {
+          data: {
+            orderNo
+          }
+        })
+      } catch {}
+    }
+
+    const paymentType = computed(() => {
+      let paymentType = musicDetail.value?.paymentType
+      if (typeof paymentType === 'string') {
+        paymentType = paymentType.split(',')
+        return paymentType
+      }
+      return []
+    })
+
+    const shareStatus = ref(false)
+    const shareUrl = ref('')
+    const shareDiscount = ref(0)
+    // console.log(data)
+    const onShare = async () => {
+      try {
+        const res = await request.post('/api-teacher/open/musicShareProfit', {
+          data: {
+            bizId: musicDetail.value?.id,
+            userId: state.user.data?.userId
+          }
+        })
+        let url =
+          location.origin +
+          `/accompany/colexiu-share.html?id=${musicDetail.value?.id}&recomUserId=${state.user.data?.userId}&userType=${state.platformType}`
+        // 判断是否有活动
+        if (res.data.discount === 1) {
+          url += `&activityId=${res.data.activityId}`
+        }
+        shareDiscount.value = res.data.discount || 0
+        shareUrl.value = url
+        shareStatus.value = true
+        return
+      } catch {}
+    }
+    return () => {
+      return (
+        <div class={styles.detail}>
+          <ColHeader
+            background="transparent"
+            border={false}
+            color="#fff"
+            backIconColor="white"
+            v-slots={{
+              right: () => (
+                <div
+                  class={styles.shareBtn}
+                  style={{
+                    color: '#fff'
+                  }}
+                  onClick={onShare}
+                >
+                  <Image src={iconShare} />
+                  分享
+                </div>
+              )
+            }}
+          />
+          <img class={styles.bgImg} src={musicDetail.value?.titleImg} />
+
+          <div
+            class={styles.musicContainer}
+            style={{
+              marginTop: '16px',
+              height: `calc(100vh - var(--van-nav-bar-height) - ${
+                heightInfo.value + 16 + 'px'
+              })`
+            }}
+          >
+            <Cell
+              border={false}
+              center
+              class={styles.musicInfo}
+              v-slots={{
+                icon: () => (
+                  <Image
+                    class={styles.pImg}
+                    src={musicDetail.value?.titleImg}
+                  />
+                ),
+                title: () => (
+                  <div class={styles.info}>
+                    <h4 class="van-ellipsis">
+                      {musicDetail.value?.musicSheetName}
+                    </h4>
+                    <p
+                      style={{
+                        display: 'flex'
+                      }}
+                    >
+                      {paymentType.value.map(tag => (
+                        <Tag
+                          style={{ color: colors[tag].color }}
+                          class={styles.tag}
+                          type="success"
+                          plain
+                        >
+                          {colors[tag].text}
+                        </Tag>
+                      ))}
+                      {musicDetail.value?.exquisiteFlag === 1 && (
+                        <Image
+                          class={styles.exquisiteFlag}
+                          src={getAssetsHomeFile('icon_ exquisite.png')}
+                        />
+                      )}
+
+                      {musicDetail.value?.albumNums > 0 && (
+                        <Image
+                          class={styles.songAlbum}
+                          src={getAssetsHomeFile('icon_album_active.png')}
+                        />
+                      )}
+                      <span style={{ paddingTop: '2px', paddingLeft: '6px' }}>
+                        {musicDetail.value?.composer}
+                      </span>
+                    </p>
+                  </div>
+                ),
+                value: () => (
+                  <span class={styles.download}>
+                    <img src={iconDownload} />
+                    下载曲谱
+                  </span>
+                )
+              }}
+            />
+            <div class={styles.musicContent}>
+              <iframe
+                id="containerPrint"
+                ref="print"
+                style="width: 100%;page-break-after:always; height: 0"
+                // src={state.accompanyUrl}
+              />
+              <p class={styles.musicTitle}>
+                {musicDetail.value?.musicSheetName}
+              </p>
+              {showImg.value ? (
+                <img src={showImg.value} alt="" class={styles.musicImg} />
+              ) : (
+                <>
+                  <Vue3Lottie
+                    animationData={AstronautJSON}
+                    class={styles.finch}
+                  ></Vue3Lottie>
+                  <p class={styles.finchLoad}>加载中...</p>
+                </>
+              )}
+
+              <div class={styles.videoOperation}>
+                <div class={[styles.collect, styles.collectCell]}>
+                  <div class={styles.userInfo}>
+                    <img src="" />
+                    <span>用户名</span>
+                  </div>
+
+                  <div class={styles.collectSection}>
+                    <span>326人收藏</span>
+                    <img src={iconCollect} />
+                  </div>
+                </div>
+              </div>
+
+              <div class={styles.lookAlbum}></div>
+            </div>
+          </div>
+
+          <ColSticky position="bottom" background="white">
+            <div ref={headers}>
+              <div class={styles.colSticky}>
+                <div class={styles.priceSection}>
+                  <span>点播价:</span>
+                  <span class={styles.price}>
+                    <i>¥</i>
+                    {moneyFormat(9.9)}
+                  </span>
+                </div>
+                <div class={[styles.buyBtn]}>
+                  <Button
+                    round
+                    type="primary"
+                    color="linear-gradient(180deg, #59E5D5 0%, #2DC7AA 100%)"
+                    class={styles.primary}
+                    onClick={onBuy}
+                  >
+                    立即点播
+                  </Button>
+
+                  <Button
+                    round
+                    type="primary"
+                    color="linear-gradient(180deg, #F7BD8D 0%, #CD8806 100%)"
+                    class={styles.memeber}
+                    onClick={onBuy}
+                  >
+                    开通会员
+                  </Button>
+                </div>
+              </div>
+            </div>
+          </ColSticky>
+
+          <Popup
+            v-model:show={shareStatus.value}
+            style={{ background: 'transparent' }}
+            teleport="body"
+          >
+            <ColShare
+              teacherId={state.user.data?.userId}
+              shareUrl={shareUrl.value}
+              shareType="music"
+            >
+              <div class={styles.shareMate}>
+                {shareDiscount.value === 1 && (
+                  <div class={styles.tagDiscount}>专属优惠</div>
+                )}
+
+                <img
+                  class={styles.icon}
+                  crossorigin="anonymous"
+                  src={
+                    musicDetail.value?.titleImg +
+                    `@base@tag=imgScale&h=80&w=80&m=1?t=${+new Date()}`
+                  }
+                />
+                <div class={styles.info}>
+                  <h4 class="van-multi-ellipsis--l2">
+                    {musicDetail.value?.musicSheetName}
+                  </h4>
+                  <p>作曲人:{musicDetail.value?.composer}</p>
+                </div>
+              </div>
+            </ColShare>
+          </Popup>
+        </div>
+      )
+    }
+  }
+})

+ 22 - 9
src/views/music/personal/album-my.tsx

@@ -5,11 +5,14 @@ import Item from '../album/item'
 import { useRoute, useRouter } from 'vue-router'
 import ColResult from '@/components/col-result'
 import { state } from '@/state'
+import MusicGrid from '../component/music-grid'
+import styles from './index.module.less'
 
 export default defineComponent({
   name: 'MusicList',
   setup() {
     const route = useRoute()
+    const router = useRouter()
     const params = reactive({
       page: 1
     })
@@ -49,15 +52,25 @@ export default defineComponent({
         onLoad={FetchList}
         error={isError.value}
       >
-        {rows.value.length
-          ? rows.value.map(item => <Item data={item} />)
-          : !loading.value && (
-              <ColResult
-                tips="暂无专辑"
-                classImgSize="SMALL"
-                btnStatus={false}
-              />
-            )}
+        {rows.value.length ? (
+          <div class={styles.musicGrid}>
+            <MusicGrid
+              list={data.value.rows}
+              onGoto={(n: any) => {
+                router.push({
+                  name: 'music-album-detail',
+                  params: {
+                    id: n.id
+                  }
+                })
+              }}
+            />
+          </div>
+        ) : (
+          !loading.value && (
+            <ColResult tips="暂无专辑" classImgSize="SMALL" btnStatus={false} />
+          )
+        )}
       </List>
     )
   }

+ 26 - 9
src/views/music/personal/album.tsx

@@ -5,11 +5,14 @@ import Item from '../album/item'
 import { useRoute, useRouter } from 'vue-router'
 import ColResult from '@/components/col-result'
 import { state } from '@/state'
+import MusicGrid from '../component/music-grid'
+import styles from './index.module.less'
 
 export default defineComponent({
   name: 'MusicList',
   setup() {
     const route = useRoute()
+    const router = useRouter()
     const params = reactive({
       search: (route.query.search as string) || '',
       musicTagIds: route.query.tagids || '',
@@ -51,15 +54,29 @@ export default defineComponent({
         onLoad={FetchList}
         error={isError.value}
       >
-        {rows.value.length
-          ? rows.value.map(item => <Item data={item} />)
-          : !loading.value && (
-              <ColResult
-                tips="暂无收藏专辑"
-                classImgSize="SMALL"
-                btnStatus={false}
-              />
-            )}
+        {rows.value.length ? (
+          <div class={styles.musicGrid}>
+            <MusicGrid
+              list={data.value.rows}
+              onGoto={(n: any) => {
+                router.push({
+                  name: 'music-album-detail',
+                  params: {
+                    id: n.id
+                  }
+                })
+              }}
+            />
+          </div>
+        ) : (
+          !loading.value && (
+            <ColResult
+              tips="暂无收藏专辑"
+              classImgSize="SMALL"
+              btnStatus={false}
+            />
+          )
+        )}
       </List>
     )
   }

+ 4 - 0
src/views/music/personal/index.module.less

@@ -31,3 +31,7 @@
 .personalSong {
   margin: 14px;
 }
+
+.musicGrid {
+  margin: 16px 12px;
+}

+ 2 - 1
src/views/order-detail/use-coupons/index.tsx

@@ -16,7 +16,8 @@ export const couponEnum = {
   MUSIC: 'MUSIC',
   PRACTICE: 'SPARRING',
   LIVE: 'LIVE',
-  VIDEO: 'VIDEO'
+  VIDEO: 'VIDEO',
+  ALBUM: 'ALBUM'
 }
 
 export default defineComponent({

+ 12 - 0
yarn.lock

@@ -3325,6 +3325,11 @@
     "slice-ansi" "^4.0.0"
     "wrap-ansi" "^6.2.0"
 
+"lottie-web@^5.8.1":
+  "integrity" "sha512-JFs7KsHwflugH5qIXBpB4905yC1Sub2MZWtl/elvO/QC6qj1ApqbUZJyjzJseJUtVpgiDaXQLjBlIJGS7UUUXA=="
+  "resolved" "https://registry.npmmirror.com/lottie-web/-/lottie-web-5.9.6.tgz"
+  "version" "5.9.6"
+
 "lower-case@^2.0.2":
   "integrity" "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="
   "resolved" "https://registry.npmmirror.com/lower-case/-/lower-case-2.0.2.tgz"
@@ -4895,6 +4900,13 @@
     "@vue/server-renderer" "3.2.26"
     "@vue/shared" "3.2.26"
 
+"vue3-lottie@^2.3.0":
+  "integrity" "sha512-pThHpAIxxvk9c5lJXyCgrIAUIy/Xn/XLETqW2yA+VIg5B+phjQkdxkTvRG60pq3zOZ9su2hee+HZgT9tWA+8Fw=="
+  "resolved" "https://registry.npmmirror.com/vue3-lottie/-/vue3-lottie-2.3.0.tgz"
+  "version" "2.3.0"
+  dependencies:
+    "lottie-web" "^5.8.1"
+
 "vuex@^4.0.2":
   "integrity" "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q=="
   "resolved" "https://registry.npmmirror.com/vuex/-/vuex-4.0.2.tgz"

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff