/**
* 游戏结束模态弹窗(胜利 / 失败)
* 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)
}