115 lines
4.5 KiB
Vue
115 lines
4.5 KiB
Vue
<template>
|
|
<div class="flex flex-col space-y-8 pb-12 lg:pb-20 animate-in fade-in slide-in-from-bottom-4 duration-500">
|
|
<div class="flex flex-col space-y-2">
|
|
<h2 class="text-2xl font-bold tracking-tight text-zinc-100">图片歌单</h2>
|
|
<p class="text-sm text-zinc-500">选择日期生成广播排期卡片并分享</p>
|
|
</div>
|
|
|
|
<div class="flex flex-col gap-8">
|
|
<!-- 设置面板 -->
|
|
<div class="w-full flex flex-col gap-6">
|
|
<div class="bg-zinc-900/40 border border-zinc-800 rounded-xl p-6 space-y-6 shadow-lg">
|
|
<h3 class="text-lg font-bold flex items-center gap-2 text-zinc-100 shrink-0">
|
|
<Layout class="w-4 h-4 text-blue-500" /> 卡片设置
|
|
</h3>
|
|
|
|
<div class="flex flex-col gap-5 items-end">
|
|
<!-- 日期选择 -->
|
|
<div class="space-y-2 flex-1 w-full">
|
|
<label class="text-[11px] font-black uppercase text-zinc-600 tracking-wider">排期日期</label>
|
|
|
|
<!-- 类似排期管理的日期选择器 -->
|
|
<AdminDatePicker
|
|
:modelValue="selectedDate"
|
|
@update:modelValue="selectedDate = $event"
|
|
@change="fetchSchedules"
|
|
/>
|
|
</div>
|
|
|
|
<button
|
|
:disabled="loading || schedules.length === 0"
|
|
class="w-full py-3 h-[54px] bg-blue-600 hover:bg-blue-500 text-white text-xs font-bold rounded-xl shadow-lg shadow-blue-900/20 transition-colors uppercase tracking-wider disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2 shrink-0"
|
|
@click="showModal = true"
|
|
>
|
|
<ImageIcon class="w-4 h-4" />
|
|
{{ loading ? '加载中...' : (schedules.length === 0 ? '该日期无排期' : '生成卡片') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 预览区 -->
|
|
<div class="w-full flex flex-col gap-4">
|
|
<div v-if="schedules.length > 0" class="bg-zinc-900/40 border border-zinc-800 rounded-xl p-6 shadow-lg">
|
|
<h3 class="text-lg font-bold text-zinc-100 mb-4">排期预览 ({{ schedules.length }} 首)</h3>
|
|
<div class="space-y-3">
|
|
<div v-for="(schedule, index) in schedules" :key="schedule.id" class="flex items-center gap-3 p-3 bg-zinc-950/50 border border-zinc-800/50 rounded-lg">
|
|
<span class="text-blue-500 font-bold w-6">{{ index + 1 }}.</span>
|
|
<div class="flex-1 overflow-hidden">
|
|
<p class="text-sm text-zinc-200 font-medium truncate">{{ schedule.song?.title || schedule.title }}</p>
|
|
<p class="text-xs text-zinc-500 truncate">{{ schedule.song?.artist || schedule.artist }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else-if="!loading" class="flex flex-col items-center justify-center py-20 bg-zinc-900/20 border border-zinc-800/50 rounded-xl border-dashed">
|
|
<CalendarDays class="w-12 h-12 text-zinc-700 mb-4" />
|
|
<p class="text-zinc-500">该日期没有排期的歌曲</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<AdminPlaylistCardGenerator
|
|
:show="showModal"
|
|
:songs="schedules"
|
|
:default-title="`${selectedDate} 校园广播歌单`"
|
|
@close="showModal = false"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted } from 'vue'
|
|
import { Layout, Image as ImageIcon, CalendarDays } from '@lucide/vue'
|
|
import AdminDatePicker from './AdminDatePicker.vue'
|
|
import AdminPlaylistCardGenerator from './PlaylistCardGenerator.vue'
|
|
import { useAuth } from '~/composables/useAuth'
|
|
|
|
const auth = useAuth()
|
|
|
|
const selectedDate = ref(new Date().toISOString().split('T')[0])
|
|
const schedules = ref([])
|
|
const loading = ref(false)
|
|
const showModal = ref(false)
|
|
|
|
const fetchSchedules = async () => {
|
|
loading.value = true
|
|
try {
|
|
const response = await $fetch('/api/admin/schedule/full', {
|
|
...auth.getAuthConfig(),
|
|
query: {
|
|
date: selectedDate.value,
|
|
includeDrafts: 'true'
|
|
}
|
|
})
|
|
if (response.success && response.data && response.data.schedules) {
|
|
schedules.value = response.data.schedules
|
|
} else {
|
|
schedules.value = []
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to fetch schedules:', error)
|
|
if (window.$showNotification) {
|
|
window.$showNotification('获取排期失败', 'error')
|
|
}
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
fetchSchedules()
|
|
})
|
|
|
|
</script>
|