Kaynağa Gözat

分享路由修改

黄琪勇 10 ay önce
ebeveyn
işleme
bdec2f3b07

+ 4 - 662
src/views/creation/index-share.vue

@@ -1,671 +1,13 @@
 <template>
-   <div
-      class="creation"
-      :style="{
-         '--heightA': state.heightA + 'px',
-         '--navBarHeight': navBarHeight + 'px',
-         '--creationHeight': creationHeight ? creationHeight + 'px' : '100vh'
-      }"
-   >
-      <div class="creationBg"></div>
-      <van-sticky>
-         <van-nav-bar
-            v-if="browser().isApp"
-            class="nav"
-            :class="{ isScreenScroll: isScreenScroll }"
-            :fixed="false"
-            :title="state.musicDetail.musicSheetName"
-            left-arrow
-            @click-left="goBack"
-         />
-         <div v-else class="logoDownload" :class="{ isShareScreenScroll: isScreenScroll }">
-            <img :src="isScreenScroll ? require('./img/logo1.png') : require('./img/logo.png')" class="logoImg" />
-            <div class="logTit" @click="handlerDownLoad">下载App</div>
-         </div>
-      </van-sticky>
-      <div v-if="isEmpty" class="isEmpty">
-         <MEmpty msg="作品已删除~" />
-      </div>
-      <template v-else>
-         <div class="singerBox">
-            <div class="musicSheetName">
-               <van-notice-bar :text="state.musicDetail.musicSheetName" background="none" />
-            </div>
-            <div class="singerName">演奏:{{ state.musicDetail.username }}</div>
-         </div>
-         <van-sticky :offset-top="44 + navBarHeight" :z-index="200">
-            <div class="playBox" ref="playBoxDom">
-               <div
-                  :class="[
-                     'playSection',
-                     plyrState.mediaTimeShow && 'mediaTimeShow',
-                     isLandscapeScreen && 'isLandscapeScreen',
-                     state.playType === 'Video' && 'videoType'
-                  ]"
-                  id="playMediaSection"
-                  @click="handlerClickPlay"
-               >
-                  <!-- 横屏 -->
-                  <div v-if="isLandscapeScreen" class="backBox">
-                     <img class="backImg" :src="require('./img/back.png')" @click="handlerBack" />
-                     <div class="musicDetail">
-                        <div class="musicSheetName">
-                           <van-notice-bar :text="state.musicDetail.musicSheetName" background="none" />
-                        </div>
-                        <div class="username">演奏:{{ state.musicDetail.username }}</div>
-                     </div>
-                  </div>
-                  <!-- audio -->
-                  <div class="audioBox" v-if="state.playType === 'Audio'">
-                     <canvas class="audioVisualizer" id="audioVisualizer"></canvas>
-                     <audio
-                        crossorigin="anonymous"
-                        id="audioMediaSrc"
-                        :src="state.musicDetail.videoUrl"
-                        controls="false"
-                        preload="metadata"
-                        playsinline
-                        webkit-playsinline
-                     />
-                     <div class="audioBoxBg">
-                        <div :class="['audioPan', plyrState.playIngShow ? 'imgRotate' : '']">
-                           <van-image class="audioImg" :src="state.musicDetail.img || require('./img/music_bg.png')" />
-                        </div>
-                        <i class="audioPoint"></i>
-                        <i :class="['audioZhen', plyrState.playIngShow && 'active']"></i>
-                     </div>
-                  </div>
-                  <!-- video -->
-                  <video
-                     v-if="state.playType === 'Video'"
-                     id="videoMediaSrc"
-                     class="videoBox"
-                     :src="state.musicDetail.videoUrl"
-                     :data-poster="state.musicDetail.videoImg || require('./img/videoBg.png')"
-                     :poster="state.musicDetail.videoImg || require('./img/videoBg.png')"
-                     preload="metadata"
-                     playsinline
-                     webkit-playsinline
-                     x5-playsinline
-                  />
-                  <!-- 工具 -->
-                  <div :class="['playLarge', !plyrState.mediaTimeShow && plyrState.playIngShow && 'playIngShow']"></div>
-                  <div class="mediaTimeCon">
-                     <div class="mediaTime">
-                        <div>
-                           {{ getSecondRPM(plyrState.currentTime) }}
-                        </div>
-                        <div class="note">/</div>
-                        <div class="duration">
-                           {{ getSecondRPM(plyrState.duration) }}
-                        </div>
-                     </div>
-                  </div>
-                  <div class="landscapeScreen" @click="handlerLandscapeScreen"></div>
-                  <!-- 谱面 -->
-                  <div v-if="staffState.staffSrc" :class="['staffBoxCon', staffState.isShow && 'staffBoxShow']">
-                     <div
-                        class="staffBox"
-                        :style="{
-                           '--staffBoxHeight': staffState.height
-                        }"
-                     >
-                        <div class="mask"></div>
-                        <iframe ref="staffDom" class="staff" frameborder="0" :src="staffState.staffSrc"></iframe>
-                     </div>
-                  </div>
-               </div>
-            </div>
-         </van-sticky>
-         <div class="musicSection musicShareSection">
-            <div class="avatarInfoBox">
-               <div class="avatar">
-                  <van-image class="userLogo" :src="state.musicDetail.avatar" />
-                  <div class="infoCon">
-                     <div class="info">
-                        <span class="userName">{{ state.musicDetail.username }}</span>
-                        <img :src="require('./img/icon-member.png')" v-if="state.musicDetail.vipFlag" class="iconMember" />
-                     </div>
-                     <div class="sub">
-                        {{ state.musicDetail.subjectName ? state.musicDetail.subjectName : "" }}
-                     </div>
-                  </div>
-               </div>
-               <div class="linkes" @click="onStarChange">
-                  <img src="./img/icon-zan-active.png" v-if="state.musicDetail.starFlag" class="iconZan" />
-                  <img src="./img/icon-zan.png" v-else class="iconZan" />
-                  <span>{{ state.musicDetail.likeNum }}</span>
-               </div>
-            </div>
-            <textEllipsis class="textEllipsis" :text="state.musicDetail.desc || ''" />
-         </div>
-         <div class="likeSection likeShareSection">
-            <div class="likeTitle">推荐作品</div>
-            <template v-if="state.listState.dataShow">
-               <van-list :finished="state.listState.finished" :finishedText="' '" :immediateCheck="false">
-                  <van-cell
-                     v-for="(item, index) in state.list"
-                     :key="index"
-                     :class="['likeShareItem', index === state.list.length - 1 && 'likeShareItemLast']"
-                     :border="false"
-                     @click="onDetail(item)"
-                  >
-                     <template #icon>
-                        <div class="audioImgBox">
-                           <img :src="require('./img/audio-pan.png')" class="audioPan" crossorigin="anonymous" />
-                           <img :src="item.img || require('./share-model/images/music-bg.png')" class="muploader" crossorigin="anonymous" />
-                           <img
-                              class="imgLabel"
-                              :src="
-                                 item.videoUrl && item.videoUrl.lastIndexOf('mp4') !== -1
-                                    ? require('./share-model/images/videoLabel.png')
-                                    : require('./share-model/images/audioLabel.png')
-                              "
-                           />
-                        </div>
-                     </template>
-                     <template #title>
-                        <div class="userInfo">
-                           <div class="musicSheetName van-ellipsis">{{ item.musicSheetName }}</div>
-                           <div class="usernameCon">
-                              <div class="likeNum">
-                                 <img :src="require('./img/icon-zan-active.png')" />
-                                 <span>{{ item.likeNum }}</span>
-                              </div>
-                              <div class="username van-ellipsis">{{ item.username }}</div>
-                           </div>
-                        </div>
-                     </template>
-                     <template #default>
-                        <div class="time">
-                           <img :src="require('./img/play.png')" class="playImg" />
-                        </div>
-                     </template>
-                  </van-cell>
-               </van-list>
-               <div v-if="!state.listState.finished || state.params.page > 2" class="btnImg">
-                  <img @click="handleChangeList" @touchstart="() => {}" :src="require('./img/btn.png')" />
-               </div>
-            </template>
-            <MEmpty class="mEmpty" v-else msg="暂无作品" style="margin-bottom: 0.5rem" />
-         </div>
-         <div class="upward shareUpward" v-show="!isScreenScroll">
-            <img :src="require('./img/upward.png')" />
-         </div>
-      </template>
-      <van-popup v-model="loginStatus" style="background: transparent; overflow: inherit">
-         <LoginModel @close="() => (this.loginStatus = false)" @confirm="onConfirm" />
-      </van-popup>
-      <Loading v-if="!staffState.isShow"></Loading>
-      <div
-         v-if="wxStatus"
-         class="wxpopup"
-         @click="
-            () => {
-               wxStatus = false
-            }
-         "
-      >
-         <img src="./img/wx_bg.png" alt="" />
-      </div>
-   </div>
+   <indexShareRoute :key="$route.fullPath" />
 </template>
 
 <script>
