瀏覽代碼

专辑详情 - 曲目列表(50%) - 首页统计

lex-xin 3 月之前
父節點
當前提交
d4b93c4f48

+ 185 - 74
src/teacher/statistics/home-statistics/index.tsx

@@ -1,14 +1,21 @@
-import { defineComponent, nextTick, onMounted, ref } from "vue";
-import styles from './index.module.less';
-import icon1 from '../images/icon1.png';
-import iconArrow from '../images/icon-arrow.png';
-import iconArrow1 from '../images/icon-arrow1.png';
-import iconArrow11 from '../images/icon-arrow1-1.png';
-import { Popover } from "vant";
+import {
+  computed,
+  defineComponent,
+  nextTick,
+  onMounted,
+  reactive,
+  ref
+} from 'vue'
+import styles from './index.module.less'
+import icon1 from '../images/icon1.png'
+import iconArrow from '../images/icon-arrow.png'
+import iconArrow1 from '../images/icon-arrow1.png'
+import iconArrow11 from '../images/icon-arrow1-1.png'
+import { Popover } from 'vant'
 
 import * as echarts from 'echarts/core'
 import {
-  LineChart,
+  LineChart
   // LineSeriesOption
 } from 'echarts/charts'
 // import { PieChart } from 'echarts/charts'
@@ -30,7 +37,12 @@ import {
 } from 'echarts/components'
 import { LabelLayout } from 'echarts/features'
 import { CanvasRenderer } from 'echarts/renderers'
