import { defineComponent, onMounted, onUnmounted, reactive, ref, watch, nextTick, onBeforeMount } from 'vue'; // import WaveSurfer from 'wavesurfer.js'; // import Regions from 'wavesurfer.js/dist/plugins/regions.js'; import styles from './index.module.less'; import MHeader from '@/components/m-header'; import { Cell, Image, List, Popup, Sticky, TextEllipsis, NoticeBar, showConfirmDialog, showToast } from 'vant'; import iconMember from './images/icon-member.png'; import iconZan from './images/icon-zan.png'; import iconZanActive from './images/icon-zan-active.png'; import logoImg from './images/logo.png'; import logo1Img from './images/logo1.png'; import iconUpward from './images/upward.png'; import iconPlay from './images/icon-play.png'; import iconPause from './images/icon-pause.png'; import audioPan from './images/audio-pan.png'; import audioLabel from './share-model/images/audioLabel.png'; import videoLabel from './share-model/images/videoLabel.png'; import musicBg from './share-model/images/music-bg.png'; import playImg from './images/play.png'; import { browser, getGradeCh, getSecondRPM, vaildMusicScoreUrl } from '@/helpers/utils'; import { onBeforeRouteUpdate, useRoute, useRouter, onBeforeRouteLeave } from 'vue-router'; import { postMessage } from '@/helpers/native-message'; import { api_openUserMusicDetail, api_openUserMusicPage, api_userMusicStar, api_verification } from './api'; import MEmpty from '@/components/m-empty'; import MVideo from '@/components/m-video'; import LoginModel from './login-model'; import { removeAuth } from '../student-register/layout/utils'; import { setLogout } from '@/state'; import { storage } from '@/helpers/storage'; import { ACCESS_TOKEN } from '@/store/mutation-types'; import MWxTip from '@/components/m-wx-tip'; import { usePageVisibility, useEventListener, useWindowSize } from '@vant/use'; import LoginChangeModel from './login-change-model'; import MSticky from '@/components/m-sticky'; import "plyr/dist/plyr.css"; import Plyr from "plyr"; import { Vue3Lottie } from "vue3-lottie"; import audioBga from "./images/audioBga.json"; import audioBga1 from "./images/leftCloud.json"; import audioBga2 from "./images/rightCloud.json"; import videobg from "./images/videobg.png"; import btnImg from './images/btn.png'; import audioVisualDraw from "./audioVisualDraw" //import playProgressData from "./playCreation/playProgress" import Loading from './loading'; import backImg from "./images/back.png"; import wxBg from '../download/images/wx_bg.png'; export default defineComponent({ name: 'creation-detail', setup() { const {isApp, isTablet, weixin} = browser() const route = useRoute(); const router = useRouter(); const isScreenScroll = ref(false) const creationHeight = ref(0) const state = reactive({ id: route.query.id, isEmpty:false, loginTag: false, // 是否登录标识 loginStatus: false, loginChangeState: false, // 切换账号 credential: {} as any, playType: '' as 'Audio' | 'Video' | '', // 播放类型 musicDetail: {} as any, isClick: false, list: [] as any, listState: { dataShow: true, // 判断是否有数据 loading: false, finished: false }, params: { page: 1, rows: 4 }, messageStatus: false, message: '', _plrl: null as any, heightV:0, heightB:0 }); const plyrState = reactive({ duration: 0, currentTime: 0, mediaTimeShow: false, playIngShow: true, loaded:false }) // 谱面 const staffState = reactive({ staffSrc: "", isShow: false, height:"initial", speedRate:1, musicRenderType:"staff", partIndex:0 }) const isLandscapeScreen = ref(false) const wxStatus = ref(false) const staffDom= ref() const {playStaff, pauseStaff, updateProgressStaff} = staffMoveInstance() // 点赞 const onStarChange = async () => { await checkLogin(); // 是否登录 if (!state.loginTag) { state.loginStatus = true; return; } try { await api_userMusicStar({ userMusicId: state.id, star: !state.musicDetail.starFlag }); state.musicDetail.starFlag = !state.musicDetail.starFlag; if (state.musicDetail.starFlag) { state.musicDetail.likeNum += 1; } else { state.musicDetail.likeNum -= 1; } } catch { // } }; // 获取列表 const getList = async () => { try { if (state.isClick) return; state.isClick = true; const res = await api_openUserMusicPage({ type: 'FORMAL', exclusionId: state.id, sort: 1, ...state.params }); state.listState.loading = false; const result = res.data || {}; // 处理重复请求数据 // if (state.list.length > 0 && result.current === 1) { // return; // } state.list = result.rows || []; state.listState.finished = result.current >= result.pages; state.params.page = result.current + 1; state.listState.dataShow = state.list.length > 0; state.isClick = false; } catch { state.listState.dataShow = false; state.listState.finished = true; state.isClick = false; } }; function handleChangeList() { if(state.listState.finished){ state.listState.finished = false state.params.page = 1; getList() }else{ getList() } } const onDetail = (item: any) => { // playProgressData.playProgress = 0 // playProgressData.playState = false router.push({ path: '/shareCreation', query: { id: item.id } }); }; // 初始化 媒体播放 function initMediaPlay(){ const id = state.playType === "Audio" ? "#audioMediaSrc" : "#videoMediaSrc"; state._plrl = new Plyr(id, { controls: ["play", "progress", "current-time", "duration"], fullscreen: { enabled: false, fallback: false } }); const player = state._plrl // 创建音波数据 if(state.playType === "Audio"){ const audioDom = document.querySelector("#audioMediaSrc") as HTMLAudioElement const canvasDom = document.querySelector("#audioVisualizer") as HTMLCanvasElement const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom) player.on('play', () => { playVisualDraw() }); player.on('pause', () => { pauseVisualDraw() }); } // 在微信中运行的时候,微信没有开放自动加载资源的权限,所以要等播放之后才显示播放控制器 player.on('loadedmetadata', () => { plyrState.loaded = true //player.currentTime = playProgressData.playProgress }); player.on("timeupdate", ()=>{ plyrState.currentTime = player.currentTime }) player.on('play', () => { plyrState.playIngShow = false playStaff() }); player.on('pause', () => { plyrState.playIngShow = true pauseStaff() }); player.on('ended', () => { player.currentTime = 0 if(!player.playing){ setTimeout(() => { updateProgressStaff(player.currentTime) }, 100); } }); // 处理按压事件 const handleStart = () => { if(isLandscapeScreen.value){ return } plyrState.duration = player.duration plyrState.mediaTimeShow = true }; // 处理松开事件 const handleEnd = () => { plyrState.mediaTimeShow = false // 暂停的时候调用 if(!player.playing){ updateProgressStaff(player.currentTime) } }; const progressDom = document.querySelector("#playMediaSection .plyr__controls .plyr__progress__container") as HTMLElement progressDom.addEventListener('mousedown', handleStart); progressDom.addEventListener('touchstart', handleStart); progressDom.addEventListener('mouseup', handleEnd); progressDom.addEventListener('touchend', handleEnd); } //点击改变播放状态 function handlerClickPlay(event?:MouseEvent){ // 原生 播放暂停按钮 点击的时候 不触发 // @ts-ignore if(event?.target?.matches('button.plyr__control')){ return } const player = state._plrl; if (player.playing) { player.pause(); } else { player.play(); } } function handlerBack(event:any){ event.stopPropagation() verticalScreen() } function landscapeScreen(){ postMessage({ api: "setRequestedOrientation", content: { orientation: 0, }, }); isLandscapeScreen.value = true } function verticalScreen(){ postMessage({ api: "setRequestedOrientation", content: { orientation: 1, }, }); isLandscapeScreen.value = false } function handlerLandscapeScreen(event:any){ event.stopPropagation() if(isApp){ landscapeScreen() return } if(weixin){ wxStatus.value = true }else{ const t = Date.now() const str = location.href shareCall(str) setTimeout(() => { if(Date.now() - t < 3500){ window.location.href = location.origin + '/classroom-app/#/transfer' } }, 3000) } // showConfirmDialog({ // className: "dialogMusicClass", // message: '即将离开\n打开“音乐数字课堂”', // confirmButtonText: "允许", // cancelButtonText: "取消" // }).then(() => { // const str = location.href // shareCall(str) // }); // playProgressData.playState = !!state._plrl?.playing // playProgressData.playProgress = state._plrl?.currentTime || 0 // router.push({ // path:"/playCreation", // query:{ // resourceUrl:encodeURIComponent(state.musicDetail?.videoUrl), // videoBgUrl:encodeURIComponent(state.musicDetail?.videoImg || ""), // musicSheetName:encodeURIComponent(state.musicDetail?.musicSheetName), // username:encodeURIComponent(state.musicDetail?.username), // musicSheetId:encodeURIComponent(state.musicDetail?.musicSheetId), // speedRate:encodeURIComponent(staffState.speedRate), // musicRenderType:encodeURIComponent(staffState.musicRenderType), // partIndex:encodeURIComponent(staffState.partIndex), // } // }) } const shareCall = (str: string, params?: any) => { const query = { url: str, action: params?.action || 'h5', // app, h5 pageTag: params?.pageTag || 1 // 页面标识 } const iosStr = encodeURIComponent(JSON.stringify(query)) const userAgent = navigator.userAgent || navigator.vendor; const platform = navigator.platform || 'unknown'; if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent) || (platform === 'MacIntel')) { window.location.href = `BandInstrumentTeam://linkUrl=${iosStr}` } else if (/(Android)/i.test(userAgent)) { window.location.href = `colexiukt://html:8888/SplashActivity?url=${iosStr}` } else { showToast('请用手机或移动设备打开') } } const checkLogin = async () => { try { // 判断是否登录 const Authorization = storage.get(ACCESS_TOKEN) || ''; if (Authorization) { const res = await api_verification({ token: Authorization }); console.log(res.data, 'res.data'); state.loginTag = res.data; if (!res.data) { removeAuth(); setLogout(); } } } catch (err) { // storage.remove(ACCESS_TOKEN); removeAuth(); setLogout(); state.loginTag = false; } }; const __init = async () => { await checkLogin(); try { const res = await api_openUserMusicDetail(state.id); if (res.code === 999) { // 没有的时候显示缺省页 state.isEmpty = true staffState.isShow = true return; } else { state.musicDetail = res.data; try{ const jsonConfig = JSON.parse(res.data.jsonConfig) jsonConfig.speedRate && (staffState.speedRate = jsonConfig.speedRate) jsonConfig.musicRenderType && (staffState.musicRenderType = jsonConfig.musicRenderType) jsonConfig.partIndex && (staffState.partIndex = jsonConfig.partIndex) }catch{ } // 五线谱 initStaff() getList(); // 判断是视频还是音频 if (res.data.videoUrl.lastIndexOf('mp4') !== -1) { state.playType = 'Video'; } else { state.playType = 'Audio'; } // 初始化 nextTick(() => { initMediaPlay(); }); } } catch (err:any) { // 没有的时候显示缺省页 state.message = err; state.messageStatus = true; } }; // 滚动事件 const cleanScrollEvent = useEventListener('scroll', () => { // 作品已删除不让滚动变色 if(state.isEmpty) return const height = window.scrollY || document.documentElement.scrollTop // 防止多次调用 if(height > 0 && isScreenScroll.value === false){ isScreenScroll.value = true if(isApp){ setStatusBarTextColor(false) } } if(height <= 0){ isScreenScroll.value = false if(isApp){ setStatusBarTextColor(true) } } }) function handlerDownLoad(){ if(weixin){ wxStatus.value = true }else{ router.push({ path:"/transfer" }) } } const pageVisibility = usePageVisibility(); watch(pageVisibility, value => { if (value === 'hidden') { state._plrl?.pause(); } }); // 初始化五线谱 function initStaff(){ const src = `${vaildMusicScoreUrl()}/instrument/#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`; //const src = `http://192.168.3.122:3000/instrument.html#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`; staffState.staffSrc = src window.addEventListener('message', (event) => { const { api, height } = event.data; if (api === 'api_musicPage') { staffState.isShow = true staffState.height = height + "px" // 如果是播放中自动开始播放 不是播放 自动跳转到当前位置 // if(playProgressData.playState){ // handlerClickPlay() // }else{ // updateProgressStaff(state._plrl.currentTime) // } } }); } function staffMoveInstance(){ let isPause = true const requestAnimationFrameFun = () => { requestAnimationFrame(() => { staffDom.value?.contentWindow?.postMessage( { api: 'api_playProgress', content: { currentTime: state._plrl.currentTime * staffState.speedRate } }, "*" ) if (!isPause) { requestAnimationFrameFun() } }) } const playStaff = () => { // 没渲染不执行 if(!staffState.isShow) return isPause = false staffDom.value?.contentWindow?.postMessage( { api: 'api_play' }, "*" ) requestAnimationFrameFun() } const pauseStaff = () => { // 没渲染不执行 if(!staffState.isShow) return isPause = true staffDom.value?.contentWindow?.postMessage( { api: 'api_paused' }, "*" ) } const updateProgressStaff = (currentTime: number) => { // 没渲染不执行 if(!staffState.isShow) return staffDom.value?.contentWindow?.postMessage( { api: 'api_updateProgress', content: { currentTime: currentTime * staffState.speedRate } }, "*" ) } return { playStaff, pauseStaff, updateProgressStaff } } // 设置导航栏颜色 function setStatusBarTextColor(isWhite:boolean){ postMessage({ api: 'setStatusBarTextColor', content: { statusBarTextColor: isWhite } }) } function setFullHeight(){ creationHeight.value = window.innerHeight } onBeforeMount(() => { if(isApp) { postMessage({ api: "setRequestedOrientation", content: { orientation: 1, }, }); setStatusBarTextColor(true) } }) onMounted(async () => { __init(); setFullHeight() window.addEventListener('resize', setFullHeight) }); onUnmounted(() => { cleanScrollEvent() window.removeEventListener('resize', setFullHeight) state._plrl?.destroy() }); onBeforeRouteUpdate((to: any) => { state.id = to.query.id; state.playType = ''; state.params.page = 1; state.list = []; if(state._plrl){ state._plrl.destroy() } plyrState.playIngShow = true staffState.staffSrc = "" staffState.isShow = false staffState.height = "initial" __init(); }); // onBeforeRouteLeave((to, from, next)=>{ // if(to.path !== "/playCreation"){ // playProgressData.playProgress = 0 // playProgressData.playState = false // } // next() // }) return () => (
{ console.log(height, 'height', height) state.heightV = height }} > { isApp ? { setStatusBarTextColor(false) }} /> :
下载App
}
{ state.isEmpty ?
: <>
演奏:{state.musicDetail?.username}
{ isLandscapeScreen.value &&
演奏:{state.musicDetail?.username}
} { state.playType && <> { state.playType === 'Audio' &&
} { state.playType === 'Video' &&
{state.musicDetail?.username} {state.musicDetail.vipFlag && ( )}
{state.musicDetail.subjectName}{' '} {getGradeCh(state.musicDetail.currentGradeNum - 1)}
{state.musicDetail.likeNum}
推荐作品
{state.listState.dataShow ? ( <> {state.list.map((item: any, index:number) => ( onDetail(item)} > {{ icon: () => (
), title: () => (
{item.musicSheetName}
{item.likeNum}
{item.username}
), value: () => ( ) }}
))}
{ (!state.listState.finished || state.params.page>2) &&
{}} src={btnImg} />
} ) : ( )}
{ !isScreenScroll.value &&
} } (state.loginStatus = false)} onConfirm={async (val: any) => { if (val.loginTag) { state.loginTag = val.loginTag; state.loginStatus = false; const { data } = await api_openUserMusicDetail(state.id); state.musicDetail = data; } else { state.credential = val.data; state.loginChangeState = true; state.loginStatus = false; } }} /> { state.credential = {}; state.loginChangeState = false; }} onConfirm={async (val: any) => { state.loginTag = val.loginTag; state.loginChangeState = false; const { data } = await api_openUserMusicDetail(state.id); state.musicDetail = data; }} /> { !staffState.isShow && } {wxStatus.value && (
{ wxStatus.value = false; }}>
)}
); } });