import { defineComponent, onMounted, onUnmounted, onBeforeMount, reactive, ref, watch, nextTick, } from 'vue' // import WaveSurfer from 'wavesurfer.js'; // import Regions from 'wavesurfer.js/dist/plugins/regions.js'; import styles from './index.module.less' import { Cell, Image, List, Popup, Slider, Sticky, NoticeBar, Toast } from 'vant' import TextEllipsis from './text-ellipsis/index'; import MSticky from '@/components/col-sticky' import MHeader from '@/components/col-header' 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 backImg from "./images/back.png"; import videobg from "./images/videobg.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 btnImg from './images/btn.png'; import iconUpward from './images/upward.png'; import vipIcon from './images/vip_icon.png'; import svipIcon from './images/svip_icon.png'; import wxBg from './images/wx_bg.png'; import tyBg from './images/ty.png'; import { browser, getAuth, getGradeCh, getSecondRPM, removeAuth } from '@/helpers/utils' import { postMessage, promisefiyPostMessage } from '@/helpers/native-message' import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router' import { api_openUserMusicDetail, api_openUserMusicPage, api_userMusicStar, api_verification } from './api' import MEmpty from '@/components/col-result' import LoginModel from './login-model' import { setLogout } from '@/state' import MWxTip from '@/components/the-wx-tip' import { usePageVisibility } from '@vant/use' import "plyr/dist/plyr.css"; import Plyr from "plyr"; import audioVisualDraw from "./audioVisualDraw" import Loading from './loading'; 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, playType: '' as 'Audio' | 'Video' | '', // 播放类型 musicDetail: {} as any, timer: null as any, paused: true, audioWidth: 0, currentTime: 0, duration: 0.1, loop: false, dragStatus: false, // 是否开始拖动 isClick: false, list: [] as any, listState: { dataShow: true, // 判断是否有数据 loading: false, finished: false }, params: { page: 1, rows: 4 }, messageStatus: false, message: '' as any, _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 = state.list.concat(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) => { 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 + '/#/transfer' } }, 3000) } } 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 = `ColexiuStudent://linkUrl=${iosStr}` } else if (/(Android)/i.test(userAgent)) { window.location.href = `colexiustudent://html:8888/SplashActivity?url=${iosStr}` } else { Toast('请用手机或移动设备打开') } } const checkLogin = async () => { try { // 判断是否登录 const Authorization = getAuth() // storage.get(ACCESS_TOKEN) || '' if (Authorization) { await api_verification({ token: Authorization }) state.loginTag = true // if (!res.data) { // removeAuth() // setLogout() // } } } catch (e: any) { // 登录是否有效 state.loginTag = false removeAuth() setLogout() } }; 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["part-index"] && (staffState.partIndex = jsonConfig["part-index"]) }catch{ } // 五线谱 initStaff() getList() // 判断是视频还是音频 if (res.data.videoUrl.lastIndexOf('mp4') !== -1) { state.playType = 'Video' } else { state.playType = 'Audio' } // 初始化 nextTick(() => { initMediaPlay(); }); } } catch (err) { state.listState.dataShow = false // 没有的时候显示缺省页 state.message = err; state.messageStatus = true; } } // 滚动事件 const handleScroll = () => { // 作品已删除不让滚动变色 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{ // 如果是老师端 if (window.location.pathname.includes('teacher')) { window.location.href = location.origin + '/student' + '/#/transfer' } else { router.push({ path:"/transfer" }) } } } const pageVisibility = usePageVisibility() watch(pageVisibility, value => { if (value === 'hidden') { state._plrl?.pause(); } }); // 初始化五线谱 function initStaff(){ const src = `/klx-music-score/#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}&userMusicId=${state.id}`; // const src = `http://192.168.3.68:3000/instrument.html#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}&userMusicId=${state.id}`; 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 () => { window.addEventListener("scroll", handleScroll) __init() setFullHeight() window.addEventListener('resize', setFullHeight) }) onUnmounted(() => { window.removeEventListener("scroll", handleScroll) 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(); }) return () => (
{ console.log(height, 'height', height) state.heightV = height }} > { isApp ? { setStatusBarTextColor(false) postMessage({ api: 'back' }); }} /> :
下载App
}
{ state.isEmpty ?
: <>
演奏:{state.musicDetail?.username}
{ isLandscapeScreen.value &&
演奏:{state.musicDetail?.username}
} { state.playType && <> { state.playType === 'Audio' &&
} { state.playType === 'Video' &&
{ (state.musicDetail.vipType === 'VIP' || state.musicDetail.vipType === 'PERMANENT_SVIP' || state.musicDetail.vipType === 'SVIP') && }
{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: boolean) => { state.loginTag = val state.loginStatus = false const { data } = await api_openUserMusicDetail(state.id) state.musicDetail = data }} /> { !staffState.isShow && } {wxStatus.value && (
{ wxStatus.value = false; }}>
)}
) } })