Przeglądaj źródła

Merge branch 'dev' of http://git.dayaedu.com/lex/h5-colexiu into dev

skyblued 3 lat temu
rodzic
commit
693cc5e117

BIN
src/common/images/icon-arrow.png


BIN
src/common/images/icon-play.png


BIN
src/common/images/icon-title.png


BIN
src/common/images/icon_more.png


+ 9 - 1
src/router/index-teacher.ts

@@ -3,7 +3,15 @@ import { createRouter, createWebHashHistory, Router } from 'vue-router'
 import routes from './routes-teacher'
 const router: Router = createRouter({
   history: createWebHashHistory(),
-  routes
+  routes,
+  scrollBehavior(to, from, savedPosition) {
+    if (to.hash) {
+      return {
+        el: to.hash,
+        behavior: 'smooth'
+      }
+    }
+  }
 })
 
 router.beforeEach((to, from, next) => {

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

@@ -146,6 +146,7 @@ export const router = [
   },
   {
     path: '/music-album-detail/:id',
+    name: 'music-album-detail',
     component: () => import('@/views/music/album-detail'),
     meta: {
       title: '专辑详情'

BIN
src/views/music/album-detail/iStart.png


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

@@ -4,6 +4,11 @@
 }
 .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) {
@@ -96,3 +101,94 @@
     margin-top: 0;
   }
 }
+
+.bgImg {
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 265px;
+  object-fit: cover;
+  filter: blur(10px);
+}
+.musicContent {
+  position: absolute;
+  top: 0;
+  height: 265px;
+  width: 100%;
+  padding-top: 55px;
+  z-index: 10;
+  background-color: rgba(0, 0, 0, 0.6);
+  backdrop-filter: blur(20px);
+  -webkit-backdrop-filter: blur(20px);
+}
+
+.bg {
+  position: relative;
+  height: 100%;
+  padding: 16px;
+  z-index: 11;
+}
+.alumWrap {
+  display: flex;
+  align-items: center;
+  .img {
+    width: 115px;
+    height: 115px;
+    flex-shrink: 0;
+    border-radius: 6px;
+    overflow: hidden;
+    margin-right: 14px;
+  }
+  .alumTitle {
+    font-size: 18px;
+    font-weight: 500;
+    color: #fff;
+  }
+  .alumDes {
+    width: calc(100% - 129px);
+    .des {
+      color: #999;
+    }
+  }
+}
+.tags {
+  margin: 6px -2px 24px -2px;
+  .tag {
+    margin: 0 2px;
+    padding: 2px 6px;
+    color: #000;
+    background-color: rgba(113, 138, 147, 1);
+    border-radius: 20px;
+  }
+}
+.alumCollect {
+  display: flex;
+  align-items: center;
+  padding-top: 20px;
+  color: #999;
+  font-size: 14px;
+  img {
+    display: inline-block;
+    width: 20px;
+    height: 20px;
+    margin-right: 6px;
+  }
+  .right {
+    display: flex;
+    align-items: center;
+    margin-left: 26px;
+  }
+}
+.alumnContainer {
+  position: relative;
+  padding: 0 16px;
+  // margin-top: -16px;
+  z-index: 10;
+  .alumnList {
+    padding: 0 12px;
+    border-radius: 18px;
+    background-color: #fff;
+    margin-bottom: 16px;
+  }
+}

+ 143 - 98
src/views/music/album-detail/index.tsx

@@ -1,17 +1,25 @@
 import { defineComponent, nextTick, onMounted, reactive, ref } from 'vue'
-import { useRoute } from 'vue-router'
+import { useRoute, useRouter } from 'vue-router'
 import request from '@/helpers/request'
 import ColHeader from '@/components/col-header'
-import { Button, Icon, Image, List, Sticky } from 'vant'
-import classNames from 'classnames'
-import Footer from '../album/footer'
-import FavoriteIcon from '../album/favorite.svg'
-import FavoritedIcon from '../album/favorited.svg'
+import { Button, Icon, Image, List, NavBar, Sticky } from 'vant'
+// import classNames from 'classnames'
+// import Footer from '../album/footer'
+// import FavoriteIcon from '../album/favorite.svg'
+// import FavoritedIcon from '../album/favorited.svg'
 import styles from './index.module.less'
-import Item from '../list/item'
+// import Item from '../list/item'
 import { useRect } from '@vant/use'
+import { useEventListener, useWindowScroll } from '@vueuse/core'
 import { getRandomKey, musicBuy } from '../music'
 import { state } from '@/state'
+import IconPan from './pan.png'
+import oStart from './oStart.png'
+import iStart from './iStart.png'
+import Title from '../component/title'
+import Song from '../component/song'
+import ColResult from '@/components/col-result'
+import MusicGrid from '../component/music-grid'
 
 const noop = () => {}
 
@@ -25,23 +33,26 @@ export default defineComponent({
   },
   setup({ onItemClick }) {
     localStorage.setItem('behaviorId', getRandomKey())
+    const router = useRouter()
     const params = reactive({
       search: '',
-      page: 1
+      page: 1,
+      rows: 200
     })
     const albumDetail = ref<any>(null)
-    const data = ref<any>(null)
+    // const data = ref<any>(null)
     const rows = ref<any[]>([])
     const loading = ref(false)
-    const finished = ref(false)
+    // const finished = ref(false)
     const isError = ref(false)
     const favorited = ref(0)
     const albumFavoriteCount = ref(0)
     const headers = ref(null)
-    let heights = ref(0)
+    const background = ref<string>('rgba(55, 205, 177, 0)')
+    const heightInfo = ref<any>('auto')
 
     const route = useRoute()
-    const FetchList = async () => {
+    const FetchList = async (id?: any) => {
       if (loading.value) {
         return
       }
@@ -51,14 +62,15 @@ export default defineComponent({
         const res = await request.post('/music/album/detail', {
           prefix:
             state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student',
-          data: { id: route.params.id, ...params }
+          data: { id: id || route.params.id, ...params }
         })
         const { musicSheetList, ...rest } = res.data
-        rows.value = [...rows.value, ...musicSheetList.rows]
-        albumDetail.value = rest
-        data.value = musicSheetList
-        params.page = musicSheetList.pageNo + 1
-        finished.value = musicSheetList.pageNo >= musicSheetList.totalPage
+        rows.value = [...musicSheetList.rows]
+        const musicTagNames = rest?.musicTagNames?.split(',') || []
+        albumDetail.value = {
+          ...rest,
+          musicTagNames
+        }
         favorited.value = rest.favorite
         albumFavoriteCount.value = rest.albumFavoriteCount
       } catch (error) {
@@ -69,6 +81,14 @@ export default defineComponent({
 
     const favoriteLoading = ref(false)
 
+    onMounted(() => {
+      FetchList()
+      useEventListener(document, 'scroll', evt => {
+        const { y } = useWindowScroll()
+        background.value = `rgba(55, 205, 177, ${y.value / 100})`
+      })
+    })
+
     const toggleFavorite = async (id: number) => {
       favoriteLoading.value = true
       try {
@@ -82,95 +102,120 @@ export default defineComponent({
       favoriteLoading.value = false
     }
 
-    onMounted(() => {
-      nextTick(() => {
-        setTimeout(() => {
-          const { height } = useRect(headers as any)
-          console.log(height, 'height')
-          heights.value = height
-        }, 100)
-      })
-    })
-
     return () => {
-      // console.log(albumFavoriteCount.value)
       return (
         <div class={styles.detail}>
-          <Sticky
-            class={[styles.base, 'sticky']}
-            style={{
-              height: heights.value + 'px !important',
-              width: '100%'
-            }}
-          >
-            <div ref={headers}>
-              <ColHeader
-                class={styles.header}
-                background="transparent"
-                color="#fff"
-                title="专辑详情"
-                backIconColor="white"
-                border={false}
-                isFixed={false}
-              />
-              <div class={styles.detailContent}>
-                <div class={classNames(styles.main, 'van-hairline--bottom')}>
-                  <Image
-                    class={styles.img}
-                    src={albumDetail.value?.albumCoverUrl}
-                  />
-                  <div class={styles.content}>
-                    <h4 class="van-ellipsis">{albumDetail.value?.albumName}</h4>
-                    <p class="van-multi-ellipsis--l3">
-                      {albumDetail.value?.albumDesc}
-                    </p>
-                  </div>
+          <div ref={headers}>
+            <ColHeader
+              background={background.value}
+              border={false}
+              color="#fff"
+              backIconColor="white"
+              onHeaderBack={() => {
+                nextTick(() => {
+                  const { height } = useRect(headers as any)
+                  heightInfo.value = height
+                })
+              }}
+            />
+          </div>
+          <img class={styles.bgImg} src={albumDetail.value?.albumCoverUrl} />
+          <div class={styles.musicContent}></div>
+          <div class={styles.bg}>
+            <div class={styles.alumWrap}>
+              <div class={styles.img}>
+                <Image
+                  class={styles.image}
+                  width="100%"
+                  height="100%"
+                  fit="cover"
+                  src={albumDetail.value?.albumCoverUrl}
+                />
+              </div>
+              <div class={styles.alumDes}>
+                <div class={[styles.alumTitle, 'van-ellipsis']}>
+                  {albumDetail.value?.albumName}
                 </div>
-                <div class={styles.footerBar}>
-                  <Footer
-                    musicSheetCount={albumDetail.value?.musicSheetCount}
-                    albumFavoriteCount={albumFavoriteCount.value}
-                  />
-                  {state.platformType === 'STUDENT' && (
-                    <Button
-                      class={styles.favoriteContaineer}
-                      loading={favoriteLoading.value}
-                      onClick={() => toggleFavorite(albumDetail.value?.id)}
-                      size="mini"
-                    >
-                      <Icon
-                        key={favorited.value}
-                        class={styles.favorite}
-                        name={favorited.value ? FavoritedIcon : FavoriteIcon}
-                      />{' '}
-                      <span>{favorited.value ? '已' : ''}收藏</span>
-                    </Button>
-                  )}
+                <div class={styles.tags}>
+                  {albumDetail.value?.musicTagNames?.map((tag: any) => (
+                    <span class={styles.tag}>{tag}</span>
+                  ))}
+                </div>
+                <div
+                  class={[styles.des, 'van-multi-ellipsis--l3']}
+                  style={{
+                    height: '48px',
+                    lineHeight: '16px'
+                  }}
+                >
+                  {albumDetail.value?.albumDesc}
                 </div>
               </div>
             </div>
-          </Sticky>
-          <List
-            loading={loading.value}
-            finished={finished.value}
-            finished-text="没有更多了"
-            onLoad={FetchList}
-          >
-            {rows.value.length
-              ? rows.value.map(item => (
-                  <Item
-                    data={item}
-                    onClick={() => {
-                      if (onItemClick === noop || !onItemClick) {
-                        musicBuy(item)
-                      } else {
-                        onItemClick(item)
-                      }
+            <div class={styles.alumCollect}>
+              <img src={IconPan} />
+              <span>共{albumDetail.value?.musicSheetCount}首曲目</span>
+              <div
+                class={styles.right}
+                onClick={() => toggleFavorite(albumDetail.value?.id)}
+              >
+                <img src={favorited.value ? iStart : oStart} />
+                <span>{albumFavoriteCount.value}人收藏</span>
+              </div>
+            </div>
+          </div>
+          <div class={styles.alumnContainer}>
+            <div class={styles.alumnList}>
+              <Title title="曲目列表" isMore={false} />
+              <Song
+                list={rows.value}
+                onDetail={(item: any) => {
+                  if (onItemClick === noop || !onItemClick) {
+                    musicBuy(item, () => {}, {
+                      albumId: route.params.id
+                    })
+                  } else {
+                    onItemClick(item)
+                  }
+                }}
+              />
+
+              {rows.value && rows.value.length <= 0 && (
+                <ColResult btnStatus={false} tips="暂无曲目列表" />
+              )}
+            </div>
+
+            {albumDetail.value?.relatedMusicAlbum &&
+              albumDetail.value?.relatedMusicAlbum.length > 0 && (
+                <>
+                  <Title
+                    title="相关专辑"
+                    onMore={() => {
+                      router.push({
+                        path: '/music-album'
+                      })
+                    }}
+                  />
+
+                  <MusicGrid
+                    list={albumDetail.value?.relatedMusicAlbum}
+                    onGoto={(n: any) => {
+                      router
+                        .push({
+                          name: 'music-album-detail',
+                          params: {
+                            id: n.id
+                          }
+                        })
+                        .then(() => {
+                          FetchList(n.id)
+                          window.scrollTo(0, 0)
+                        })
                     }}
                   />
-                ))
-              : null}
-          </List>
+                </>
+              )}
+          </div>
         </div>
       )
     }

BIN
src/views/music/album-detail/oStart.png


BIN
src/views/music/album-detail/pan.png


+ 0 - 0
src/views/music/component/collection/index.module.less


+ 13 - 0
src/views/music/component/collection/index.tsx

@@ -0,0 +1,13 @@
+import { Cell, CellGroup } from 'vant'
+import { defineComponent } from 'vue'
+
+export default defineComponent({
+  name: 'Collection',
+  setup() {
+    return () => (
+      <CellGroup>
+        <Cell title={'收藏曲目'} />
+      </CellGroup>
+    )
+  }
+})

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


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


BIN
src/views/music/component/images/icon-xin.png


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


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


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


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


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


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

@@ -0,0 +1,58 @@
+.theMusicGrid {
+  :global {
+    .van-grid {
+      margin: 0 -4px;
+    }
+    .van-grid-item {
+      width: calc(100% / 3);
+    }
+    .van-grid-item__content {
+      display: block;
+      padding: 0 4px;
+      background-color: transparent;
+    }
+  }
+  .item {
+    margin-bottom: 15px;
+    .title {
+      font-size: 14px;
+      color: #333;
+      line-height: 20px;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      margin-bottom: 2px;
+    }
+    .des {
+      font-size: 12px;
+      color: #999;
+      line-height: 16px;
+    }
+  }
+  .imgWrap {
+    position: relative;
+    // height: 110px;
+    height: calc((100vw - 48px) / 3);
+    border-radius: 6px;
+    overflow: hidden;
+    margin-bottom: 6px;
+    .model {
+      position: absolute;
+      left: 4px;
+      bottom: 4px;
+      background: rgba(67, 67, 67, 0.6);
+      backdrop-filter: blur(20px);
+      -webkit-backdrop-filter: blur(20px);
+      display: flex;
+      align-items: center;
+      padding: 4px 6px;
+      border-radius: 20px;
+      font-size: 12px;
+      color: #fff;
+      transform: scale(0.9);
+    }
+    .num {
+      margin-left: 3px;
+    }
+  }
+}

+ 44 - 0
src/views/music/component/music-grid/index.tsx

@@ -0,0 +1,44 @@
+import { Grid, GridItem, Icon, Image, Loading } from 'vant'
+import { defineComponent, PropType } from 'vue'
+import styles from './index.module.less'
+import IconXin from '../images/icon-xin.png'
+
+export default defineComponent({
+  name: 'TheMusicGrid',
+  props: {
+    list: {
+      type: Array as any,
+      default: () => []
+    }
+  },
+  emits: ['goto'],
+  setup(props, { emit }) {
+    return () => (
+      <div class={styles.theMusicGrid}>
+        <Grid border={false} columnNum={3}>
+          {props.list.map((n: any) => (
+            <GridItem>
+              <div class={styles.item} onClick={() => emit('goto', n)}>
+                <div class={styles.imgWrap}>
+                  <Image
+                    class={styles.image}
+                    width="100%"
+                    height="100%"
+                    fit="cover"
+                    src={n.albumCoverUrl}
+                  />
+                  <div class={styles.model}>
+                    <Icon name={IconXin} />
+                    <span class={styles.num}>{n.albumFavoriteCount}人</span>
+                  </div>
+                </div>
+                <div class={styles.title}>{n.albumName}</div>
+                <div class={styles.des}>共{n.musicSheetCount}首</div>
+              </div>
+            </GridItem>
+          ))}
+        </Grid>
+      </div>
+    )
+  }
+})

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

@@ -0,0 +1,160 @@
+.theSong {
+  padding: 0 10px;
+  background-color: #fff;
+  border-radius: 8px;
+  box-shadow: 0px 2px 10px 0px rgba(229, 229, 229, 0.1);
+  // --van-popup-close-icon-z-index: 19;
+  .item {
+    display: flex;
+    align-items: center;
+    border-bottom: 1px solid #e8e8e8;
+    padding: 16px 0;
+  }
+  .item:last-child {
+    border: none;
+  }
+  .content {
+    flex: 1;
+    .top {
+      display: flex;
+      align-items: center;
+      margin-bottom: 10px;
+    }
+    .tag {
+      flex-shrink: 0;
+      padding: 2px 4px;
+      border-radius: 4px;
+    }
+    .user {
+      display: flex;
+      align-items: center;
+      .name {
+        font-size: 12px;
+        color: #999;
+        line-height: 16px;
+        margin-right: 12px;
+      }
+      .tags {
+        & > span {
+          display: inline-block;
+          background: #effbf9;
+          border-radius: 20px;
+          color: var(--van-primary-color);
+          padding: 4px 8px;
+          margin-right: 4px;
+          font-size: 12px;
+          transform: scale(0.9);
+        }
+      }
+    }
+    .title {
+      max-width: 150px;
+      font-size: 16px;
+      font-weight: bold;
+      color: #1a1a1a;
+      margin: 0 6px;
+    }
+    .singer {
+      max-width: 50px;
+      font-size: 12px;
+      color: #999;
+    }
+  }
+
+  .play {
+    flex-shrink: 0;
+    display: flex;
+    align-items: center;
+  }
+}
+
+.pImg {
+  width: 50px;
+  height: 50px;
+  border-radius: 10px;
+  overflow: hidden;
+  flex-shrink: 0;
+}
+
+.info {
+  margin-left: 14px;
+  flex: 1;
+  margin-right: 14px;
+  word-break: break-all;
+  > h4 {
+    color: #1a1a1a;
+    font-size: 14px;
+    font-weight: 600;
+    width: 300px;
+  }
+  > p {
+    color: #999;
+    line-height: 17px;
+  }
+}
+
+.collection {
+  width: 13px;
+  height: 12px;
+  margin-right: 8px;
+}
+
+.musicInfo {
+  padding-top: 23px;
+  padding-bottom: 23px;
+  margin-bottom: 10px;
+}
+
+.shareIcon {
+  display: flex;
+  width: 22px;
+  height: 19px;
+  margin-right: 14px;
+}
+
+.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;
+  }
+}

+ 292 - 0
src/views/music/component/song/index.tsx

@@ -0,0 +1,292 @@
+import { CellGroup, Cell, Icon, Image, Popup, Tag, Toast } from 'vant'
+import { defineComponent, PropType, ref } from 'vue'
+import styles from './index.module.less'
+import IconPlay from '@/common/images/icon-play.png'
+import IconMore from '@/common/images/icon_more.png'
+import { useRouter } from 'vue-router'
+import { state } from '@/state'
+import request from '@/helpers/request'
+import ColShare from '@/components/col-share'
+import MusicIcon from '../../list/icons/music-icon.png'
+export const getAssetsHomeFile = (fileName: string) => {
+  const path = `../images/${fileName}`
+  const modules = import.meta.globEager('../images/*')
+  return modules[path].default
+}
+export default defineComponent({
+  name: 'TheSong',
+  props: {
+    list: {
+      type: Array as PropType<any[]>,
+      default: () => []
+    }
+  },
+  emits: ['detail'],
+  setup(props, { emit }) {
+    const isMore = ref<boolean>(false)
+    const moreData = ref<any>({})
+    const router = useRouter()
+    const colors: any = {
+      FREE: {
+        color: '#01B84F',
+        text: '免费'
+      },
+      VIP: {
+        color: '#CD863E',
+        text: '会员'
+      },
+      CHARGE: {
+        color: '#3591CE',
+        text: '点播'
+      }
+    }
+
+    const toggleFavorite = async () => {
+      try {
+        await request.post('/music/sheet/favorite/' + moreData.value.id, {
+          prefix:
+            state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student'
+        })
+        moreData.value.favorite = moreData.value.favorite ? 0 : 1
+        setTimeout(() => {
+          Toast(moreData.value.favorite ? '收藏成功' : '取消收藏成功')
+          isMore.value = false
+        }, 100)
+      } catch (error) {}
+    }
+
+    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: moreData.value.id,
+            userId: state.user.data?.userId
+          }
+        })
+        let url =
+          location.origin +
+          `/accompany/colexiu-share.html?id=${moreData.value.id}&recomUserId=${state.user.data?.userId}`
+        // 判断是否有活动
+        if (res.data.discount === 1) {
+          url += `&activityId=${res.data.activityId}`
+        }
+        shareDiscount.value = res.data.discount || 0
+        shareUrl.value = url
+        isMore.value = false
+        shareStatus.value = true
+        return
+      } catch {}
+    }
+
+    return () => (
+      <div class={styles.theSong}>
+        {props.list.map((n: any) => (
+          <div class={styles.item} onClick={() => emit('detail', n)}>
+            <div class={styles.content}>
+              <div class={styles.top}>
+                <Tag
+                  style={{ color: colors[n.chargeType].color }}
+                  class={styles.tag}
+                  type="success"
+                  plain
+                >
+                  {colors[n.chargeType].text}
+                </Tag>
+                <span class={[styles.title, 'van-ellipsis']}>
+                  {n.musicSheetName}
+                </span>
+                <span class={[styles.singer, 'van-ellipsis']}>
+                  -{n.composer}
+                </span>
+              </div>
+              <div class={styles.user}>
+                {n.favorite === 1 && (
+                  <Image
+                    src={getAssetsHomeFile('collection_active.png')}
+                    class={styles.collection}
+                  />
+                )}
+                {n.addName ? (
+                  <span class={styles.name}>上传者:{n.addName}</span>
+                ) : (
+                  <span class={styles.name}>作曲:{n.composer}</span>
+                )}
+                <div class={styles.tags}>
+                  {n?.subjectNames.split(',').map((name: any) => (
+                    <span>{name}</span>
+                  ))}
+                </div>
+              </div>
+            </div>
+            <div class={styles.play}>
+              <Icon name={IconPlay} size={28} />
+
+              <Icon
+                name={IconMore}
+                size={18}
+                style={{ marginLeft: '12px  ' }}
+                onClick={() => {
+                  isMore.value = true
+                  moreData.value = n
+                }}
+              />
+            </div>
+          </div>
+        ))}
+
+        <Popup v-model:show={isMore.value} position="bottom" round>
+          <CellGroup border={false}>
+            <Cell
+              center
+              class={styles.musicInfo}
+              v-slots={{
+                icon: () => (
+                  <Image class={styles.pImg} src={moreData?.value.titleImg} />
+                ),
+                title: () => (
+                  <div class={styles.info}>
+                    <h4 class="van-ellipsis">
+                      {moreData?.value.musicSheetName}
+                    </h4>
+                    <p>
+                      <Tag
+                        style={{
+                          color: colors[moreData?.value.chargeType].color,
+                          marginRight: '6px'
+                        }}
+                        class={styles.tag}
+                        type="success"
+                        plain
+                      >
+                        {colors[moreData?.value.chargeType].text}
+                      </Tag>
+                      {moreData?.value.composer}
+                    </p>
+                  </div>
+                )
+              }}
+            />
+            {state.platformType === 'STUDENT' && (
+              <Cell
+                border={false}
+                size="large"
+                title={moreData.value.favorite ? '取消收藏' : '收藏曲目'}
+                center
+                onClick={() => toggleFavorite()}
+                v-slots={{
+                  icon: () => (
+                    <div class={styles.shareIcon}>
+                      <Image
+                        src={
+                          moreData.value.favorite
+                            ? getAssetsHomeFile('collection_active.png')
+                            : getAssetsHomeFile('collection.png')
+                        }
+                      />
+                    </div>
+                  )
+                }}
+              />
+            )}
+            {state.platformType !== 'TEACHER' && (
+              <Cell
+                border={false}
+                size="large"
+                title={'分享曲目'}
+                onClick={() => onShare()}
+                v-slots={{
+                  icon: () => (
+                    <div class={styles.shareIcon}>
+                      <Image src={getAssetsHomeFile('icon_share.png')} />
+                    </div>
+                  )
+                }}
+              />
+            )}
+
+            <Cell
+              border={false}
+              size="large"
+              title={`作曲:${moreData.value?.composer}`}
+              v-slots={{
+                icon: () => (
+                  <div class={styles.shareIcon}>
+                    <Image src={getAssetsHomeFile('icon_author.png')} />
+                  </div>
+                )
+              }}
+            />
+            <Cell
+              border={false}
+              size="large"
+              title={`上传:${moreData.value?.addName || '--'}`}
+              v-slots={{
+                icon: () => (
+                  <div class={styles.shareIcon}>
+                    <Image src={getAssetsHomeFile('icon_uploader.png')} />
+                  </div>
+                )
+              }}
+            />
+            <Cell
+              border={false}
+              size="large"
+              title={'小酷Ai练习'}
+              isLink
+              style={{ marginBottom: '30px' }}
+              onClick={() => {
+                isMore.value = false
+                emit('detail', moreData.value)
+              }}
+              v-slots={{
+                icon: () => (
+                  <div class={styles.shareIcon}>
+                    <Image src={getAssetsHomeFile('icon_ai.png')} />
+                  </div>
+                )
+              }}
+            />
+          </CellGroup>
+        </Popup>
+
+        <Popup
+          v-model:show={shareStatus.value}
+          style={{ background: 'transparent' }}
+          teleport="body"
+        >
+          <ColShare
+            teacherId={moreData.value?.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={
+                  moreData.value?.titleImg +
+                    `@base@tag=imgScale&h=80&w=80&m=1?t=${+new Date()}` ||
+                  MusicIcon
+                }
+              />
+              <div class={styles.info}>
+                <h4 class="van-multi-ellipsis--l2">
+                  {moreData.value?.musicSheetName}
+                </h4>
+                <p>作曲人:{moreData.value?.composer}</p>
+              </div>
+            </div>
+          </ColShare>
+        </Popup>
+      </div>
+    )
+  }
+})

+ 29 - 0
src/views/music/component/title/index.module.less

@@ -0,0 +1,29 @@
+.theTitle {
+  display: flex;
+  align-items: center;
+  padding: 15px 0;
+  .title {
+    font-size: 18px;
+    font-weight: bold;
+    color: #1d1f26;
+  }
+  .img {
+    display: inline-block;
+    width: 21px;
+    height: 14px;
+    margin-left: 4px;
+  }
+  .more {
+    display: flex;
+    align-items: center;
+    margin-left: auto;
+    font-size: 16px;
+    color: #1d1f26;
+    font-weight: 400;
+    :global {
+      .van-icon {
+        margin-left: 6px;
+      }
+    }
+  }
+}

+ 40 - 0
src/views/music/component/title/index.tsx

@@ -0,0 +1,40 @@
+import { defineComponent } from 'vue'
+import styles from './index.module.less'
+import IconTitle from '@/common/images/icon-title.png'
+import { Icon } from 'vant'
+import IconArrow from '@/common/images/icon-arrow.png'
+
+export default defineComponent({
+  name: 'TheTitle',
+  props: {
+    title: {
+      type: String
+    },
+    isMore: {
+      type: Boolean,
+      default: true
+    },
+    onMore: {
+      type: Function
+    }
+  },
+  setup(props) {
+    return () => (
+      <div class={styles.theTitle}>
+        <div class={styles.title}>{props.title}</div>
+        <img src={IconTitle} class={styles.img} />
+        {props.isMore && (
+          <div
+            class={styles.more}
+            onClick={() => {
+              props.onMore && props.onMore()
+            }}
+          >
+            <span>更多</span>
+            <Icon name={IconArrow} size={17} />
+          </div>
+        )}
+      </div>
+    )
+  }
+})

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

@@ -22,6 +22,7 @@ export const musicBuy = (item: any, callBack?: any, moreQuery = {}) => {
       ...moreQuery
     }
   })
+  console.log(url)
   postMessage({
     api: 'openAccompanyWebView',
     content: {