-import { format } from "path";
+import { format } from 'path'
+import request from '@/helpers/request'
+import dayjs from 'dayjs'
+import { postMessage } from '@/helpers/native-message'
+import { browser } from '@/helpers/utils'
+import { useRouter } from 'vue-router'
 
 // 注册必须的组件
 echarts.use([
@@ -52,9 +64,9 @@ echarts.use([
 const lineChartOption = (xAxisData: any, seriesData: any) => {
   return {
     title: {
-      text: "单位:次",
+      text: '单位:次',
       textStyle: {
-        color: "#777777",
+        color: '#777777',
         fontSize: 13,
         fontWeight: 400
       }
@@ -70,7 +82,7 @@ const lineChartOption = (xAxisData: any, seriesData: any) => {
     },
     color: [
       '#2DC7AA',
-      '#FF6079',
+      '#FF6079'
       // '#2DC7AA',
       // '#FF602C',
       // '#91DD1C',
@@ -132,7 +144,7 @@ const lineChartOption = (xAxisData: any, seriesData: any) => {
       trigger: 'axis',
       confine: true,
       formatter: function (params: any) {
-        return params[0].name;
+        return params[0].name
       },
       backgroundColor: '#FF6079',
       borderWidth: 0,
@@ -155,68 +167,103 @@ const lineChartOption = (xAxisData: any, seriesData: any) => {
   }
 }
 
+/** 获取时间范围 */
+export const getTimeRange = (
+  type: 'MONTH' | 'THREE_MONTH' | 'HALF_YEAR' | 'YEAR'
+) => {
+  if (type === 'MONTH') {
+    return {
+      startTime: dayjs().format('YYYY-MM') + '-01',
+      endTime: dayjs().format('YYYY-MM-DD')
+    }
+  } else if (type === 'THREE_MONTH') {
+    return {
+      startTime: dayjs().subtract(3, 'month').format('YYYY-MM-DD'),
+      endTime: dayjs().format('YYYY-MM-DD')
+    }
+  } else if (type === 'HALF_YEAR') {
+    return {
+      startTime: dayjs().subtract(6, 'month').format('YYYY-MM-DD'),
+      endTime: dayjs().format('YYYY-MM-DD')
+    }
+  } else if (type === 'YEAR') {
+    return {
+      startTime: dayjs().subtract(1, 'year').format('YYYY-MM-DD'),
+      endTime: dayjs().format('YYYY-MM-DD')
+    }
+  }
+}
+
 export default defineComponent({
   name: 'HomeStatistics',
   setup() {
-    const popoverStatus = ref(false);
+    const router = useRouter()
+    const popoverStatus = ref(false)
+    const currentType = ref<'MONTH' | 'THREE_MONTH' | 'HALF_YEAR' | 'YEAR'>(
+      'MONTH'
+    )
+    const timeRange = ref(getTimeRange(currentType.value))
     const statisticCounts = ref({
       browseCount: 0,
       buyCount: 0
     })
     let myChart: echarts.ECharts
-
     nextTick(() => {
-      myChart = echarts.init(document.getElementById('eChart') as HTMLDivElement)
+      myChart = echarts.init(
+        document.getElementById('eChart') as HTMLDivElement
+      )
+      getDetail()
+    })
+
+    const searchText = computed(() => {
+      const template = {
+        MONTH: '本月',
+        THREE_MONTH: '近三个月',
+        HALF_YEAR: '近年半',
+        YEAR: '近一年'
+      }
+      return template[currentType.value]
     })
 
-    onMounted(() => {
-      nextTick(() => {
+    const getDetail = async () => {
+      try {
+        const { data } = await request.post(
+          '/api-teacher/home/courseExposure',
+          {
+            data: timeRange.value
+          }
+        )
+
+        const buy = data.buy || []
+        const exposure = data.exposure || []
+        const xAxisData: string[] = []
+        const exposureList: number[] = []
+        exposure.forEach((item: any, index: number) => {
+          xAxisData.push(item.date)
+          exposureList.push(item.exposureNum)
+
+          if(exposure.length - 1 === index) {
+            statisticCounts.value.browseCount = item.exposureNum
+          }
+        })
+        const buyList: number[] = []
+        buy.forEach((item: any, index: number) => {
+          buyList.push(item.exposureNum)
+
+          if(buy.length - 1 === index) {
+            statisticCounts.value.buyCount = item.exposureNum
+          }
+        })
+        const yAxisData = [exposureList, buyList]
+
         myChart.clear()
-        lineChartOption && myChart.setOption(lineChartOption([
-        '01月',
-        '02月',
-        '03月',
-        '04月',
-        '05月',
-        '06月',
-        '07月',
-        '08月',
-        '09月',
-        '10月',
-        '11月',
-        '12月'
-      ], [[
-        '0',
-        '0',
-        '0',
-        '0',
-        '0',
-        '0',
-        '0',
-        '2',
-        '0',
-        '8',
-        '10',
-        '0'
-      ], [
-        '0',
-        '0',
-        '0',
-        '0',
-        '1',
-        '3',
-        '0',
-        '2',
-        '0',
-        '8',
-        '10',
-        '0'
-      ]]))
+        lineChartOption &&
+          myChart.setOption(lineChartOption(xAxisData, yAxisData))
         myChart.on('highlight', function (params: any) {
           const batch = params.batch || []
           const options: any = myChart.getOption()
           batch.forEach((item: any) => {
-            const batchIndex = item.dataIndex;
+            const batchIndex = item.dataIndex
 
             const browseCount = options.series[0].data[batchIndex]
             const buyCount = options.series[1].data[batchIndex]
@@ -226,10 +273,36 @@ export default defineComponent({
             }
           })
         })
-      })
-    })
+      } catch {
+        //
+      }
+    }
 
+    const onChangeTime = (
+      type: 'MONTH' | 'THREE_MONTH' | 'HALF_YEAR' | 'YEAR'
+    ) => {
+      popoverStatus.value = false
+      if (currentType.value === type) return
+      currentType.value = type
+      timeRange.value = getTimeRange(currentType.value)
+      getDetail()
+    }
 
+    /** 跳转详情 */
+    const goDetail = () => {
+      if(browser().isApp) {
+        postMessage({
+          api: 'openWebView',
+          content: {
+            url: `${location.origin}/teacher/#/home-statistics-detail`,
+            orientation: 1,
+            isHideTitle: false
+          }
+        })
+      } else {
+        router.push({ path: '/home-statistics-detail' })
+      }
+    }
     return () => (
       <div class={styles.homeStatistics}>
         <div class={styles.homeHead}>
@@ -238,7 +311,7 @@ export default defineComponent({
             <span>浏览/购买</span>
           </div>
 
-          <div class={styles.more}>
+          <div class={styles.more} onClick={goDetail}>
             <span>详情</span>
             <img src={iconArrow} />
           </div>
@@ -250,12 +323,16 @@ export default defineComponent({
               <div class={styles.item} style="--color: #2DC7AA">
                 <span class={styles.line}></span>
                 <span class={styles.text}>浏览次数</span>
-                <span class={styles.num}>{statisticCounts.value.browseCount}次</span>
+                <span class={styles.num}>
+                  {statisticCounts.value.browseCount}次
+                </span>
               </div>
               <div class={styles.item} style="--color: #FF6079">
                 <span class={styles.line}></span>
                 <span class={styles.text}>购买次数</span>
-                <span class={styles.num}>{statisticCounts.value.buyCount}次</span>
+                <span class={styles.num}>
+                  {statisticCounts.value.buyCount}次
+                </span>
               </div>
             </div>
             <div class={styles.right}>
@@ -263,15 +340,49 @@ export default defineComponent({
                 {{
                   default: () => (
                     <div class={'select-time'}>
-                      <span>本月</span>
-                      <span class={'active'}>近三个月</span>
-                      <span>近半年</span>
-                      <span>近一年</span>
-                    </div>),
-                  reference: () => (<div class={[styles.showItem, popoverStatus.value && styles.showItemActive]}>
-                    <span>本月</span>
-                    <img src={popoverStatus.value?iconArrow11 : iconArrow1} />
-                  </div>)
+                      <span
+                        onClick={() => onChangeTime('MONTH')}
+                        class={currentType.value === 'MONTH' ? 'active' : ''}
+                      >
+                        本月
+                      </span>
+                      <span
+                        onClick={() => onChangeTime('THREE_MONTH')}
+                        class={
+                          currentType.value === 'THREE_MONTH' ? 'active' : ''
+                        }
+                      >
+                        近三个月
+                      </span>
+                      <span
+                        onClick={() => onChangeTime('HALF_YEAR')}
+                        class={
+                          currentType.value === 'HALF_YEAR' ? 'active' : ''
+                        }
+                      >
+                        近半年
+                      </span>
+                      <span
+                        onClick={() => onChangeTime('YEAR')}
+                        class={currentType.value === 'YEAR' ? 'active' : ''}
+                      >
+                        近一年
+                      </span>
+                    </div>
+                  ),
+                  reference: () => (
+                    <div
+                      class={[
+                        styles.showItem,
+                        popoverStatus.value && styles.showItemActive
+                      ]}
+                    >
+                      <span>{searchText.value}</span>
+                      <img
+                        src={popoverStatus.value ? iconArrow11 : iconArrow1}
+                      />
+                    </div>
+                  )
                 }}
               </Popover>
             </div>
@@ -284,4 +395,4 @@ export default defineComponent({
       </div>
     )
   }
-})
+})

+ 77 - 4
src/views/music/album-detail/index.module.less

@@ -5,11 +5,18 @@
 
 .detail {
   overflow: hidden;
-
+  min-height: 100vh;
+  background-color: #fff;
   --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;
+
+  :global {
+    .btnMore {
+      justify-content: space-between;
+    }
+  }
 }
 
 .base {
@@ -193,7 +200,7 @@
     font-size: 18px;
     font-weight: 500;
     color: #fff;
-    padding-bottom: 8px;
+    padding-bottom: 6px;
   }
 
   .alumDes {
@@ -206,7 +213,7 @@
 }
 
 .tags {
-  margin: 6px -2px 22px -2px;
+  margin: 0 0 12px 0;
 
   .tag {
     margin: 0 2px;
@@ -214,6 +221,18 @@
     color: #000;
     background-color: rgba(113, 138, 147, 1);
     border-radius: 20px;
+    display: inline-block;
+  }
+}
+
+.btnGroup {
+  padding: 10px 28px 30px;
+  background-color: #fff;
+  box-shadow: 0px 0px 2px 0px rgba(216,216,216,0.5);
+  :global {
+    .van-button {
+      font-size: 16px;
+    }
   }
 }
 
@@ -263,7 +282,7 @@
 
 .alumnContainer {
   position: relative;
-  padding: 0 16px;
+  padding: 0;
   // margin-top: -16px;
   z-index: 12;
 
@@ -272,6 +291,60 @@
     border-radius: 18px;
     background-color: #fff;
     margin-bottom: 16px;
+    min-height: 300px;
+  }
+
+  .searchSection {
+    :global {
+      .van-search {
+        padding-left: 0;
+        padding-right: 0;
+      }
+
+      .van-dropdown-menu__bar {
+        box-shadow: none;
+        padding-right: 12px;
+      }
+      .van-dropdown-menu__title {
+        padding-left: 0;
+      }
+      .van-dropdown-item {
+        --van-dropdown-item-z-index: 100;
+      }
+
+      .van-dropdown-item__content {
+        --van-dropdown-menu-content-max-height: 322px;
+        border-bottom-left-radius: 20px;
+        border-bottom-right-radius: 20px;
+        margin-top: -1px;
+      }
+      .van-overlay {
+        top: 1px;
+      }
+    }
+
+    // .label {
+    //   margin-right: 8px;
+    //   font-size: 14px;
+    //   color: #131415;
+
+    //   &.labelActive {
+    //     color: #2DC7AA;
+    //     :global {
+    //       .iconfont-down {
+    //         transform: rotate(180deg);
+    //         color: #2DC7AA;
+    //       }
+    //     }
+    //   }
+    //   :global {
+    //     .iconfont-down {
+    //       font-size: 12px;
+    //       margin-left: 4px;
+    //       color: #999;
+    //     }
+    //   }
+    // }
   }
 
   .subjectSearch {

+ 165 - 76
src/views/music/album-detail/index.tsx

@@ -10,7 +10,18 @@ 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, Dialog, Icon, Image, List, NavBar, Popup, Sticky } from 'vant'
+import {
+  Button,
+  Dialog,
+  DropdownItem,
+  DropdownMenu,
+  Icon,
+  Image,
+  List,
+  NavBar,
+  Popup,
+  Sticky
+} from 'vant'
 // import classNames from 'classnames'
 // import Footer from '../album/footer'
 // import FavoriteIcon from '../album/favorite.svg'
@@ -24,21 +35,24 @@ import { openDefaultWebView, state } from '@/state'
 import IconPan from './pan.png'
 import oStart from './oStart.png'
 import iStart from './iStart.png'
-import Title from '../component/title'
+// import Title from '../component/title'
 import Song from '../component/song'
 import ColResult from '@/components/col-result'
-import MusicGrid from '../component/music-grid'
+// import MusicGrid from '../component/music-grid'
 import { useEventTracking } from '@/helpers/hooks'
-import ColSticky from '@/components/col-sticky'
+// import ColSticky from '@/components/col-sticky'
 import { moneyFormat } from '@/helpers/utils'
 import { orderStatus } from '@/views/order-detail/orderStatus'
 import iconShare from '../album/icon_share.svg'
 import iconShare2 from '../album/icon_share2.svg'
 import ColShare from '@/components/col-share'
-import iconShareMusic from '/src/views/music/component/images/icon_album_active.png'
+// import iconShareMusic from '/src/views/music/component/images/icon_album_active.png'
 import SongShare from '../component/song-share'
 import icon_music_list from './icon_music_list.png'
 import SelectSubject from '../search/select-subject'
+import TheSticky from '@/components/the-sticky'
+import ColSearch from '@/components/col-search'
+import SearchGroup from './search-group'
 
 const noop = () => {}
 
@@ -56,17 +70,20 @@ export default defineComponent({
     const route = useRoute()
     const params = reactive({
       search: '',
-      relatedNum: 6, //相关专辑数
+      // relatedNum: 6, //相关专辑数
+      musicSheetName: '',
+      albumCategoryLevelId: null,
+      albumCategoryTypeId: null,
       page: 1,
-      rows: 200
+      rows: 20
     })
+    const title = ref(' ')
     const albumDetail = ref<any>(null)
-    // const data = ref<any>(null)
     const rows = ref<any[]>([])
     const loading = ref(false)
     const aId = Number(route.query.activityId) || 0
     const studentActivityId = ref(aId)
-    // const finished = ref(false)
+    const finished = ref(false)
     const isError = ref(false)
     const favorited = ref(0)
     const albumFavoriteCount = ref(0)
@@ -74,18 +91,19 @@ export default defineComponent({
     const background = ref<string>('rgba(55, 205, 177, 0)')
     const color = ref<string>('#fff')
     const heightInfo = ref<any>('auto')
+
+    const dropdownItemRef = ref()
+
     const subjects = reactive({
       show: false,
       name: route.query.subjectName || '全部声部',
       id: route.query.subjectId || null
     })
 
-    const FetchList = async (id?: any) => {
-      if (loading.value) {
-        return
-      }
-      loading.value = true
-      isError.value = false
+    const albumLevel = ref([])
+    const albumType = ref([])
+
+    const FetchDetail = async (id?: any) => {
       try {
         const res = await request.post('/music/album/detail', {
           prefix:
@@ -93,11 +111,13 @@ export default defineComponent({
           data: {
             id: id || route.params.id,
             ...params,
+            queryMusicSheet: false,
+            queryCategory: true,
+            queryRelatedAlbum: false,
             subjectIds: subjects.id
           }
         })
-        const { musicSheetList, ...rest } = res.data
-        rows.value = [...musicSheetList.rows]
+        const { albumLevelList, albumTypeList, ...rest } = res.data
         const musicTagNames = rest?.musicTagNames
           ? rest?.musicTagNames?.split(',')
           : []
@@ -105,8 +125,36 @@ export default defineComponent({
           ...rest,
           musicTagNames
         }
+        albumLevel.value = albumLevelList || []
+        albumType.value = albumTypeList || []
+
         favorited.value = rest.favorite
         albumFavoriteCount.value = rest.albumFavoriteCount
+      } catch {
+        //
+      }
+    }
+
+    const FetchList = async (id?: any) => {
+      if (loading.value) {
+        return
+      }
+      loading.value = true
+      isError.value = false
+      try {
+        const { data } = await request.post('/music/album/musicPage', {
+          prefix:
+            state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student',
+          data: {
+            id: id || route.params.id,
+            ...params,
+            subjectIds: subjects.id
+          }
+        })
+        const result = (rows.value || []).concat(data.rows || [])
+        rows.value = result
+        params.page = data.pageNo + 1
+        finished.value = data.pageNo >= data.totalPage
       } catch (error) {
         isError.value = true
       }
@@ -115,30 +163,23 @@ export default defineComponent({
 
     const favoriteLoading = ref(false)
 
-    onMounted(() => {
-      FetchList()
-      useEventListener(document, 'scroll', evt => {
-        const { y } = useWindowScroll()
-        if (y.value > 20) {
-          background.value = `rgba(255, 255, 255)`
-          color.value = 'black'
-          // postMessage({
-          //   api: 'backIconChange',
-          //   content: { iconStyle: 'black' }
-          // })
-        } else {
-          background.value = 'transparent'
-          color.value = '#fff'
-          // postMessage({
-          //   api: 'backIconChange',
-          //   content: { iconStyle: 'white' }
-          // })
-        }
-      })
-
-      useEventTracking('专辑')
+    FetchDetail()
+    FetchList()
+    useEventListener(document, 'scroll', () => {
+      const { y } = useWindowScroll()
+      if (y.value > 20) {
+        background.value = `rgba(255, 255, 255)`
+        color.value = 'black'
+        title.value = albumDetail.value?.albumName || ' '
+      } else {
+        background.value = 'transparent'
+        color.value = '#fff'
+        title.value = ' '
+      }
     })
 
+    useEventTracking('专辑')
+
     const toggleFavorite = async (id: number) => {
       favoriteLoading.value = true
       try {
@@ -173,7 +214,7 @@ export default defineComponent({
 
       const res = await request.post('/userOrder/getPendingOrder', {
         prefix:
-            state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student',
+          state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student',
         data: {
           goodType: 'ALBUM',
           bizId: album.id
@@ -251,7 +292,6 @@ export default defineComponent({
       const userId = state.user.data.userId
       const id = route.params.id
       let activityId = 0
-      console.log(state.user, userId)
       if (state.platformType === 'TEACHER') {
         const res = await request.post('/api-teacher/open/vipProfit', {
           data: {
@@ -286,6 +326,7 @@ export default defineComponent({
             <ColHeader
               background={background.value}
               border={false}
+              title={title.value}
               color={color.value}
               backIconColor="white"
               onHeaderBack={() => {
@@ -372,7 +413,7 @@ export default defineComponent({
           </div>
           <div class={styles.alumnContainer}>
             <div class={styles.alumnList}>
-              <Title title="曲目列表" isMore={false}>
+              {/* <Title title="曲目列表" isMore={false}>
                 {{
                   right: () =>
                     albumDetail.value?.albumType === 'CONCERT' && (
@@ -387,39 +428,88 @@ export default defineComponent({
                       </div>
                     )
                 }}
-              </Title>
-              <Song
-                list={rows.value}
-                onDetail={(item: any) => {
-                  if (onItemClick === noop || !onItemClick) {
-                    const url =
-                      location.origin +
-                      location.pathname +
-                      '#/music-detail?id=' +
-                      item.id +
-                      '&albumId=' +
-                      route.params.id
-                    openDefaultWebView(url, () => {
-                      router.push({
-                        path: '/music-detail',
-                        query: {
-                          id: item.id,
-                          albumId: route.params.id
-                        }
-                      })
-                    })
-                  } else {
-                    onItemClick(item)
-                  }
+              </Title> */}
+              <ColSearch
+                class={styles.searchSection}
+                background="transparent"
+                placeholder="请输入曲目关键词"
+                onSearch={(val: string) => {
+                  params.musicSheetName = val
+                  rows.value = []
+                  params.page = 1
+                  FetchList()
+                }}
+                v-slots={{
+                  left: () =>
+                    albumLevel.value.length > 0 ||
+                    albumType.value.length > 0 ? (
+                      <DropdownMenu activeColor="#2DC7AA">
+                        <DropdownItem title="筛选" ref={dropdownItemRef}>
+                          <SearchGroup
+                            searchList={{
+                              albumLevelList: albumLevel.value,
+                              albumTypeList: albumType.value
+                            }}
+                            searchObj={{
+                              albumCategoryLevelId: params.albumCategoryLevelId,
+                              albumCategoryTypeId: params.albumCategoryTypeId
+                            }}
+                            onConfirm={(val: any) => {
+                              params.albumCategoryLevelId =
+                                val.albumCategoryLevelId
+                              params.albumCategoryTypeId =
+                                val.albumCategoryTypeId
+                              dropdownItemRef.value?.toggle()
+                              rows.value = []
+                              params.page = 1
+                              FetchList()
+                            }}
+                          />
+                        </DropdownItem>
+                      </DropdownMenu>
+                    ) : (
+                      ''
+                    )
                 }}
               />
-
-              {rows.value && rows.value.length <= 0 && (
-                <ColResult btnStatus={false} tips="暂无曲目" />
-              )}
+              <List
+                loading={loading.value}
+                finished={finished.value}
+                onLoad={FetchList}
+                error={isError.value}
+              >
+                <Song
+                  list={rows.value}
+                  onDetail={(item: any) => {
+                    if (onItemClick === noop || !onItemClick) {
+                      const url =
+                        location.origin +
+                        location.pathname +
+                        '#/music-detail?id=' +
+                        item.id +
+                        '&albumId=' +
+                        route.params.id
+                      openDefaultWebView(url, () => {
+                        router.push({
+                          path: '/music-detail',
+                          query: {
+                            id: item.id,
+                            albumId: route.params.id
+                          }
+                        })
+                      })
+                    } else {
+                      onItemClick(item)
+                    }
+                  }}
+                />
+                {rows.value && !loading.value && rows.value.length <= 0 && (
+                  <ColResult btnStatus={false} tips="暂无曲目" />
+                )}
+              </List>
             </div>
 
-            {albumDetail.value?.relatedMusicAlbum &&
+            {/* {albumDetail.value?.relatedMusicAlbum &&
               albumDetail.value?.relatedMusicAlbum.length > 0 && (
                 <>
                   <Title
@@ -448,21 +538,20 @@ export default defineComponent({
                     }}
                   />
                 </>
-              )}
+              )} */}
           </div>
 
           {/* 判断是否是收费 是否是已经购买 */}
           {albumDetail.value?.paymentType === 'CHARGE' &&
             albumDetail.value?.orderStatus !== 'PAID' && (
-              <ColSticky position="bottom" background="white">
+              <TheSticky position="bottom">
                 <div
                   class={[
-                    'btnGroup',
+                    styles.btnGroup,
                     buyVip.value &&
                       !(state.user.data.userVip?.vipType !== 'NOT_VIP') &&
                       'btnMore'
                   ]}
-                  style={{ padding: '0' }}
                 >
                   <Button
                     block
@@ -496,7 +585,7 @@ export default defineComponent({
                       </Button>
                     )}
                 </div>
-              </ColSticky>
+              </TheSticky>
             )}
 
           <Popup

+ 125 - 0
src/views/music/album-detail/search-group/index.module.less

@@ -0,0 +1,125 @@
+
+.popupContainer {
+  .popupSection {
+    padding: 0 16px 18px;
+
+    &:first-child {
+      padding-top: 10px;
+    }
+    .title {
+      display: flex;
+      justify-content: space-between;
+      padding-bottom: 10px;
+      span {
+        display: flex;
+        align-items: center;
+        font-weight: 600;
+        font-size: 15px;
+        color: #333333;
+        line-height: 18px;
+        &::before {
+          content: '';
+          display: inline-block;
+          width: 3px;
+          height: 12px;
+          background: linear-gradient(180deg, #59e5d4 0%, #2dc7aa 100%);
+          border-radius: 2px;
+          margin-right: 4px;
+        }
+      }
+    }
+
+    .timeCount {
+      display: flex;
+      align-items: center;
+
+      p {
+        margin-left: 10px;
+        flex: 1;
+        background: #f8f8f8;
+        border: 1px solid #f8f8f8;
+        border-radius: 4px;
+        font-size: 13px;
+        color: #999999;
+        line-height: 18px;
+        text-align: center;
+        padding: 6px 0;
+        &:first-child {
+          margin-left: 0;
+        }
+
+        &.active {
+          background: #e9fff8;
+          border-radius: 4px;
+          border: 1px solid #2dc7aa;
+          color: #2dc7aa;
+        }
+      }
+    }
+
+    .timeSubject {
+      flex-wrap: wrap;
+      margin-left: -5px;
+      margin-right: -5px;
+      p {
+        width: calc(33.333% - 10px);
+        padding: 6px 3px;
+        margin: 0 5px;
+        flex: none;
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        margin-bottom: 9px;
+        box-sizing: border-box;
+        &:first-child {
+          margin-left: 5px;
+        }
+
+      }
+    }
+
+    .timeRang {
+      margin-top: 10px;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+
+      .timeInput {
+        width: 159px;
+        line-height: 32px;
+        text-align: center;
+        background: #f8f8f8;
+        border-radius: 4px;
+        font-size: 13px;
+        color: #999999;
+        cursor: pointer;
+      }
+
+      .timeUnit {
+        width: 12px;
+        height: 1px;
+        background: #d0d0d0;
+      }
+    }
+  }
+
+  .popupBottom {
+    position: sticky;
+    z-index: 1;
+    bottom: 0;
+    border-top: 1px solid #f2f2f2;
+    padding: 20px 13px 17px;
+    display: flex;
+    align-items: center;
+    background-color: #fff;
+    border-radius: 0px 0px 20px 20px;
+    :global {
+      .van-button {
+        font-size: 16px;
+      }
+      .van-button + .van-button {
+        margin-left: 15px;
+      }
+    }
+  }
+}

+ 109 - 0
src/views/music/album-detail/search-group/index.tsx

@@ -0,0 +1,109 @@
+import { defineComponent, reactive, watch } from 'vue'
+import styles from './index.module.less'
+import { Button } from 'vant'
+
+export default defineComponent({
+  name: 'searchGroup',
+  props: {
+    searchList: {
+      type: Object,
+      default: () => ({ albumLevelList: [], albumTypeList: [] })
+    },
+    searchObj: {
+      type: Object,
+      default: () => ({ albumCategoryLevelId: null, albumCategoryTypeId: null })
+    }
+  },
+  emits: ['confirm'],
+  setup(props, { emit }) {
+    const searchList = reactive({
+      albumCategoryLevelId: props.searchObj.albumCategoryLevelId,
+      albumCategoryTypeId: props.searchObj.albumCategoryTypeId
+    })
+
+    watch(
+      () => props.searchObj,
+      () => {
+        ;(searchList.albumCategoryLevelId =
+          props.searchObj.albumCategoryLevelId),
+          (searchList.albumCategoryTypeId = props.searchObj.albumCategoryTypeId)
+      }
+    )
+
+    /** 重置 */
+    const onReset = () => {
+      searchList.albumCategoryLevelId = null
+      searchList.albumCategoryTypeId = null
+    }
+    /** 确认 */
+    const onSubmit = () => {
+      emit('confirm', searchList)
+    }
+    return () => (
+      <div class={styles.popupContainer}>
+        <div class={styles.popupSearchList}>
+          {props.searchList.albumLevelList.length > 0 ? (
+            <div class={styles.popupSection}>
+              <div class={styles.title}>
+                <span>级别</span>
+              </div>
+
+              <div class={[styles.timeCount, styles.timeSubject]}>
+                {props.searchList.albumLevelList.map((item: any) => (
+                  <p
+                    class={
+                      searchList.albumCategoryLevelId === item.id &&
+                      styles.active
+                    }
+                    onClick={() => {
+                      searchList.albumCategoryLevelId = item.id
+                    }}
+                  >
+                    {item.name}
+                  </p>
+                ))}
+              </div>
+            </div>
+          ) : (
+            ''
+          )}
+
+          {props.searchList.albumTypeList.length > 0 ? (
+            <div class={styles.popupSection}>
+              <div class={styles.title}>
+                <span>类型</span>
+              </div>
+
+              <div class={[styles.timeCount, styles.timeSubject]}>
+                {props.searchList.albumTypeList.map((item: any) => (
+                  <p
+                    class={
+                      searchList.albumCategoryTypeId === item.id &&
+                      styles.active
+                    }
+                    onClick={() => {
+                      searchList.albumCategoryTypeId = item.id
+                    }}
+                  >
+                    {item.name}
+                  </p>
+                ))}
+              </div>
+            </div>
+          ) : (
+            ''
+          )}
+        </div>
+
+        <div class={styles.popupBottom}>
+          <Button round block type="default" onClick={onReset}>
+            重置
+          </Button>
+          <Button round block type="primary" onClick={onSubmit}>
+            确认
+          </Button>
+        </div>
+      </div>
+    )
+  }
+})

+ 69 - 5
src/views/music/list/index.module.less

@@ -36,7 +36,7 @@
 }
 
 .searchGroup {
-  background-color: #F8F9FC;
+  background-color: #f8f9fc;
   :global {
     .van-search {
       padding-top: 0;
@@ -56,7 +56,6 @@
   }
 
   :global {
-
     .van-list__loading,
     .van-list__finished-text,
     .van-list__error-text {
@@ -69,11 +68,76 @@
   }
 }
 
+.woringHeader {
+  display: flex;
+  align-items: center;
+  height: var(--van-nav-bar-height);
+
+  .leftArrow {
+    padding: 0 var(--k-padding-md);
+    margin-right: 0;
+    color: #fff;
+  }
+
+  .tabSection {
+    // padding: 0 32px;
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    --van-tab-font-size: 16px;
+    --van-tabs-line-height: 28px;
+    --van-tab-text-color: rgba(51, 51, 51, 0.5);
+    --van-tab-active-text-color: #333333;
+    --van-tabs-nav-background: transparent;
+    --van-padding-xs: 0;
+
+    .moreIcon {
+      display: flex;
+      align-items: center;
+      position: relative;
+      span {
+        // padding-right: 4px;
+      }
+    }
+
+    :global {
+      .van-tabs__nav {
+        background-color: transparent;
+      }
+      .van-tabs__line {
+        display: inline-block;
+        width: 30px;
+        height: 7px;
+        background: #2dc7aa;
+        border-radius: 4px;
+        bottom: 18px;
+      }
+      .van-tab {
+        font-size: 16px;
+        color: #ffffff;
+      }
+      .van-tab--active {
+        font-weight: bold;
+      }
+      .van-tab__text {
+        line-height: normal;
+      }
+
+      .van-tab--shrink {
+        padding: 0 22px;
+        z-index: 9;
+      }
+    }
+  }
+}
+
 .alumnList {
   padding: 0 12px;
-  border-radius: 18px;
+  border-radius: 10px 10px 8px 8px;
   background-color: #fff;
-  margin: 14px;
+  margin: 0 0 14px;
+  min-height: 200px;
 
   &.alumnListOnly {
     margin-top: 0;
@@ -171,4 +235,4 @@
       }
     }
   }
-}
+}

+ 201 - 101
src/views/music/list/index.tsx

@@ -1,4 +1,12 @@
-import { computed, defineComponent,  nextTick, onMounted, reactive, ref, watch } from 'vue'
+import {
+  computed,
+  defineComponent,
+  nextTick,
+  onMounted,
+  reactive,
+  ref,
+  watch
+} from 'vue'
 import { Sticky, List, Popup, Icon, Switch, Tabs, Tab } from 'vant'
 import Search from '@/components/col-search'
 import request from '@/helpers/request'
@@ -57,7 +65,15 @@ export default defineComponent({
     }
   },
   setup(
-    { hideSearch, onlySearch, height, defauleParams, onItemClick, teacherId, myself },
+    {
+      hideSearch,
+      onlySearch,
+      height,
+      defauleParams,
+      onItemClick,
+      teacherId,
+      myself
+    },
     { expose }
   ) {
     const { isLoading, state } = useAsyncState(
@@ -75,7 +91,6 @@ export default defineComponent({
       stickyHeight.value = height
     }
 
-
     const teacherDetaultSubject = ref({
       id: '',
       name: ''
@@ -91,26 +106,26 @@ export default defineComponent({
       // const subjects: any = useSubjectId(SubjectEnum.SEARCH)
       // 判断是否已有数据
       // if (!subjects.id) {
-        const users = baseState.user.data
-        // const subjectId = users.subjectId
-        //   ? Number(users.subjectId.split(',')[0])
-        //   : ''
-        // const subjectName = users.subjectName
-        //   ? users.subjectName.split(',')[0]
-        //   : ''
-        // 存储instrumentId
-        const userInstrumentId = users.instrumentId
-        localStorage.setItem('userInstrumentId', userInstrumentId)
-        // if (subjectId) {
-        //   useSubjectId(
-        //     SubjectEnum.SEARCH,
-        //     JSON.stringify({
-        //       id: subjectId,
-        //       name: subjectName
-        //     }),
-        //     'set'
-        //   )
-        // }
+      const users = baseState.user.data
+      // const subjectId = users.subjectId
+      //   ? Number(users.subjectId.split(',')[0])
+      //   : ''
+      // const subjectName = users.subjectName
+      //   ? users.subjectName.split(',')[0]
+      //   : ''
+      // 存储instrumentId
+      const userInstrumentId = users.instrumentId
+      localStorage.setItem('userInstrumentId', userInstrumentId)
+      // if (subjectId) {
+      //   useSubjectId(
+      //     SubjectEnum.SEARCH,
+      //     JSON.stringify({
+      //       id: subjectId,
+      //       name: subjectName
+      //     }),
+      //     'set'
+      //   )
+      // }
       // }
     }
 
@@ -241,32 +256,31 @@ export default defineComponent({
       tagVisibility.value = false
     }
     const onComfirmSubject = item => {
-    //   params.page = 1
-    //   params.subjectIds = item.id
-    //   data.value = null
-    //   subject.instrumentId = item.instrumentId
-    //   localStorage.setItem('userInstrumentId', item.instrumentId || "")
-    //   if (baseState.platformType === 'TEACHER') {
-    //     teacherDetaultSubject.value = {
-    //       name: item.name,
-    //       id: item.id
-    //     }
-    //     setDefaultSubject(item.id)
-    //   } else {
-    //     subject.id = item.id
-    //     subject.name = item.name
-    //     useSubjectId(
-    //       SubjectEnum.SEARCH,
-    //       JSON.stringify({
-    //         id: item.id,
-    //         name: item.name
-    //       }),
-    //       'set'
-    //     )
-    //   }
-
-    //   FetchList()
-    //   subject.show = false
+      //   params.page = 1
+      //   params.subjectIds = item.id
+      //   data.value = null
+      //   subject.instrumentId = item.instrumentId
+      //   localStorage.setItem('userInstrumentId', item.instrumentId || "")
+      //   if (baseState.platformType === 'TEACHER') {
+      //     teacherDetaultSubject.value = {
+      //       name: item.name,
+      //       id: item.id
+      //     }
+      //     setDefaultSubject(item.id)
+      //   } else {
+      //     subject.id = item.id
+      //     subject.name = item.name
+      //     useSubjectId(
+      //       SubjectEnum.SEARCH,
+      //       JSON.stringify({
+      //         id: item.id,
+      //         name: item.name
+      //       }),
+      //       'set'
+      //     )
+      //   }
+      //   FetchList()
+      //   subject.show = false
     }
 
     // const getSubject: any = useSubjectId(SubjectEnum.SEARCH)
@@ -329,33 +343,113 @@ export default defineComponent({
                 <ColHeader
                   background="transparent"
                   isFixed={false}
-                  border={false}
-                  backIconColor="white"
-                  color="#fff"
                   v-slots={{
-                    right: () =>
-                      !isAudit.value && (
-                        <span
-                          class={styles.fleg}
+                    content: () => (
+                      <div class={styles.woringHeader}>
+                        <i
                           onClick={() => {
-                            // 不要看这个字段的意思
-                            exquisiteFlag.value != exquisiteFlag.value
-                            useSubjectId(
-                              SubjectEnum.MUSIC_FREE,
-                              JSON.stringify({
-                                chargeType: exquisiteFlag.value
-                              }),
-                              'set'
-                            )
-                            data.value = null
-                            params.page = 1
-                            FetchList()
+                            if (browser().isApp) {
+                              postMessage({
+                                api: 'back'
+                              })
+                            } else {
+                              router.back()
+                            }
                           }}
+                          class={[
+                            'van-badge__wrapper van-icon van-icon-arrow-left van-nav-bar__arrow',
+                            styles.leftArrow
+                          ]}
+                        ></i>
+                        <Tabs
+                          class={styles.tabSection}
+                          // v-model:active={state.tabActive}
+                          shrink
+                          // onClickTab={(val) => {
+                          //   if (state.tabActive === '') {
+                          //     if (state.isAllStatus) {
+                          //       state.searchPopup = !state.searchPopup;
+                          //       if (state.searchPopup) {
+                          //         const allSearch = state.allSearch;
+                          //         if (allSearch.audioPlayTypes.length > 0) {
+                          //           if (allSearch.audioPlayTypes.length == 1) {
+                          //             state.sAPT = allSearch.audioPlayTypes.join(',');
+                          //           } else {
+                          //             state.sAPT = 'PLAY_SING';
+                          //           }
+                          //         } else {
+                          //           state.sAPT = '';
+                          //         }
+                          //         state.sNt = allSearch.musicTagIds;
+                          //         if (allSearch.bookVersionId) {
+                          //           let ids: any = [];
+                          //           data.tags.forEach((item: any) => {
+                          //             if (item.id === allSearch.bookVersionId) {
+                          //               ids.push(item.id);
+                          //             }
+                          //           });
+                          //           if (ids.length <= 0) {
+                          //             ids = formatParentId(
+                          //               allSearch.bookVersionId,
+                          //               data.tags
+                          //             );
+                          //           }
+                          //           // console.log(ids, 'ids', allSearch.bookVersionId)
+                          //           data.tagActiveId = ids[0];
+
+                          //           if (data.tagActiveId) {
+                          //             const item = data.tags.find(
+                          //               item => item.id === ids[0]
+                          //             );
+                          //             if (item) changeTag(item, ids[1]);
+                          //           }
+                          //         } else {
+                          //           data.tagActiveId = '';
+                          //           data.childSelectId = null;
+                          //           data.selectParents = {};
+                          //         }
+                          //       }
+                          //     } else {
+                          //       state.isAllStatus = true;
+                          //       onSearch();
+                          //     }
+                          //   } else {
+                          //     state.searchPopup = false;
+                          //     state.isAllStatus = false;
+                          //     onSearch();
+                          //   }
+                          // }}
                         >
-                          <Switch v-model={exquisiteFlag.value} size="20px" />
-                          <span>免费</span>
-                        </span>
-                      )
+                          <Tab name="" title="全部"></Tab>
+                          <Tab name="RECOMMEND" title="推荐"></Tab>
+                          <Tab name="HOT" title="热门"></Tab>
+                          <Tab name="NEW" title="最新"></Tab>
+                        </Tabs>
+                      </div>
+                    )
+                    // right: () =>
+                    //   !isAudit.value && (
+                    //     <span
+                    //       class={styles.fleg}
+                    //       onClick={() => {
+                    //         // 不要看这个字段的意思
+                    //         exquisiteFlag.value != exquisiteFlag.value
+                    //         useSubjectId(
+                    //           SubjectEnum.MUSIC_FREE,
+                    //           JSON.stringify({
+                    //             chargeType: exquisiteFlag.value
+                    //           }),
+                    //           'set'
+                    //         )
+                    //         data.value = null
+                    //         params.page = 1
+                    //         FetchList()
+                    //       }}
+                    //     >
+                    //       <Switch v-model={exquisiteFlag.value} size="20px" />
+                    //       <span>免费</span>
+                    //     </span>
+                    //   )
                   }}
                 />
                 <Search
@@ -383,7 +477,7 @@ export default defineComponent({
                   //   )
                   // }}
                 />
-                <Tabs
+                {/* <Tabs
                   shrink
                   class={styles.tagTabs}
                   lineHeight={0}
@@ -398,37 +492,43 @@ export default defineComponent({
                   {tagList.map((tag: any) => (
                     <Tab title={tag.name} name={tag.id}></Tab>
                   ))}
-                </Tabs>
+                </Tabs> */}
               </TheSticky>
               <img class={styles.bgImg} src={bgImg} />
             </>
           )}
-          {onlySearch ? <Sticky position='top' offsetTop={stickyHeight.value as any}><Search
-                  onSearch={onSearch}
-                  background="transparent"
-                  inputBackground='white'
-                  // leftIcon={iconSearch}
-                  class={styles.searchGroup}
-                  // v-slots={{
-                  //   left: () => (
-                  //     <div
-                  //       class={[styles.label, styles.searchs]}
-                  //       onClick={() => (subject.show = true)}
-                  //     >
-                  //       {baseState.platformType === 'TEACHER'
-                  //         ? teacherDetaultSubject.value.name
-                  //         : subject.name}
+          {onlySearch ? (
+            <Sticky position="top" offsetTop={stickyHeight.value as any}>
+              <Search
+                onSearch={onSearch}
+                background="transparent"
+                inputBackground="white"
+                // leftIcon={iconSearch}
+                class={styles.searchGroup}
+                // v-slots={{
+                //   left: () => (
+                //     <div
+                //       class={[styles.label, styles.searchs]}
+                //       onClick={() => (subject.show = true)}
+                //     >
+                //       {baseState.platformType === 'TEACHER'
+                //         ? teacherDetaultSubject.value.name
+                //         : subject.name}
 
-                  //       <Icon
-                  //         classPrefix="iconfont"
-                  //         name="down"
-                  //         size={12}
-                  //         color="#949597"
-                  //       />
-                  //     </div>
-                  //   )
-                  // }}
-                /></Sticky> : ''}
+                //       <Icon
+                //         classPrefix="iconfont"
+                //         name="down"
+                //         size={12}
+                //         color="#949597"
+                //       />
+                //     </div>
+                //   )
+                // }}
+              />
+            </Sticky>
+          ) : (
+            ''
+          )}
 
           <div class={[styles.alumnList, onlySearch && styles.alumnListOnly]}>
             <List
@@ -448,12 +548,12 @@ export default defineComponent({
                         location.pathname +
                         '#/music-detail?id=' +
                         item.id
-                        //  + '&instrumentId=' + subject.instrumentId
+                      //  + '&instrumentId=' + subject.instrumentId
                       openDefaultWebView(url, () => {
                         router.push({
                           path: '/music-detail',
                           query: {
-                            id: item.id,
+                            id: item.id
                             // instrumentId: subject.instrumentId
                           }
                         })

+ 1 - 0
src/views/music/personal/collection.tsx

@@ -22,6 +22,7 @@ export default defineComponent({
     const params = reactive({
       search: (route.query.search as string) || '',
       musicTagIds: route.query.tagids || '',
+      providerType: props.type === "TENANT" ? 'TENANT' : 'PLATFORM',
       page: 1
     })
     const rows = ref<any[]>([])

+ 1 - 1
vite.config.ts

@@ -12,7 +12,7 @@ function resolve(dir: string) {
 // https://vitejs.dev/config/
 // https://github.com/vitejs/vite/issues/1930 .env
 // const proxyUrl = 'https://online.colexiu.com/'
-const proxyUrl = 'https://test.colexiu.com/'
+const proxyUrl = 'https://dev.colexiu.com/'
 // const proxyUrl = 'http://192.168.3.14:8000/'
 export default defineConfig({
   base: './',