import { useEffect, useState, useCallback } from 'react'; import { adminApi } from '../lib/api'; import type { Team, TeamDetail } from '../types'; import { showToast } from '../components/Toast'; import { ConfirmModal } from '../components/ConfirmModal'; import styles from './TeamsPage.module.css'; function fmtSec(s: number): string { return Math.round(s).toLocaleString() + 's'; } export function TeamsPage() { const [teams, setTeams] = useState([]); const [loading, setLoading] = useState(true); // Create team modal const [createOpen, setCreateOpen] = useState(false); const [newName, setNewName] = useState(''); const [newMonthlyLimit, setNewMonthlyLimit] = useState('36000'); const [newDailyMemberLimit, setNewDailyMemberLimit] = useState('600'); const [createError, setCreateError] = useState(''); // Top-up modal const [topupTeam, setTopupTeam] = useState(null); const [topupSeconds, setTopupSeconds] = useState('3600'); // Create admin modal const [adminTeam, setAdminTeam] = useState(null); const [adminUsername, setAdminUsername] = useState(''); const [adminEmail, setAdminEmail] = useState(''); const [adminPassword, setAdminPassword] = useState(''); const [adminError, setAdminError] = useState(''); // Team detail drawer const [detailTeam, setDetailTeam] = useState(null); const [drawerOpen, setDrawerOpen] = useState(false); // Edit pool modal const [editPoolOpen, setEditPoolOpen] = useState(false); const [editPoolValue, setEditPoolValue] = useState(''); const [editPoolError, setEditPoolError] = useState(''); // Confirm toggle const [confirmTeam, setConfirmTeam] = useState(null); const fetchTeams = useCallback(async () => { setLoading(true); try { const { data } = await adminApi.getTeams(); setTeams(data.results); } catch { showToast('加载团队列表失败'); } finally { setLoading(false); } }, []); useEffect(() => { fetchTeams(); }, [fetchTeams]); const handleToggleStatus = async (team: Team) => { try { await adminApi.updateTeam(team.id, { is_active: !team.is_active }); showToast(team.is_active ? '已禁用团队' : '已启用团队'); fetchTeams(); } catch { showToast('操作失败'); } }; const resetCreateForm = () => { setNewName(''); setNewMonthlyLimit('36000'); setNewDailyMemberLimit('600'); setCreateError(''); }; const handleCreateTeam = async () => { setCreateError(''); if (!newName.trim()) { setCreateError('请输入团队名称'); return; } try { await adminApi.createTeam({ name: newName.trim(), monthly_seconds_limit: Number(newMonthlyLimit), daily_member_limit_default: Number(newDailyMemberLimit), }); showToast('团队创建成功'); setCreateOpen(false); resetCreateForm(); fetchTeams(); } catch (err: any) { const msg = err.response?.data?.error || err.response?.data?.name?.[0] || '创建失败'; setCreateError(msg); } }; const handleTopUp = async () => { if (!topupTeam) return; const seconds = Number(topupSeconds); if (!seconds || seconds <= 0) { showToast('请输入有效的秒数'); return; } try { await adminApi.topUpTeam(topupTeam.id, seconds); showToast(`已为 ${topupTeam.name} 充值 ${fmtSec(seconds)} 秒`); setTopupTeam(null); fetchTeams(); } catch { showToast('充值失败'); } }; const handleSetPool = async () => { if (!detailTeam) return; const newPool = Number(editPoolValue); if (isNaN(newPool) || newPool < 0) { setEditPoolError('请输入有效的非负数'); return; } try { await adminApi.setTeamPool(detailTeam.id, newPool); showToast(`已将 ${detailTeam.name} 总秒数池修改为 ${fmtSec(newPool)}`); setEditPoolOpen(false); // Refresh detail const { data } = await adminApi.getTeamDetail(detailTeam.id); setDetailTeam(data); fetchTeams(); } catch (err: any) { const msg = err.response?.data?.error || '修改失败'; setEditPoolError(msg); } }; const resetAdminForm = () => { setAdminUsername(''); setAdminEmail(''); setAdminPassword(''); setAdminError(''); }; const handleCreateAdmin = async () => { if (!adminTeam) return; setAdminError(''); if (!adminUsername.trim()) { setAdminError('请输入用户名'); return; } if (!adminEmail.trim()) { setAdminError('请输入邮箱'); return; } if (adminPassword.length < 6) { setAdminError('密码至少6位'); return; } try { await adminApi.createTeamAdmin(adminTeam.id, { username: adminUsername.trim(), email: adminEmail.trim(), password: adminPassword, }); showToast('团队管理员创建成功'); setAdminTeam(null); resetAdminForm(); fetchTeams(); } catch (err: any) { const msg = err.response?.data?.error || err.response?.data?.username?.[0] || '创建失败'; setAdminError(msg); } }; const openDrawer = async (teamId: number) => { try { const { data } = await adminApi.getTeamDetail(teamId); setDetailTeam(data); setDrawerOpen(true); } catch { showToast('加载团队详情失败'); } }; const colCount = 9; return (

团队管理

共 {teams.length} 个团队
{loading ? ( Array.from({ length: 5 }).map((_, i) => ( {Array.from({ length: colCount }).map((_, j) => ( ))} )) ) : teams.length === 0 ? ( ) : ( teams.map((t) => ( )) )}
团队名称 总秒数池 已消耗 剩余 月限额 本月消费 成员数 状态 操作
暂无数据
{fmtSec(t.total_seconds_pool)} {fmtSec(t.total_seconds_used)} {fmtSec(t.remaining_seconds)} {fmtSec(t.monthly_seconds_limit)} {fmtSec(t.monthly_seconds_used)} {t.member_count} {t.is_active ? '启用' : '禁用'}
{/* Create Team Modal */} {createOpen && (
{ if (e.target === e.currentTarget) setCreateOpen(false); }}>

新增团队

setNewName(e.target.value)} placeholder="请输入团队名称" />
setNewMonthlyLimit(e.target.value)} />
setNewDailyMemberLimit(e.target.value)} />
{createError &&
{createError}
}
)} {/* Top-up Modal */} {topupTeam && (
{ if (e.target === e.currentTarget) setTopupTeam(null); }}>

充值秒数 — {topupTeam.name}

setTopupSeconds(e.target.value)} placeholder="输入秒数" />
当前剩余: {fmtSec(topupTeam.remaining_seconds)} | 充值后: {fmtSec(topupTeam.remaining_seconds + (Number(topupSeconds) || 0))}
)} {/* Create Team Admin Modal */} {adminTeam && (
{ if (e.target === e.currentTarget) setAdminTeam(null); }}>

添加管理员 — {adminTeam.name}

setAdminUsername(e.target.value)} placeholder="请输入用户名" />
setAdminEmail(e.target.value)} placeholder="请输入邮箱" />
setAdminPassword(e.target.value)} placeholder="至少6位" />
{adminError &&
{adminError}
}
)} { if (confirmTeam) { handleToggleStatus(confirmTeam); setConfirmTeam(null); } }} onCancel={() => setConfirmTeam(null)} /> {/* Team Detail Modal */} {drawerOpen && detailTeam && (
{ if (e.target === e.currentTarget) setDrawerOpen(false); }}>

团队详情 — {detailTeam.name} {detailTeam.is_active ? '启用' : '禁用'}

总秒数池 {fmtSec(detailTeam.total_seconds_pool)}
已消耗 {fmtSec(detailTeam.total_seconds_used)}
剩余 {fmtSec(detailTeam.remaining_seconds)}
月限额 {fmtSec(detailTeam.monthly_seconds_limit)}
本月消费 {fmtSec(detailTeam.monthly_seconds_used)}
成员数 {detailTeam.member_count}
成员日限额(默认) {fmtSec(detailTeam.daily_member_limit_default)}
创建时间 {new Date(detailTeam.created_at).toLocaleDateString('zh-CN')}

成员列表 ({detailTeam.members.length})

{detailTeam.members.length === 0 ? (
暂无成员
) : (
{detailTeam.members.map((m) => ( ))}
用户名 邮箱 角色 状态 日限额 今日消费 本月消费
{m.username} {m.email} {m.is_team_admin ? ( 管理员 ) : '成员'} {m.is_active ? '启用' : '禁用'} {fmtSec(m.daily_seconds_limit)} {fmtSec(m.seconds_today)} {fmtSec(m.seconds_this_month)}
)}
)} {/* Edit Pool Modal */} {editPoolOpen && detailTeam && (
{ if (e.target === e.currentTarget) setEditPoolOpen(false); }}>

修改总秒数池 — {detailTeam.name}

{editPoolError &&
{editPoolError}
}
setEditPoolValue(e.target.value)} placeholder="输入总秒数" />
当前: {fmtSec(detailTeam.total_seconds_pool)} | 已消耗: {fmtSec(detailTeam.total_seconds_used)} | 修改后剩余: {fmtSec(Math.max(0, (Number(editPoolValue) || 0) - detailTeam.total_seconds_used))}
)}
); }