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:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user