|
@@ -1,953 +1,608 @@
|
|
|
<template>
|
|
|
- <div class="creation">
|
|
|
- <div class="playSection">
|
|
|
- <videoTcplayer v-if="playType === 'Video'" :src="musicDetail.videoUrl" :poster="musicDetail.videoImg || videoBg" />
|
|
|
- <div class="audioSection" v-if="playType === 'Audio'">
|
|
|
- <div class="audioContainer">
|
|
|
- <div class="waveActive" :style="{ width: audioWidth + '%' }"></div>
|
|
|
- <div class="waveDefault"></div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="audioBox">
|
|
|
- <div :class="['audioPan', paused ? 'imgRotate' : '']">
|
|
|
- <van-image class="audioImg" :src="musicDetail.img || musicBg" />
|
|
|
- </div>
|
|
|
- <i class="audioPoint"></i>
|
|
|
- <i :class="['audioZhen', paused && 'active']"></i>
|
|
|
- </div>
|
|
|
- <div class="controls" @click="onControls">
|
|
|
- <div class="actions">
|
|
|
- <div class="actionBtn" @click="onToggleAudio">
|
|
|
- <img v-if="paused" src="./img/icon-play.png" />
|
|
|
- <img v-else src="./img/icon-pause.png" />
|
|
|
+ <div
|
|
|
+ class="creation"
|
|
|
+ :style="{
|
|
|
+ '--heightA': state.heightA + 'px',
|
|
|
+ '--navBarHeight': navBarHeight + 'px'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <div class="creationBg"></div>
|
|
|
+ <van-sticky>
|
|
|
+ <van-nav-bar
|
|
|
+ class="nav"
|
|
|
+ :class="{ isScreenScroll: isScreenScroll }"
|
|
|
+ :fixed="false"
|
|
|
+ :title="state.musicDetail.musicSheetName"
|
|
|
+ left-arrow
|
|
|
+ @click-left="goBack"
|
|
|
+ />
|
|
|
+ </van-sticky>
|
|
|
+ <div class="singer">演奏:{{ state.musicDetail.username }}</div>
|
|
|
+ <van-sticky :offset-top="44 + navBarHeight" :z-index="200">
|
|
|
+ <div class="playBox" data-html2canvas-ignore="true" 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="state.playType === 'Video'?require('./img/back1.png'):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
|
|
|
+ />
|
|
|
+ <img src="./img/ty.png" class="tyBg" />
|
|
|
+ <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>
|
|
|
- <div class="slider">
|
|
|
- <van-slider :step="0.01" class="timeProgress" v-model="currentTime" :max="duration" @input="handleChangeTime" @drag-start="dragStatus = true" @drag-end="dragStatus = false" />
|
|
|
- </div>
|
|
|
- <div class="time">
|
|
|
- <div>{{ getSecondRPM(currentTime) }}</div>
|
|
|
- <span>/</span>
|
|
|
- <div>{{ getSecondRPM(duration) }}</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <van-cell class="userSection" center :border="false">
|
|
|
- <template #icon>
|
|
|
- <van-image class="userLogo" :src="musicDetail.avatar" />
|
|
|
- </template>
|
|
|
- <template #title>
|
|
|
- <div class="userInfo">
|
|
|
- <p class="name">
|
|
|
- <span>{{ musicDetail.username }}</span>
|
|
|
- <img v-if="musicDetail.vipFlag" src="./img/icon-member.png" class="iconMember" />
|
|
|
- </p>
|
|
|
- <p class="sub van-multi-ellipsis--l2">
|
|
|
- {{ musicDetail.subjectName }}
|
|
|
- {{ getGradeCh(musicDetail.currentGradeNum - 1) }}
|
|
|
- </p>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- <template #default>
|
|
|
- <div :class="['zan', 'zanActive']">
|
|
|
- <img src="./img/icon-zan-active.png" class="iconZan" />
|
|
|
- {{ musicDetail.likeNum }}
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </van-cell>
|
|
|
-
|
|
|
- <div class="musicSection">
|
|
|
- <div class="musicName">
|
|
|
- <span class="musicTag">曲目名称</span>
|
|
|
- {{ musicDetail.musicSheetName }}
|
|
|
- </div>
|
|
|
- <div class="musicDesc">{{ musicDetail.desc }}</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="likeSection">
|
|
|
- <div class="likeTitle">点赞记录</div>
|
|
|
-
|
|
|
- <van-list v-if="listState.dataShow" class="container containerInformation" :finished="listState.finished" finished-text=" " :immediate-check="false" @load="getStarList()">
|
|
|
- <!-- {state.list.map((item: any, index: number) => ( -->
|
|
|
- <van-cell v-for="(item, index) in list" :key="index" class="likeItem" :border="list.length - 1 == index ? false : true">
|
|
|
- <template #icon>
|
|
|
- <van-image :src="item.userAvatar" class="userLogo" />
|
|
|
- </template>
|
|
|
- <template #title>
|
|
|
- <div class="userInfo">
|
|
|
- <p class="name">{{ item.userName }}</p>
|
|
|
- <p class="sub">
|
|
|
- {{ item.subjectName }}
|
|
|
- {{ getGradeCh(item.currentGradeNum - 1) }}
|
|
|
- </p>
|
|
|
+ </div>
|
|
|
+ </van-sticky>
|
|
|
+ <div class="musicSection">
|
|
|
+ <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.currentGradeNum ? getGradeCh(state.musicDetail.currentGradeNum - 1) : "")
|
|
|
+ }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </template>
|
|
|
- <template #default>
|
|
|
- <div class="time">
|
|
|
- {{ onDayjs(item.createTime) }}
|
|
|
+ <div class="linkes">
|
|
|
+ <img :src="require('./img/icon-zan.png')" class="iconZan" />
|
|
|
+ <span>{{ state.musicDetail.likeNum }}</span>
|
|
|
</div>
|
|
|
- </template>
|
|
|
- </van-cell>
|
|
|
- </van-list>
|
|
|
-
|
|
|
- <MEmpty v-else msg="暂无数据" style="margin-bottom: 0.5rem" />
|
|
|
-
|
|
|
- <div class="sticky-section">
|
|
|
- <div class="bottomSection">
|
|
|
- <div class="bottomShare">
|
|
|
+ </div>
|
|
|
+ <textEllipsis class="textEllipsis" :text="state.musicDetail.desc || ''" />
|
|
|
+ </div>
|
|
|
+ <div class="likeSection">
|
|
|
+ <div class="likeTitle">点赞记录</div>
|
|
|
+ <van-list
|
|
|
+ v-if="state.listState.dataShow"
|
|
|
+ :finished="state.listState.finished"
|
|
|
+ :finishedText="' '"
|
|
|
+ @load="getStarList"
|
|
|
+ :immediateCheck="false"
|
|
|
+ >
|
|
|
+ <van-cell
|
|
|
+ v-for="(item, index) in state.list"
|
|
|
+ :key="index"
|
|
|
+ :class="['likeItem', index === state.list.length - 1 && 'likeItemLast']"
|
|
|
+ :border="false"
|
|
|
+ >
|
|
|
+ <template #icon>
|
|
|
+ <van-image :src="item.userAvatar" class="userLogo" />
|
|
|
+ </template>
|
|
|
+ <template #title>
|
|
|
+ <div class="userInfo">
|
|
|
+ <p class="name">{{ item.userName || `游客${item.userId}` }}</p>
|
|
|
+ <p class="sub">
|
|
|
+ {{ (item.subjectName || "") + " " + (item.currentGradeNum ? getGradeCh(item.currentGradeNum - 1) : "") }}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template #default>
|
|
|
+ <div class="time">
|
|
|
+ {{ onDayjs(item.createTime) }}
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </van-cell>
|
|
|
+ </van-list>
|
|
|
+ <MEmpty class="mEmpty" v-else msg="暂无内容" style="margin-bottom: 0.5rem" />
|
|
|
+ </div>
|
|
|
+ <div class="upward" v-show="!isScreenScroll">
|
|
|
+ <img :src="require('./img/upward.png')" />
|
|
|
+ </div>
|
|
|
+ <div class="bottomSection">
|
|
|
+ <div class="bottomShare">
|
|
|
<p @click="onDownload">
|
|
|
- <img src="./img/icon-download.png" />
|
|
|
- <span>下载</span>
|
|
|
+ <img :src="require('./img/icon-download.png')" />
|
|
|
+ <span>下载</span>
|
|
|
</p>
|
|
|
- <p @click="shareStatus = true">
|
|
|
- <img src="./img/icon-share.png" />
|
|
|
- <span>分享</span>
|
|
|
+ <p @click="() => (state.shareStatus = true)">
|
|
|
+ <img :src="require('./img/icon-share.png')" />
|
|
|
+ <span>分享</span>
|
|
|
</p>
|
|
|
- <p @click="deleteStatus = true">
|
|
|
- <img src="./img/icon-delete.png" />
|
|
|
- <span>删除</span>
|
|
|
+ <p @click="() => (state.deleteStatus = true)">
|
|
|
+ <img :src="require('./img/icon-delete.png')" />
|
|
|
+ <span>删除</span>
|
|
|
</p>
|
|
|
- </div>
|
|
|
- <van-button round class="btnEdit" type="primary" @click="onDetail"> 编辑 </van-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <van-popup position="bottom" v-model="shareStatus" style="background: transparent">
|
|
|
- <ShareModel :musicDetail="musicDetail" @close="shareStatus = false" />
|
|
|
- </van-popup>
|
|
|
-
|
|
|
- <van-popup v-model="deleteStatus" round class="popupContainer">
|
|
|
- <p class="popupContent">确定删除吗?</p>
|
|
|
- <div class="popupBtnGroup">
|
|
|
- <van-button round @click="() => (deleteStatus = false)"> 取消 </van-button>
|
|
|
- <van-button round type="primary" @click="onDelete"> 确定 </van-button>
|
|
|
+ </div>
|
|
|
+ <img
|
|
|
+ :src="require('./img/edit.png')"
|
|
|
+ class="btnEdit"
|
|
|
+ @click="
|
|
|
+ () => {
|
|
|
+ setStatusBarTextColor(false)
|
|
|
+ $router.push({ path: '/creation-edit', query: { id: this.id } })
|
|
|
+ }
|
|
|
+ "
|
|
|
+ />
|
|
|
</div>
|
|
|
- </van-popup>
|
|
|
- </div>
|
|
|
+ <Loading v-if="!staffState.isShow"></Loading>
|
|
|
+ <van-popup position="bottom" v-model="state.shareStatus" style=" background: transparent ">
|
|
|
+ <ShareModel :musicDetail="state.musicDetail" @close="state.shareStatus = false" />
|
|
|
+ </van-popup>
|
|
|
+ <van-popup v-model="state.deleteStatus" round class="popupContainer">
|
|
|
+ <p class="popupTit">温馨提示</p>
|
|
|
+ <p class="popupContent">确认删除作品吗?</p>
|
|
|
+ <div class="popupBtnGroup">
|
|
|
+ <van-button round @click="() => (state.deleteStatus = false)">
|
|
|
+ 取消
|
|
|
+ </van-button>
|
|
|
+ <van-button round type="primary" @click="onDelete">
|
|
|
+ 确认
|
|
|
+ </van-button>
|
|
|
+ </div>
|
|
|
+ </van-popup>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import dayjs from "dayjs";
|
|
|
-import { getSecondRPM, browser, getGradeCh } from "@/common/common";
|
|
|
-import videoTcplayer from "@/components/video-tcplayer";
|
|
|
-import MEmpty from "@/components/MEmpty";
|
|
|
-import { postMessage } from "@/helpers/native-message";
|
|
|
-import { api_userMusicRemove, api_userMusicDetail, api_userMusicStarPage } from "./api";
|
|
|
-import ShareModel from "./share-model";
|
|
|
-const audioDom = new Audio();
|
|
|
-audioDom.controls = true;
|
|
|
-audioDom.style.width = "100%";
|
|
|
-audioDom.className = "audio";
|
|
|
+import dayjs from "dayjs"
|
|
|
+import { browser, getSecondRPM, getGradeCh} from "@/common/common"
|
|
|
+import { postMessage } from "@/helpers/native-message"
|
|
|
+import { api_userMusicDetail, api_userMusicRemove, api_userMusicStarPage } 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 ShareModel from "./share-model"
|
|
|
export default {
|
|
|
- components: { videoTcplayer, MEmpty, ShareModel },
|
|
|
- data() {
|
|
|
- return {
|
|
|
- id: this.$route.query.id,
|
|
|
- videoBg: require("./img/video-bg.png"),
|
|
|
- musicBg: require("./img/music_bg.png"),
|
|
|
- deleteStatus: false,
|
|
|
- shareStatus: false,
|
|
|
- playType: "", // 播放类型
|
|
|
- musicDetail: {},
|
|
|
- timer: null,
|
|
|
- audioWidth: 0,
|
|
|
- paused: true,
|
|
|
- currentTime: 0,
|
|
|
- duration: 0.1,
|
|
|
- loop: false,
|
|
|
- dragStatus: false, // 是否开始拖动
|
|
|
- isClick: false,
|
|
|
- list: [],
|
|
|
- listState: {
|
|
|
- dataShow: true, // 判断是否有数据
|
|
|
- loading: false,
|
|
|
- finished: false,
|
|
|
+ name: "creation",
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ id: this.$route.query.id,
|
|
|
+ state: {
|
|
|
+ deleteStatus: false,
|
|
|
+ shareStatus: false,
|
|
|
+ playType: "", // 播放类型
|
|
|
+ musicDetail: {},
|
|
|
+ isClick: false,
|
|
|
+ list: [],
|
|
|
+ listState: {
|
|
|
+ dataShow: true, // 判断是否有数据
|
|
|
+ loading: false,
|
|
|
+ finished: false
|
|
|
+ },
|
|
|
+ params: {
|
|
|
+ page: 1,
|
|
|
+ rows: 20
|
|
|
+ },
|
|
|
+ _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
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ components: {
|
|
|
+ textEllipsis,
|
|
|
+ MEmpty,
|
|
|
+ Loading,
|
|
|
+ ShareModel
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ getGradeCh,
|
|
|
+ getSecondRPM,
|
|
|
+ onDayjs(time) {
|
|
|
+ return dayjs(time).format("YYYY-MM-DD HH:mm")
|
|
|
},
|
|
|
- params: {
|
|
|
- page: 1,
|
|
|
- rows: 20,
|
|
|
+ goBack() {
|
|
|
+ if (browser().isApp) {
|
|
|
+ this.setStatusBarTextColor(false)
|
|
|
+ postMessage({ api: "setBarStatus", content: { status: 1, backButtonHidden: 0 } })
|
|
|
+ postMessage({
|
|
|
+ api: "goBack"
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ this.$router.back()
|
|
|
+ }
|
|
|
},
|
|
|
- };
|
|
|
- },
|
|
|
- async mounted() {
|
|
|
- document.title = "作品详情";
|
|
|
- try {
|
|
|
- const res = await api_userMusicDetail(this.id);
|
|
|
-
|
|
|
- this.musicDetail = res.data || {};
|
|
|
-
|
|
|
- this.getStarList();
|
|
|
- // 判断是视频还是音频
|
|
|
- if (res.data.videoUrl.lastIndexOf("mp4") !== -1) {
|
|
|
- this.playType = "Video";
|
|
|
- } else {
|
|
|
- this.playType = "Audio";
|
|
|
- // 初始化
|
|
|
- this.$nextTick(() => {
|
|
|
- this.initAudio();
|
|
|
- });
|
|
|
- }
|
|
|
- } catch (e) {
|
|
|
- //
|
|
|
- if (e.code === 999) {
|
|
|
- this.$dialog
|
|
|
- .alert({
|
|
|
- message: e.msg,
|
|
|
- theme: "round-button",
|
|
|
- confirmButtonColor: "#2DC7AA",
|
|
|
- })
|
|
|
- .then(() => {
|
|
|
- if (browser().isApp) {
|
|
|
- postMessage({
|
|
|
- api: "goBack",
|
|
|
- });
|
|
|
- } else {
|
|
|
- this.$router.back();
|
|
|
+ // 下载
|
|
|
+ onDownload() {
|
|
|
+ postMessage({
|
|
|
+ api: "saveFile",
|
|
|
+ content: {
|
|
|
+ url: this.state.musicDetail.videoUrl
|
|
|
}
|
|
|
- });
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
- // 设置隐藏属性和改变可见属性的事件的名称
|
|
|
- var hidden, visibilityChange;
|
|
|
- if (typeof document.hidden !== "undefined") {
|
|
|
- // Opera 12.10 and Firefox 18 and later support
|
|
|
- hidden = "hidden";
|
|
|
- visibilityChange = "visibilitychange";
|
|
|
- } else if (typeof document.msHidden !== "undefined") {
|
|
|
- hidden = "msHidden";
|
|
|
- visibilityChange = "msvisibilitychange";
|
|
|
- } else if (typeof document.webkitHidden !== "undefined") {
|
|
|
- hidden = "webkitHidden";
|
|
|
- visibilityChange = "webkitvisibilitychange";
|
|
|
- }
|
|
|
-
|
|
|
- // 如果页面是隐藏状态,则暂停视频
|
|
|
- // 如果页面是展示状态,则播放视频
|
|
|
- const that = this;
|
|
|
- function handleVisibilityChange() {
|
|
|
- if (document[hidden]) {
|
|
|
- if (audioDom) {
|
|
|
- audioDom.pause();
|
|
|
- that.paused = audioDom.paused;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 如果浏览器不支持addEventListener 或 Page Visibility API 给出警告
|
|
|
- if (typeof document.addEventListener === "undefined" || typeof document[hidden] === "undefined") {
|
|
|
- console.log("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
|
|
|
- } else {
|
|
|
- // 处理页面可见属性的改变
|
|
|
- document.addEventListener(visibilityChange, handleVisibilityChange, false);
|
|
|
- }
|
|
|
- },
|
|
|
- methods: {
|
|
|
- onDetail() {
|
|
|
- if (audioDom) {
|
|
|
- audioDom.pause();
|
|
|
- this.paused = audioDom.paused;
|
|
|
- }
|
|
|
- this.$router.push({
|
|
|
- path: "/creation-edit",
|
|
|
- query: {
|
|
|
- id: this.id,
|
|
|
- },
|
|
|
- });
|
|
|
- },
|
|
|
- /** 改变播放时间 */
|
|
|
- handleChangeTime(val) {
|
|
|
- this.currentTime = val;
|
|
|
- clearTimeout(this.timer);
|
|
|
- this.timer = setTimeout(() => {
|
|
|
- // audioRef.value.currentTime = val;
|
|
|
- audioDom.currentTime = val;
|
|
|
- this.timer = null;
|
|
|
- }, 60);
|
|
|
- },
|
|
|
-
|
|
|
- // 切换音频播放
|
|
|
- onToggleAudio(e) {
|
|
|
- e.stopPropagation();
|
|
|
- if (audioDom.paused) {
|
|
|
- audioDom.play();
|
|
|
- } else {
|
|
|
- audioDom.pause();
|
|
|
- }
|
|
|
-
|
|
|
- this.paused = audioDom.paused;
|
|
|
- },
|
|
|
-
|
|
|
- // 获取列表
|
|
|
- async getStarList() {
|
|
|
- try {
|
|
|
- if (this.isClick) return;
|
|
|
- this.isClick = true;
|
|
|
- const res = await api_userMusicStarPage({
|
|
|
- userMusicId: this.id,
|
|
|
- ...this.params,
|
|
|
- });
|
|
|
- this.listState.loading = false;
|
|
|
- const result = res.data || {};
|
|
|
- // 处理重复请求数据
|
|
|
- if (this.list.length > 0 && result.current === 1) {
|
|
|
- return;
|
|
|
- }
|
|
|
- this.list = this.list.concat(result.rows || []);
|
|
|
- this.listState.finished = result.current >= result.pages;
|
|
|
- this.params.page = result.current + 1;
|
|
|
- this.listState.dataShow = this.list.length > 0;
|
|
|
- this.isClick = false;
|
|
|
- } catch {
|
|
|
- this.listState.dataShow = false;
|
|
|
- this.listState.finished = true;
|
|
|
- this.isClick = false;
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 删除作品
|
|
|
+ async onDelete() {
|
|
|
+ try {
|
|
|
+ await api_userMusicRemove({ id: this.id })
|
|
|
+ setTimeout(() => {
|
|
|
+ this.state.deleteStatus = false
|
|
|
+ this.$toast("删除成功")
|
|
|
+ }, 100)
|
|
|
+ setTimeout(() => {
|
|
|
+ this.goBack()
|
|
|
+ }, 1200)
|
|
|
+ } catch {
|
|
|
+ //
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async getStarList() {
|
|
|
+ try {
|
|
|
+ if (this.state.isClick) return
|
|
|
+ this.state.isClick = true
|
|
|
+ const res = await api_userMusicStarPage({
|
|
|
+ userMusicId: this.id,
|
|
|
+ ...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 = this.state.list.concat(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
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 初始化 媒体播放
|
|
|
+ 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() {
|
|
|
+ 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()
|
|
|
+ if (!this.isLandscapeScreen) {
|
|
|
+ this.landscapeScreen()
|
|
|
+ }
|
|
|
}
|
|
|
- },
|
|
|
-
|
|
|
- initAudio() {
|
|
|
- audioDom.src = this.musicDetail.videoUrl;
|
|
|
- audioDom.load();
|
|
|
- audioDom.oncanplaythrough = () => {
|
|
|
- this.paused = audioDom.paused;
|
|
|
- this.duration = audioDom.duration;
|
|
|
- };
|
|
|
- // 播放时监听
|
|
|
- audioDom.addEventListener("timeupdate", () => {
|
|
|
- this.duration = audioDom.duration;
|
|
|
- this.currentTime = audioDom.currentTime;
|
|
|
- const rate = (this.currentTime / this.duration) * 100;
|
|
|
- this.audioWidth = rate > 100 ? 100 : rate;
|
|
|
- });
|
|
|
- audioDom.addEventListener("ended", () => {
|
|
|
- this.paused = audioDom.paused;
|
|
|
- });
|
|
|
- },
|
|
|
- // 删除作品
|
|
|
- async onDelete() {
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.state.heightA = this.$refs.playBoxDom.offsetHeight
|
|
|
+ document.addEventListener("scroll", this.handleScroll)
|
|
|
+ document.addEventListener("visibilitychange", this.handleVisibilitychange)
|
|
|
+ },
|
|
|
+ destroyed() {
|
|
|
+ this.state._plrl?.destroy()
|
|
|
+ document.removeEventListener("scroll", this.handleScroll)
|
|
|
+ document.removeEventListener("visibilitychange", this.handleVisibilitychange)
|
|
|
+ },
|
|
|
+ async 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
|
|
|
+ }
|
|
|
+ })
|
|
|
+ /* 初始化请求 */
|
|
|
try {
|
|
|
- await api_userMusicRemove({ id: this.id });
|
|
|
-
|
|
|
- setTimeout(() => {
|
|
|
- this.deleteStatus = false;
|
|
|
- this.$toast("删除成功");
|
|
|
- }, 100);
|
|
|
-
|
|
|
- setTimeout(() => {
|
|
|
- if (browser().isApp) {
|
|
|
- postMessage({
|
|
|
- api: "back",
|
|
|
- });
|
|
|
- } else {
|
|
|
- this.$router.back();
|
|
|
- }
|
|
|
- }, 1200);
|
|
|
- } catch {
|
|
|
- //
|
|
|
+ const res = await api_userMusicDetail(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.$dialog
|
|
|
+ .alert({
|
|
|
+ message: e.msg,
|
|
|
+ theme: "round-button",
|
|
|
+ confirmButtonColor: "#2DC7AA"
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ this.goBack()
|
|
|
+ })
|
|
|
+ }
|
|
|
}
|
|
|
- },
|
|
|
- // 下载
|
|
|
- async onDownload() {
|
|
|
- postMessage({
|
|
|
- api: "saveFile",
|
|
|
- content: {
|
|
|
- url: this.musicDetail.videoUrl,
|
|
|
- },
|
|
|
- });
|
|
|
- },
|
|
|
- onDayjs(time) {
|
|
|
- return dayjs(time).format("YYYY-MM-DD HH:mm");
|
|
|
- },
|
|
|
- getGradeCh,
|
|
|
- getSecondRPM,
|
|
|
- onControls(e) {
|
|
|
- e.stopPropagation();
|
|
|
- },
|
|
|
- },
|
|
|
- destory() {
|
|
|
- if (audioDom) {
|
|
|
- audioDom.pause();
|
|
|
- this.paused = audioDom.paused;
|
|
|
- }
|
|
|
- },
|
|
|
-};
|
|
|
+ }
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
-.creation {
|
|
|
- min-height: 100vh;
|
|
|
- background-color: #f8f8f8;
|
|
|
-}
|
|
|
-
|
|
|
-/deep/ .vjs-poster {
|
|
|
- background-size: cover;
|
|
|
-}
|
|
|
-
|
|
|
-/deep/ .video-js .vjs-progress-control:hover .vjs-progress-holder {
|
|
|
- font-size: inherit !important;
|
|
|
-}
|
|
|
-
|
|
|
-/deep/ .tcp-skin .vjs-play-progress {
|
|
|
- background-color: #01c1b5;
|
|
|
-}
|
|
|
-
|
|
|
-/deep/ .video-js .vjs-slider:focus {
|
|
|
- box-shadow: none !important;
|
|
|
- text-shadow: none !important;
|
|
|
-}
|
|
|
-
|
|
|
-.playSection {
|
|
|
- min-height: 1.75rem;
|
|
|
-}
|
|
|
-
|
|
|
-@keyframes rotateImg {
|
|
|
- 100% {
|
|
|
- transform: rotate(360deg);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.audioSection {
|
|
|
- position: relative;
|
|
|
- background: url("./img/audio-banner-bg.png") no-repeat top center;
|
|
|
- background-size: cover;
|
|
|
- height: 1.75rem;
|
|
|
-
|
|
|
- .audioContainer {
|
|
|
- position: absolute;
|
|
|
- top: 0;
|
|
|
- left: 50%;
|
|
|
- width: 1.96rem;
|
|
|
- height: 0.35rem;
|
|
|
- transform: translate(-50%, 0.6rem);
|
|
|
-
|
|
|
- .waveActive,
|
|
|
- .waveDefault {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- }
|
|
|
-
|
|
|
- .waveDefault {
|
|
|
- position: absolute;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- background: url("./img/wave-1.png") no-repeat center left;
|
|
|
- background-size: cover;
|
|
|
- }
|
|
|
-
|
|
|
- .waveActive {
|
|
|
- position: absolute;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- z-index: 1;
|
|
|
- background: url("./img/wave-2.png") no-repeat center left;
|
|
|
- background-size: cover;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .audioBox {
|
|
|
- position: absolute;
|
|
|
- left: 50%;
|
|
|
- transform: translate(-50%, 50%);
|
|
|
- z-index: 2;
|
|
|
- width: 0.74rem;
|
|
|
- height: 0.75rem;
|
|
|
- background: url("./img/audio-bg.png") no-repeat center;
|
|
|
- background-size: contain;
|
|
|
-
|
|
|
- .audioPan {
|
|
|
- position: absolute;
|
|
|
- left: 0.08rem;
|
|
|
- top: 0.06rem;
|
|
|
- z-index: 8;
|
|
|
- width: 0.59rem;
|
|
|
- height: 0.6rem;
|
|
|
- background: url("./img/audio-pan.png") no-repeat center;
|
|
|
- background-size: contain;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
-
|
|
|
- animation: rotateImg 6s linear infinite;
|
|
|
-
|
|
|
- &.imgRotate {
|
|
|
- animation-play-state: paused;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .audioImg {
|
|
|
- width: 0.32rem;
|
|
|
- height: 0.32rem;
|
|
|
- border-radius: 50%;
|
|
|
- overflow: hidden;
|
|
|
- }
|
|
|
-
|
|
|
- .audioPoint {
|
|
|
- position: absolute;
|
|
|
- z-index: 9;
|
|
|
- left: 50%;
|
|
|
- top: 50%;
|
|
|
- transform: translate(-50%, -50%);
|
|
|
- width: 0.08rem;
|
|
|
- height: 0.08rem;
|
|
|
- background: url("./img/audio-point.png") no-repeat center;
|
|
|
- background-size: contain;
|
|
|
- }
|
|
|
-
|
|
|
- .audioZhen {
|
|
|
- position: absolute;
|
|
|
- z-index: 9;
|
|
|
- right: -0.04rem;
|
|
|
- top: -0.33rem;
|
|
|
- width: 0.26rem;
|
|
|
- height: 0.87rem;
|
|
|
- background: url("./img/audio-zhen.png") no-repeat center;
|
|
|
- background-size: contain;
|
|
|
- transition: transform 0.5s ease-in-out;
|
|
|
-
|
|
|
- &.active {
|
|
|
- transform: rotate(92deg) translate3d(0, 0, 3px);
|
|
|
- transition: transform 0.5s ease-in-out;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.controls {
|
|
|
- position: absolute;
|
|
|
- left: 0;
|
|
|
- bottom: 0;
|
|
|
- right: 0;
|
|
|
- height: 0.44rem;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- justify-content: space-between;
|
|
|
- flex-direction: row;
|
|
|
- transition: all 0.5s;
|
|
|
- padding: 0 0.12rem;
|
|
|
-
|
|
|
- & > div {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- }
|
|
|
-
|
|
|
- &.hide {
|
|
|
- transform: translateY(100%);
|
|
|
- }
|
|
|
-
|
|
|
- .actionBtn {
|
|
|
- line-height: 0;
|
|
|
- margin-right: 0.04rem;
|
|
|
-
|
|
|
- img {
|
|
|
- width: 0.14rem;
|
|
|
- height: 0.14rem;
|
|
|
- margin-bottom: -0.02rem;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .time {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- flex: 1;
|
|
|
- min-width: 0.86rem;
|
|
|
- font-size: 0.12rem;
|
|
|
- color: #131415;
|
|
|
- line-height: 0.2rem;
|
|
|
-
|
|
|
- span {
|
|
|
- font-size: 0.12rem;
|
|
|
- padding: 0 0.01rem;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .slider {
|
|
|
- width: 100%;
|
|
|
- margin: 0 0.12rem;
|
|
|
- // --van-slider-bar-height: 4px;
|
|
|
- // --van-slider-button-width: 0.13rem !important;
|
|
|
- // --van-slider-button-height: 0.13rem !important;
|
|
|
- // --van-slider-inactive-background: #fff;
|
|
|
- // --van-slider-inactive-background-color: #fff;
|
|
|
- // --van-slider-active-background: #2DC7AA !important;
|
|
|
-
|
|
|
- /deep/ .van-slider {
|
|
|
- height: 0.04rem;
|
|
|
- }
|
|
|
-
|
|
|
- /deep/ .van-slider__button {
|
|
|
- width: 0.13rem;
|
|
|
- height: 0.13rem;
|
|
|
- }
|
|
|
-
|
|
|
- /deep/ .van-loading {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.userSection {
|
|
|
- padding: 0.15rem 0.12rem !important;
|
|
|
- background-color: transparent !important;
|
|
|
-
|
|
|
- .userLogo {
|
|
|
- width: 0.44rem;
|
|
|
- height: 0.44rem;
|
|
|
- border: 0.01rem solid #ffffff;
|
|
|
- margin-right: 0.1rem;
|
|
|
- border-radius: 50%;
|
|
|
- overflow: hidden;
|
|
|
- }
|
|
|
-
|
|
|
- .userInfo {
|
|
|
- .name {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- font-size: 0.16rem;
|
|
|
- font-weight: 500;
|
|
|
- color: #333333;
|
|
|
- line-height: 0.22rem;
|
|
|
-
|
|
|
- span {
|
|
|
- display: inline-block;
|
|
|
- white-space: nowrap;
|
|
|
- overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
- max-width: 1rem;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .sub {
|
|
|
- padding-top: 0.01rem;
|
|
|
- font-size: 0.12rem;
|
|
|
- color: #777777;
|
|
|
- line-height: 0.17rem;
|
|
|
- }
|
|
|
-
|
|
|
- .iconMember {
|
|
|
- margin-left: 0.06rem;
|
|
|
- width: 0.14rem;
|
|
|
- height: 0.14rem;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .zan {
|
|
|
- background: #ffffff;
|
|
|
- border-radius: 0.13rem;
|
|
|
- font-size: 0.14rem;
|
|
|
- color: #777777;
|
|
|
- line-height: 0.2rem;
|
|
|
- padding: 0.04rem 0.09rem 0.03rem;
|
|
|
- display: inline-flex;
|
|
|
- align-items: center;
|
|
|
-
|
|
|
- &.zanActive {
|
|
|
- background: #f7eeee;
|
|
|
- color: #ff6a6a;
|
|
|
- }
|
|
|
-
|
|
|
- .iconZan {
|
|
|
- width: 0.18rem;
|
|
|
- height: 0.18rem;
|
|
|
- margin-right: 0.01rem;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.musicSection {
|
|
|
- margin: 0 0.13rem 0.12rem;
|
|
|
- padding: 0.14rem 0.12rem;
|
|
|
- background: #ffffff;
|
|
|
- border-radius: 0.1rem;
|
|
|
-
|
|
|
- .musicName {
|
|
|
- font-size: 0.15rem;
|
|
|
- font-weight: 500;
|
|
|
- color: #333333;
|
|
|
- line-height: 0.21rem;
|
|
|
- // display: flex;
|
|
|
- // align-items: center;
|
|
|
- overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
- white-space: nowrap;
|
|
|
- max-width: 100%;
|
|
|
-
|
|
|
- .musicTag {
|
|
|
- margin-right: 0.06rem;
|
|
|
- padding: 0.01rem 0.06rem;
|
|
|
- font-size: 0.12rem;
|
|
|
- color: #ff7b31;
|
|
|
- line-height: 0.17rem;
|
|
|
- background: rgba(255, 166, 115, 0.07);
|
|
|
- border-radius: 0.09rem;
|
|
|
- border: 0.01rem solid #ffbf9a;
|
|
|
- font-weight: 400;
|
|
|
- vertical-align: text-bottom;
|
|
|
- display: inline-block;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .musicDesc {
|
|
|
- padding-top: 0.08rem;
|
|
|
- font-size: 0.14rem;
|
|
|
- color: #777777;
|
|
|
- line-height: 0.2rem;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.likeSection {
|
|
|
- margin: 0 0.13rem 0.12rem;
|
|
|
- background: #ffffff;
|
|
|
- border-radius: 0.1rem;
|
|
|
- padding: 0.1rem 0.12rem;
|
|
|
- margin-bottom: calc(0.77rem + env(safe-area-inset-bottom));
|
|
|
-
|
|
|
- .likeTitle {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- font-size: 0.17rem;
|
|
|
- font-weight: 600;
|
|
|
- color: #333333;
|
|
|
- line-height: 0.24rem;
|
|
|
- padding-bottom: 0.08rem;
|
|
|
-
|
|
|
- &::before {
|
|
|
- display: inline-block;
|
|
|
- content: "";
|
|
|
- width: 0.04rem;
|
|
|
- height: 0.14rem;
|
|
|
- border-radius: 0.01rem;
|
|
|
- background: linear-gradient(to bottom, #59e5d5, #2dc7aa);
|
|
|
- margin-right: 0.06rem;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.likeItem {
|
|
|
- padding: 0.16rem 0;
|
|
|
-
|
|
|
- .userLogo {
|
|
|
- border-radius: 50%;
|
|
|
- overflow: hidden;
|
|
|
- width: 0.42rem;
|
|
|
- height: 0.42rem;
|
|
|
- margin-right: 0.07rem;
|
|
|
- }
|
|
|
-
|
|
|
- .userInfo {
|
|
|
- .name {
|
|
|
- font-size: 0.16rem;
|
|
|
- font-weight: 500;
|
|
|
- color: #333333;
|
|
|
- line-height: 0.22rem;
|
|
|
- }
|
|
|
-
|
|
|
- .sub {
|
|
|
- padding-top: 0.01rem;
|
|
|
- font-size: 0.13rem;
|
|
|
- color: #777777;
|
|
|
- line-height: 0.18rem;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .time {
|
|
|
- font-size: 0.13rem;
|
|
|
- color: #777777;
|
|
|
- line-height: 0.18rem;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.bottomSection {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- background-color: #fff;
|
|
|
- padding: 0.15rem 0.12rem calc(0.15rem + env(safe-area-inset-bottom));
|
|
|
-
|
|
|
- .bottomShare {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
-
|
|
|
- p {
|
|
|
- padding: 0 0.15rem;
|
|
|
- text-align: center;
|
|
|
- line-height: 0;
|
|
|
-
|
|
|
- &:first-child {
|
|
|
- padding-left: 0.05rem;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- img {
|
|
|
- width: 0.18rem;
|
|
|
- height: 0.18rem;
|
|
|
- }
|
|
|
-
|
|
|
- span {
|
|
|
- padding-top: 0.08rem;
|
|
|
- font-size: 0.12rem;
|
|
|
- color: #333333;
|
|
|
- line-height: 0.17rem;
|
|
|
- display: block;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .btnEdit {
|
|
|
- font-size: 0.14rem;
|
|
|
- font-weight: 500;
|
|
|
- background: #2dc7aa;
|
|
|
- color: #ffffff;
|
|
|
- line-height: 0.22rem;
|
|
|
- min-width: 0.8rem;
|
|
|
- height: 0.3rem;
|
|
|
- border: none;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.popupContainer {
|
|
|
- width: 80%;
|
|
|
-
|
|
|
- .popupContent {
|
|
|
- padding: 0.29rem 0 0.25rem;
|
|
|
- text-align: center;
|
|
|
- font-size: 0.18rem;
|
|
|
- font-weight: 500;
|
|
|
- color: #333333;
|
|
|
- line-height: 0.25rem;
|
|
|
- }
|
|
|
-
|
|
|
- .popupBtnGroup {
|
|
|
- text-align: center;
|
|
|
- margin-bottom: 0.22rem;
|
|
|
-
|
|
|
- .van-button {
|
|
|
- height: 0.4rem;
|
|
|
- font-size: 0.16rem;
|
|
|
- font-weight: 400 !important;
|
|
|
- line-height: 0.22rem;
|
|
|
- min-width: 1.22rem;
|
|
|
-
|
|
|
- &:last-child {
|
|
|
- margin-left: 0.1rem;
|
|
|
- background: #2dc7aa;
|
|
|
- border: none;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.cellGroup {
|
|
|
- display: flex;
|
|
|
- flex-wrap: wrap;
|
|
|
-}
|
|
|
-
|
|
|
-.cell {
|
|
|
- // display: flex;
|
|
|
- // flex-direction: column;
|
|
|
- width: 0.96rem;
|
|
|
- margin-right: 0.18rem;
|
|
|
- margin-bottom: 0.18rem;
|
|
|
-
|
|
|
- &:nth-child(3n + 3) {
|
|
|
- margin-right: 0;
|
|
|
- }
|
|
|
-
|
|
|
- .cellImg {
|
|
|
- position: relative;
|
|
|
- width: 0.88rem;
|
|
|
- height: 0.88rem;
|
|
|
-
|
|
|
- &::before {
|
|
|
- content: "";
|
|
|
- position: absolute;
|
|
|
- right: -0.06rem;
|
|
|
- top: 0.03rem;
|
|
|
- z-index: 8;
|
|
|
- width: 0.84rem;
|
|
|
- height: 0.84rem;
|
|
|
- background: url("./img/audio-pan.png") no-repeat center;
|
|
|
- background-size: contain;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- }
|
|
|
-
|
|
|
- .iconZan {
|
|
|
- position: absolute;
|
|
|
- bottom: 0.04rem;
|
|
|
- left: 0.04rem;
|
|
|
- z-index: 10;
|
|
|
- padding: 0.03rem;
|
|
|
- background: rgba(67, 67, 67, 0.3);
|
|
|
- border-radius: 0.08rem;
|
|
|
- backdrop-filter: blur(0.04rem);
|
|
|
-
|
|
|
- font-size: 0.09rem;
|
|
|
- font-weight: 500;
|
|
|
- color: #ffffff;
|
|
|
- line-height: 0.13rem;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
-
|
|
|
- &::before {
|
|
|
- content: "";
|
|
|
- display: inline-block;
|
|
|
- width: 0.12rem;
|
|
|
- height: 0.12rem;
|
|
|
- background: url("./img/icon-z.png") no-repeat center;
|
|
|
- background-size: contain;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .cellImage {
|
|
|
- position: relative;
|
|
|
- width: 0.88rem;
|
|
|
- height: 0.88rem;
|
|
|
- border-radius: 0.12rem;
|
|
|
- overflow: hidden;
|
|
|
- z-index: 9;
|
|
|
-
|
|
|
- img {
|
|
|
- border-radius: 0.12rem;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .cellTitle {
|
|
|
- font-size: 0.13rem;
|
|
|
- color: #131415;
|
|
|
- line-height: 0.18rem;
|
|
|
- margin: 0.08rem 0 0.06rem;
|
|
|
- }
|
|
|
-
|
|
|
- .users {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
-
|
|
|
- .userImg {
|
|
|
- width: 0.2rem;
|
|
|
- height: 0.2rem;
|
|
|
- border-radius: 50%;
|
|
|
- overflow: hidden;
|
|
|
- margin-right: 0.04rem;
|
|
|
- flex-shrink: 0;
|
|
|
- }
|
|
|
-
|
|
|
- .name {
|
|
|
- font-size: 0.12rem;
|
|
|
- color: #402424;
|
|
|
- line-height: 0.14rem;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.sticky-section {
|
|
|
- position: fixed;
|
|
|
- bottom: 0;
|
|
|
- left: 0;
|
|
|
- right: 0;
|
|
|
-}
|
|
|
+@import url("./index.less");
|
|
|
</style>
|