调整,音乐模块
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { toast } from 'vue-sonner'
|
||||
import { Cloud, Music2, MoreHorizontal, Play, Plus } from '@lucide/vue'
|
||||
import type { PlayableItem } from '@/stores/feiniuStore'
|
||||
import { useFeiniuStore } from '@/stores/feiniuStore'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
|
||||
const props = defineProps<{
|
||||
item: PlayableItem
|
||||
active?: boolean
|
||||
}>()
|
||||
|
||||
const store = useFeiniuStore()
|
||||
|
||||
const coverUrl = computed(() => {
|
||||
if (props.item.source === 'feiniu' && props.item.coverId && store.mediaPrefix) {
|
||||
return `${store.mediaPrefix}/cover?coverId=${encodeURIComponent(props.item.coverId)}&size=64`
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
const durationText = computed(() => store.fmtDuration(props.item.durationMs ? props.item.durationMs / 1000 : undefined))
|
||||
|
||||
function addToPlaylist(playlistId: string) {
|
||||
store.addToPlaylist(playlistId, [props.item])
|
||||
toast.success('已加入歌单')
|
||||
}
|
||||
|
||||
async function uploadToFeiniu() {
|
||||
try {
|
||||
await store.uploadLocalTrack(props.item)
|
||||
toast.success('已上传到飞牛曲库')
|
||||
} catch (e) {
|
||||
toast.error(String(e))
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="group flex items-center gap-3 rounded-lg border px-3 py-2 transition-colors"
|
||||
:class="active ? 'border-primary bg-primary/10' : 'border-border hover:bg-muted/40'"
|
||||
>
|
||||
<img
|
||||
v-if="coverUrl"
|
||||
:src="coverUrl"
|
||||
class="size-10 shrink-0 rounded-md object-cover"
|
||||
alt=""
|
||||
loading="lazy"
|
||||
@error="($event.target as HTMLImageElement).style.display = 'none'"
|
||||
/>
|
||||
<div v-else class="flex size-10 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground">
|
||||
<Music2 class="size-4" />
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="flex size-10 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground opacity-0 transition-opacity group-hover:opacity-100"
|
||||
:disabled="store.playing && store.current?.guid === item.guid"
|
||||
@click="store.playItem(item)"
|
||||
>
|
||||
<Play class="size-4 translate-x-[1px]" />
|
||||
</button>
|
||||
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="truncate text-sm font-medium">{{ item.title }}</div>
|
||||
<div class="truncate text-xs text-muted-foreground">
|
||||
{{ item.artistNames }}<template v-if="item.artistNames && item.album"> · </template>{{ item.album }}
|
||||
<span v-if="item.source === 'local'" class="ml-1 rounded bg-muted px-1 text-[10px]">本地</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="shrink-0 text-xs tabular-nums text-muted-foreground">{{ durationText }}</span>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<Button size="icon" variant="ghost" class="size-8">
|
||||
<MoreHorizontal class="size-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" class="w-48">
|
||||
<DropdownMenuLabel>{{ item.title }}</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem @click="store.playItem(item)">
|
||||
<Play class="size-4" /> 播放
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
v-if="item.source === 'local' && store.fnosLoggedIn && store.libraryNasPath"
|
||||
:disabled="store.uploading"
|
||||
@click="uploadToFeiniu"
|
||||
>
|
||||
<Cloud class="size-4" /> 上传到飞牛曲库
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<Plus class="size-4" /> 加入歌单
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent class="w-48 max-h-64 overflow-y-auto">
|
||||
<DropdownMenuItem v-if="store.playlists.length === 0" disabled>还没有歌单</DropdownMenuItem>
|
||||
<DropdownMenuItem v-for="p in store.playlists" :key="p.id" @click="addToPlaylist(p.id)">
|
||||
{{ p.name }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user