|
@@ -2,23 +2,33 @@ import {
|
|
|
defineComponent,
|
|
|
onMounted,
|
|
|
onUnmounted,
|
|
|
+ onBeforeMount,
|
|
|
reactive,
|
|
|
ref,
|
|
|
- watch
|
|
|
+ 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 } from 'vant'
|
|
|
-// import iconMember from './images/icon-member.png'
|
|
|
-import iconVip from './images/icon-vip.png'
|
|
|
-import iconSVip from './images/icon-svip.png'
|
|
|
+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 iconZ from './images/icon-z.png'
|
|
|
-import iconPlay from './images/icon-play.png'
|
|
|
-import iconPause from './images/icon-pause.png'
|
|
|
-import videoBg from './images/video-bg.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 {
|
|
|
browser,
|
|
|
getAuth,
|
|
@@ -26,6 +36,7 @@ import {
|
|
|
getSecondRPM,
|
|
|
removeAuth
|
|
|
} from '@/helpers/utils'
|
|
|
+import { postMessage, promisefiyPostMessage } from '@/helpers/native-message'
|
|
|
import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router'
|
|
|
import {
|
|
|
api_openUserMusicDetail,
|
|
@@ -34,21 +45,26 @@ import {
|
|
|
api_verification
|
|
|
} from './api'
|
|
|
import MEmpty from '@/components/col-result'
|
|
|
-import { nextTick } from 'process'
|
|
|
-import MVideo from '@/components/col-video-tcplayer'
|
|
|
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' | '', // 播放类型
|
|
@@ -72,38 +88,35 @@ export default defineComponent({
|
|
|
rows: 20
|
|
|
},
|
|
|
messageStatus: false,
|
|
|
- message: ''
|
|
|
+ message: '' as any,
|
|
|
+ _plrl: null as any,
|
|
|
+ heightV: 0,
|
|
|
+ heightB: 0,
|
|
|
})
|
|
|
- // window.AudioContext = window.AudioContext || window.webkitAudioContext;
|
|
|
- const audioDom = new Audio()
|
|
|
- audioDom.controls = true
|
|
|
- audioDom.style.width = '100%'
|
|
|
- audioDom.className = styles.audio
|
|
|
-
|
|
|
- /** 改变播放时间 */
|
|
|
- const handleChangeTime = (val: number) => {
|
|
|
- state.currentTime = val
|
|
|
- clearTimeout(state.timer)
|
|
|
- state.timer = setTimeout(() => {
|
|
|
- audioDom.currentTime = val
|
|
|
- state.timer = null
|
|
|
- }, 60)
|
|
|
- }
|
|
|
-
|
|
|
- // 切换音频播放
|
|
|
- const onToggleAudio = (e: any) => {
|
|
|
- e.stopPropagation()
|
|
|
- if (audioDom.paused) {
|
|
|
- audioDom.play()
|
|
|
- } else {
|
|
|
- audioDom.pause()
|
|
|
- }
|
|
|
-
|
|
|
- state.paused = audioDom.paused
|
|
|
- }
|
|
|
+ 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<HTMLIFrameElement>()
|
|
|
+ const {playStaff, pauseStaff, updateProgressStaff} = staffMoveInstance()
|
|
|
|
|
|
// 点赞
|
|
|
const onStarChange = async () => {
|
|
|
+ await checkLogin();
|
|
|
// 是否登录
|
|
|
if (!state.loginTag) {
|
|
|
state.loginStatus = true
|
|
@@ -140,9 +153,9 @@ export default defineComponent({
|
|
|
state.listState.loading = false
|
|
|
const result = res.data || {}
|
|
|
// 处理重复请求数据
|
|
|
- if (state.list.length > 0 && result.current === 1) {
|
|
|
- return
|
|
|
- }
|
|
|
+ // 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
|
|
@@ -155,6 +168,16 @@ export default defineComponent({
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ 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',
|
|
@@ -163,32 +186,148 @@ export default defineComponent({
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
-
|
|
|
- const initAudio = () => {
|
|
|
- try {
|
|
|
- audioDom.src = state.musicDetail.videoUrl
|
|
|
- audioDom.load()
|
|
|
- audioDom.oncanplaythrough = () => {
|
|
|
- state.paused = audioDom.paused
|
|
|
- state.duration = audioDom.duration
|
|
|
+ // 初始化 媒体播放
|
|
|
+ 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
|
|
|
}
|
|
|
- // 播放时监听
|
|
|
- audioDom.addEventListener('timeupdate', () => {
|
|
|
- state.duration = audioDom.duration
|
|
|
- state.currentTime = audioDom.currentTime
|
|
|
- const rate = (state.currentTime / state.duration) * 100
|
|
|
- state.audioWidth = rate > 100 ? 100 : rate
|
|
|
- })
|
|
|
- audioDom.addEventListener('ended', () => {
|
|
|
- state.paused = audioDom.paused
|
|
|
- })
|
|
|
- } catch (e) {
|
|
|
- //
|
|
|
- console.log(e)
|
|
|
+ });
|
|
|
+ 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);
|
|
|
}
|
|
|
-
|
|
|
- const __init = async () => {
|
|
|
+ //点击改变播放状态
|
|
|
+ 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)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ 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 {
|
|
|
+ Toast('请用手机或移动设备打开')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const checkLogin = async () => {
|
|
|
try {
|
|
|
// 判断是否登录
|
|
|
const Authorization = getAuth() // storage.get(ACCESS_TOKEN) || ''
|
|
@@ -208,238 +347,466 @@ export default defineComponent({
|
|
|
removeAuth()
|
|
|
setLogout()
|
|
|
}
|
|
|
+ };
|
|
|
+
|
|
|
+ const __init = async () => {
|
|
|
+ await checkLogin();
|
|
|
try {
|
|
|
const res = await api_openUserMusicDetail(state.id)
|
|
|
|
|
|
if (res.code === 999) {
|
|
|
- state.message = res.msg
|
|
|
- state.messageStatus = true
|
|
|
+ // 没有的时候显示缺省页
|
|
|
+ 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(() => {
|
|
|
- initAudio()
|
|
|
- })
|
|
|
}
|
|
|
+ // 初始化
|
|
|
+ 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{
|
|
|
+ router.push({
|
|
|
+ path:"/transfer"
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
|
|
|
const pageVisibility = usePageVisibility()
|
|
|
watch(pageVisibility, value => {
|
|
|
if (value === 'hidden') {
|
|
|
- if (audioDom) {
|
|
|
- audioDom.pause()
|
|
|
- state.paused = audioDom.paused
|
|
|
+ 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(() => {
|
|
|
- if (audioDom) {
|
|
|
- audioDom.pause()
|
|
|
- state.paused = audioDom.paused
|
|
|
- }
|
|
|
+ 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
|
|
|
- if (audioDom) {
|
|
|
- audioDom.currentTime = 0
|
|
|
- audioDom.pause()
|
|
|
- state.paused = audioDom.paused
|
|
|
+ state.id = to.query.id;
|
|
|
+ state.playType = '';
|
|
|
+ state.params.page = 1;
|
|
|
+ state.list = [];
|
|
|
+ if(state._plrl){
|
|
|
+ state._plrl.destroy()
|
|
|
}
|
|
|
- state.list = []
|
|
|
- __init()
|
|
|
+ plyrState.playIngShow = true
|
|
|
+ staffState.staffSrc = ""
|
|
|
+ staffState.isShow = false
|
|
|
+ staffState.height = "initial"
|
|
|
+ __init();
|
|
|
})
|
|
|
return () => (
|
|
|
- <div class={styles.creation}>
|
|
|
- <div class={styles.playSection}>
|
|
|
- {state.playType === 'Video' && (
|
|
|
- <MVideo
|
|
|
- src={state.musicDetail.videoUrl}
|
|
|
- poster={state.musicDetail.videoImg || videoBg}
|
|
|
- />
|
|
|
- )}
|
|
|
- {state.playType === 'Audio' && (
|
|
|
- <div class={styles.audioSection}>
|
|
|
- <div class={styles.audioContainer}>
|
|
|
- <div
|
|
|
- class={styles.waveActive}
|
|
|
- style={{
|
|
|
- width: state.audioWidth + '%'
|
|
|
+ <div
|
|
|
+ style={
|
|
|
+ {
|
|
|
+ '--barheight':state.heightV + "px",
|
|
|
+ "--creationHeight":creationHeight.value ? creationHeight.value+"px" : "100vh"
|
|
|
+ }
|
|
|
+ }
|
|
|
+ class={[
|
|
|
+ styles.creation,
|
|
|
+ isTablet ? styles.creationTablet : '',
|
|
|
+ isScreenScroll.value && styles.isShareScreenScroll
|
|
|
+ ]}>
|
|
|
+ <div class={styles.creationBg}></div>
|
|
|
+ <MSticky position="top"
|
|
|
+ onGetHeight={(height: any) => {
|
|
|
+ console.log(height, 'height', height)
|
|
|
+ state.heightV = height
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {
|
|
|
+ isApp ? <MHeader
|
|
|
+ leftClickDefault={false}
|
|
|
+ color={isScreenScroll.value ? "#333333" : "#ffffff"}
|
|
|
+ background={isScreenScroll.value ? `rgb(255,255,255` : "transparent"}
|
|
|
+ border={false}
|
|
|
+ isBack={route.query.platformType != 'ANALYSIS'}
|
|
|
+ title={"作品详情"}
|
|
|
+ onLeftClick={()=>{
|
|
|
+ setStatusBarTextColor(false)
|
|
|
+ postMessage({
|
|
|
+ api: 'back'
|
|
|
+ });
|
|
|
}}
|
|
|
- ></div>
|
|
|
- <div class={styles.waveDefault}></div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class={styles.audioBox}>
|
|
|
- <div
|
|
|
- class={[styles.audioPan, state.paused && styles.imgRotate]}
|
|
|
- >
|
|
|
- <Image class={styles.audioImg} src={state.musicDetail?.img} />
|
|
|
- </div>
|
|
|
- <i class={styles.audioPoint}></i>
|
|
|
- <i
|
|
|
- class={[styles.audioZhen, state.paused && styles.active]}
|
|
|
- ></i>
|
|
|
- </div>
|
|
|
- <div
|
|
|
- class={[styles.controls]}
|
|
|
- onClick={(e: Event) => {
|
|
|
- e.stopPropagation()
|
|
|
- }}
|
|
|
- >
|
|
|
- <div class={styles.actions}>
|
|
|
- <div class={styles.actionBtn} onClick={onToggleAudio}>
|
|
|
- <img src={state.paused ? iconPlay : iconPause} />
|
|
|
+ />
|
|
|
+ : <div class={styles.logoDownload}>
|
|
|
+ <img src={isScreenScroll.value ? logo1Img : logoImg} class={styles.logoImg}></img>
|
|
|
+ <div class={styles.logTit} onClick={handlerDownLoad}>下载App</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <div class={[styles.slider]}>
|
|
|
- <Slider
|
|
|
- step={0.01}
|
|
|
- class={styles.timeProgress}
|
|
|
- v-model={state.currentTime}
|
|
|
- max={state.duration}
|
|
|
- onUpdate:modelValue={val => {
|
|
|
- handleChangeTime(val)
|
|
|
- }}
|
|
|
- onDrag-start={() => {
|
|
|
- state.dragStatus = true
|
|
|
- console.log('onDragStart')
|
|
|
- }}
|
|
|
- onDrag-end={() => {
|
|
|
- state.dragStatus = false
|
|
|
- console.log('onDragEnd')
|
|
|
- }}
|
|
|
- />
|
|
|
- </div>
|
|
|
- <div class={styles.time}>
|
|
|
- <div>{getSecondRPM(state.currentTime)}</div>
|
|
|
- <span>/</span>
|
|
|
- <div>{getSecondRPM(state.duration)}</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- )}
|
|
|
- </div>
|
|
|
-
|
|
|
- <Cell class={styles.userSection} center border={false}>
|
|
|
- {{
|
|
|
- icon: () => (
|
|
|
- <div
|
|
|
- class={[
|
|
|
- styles.userLogoSection,
|
|
|
- (state.musicDetail.vipType === 'SVIP' ||
|
|
|
- state.musicDetail.vipType === 'PERMANENT_SVIP') &&
|
|
|
- styles.userSVip,
|
|
|
- state.musicDetail.vipType === 'VIP' && styles.userVip
|
|
|
- ]}
|
|
|
- >
|
|
|
- <Image class={styles.userLogo} src={state.musicDetail.avatar} />
|
|
|
- <i class={styles.showMemeber}></i>
|
|
|
- </div>
|
|
|
- ),
|
|
|
- title: () => (
|
|
|
- <div class={styles.userInfo}>
|
|
|
- <p class={styles.name}>
|
|
|
- <span>{state.musicDetail.username}</span>
|
|
|
- {/* {state.musicDetail.vipType === 'VIP' && (
|
|
|
- <img src={iconVip} class={styles.iconMember} />
|
|
|
- )} */}
|
|
|
- {/* {(state.musicDetail.vipType === 'SVIP' ||
|
|
|
- state.musicDetail.vipType === 'PERMANENT_SVIP') && (
|
|
|
- <img src={iconSVip} class={styles.iconMember} />
|
|
|
- )} */}
|
|
|
- </p>
|
|
|
- <p class={styles.sub}>
|
|
|
- {state.musicDetail.subjectName}{' '}
|
|
|
- {getGradeCh(state.musicDetail.currentGradeNum - 1)}
|
|
|
- </p>
|
|
|
- </div>
|
|
|
- ),
|
|
|
- value: () => (
|
|
|
- <div
|
|
|
- class={[
|
|
|
- styles.zan,
|
|
|
- state.musicDetail.starFlag && styles.zanActive
|
|
|
- ]}
|
|
|
- onClick={onStarChange}
|
|
|
- >
|
|
|
- <img
|
|
|
- src={state.musicDetail.starFlag ? iconZanActive : iconZan}
|
|
|
- class={styles.iconZan}
|
|
|
+ }
|
|
|
+ </MSticky>
|
|
|
+ {
|
|
|
+ state.isEmpty ?
|
|
|
+ <div class={styles.isEmpty}>
|
|
|
+ <MEmpty tips="作品已删除~" btnStatus={false} />
|
|
|
+ </div> :
|
|
|
+ <>
|
|
|
+ <div class={styles.singerBox}>
|
|
|
+ <div class={styles.musicSheetName}>
|
|
|
+ <NoticeBar
|
|
|
+ text={state.musicDetail?.musicSheetName}
|
|
|
+ background="none"
|
|
|
/>
|
|
|
- {state.musicDetail.likeNum}
|
|
|
</div>
|
|
|
- )
|
|
|
- }}
|
|
|
- </Cell>
|
|
|
-
|
|
|
- <div class={styles.musicSection}>
|
|
|
- <div class={styles.musicName}>
|
|
|
- <span class={styles.musicTag}>曲目名称</span>
|
|
|
- {state.musicDetail?.musicSheetName}
|
|
|
- </div>
|
|
|
- {state.musicDetail?.desc && (
|
|
|
- <div class={styles.musicDesc}>{state.musicDetail?.desc}</div>
|
|
|
- )}
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class={styles.likeSection}>
|
|
|
- <div class={styles.likeTitle}>推荐作品</div>
|
|
|
-
|
|
|
- {state.listState.dataShow ? (
|
|
|
- <List
|
|
|
- finished={state.listState.finished}
|
|
|
- finishedText=" "
|
|
|
- class={[styles.container, styles.containerInformation]}
|
|
|
- onLoad={getList}
|
|
|
- immediateCheck={false}
|
|
|
- >
|
|
|
- <div class={styles.cellGroup}>
|
|
|
- {state.list.map((item: any) => (
|
|
|
- <div class={styles.cell} onClick={() => onDetail(item)}>
|
|
|
- <div class={styles.cellImg}>
|
|
|
- <Image
|
|
|
- class={styles.cellImage}
|
|
|
- src={item.img}
|
|
|
- fit="cover"
|
|
|
+ <div class={styles.singerName}>
|
|
|
+ 演奏:{state.musicDetail?.username}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <Sticky zIndex={1000} offsetTop={state.heightV - 1 + "px"}>
|
|
|
+ <div class={[styles.playSection, plyrState.mediaTimeShow && styles.mediaTimeShow,!plyrState.loaded && styles.notLoaded,isLandscapeScreen.value&&styles.isLandscapeScreen]} id="playMediaSection" onClick={handlerClickPlay}>
|
|
|
+ {
|
|
|
+ isLandscapeScreen.value &&
|
|
|
+ <div class={styles.backBox}>
|
|
|
+ <img class={styles.backImg} src={backImg} onClick={handlerBack}/>
|
|
|
+ <div class={styles.musicDetail}>
|
|
|
+ <div class={styles.musicSheetName}>
|
|
|
+ <NoticeBar
|
|
|
+ text={state.musicDetail?.musicSheetName}
|
|
|
+ background="none"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class={styles.username}>演奏:{state.musicDetail?.username}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ {
|
|
|
+ state.playType &&
|
|
|
+ <>
|
|
|
+ {
|
|
|
+ state.playType === 'Audio' &&
|
|
|
+ <div class={styles.audioBox}>
|
|
|
+ <canvas class={styles.audioVisualizer} id="audioVisualizer"></canvas>
|
|
|
+ <audio
|
|
|
+ crossorigin="anonymous"
|
|
|
+ id="audioMediaSrc"
|
|
|
+ src={state.musicDetail?.videoUrl}
|
|
|
+ controls="false"
|
|
|
+ preload="metadata"
|
|
|
+ playsinline
|
|
|
+ webkit-playsinline
|
|
|
+ />
|
|
|
+ <img src="./img/ty.png" class={styles.tyBg} />
|
|
|
+ <div class="audioBoxBg">
|
|
|
+ <div class={[styles.audioPan, plyrState.playIngShow && styles.imgRotate]}>
|
|
|
+ <img class={styles.audioImg} src={state.musicDetail.img || musicBg} />
|
|
|
+ </div>
|
|
|
+ <i class={styles.audioPoint}></i>
|
|
|
+ <i class={[styles.audioZhen, plyrState.playIngShow && styles.active]}></i>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ {
|
|
|
+ state.playType === 'Video' &&
|
|
|
+ <video
|
|
|
+ id="videoMediaSrc"
|
|
|
+ class={styles.videoBox}
|
|
|
+ src={state.musicDetail?.videoUrl}
|
|
|
+ data-poster={ state.musicDetail?.videoImg || videobg}
|
|
|
+ poster={ state.musicDetail?.videoImg || videobg}
|
|
|
+ preload="metadata"
|
|
|
+ playsinline
|
|
|
+ webkit-playsinline
|
|
|
+ x5-playsinline
|
|
|
/>
|
|
|
-
|
|
|
- <div class={styles.iconZan}>{item.likeNum}</div>
|
|
|
+ }
|
|
|
+ <div class={[styles.playLarge, !plyrState.mediaTimeShow && plyrState.playIngShow && styles.playIngShow]}></div>
|
|
|
+ <div class={styles.mediaTimeCon}>
|
|
|
+ <div class={styles.mediaTime}>
|
|
|
+ <div>
|
|
|
+ {getSecondRPM(plyrState.currentTime)}
|
|
|
+ </div>
|
|
|
+ <div class={styles.note}>/</div>
|
|
|
+ <div class={styles.duration}>
|
|
|
+ {getSecondRPM(plyrState.duration)}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class={[styles.cellTitle, 'van-ellipsis']}>
|
|
|
- {item.musicSheetName}
|
|
|
+ <div class={styles.landscapeScreen} onClick={handlerLandscapeScreen}></div>
|
|
|
+ {/* 谱面 */}
|
|
|
+ {
|
|
|
+ staffState.staffSrc &&
|
|
|
+ <div class={[styles.staffBoxCon, staffState.isShow && styles.staffBoxShow]}>
|
|
|
+ <div
|
|
|
+ class={styles.staffBox}
|
|
|
+ style={
|
|
|
+ {
|
|
|
+ '--staffBoxHeight':staffState.height
|
|
|
+ }
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <div class={styles.mask}></div>
|
|
|
+ <iframe
|
|
|
+ ref={staffDom}
|
|
|
+ class={styles.staff}
|
|
|
+ frameborder="0"
|
|
|
+ src={staffState.staffSrc}>
|
|
|
+ </iframe>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </Sticky>
|
|
|
+ <div class={[styles.musicSection, styles.musicShareSection]}>
|
|
|
+ <div class={styles.avatarInfoBox}>
|
|
|
+ <div class={styles.avatar}>
|
|
|
+ <Image class={styles.userLogo} src={state.musicDetail.avatar} />
|
|
|
+ <div class={styles.infoCon}>
|
|
|
+ <div class={styles.info}>
|
|
|
+ <span class={styles.userName}>{state.musicDetail?.username}</span>
|
|
|
+ {state.musicDetail.vipFlag && (
|
|
|
+ <img src={iconMember} class={styles.iconMember} />
|
|
|
+ )}
|
|
|
</div>
|
|
|
- <div class={styles.users}>
|
|
|
- <Image src={item.avatar} class={styles.userImg} />
|
|
|
- <span class={styles.name}>{item.username}</span>
|
|
|
+ <div class={styles.sub}>
|
|
|
+ {state.musicDetail.subjectName}{' '}
|
|
|
+ {getGradeCh(state.musicDetail.currentGradeNum - 1)}
|
|
|
</div>
|
|
|
</div>
|
|
|
- ))}
|
|
|
+ </div>
|
|
|
+ <div class={styles.linkes} onClick={onStarChange}>
|
|
|
+ <img src={state.musicDetail.starFlag ? iconZanActive : iconZan} class={styles.iconZan} />
|
|
|
+ <span>{state.musicDetail.likeNum}</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </List>
|
|
|
- ) : (
|
|
|
- <MEmpty tips="暂无数据" btnStatus={false} />
|
|
|
- )}
|
|
|
- </div>
|
|
|
+ <TextEllipsis class={styles.textEllipsis} text={state.musicDetail?.desc || ''} />
|
|
|
+ </div>
|
|
|
+ <div class={styles.likeSection}>
|
|
|
+ <div class={styles.likeTitle}>推荐作品</div>
|
|
|
+ {state.listState.dataShow ? (
|
|
|
+ <>
|
|
|
+ <List
|
|
|
+ finished={true}
|
|
|
+ finishedText=" "
|
|
|
+ class={[styles.container, styles.containerInformation]}
|
|
|
+ //onLoad={getList}
|
|
|
+ immediateCheck={false}>
|
|
|
+ {state.list.map((item: any, index:number) => (
|
|
|
+ <Cell
|
|
|
+ class={[styles.likeShareItem, index===state.list.length-1&&styles.likeShareItemLast]}
|
|
|
+ border={false}
|
|
|
+ onClick={() => onDetail(item)}
|
|
|
+ >
|
|
|
+ {{
|
|
|
+ icon: () => (
|
|
|
+ <div class={styles.audioImgBox}>
|
|
|
+ <img
|
|
|
+ src={audioPan}
|
|
|
+ class={styles.audioPan}
|
|
|
+ crossorigin="anonymous"
|
|
|
+ />
|
|
|
+ <img
|
|
|
+ src={
|
|
|
+ item.img || musicBg
|
|
|
+ }
|
|
|
+ class={styles.muploader}
|
|
|
+ crossorigin="anonymous"
|
|
|
+ />
|
|
|
+ <img class={styles.imgLabel} src={item.videoUrl?.lastIndexOf('mp4') !== -1 ? videoLabel : audioLabel} />
|
|
|
+ </div>
|
|
|
+ ),
|
|
|
+ title: () => (
|
|
|
+ <div class={styles.userInfo}>
|
|
|
+ <div class={[styles.musicSheetName,'van-ellipsis']}>{item.musicSheetName}</div>
|
|
|
+ <div class={styles.usernameCon}>
|
|
|
+ <div class={styles.likeNum}>
|
|
|
+ <img src={iconZanActive} />
|
|
|
+ <span>{item.likeNum}</span>
|
|
|
+ </div>
|
|
|
+ <div class={[styles.username, 'van-ellipsis']}>{item.username}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ ),
|
|
|
+ value: () => (
|
|
|
+ <img src={playImg} class={styles.playImg} />
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ </Cell>
|
|
|
+ ))}
|
|
|
+ </List>
|
|
|
+ {
|
|
|
+ (!state.listState.finished || state.params.page>2) &&
|
|
|
+ <div class={styles.btnImg}>
|
|
|
+ <img onClick={handleChangeList} onTouchstart={()=>{}} src={btnImg} />
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </>
|
|
|
+ ) : (
|
|
|
+ <MEmpty tips="暂无作品~" btnStatus={false} />
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ {
|
|
|
+ !isScreenScroll.value &&
|
|
|
+ <MSticky position="bottom" offsetBottom={state.heightB - 1 + "px"} >
|
|
|
+ <div class={styles.upward}>
|
|
|
+ <img src={iconUpward} />
|
|
|
+ </div>
|
|
|
+ </MSticky>
|
|
|
+ }
|
|
|
+ </>
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
<Popup
|
|
|
v-model:show={state.loginStatus}
|
|
@@ -461,6 +828,18 @@ export default defineComponent({
|
|
|
message={state.message}
|
|
|
showButton={false}
|
|
|
/>
|
|
|
+ {
|
|
|
+ !staffState.isShow && <Loading></Loading>
|
|
|
+ }
|
|
|
+ {wxStatus.value && (
|
|
|
+ <div
|
|
|
+ class={styles.wxpopup}
|
|
|
+ onClick={() => {
|
|
|
+ wxStatus.value = false;
|
|
|
+ }}>
|
|
|
+ <img src={wxBg} alt="" />
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
</div>
|
|
|
)
|
|
|
}
|