-import dayjs from "dayjs"
-import { browser, getSecondRPM, validStudentUrl } from "@/common/common"
-import { postMessage } from "@/helpers/native-message"
-import { api_openUserMusicPage, api_userMusicStar, api_openUserMusicDetail } from "./api"
-import audioVisualDraw, { vaildMusicScoreUrl } from "./audioVisualDraw"
-import textEllipsis from "./textEllipsis"
-import Loading from "./loading"
-import "plyr/dist/plyr.css"
-import Plyr from "plyr"
-import MEmpty from "@/components/MEmpty"
-import LoginModel from "./login-model"
+import indexShareRoute from "./index-shareRoute"
 export default {
-   name: "creation",
-   data() {
-      return {
-         id: this.$route.query.id,
-         loginTag: false, // 是否登录标识
-         loginStatus: false,
-         isEmpty: false,
-         wxStatus: false,
-         state: {
-            playType: "", // 播放类型
-            musicDetail: {},
-            isClick: false,
-            list: [],
-            listState: {
-               dataShow: true, // 判断是否有数据
-               loading: false,
-               finished: false
-            },
-            params: {
-               page: 1,
-               rows: 4
-            },
-            _plrl: null,
-            heightA: 0
-         },
-         plyrState: {
-            duration: 0,
-            currentTime: 0,
-            mediaTimeShow: false,
-            playIngShow: true
-         },
-         isLandscapeScreen: false,
-         isScreenScroll: false,
-         navBarHeight: 0,
-         staffState: {
-            staffSrc: "",
-            isShow: false,
-            height: "initial",
-            speedRate: 1,
-            musicRenderType: "staff",
-            partIndex: 0
-         },
-         creationHeight: 0
-      }
-   },
+   name: "index-share",
    components: {
-      textEllipsis,
-      MEmpty,
-      Loading,
-      LoginModel
-   },
-   methods: {
-      getSecondRPM,
-      browser,
-      onDayjs(time) {
-         return dayjs(time).format("YYYY-MM-DD HH:mm")
-      },
-      goBack() {
-         if (browser().isApp) {
-            this.setStatusBarTextColor(false)
-            postMessage({ api: "setBarStatus", content: { status: 1, backButtonHidden: 0 } })
-            postMessage({
-               api: "back"
-            })
-         } else {
-            this.$router.back()
-         }
-      },
-      onDetail(item) {
-         this.$router.push({
-            path: "/shareCreation",
-            query: {
-               id: item.id
-            }
-         })
-      },
-      // 点赞
-      async onStarChange() {
-         try {
-            await api_userMusicStar({
-               userMusicId: this.id,
-               star: !this.state.musicDetail.starFlag
-            })
-
-            this.state.musicDetail.starFlag = !this.state.musicDetail.starFlag
-            if (this.state.musicDetail.starFlag) {
-               this.state.musicDetail.likeNum += 1
-            } else {
-               this.state.musicDetail.likeNum -= 1
-            }
-         } catch (e) {
-            //
-            if (e.code === 403) {
-               this.loginStatus = true
-            }
-         }
-      },
-      async onConfirm(val) {
-         this.loginTag = val
-         this.loginStatus = false
-         const { data } = await api_openUserMusicDetail(this.id)
-         this.musicDetail = data
-      },
-      async getStarList() {
-         try {
-            if (this.state.isClick) return
-            this.state.isClick = true
-            const res = await api_openUserMusicPage({
-               type: "FORMAL",
-               exclusionId: this.id,
-               sort: 1,
-               ...this.state.params
-            })
-            this.state.listState.loading = false
-            const result = res.data || {}
-            // 处理重复请求数据
-            // if (this.state.list.length > 0 && result.current === 1) {
-            //    return
-            // }
-            this.state.list = result.rows || []
-
-            this.state.listState.finished = result.current >= result.pages
-            this.state.params.page = result.current + 1
-            this.state.listState.dataShow = this.state.list.length > 0
-            this.state.isClick = false
-         } catch {
-            this.state.listState.dataShow = false
-            this.state.listState.finished = true
-            this.state.isClick = false
-         }
-      },
-      handleChangeList() {
-         if (this.state.listState.finished) {
-            this.state.listState.finished = false
-            this.state.params.page = 1
-            this.getStarList()
-         } else {
-            this.getStarList()
-         }
-      },
-      async init() {
-         /* 初始化请求 */
-         try {
-            const res = await api_openUserMusicDetail(this.id)
-            this.state.musicDetail = res.data || {}
-            try {
-               const jsonConfig = JSON.parse(res.data.jsonConfig)
-               jsonConfig.speedRate && (this.staffState.speedRate = jsonConfig.speedRate)
-               jsonConfig.musicRenderType && (this.staffState.musicRenderType = jsonConfig.musicRenderType)
-               jsonConfig.partIndex && (this.staffState.partIndex = jsonConfig.partIndex)
-            } catch {}
-            // 五线谱
-            this.initStaff()
-            this.getStarList()
-            // 判断是视频还是音频
-            if (res.data.videoUrl.lastIndexOf("mp4") !== -1) {
-               this.state.playType = "Video"
-            } else {
-               this.state.playType = "Audio"
-            }
-            this.$nextTick(() => {
-               this.initMediaPlay()
-            })
-         } catch (e) {
-            this.staffState.isShow = true
-            if (e.code === 999) {
-               this.isEmpty = true
-            }
-         }
-      },
-      // 初始化 媒体播放
-      initMediaPlay() {
-         const { playStaff, pauseStaff, updateProgressStaff } = this.staffMoveInstance()
-         const id = this.state.playType === "Audio" ? "#audioMediaSrc" : "#videoMediaSrc"
-         this.state._plrl = new Plyr(id, {
-            controls: ["play", "progress", "current-time", "duration"],
-            fullscreen: {
-               enabled: false,
-               fallback: false
-            }
-         })
-         const player = this.state._plrl
-         // 创建音波数据
-         if (this.state.playType === "Audio") {
-            const audioDom = document.querySelector("#audioMediaSrc")
-            const canvasDom = document.querySelector("#audioVisualizer")
-            const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
-            player.on("play", () => {
-               playVisualDraw()
-            })
-            player.on("pause", () => {
-               pauseVisualDraw()
-            })
-         }
-         player.on("timeupdate", () => {
-            this.plyrState.currentTime = player.currentTime
-         })
-         player.on("play", () => {
-            this.plyrState.playIngShow = false
-            playStaff()
-         })
-         player.on("pause", () => {
-            this.plyrState.playIngShow = true
-            pauseStaff()
-         })
-         player.on("ended", () => {
-            if (this.plyrState.mediaTimeShow) return
-            player.currentTime = 0
-            if (!player.playing) {
-               setTimeout(() => {
-                  updateProgressStaff(player.currentTime)
-               }, 100)
-            }
-         })
-         // 处理按压事件
-         const handleStart = () => {
-            if (this.isLandscapeScreen.value) {
-               return
-            }
-            this.plyrState.duration = player.duration
-            this.plyrState.mediaTimeShow = true
-         }
-         // 处理松开事件
-         const handleEnd = () => {
-            this.plyrState.mediaTimeShow = false
-            // 暂停的时候调用
-            if (!player.playing) {
-               updateProgressStaff(player.currentTime)
-            }
-         }
-         const progressDom = document.querySelector("#playMediaSection .plyr__controls .plyr__progress__container")
-         progressDom.addEventListener("mousedown", handleStart)
-         progressDom.addEventListener("touchstart", handleStart)
-         progressDom.addEventListener("mouseup", handleEnd)
-         progressDom.addEventListener("touchend", handleEnd)
-      },
-      // 初始化五线谱
-      initStaff() {
-         const src = `${vaildMusicScoreUrl()}/gym-music-score/#/simple-detail?id=${this.state.musicDetail.musicSheetId}&musicRenderType=${
-            this.staffState.musicRenderType
-         }&part-index=${this.staffState.partIndex}`
-         //const src = `http://192.168.3.122:3000/gym-music-score.html#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
-         this.staffState.staffSrc = src
-         window.addEventListener("message", event => {
-            const { api, height } = event.data
-            if (api === "api_musicPage") {
-               this.staffState.isShow = true
-               this.staffState.height = height + "px"
-            }
-         })
-      },
-      staffMoveInstance() {
-         let isPause = true
-         const requestAnimationFrameFun = () => {
-            requestAnimationFrame(() => {
-               this.$refs.staffDom?.contentWindow?.postMessage(
-                  {
-                     api: "api_playProgress",
-                     content: {
-                        currentTime: this.state._plrl.currentTime * this.staffState.speedRate
-                     }
-                  },
-                  "*"
-               )
-               if (!isPause) {
-                  requestAnimationFrameFun()
-               }
-            })
-         }
-         const playStaff = () => {
-            // 没渲染不执行
-            if (!this.staffState.isShow) return
-            isPause = false
-            this.$refs.staffDom?.contentWindow?.postMessage(
-               {
-                  api: "api_play"
-               },
-               "*"
-            )
-            requestAnimationFrameFun()
-         }
-         const pauseStaff = () => {
-            // 没渲染不执行
-            if (!this.staffState.isShow) return
-            isPause = true
-            this.$refs.staffDom?.contentWindow?.postMessage(
-               {
-                  api: "api_paused"
-               },
-               "*"
-            )
-         }
-         const updateProgressStaff = currentTime => {
-            // 没渲染不执行
-            if (!this.staffState.isShow) return
-            this.$refs.staffDom?.contentWindow?.postMessage(
-               {
-                  api: "api_updateProgress",
-                  content: {
-                     currentTime: currentTime * this.staffState.speedRate
-                  }
-               },
-               "*"
-            )
-         }
-         return {
-            playStaff,
-            pauseStaff,
-            updateProgressStaff
-         }
-      },
-      //点击改变播放状态
-      handlerClickPlay(event) {
-         // 原生 播放暂停按钮 点击的时候 不触发
-         if (event?.target?.matches("button.plyr__control")) {
-            return
-         }
-         if (this.state._plrl.playing) {
-            this.state._plrl.pause()
-         } else {
-            this.state._plrl.play()
-         }
-      },
-      handleScroll() {
-         // 作品已删除不让滚动变色
-         if (this.isEmpty) return
-         const height = window.scrollY || document.documentElement.scrollTop
-         // 防止多次调用
-         if (height > 0 && this.isScreenScroll === false) {
-            this.isScreenScroll = true
-            this.setStatusBarTextColor(false)
-         }
-         if (height <= 0) {
-            this.isScreenScroll = false
-            this.setStatusBarTextColor(true)
-         }
-      },
-      // 设置导航栏颜色
-      setStatusBarTextColor(isWhite) {
-         postMessage({
-            api: "setStatusBarTextColor",
-            content: { statusBarTextColor: isWhite }
-         })
-      },
-      handleVisibilitychange() {
-         if (document.hidden) {
-            this.state._plrl?.pause()
-         }
-      },
-      handlerBack(event) {
-         event.stopPropagation()
-         this.verticalScreen()
-      },
-      landscapeScreen() {
-         postMessage({
-            api: "setRequestedOrientation",
-            content: {
-               orientation: 0
-            }
-         })
-         this.isLandscapeScreen = true
-      },
-      verticalScreen() {
-         postMessage({
-            api: "setRequestedOrientation",
-            content: {
-               orientation: 1
-            }
-         })
-         this.isLandscapeScreen = false
-      },
-      handlerLandscapeScreen(event) {
-         event.stopPropagation()
-         const { isApp, weixin } = browser()
-         if (isApp) {
-            this.landscapeScreen()
-            return
-         }
-         if (weixin) {
-            this.wxStatus = true
-         } else {
-            const t = Date.now()
-            const str = location.href
-            this.shareCall(str)
-            setTimeout(() => {
-               if (Date.now() - t < 3500) {
-                  window.location.replace(validStudentUrl() + "/#/studentDownLoad")
-               }
-            }, 3000)
-         }
-      },
-      shareCall(str) {
-         const iosStr = encodeURIComponent(str)
-         const userAgent = navigator.userAgent || navigator.vendor
-         if (/(iPhone|iPad|iPod|iOS)/i.test(userAgent)) {
-            window.location.href = `StudentsDaya://linkUrl=${iosStr}`
-         } else if (/(Android)/i.test(userAgent)) {
-            window.location.href = `studentdaya://html:8888/SplashActivity?url=${iosStr}`
-         } else {
-            showToast("请用手机或移动设备打开")
-         }
-      },
-      handlerDownLoad() {
-         if (browser().weixin) {
-            this.wxStatus = true
-         } else {
-            window.location.replace(validStudentUrl() + "/#/studentDownLoad")
-         }
-      },
-      setFullHeight() {
-         this.creationHeight = window.innerHeight
-      }
-   },
-   mounted() {
-      this.state.heightA = this.$refs.playBoxDom.offsetHeight
-      document.addEventListener("scroll", this.handleScroll)
-      document.addEventListener("visibilitychange", this.handleVisibilitychange)
-      this.setFullHeight()
-      window.addEventListener("resize", this.setFullHeight)
-   },
-   destroyed() {
-      this.state._plrl?.destroy()
-      document.removeEventListener("scroll", this.handleScroll)
-      document.removeEventListener("visibilitychange", this.handleVisibilitychange)
-      window.removeEventListener("resize", this.setFullHeight)
-   },
-   created() {
-      this.setStatusBarTextColor(true)
-      postMessage({ api: "setBarStatus", content: { status: 0, backButtonHidden: 1 } })
-      postMessage({ api: "getNavHeight" }, res => {
-         const { content } = res
-         const dpi = content.dpi || 2
-         if (content.navHeight) {
-            const navHeight = content.navHeight / dpi
-            this.navBarHeight = navHeight
-         }
-      })
-      this.init()
+      indexShareRoute
    }
 }
 </script>
