/** * 游戏结束模态弹窗(胜利 / 失败) * DOM 层实现(z-index: 9998),覆盖 canvas */ export interface VictoryData { kpi: number hc: number grade: string gradeColor: string gradeDesc: string } function injectEndStyles(): void { if (document.getElementById('end-screen-styles')) return const style = document.createElement('style') style.id = 'end-screen-styles' style.textContent = ` @keyframes endOverlayIn { from { opacity: 0 } to { opacity: 1 } } @keyframes endCardIn { from { transform: scale(0.8); opacity: 0 } to { transform: scale(1); opacity: 1 } } ` document.head.appendChild(style) } function buildOverlay(): HTMLElement { const overlay = document.createElement('div') overlay.id = 'end-screen-overlay' overlay.style.cssText = ` position: fixed; inset: 0; background: rgba(0,0,0,0.85); z-index: 9998; display: flex; align-items: center; justify-content: center; font-family: 'VT323', monospace; animation: endOverlayIn 0.4s ease; ` return overlay } function buildVictoryCard(data: VictoryData): HTMLElement { const card = document.createElement('div') card.style.cssText = ` background: #0f0c29; border: 2px solid #d97706; border-radius: 14px; padding: 36px 48px; max-width: 480px; width: 90%; text-align: center; box-shadow: 0 0 60px rgba(217,119,6,0.4); animation: endCardIn 0.4s ease; ` card.innerHTML = `
绩效评级公示
最终KPI${data.kpi}%
剩余HC${data.hc}
${data.grade}
${data.gradeDesc}
` const btnWrap = document.createElement('div') btnWrap.style.cssText = 'display:flex;gap:16px;justify-content:center;' const restartBtn = document.createElement('button') restartBtn.textContent = '再战一局' restartBtn.style.cssText = ` padding:12px 28px;background:#7c3aed;color:#fff;border:2px solid #7c3aed; border-radius:8px;font-family:'VT323',monospace;font-size:20px;cursor:pointer; ` restartBtn.addEventListener('click', () => window.location.reload()) const homeBtn = document.createElement('button') homeBtn.textContent = '见好就收' homeBtn.style.cssText = ` padding:12px 28px;background:#374151;color:#d1d5db;border:1px solid #4b5563; border-radius:8px;font-family:'VT323',monospace;font-size:20px;cursor:pointer; ` homeBtn.addEventListener('click', () => { window.location.href = '/' }) btnWrap.appendChild(restartBtn) btnWrap.appendChild(homeBtn) card.appendChild(btnWrap) return card } function buildDefeatCard(): HTMLElement { const card = document.createElement('div') card.style.cssText = ` background: #ffffff; border-radius: 14px; max-width: 420px; width: 90%; overflow: hidden; box-shadow: 0 20px 60px rgba(0,0,0,0.5); animation: endCardIn 0.4s ease; ` const topBar = document.createElement('div') topBar.textContent = '系统通知 — 人力资源管理系统' topBar.style.cssText = ` background: #1677ff; color: #fff; font-family: 'VT323', monospace; font-size: 18px; padding: 10px 20px; letter-spacing: 2px; ` card.appendChild(topBar) const body = document.createElement('div') body.style.cssText = 'padding: 28px 32px 24px;' body.innerHTML = `
📋
鉴于您近期的表现未能达成业务闭环,
经公司管理层研究决定,
对您进行「毕业」处理。
请于5分钟内归还工牌,
不要带走办公文具。
` const btnWrap = document.createElement('div') btnWrap.style.cssText = 'display:flex;gap:12px;justify-content:center;' const restartBtn = document.createElement('button') restartBtn.textContent = '领取 N+1' restartBtn.style.cssText = ` padding:10px 24px;background:#1677ff;color:#fff;border:none; border-radius:6px;font-family:'VT323',monospace;font-size:20px;cursor:pointer; ` restartBtn.addEventListener('click', () => window.location.reload()) const homeBtn = document.createElement('button') homeBtn.textContent = '申请仲裁' homeBtn.style.cssText = ` padding:10px 24px;background:#f3f4f6;color:#374151;border:1px solid #d1d5db; border-radius:6px;font-family:'VT323',monospace;font-size:20px;cursor:pointer; ` homeBtn.addEventListener('click', () => { window.location.href = '/' }) btnWrap.appendChild(restartBtn) btnWrap.appendChild(homeBtn) body.appendChild(btnWrap) card.appendChild(body) return card } /** 显示胜利结算弹窗 */ export function showVictoryModal(data: VictoryData): void { injectEndStyles() const overlay = buildOverlay() overlay.appendChild(buildVictoryCard(data)) document.body.appendChild(overlay) } /** 显示失败结算弹窗 */ export function showDefeatModal(): void { injectEndStyles() const overlay = buildOverlay() overlay.appendChild(buildDefeatCard()) document.body.appendChild(overlay) }