|
@@ -17,9 +17,9 @@
|
|
|
下方向键 - 音量减小<br />
|
|
下方向键 - 音量减小<br />
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
- <i class="tip-icon anticon anticon-bulb"></i>
|
|
|
|
|
|
|
+ <BulbOutlined class="tip-icon" />
|
|
|
</a-tooltip>
|
|
</a-tooltip>
|
|
|
- <i class="close-icon anticon anticon-close" title="关闭(Escape)" @click="handleClosePreview"></i>
|
|
|
|
|
|
|
+ <CloseOutlined class="close-icon" title="关闭(Escape)" @click="handleClosePreview" />
|
|
|
</div>
|
|
</div>
|
|
|
<audio
|
|
<audio
|
|
|
ref="audioRef"
|
|
ref="audioRef"
|
|
@@ -108,28 +108,28 @@
|
|
|
<!-- 底部音乐控件 -->
|
|
<!-- 底部音乐控件 -->
|
|
|
<div class="control-wrapper">
|
|
<div class="control-wrapper">
|
|
|
<div class="control-left">
|
|
<div class="control-left">
|
|
|
- <i
|
|
|
|
|
- class="operate-icon iconfont icon-shangyishou"
|
|
|
|
|
|
|
+ <StepBackwardOutlined
|
|
|
|
|
+ class="operate-icon"
|
|
|
title="上一个(按左方向键)"
|
|
title="上一个(按左方向键)"
|
|
|
@click="handleChangeAudioIndex('pre')"
|
|
@click="handleChangeAudioIndex('pre')"
|
|
|
- ></i>
|
|
|
|
|
- <i
|
|
|
|
|
- class="operate-icon play-icon iconfont icon-icon-7"
|
|
|
|
|
|
|
+ />
|
|
|
|
|
+ <PlayCircleOutlined
|
|
|
|
|
+ class="operate-icon play-icon"
|
|
|
v-show="!isPlay"
|
|
v-show="!isPlay"
|
|
|
title="播放(按空格键)"
|
|
title="播放(按空格键)"
|
|
|
@click="handleClickPlayIcon"
|
|
@click="handleClickPlayIcon"
|
|
|
- ></i>
|
|
|
|
|
- <i
|
|
|
|
|
- class="operate-icon pause-icon iconfont icon-icon-3"
|
|
|
|
|
|
|
+ />
|
|
|
|
|
+ <PauseCircleOutlined
|
|
|
|
|
+ class="operate-icon pause-icon"
|
|
|
v-show="isPlay"
|
|
v-show="isPlay"
|
|
|
title="暂停(按空格键)"
|
|
title="暂停(按空格键)"
|
|
|
@click="handleClickPauseIcon"
|
|
@click="handleClickPauseIcon"
|
|
|
- ></i>
|
|
|
|
|
- <i
|
|
|
|
|
- class="operate-icon iconfont icon-xiayishou"
|
|
|
|
|
|
|
+ />
|
|
|
|
|
+ <StepForwardOutlined
|
|
|
|
|
+ class="operate-icon"
|
|
|
title="下一个(按右方向键)"
|
|
title="下一个(按右方向键)"
|
|
|
@click="handleChangeAudioIndex('next')"
|
|
@click="handleChangeAudioIndex('next')"
|
|
|
- ></i>
|
|
|
|
|
|
|
+ />
|
|
|
<a-slider
|
|
<a-slider
|
|
|
class="progress-bar control-item"
|
|
class="progress-bar control-item"
|
|
|
v-model:value="currentTime"
|
|
v-model:value="currentTime"
|
|
@@ -145,22 +145,21 @@
|
|
|
>
|
|
>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="control-right">
|
|
<div class="control-right">
|
|
|
- <i
|
|
|
|
|
- class="operate-icon cycle-type iconfont"
|
|
|
|
|
- :class="cycleTypeMap[String(cycleType)].icon"
|
|
|
|
|
|
|
+ <ReloadOutlined
|
|
|
|
|
+ class="operate-icon cycle-type"
|
|
|
:title="cycleTypeMap[String(cycleType)].text"
|
|
:title="cycleTypeMap[String(cycleType)].text"
|
|
|
@click="handleChangeCycleType"
|
|
@click="handleChangeCycleType"
|
|
|
- ></i>
|
|
|
|
|
|
|
+ />
|
|
|
<a
|
|
<a
|
|
|
class="operate-icon download-link"
|
|
class="operate-icon download-link"
|
|
|
:href="$file.getDownloadFilePath(activeFileObj)"
|
|
:href="$file.getDownloadFilePath(activeFileObj)"
|
|
|
target="_blank"
|
|
target="_blank"
|
|
|
title="下载"
|
|
title="下载"
|
|
|
>
|
|
>
|
|
|
- <i class="download-icon anticon anticon-download"></i>
|
|
|
|
|
|
|
+ <DownloadOutlined class="download-icon" />
|
|
|
</a>
|
|
</a>
|
|
|
- <i
|
|
|
|
|
- class="operate-icon share-icon anticon anticon-share-alt"
|
|
|
|
|
|
|
+ <ShareAltOutlined
|
|
|
|
|
+ class="operate-icon share-icon"
|
|
|
title="分享"
|
|
title="分享"
|
|
|
@click.stop="
|
|
@click.stop="
|
|
|
$openDialog.shareFile({
|
|
$openDialog.shareFile({
|
|
@@ -171,12 +170,13 @@
|
|
|
]
|
|
]
|
|
|
})
|
|
})
|
|
|
"
|
|
"
|
|
|
- ></i>
|
|
|
|
|
- <i
|
|
|
|
|
- class="operate-icon volume-icon control-item iconfont"
|
|
|
|
|
- :class="volume === 0 ? 'icon-jingyin01' : 'icon-yinliang101'"
|
|
|
|
|
- @click="handleClickVolumeIcon"
|
|
|
|
|
- ></i>
|
|
|
|
|
|
|
+ />
|
|
|
|
|
+ <template v-if="volume === 0">
|
|
|
|
|
+ <AudioMutedOutlined class="operate-icon volume-icon control-item" @click="handleClickVolumeIcon" />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <template v-else>
|
|
|
|
|
+ <SoundOutlined class="operate-icon volume-icon control-item" @click="handleClickVolumeIcon" />
|
|
|
|
|
+ </template>
|
|
|
<a-slider
|
|
<a-slider
|
|
|
class="volume-bar control-item"
|
|
class="volume-bar control-item"
|
|
|
v-model:value="volume"
|
|
v-model:value="volume"
|
|
@@ -198,7 +198,19 @@
|
|
|
import { Base64 } from 'js-base64'
|
|
import { Base64 } from 'js-base64'
|
|
|
import waveGif from '@/assets/images/myResource/audio/wave.gif'
|
|
import waveGif from '@/assets/images/myResource/audio/wave.gif'
|
|
|
import musicImg from '@/assets/images/myResource/file/file_music.png'
|
|
import musicImg from '@/assets/images/myResource/file/file_music.png'
|
|
|
-
|
|
|
|
|
|
|
+ import {
|
|
|
|
|
+ BulbOutlined,
|
|
|
|
|
+ CloseOutlined,
|
|
|
|
|
+ StepBackwardOutlined,
|
|
|
|
|
+ PlayCircleOutlined,
|
|
|
|
|
+ PauseCircleOutlined,
|
|
|
|
|
+ StepForwardOutlined,
|
|
|
|
|
+ ReloadOutlined,
|
|
|
|
|
+ DownloadOutlined,
|
|
|
|
|
+ ShareAltOutlined,
|
|
|
|
|
+ SoundOutlined,
|
|
|
|
|
+ AudioMutedOutlined
|
|
|
|
|
+ } from '@ant-design/icons-vue'
|
|
|
const { proxy } = getCurrentInstance()
|
|
const { proxy } = getCurrentInstance()
|
|
|
|
|
|
|
|
// 定义响应式数据
|
|
// 定义响应式数据
|
|
@@ -352,22 +364,40 @@
|
|
|
...res.data.music,
|
|
...res.data.music,
|
|
|
duration: res.data.music.trackLength
|
|
duration: res.data.music.trackLength
|
|
|
}
|
|
}
|
|
|
|
|
+ if (!audioInfo.value.lyrics) {
|
|
|
|
|
+ lyricsList.value = []
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
// Base64 解码为 lrc 格式的歌词文件
|
|
// Base64 解码为 lrc 格式的歌词文件
|
|
|
let lyricsStr = Base64.decode(audioInfo.value.lyrics)
|
|
let lyricsStr = Base64.decode(audioInfo.value.lyrics)
|
|
|
if (lyricsStr.includes('[offset:0]')) {
|
|
if (lyricsStr.includes('[offset:0]')) {
|
|
|
// 有歌词,从标志位 [offset:0] 下一行开始截取
|
|
// 有歌词,从标志位 [offset:0] 下一行开始截取
|
|
|
- lyricsStr = lyricsStr.split('[offset:0]\n')[1]
|
|
|
|
|
|
|
+ lyricsStr = lyricsStr.split('[offset:0]')[1]
|
|
|
}
|
|
}
|
|
|
lyricsList.value = lyricsStr
|
|
lyricsList.value = lyricsStr
|
|
|
.split('\n')
|
|
.split('\n')
|
|
|
- .map((item) => {
|
|
|
|
|
- const line = item.split('[')[1].split(']')
|
|
|
|
|
- return {
|
|
|
|
|
- time: line[0], // 当前行歌词开始播放的秒数
|
|
|
|
|
- text: line[1] // 当前歌词文本
|
|
|
|
|
|
|
+ .map((item, index) => {
|
|
|
|
|
+ // 检查行是否包含 [ 和 ] 字符
|
|
|
|
|
+ if (item && item.includes('[') && item.includes(']')) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const parts = item.split('[')
|
|
|
|
|
+ if (parts.length > 1) {
|
|
|
|
|
+ const line = parts[1].split(']')
|
|
|
|
|
+ if (line.length > 1) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ time: line[0], // 当前行歌词开始播放的秒数
|
|
|
|
|
+ text: line[1].trim() // 当前歌词文本
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('解析歌词行出错:', item, error)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ // 如果解析失败或格式不符合要求,返回null
|
|
|
|
|
+ return null
|
|
|
})
|
|
})
|
|
|
- .filter((item) => item.text !== '')
|
|
|
|
|
|
|
+ .filter((item) => item !== null && item.text !== '')
|
|
|
lyricsList.value = lyricsList.value.map((item, index) => {
|
|
lyricsList.value = lyricsList.value.map((item, index) => {
|
|
|
return {
|
|
return {
|
|
|
...item,
|
|
...item,
|
|
@@ -516,7 +546,7 @@
|
|
|
case 3: {
|
|
case 3: {
|
|
|
let newActiveIndex = 0
|
|
let newActiveIndex = 0
|
|
|
do {
|
|
do {
|
|
|
- newActiveIndex = Math.floor(Math.random() * (props.audioList.value.length - 1)) + 1
|
|
|
|
|
|
|
+ newActiveIndex = Math.floor(Math.random() * (props.audioList.length - 1)) + 1
|
|
|
} while (activeIndex.value === newActiveIndex)
|
|
} while (activeIndex.value === newActiveIndex)
|
|
|
activeIndex.value = newActiveIndex
|
|
activeIndex.value = newActiveIndex
|
|
|
break
|
|
break
|
|
@@ -524,12 +554,12 @@
|
|
|
default: {
|
|
default: {
|
|
|
if (type === 'pre') {
|
|
if (type === 'pre') {
|
|
|
if (activeIndex.value === 0) {
|
|
if (activeIndex.value === 0) {
|
|
|
- activeIndex.value = props.audioList.value.length - 1
|
|
|
|
|
|
|
+ activeIndex.value = props.audioList.length - 1
|
|
|
} else {
|
|
} else {
|
|
|
activeIndex.value--
|
|
activeIndex.value--
|
|
|
}
|
|
}
|
|
|
} else if (type === 'next') {
|
|
} else if (type === 'next') {
|
|
|
- if (activeIndex.value === props.audioList.value.length - 1) {
|
|
|
|
|
|
|
+ if (activeIndex.value === props.audioList.length - 1) {
|
|
|
activeIndex.value = 0
|
|
activeIndex.value = 0
|
|
|
} else {
|
|
} else {
|
|
|
activeIndex.value++
|
|
activeIndex.value++
|
|
@@ -561,7 +591,7 @@
|
|
|
*/
|
|
*/
|
|
|
function handleClosePreview() {
|
|
function handleClosePreview() {
|
|
|
visible.value = false
|
|
visible.value = false
|
|
|
- callback('cancel')
|
|
|
|
|
|
|
+ props.callback('cancel')
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 暴露给父组件的方法和属性
|
|
// 暴露给父组件的方法和属性
|