index.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. import {
  2. computed,
  3. defineComponent,
  4. nextTick,
  5. onMounted,
  6. reactive,
  7. ref
  8. } from 'vue'
  9. import { useRoute, useRouter } from 'vue-router'
  10. import request from '@/helpers/request'
  11. import ColHeader from '@/components/col-header'
  12. import { postMessage } from '@/helpers/native-message'
  13. import { Button, Cell, Dialog, Icon, Image, Popup, Tag } from 'vant'
  14. import styles from './index.module.less'
  15. // import Item from '../list/item'
  16. import { useRect } from '@vant/use'
  17. import { Vue3Lottie } from 'vue3-lottie'
  18. import { getRandomKey, musicBuy } from '../music'
  19. import { state } from '@/state'
  20. import { useEventTracking } from '@/helpers/hooks'
  21. import ColSticky from '@/components/col-sticky'
  22. import { moneyFormat } from '@/helpers/utils'
  23. import { orderStatus } from '@/views/order-detail/orderStatus'
  24. import iconShare from '@/views/music/album/icon_share.svg'
  25. import iconDownload from './images/icon_download.png'
  26. import AstronautJSON from './animate/bigLoad.json'
  27. import ColShare from '@/components/col-share'
  28. import iconCollect from './images/icon_collect.png'
  29. import iconCollectActive from './images/icon_collect_active.png'
  30. export const getAssetsHomeFile = (fileName: string) => {
  31. const path = `../component/images/${fileName}`
  32. const modules = import.meta.globEager('../component/images/*')
  33. return modules[path].default
  34. }
  35. export default defineComponent({
  36. name: 'MusicDetail',
  37. setup() {
  38. localStorage.setItem('behaviorId', getRandomKey())
  39. const router = useRouter()
  40. const route = useRoute()
  41. const albumDetail = ref<any>(null)
  42. const loading = ref(false)
  43. const aId = Number(route.query.activityId) || 0
  44. const studentActivityId = ref(aId)
  45. const isError = ref(false)
  46. const favorited = ref(0)
  47. const albumFavoriteCount = ref(0)
  48. const headers = ref(null)
  49. const heightInfo = ref<any>('0')
  50. const musicDetail = ref<any>(null)
  51. const showImg = ref<string>('')
  52. const colors: any = {
  53. FREE: {
  54. color: '#01B84F',
  55. text: '免费'
  56. },
  57. VIP: {
  58. color: '#CD863E',
  59. text: '会员'
  60. },
  61. CHARGE: {
  62. color: '#3591CE',
  63. text: '点播'
  64. }
  65. }
  66. const FetchList = async (id?: any) => {
  67. if (loading.value) {
  68. return
  69. }
  70. loading.value = true
  71. isError.value = false
  72. try {
  73. const res = await request.get(`/music/sheet/detail/${route.query.id}`, {
  74. prefix:
  75. state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student'
  76. })
  77. musicDetail.value = res.data
  78. showImg.value = res.data.musicImg || ''
  79. } catch (error) {
  80. isError.value = true
  81. }
  82. loading.value = false
  83. }
  84. const favoriteLoading = ref(false)
  85. onMounted(() => {
  86. FetchList()
  87. const { height } = useRect(headers as any)
  88. heightInfo.value = height
  89. })
  90. const toggleFavorite = async (id: number) => {
  91. favoriteLoading.value = true
  92. try {
  93. await request.post('/music/album/favorite/' + id, {
  94. prefix:
  95. state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student'
  96. })
  97. favorited.value = favorited.value === 1 ? 0 : 1
  98. albumFavoriteCount.value += favorited.value ? 1 : -1
  99. } catch (error) {}
  100. favoriteLoading.value = false
  101. }
  102. const onBuy = async () => {
  103. const album = albumDetail.value
  104. orderStatus.orderObject.orderType = 'ALBUM'
  105. orderStatus.orderObject.orderName = album.albumName
  106. orderStatus.orderObject.orderDesc = album.albumName
  107. orderStatus.orderObject.actualPrice = album.albumPrice
  108. orderStatus.orderObject.recomUserId = route.query.recomUserId || 0
  109. orderStatus.orderObject.activityId = route.query.activityId || 0
  110. orderStatus.orderObject.orderNo = ''
  111. orderStatus.orderObject.orderList = [
  112. {
  113. orderType: 'ALBUM',
  114. goodsName: album.albumName,
  115. recomUserId: route.query.recomUserId || 0,
  116. price: album.albumPrice,
  117. ...album
  118. }
  119. ]
  120. const res = await request.post('/api-student/userOrder/getPendingOrder', {
  121. data: {
  122. goodType: 'ALBUM',
  123. bizId: album.id
  124. }
  125. })
  126. const result = res.data
  127. if (result) {
  128. Dialog.confirm({
  129. title: '提示',
  130. message: '您有一个未支付的订单,是否继续支付?',
  131. confirmButtonColor: '#269a93',
  132. cancelButtonText: '取消订单',
  133. confirmButtonText: '继续支付'
  134. })
  135. .then(async () => {
  136. orderStatus.orderObject.orderNo = result.orderNo
  137. orderStatus.orderObject.actualPrice = result.actualPrice
  138. orderStatus.orderObject.discountPrice = result.discountPrice
  139. routerTo()
  140. })
  141. .catch(() => {
  142. Dialog.close()
  143. // 只用取消订单,不用做其它处理
  144. cancelPayment(result.orderNo)
  145. })
  146. } else {
  147. routerTo()
  148. }
  149. }
  150. const routerTo = () => {
  151. const album = albumDetail.value
  152. router.push({
  153. path: '/orderDetail',
  154. query: {
  155. orderType: 'ALBUM',
  156. album: album.id
  157. }
  158. })
  159. }
  160. const cancelPayment = async (orderNo: string) => {
  161. try {
  162. await request.post('/api-student/userOrder/orderCancel', {
  163. data: {
  164. orderNo
  165. }
  166. })
  167. } catch {}
  168. }
  169. const paymentType = computed(() => {
  170. let paymentType = musicDetail.value?.paymentType
  171. if (typeof paymentType === 'string') {
  172. paymentType = paymentType.split(',')
  173. return paymentType
  174. }
  175. return []
  176. })
  177. const shareStatus = ref(false)
  178. const shareUrl = ref('')
  179. const shareDiscount = ref(0)
  180. // console.log(data)
  181. const onShare = async () => {
  182. try {
  183. const res = await request.post('/api-teacher/open/musicShareProfit', {
  184. data: {
  185. bizId: musicDetail.value?.id,
  186. userId: state.user.data?.userId
  187. }
  188. })
  189. let url =
  190. location.origin +
  191. `/accompany/colexiu-share.html?id=${musicDetail.value?.id}&recomUserId=${state.user.data?.userId}&userType=${state.platformType}`
  192. // 判断是否有活动
  193. if (res.data.discount === 1) {
  194. url += `&activityId=${res.data.activityId}`
  195. }
  196. shareDiscount.value = res.data.discount || 0
  197. shareUrl.value = url
  198. shareStatus.value = true
  199. return
  200. } catch {}
  201. }
  202. return () => {
  203. return (
  204. <div class={styles.detail}>
  205. <ColHeader
  206. background="transparent"
  207. border={false}
  208. color="#fff"
  209. backIconColor="white"
  210. v-slots={{
  211. right: () => (
  212. <div
  213. class={styles.shareBtn}
  214. style={{
  215. color: '#fff'
  216. }}
  217. onClick={onShare}
  218. >
  219. <Image src={iconShare} />
  220. 分享
  221. </div>
  222. )
  223. }}
  224. />
  225. <img class={styles.bgImg} src={musicDetail.value?.titleImg} />
  226. <div
  227. class={styles.musicContainer}
  228. style={{
  229. marginTop: '16px',
  230. height: `calc(100vh - var(--van-nav-bar-height) - ${
  231. heightInfo.value + 16 + 'px'
  232. })`
  233. }}
  234. >
  235. <Cell
  236. border={false}
  237. center
  238. class={styles.musicInfo}
  239. v-slots={{
  240. icon: () => (
  241. <Image
  242. class={styles.pImg}
  243. src={musicDetail.value?.titleImg}
  244. />
  245. ),
  246. title: () => (
  247. <div class={styles.info}>
  248. <h4 class="van-ellipsis">
  249. {musicDetail.value?.musicSheetName}
  250. </h4>
  251. <p
  252. style={{
  253. display: 'flex'
  254. }}
  255. >
  256. {paymentType.value.map(tag => (
  257. <Tag
  258. style={{ color: colors[tag].color }}
  259. class={styles.tag}
  260. type="success"
  261. plain
  262. >
  263. {colors[tag].text}
  264. </Tag>
  265. ))}
  266. {musicDetail.value?.exquisiteFlag === 1 && (
  267. <Image
  268. class={styles.exquisiteFlag}
  269. src={getAssetsHomeFile('icon_ exquisite.png')}
  270. />
  271. )}
  272. {musicDetail.value?.albumNums > 0 && (
  273. <Image
  274. class={styles.songAlbum}
  275. src={getAssetsHomeFile('icon_album_active.png')}
  276. />
  277. )}
  278. <span style={{ paddingTop: '2px', paddingLeft: '6px' }}>
  279. {musicDetail.value?.composer}
  280. </span>
  281. </p>
  282. </div>
  283. ),
  284. value: () => (
  285. <span class={styles.download}>
  286. <img src={iconDownload} />
  287. 下载曲谱
  288. </span>
  289. )
  290. }}
  291. />
  292. <div class={styles.musicContent}>
  293. <iframe
  294. id="containerPrint"
  295. ref="print"
  296. style="width: 100%;page-break-after:always; height: 0"
  297. // src={state.accompanyUrl}
  298. />
  299. <p class={styles.musicTitle}>
  300. {musicDetail.value?.musicSheetName}
  301. </p>
  302. {showImg.value ? (
  303. <img src={showImg.value} alt="" class={styles.musicImg} />
  304. ) : (
  305. <>
  306. <Vue3Lottie
  307. animationData={AstronautJSON}
  308. class={styles.finch}
  309. ></Vue3Lottie>
  310. <p class={styles.finchLoad}>加载中...</p>
  311. </>
  312. )}
  313. <div class={styles.videoOperation}>
  314. <div class={[styles.collect, styles.collectCell]}>
  315. <div class={styles.userInfo}>
  316. <img src="" />
  317. <span>用户名</span>
  318. </div>
  319. <div class={styles.collectSection}>
  320. <span>326人收藏</span>
  321. <img src={iconCollect} />
  322. </div>
  323. </div>
  324. </div>
  325. <div class={styles.lookAlbum}></div>
  326. </div>
  327. </div>
  328. <ColSticky position="bottom" background="white">
  329. <div ref={headers}>
  330. <div class={styles.colSticky}>
  331. <div class={styles.priceSection}>
  332. <span>点播价:</span>
  333. <span class={styles.price}>
  334. <i>¥</i>
  335. {moneyFormat(9.9)}
  336. </span>
  337. </div>
  338. <div class={[styles.buyBtn]}>
  339. <Button
  340. round
  341. type="primary"
  342. color="linear-gradient(180deg, #59E5D5 0%, #2DC7AA 100%)"
  343. class={styles.primary}
  344. onClick={onBuy}
  345. >
  346. 立即点播
  347. </Button>
  348. <Button
  349. round
  350. type="primary"
  351. color="linear-gradient(180deg, #F7BD8D 0%, #CD8806 100%)"
  352. class={styles.memeber}
  353. onClick={onBuy}
  354. >
  355. 开通会员
  356. </Button>
  357. </div>
  358. </div>
  359. </div>
  360. </ColSticky>
  361. <Popup
  362. v-model:show={shareStatus.value}
  363. style={{ background: 'transparent' }}
  364. teleport="body"
  365. >
  366. <ColShare
  367. teacherId={state.user.data?.userId}
  368. shareUrl={shareUrl.value}
  369. shareType="music"
  370. >
  371. <div class={styles.shareMate}>
  372. {shareDiscount.value === 1 && (
  373. <div class={styles.tagDiscount}>专属优惠</div>
  374. )}
  375. <img
  376. class={styles.icon}
  377. crossorigin="anonymous"
  378. src={
  379. musicDetail.value?.titleImg +
  380. `@base@tag=imgScale&h=80&w=80&m=1?t=${+new Date()}`
  381. }
  382. />
  383. <div class={styles.info}>
  384. <h4 class="van-multi-ellipsis--l2">
  385. {musicDetail.value?.musicSheetName}
  386. </h4>
  387. <p>作曲人:{musicDetail.value?.composer}</p>
  388. </div>
  389. </div>
  390. </ColShare>
  391. </Popup>
  392. </div>
  393. )
  394. }
  395. }
  396. })