index.tsx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. import {
  2. defineComponent,
  3. toRefs,
  4. reactive,
  5. onMounted,
  6. ref,
  7. watch,
  8. nextTick
  9. } from 'vue'
  10. import classes from './index.module.less'
  11. import {
  12. ElButton,
  13. ElOption,
  14. ElSelect,
  15. ElScrollbar,
  16. ElMessageBox
  17. } from 'element-plus'
  18. import printIcon from './images/printIcon.png'
  19. import noMore from './images/noMore.png'
  20. import banner from './images/banner.png'
  21. import colVideo from '@/components/col-video/index'
  22. import iconClose from '@/views/login/images/icon_close.png'
  23. import start from '@/components/albumItem/images/start.png'
  24. import lineStart from '@/components/albumItem/images/lineStart.png'
  25. import oStart from '@/common/images/oStart.png'
  26. import oLineStart from '@/common/images/oLineStart.png'
  27. import teacher from '@/views/videoDetailList/images/teacher.png'
  28. import teacherHeader from '@/common/images/icon_teacher.png'
  29. import musiceIcon from '@/views/videoDetailList/images/musiceIcon.png'
  30. import music from '@/components/musicLIstItem/images/music.png'
  31. import tagItem from '@/components/tagItem'
  32. import code from '@/common/images/student_download.png'
  33. import musicItem from './modals/musicItem'
  34. import request from '@/helpers/request'
  35. import { useRoute, useRouter } from 'vue-router'
  36. import gou from './images/gou.png'
  37. import member from './images/member.png'
  38. import palyer from './images/palyer.png'
  39. import {
  40. getUserType,
  41. vaildTeachingUrl,
  42. getAuth,
  43. setAuth
  44. } from '@/helpers/utils'
  45. import { imgToCanvas, addWatermark, convasToImg } from '@/helpers/imageFunction'
  46. import arrow from '@/views/home/images/moreArrow.png'
  47. import { Vue3Lottie } from 'vue3-lottie'
  48. import 'vue3-lottie/dist/style.css'
  49. import AstronautJSON from '@/common/animate/bigLoad.json'
  50. import printJS from 'print-js'
  51. const chargeTypes = {
  52. CHARGE: '点播',
  53. FREE: '免费',
  54. VIP: '会员'
  55. }
  56. const chargeImg = {
  57. CHARGE: palyer,
  58. FREE: gou,
  59. VIP: member
  60. }
  61. const chargeClass = {
  62. CHARGE: 'charge',
  63. FREE: 'gou',
  64. VIP: 'member'
  65. }
  66. export default defineComponent({
  67. name: 'muiscDetial',
  68. props: {
  69. title: {
  70. type: String,
  71. default: ''
  72. }
  73. },
  74. components: {
  75. colVideo,
  76. tagItem,
  77. musicItem,
  78. Vue3Lottie
  79. },
  80. setup(props, conent) {
  81. const route = useRoute()
  82. const router = useRouter()
  83. const state = reactive({
  84. title: props.title,
  85. id: route.query.id,
  86. subjectId: '',
  87. subjectList: [],
  88. tagList: [],
  89. teacherDetail: {} as any,
  90. musicDetail: {} as any,
  91. musicList: [],
  92. mp3Type: '',
  93. activeRow: {} as any,
  94. showCode: false,
  95. userType: '',
  96. accompanyUrl: '',
  97. imgData: '',
  98. imgUrl: '',
  99. showImg: ''
  100. })
  101. // nextTick(() => {
  102. // // 禁用右键
  103. // // @ts-ignore:无法被执行的代码的错误
  104. // document.oncontextmenu = new Function('event.returnValue=false')
  105. // // @ts-ignore:无法被执行的代码的错误
  106. // // 禁用选择
  107. // document.onselectstart = new Function('event.returnValue=false')
  108. // // @ts-ignore:无法被执行的代码的错误
  109. // //禁止f12
  110. // document.οnkeydοwn = new Function('event.returnValue=false')
  111. // })
  112. // // 上面的禁止f12那段代码没有生效,但是加了下面这段就能生效。
  113. // document.onkeydown = function (e) {
  114. // if (e && e.keyCode === 123) {
  115. // e.returnValue = false
  116. // // e.keyCode = 0 //去掉也可以的,倘若要写,则需要setter 以及 getter配合使用,不配合,会报错
  117. // return false
  118. // }
  119. // }
  120. const print = ref()
  121. const getMusicList = async () => {
  122. try {
  123. const res = await request.get(
  124. `/api-website/open/music/sheet/detail/${state.id}`,
  125. {}
  126. )
  127. state.musicDetail = res.data
  128. state.musicList = res.data.teacher.musicSheetList
  129. state.subjectList = res.data.background
  130. state.tagList = res.data.musicTagNames
  131. ? res.data.musicTagNames.split(',')
  132. : []
  133. state.mp3Type = res.data.audioType
  134. if (state.subjectList && state.subjectList.length > 0) {
  135. state.activeRow = res.data.background[0]
  136. state.subjectId = res.data.background[0].id
  137. }
  138. state.teacherDetail = res.data.teacher
  139. setAccompanyUrl()
  140. } catch (e) {
  141. console.log(e)
  142. }
  143. }
  144. const followVideo = async () => {
  145. try {
  146. const res = await request.get('/api-website/student/starOrUnStar', {
  147. params: {
  148. userId: state.teacherDetail.userId,
  149. starStatus: state.teacherDetail.star ? 0 : 1
  150. }
  151. })
  152. getMusicList()
  153. // state.otherVideoList = res.data
  154. } catch (e) {
  155. console.log(e)
  156. }
  157. }
  158. const getDetail = (val: string | number) => {
  159. state.id = val as string
  160. router.push({
  161. query: { ...route.query, id: state.id }
  162. })
  163. state.showImg = ''
  164. getMusicList()
  165. }
  166. watch(
  167. () => state.accompanyUrl,
  168. accompanyUrl => {
  169. state.accompanyUrl = accompanyUrl
  170. }
  171. )
  172. const setAccompanyUrl = () => {
  173. let url = vaildTeachingUrl()
  174. state.accompanyUrl =
  175. url +
  176. `/accompany/colxiu-website.html?id=${state.id}&part-index=${state.subjectId}`
  177. // state.accompanyUrl = `http://192.168.3.8:3000/colxiu-website.html?id=${state.id}&part-index=${state.subjectId}`
  178. }
  179. const setSvg = (val: any) => {
  180. console.log(val)
  181. }
  182. onMounted(() => {
  183. // window.setSvg = (val)=>{
  184. // setSvg(val)
  185. // }
  186. window.addEventListener(
  187. 'message',
  188. async e => {
  189. console.log(e)
  190. state.imgData = e.data
  191. // printHander()
  192. // alert(e.data);
  193. const tempCanvas = await imgToCanvas(state.imgData)
  194. const showImg = convasToImg(tempCanvas)
  195. state.showImg = showImg
  196. },
  197. false
  198. )
  199. state.userType = getUserType()
  200. state.showCode =
  201. state.userType == 'STUDENT' || !state.userType ? true : false
  202. // 拼链接
  203. getMusicList()
  204. })
  205. const printHander = async () => {
  206. const tempCanvas = await imgToCanvas(state.imgData)
  207. const showImg = convasToImg(tempCanvas)
  208. state.showImg = showImg
  209. const canvas = addWatermark(tempCanvas, '酷乐秀')
  210. const imgUrl = convasToImg(canvas)
  211. const link = document.createElement('a')
  212. link.setAttribute('download', state.musicDetail.musicSheetName + '.png')
  213. // 添加时间戳,防止浏览器缓存图片
  214. state.imgUrl = imgUrl
  215. // console.log('printHander',imgUrl)
  216. // return
  217. link.href = imgUrl
  218. link.click()
  219. }
  220. const gotoMusic = () => {
  221. router.push({
  222. name: 'searchdetail',
  223. params: {
  224. search: state.teacherDetail.userName as string,
  225. type: 'music'
  226. }
  227. })
  228. }
  229. const favoriteMusic = async () => {
  230. const tockn = getAuth()
  231. if (!tockn) {
  232. return
  233. }
  234. ElMessageBox.confirm(
  235. `是否${state.musicDetail.favorite ? '取消收藏' : '收藏'}该曲目?`,
  236. '提示',
  237. {
  238. type: 'warning'
  239. }
  240. ).then(async () => {
  241. try {
  242. const res = await request.post(
  243. `/api-website/music/sheet/favorite/${state.id}`
  244. )
  245. getMusicList()
  246. // state.otherVideoList = res.data
  247. } catch (e) {
  248. console.log(e)
  249. }
  250. })
  251. }
  252. return () => (
  253. <>
  254. <div class={classes.wall}></div>
  255. <div class={classes.musicWraps}>
  256. <div class={[classes.width1200]}>
  257. <div class={[classes.musicWrap]}>
  258. <div class={classes.left}>
  259. <div class={classes.title}>
  260. <div class={classes.titleLeft}>
  261. <p>声部:</p>
  262. <ElSelect
  263. class="w-full subjectChiose"
  264. v-model={state.subjectId}
  265. placeholder="请选择声部"
  266. onChange={() => {
  267. setAccompanyUrl()
  268. }}
  269. >
  270. {state.subjectList.map((item: any) => (
  271. <ElOption
  272. key={item.id}
  273. value={item.id}
  274. label={item.track}
  275. />
  276. ))}
  277. </ElSelect>
  278. </div>
  279. <div class={classes.titleRight} onClick={() => printHander()}>
  280. <img src={printIcon} alt="" />
  281. <p>下载乐谱</p>
  282. </div>
  283. </div>
  284. <div class={classes.musicContent}>
  285. {/* id="iframe" ref="iframe"*/}
  286. <img class={classes.musicStag} src={chargeImg[ state.musicDetail.chargeType]} alt="" />
  287. <iframe
  288. id="containerPrint"
  289. ref="print"
  290. style="width: 538px;page-break-after:always; "
  291. src={state.accompanyUrl}
  292. class={classes.iframe}
  293. />
  294. {state.showImg ? (
  295. <img src={state.showImg} alt="" />
  296. ) : (
  297. <div>
  298. <Vue3Lottie
  299. animationData={AstronautJSON}
  300. class={classes.finch}
  301. ></Vue3Lottie>
  302. <p class={classes.finchLoad}>加载中...</p>
  303. </div>
  304. )}
  305. {}
  306. </div>
  307. {state.mp3Type == 'MP3' ? (
  308. <colVideo
  309. src={state.activeRow.audioFileUrl}
  310. styleValue={{
  311. height: '68px',
  312. bacground: '#333'
  313. }}
  314. type={'audto'}
  315. settings={['captions', 'quality', 'speed', 'loop', 'title']}
  316. class={classes.audios}
  317. poster={state.activeRow.title}
  318. ></colVideo>
  319. ) : (
  320. <>
  321. <div class={classes.noMoreWrap}>
  322. <img src={noMore} alt="" />
  323. <p>温馨提示:该曲目暂不支持播放喔~</p>
  324. </div>
  325. </>
  326. )}
  327. {state.showCode ? (
  328. <div class={classes.showCode}>
  329. <div class={classes.showCodeWrap}>
  330. <img
  331. class={classes.close}
  332. src={iconClose}
  333. alt=""
  334. onClick={() => {
  335. state.showCode = false
  336. }}
  337. />
  338. <img class={classes.code} src={code} alt="" />
  339. {/* <h2 class={classes.title}>酷乐秀</h2>
  340. <p class={classes.conent}>扫码下载酷乐秀APP</p>
  341. <p class={classes.subConent}>
  342. 使用小酷Ai即可智能练习本首曲目哦!
  343. </p> */}
  344. <img src={banner} class={classes.banner} alt="" />
  345. </div>
  346. </div>
  347. ) : null}
  348. </div>
  349. <div class={classes.right}>
  350. <div class={classes.musicInfo}>
  351. <h2>
  352. <span class={[classes.musicTag,classes[chargeClass[state.musicDetail.chargeType]]]}>{chargeTypes[state.musicDetail.chargeType]}</span>
  353. {state.musicDetail.musicSheetName}
  354. </h2>
  355. <div class={classes.collectWrap}>
  356. <div class={classes.masker}>
  357. <img
  358. src={state.musicDetail.favorite ? lineStart : start}
  359. alt=""
  360. />
  361. </div>
  362. <img src={music} class={classes.musiceIcon} alt="" />
  363. <div>
  364. <div class={classes.collect} onClick={favoriteMusic}>
  365. <img
  366. src={state.musicDetail.favorite ? oLineStart : oStart}
  367. class={classes.start}
  368. alt=""
  369. />
  370. <p>{state.musicDetail.favoriteNum}人收藏</p>
  371. </div>
  372. <div class={classes.tagList}>
  373. {state.tagList.map((item: any) => {
  374. return <div class={classes.tag}>{item}</div>
  375. })}
  376. </div>
  377. <p class={classes.subTitle}>
  378. 作曲人:<span>{state.musicDetail.composer}</span>
  379. </p>
  380. <p class={classes.subTitle}>
  381. 声部:<span>{state.musicDetail.subjectNames}</span>
  382. </p>
  383. </div>
  384. </div>
  385. </div>
  386. <div class={classes.btooom}>
  387. {state.teacherDetail.userId ? (
  388. <div class={classes.teacherInfo}>
  389. <h2>上传者</h2>
  390. <div class={classes.teacherHeadWrap}>
  391. <div class={classes.teacherHeadLeft}>
  392. <img
  393. src={
  394. state.teacherDetail.userAvatar
  395. ? state.teacherDetail.userAvatar
  396. : teacherHeader
  397. }
  398. alt=""
  399. class={classes.teacherHeader}
  400. />
  401. <div class={classes.teacherHeadInfo}>
  402. <div class={classes.teacherHeadName}>
  403. <p>{state.teacherDetail.userName}</p>
  404. {/* {!state.teacherDetail.entryFlag ? (
  405. ''
  406. ) : (
  407. <img
  408. src={teacher}
  409. class={classes.teacherIcon}
  410. alt=""
  411. />
  412. )}
  413. {!state.teacherDetail.musicianFlag ? (
  414. ''
  415. ) : (
  416. <img
  417. src={musiceIcon}
  418. class={classes.teacherIcon}
  419. alt=""
  420. />
  421. )} */}
  422. {state.userType == 'STUDENT' ? (
  423. <div
  424. class={[
  425. classes.teacherHeadRight,
  426. state.teacherDetail.star
  427. ? classes.isStart
  428. : ''
  429. ]}
  430. onClick={() => followVideo()}
  431. >
  432. {state.teacherDetail.star
  433. ? '已关注'
  434. : '+ 关注'}
  435. </div>
  436. ) : null}
  437. </div>
  438. </div>
  439. </div>
  440. <div>
  441. <p class={classes.fensNum}>
  442. {state.teacherDetail.fansNum}
  443. </p>
  444. <p class={classes.fens}>粉丝数</p>
  445. </div>
  446. </div>
  447. </div>
  448. ) : null}
  449. <div class={classes.otherMusic}>
  450. <div class={classes.videoNav}>
  451. <h5>Ta的曲谱</h5>
  452. <div
  453. class={classes.wrapRight}
  454. onClick={() => gotoMusic()}
  455. >
  456. <span>更多</span>
  457. <img class={classes.arrow} src={arrow} alt="" />
  458. </div>
  459. </div>
  460. <div class={classes.otherMusicList}>
  461. {state.musicList.map(item => {
  462. return (
  463. <musicItem
  464. item={item}
  465. onMusicDetail={val => getDetail(val)}
  466. ></musicItem>
  467. )
  468. })}
  469. </div>
  470. </div>
  471. </div>
  472. </div>
  473. {/* <img src={state.imgUrl} alt="" /> */}
  474. </div>
  475. </div>
  476. </div>
  477. </>
  478. )
  479. }
  480. })