From 35d77cbb22018cade0a831bfb4613932bc5c41c8 Mon Sep 17 00:00:00 2001 From: empty Date: Fri, 16 Jan 2026 15:57:52 +0800 Subject: [PATCH] feat: enhance AdminControl and VoteResultsView - Update AdminControl.vue with improved controls - Enhance VoteResultsView.vue with better display Co-Authored-By: Claude Opus 4.5 --- .../client-screen/src/views/AdminControl.vue | 360 ++++++++++++++++-- .../src/views/VoteResultsView.vue | 263 ++++++++++--- 2 files changed, 546 insertions(+), 77 deletions(-) diff --git a/packages/client-screen/src/views/AdminControl.vue b/packages/client-screen/src/views/AdminControl.vue index 50b23c8..e9ae27c 100644 --- a/packages/client-screen/src/views/AdminControl.vue +++ b/packages/client-screen/src/views/AdminControl.vue @@ -168,6 +168,58 @@ const lotteryPhaseLabel = computed(() => { } }); +// Award type labels +const awardLabels: Record = { + creative: '最佳创意奖', + visual: '最佳视觉奖', + atmosphere: '最佳气氛奖', + performance: '最佳表演奖', + teamwork: '最佳团队奖', + popularity: '最受欢迎奖', + potential: '最具潜力奖', +}; + +// Compute award statistics grouped by award type +const awardStats = computed(() => { + const stats: Record> = {}; + + // Initialize all award types + Object.keys(awardLabels).forEach(type => { + stats[type] = []; + }); + + // Aggregate stamps by award type + admin.programs.forEach(program => { + if (program.stamps && program.stamps.length > 0) { + // Count stamps by type for this program + const typeCount: Record = {}; + program.stamps.forEach((stamp: any) => { + const type = stamp.ticketType || 'unknown'; + typeCount[type] = (typeCount[type] || 0) + 1; + }); + + // Add to stats + Object.entries(typeCount).forEach(([type, count]) => { + if (stats[type]) { + stats[type].push({ + programId: program.id, + programName: program.name, + teamName: program.teamName, + votes: count, + }); + } + }); + } + }); + + // Sort each award type by votes descending + Object.keys(stats).forEach(type => { + stats[type].sort((a, b) => b.votes - a.votes); + }); + + return stats; +}); + // Lifecycle onMounted(() => { admin.connect(); @@ -259,30 +311,6 @@ onUnmounted(() => { - -
-
-

节目票数

- 共 {{ admin.programs.length }} 个节目 -
- -
- -
-
- {{ idx + 1 }} - {{ program.name }} - {{ program.teamName }} - {{ program.votes }} 票 -
-
-
-
-
@@ -1057,10 +1085,294 @@ $admin-danger: #ef4444; } } +// Award Statistics Styles +.award-stats { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 16px; +} + +.award-group { + background: rgba(255, 255, 255, 0.02); + border: 1px solid $admin-border; + border-radius: 8px; + overflow: hidden; +} + +.award-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 14px; + background: rgba(255, 255, 255, 0.03); + border-bottom: 1px solid $admin-border; + + .award-name { + font-size: 13px; + font-weight: 600; + color: $color-gold; + } + + .award-total { + font-size: 12px; + color: $admin-text-muted; + background: rgba($admin-primary, 0.15); + padding: 2px 8px; + border-radius: 4px; + } +} + +.award-programs { + padding: 8px; + max-height: 150px; + overflow-y: auto; +} + +.program-row { + display: grid; + grid-template-columns: 1fr auto auto; + gap: 8px; + align-items: center; + padding: 6px 8px; + border-radius: 4px; + font-size: 12px; + + &:hover { + background: rgba(255, 255, 255, 0.03); + } + + .program-name { + color: $admin-text; + font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .program-team { + color: $admin-text-muted; + font-size: 11px; + white-space: nowrap; + } + + .program-votes { + color: $admin-success; + font-weight: 600; + min-width: 24px; + text-align: right; + } +} + +.no-votes { + padding: 12px; + text-align: center; + color: $admin-text-muted; + font-size: 12px; + font-style: italic; +} + .modal-actions { display: flex; justify-content: flex-end; gap: 12px; margin-top: 20px; } + +// ========================================== +// Mobile Responsive Styles +// ========================================== +@media (max-width: 768px) { + // Header + .header { + flex-wrap: wrap; + gap: 12px; + padding: 12px 16px; + + .title { + font-size: 18px; + order: -1; + width: 100%; + text-align: center; + } + + .back-btn { + padding: 6px 12px; + font-size: 13px; + } + + .status-bar { + flex-wrap: wrap; + justify-content: center; + gap: 12px; + width: 100%; + } + + .status-item { + font-size: 13px; + } + } + + // Content Grid + .content { + grid-template-columns: 1fr; + padding: 16px; + gap: 16px; + } + + // Control Sections + .control-section { + &.lottery-section, + &.global-section { + grid-column: span 1; + } + } + + .section-header { + flex-wrap: wrap; + gap: 8px; + padding: 12px 16px; + + h2 { + font-size: 15px; + } + + .round-indicator { + gap: 8px; + } + } + + .section-body { + padding: 16px; + } + + // Stats + .stat-row { + gap: 16px; + margin-bottom: 16px; + } + + .stat-item { + .stat-value { + font-size: 24px; + } + } + + // Buttons + .button-group { + gap: 8px; + } + + .ctrl-btn { + padding: 10px 16px; + font-size: 13px; + flex: 1; + min-width: 100px; + text-align: center; + + &.large { + padding: 14px 24px; + font-size: 16px; + width: 100%; + } + } + + // Prize Info + .prize-info { + flex-wrap: wrap; + justify-content: center; + gap: 12px; + padding: 12px 16px; + text-align: center; + + .prize-level { + font-size: 18px; + width: 100%; + } + } + + // Lottery Controls + .lottery-controls { + padding: 16px 0; + } + + .complete-controls { + flex-direction: column; + gap: 12px; + width: 100%; + + .ctrl-btn { + width: 100%; + } + } + + // Winners + .winners-list { + gap: 8px; + } + + .winner-item { + padding: 6px 12px; + + .winner-name { + font-size: 14px; + } + } + + // Round Progress + .round-progress { + gap: 12px; + margin-top: 16px; + padding-top: 16px; + } + + .round-dot { + width: 28px; + height: 28px; + font-size: 12px; + } + + // Program List + .program-list { + max-height: 300px; + } + + .program-item { + padding: 8px 12px; + font-size: 13px; + } + + // Control Groups + .control-group { + margin-bottom: 20px; + + h4 { + font-size: 11px; + margin-bottom: 10px; + } + } + + // Modal + .modal { + width: 95vw; + padding: 20px; + + h3 { + font-size: 16px; + } + } + + .modal-input input { + padding: 10px; + font-size: 14px; + } + + .modal-actions { + flex-direction: column; + gap: 10px; + + .ctrl-btn { + width: 100%; + } + } +} diff --git a/packages/client-screen/src/views/VoteResultsView.vue b/packages/client-screen/src/views/VoteResultsView.vue index 27ab2fd..c29ac18 100644 --- a/packages/client-screen/src/views/VoteResultsView.vue +++ b/packages/client-screen/src/views/VoteResultsView.vue @@ -1,31 +1,85 @@