feat: redesign Big Screen voting view with philatelic postcard UI
- Add PostcardItem.vue component with Chinese postal aesthetics - Add PostcardGrid.vue container with 4x2 CSS Grid layout - Add Postmark.vue component for real-time vote stamp visualization - Update LiveVotingView.vue with cream paper theme (#FDFBF7) - Add Year of the Horse 2026 stamp image - Add responsive breakpoints for different screen sizes - Enhance admin service with program voting control - Add vote stamp accumulation for big screen display Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,36 @@ export interface VotingState {
|
||||
openedAt?: number;
|
||||
closedAt?: number;
|
||||
totalVotes: number;
|
||||
// 节目投票控制
|
||||
currentProgramId: string | null; // 当前投票节目 ID
|
||||
currentProgramIndex: number; // 当前节目序号 (0-based index)
|
||||
programs: VotingProgram[]; // 节目列表(已排序)
|
||||
allowLateCatch: boolean; // 补投票开关(默认 true)
|
||||
votingStartedAt?: number; // 当前节目投票开始时间(用于计时)
|
||||
}
|
||||
|
||||
export type ProgramVotingStatus = 'pending' | 'voting' | 'completed';
|
||||
|
||||
export interface VotingProgram {
|
||||
id: string;
|
||||
name: string;
|
||||
teamName: string;
|
||||
order: number; // 初始顺序
|
||||
status: ProgramVotingStatus; // 投票状态
|
||||
votes: number; // 票数
|
||||
stamps: VoteStamp[]; // 已盖的戳(用于大屏展示)
|
||||
}
|
||||
|
||||
export interface VoteStamp {
|
||||
id: string;
|
||||
userName: string;
|
||||
department: string;
|
||||
ticketType: string;
|
||||
x: number; // 随机 X 位置 (0-100%)
|
||||
y: number; // 随机 Y 位置 (0-100%)
|
||||
rotation: number; // 随机旋转角度
|
||||
timestamp: number;
|
||||
date: string; // 格式化日期 YYYY.MM.DD
|
||||
}
|
||||
|
||||
export interface LotteryState {
|
||||
@@ -116,6 +146,18 @@ export const PRIZE_CONFIG: PrizeConfig[] = [
|
||||
{ round: 4, level: '三等奖', name: '京东卡 500元', winnerCount: 10, zodiacFilter: 'horse' },
|
||||
];
|
||||
|
||||
// Default programs for voting
|
||||
export const DEFAULT_PROGRAMS: VotingProgram[] = [
|
||||
{ id: 'p1', name: '龙腾四海', teamName: '市场部', order: 1, status: 'pending', votes: 0, stamps: [] },
|
||||
{ id: 'p2', name: '金马奔腾', teamName: '技术部', order: 2, status: 'pending', votes: 0, stamps: [] },
|
||||
{ id: 'p3', name: '春风得意', teamName: '人力资源部', order: 3, status: 'pending', votes: 0, stamps: [] },
|
||||
{ id: 'p4', name: '鸿运当头', teamName: '财务部', order: 4, status: 'pending', votes: 0, stamps: [] },
|
||||
{ id: 'p5', name: '马到成功', teamName: '运营部', order: 5, status: 'pending', votes: 0, stamps: [] },
|
||||
{ id: 'p6', name: '一马当先', teamName: '产品部', order: 6, status: 'pending', votes: 0, stamps: [] },
|
||||
{ id: 'p7', name: '万马奔腾', teamName: '设计部', order: 7, status: 'pending', votes: 0, stamps: [] },
|
||||
{ id: 'p8', name: '龙马精神', teamName: '销售部', order: 8, status: 'pending', votes: 0, stamps: [] },
|
||||
];
|
||||
|
||||
// ============================================================================
|
||||
// Initial State
|
||||
// ============================================================================
|
||||
@@ -125,6 +167,10 @@ export const INITIAL_ADMIN_STATE: AdminState = {
|
||||
voting: {
|
||||
subPhase: 'CLOSED',
|
||||
totalVotes: 0,
|
||||
currentProgramId: null,
|
||||
currentProgramIndex: -1,
|
||||
programs: DEFAULT_PROGRAMS,
|
||||
allowLateCatch: true,
|
||||
},
|
||||
lottery: {
|
||||
round: 1,
|
||||
|
||||
@@ -82,6 +82,7 @@ export interface DrawFilters {
|
||||
export interface JoinPayload {
|
||||
userId: string;
|
||||
userName: string;
|
||||
department?: string;
|
||||
role: UserRole;
|
||||
sessionToken?: string;
|
||||
}
|
||||
@@ -189,6 +190,7 @@ export interface InterServerEvents {
|
||||
export interface SocketData {
|
||||
userId: string;
|
||||
userName: string;
|
||||
department: string;
|
||||
role: UserRole;
|
||||
connectedAt: Date;
|
||||
sessionId: string;
|
||||
|
||||
Reference in New Issue
Block a user