-
-<style lang="less" scoped>
-@import url("./index.less");
-</style>

+ 671 - 0
src/views/creation/index-shareRoute.vue

@@ -0,0 +1,671 @@
+<template>
+   <div
+      class="creation"
+      :style="{
+         '--heightA': state.heightA + 'px',
+         '--navBarHeight': navBarHeight + 'px',
+         '--creationHeight': creationHeight ? creationHeight + 'px' : '100vh'
+      }"
+   >
+      <div class="creationBg"></div>
+      <van-sticky>
+         <van-nav-bar
+            v-if="browser().isApp"
+            class="nav"
+            :class="{ isScreenScroll: isScreenScroll }"
+            :fixed="false"
+            :title="state.musicDetail.musicSheetName"
+            left-arrow
+            @click-left="goBack"
+         />
+         <div v-else class="logoDownload" :class="{ isShareScreenScroll: isScreenScroll }">
+            <img :src="isScreenScroll ? require('./img/logo1.png') : require('./img/logo.png')" class="logoImg" />
+            <div class="logTit" @click="handlerDownLoad">下载App</div>
+         </div>
+      </van-sticky>
+      <div v-if="isEmpty" class="isEmpty">
+         <MEmpty msg="作品已删除~" />
+      </div>
+      <template v-else>
+         <div class="singerBox">
+            <div class="musicSheetName">
+               <van-notice-bar :text="state.musicDetail.musicSheetName" background="none" />
+            </div>
+            <div class="singerName">演奏:{{ state.musicDetail.username }}</div>
+         </div>
+         <van-sticky :offset-top="44 + navBarHeight" :z-index="200">
+            <div class="playBox" ref="playBoxDom">
+               <div
+                  :class="[
+                     'playSection',
+                     plyrState.mediaTimeShow && 'mediaTimeShow',
+                     isLandscapeScreen && 'isLandscapeScreen',
+                     state.playType === 'Video' && 'videoType'
+                  ]"
+                  id="playMediaSection"
+                  @click="handlerClickPlay"
+               >
+                  <!-- 横屏 -->
+                  <div v-if="isLandscapeScreen" class="backBox">
+                     <img class="backImg" :src="require('./img/back.png')" @click="handlerBack" />
+                     <div class="musicDetail">
+                        <div class="musicSheetName">
+                           <van-notice-bar :text="state.musicDetail.musicSheetName" background="none" />
+                        </div>
+                        <div class="username">演奏:{{ state.musicDetail.username }}</div>
+                     </div>
+                  </div>
+                  <!-- audio -->
+                  <div class="audioBox" v-if="state.playType === 'Audio'">
+                     <canvas class="audioVisualizer" id="audioVisualizer"></canvas>
+                     <audio
+                        crossorigin="anonymous"
+                        id="audioMediaSrc"
+                        :src="state.musicDetail.videoUrl"
+                        controls="false"
+                        preload="metadata"
+                        playsinline
+                        webkit-playsinline
+                     />
+                     <div class="audioBoxBg">
+                        <div :class="['audioPan', plyrState.playIngShow ? 'imgRotate' : '']">
+                           <van-image class="audioImg" :src="state.musicDetail.img || require('./img/music_bg.png')" />
+                        </div>
+                        <i class="audioPoint"></i>
+                        <i :class="['audioZhen', plyrState.playIngShow && 'active']"></i>
+                     </div>
+                  </div>
+                  <!-- video -->
+                  <video
+                     v-if="state.playType === 'Video'"
+                     id="videoMediaSrc"
+                     class="videoBox"
+                     :src="state.musicDetail.videoUrl"
+                     :data-poster="state.musicDetail.videoImg || require('./img/videoBg.png')"
+                     :poster="state.musicDetail.videoImg || require('./img/videoBg.png')"
+                     preload="metadata"
+                     playsinline
+                     webkit-playsinline
+                     x5-playsinline
+                  />
+                  <!-- 工具 -->
+                  <div :class="['playLarge', !plyrState.mediaTimeShow && plyrState.playIngShow && 'playIngShow']"></div>
+                  <div class="mediaTimeCon">
+                     <div class="mediaTime">
+                        <div>
+                           {{ getSecondRPM(plyrState.currentTime) }}
+                        </div>
+                        <div class="note">/</div>
+                        <div class="duration">
+                           {{ getSecondRPM(plyrState.duration) }}
+                        </div>
+                     </div>
+                  </div>
+                  <div class="landscapeScreen" @click="handlerLandscapeScreen"></div>
+                  <!-- 谱面 -->
+                  <div v-if="staffState.staffSrc" :class="['staffBoxCon', staffState.isShow && 'staffBoxShow']">
+                     <div
+                        class="staffBox"
+                        :style="{
+                           '--staffBoxHeight': staffState.height
+                        }"
+                     >
+                        <div class="mask"></div>
+                        <iframe ref="staffDom" class="staff" frameborder="0" :src="staffState.staffSrc"></iframe>
+                     </div>
+                  </div>
+               </div>
+            </div>
+         </van-sticky>
+         <div class="musicSection musicShareSection">
+            <div class="avatarInfoBox">
+               <div class="avatar">
+                  <van-image class="userLogo" :src="state.musicDetail.avatar" />
+                  <div class="infoCon">
+                     <div class="info">
+                        <span class="userName">{{ state.musicDetail.username }}</span>
+                        <img :src="require('./img/icon-member.png')" v-if="state.musicDetail.vipFlag" class="iconMember" />
+                     </div>
+                     <div class="sub">
+                        {{ state.musicDetail.subjectName ? state.musicDetail.subjectName : "" }}
+                     </div>
+                  </div>
+               </div>
+               <div class="linkes" @click="onStarChange">
+                  <img src="./img/icon-zan-active.png" v-if="state.musicDetail.starFlag" class="iconZan" />
+                  <img src="./img/icon-zan.png" v-else class="iconZan" />
+                  <span>{{ state.musicDetail.likeNum }}</span>
+               </div>
+            </div>
+            <textEllipsis class="textEllipsis" :text="state.musicDetail.desc || ''" />
+         </div>
+         <div class="likeSection likeShareSection">
+            <div class="likeTitle">推荐作品</div>
+            <template v-if="state.listState.dataShow">
+               <van-list :finished="state.listState.finished" :finishedText="' '" :immediateCheck="false">
+                  <van-cell
+                     v-for="(item, index) in state.list"
+                     :key="index"
+                     :class="['likeShareItem', index === state.list.length - 1 && 'likeShareItemLast']"
+                     :border="false"
+                     @click="onDetail(item)"
+                  >
+                     <template #icon>
+                        <div class="audioImgBox">
+                           <img :src="require('./img/audio-pan.png')" class="audioPan" crossorigin="anonymous" />
+                           <img :src="item.img || require('./share-model/images/music-bg.png')" class="muploader" crossorigin="anonymous" />
+                           <img
+                              class="imgLabel"
+                              :src="
+                                 item.videoUrl && item.videoUrl.lastIndexOf('mp4') !== -1
+                                    ? require('./share-model/images/videoLabel.png')
+                                    : require('./share-model/images/audioLabel.png')
+                              "
+                           />
+                        </div>
+                     </template>
+                     <template #title>
+                        <div class="userInfo">
+                           <div class="musicSheetName van-ellipsis">{{ item.musicSheetName }}</div>
+                           <div class="usernameCon">
+                              <div class="likeNum">
+                                 <img :src="require('./img/icon-zan-active.png')" />
+                                 <span>{{ item.likeNum }}</span>
+                              </div>
+                              <div class="username van-ellipsis">{{ item.username }}</div>
+                           </div>
+                        </div>
+                     </template>
+                     <template #default>
+                        <div class="time">
+                           <img :src="require('./img/play.png')" class="playImg" />
+                        </div>
+                     </template>
+                  </van-cell>
+               </van-list>
+               <div v-if="!state.listState.finished || state.params.page > 2" class="btnImg">
+                  <img @click="handleChangeList" @touchstart="() => {}" :src="require('./img/btn.png')" />
+               </div>
+            </template>
+            <MEmpty class="mEmpty" v-else msg="暂无作品" style="margin-bottom: 0.5rem" />
+         </div>
+         <div class="upward shareUpward" v-show="!isScreenScroll">
+            <img :src="require('./img/upward.png')" />
+         </div>
+      </template>
+      <van-popup v-model="loginStatus" style="background: transparent; overflow: inherit">
+         <LoginModel @close="() => (this.loginStatus = false)" @confirm="onConfirm" />
+      </van-popup>
+      <Loading v-if="!staffState.isShow"></Loading>
+      <div
+         v-if="wxStatus"
+         class="wxpopup"
+         @click="
+            () => {
+               wxStatus = false
+            }
+         "
+      >
+         <img src="./img/wx_bg.png" alt="" />
+      </div>
+   </div>
+</template>
+
+<script>
+import dayjs from "dayjs"
+import { browser, getSecondRPM, validStudentUrl } from "@/common/common"
+import { postMessage } from "@/helpers/native-message"
+import { api_openUserMusicPage, api_userMusicStar, api_openUserMusicDetail } from "./api"
+import audioVisualDraw, { vaildMusicScoreUrl } from "./audioVisualDraw"
+import textEllipsis from "./textEllipsis"
+import Loading from "./loading"
+import "plyr/dist/plyr.css"
+import Plyr from "plyr"
+import MEmpty from "@/components/MEmpty"
+import LoginModel from "./login-model"
+export default {
+   name: "creation",
+   data() {
+      return {
+         id: this.$route.query.id,
+         loginTag: false, // 是否登录标识
+         loginStatus: false,
+         isEmpty: false,
+         wxStatus: false,
+         state: {
+            playType: "", // 播放类型
+            musicDetail: {},
+            isClick: false,
+            list: [],
+            listState: {
+               dataShow: true, // 判断是否有数据
+               loading: false,
+               finished: false
+            },
+            params: {
+               page: 1,
+               rows: 4
+            },
+            _plrl: null,
+            heightA: 0
+         },
+         plyrState: {
+            duration: 0,
+            currentTime: 0,
+            mediaTimeShow: false,
+            playIngShow: true
+         },
+         isLandscapeScreen: false,
+         isScreenScroll: false,
+         navBarHeight: 0,
+         staffState: {
+            staffSrc: "",
+            isShow: false,
+            height: "initial",
+            speedRate: 1,
+            musicRenderType: "staff",
+            partIndex: 0
+         },
+         creationHeight: 0
+      }
+   },
+   components: {
+      textEllipsis,
+      MEmpty,
+      Loading,
+      LoginModel
+   },
+   methods: {
+      getSecondRPM,
+      browser,
+      onDayjs(time) {
+         return dayjs(time).format("YYYY-MM-DD HH:mm")
+      },
+      goBack() {
+         if (browser().isApp) {
+            this.setStatusBarTextColor(false)
+            postMessage({ api: "setBarStatus", content: { status: 1, backButtonHidden: 0 } })
+            postMessage({
+               api: "back"
+            })
+         } else {
+            this.$router.back()
+         }
+      },
+      onDetail(item) {
+         this.$router.push({
+            path: "/shareCreation",
+            query: {
+               id: item.id
+            }
+         })
+      },
+      // 点赞
+      async onStarChange() {
+         try {
+            await api_userMusicStar({
+               userMusicId: this.id,
+               star: !this.state.musicDetail.starFlag
+            })
+
+            this.state.musicDetail.starFlag = !this.state.musicDetail.starFlag
+            if (this.state.musicDetail.starFlag) {
+               this.state.musicDetail.likeNum += 1
+            } else {
+               this.state.musicDetail.likeNum -= 1
+            }
+         } catch (e) {
+            //
+            if (e.code === 403) {
+               this.loginStatus = true
+            }
+         }
+      },
+      async onConfirm(val) {
+         this.loginTag = val
+         this.loginStatus = false
+         const { data } = await api_openUserMusicDetail(this.id)
+         this.musicDetail = data
+      },
+      async getStarList() {
+         try {
+            if (this.state.isClick) return
+            this.state.isClick = true
+            const res = await api_openUserMusicPage({
+               type: "FORMAL",
+               exclusionId: this.id,
+               sort: 1,
+               ...this.state.params
+            })
+            this.state.listState.loading = false
+            const result = res.data || {}
+            // 处理重复请求数据
+            // if (this.state.list.length > 0 && result.current === 1) {
+            //    return
+            // }
+            this.state.list = result.rows || []
+
+            this.state.listState.finished = result.current >= result.pages
+            this.state.params.page = result.current + 1
+            this.state.listState.dataShow = this.state.list.length > 0
+            this.state.isClick = false
+         } catch {
+            this.state.listState.dataShow = false
+            this.state.listState.finished = true
+            this.state.isClick = false
+         }
+      },
+      handleChangeList() {
+         if (this.state.listState.finished) {
+            this.state.listState.finished = false
+            this.state.params.page = 1
+            this.getStarList()
+         } else {
+            this.getStarList()
+         }
+      },
+      async init() {
+         /* 初始化请求 */
+         try {
+            const res = await api_openUserMusicDetail(this.id)
+            this.state.musicDetail = res.data || {}
+            try {
+               const jsonConfig = JSON.parse(res.data.jsonConfig)
+               jsonConfig.speedRate && (this.staffState.speedRate = jsonConfig.speedRate)
+               jsonConfig.musicRenderType && (this.staffState.musicRenderType = jsonConfig.musicRenderType)
+               jsonConfig.partIndex && (this.staffState.partIndex = jsonConfig.partIndex)
+            } catch {}
+            // 五线谱
+            this.initStaff()
+            this.getStarList()
+            // 判断是视频还是音频
+            if (res.data.videoUrl.lastIndexOf("mp4") !== -1) {
+               this.state.playType = "Video"
+            } else {
+               this.state.playType = "Audio"
+            }
+            this.$nextTick(() => {
+               this.initMediaPlay()
+            })
+         } catch (e) {
+            this.staffState.isShow = true
+            if (e.code === 999) {
+               this.isEmpty = true
+            }
+         }
+      },
+      // 初始化 媒体播放
+      initMediaPlay() {
+         const { playStaff, pauseStaff, updateProgressStaff } = this.staffMoveInstance()
+         const id = this.state.playType === "Audio" ? "#audioMediaSrc" : "#videoMediaSrc"
+         this.state._plrl = new Plyr(id, {
+            controls: ["play", "progress", "current-time", "duration"],
+            fullscreen: {
+               enabled: false,
+               fallback: false
+            }
+         })
+         const player = this.state._plrl
+         // 创建音波数据
+         if (this.state.playType === "Audio") {
+            const audioDom = document.querySelector("#audioMediaSrc")
+            const canvasDom = document.querySelector("#audioVisualizer")
+            const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
+            player.on("play", () => {
+               playVisualDraw()
+            })
+            player.on("pause", () => {
+               pauseVisualDraw()
+            })
+         }
+         player.on("timeupdate", () => {
+            this.plyrState.currentTime = player.currentTime
+         })
+         player.on("play", () => {
+            this.plyrState.playIngShow = false
+            playStaff()
+         })
+         player.on("pause", () => {
+            this.plyrState.playIngShow = true
+            pauseStaff()
+         })
+         player.on("ended", () => {
+            if (this.plyrState.mediaTimeShow) return
+            player.currentTime = 0
+            if (!player.playing) {
+               setTimeout(() => {
+                  updateProgressStaff(player.currentTime)
+               }, 100)
+            }
+         })
+         // 处理按压事件
+         const handleStart = () => {
+            if (this.isLandscapeScreen.value) {
+               return
+            }
+            this.plyrState.duration = player.duration
+            this.plyrState.mediaTimeShow = true
+         }
+         // 处理松开事件
+         const handleEnd = () => {
+            this.plyrState.mediaTimeShow = false
+            // 暂停的时候调用
+            if (!player.playing) {
+               updateProgressStaff(player.currentTime)
+            }
+         }
+         const progressDom = document.querySelector("#playMediaSection .plyr__controls .plyr__progress__container")
+         progressDom.addEventListener("mousedown", handleStart)
+         progressDom.addEventListener("touchstart", handleStart)
+         progressDom.addEventListener("mouseup", handleEnd)
+         progressDom.addEventListener("touchend", handleEnd)
+      },
+      // 初始化五线谱
+      initStaff() {
+         const src = `${vaildMusicScoreUrl()}/gym-music-score/#/simple-detail?id=${this.state.musicDetail.musicSheetId}&musicRenderType=${
+            this.staffState.musicRenderType
+         }&part-index=${this.staffState.partIndex}`
+         //const src = `http://192.168.3.122:3000/gym-music-score.html#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
+         this.staffState.staffSrc = src
+         window.addEventListener("message", event => {
+            const { api, height } = event.data
+            if (api === "api_musicPage") {
+               this.staffState.isShow = true
+               this.staffState.height = height + "px"
+            }
+         })
+      },
+      staffMoveInstance() {
+         let isPause = true
+         const requestAnimationFrameFun = () => {
+            requestAnimationFrame(() => {
+               this.$refs.staffDom?.contentWindow?.postMessage(
+                  {
+                     api: "api_playProgress",
+                     content: {
+                        currentTime: this.state._plrl.currentTime * this.staffState.speedRate
+                     }
+                  },
+                  "*"
+               )
+               if (!isPause) {
+                  requestAnimationFrameFun()
+               }
+            })
+         }
+         const playStaff = () => {
+            // 没渲染不执行
+            if (!this.staffState.isShow) return
+            isPause = false
+            this.$refs.staffDom?.contentWindow?.postMessage(
+               {
+                  api: "api_play"
+               },
+               "*"
+            )
+            requestAnimationFrameFun()
+         }
+         const pauseStaff = () => {
+            // 没渲染不执行
+            if (!this.staffState.isShow) return
+            isPause = true
+            this.$refs.staffDom?.contentWindow?.postMessage(
+               {
+                  api: "api_paused"
+               },
+               "*"
+            )
+         }
+         const updateProgressStaff = currentTime => {
+            // 没渲染不执行
+            if (!this.staffState.isShow) return
+            this.$refs.staffDom?.contentWindow?.postMessage(
+               {
+                  api: "api_updateProgress",
+                  content: {
+                     currentTime: currentTime * this.staffState.speedRate
+                  }
+               },
+               "*"
+            )
+         }
+         return {
+            playStaff,
+            pauseStaff,
+            updateProgressStaff
+         }
+      },
+      //点击改变播放状态
+      handlerClickPlay(event) {
+         // 原生 播放暂停按钮 点击的时候 不触发
+         if (event?.target?.matches("button.plyr__control")) {
+            return
+         }
+         if (this.state._plrl.playing) {
+            this.state._plrl.pause()
+         } else {
+            this.state._plrl.play()
+         }
+      },
+      handleScroll() {
+         // 作品已删除不让滚动变色
+         if (this.isEmpty) return
+         const height = window.scrollY || document.documentElement.scrollTop
+         // 防止多次调用
+         if (height > 0 && this.isScreenScroll === false) {
+            this.isScreenScroll = true
+            this.setStatusBarTextColor(false)
+         }
+         if (height <= 0) {
+            this.isScreenScroll = false
+            this.setStatusBarTextColor(true)
+         }
+      },
+      // 设置导航栏颜色
+      setStatusBarTextColor(isWhite) {
+         postMessage({
+            api: "setStatusBarTextColor",
+            content: { statusBarTextColor: isWhite }
+         })
+      },
+      handleVisibilitychange() {
+         if (document.hidden) {
+            this.state._plrl?.pause()
+         }
+      },
+      handlerBack(event) {
+         event.stopPropagation()
+         this.verticalScreen()
+      },
+      landscapeScreen() {
+         postMessage({
+            api: "setRequestedOrientation",
+            content: {
+               orientation: 0
+            }
+         })
+         this.isLandscapeScreen = true
+      },
+      verticalScreen() {
+         postMessage({
+            api: "setRequestedOrientation",
+            content: {
+               orientation: 1
+            }
+         })
+         this.isLandscapeScreen = false
+      },
+      handlerLandscapeScreen(event) {
+         event.stopPropagation()
+         const { isApp, weixin } = browser()
+         if (isApp) {
+            this.landscapeScreen()
+            return
+         }
+         if (weixin) {
+            this.wxStatus = true
+         } else {
+            const t = Date.now()
+            const str = location.href
+            this.shareCall(str)
+            setTimeout(() => {
+               if (Date.now() - t < 3500) {
+                  window.location.replace(validStudentUrl() + "/#/studentDownLoad")
+               }
+            }, 3000)
+         }
+      },
+      shareCall(str) {
+         const iosStr = encodeURIComponent(str)
+         const userAgent = navigator.userAgent || navigator.vendor
+         if (/(iPhone|iPad|iPod|iOS)/i.test(userAgent)) {
+            window.location.href = `StudentsDaya://linkUrl=${iosStr}`
+         } else if (/(Android)/i.test(userAgent)) {
+            window.location.href = `studentdaya://html:8888/SplashActivity?url=${iosStr}`
+         } else {
+            showToast("请用手机或移动设备打开")
+         }
+      },
+      handlerDownLoad() {
+         if (browser().weixin) {
+            this.wxStatus = true
+         } else {
+            window.location.replace(validStudentUrl() + "/#/studentDownLoad")
+         }
+      },
+      setFullHeight() {
+         this.creationHeight = window.innerHeight
+      }
+   },
+   mounted() {
+      this.state.heightA = this.$refs.playBoxDom.offsetHeight
+      document.addEventListener("scroll", this.handleScroll)
+      document.addEventListener("visibilitychange", this.handleVisibilitychange)
+      this.setFullHeight()
+      window.addEventListener("resize", this.setFullHeight)
+   },
+   destroyed() {
+      this.state._plrl?.destroy()
+      document.removeEventListener("scroll", this.handleScroll)
+      document.removeEventListener("visibilitychange", this.handleVisibilitychange)
+      window.removeEventListener("resize", this.setFullHeight)
+   },
+   created() {
+      this.setStatusBarTextColor(true)
+      postMessage({ api: "setBarStatus", content: { status: 0, backButtonHidden: 1 } })
+      postMessage({ api: "getNavHeight" }, res => {
+         const { content } = res
+         const dpi = content.dpi || 2
+         if (content.navHeight) {
+            const navHeight = content.navHeight / dpi
+            this.navBarHeight = navHeight
+         }
+      })
+      this.init()
+   }
+}
+</script>
+
+<style lang="less" scoped>
+@import url("./index.less");
+</style>