feat(client-screen): 统一大屏页面标题和连接状态显示

- LiveVotingView/LuckyDrawView/VoteResultsView/LotteryResultsView 标题改用 displayStore.eventTitle
- 移除各页面右上角重复的连接状态指示器
- LuckyDrawView 保留"第X轮"显示在标题下方

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
empty
2026-02-04 17:23:21 +08:00
parent 71d82f80a4
commit c1b4b09e40
4 changed files with 43 additions and 154 deletions

View File

@@ -81,19 +81,19 @@ onUnmounted(() => {
<div class="live-voting-view">
<!-- 头部信息栏 -->
<header class="header">
<button class="back-btn" @click="goBack"> 返回</button>
<h1 class="title">实时投票</h1>
<div class="header-right">
<div class="header-left">
<div class="vote-counter">
<span class="counter-label">总票数</span>
<span class="counter-value">{{ formattedVotes }}</span>
</div>
</div>
<h1 class="title gold-text">{{ displayStore.eventTitle }}</h1>
<div class="header-right">
<div class="status">
<span class="status-badge" :class="{ open: votingOpen }">
{{ votingOpen ? '投票进行中' : '投票未开始' }}
</span>
<span class="online-count">{{ displayStore.onlineUsers }} 人在线</span>
<span class="connection-dot" :class="{ connected: displayStore.isConnected }"></span>
</div>
</div>
</header>
@@ -139,47 +139,22 @@ onUnmounted(() => {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 60px;
position: relative;
z-index: 100;
background: rgba(0, 0, 0, 0.2);
backdrop-filter: blur(10px);
border-bottom: 1px solid rgba($color-gold, 0.2);
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
flex-wrap: wrap;
gap: 20px;
.back-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba($color-gold, 0.5);
color: $color-gold;
padding: 10px 24px;
border-radius: 30px;
cursor: pointer;
font-size: 14px;
transition: all $transition-fast;
&:hover {
background: rgba($color-gold, 0.2);
transform: translateX(-4px);
}
}
padding: 30px 60px;
flex-shrink: 0;
z-index: 10;
.title {
font-size: 48px;
font-family: 'SimSun', 'Songti SC', serif;
font-weight: 800;
color: #fff;
letter-spacing: 12px;
margin: 0;
text-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
letter-spacing: 4px;
text-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.header-left,
.header-right {
display: flex;
align-items: center;
gap: 32px;
flex-wrap: wrap;
gap: 16px;
}
.vote-counter {
@@ -235,18 +210,6 @@ onUnmounted(() => {
font-size: 14px;
color: rgba(255, 255, 255, 0.7);
}
.connection-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: #475569;
&.connected {
background: #4ade80;
box-shadow: 0 0 10px #4ade80;
}
}
}
}

View File

@@ -2,9 +2,11 @@
import { computed, onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import { useAdminStore } from '../stores/admin';
import { useDisplayStore } from '../stores/display';
const router = useRouter();
const admin = useAdminStore();
const displayStore = useDisplayStore();
// Lottery results from API
const lotteryResults = ref<Array<{
@@ -19,12 +21,10 @@ function goBack() {
router.push('/');
}
// Fetch lottery results from API
// Fetch lottery results from public API (no auth required for screen)
async function fetchLotteryResults() {
try {
const res = await fetch('/api/admin/lottery/results', {
headers: { 'x-session-token': localStorage.getItem('gala_admin_token') || '' },
});
const res = await fetch('/api/public/lottery/results');
const data = await res.json();
if (data.success && data.data?.draws) {
lotteryResults.value = data.data.draws;
@@ -77,12 +77,9 @@ onMounted(() => {
<div class="lottery-results-view">
<!-- Header -->
<header class="header">
<button class="back-btn" @click="goBack"> 返回</button>
<h1 class="title gold-text">抽奖结果</h1>
<div class="status-indicator">
<span class="dot" :class="admin.isConnected ? 'online' : 'offline'"></span>
{{ admin.isConnected ? '已连接' : '连接中...' }}
</div>
<div class="header-placeholder"></div>
<h1 class="title gold-text">{{ displayStore.eventTitle }}</h1>
<div class="header-placeholder"></div>
</header>
<!-- Results display -->
@@ -200,30 +197,8 @@ onMounted(() => {
text-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.status-indicator {
display: flex;
align-items: center;
gap: 10px;
font-size: 14px;
color: rgba(255, 255, 255, 0.8);
background: rgba(0, 0, 0, 0.2);
padding: 8px 16px;
border-radius: 20px;
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
&.online {
background: #4ade80;
box-shadow: 0 0 12px #4ade80;
}
&.offline {
background: #94a3b8;
}
}
.header-placeholder {
width: 80px; // Balance the back button
}
}

View File

@@ -2,12 +2,14 @@
import { ref, onMounted, onUnmounted, nextTick, watch } from 'vue';
import { useRouter } from 'vue-router';
import { useSocketClient } from '../composables/useSocketClient';
import { useDisplayStore } from '../stores/display';
import { LotteryMachine, type Participant, type LotteryPhase } from '../pixi/LotteryMachine';
import type { AdminState } from '@gala/shared/types';
import { SOCKET_EVENTS } from '@gala/shared/constants';
const router = useRouter();
const { isConnected, onlineUsers, adminState, onAdminStateChange } = useSocketClient();
const displayStore = useDisplayStore();
// Pixi canvas ref
const canvasRef = ref<HTMLCanvasElement | null>(null);
@@ -287,21 +289,19 @@ onUnmounted(() => {
<div class="overlay-ui">
<!-- Header -->
<header class="header">
<button class="back-btn" @click="goBack"> 返回</button>
<div class="round-indicator">
<span class="round-label"> {{ currentRound }} </span>
<span v-if="currentRound === 4" class="filter-badge">🐴 马年限定</span>
</div>
<h1 class="title gold-text">{{ displayStore.eventTitle }}</h1>
<div class="status">
<span class="online-count">{{ onlineUsers }} 人在线</span>
<span class="connection-dot" :class="{ connected: isConnected }"></span>
</div>
</header>
<!-- Prize Display -->
<div class="prize-display" :class="{ hidden: currentPhase === 'storm' }">
<div class="prize-badge">
<span class="prize-level">{{ currentPrize.level }}</span>
<span class="prize-name">{{ currentPrize.name }}</span>
</div>
</div>
@@ -376,23 +376,14 @@ onUnmounted(() => {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30px 50px;
padding: 30px 60px;
background: linear-gradient(180deg, rgba(0, 0, 0, 0.5) 0%, transparent 100%);
.back-btn {
background: rgba(0, 0, 0, 0.3);
border: 1px solid $color-gold;
color: $color-gold;
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
transition: all $transition-fast;
backdrop-filter: blur(10px);
&:hover {
background: rgba($color-gold, 0.2);
}
.title {
font-size: 48px;
font-weight: 800;
letter-spacing: 4px;
text-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.round-indicator {
@@ -401,13 +392,15 @@ onUnmounted(() => {
gap: 12px;
.round-label {
font-size: 24px;
font-size: 36px;
color: $color-gold;
font-weight: bold;
text-shadow: $glow-gold;
letter-spacing: 2px;
}
.filter-badge {
padding: 6px 12px;
padding: 4px 10px;
background: rgba($color-gold, 0.2);
border: 1px solid $color-gold;
border-radius: 20px;
@@ -425,19 +418,6 @@ onUnmounted(() => {
color: $color-text-muted;
font-size: 18px;
}
.connection-dot {
width: 12px;
height: 12px;
border-radius: 50%;
background: #666;
transition: background 0.3s;
&.connected {
background: #4ade80;
box-shadow: 0 0 10px rgba(74, 222, 128, 0.5);
}
}
}
}
@@ -462,17 +442,11 @@ onUnmounted(() => {
border-radius: 16px;
backdrop-filter: blur(10px);
.prize-level {
font-size: 24px;
color: $color-gold;
margin-bottom: 8px;
text-shadow: $glow-gold;
}
.prize-name {
font-size: 36px;
color: $color-text-light;
font-size: 40px;
color: $color-gold;
font-weight: bold;
text-shadow: $glow-gold;
}
}
}

View File

@@ -2,10 +2,12 @@
import { computed, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { useAdminStore } from '../stores/admin';
import { useDisplayStore } from '../stores/display';
import { TICKET_TYPES } from '@gala/shared/constants';
const router = useRouter();
const admin = useAdminStore();
const displayStore = useDisplayStore();
function goBack() {
router.push('/');
@@ -80,12 +82,9 @@ onMounted(() => {
<div class="vote-results-view">
<!-- Header -->
<header class="header">
<button class="back-btn" @click="goBack"> 返回</button>
<h1 class="title gold-text">结果展示</h1>
<div class="status-indicator">
<span class="dot" :class="admin.isConnected ? 'online' : 'offline'"></span>
{{ admin.isConnected ? '已连接' : '连接中...' }}
</div>
<div class="header-placeholder"></div>
<h1 class="title gold-text">{{ displayStore.eventTitle }}</h1>
<div class="header-placeholder"></div>
</header>
<!-- Results grid - 7 award categories -->
@@ -180,30 +179,8 @@ onMounted(() => {
text-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.status-indicator {
display: flex;
align-items: center;
gap: 10px;
font-size: 14px;
color: rgba(255, 255, 255, 0.8);
background: rgba(0, 0, 0, 0.2);
padding: 8px 16px;
border-radius: 20px;
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
&.online {
background: #4ade80;
box-shadow: 0 0 12px #4ade80;
}
&.offline {
background: #94a3b8;
}
}
.header-placeholder {
width: 80px; // Balance the back button
}
}