import { useEffect, useState, useCallback } from 'react'; import { teamApi } from '../lib/api'; import type { TeamMember } from '../types'; import { showToast } from '../components/Toast'; import { ConfirmModal } from '../components/ConfirmModal'; import styles from './UsersPage.module.css'; export function TeamMembersPage() { const [members, setMembers] = useState([]); const [loading, setLoading] = useState(true); // Create member modal const [createOpen, setCreateOpen] = useState(false); const [newUsername, setNewUsername] = useState(''); const [newPassword, setNewPassword] = useState(''); const [newDaily, setNewDaily] = useState('50'); const [newMonthly, setNewMonthly] = useState('500'); const [createError, setCreateError] = useState(''); // Confirm toggle const [confirmMember, setConfirmMember] = useState(null); // Edit quota modal const [editMember, setEditMember] = useState(null); const [editDaily, setEditDaily] = useState(''); const [editMonthly, setEditMonthly] = useState(''); const fetchMembers = useCallback(async () => { setLoading(true); try { const { data } = await teamApi.getMembers(); setMembers(data.results); } catch { showToast('加载成员列表失败'); } finally { setLoading(false); } }, []); useEffect(() => { fetchMembers(); }, [fetchMembers]); const formatLimit = (v: number) => v === -1 ? '不限' : v + '次'; const fmtMoney = (val: number) => '¥' + (val || 0).toFixed(2); const handleToggleStatus = async (member: TeamMember) => { try { await teamApi.updateMemberStatus(member.id, !member.is_active); showToast(member.is_active ? '已禁用成员' : '已启用成员'); fetchMembers(); } catch { showToast('操作失败'); } }; const openEditModal = (member: TeamMember) => { setEditMember(member); setEditDaily(String(member.daily_generation_limit ?? 50)); setEditMonthly(String(member.monthly_generation_limit ?? 500)); }; const handleSaveQuota = async () => { if (!editMember) return; try { await teamApi.updateMemberQuota(editMember.id, Number(editDaily), Number(editMonthly)); showToast('配额已更新'); setEditMember(null); fetchMembers(); } catch { showToast('更新失败'); } }; const resetCreateForm = () => { setNewUsername(''); setNewPassword(''); setNewDaily('50'); setNewMonthly('500'); setCreateError(''); }; const handleCreateMember = async () => { setCreateError(''); if (!newUsername.trim()) { setCreateError('请输入用户名'); return; } if (newPassword.length < 6) { setCreateError('密码至少6位'); return; } try { await teamApi.createMember({ username: newUsername.trim(), password: newPassword, daily_generation_limit: Number(newDaily), monthly_generation_limit: Number(newMonthly), }); showToast('成员创建成功'); setCreateOpen(false); resetCreateForm(); fetchMembers(); } catch (err: any) { const msg = err.response?.data?.error || err.response?.data?.username?.[0] || '创建失败'; setCreateError(msg); } }; return (

成员管理

{loading ? ( Array.from({ length: 5 }).map((_, i) => ( {Array.from({ length: 8 }).map((_, j) => ( ))} )) ) : members.length === 0 ? ( ) : ( members.map((m) => ( )) )}
用户名 角色 状态 日生成上限 月生成上限 今日生成/消费 本月生成/消费 操作
暂无成员
{m.username} {m.is_team_admin ? ( 管理员 ) : ( 成员 )} {m.is_active ? '启用' : '禁用'} {formatLimit(m.daily_generation_limit)} {formatLimit(m.monthly_generation_limit)} {(m.generations_today || 0) + '次 / ' + fmtMoney(m.spent_today)} {(m.generations_this_month || 0) + '次 / ' + fmtMoney(m.spent_this_month)}
{ if (confirmMember) { handleToggleStatus(confirmMember); setConfirmMember(null); } }} onCancel={() => setConfirmMember(null)} /> {/* Edit Quota Modal */} {editMember && (
{ if (e.target === e.currentTarget) setEditMember(null); }}>

编辑配额 — {editMember.username}

setEditDaily(e.target.value)} />
setEditMonthly(e.target.value)} />
)} {/* Create Member Modal */} {createOpen && (
{ if (e.target === e.currentTarget) setCreateOpen(false); }}>

新增成员

setNewUsername(e.target.value)} placeholder="请输入用户名" />
setNewPassword(e.target.value)} placeholder="至少6位" />
setNewDaily(e.target.value)} />
setNewMonthly(e.target.value)} />
{createError &&
{createError}
}
)}
); }