Files
BYW-VoiceHub/app/components/Admin/ScheduleItemPrint.vue
T
Henry_Du 1106aeea6c feat: 迁移自定义功能至 1.5.9.9 版本
包含音乐源限制、CI 防 OOM 优化、数据库连接池优化、管理端权限及 UI 细节定制等功能
2026-09-12 19:26:42 +08:00

329 lines
6.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="schedule-item-print">
<div class="item-content">
<!-- 序号 -->
<div v-if="settings.showSequence" class="sequence-number">
{{ schedule.sequence || 1 }}
</div>
<!-- 歌曲封面 -->
<div v-if="settings.showCover" class="cover-section aspect-square">
<img
v-if="schedule.song.cover"
:alt="schedule.song.title"
:src="convertToHttps(schedule.song.cover)"
class="song-cover object-cover"
referrerpolicy="no-referrer"
@error="handleImageError"
>
<div class="cover-placeholder object-contain" :class="{ 'show': !schedule.song.cover }">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="3" />
<path d="M12 1v6m0 6v6" />
<path d="m21 12-6-3-6 3-6-3" />
</svg>
</div>
</div>
<!-- 歌曲信息 -->
<div class="song-info">
<div v-if="settings.showTitle" class="song-title">
{{ schedule.song.title }}
<!-- 重播标识 -->
<span v-if="schedule.song.replayRequestCount > 0" class="replay-badge-print"> 重播 </span>
</div>
<div v-if="settings.showArtist" class="song-artist">
{{ schedule.song.artist }}
</div>
</div>
<!-- 投稿人信息(重播歌曲不显示申请人,只显示原投稿人) -->
<div v-if="settings.showRequester" class="requester-info">
<span class="label">投稿人:</span>
<span class="value">
{{ schedule.song.requester }}
<span v-if="schedule.song.collaborators && schedule.song.collaborators.length > 0">
& {{ schedule.song.collaborators.map((c) => c.displayName || c.name).join(' & ') }}
</span>
</span>
</div>
<!-- 人数信息 -->
<div v-if="settings.showVotes" class="votes-info">
<span v-if="schedule.song.replayRequestCount > 0" class="label">申请重播:</span>
<span v-else class="label">热度:</span>
<span class="value">{{
schedule.song.replayRequestCount > 0
? schedule.song.replayRequestCount + '人'
: schedule.song.voteCount || 0
}}</span>
</div>
</div>
</div>
</template>
<script setup>
import { defineProps } from 'vue'
import { convertToHttps } from '~/utils/url'
// 定义props
defineProps({
schedule: {
type: Object,
required: true
},
settings: {
type: Object,
required: true
}
})
// 处理图片加载错误
const handleImageError = (event) => {
event.target.style.display = 'none'
event.target.nextElementSibling?.classList.add('show')
}
</script>
<style scoped>
.schedule-item-print {
display: flex;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #e5e5e5;
page-break-inside: avoid;
}
.item-content {
display: flex;
align-items: center;
width: 100%;
gap: 12px;
}
.sequence-number {
width: 30px;
height: 30px;
background: #f0f0f0;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 14px;
color: var(--text-quaternary, #333333);
flex-shrink: 0;
}
.cover-section {
width: 40px;
height: 40px;
aspect-ratio: 1 / 1;
flex-shrink: 0;
}
.song-cover {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.cover-placeholder {
width: 100%;
height: 100%;
aspect-ratio: 1 / 1;
object-fit: contain;
background: #f5f5f5;
border-radius: 4px;
display: none;
align-items: center;
justify-content: center;
color: var(--text-tertiary, #999999);
}
.cover-placeholder.show {
display: flex;
}
.cover-placeholder svg {
width: 20px;
height: 20px;
}
.song-info {
flex: 1;
min-width: 0;
}
.song-title {
font-weight: bold;
font-size: 16px;
color: var(--text-quaternary, #333333);
margin-bottom: 2px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: flex;
align-items: center;
gap: 4px;
}
/* 打印用重播标识 */
.replay-badge-print {
display: inline-block;
padding: 1px 4px;
background: #e3f2fd;
border: 1px solid var(--border-secondary, #2196f3);
border-radius: 3px;
color: #1976d2;
font-size: 10px;
font-weight: bold;
flex-shrink: 0;
}
.song-artist {
font-size: 14px;
color: var(--text-quaternary, #666666);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.requester-info,
.votes-info {
display: flex;
align-items: center;
font-size: 12px;
color: var(--text-quaternary, #666666);
white-space: nowrap;
}
.label {
font-weight: 500;
margin-right: 4px;
}
.value {
color: var(--text-quaternary, #333333);
}
/* 打印样式 */
@media print {
.schedule-item-print {
color: var(--text-primary, #000) !important;
background: var(--card-bg, #fff) !important;
width: 100% !important;
max-width: none !important;
box-sizing: border-box !important;
}
.item-content {
display: flex !important;
flex-direction: row !important;
align-items: center !important;
width: 100% !important;
gap: 12px !important;
}
.sequence-number {
background: #f0f0f0 !important;
color: var(--text-primary, #000) !important;
width: 30px !important;
height: 30px !important;
flex-shrink: 0 !important;
}
.cover-section {
width: 48px !important;
height: 48px !important;
aspect-ratio: 1 / 1 !important;
flex-shrink: 0 !important;
}
.song-cover {
width: 100% !important;
height: 100% !important;
object-fit: contain !important;
border-radius: 0 !important;
box-shadow: none !important;
}
.cover-placeholder {
width: 100% !important;
height: 100% !important;
object-fit: contain !important;
border-radius: 0 !important;
}
.song-info {
flex: 1 !important;
min-width: 0 !important;
}
.song-title {
color: var(--text-primary, #000) !important;
font-size: 16px !important;
white-space: nowrap !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
}
.song-artist,
.label,
.value {
color: var(--text-quaternary, #333333) !important;
}
.time-range {
color: var(--text-quaternary, #666666) !important;
}
.requester-info,
.votes-info,
.playtime-info {
display: flex !important;
align-items: center !important;
font-size: 12px !important;
white-space: nowrap !important;
flex-shrink: 0 !important;
}
}
/* 紧凑模式 */
.compact .schedule-item-print {
padding: 4px 0;
}
.compact .item-content {
gap: 8px;
}
.compact .sequence-number {
width: 24px;
height: 24px;
font-size: 12px;
}
.compact .cover-section {
width: 32px;
height: 32px;
}
.compact .song-title {
font-size: 14px;
}
.compact .song-artist {
font-size: 12px;
}
.compact .requester-info,
.compact .votes-info,
.compact .playtime-info {
font-size: 11px;
}
</style>