import { useState, useEffect } from 'react' import { Upload, CheckCircle, Trash2, Clock, Users, RefreshCw } from 'lucide-react' import api from '../../api' import toast from 'react-hot-toast' export default function RosterPage() { const [rosterData, setRosterData] = useState({ headers: [], rows: [] }) const [rosterInfo, setRosterInfo] = useState({ uploaded: false }) const [file, setFile] = useState(null) const [uploading, setUploading] = useState(false) const [loading, setLoading] = useState(true) const loadRosterData = async () => { try { const [infoRes, dataRes] = await Promise.all([ api.get('/api/roster/info'), api.get('/api/roster/data').catch(() => ({ data: { headers: [], rows: [] } })) ]) setRosterInfo(infoRes.data) setRosterData(dataRes.data || { headers: [], rows: [] }) } catch (err) { console.error('Load error:', err) } finally { setLoading(false) } } useEffect(() => { loadRosterData() }, []) const handleUpload = async (e) => { e.preventDefault() if (!file) return setUploading(true) const formData = new FormData() formData.append('file', file) try { await api.post('/api/roster/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' } }) toast.success('上傳成功!') setFile(null) loadRosterData() } catch (err) { toast.error(err.response?.data?.detail || '上傳失敗') } finally { setUploading(false) } } const handleDelete = async () => { if (!confirm('確定要刪除班次表嗎?')) return try { await api.delete('/api/roster') toast.success('已刪除') setRosterData({ headers: [], rows: [] }) setRosterInfo({ uploaded: false }) } catch (err) { toast.error('刪除失敗') } } const handleRecalc = async () => { setLoading(true) try { await Promise.all([ api.get('/api/roster/info'), api.get('/api/roster/data').catch(() => ({ data: { headers: [], rows: [] } })) ]) toast.success('已重新計算') } catch { toast.error('重新計算失敗') } finally { loadRosterData() } } if (loading) { return
已上傳班次表
{rosterInfo.rows} 個班次,{rosterInfo.columns} 欄
| {header} | ))}
|---|
| {row[colIdx] !== null && row[colIdx] !== undefined ? String(row[colIdx]) : '-'} | ))}