gongxiangp2/app/performance-survey/PerformanceSurveyExportDialog.tsx

128 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import { useEffect, useRef } from 'react'
import { createPortal } from 'react-dom'
export function PerformanceSurveyExportDialog({
open,
positionName,
monthLabel,
employeeSummary,
assessmentCount,
busy,
error,
onClose,
onExport,
}: {
open: boolean
positionName: string
monthLabel: string
employeeSummary: string
assessmentCount: number
busy: boolean
error: string | null
onClose: () => void
onExport: () => void
}) {
const exportButtonRef = useRef<HTMLButtonElement>(null)
useEffect(() => {
if (!open) return
const previousActiveElement = document.activeElement as HTMLElement | null
window.requestAnimationFrame(() => exportButtonRef.current?.focus())
const onKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Escape' && !busy) onClose()
}
document.addEventListener('keydown', onKeyDown)
return () => {
document.removeEventListener('keydown', onKeyDown)
previousActiveElement?.focus()
}
}, [busy, onClose, open])
if (!open || typeof document === 'undefined') return null
return createPortal(
<div
className="fixed inset-0 z-[100] flex items-end justify-center bg-black/45 p-0 sm:items-center sm:p-5"
onMouseDown={(event) => {
if (event.target === event.currentTarget && !busy) onClose()
}}
>
<section
role="dialog"
aria-modal="true"
aria-labelledby="performance-survey-export-title"
aria-describedby="performance-survey-export-description"
className="w-full border border-[#d0d5dd] bg-white shadow-[0_18px_45px_rgba(15,23,42,0.18)] sm:max-w-lg sm:rounded-xl"
>
<div className="flex items-start justify-between gap-4 border-b border-[#e2e2e2] px-5 py-4">
<div className="min-w-0">
<h2 id="performance-survey-export-title" className="text-[18px] font-bold text-[#1a1c1c]">
导出公共看板
</h2>
<p id="performance-survey-export-description" className="mt-1 text-[13px] leading-5 text-[#5f5e5e]">
生成 WPS/Excel 可直接打开的 .xlsx 表格。
</p>
</div>
<button
type="button"
aria-label="关闭导出窗口"
disabled={busy}
onClick={onClose}
className="flex h-10 w-10 shrink-0 items-center justify-center rounded border border-transparent text-[22px] leading-none text-[#5f5e5e] transition-colors hover:border-[#d0d5dd] hover:bg-[#f7f7f7] focus:outline-none focus:ring-2 focus:ring-[#0050cb] disabled:opacity-40"
>
×
</button>
</div>
<dl className="grid grid-cols-2 border-b border-[#e2e2e2] bg-[#f8f9fb] sm:grid-cols-4">
{[
['岗位', positionName],
['月份', monthLabel],
['人员范围', employeeSummary],
['考核项', `${assessmentCount} 项`],
].map(([label, value]) => (
<div key={label} className="min-w-0 border-b border-[#e2e2e2] px-4 py-3 last:border-b-0 sm:border-b-0 sm:border-r sm:last:border-r-0">
<dt className="text-[11px] font-semibold text-[#727687]">{label}</dt>
<dd className="mt-1 truncate text-[13px] font-bold text-[#1a1c1c]" title={value}>{value}</dd>
</div>
))}
</dl>
<div className="px-5 py-4">
<p className="text-[13px] font-medium leading-6 text-[#475467]">
表格包含岗位、考核月份、姓名、工号、组织、职级及全部考核项得分。支持保存位置选择的浏览器会先打开本地路径窗口;其他浏览器将保存到默认下载目录。
</p>
{error && (
<div role="alert" className="mt-3 rounded border border-[#ffdad6] bg-[#fff6f4] px-3 py-2 text-[12px] font-semibold leading-5 text-[#93000a]">
{error}
</div>
)}
</div>
<div className="flex flex-col-reverse gap-2 border-t border-[#e2e2e2] px-5 py-4 sm:flex-row sm:justify-end">
<button
type="button"
disabled={busy}
onClick={onClose}
className="min-h-11 rounded border border-[#c9c9c9] bg-white px-4 text-[13px] font-bold text-[#1a1c1c] transition-colors hover:border-[#1a1c1c] hover:bg-[#f7f7f7] focus:outline-none focus:ring-2 focus:ring-[#0050cb] disabled:opacity-50"
>
取消
</button>
<button
ref={exportButtonRef}
type="button"
disabled={busy}
onClick={onExport}
className="min-h-11 rounded bg-[#0050cb] px-5 text-[13px] font-bold text-white transition-colors hover:bg-[#003f9f] focus:outline-none focus:ring-2 focus:ring-[#0050cb] focus:ring-offset-2 disabled:cursor-wait disabled:opacity-60"
>
{busy ? '正在生成表格…' : '选择保存位置并导出'}
</button>
</div>
</section>
</div>,
document.body,
)
}