index-share.tsx 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. import {
  2. defineComponent,
  3. onMounted,
  4. onUnmounted,
  5. reactive,
  6. ref,
  7. watch,
  8. nextTick
  9. } from 'vue';
  10. // import WaveSurfer from 'wavesurfer.js';
  11. // import Regions from 'wavesurfer.js/dist/plugins/regions.js';
  12. import styles from './index.module.less';
  13. import { Cell, Image, List, Popup, Sticky, TextEllipsis } from 'vant';
  14. import iconMember from './images/icon-member.png';
  15. import iconZan from './images/icon-zan.png';
  16. import iconZanActive from './images/icon-zan-active.png';
  17. import logoImg from './images/logo.png';
  18. import logo1Img from './images/logo1.png';
  19. import iconUpward from './images/upward.png';
  20. import iconPlay from './images/icon-play.png';
  21. import iconPause from './images/icon-pause.png';
  22. import audioPan from './images/audio-pan.png';
  23. import audioLabel from './share-model/images/audioLabel.png';
  24. import videoLabel from './share-model/images/videoLabel.png';
  25. import musicBg from './share-model/images/music-bg.png';
  26. import playImg from './images/play.png';
  27. import { browser, getGradeCh, getSecondRPM, vaildMusicScoreUrl } from '@/helpers/utils';
  28. import { onBeforeRouteUpdate, useRoute, useRouter, onBeforeRouteLeave } from 'vue-router';
  29. import {
  30. api_openUserMusicDetail,
  31. api_openUserMusicPage,
  32. api_userMusicStar,
  33. api_verification
  34. } from './api';
  35. import MEmpty from '@/components/m-empty';
  36. import MVideo from '@/components/m-video';
  37. import LoginModel from './login-model';
  38. import { removeAuth } from '../student-register/layout/utils';
  39. import { setLogout } from '@/state';
  40. import { storage } from '@/helpers/storage';
  41. import { ACCESS_TOKEN } from '@/store/mutation-types';
  42. import MWxTip from '@/components/m-wx-tip';
  43. import { usePageVisibility, useEventListener } from '@vant/use';
  44. import videoBg from './images/video-bg.png';
  45. import LoginChangeModel from './login-change-model';
  46. import MSticky from '@/components/m-sticky';
  47. import "plyr/dist/plyr.css";
  48. import Plyr from "plyr";
  49. import { Vue3Lottie } from "vue3-lottie";
  50. import audioBga from "./images/audioBga.json";
  51. import audioBga1 from "./images/leftCloud.json";
  52. import audioBga2 from "./images/rightCloud.json";
  53. import videobg from "./images/videobg.png";
  54. import audioVisualDraw from "./audioVisualDraw"
  55. import playProgressData from "./playCreation/playProgress"
  56. export default defineComponent({
  57. name: 'creation-detail',
  58. setup() {
  59. const route = useRoute();
  60. const router = useRouter();
  61. const isScreenScroll = ref(false)
  62. const creationHeight = ref(0)
  63. const lottieDom = ref()
  64. const lottieDom1 = ref()
  65. const lottieDom2 = ref()
  66. const state = reactive({
  67. id: route.query.id,
  68. isEmpty:false,
  69. loginTag: false, // 是否登录标识
  70. loginStatus: false,
  71. loginChangeState: false, // 切换账号
  72. credential: {} as any,
  73. playType: '' as 'Audio' | 'Video' | '', // 播放类型
  74. musicDetail: {} as any,
  75. isClick: false,
  76. list: [] as any,
  77. listState: {
  78. dataShow: true, // 判断是否有数据
  79. loading: false,
  80. finished: false
  81. },
  82. params: {
  83. page: 1,
  84. rows: 20
  85. },
  86. messageStatus: false,
  87. message: '',
  88. _plrl: null as any,
  89. heightV:0,
  90. heightB:0
  91. });
  92. const plyrState = reactive({
  93. duration: 0,
  94. currentTime: 0,
  95. mediaTimeShow: false,
  96. playIngShow: true,
  97. loaded:false
  98. })
  99. // 谱面
  100. const staffState = reactive({
  101. staffSrc: "",
  102. isShow: false,
  103. height:"initial",
  104. speedRate:1,
  105. musicRenderType:"staff",
  106. partIndex:0
  107. })
  108. const staffDom= ref<HTMLIFrameElement>()
  109. const {playStaff, pauseStaff, updateProgressStaff} = staffMoveInstance()
  110. let isInitAudioVisualDraw =false
  111. // 点赞
  112. const onStarChange = async () => {
  113. await checkLogin();
  114. // 是否登录
  115. if (!state.loginTag) {
  116. state.loginStatus = true;
  117. return;
  118. }
  119. try {
  120. await api_userMusicStar({
  121. userMusicId: state.id,
  122. star: !state.musicDetail.starFlag
  123. });
  124. state.musicDetail.starFlag = !state.musicDetail.starFlag;
  125. if (state.musicDetail.starFlag) {
  126. state.musicDetail.likeNum += 1;
  127. } else {
  128. state.musicDetail.likeNum -= 1;
  129. }
  130. } catch {
  131. //
  132. }
  133. };
  134. // 获取列表
  135. const getList = async () => {
  136. try {
  137. if (state.isClick) return;
  138. state.isClick = true;
  139. const res = await api_openUserMusicPage({
  140. type: 'FORMAL',
  141. exclusionId: state.id,
  142. sort: 1,
  143. ...state.params
  144. });
  145. state.listState.loading = false;
  146. const result = res.data || {};
  147. // 处理重复请求数据
  148. if (state.list.length > 0 && result.current === 1) {
  149. return;
  150. }
  151. state.list = state.list.concat(result.rows || []);
  152. state.listState.finished = result.current >= result.pages;
  153. state.params.page = result.current + 1;
  154. state.listState.dataShow = state.list.length > 0;
  155. state.isClick = false;
  156. } catch {
  157. state.listState.dataShow = false;
  158. state.listState.finished = true;
  159. state.isClick = false;
  160. }
  161. };
  162. const onDetail = (item: any) => {
  163. playProgressData.playProgress = 0
  164. playProgressData.playState = false
  165. router.push({
  166. path: '/shareCreation',
  167. query: {
  168. id: item.id
  169. }
  170. });
  171. };
  172. // 初始化 媒体播放
  173. function initMediaPlay(){
  174. const id = state.playType === "Audio" ? "#audioMediaSrc" : "#videoMediaSrc";
  175. state._plrl = new Plyr(id, {
  176. controls: ["progress"],
  177. fullscreen: { enabled: false },
  178. });
  179. const player = state._plrl
  180. // 在微信中运行的时候,微信没有开放自动加载资源的权限,所以要等播放之后才显示播放控制器
  181. player.on('loadedmetadata', () => {
  182. plyrState.loaded = true
  183. player.currentTime = playProgressData.playProgress
  184. if(playProgressData.playState) handlerClickPlay()
  185. });
  186. player.on("timeupdate", ()=>{
  187. plyrState.currentTime = player.currentTime
  188. })
  189. player.on('play', () => {
  190. plyrState.playIngShow = false
  191. playStaff()
  192. });
  193. player.on('pause', () => {
  194. plyrState.playIngShow = true
  195. pauseStaff()
  196. });
  197. // 处理按压事件
  198. const handleStart = () => {
  199. plyrState.duration = player.duration
  200. plyrState.mediaTimeShow = true
  201. };
  202. // 处理松开事件
  203. const handleEnd = () => {
  204. plyrState.mediaTimeShow = false
  205. // 暂停的时候调用
  206. if(!player.playing){
  207. updateProgressStaff(player.currentTime)
  208. }
  209. };
  210. const progressDom = document.querySelector("#playMediaSection .plyr__controls .plyr__progress__container") as HTMLElement
  211. progressDom.addEventListener('mousedown', handleStart);
  212. progressDom.addEventListener('touchstart', handleStart);
  213. progressDom.addEventListener('mouseup', handleEnd);
  214. progressDom.addEventListener('touchend', handleEnd);
  215. }
  216. //点击改变播放状态
  217. function handlerClickPlay(){
  218. const player = state._plrl;
  219. // 由于ios低版本必须在用户操作之后才能初始化 createMediaElementSource 所以必须在用户操作之后初始化
  220. if(!isInitAudioVisualDraw && state.playType === "Audio"){
  221. isInitAudioVisualDraw = true
  222. // 创建音波数据
  223. const audioDom = document.querySelector("#audioMediaSrc") as HTMLAudioElement
  224. const canvasDom = document.querySelector("#audioVisualizer") as HTMLCanvasElement
  225. const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
  226. player.on('play', () => {
  227. lottieDom.value.play()
  228. lottieDom1.value.play()
  229. lottieDom2.value.play()
  230. playVisualDraw()
  231. });
  232. player.on('pause', () => {
  233. lottieDom.value.pause()
  234. lottieDom1.value.pause()
  235. lottieDom2.value.pause()
  236. pauseVisualDraw()
  237. });
  238. }
  239. if (player.playing) {
  240. player.pause();
  241. } else {
  242. player.play();
  243. }
  244. }
  245. function handlerLandscapeScreen(event:any){
  246. event.stopPropagation()
  247. playProgressData.playState = !!state._plrl?.playing
  248. playProgressData.playProgress = state._plrl?.currentTime || 0
  249. router.push({
  250. path:"/playCreation",
  251. query:{
  252. resourceUrl:encodeURIComponent(state.musicDetail?.videoUrl),
  253. videoBgUrl:encodeURIComponent(state.musicDetail?.videoImg),
  254. musicSheetName:encodeURIComponent(state.musicDetail?.musicSheetName),
  255. username:encodeURIComponent(state.musicDetail?.username),
  256. musicSheetId:encodeURIComponent(state.musicDetail?.musicSheetId),
  257. speedRate:encodeURIComponent(staffState.speedRate),
  258. musicRenderType:encodeURIComponent(staffState.musicRenderType),
  259. partIndex:encodeURIComponent(staffState.partIndex),
  260. }
  261. })
  262. }
  263. const checkLogin = async () => {
  264. try {
  265. // 判断是否登录
  266. const Authorization = storage.get(ACCESS_TOKEN) || '';
  267. if (Authorization) {
  268. const res = await api_verification({
  269. token: Authorization
  270. });
  271. console.log(res.data, 'res.data');
  272. state.loginTag = res.data;
  273. if (!res.data) {
  274. removeAuth();
  275. setLogout();
  276. }
  277. }
  278. } catch (err) {
  279. //
  280. storage.remove(ACCESS_TOKEN);
  281. removeAuth();
  282. setLogout();
  283. state.loginTag = false;
  284. }
  285. };
  286. const __init = async () => {
  287. await checkLogin();
  288. try {
  289. const res = await api_openUserMusicDetail(state.id);
  290. if (res.code === 999) {
  291. // 没有的时候显示缺省页
  292. state.isEmpty = true
  293. return;
  294. } else {
  295. state.musicDetail = res.data;
  296. try{
  297. const jsonConfig = JSON.parse(res.data.jsonConfig)
  298. jsonConfig.speedRate && (staffState.speedRate = jsonConfig.speedRate)
  299. jsonConfig.musicRenderType && (staffState.musicRenderType = jsonConfig.musicRenderType)
  300. jsonConfig.partIndex && (staffState.partIndex = jsonConfig.partIndex)
  301. }catch{
  302. }
  303. // 五线谱
  304. initStaff()
  305. getList();
  306. // 判断是视频还是音频
  307. if (res.data.videoUrl.lastIndexOf('mp4') !== -1) {
  308. state.playType = 'Video';
  309. } else {
  310. state.playType = 'Audio';
  311. }
  312. // 初始化
  313. nextTick(() => {
  314. initMediaPlay();
  315. });
  316. }
  317. } catch (err:any) {
  318. // 没有的时候显示缺省页
  319. state.message = err;
  320. state.messageStatus = true;
  321. }
  322. };
  323. // 滚动事件
  324. const cleanScrollEvent = useEventListener('scroll', () => {
  325. creationHeight.value = window.innerHeight
  326. const height =
  327. window.scrollY ||
  328. document.documentElement.scrollTop
  329. // 防止多次调用
  330. if(height > 0 && isScreenScroll.value === false){
  331. isScreenScroll.value = true
  332. }
  333. if(height <= 0){
  334. isScreenScroll.value = false
  335. }
  336. })
  337. function handlerDownLoad(){
  338. router.push({
  339. path:"/transfer"
  340. })
  341. }
  342. const pageVisibility = usePageVisibility();
  343. watch(pageVisibility, value => {
  344. if (value === 'hidden') {
  345. state._plrl?.pause();
  346. }
  347. });
  348. // 初始化五线谱
  349. function initStaff(){
  350. const src = `${vaildMusicScoreUrl()}/instrument/#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
  351. //const src = `http://192.168.3.122:3000/instrument.html#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
  352. staffState.staffSrc = src
  353. window.addEventListener('message', (event) => {
  354. const { api, height } = event.data;
  355. if (api === 'api_musicPage') {
  356. staffState.isShow = true
  357. staffState.height = height + "px"
  358. // 如果是播放中自动开始 播放
  359. if(state._plrl.playing){
  360. playStaff()
  361. }
  362. }
  363. });
  364. }
  365. function staffMoveInstance(){
  366. let isPause = true
  367. const requestAnimationFrameFun = () => {
  368. requestAnimationFrame(() => {
  369. staffDom.value?.contentWindow?.postMessage(
  370. {
  371. api: 'api_playProgress',
  372. content: {
  373. currentTime: state._plrl.currentTime * staffState.speedRate
  374. }
  375. },
  376. "*"
  377. )
  378. if (!isPause) {
  379. requestAnimationFrameFun()
  380. }
  381. })
  382. }
  383. const playStaff = () => {
  384. // 没渲染不执行
  385. if(!staffState.isShow) return
  386. isPause = false
  387. staffDom.value?.contentWindow?.postMessage(
  388. {
  389. api: 'api_play'
  390. },
  391. "*"
  392. )
  393. requestAnimationFrameFun()
  394. }
  395. const pauseStaff = () => {
  396. // 没渲染不执行
  397. if(!staffState.isShow) return
  398. isPause = true
  399. staffDom.value?.contentWindow?.postMessage(
  400. {
  401. api: 'api_paused'
  402. },
  403. "*"
  404. )
  405. }
  406. const updateProgressStaff = (currentTime: number) => {
  407. // 没渲染不执行
  408. if(!staffState.isShow) return
  409. staffDom.value?.contentWindow?.postMessage(
  410. {
  411. api: 'api_updateProgress',
  412. content: {
  413. currentTime: currentTime * staffState.speedRate
  414. }
  415. },
  416. "*"
  417. )
  418. }
  419. return {
  420. playStaff,
  421. pauseStaff,
  422. updateProgressStaff
  423. }
  424. }
  425. onMounted(async () => {
  426. __init();
  427. });
  428. onUnmounted(() => {
  429. cleanScrollEvent()
  430. });
  431. onBeforeRouteUpdate((to: any) => {
  432. state.id = to.query.id;
  433. state.playType = '';
  434. state.params.page = 1;
  435. state.list = [];
  436. isInitAudioVisualDraw = false
  437. if(state._plrl){
  438. state._plrl.destroy()
  439. }
  440. staffState.staffSrc = ""
  441. staffState.isShow = false
  442. staffState.height = "initial"
  443. __init();
  444. });
  445. onBeforeRouteLeave((to, from, next)=>{
  446. if(to.path !== "/playCreation"){
  447. playProgressData.playProgress = 0
  448. playProgressData.playState = false
  449. }
  450. next()
  451. })
  452. return () => (
  453. <div
  454. style={
  455. {
  456. '--barheight':state.heightV + "px"
  457. }
  458. }
  459. class={[
  460. styles.creation,
  461. browser().isTablet ? styles.creationTablet : '',
  462. isScreenScroll.value && styles.isShareScreenScroll
  463. ]}>
  464. <div style={ creationHeight.value ? {"--creationHeight":creationHeight.value + "px"} : {}} class={styles.creationBg}></div>
  465. <MSticky position="top"
  466. onBarHeight={(height: any) => {
  467. console.log(height, 'height', height)
  468. state.heightV = height
  469. }}
  470. >
  471. <div class={styles.logoDownload}>
  472. <img src={isScreenScroll.value ? logo1Img : logoImg} class={styles.logoImg}></img>
  473. <div class={styles.logTit} onClick={handlerDownLoad}>下载App</div>
  474. </div>
  475. </MSticky>
  476. {
  477. state.isEmpty ?
  478. <div class={styles.isEmpty}>
  479. <MEmpty image={"empty2"} description="作品已删除~" />
  480. </div> :
  481. <>
  482. <div class={styles.singerBox}>
  483. <div class={styles.musicSheetName}>
  484. {state.musicDetail?.musicSheetName}
  485. </div>
  486. <div class={styles.singerName}>
  487. 演奏:{state.musicDetail?.username}
  488. </div>
  489. </div>
  490. <Sticky offsetTop={state.heightV - 1 + "px"}>
  491. <div class={[styles.playSection, plyrState.mediaTimeShow && styles.mediaTimeShow,!plyrState.loaded && styles.notLoaded]} id="playMediaSection" onClick={handlerClickPlay}>
  492. {
  493. state.playType &&
  494. <>
  495. {
  496. state.playType === 'Audio' &&
  497. <div class={styles.audioBox}>
  498. <canvas class={styles.audioVisualizer} id="audioVisualizer"></canvas>
  499. <Vue3Lottie ref={lottieDom} class={styles.audioBga} animationData={audioBga} autoPlay={false} loop={true}></Vue3Lottie>
  500. <Vue3Lottie ref={lottieDom1} class={styles.audioBga1} animationData={audioBga1} autoPlay={false} loop={true}></Vue3Lottie>
  501. <Vue3Lottie ref={lottieDom2} class={styles.audioBga2} animationData={audioBga2} autoPlay={false} loop={true}></Vue3Lottie>
  502. <audio
  503. crossorigin="anonymous"
  504. id="audioMediaSrc"
  505. src={state.musicDetail?.videoUrl}
  506. controls="false"
  507. preload="metadata"
  508. playsinline
  509. />
  510. </div>
  511. }
  512. {
  513. state.playType === 'Video' &&
  514. <video
  515. id="videoMediaSrc"
  516. class={styles.videoBox}
  517. src={state.musicDetail?.videoUrl}
  518. data-poster={ state.musicDetail?.videoImg || videobg}
  519. preload="metadata"
  520. playsinline
  521. />
  522. }
  523. <div class={[styles.playLarge, plyrState.playIngShow && styles.playIngShow]}></div>
  524. <div class={styles.mediaTime}>
  525. <div>
  526. {getSecondRPM(plyrState.currentTime)}
  527. </div>
  528. <div class={styles.note}>/</div>
  529. <div class={styles.duration}>
  530. {getSecondRPM(plyrState.duration)}
  531. </div>
  532. </div>
  533. <div class={styles.landscapeScreen} onClick={handlerLandscapeScreen}></div>
  534. {/* 谱面 */}
  535. {
  536. staffState.staffSrc &&
  537. <div
  538. class={[styles.staffBox, staffState.isShow && styles.staffBoxShow]}
  539. style={
  540. {
  541. '--staffBoxHeight':staffState.height
  542. }
  543. }
  544. >
  545. <div class={styles.mask}></div>
  546. <iframe
  547. ref={staffDom}
  548. class={styles.staff}
  549. frameborder="0"
  550. src={staffState.staffSrc}>
  551. </iframe>
  552. </div>
  553. }
  554. </>
  555. }
  556. </div>
  557. </Sticky>
  558. <div class={[styles.musicSection, styles.musicShareSection]}>
  559. <div class={styles.avatarInfoBox}>
  560. <div class={styles.avatar}>
  561. <Image class={styles.userLogo} src={state.musicDetail.avatar} />
  562. <div class={styles.infoCon}>
  563. <div class={styles.info}>
  564. <span class={styles.userName}>{state.musicDetail?.username}</span>
  565. {state.musicDetail.vipFlag && (
  566. <img src={iconMember} class={styles.iconMember} />
  567. )}
  568. </div>
  569. <div class={styles.sub}>
  570. {state.musicDetail.subjectName}{' '}
  571. {getGradeCh(state.musicDetail.currentGradeNum - 1)}
  572. </div>
  573. </div>
  574. </div>
  575. <div class={styles.linkes} onClick={onStarChange}>
  576. <img src={state.musicDetail.starFlag ? iconZanActive : iconZan} class={styles.iconZan} />
  577. <span>{state.musicDetail.likeNum}</span>
  578. </div>
  579. </div>
  580. <TextEllipsis class={styles.textEllipsis} rows={2} content={state.musicDetail?.desc} expand-text="展开" collapse-text="收起" />
  581. </div>
  582. <div class={styles.likeSection}>
  583. <div class={styles.likeTitle}>推荐作品</div>
  584. {state.listState.dataShow ? (
  585. <List
  586. finished={state.listState.finished}
  587. finishedText=" "
  588. class={[styles.container, styles.containerInformation]}
  589. onLoad={getList}
  590. immediateCheck={false}>
  591. {state.list.map((item: any, index: number) => (
  592. <Cell
  593. class={[styles.likeShareItem, index===state.list.length-1&&styles.likeShareItemLast]}
  594. border={false}
  595. onClick={() => onDetail(item)}
  596. >
  597. {{
  598. icon: () => (
  599. <div class={styles.audioImgBox}>
  600. <img
  601. src={audioPan}
  602. class={styles.audioPan}
  603. crossorigin="anonymous"
  604. />
  605. <img
  606. src={
  607. item.img || musicBg
  608. }
  609. class={styles.muploader}
  610. crossorigin="anonymous"
  611. />
  612. <img class={styles.imgLabel} src={item.videoUrl?.lastIndexOf('mp4') !== -1 ? videoLabel : audioLabel} />
  613. </div>
  614. ),
  615. title: () => (
  616. <div class={styles.userInfo}>
  617. <div class={[styles.musicSheetName,'van-ellipsis']}>{item.musicSheetName}</div>
  618. <div class={styles.usernameCon}>
  619. <div class={styles.likeNum}>
  620. <img src={iconZanActive} />
  621. <span>{item.likeNum}</span>
  622. </div>
  623. <div class={styles.username}>{item.username}</div>
  624. </div>
  625. </div>
  626. ),
  627. value: () => (
  628. <img src={playImg} class={styles.playImg} />
  629. )
  630. }}
  631. </Cell>
  632. ))}
  633. </List>
  634. ) : (
  635. <MEmpty image={"empty2"} description="暂无作品" />
  636. )}
  637. </div>
  638. {
  639. !isScreenScroll.value &&
  640. <MSticky position="bottom" offsetBottom={state.heightB - 1 + "px"} >
  641. <div class={styles.upward}>
  642. <img src={iconUpward} />
  643. </div>
  644. </MSticky>
  645. }
  646. </>
  647. }
  648. <Popup
  649. v-model:show={state.loginStatus}
  650. style={{ background: 'transparent', overflow: 'inherit' }}>
  651. <LoginModel
  652. isRegister
  653. onClose={() => (state.loginStatus = false)}
  654. onConfirm={async (val: any) => {
  655. if (val.loginTag) {
  656. state.loginTag = val.loginTag;
  657. state.loginStatus = false;
  658. const { data } = await api_openUserMusicDetail(state.id);
  659. state.musicDetail = data;
  660. } else {
  661. state.credential = val.data;
  662. state.loginChangeState = true;
  663. state.loginStatus = false;
  664. }
  665. }}
  666. />
  667. </Popup>
  668. <Popup
  669. v-model:show={state.loginChangeState}
  670. style={{ background: 'transparent', overflow: 'inherit' }}>
  671. <LoginChangeModel
  672. credential={state.credential}
  673. onClose={() => {
  674. state.credential = {};
  675. state.loginChangeState = false;
  676. }}
  677. onConfirm={async (val: any) => {
  678. state.loginTag = val.loginTag;
  679. state.loginChangeState = false;
  680. const { data } = await api_openUserMusicDetail(state.id);
  681. state.musicDetail = data;
  682. }}
  683. />
  684. </Popup>
  685. <MWxTip
  686. v-model:show={state.messageStatus}
  687. message={state.message}
  688. showButton={false}
  689. />
  690. </div>
  691. );
  692. }
  693. });