feat: add vue-toast-notification for user feedback and implement queue management in TrackItem component
This commit is contained in:
parent
7f86c8bfa9
commit
c6868ed2a2
13
package-lock.json
generated
13
package-lock.json
generated
|
@ -15,6 +15,7 @@
|
||||||
"tailwindcss": "^4.1.7",
|
"tailwindcss": "^4.1.7",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "^4.5.1",
|
"vue-router": "^4.5.1",
|
||||||
|
"vue-toast-notification": "^3.1.3",
|
||||||
"webextension-polyfill": "^0.12.0"
|
"webextension-polyfill": "^0.12.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -2675,6 +2676,18 @@
|
||||||
"vue": "^3.2.0"
|
"vue": "^3.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-toast-notification": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-toast-notification/-/vue-toast-notification-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-XNyWqwLIGBFfX5G9sK+clq3N3IPlhDjzNdbZaXkEElcotPlWs0wWZailk1vqhdtLYT/93Y4FHAVuzyatLmPZRA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.15.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vue-tsc": {
|
"node_modules/vue-tsc": {
|
||||||
"version": "2.2.10",
|
"version": "2.2.10",
|
||||||
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.2.10.tgz",
|
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.2.10.tgz",
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
"tailwindcss": "^4.1.7",
|
"tailwindcss": "^4.1.7",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "^4.5.1",
|
"vue-router": "^4.5.1",
|
||||||
|
"vue-toast-notification": "^3.1.3",
|
||||||
"webextension-polyfill": "^0.12.0"
|
"webextension-polyfill": "^0.12.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
11
src/assets/icons/queueadd.vue
Normal file
11
src/assets/icons/queueadd.vue
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{
|
||||||
|
size: number
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" :class="`w-${size} h-${size}`">
|
||||||
|
<path d="M2 18H12V20H2V18ZM2 11H22V13H2V11ZM2 4H22V6H2V4ZM18 18V15H20V18H23V20H20V23H18V20H15V18H18Z"></path>
|
||||||
|
</svg>
|
||||||
|
</template>
|
|
@ -131,6 +131,7 @@ function playTheAlbum(from: number = 0) {
|
||||||
playQueue.isPlaying = true
|
playQueue.isPlaying = true
|
||||||
playQueue.isBuffering = true
|
playQueue.isBuffering = true
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -180,7 +180,6 @@ function updateCurrentTime() {
|
||||||
const remainingTimeThreshold = config.remainingTimeThreshold || 30
|
const remainingTimeThreshold = config.remainingTimeThreshold || 30
|
||||||
|
|
||||||
if ((progress > preloadTrigger || remainingTime < remainingTimeThreshold) && !playQueueStore.isPreloading) {
|
if ((progress > preloadTrigger || remainingTime < remainingTimeThreshold) && !playQueueStore.isPreloading) {
|
||||||
console.log(`[Player] 触发预加载 - 进度: ${Math.round(progress * 100)}%, 剩余: ${Math.round(remainingTime)}s`)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeof playQueueStore.preloadNext === 'function') {
|
if (typeof playQueueStore.preloadNext === 'function') {
|
||||||
|
|
|
@ -1,18 +1,44 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { artistsOrganize } from '../utils'
|
import { artistsOrganize } from '../utils'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { usePlayQueueStore } from '../stores/usePlayQueueStore'
|
||||||
|
import { useToast } from 'vue-toast-notification'
|
||||||
|
|
||||||
defineProps<{
|
import QueueAddIcon from '../assets/icons/queueadd.vue'
|
||||||
|
import StarEmptyIcon from '../assets/icons/starempty.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
album?: Album,
|
album?: Album,
|
||||||
track: Song,
|
track: Song,
|
||||||
index: number,
|
index: number,
|
||||||
playfrom: (index: number) => void,
|
playfrom: (index: number) => void,
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const hover = ref(false)
|
||||||
|
|
||||||
|
const playQueueStore = usePlayQueueStore()
|
||||||
|
const toast = useToast()
|
||||||
|
|
||||||
|
function appendToQueue() {
|
||||||
|
console.log('aaa')
|
||||||
|
let queue = playQueueStore.list
|
||||||
|
queue.push({
|
||||||
|
song: props.track,
|
||||||
|
album: props.album,
|
||||||
|
} as QueueItem)
|
||||||
|
playQueueStore.list = queue
|
||||||
|
playQueueStore.queueReplaceLock = true
|
||||||
|
toast.success('已添加到队列末尾', {
|
||||||
|
position: 'top-right',
|
||||||
|
duration: 500,
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<button
|
<button
|
||||||
class="flex align-center gap-4 text-left px-2 h-[2.75rem] hover:bg-neutral-600/40 odd:bg-netural-600/20 align-center relative overflow-hidden bg-neutral-800/20 odd:bg-neutral-800/40 transition-all"
|
class="flex justify-between align-center gap-4 text-left px-2 h-[2.75rem] hover:bg-neutral-600/40 odd:bg-netural-600/20 relative overflow-hidden bg-neutral-800/20 odd:bg-neutral-800/40 transition-all"
|
||||||
@click="playfrom(index)">
|
@click="playfrom(index)" @mouseenter="() => { hover = true; console.log('aaa') }" @mouseleave="hover = false">
|
||||||
|
|
||||||
<span class="text-[3.7rem] text-white/10 absolute left-0 top-[-1.4rem] track_num">{{ index + 1 }}</span>
|
<span class="text-[3.7rem] text-white/10 absolute left-0 top-[-1.4rem] track_num">{{ index + 1 }}</span>
|
||||||
|
|
||||||
|
@ -24,6 +50,16 @@ defineProps<{
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center justify-center gap-2" v-if="hover">
|
||||||
|
<button @click.stop="appendToQueue"
|
||||||
|
class="hover:scale-110 transition-all text-white/50 hover:text-white active:text-white/40 active:scale-95">
|
||||||
|
<QueueAddIcon :size="4" />
|
||||||
|
</button>
|
||||||
|
<button @click.stop=""
|
||||||
|
class="hover:scale-110 transition-all text-white/50 hover:text-white active:text-white/40 active:scale-95">
|
||||||
|
<StarEmptyIcon :size="4" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
|
@ -2,6 +2,8 @@ import { createApp } from 'vue'
|
||||||
import { createWebHashHistory, createRouter } from 'vue-router'
|
import { createWebHashHistory, createRouter } from 'vue-router'
|
||||||
import './style.css'
|
import './style.css'
|
||||||
import { createPinia } from 'pinia'
|
import { createPinia } from 'pinia'
|
||||||
|
import ToastPlugin from 'vue-toast-notification'
|
||||||
|
import 'vue-toast-notification/dist/theme-default.css'
|
||||||
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import HomePage from './pages/Home.vue'
|
import HomePage from './pages/Home.vue'
|
||||||
|
@ -21,5 +23,5 @@ const router = createRouter({
|
||||||
|
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
|
|
||||||
createApp(App).use(router).use(pinia).mount('#app')
|
createApp(App).use(router).use(pinia).use(ToastPlugin).mount('#app')
|
||||||
|
|
||||||
|
|
|
@ -55,11 +55,9 @@ export const usePlayQueueStore = defineStore('queue', () => {
|
||||||
|
|
||||||
// 预加载下一首歌
|
// 预加载下一首歌
|
||||||
const preloadNext = async () => {
|
const preloadNext = async () => {
|
||||||
console.log('[Store] preloadNext 被调用')
|
|
||||||
|
|
||||||
const nextIndex = getNextIndex.value
|
const nextIndex = getNextIndex.value
|
||||||
if (nextIndex === -1) {
|
if (nextIndex === -1) {
|
||||||
console.log('[Store] 没有下一首歌,跳过预加载')
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +70,6 @@ export const usePlayQueueStore = defineStore('queue', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nextSong || !nextSong.song) {
|
if (!nextSong || !nextSong.song) {
|
||||||
console.log('[Store] 下一首歌曲不存在,跳过预加载')
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +77,6 @@ export const usePlayQueueStore = defineStore('queue', () => {
|
||||||
|
|
||||||
// 如果已经预加载过,跳过
|
// 如果已经预加载过,跳过
|
||||||
if (preloadedAudio.value.has(songId)) {
|
if (preloadedAudio.value.has(songId)) {
|
||||||
console.log(`[Store] 歌曲 ${songId} 已预加载`)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,8 +152,8 @@ export const usePlayQueueStore = defineStore('queue', () => {
|
||||||
const limitPreloadCache = () => {
|
const limitPreloadCache = () => {
|
||||||
while (preloadedAudio.value.size > 3) {
|
while (preloadedAudio.value.size > 3) {
|
||||||
const oldestKey = preloadedAudio.value.keys().next().value
|
const oldestKey = preloadedAudio.value.keys().next().value
|
||||||
if (oldestKey) {
|
if (oldestKey) {
|
||||||
clearPreloadedAudio(oldestKey)
|
clearPreloadedAudio(oldestKey)
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user