index.tsx 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. import { defineComponent, nextTick, onMounted, reactive, ref } from 'vue'
  2. import { useRoute, useRouter } from 'vue-router'
  3. import request from '@/helpers/request'
  4. import ColHeader from '@/components/col-header'
  5. import { postMessage } from '@/helpers/native-message'
  6. import { Button, Icon, Image, List, NavBar, Sticky } from 'vant'
  7. // import classNames from 'classnames'
  8. // import Footer from '../album/footer'
  9. // import FavoriteIcon from '../album/favorite.svg'
  10. // import FavoritedIcon from '../album/favorited.svg'
  11. import styles from './index.module.less'
  12. // import Item from '../list/item'
  13. import { useRect } from '@vant/use'
  14. import { useEventListener, useWindowScroll } from '@vueuse/core'
  15. import { getRandomKey, musicBuy } from '../music'
  16. import { state } from '@/state'
  17. import IconPan from './pan.png'
  18. import oStart from './oStart.png'
  19. import iStart from './iStart.png'
  20. import Title from '../component/title'
  21. import Song from '../component/song'
  22. import ColResult from '@/components/col-result'
  23. import MusicGrid from '../component/music-grid'
  24. import { useEventTracking } from '@/helpers/hooks'
  25. const noop = () => {}
  26. export default defineComponent({
  27. name: 'AlbumDetail',
  28. props: {
  29. onItemClick: {
  30. type: Function,
  31. default: noop
  32. }
  33. },
  34. setup({ onItemClick }) {
  35. localStorage.setItem('behaviorId', getRandomKey())
  36. const router = useRouter()
  37. const params = reactive({
  38. search: '',
  39. relatedNum: 6, //相关专辑数
  40. page: 1,
  41. rows: 200
  42. })
  43. const albumDetail = ref<any>(null)
  44. // const data = ref<any>(null)
  45. const rows = ref<any[]>([])
  46. const loading = ref(false)
  47. // const finished = ref(false)
  48. const isError = ref(false)
  49. const favorited = ref(0)
  50. const albumFavoriteCount = ref(0)
  51. const headers = ref(null)
  52. const background = ref<string>('rgba(55, 205, 177, 0)')
  53. const color = ref<string>('#fff')
  54. const heightInfo = ref<any>('auto')
  55. const route = useRoute()
  56. const FetchList = async (id?: any) => {
  57. if (loading.value) {
  58. return
  59. }
  60. loading.value = true
  61. isError.value = false
  62. try {
  63. const res = await request.post('/music/album/detail', {
  64. prefix:
  65. state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student',
  66. data: { id: id || route.params.id, ...params }
  67. })
  68. const { musicSheetList, ...rest } = res.data
  69. rows.value = [...musicSheetList.rows]
  70. const musicTagNames = rest?.musicTagNames?.split(',') || []
  71. albumDetail.value = {
  72. ...rest,
  73. musicTagNames
  74. }
  75. favorited.value = rest.favorite
  76. albumFavoriteCount.value = rest.albumFavoriteCount
  77. } catch (error) {
  78. isError.value = true
  79. }
  80. loading.value = false
  81. }
  82. const favoriteLoading = ref(false)
  83. onMounted(() => {
  84. FetchList()
  85. useEventListener(document, 'scroll', evt => {
  86. const { y } = useWindowScroll()
  87. if (y.value > 20) {
  88. background.value = `rgba(255, 255, 255)`
  89. color.value = 'black'
  90. postMessage({
  91. api: 'backIconChange',
  92. content: { iconStyle: 'black' }
  93. })
  94. } else {
  95. background.value = 'transparent'
  96. color.value = '#fff'
  97. postMessage({
  98. api: 'backIconChange',
  99. content: { iconStyle: 'white' }
  100. })
  101. }
  102. })
  103. useEventTracking('专辑')
  104. })
  105. const toggleFavorite = async (id: number) => {
  106. favoriteLoading.value = true
  107. try {
  108. await request.post('/music/album/favorite/' + id, {
  109. prefix:
  110. state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student'
  111. })
  112. favorited.value = favorited.value === 1 ? 0 : 1
  113. albumFavoriteCount.value += favorited.value ? 1 : -1
  114. } catch (error) {}
  115. favoriteLoading.value = false
  116. }
  117. return () => {
  118. return (
  119. <div class={styles.detail}>
  120. <div ref={headers}>
  121. <ColHeader
  122. background={background.value}
  123. border={false}
  124. color={color.value}
  125. backIconColor="white"
  126. onHeaderBack={() => {
  127. nextTick(() => {
  128. const { height } = useRect(headers as any)
  129. heightInfo.value = height
  130. })
  131. }}
  132. />
  133. </div>
  134. <img class={styles.bgImg} src={albumDetail.value?.albumCoverUrl} />
  135. <div class={styles.musicContent}></div>
  136. <div class={styles.bg}>
  137. <div class={styles.alumWrap}>
  138. <div class={styles.img}>
  139. <Image
  140. class={styles.image}
  141. width="100%"
  142. height="100%"
  143. fit="cover"
  144. src={albumDetail.value?.albumCoverUrl}
  145. />
  146. </div>
  147. <div class={styles.alumDes}>
  148. <div class={[styles.alumTitle, 'van-ellipsis']}>
  149. {albumDetail.value?.albumName}
  150. </div>
  151. <div class={styles.tags}>
  152. {albumDetail.value?.musicTagNames?.map((tag: any) => (
  153. <span class={styles.tag}>{tag}</span>
  154. ))}
  155. </div>
  156. <div
  157. class={[styles.des, 'van-multi-ellipsis--l3']}
  158. style={{
  159. height: '48px',
  160. lineHeight: '16px'
  161. }}
  162. >
  163. {albumDetail.value?.albumDesc}
  164. </div>
  165. </div>
  166. </div>
  167. <div class={styles.alumCollect}>
  168. <img src={IconPan} />
  169. <span>共{albumDetail.value?.musicSheetCount}首曲目{state.platformType}</span>
  170. <div
  171. class={styles.right}
  172. onClick={() => toggleFavorite(albumDetail.value?.id)}
  173. >
  174. <img src={favorited.value ? iStart : oStart} />
  175. <span>{albumFavoriteCount.value}人收藏</span>
  176. </div>
  177. </div>
  178. </div>
  179. <div class={styles.alumnContainer}>
  180. <div class={styles.alumnList}>
  181. <Title title="曲目列表" isMore={false} />
  182. <Song
  183. list={rows.value}
  184. onDetail={(item: any) => {
  185. if (onItemClick === noop || !onItemClick) {
  186. musicBuy(item, () => {}, {
  187. albumId: route.params.id,
  188. albumName: albumDetail.value?.albumName
  189. })
  190. } else {
  191. onItemClick(item)
  192. }
  193. }}
  194. />
  195. {rows.value && rows.value.length <= 0 && (
  196. <ColResult btnStatus={false} tips="暂无曲目" />
  197. )}
  198. </div>
  199. {albumDetail.value?.relatedMusicAlbum &&
  200. albumDetail.value?.relatedMusicAlbum.length > 0 && (
  201. <>
  202. <Title
  203. title="相关专辑"
  204. onMore={() => {
  205. router.push({
  206. path: '/music-album'
  207. })
  208. }}
  209. />
  210. <MusicGrid
  211. list={albumDetail.value?.relatedMusicAlbum}
  212. onGoto={(n: any) => {
  213. router
  214. .push({
  215. name: 'music-album-detail',
  216. params: {
  217. id: n.id
  218. }
  219. })
  220. .then(() => {
  221. FetchList(n.id)
  222. window.scrollTo(0, 0)
  223. })
  224. }}
  225. />
  226. </>
  227. )}
  228. </div>
  229. </div>
  230. )
  231. }
  232. }
  233. })