diff --git a/packages/client-screen/src/App.vue b/packages/client-screen/src/App.vue index 907b474..8951b28 100644 --- a/packages/client-screen/src/App.vue +++ b/packages/client-screen/src/App.vue @@ -15,6 +15,7 @@ const modeRoutes: Record = { 'voting': '/screen/voting', 'draw': '/screen/draw', 'results': '/screen/results', + 'lottery_results': '/screen/lottery-results', }; // Unlock audio playback (required by browser autoplay policy) diff --git a/packages/client-screen/src/router/index.ts b/packages/client-screen/src/router/index.ts index e6c0221..bcb019f 100644 --- a/packages/client-screen/src/router/index.ts +++ b/packages/client-screen/src/router/index.ts @@ -51,6 +51,12 @@ const router = createRouter({ component: () => import('../views/VoteResultsView.vue'), meta: { title: '年会大屏 - 投票结果' }, }, + { + path: '/screen/lottery-results', + name: 'screen-lottery-results', + component: () => import('../views/LotteryResultsView.vue'), + meta: { title: '年会大屏 - 抽奖结果' }, + }, { path: '/screen/horse-race', name: 'screen-horse-race', diff --git a/packages/client-screen/src/stores/display.ts b/packages/client-screen/src/stores/display.ts index 02ba2e8..b3482df 100644 --- a/packages/client-screen/src/stores/display.ts +++ b/packages/client-screen/src/stores/display.ts @@ -30,7 +30,7 @@ export const useDisplayStore = defineStore('display', () => { const isConnected = ref(false); const isConnecting = ref(false); const onlineUsers = ref(0); - const currentMode = ref<'idle' | 'voting' | 'draw' | 'results'>('idle'); + const currentMode = ref<'idle' | 'voting' | 'draw' | 'results' | 'lottery_results'>('idle'); // Draw state const isDrawing = ref(false); @@ -131,11 +131,12 @@ export const useDisplayStore = defineStore('display', () => { console.log('[Screen] Admin state sync received:', state.systemPhase); // Map SystemPhase to display mode - const phaseToMode: Record = { + const phaseToMode: Record = { 'IDLE': 'idle', 'VOTING': 'voting', 'LOTTERY': 'draw', 'RESULTS': 'results', + 'LOTTERY_RESULTS': 'lottery_results', }; const newMode = phaseToMode[state.systemPhase] || 'idle'; diff --git a/packages/client-screen/src/views/LotteryResultsView.vue b/packages/client-screen/src/views/LotteryResultsView.vue new file mode 100644 index 0000000..4b34b78 --- /dev/null +++ b/packages/client-screen/src/views/LotteryResultsView.vue @@ -0,0 +1,483 @@ + + + + + diff --git a/packages/client-screen/src/views/VoteResultsView.vue b/packages/client-screen/src/views/VoteResultsView.vue index 867f0d0..d6476b0 100644 --- a/packages/client-screen/src/views/VoteResultsView.vue +++ b/packages/client-screen/src/views/VoteResultsView.vue @@ -16,6 +16,7 @@ const awardResults = computed(() => { const results: Array<{ awardType: string; awardName: string; + awardIcon: string; remark: string; programs: Array<{ id: string; name: string; teamName: string; votes: number; percentage: number }>; totalVotes: number; diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index 7b5cf45..124d2e8 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -20,7 +20,6 @@ model User { updatedAt DateTime @updatedAt @map("updated_at") votes Vote[] - drawResults DrawResult[] @@map("users") } @@ -82,14 +81,12 @@ model DrawResult { drawId String @map("draw_id") prizeLevel String @map("prize_level") @db.VarChar(20) prizeName String @map("prize_name") @db.VarChar(100) - winnerId String @map("winner_id") + winnerId String @map("winner_id") @db.VarChar(100) winnerName String @map("winner_name") @db.VarChar(100) winnerDepartment String @map("winner_department") @db.VarChar(100) drawnAt DateTime @default(now()) @map("drawn_at") drawnBy String @map("drawn_by") @db.VarChar(100) - winner User @relation(fields: [winnerId], references: [id]) - @@index([drawId]) @@index([prizeLevel]) @@index([winnerId]) diff --git a/packages/server/src/config/db.ts b/packages/server/src/config/db.ts new file mode 100644 index 0000000..7b4a7e7 --- /dev/null +++ b/packages/server/src/config/db.ts @@ -0,0 +1,51 @@ +/** + * Database configuration using Prisma Client + */ +import { PrismaClient } from '@prisma/client'; +import { logger } from '../utils/logger'; + +// Prisma Client instance with logging in development +export const prisma = new PrismaClient({ + log: process.env.NODE_ENV === 'development' + ? ['query', 'info', 'warn', 'error'] + : ['error'], +}); + +/** + * Connect to database + */ +export async function connectDatabase(): Promise { + try { + await prisma.$connect(); + logger.info('Database connected successfully'); + } catch (error) { + logger.error({ error }, 'Failed to connect to database'); + throw error; + } +} + +/** + * Disconnect from database + */ +export async function disconnectDatabase(): Promise { + try { + await prisma.$disconnect(); + logger.info('Database disconnected'); + } catch (error) { + logger.error({ error }, 'Error disconnecting from database'); + throw error; + } +} + +/** + * Health check for database connection + */ +export async function checkDatabaseHealth(): Promise { + try { + await prisma.$queryRaw`SELECT 1`; + return true; + } catch (error) { + logger.error({ error }, 'Database health check failed'); + return false; + } +} diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index d47c279..3cb542f 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -2,6 +2,7 @@ import { createServer } from 'http'; import { app, logger } from './app'; import { config } from './config'; import { connectRedis } from './config/redis'; +import { connectDatabase, disconnectDatabase } from './config/db'; import { initializeSocket } from './socket'; import { loadLuaScripts } from './services/vote.service'; import { loadVotingScripts } from './services/voting.engine'; @@ -11,6 +12,10 @@ import { participantService } from './services/participant.service'; async function main(): Promise { try { + // Connect to Database + logger.info('Connecting to Database...'); + await connectDatabase(); + // Connect to Redis logger.info('Connecting to Redis...'); await connectRedis(); @@ -50,6 +55,9 @@ async function main(): Promise { const shutdown = async (signal: string) => { logger.info({ signal }, 'Shutdown signal received'); + // Disconnect from database + await disconnectDatabase(); + httpServer.close(() => { logger.info('HTTP server closed'); process.exit(0); diff --git a/packages/shared/src/types/admin.types.ts b/packages/shared/src/types/admin.types.ts index 4bc4faa..733be70 100644 --- a/packages/shared/src/types/admin.types.ts +++ b/packages/shared/src/types/admin.types.ts @@ -4,7 +4,7 @@ // System Phase State Machine // ============================================================================ -export type SystemPhase = 'IDLE' | 'VOTING' | 'LOTTERY' | 'RESULTS'; +export type SystemPhase = 'IDLE' | 'VOTING' | 'LOTTERY' | 'RESULTS' | 'LOTTERY_RESULTS'; export type VotingSubPhase = 'CLOSED' | 'OPEN' | 'PAUSED';