import { useEffect, useState } from 'react'
import { Button, Badge, Select } from '@/components/atoms'
import { Modal } from '@/components/common/Modal'
import { DataTable, type DataColumn } from '@/components/common/DataTable'
import { showToast } from '@/stores/toastStore'
import { getMembers, addMember, updateMember, deleteMember, type Member } from '@/lib/api'
const ROLE_LABELS: Record<string, string> = { Parent: '家长', Child: '孩子', Guest: '访客' }
const ROLE_OPTIONS = [
{ value: 'Parent', label: '家长' },
{ value: 'Child', label: '孩子' },
{ value: 'Guest', label: '访客' },
]
export function MembersPage() {
const [members, setMembers] = useState<Member[]>([])
const [loading, setLoading] = useState(true)
const [showAdd, setShowAdd] = useState(false)
const [editing, setEditing] = useState<Member | null>(null)
const [form, setForm] = useState({ name: '', displayName: '', mobile: '', role: 'Child', monthlyQuota: 0 })
const fetchData = async () => {
try { setMembers(await getMembers()) } catch { /* 静默 */ }
setLoading(false)
}
useEffect(() => { fetchData() }, [])
const resetForm = () => setForm({ name: '', displayName: '', mobile: '', role: 'Child', monthlyQuota: 0 })
const handleAdd = async () => {
if (!form.name) { showToast('warning', '姓名为必填'); return }
try { await addMember(form); showToast('success', '成员已添加'); setShowAdd(false); resetForm(); await fetchData() }
catch { showToast('error', '添加失败') }
}
const handleEdit = (m: Member) => {
setEditing(m)
setForm({
name: m.name, displayName: m.displayName || '', mobile: m.mobile || '',
role: m.role || 'Child', monthlyQuota: m.monthlyQuota || 0,
})
}
const handleSaveEdit = async () => {
if (!editing) return
try { await updateMember(editing.id, form); showToast('success', '已更新'); setEditing(null); resetForm(); await fetchData() }
catch { showToast('error', '更新失败') }
}
const handleDelete = async (id: number) => {
try { await deleteMember(id); showToast('success', '已删除'); await fetchData() }
catch { showToast('error', '删除失败') }
}
const quotaText = (bytes: number) => {
if (bytes === 0) return '不限'
if (bytes >= 1e9) return `${(bytes / 1e9).toFixed(0)} GB`
return `${(bytes / 1e6).toFixed(0)} MB`
}
const columns: DataColumn<Member>[] = [
{ key: 'name', label: '姓名', sortable: true, render: (m) => <span className="font-medium">{m.name}</span> },
{ key: 'displayName', label: '显示名', sortable: true, render: (m) => m.displayName || '-' },
{ key: 'mobile', label: '手机号', render: (m) => m.mobile || '-' },
{
key: 'role', label: '角色', sortable: true,
render: (m) => {
const v = m.role === 'Parent' ? 'primary' as const : m.role === 'Child' ? 'info' as const : 'default' as const
return <Badge variant={v}>{ROLE_LABELS[m.role] || m.role}</Badge>
},
},
{ key: 'monthlyQuota', label: '流量配额', render: (m) => quotaText(m.monthlyQuota) },
{
key: 'enable', label: '状态', sortable: true,
render: (m) => <Badge variant={m.enable ? 'success' : 'default'}>{m.enable ? '启用' : '禁用'}</Badge>,
},
{
key: 'actions', label: '操作',
render: (m) => (
<div className="flex gap-1">
<Button variant="ghost" size="sm" onClick={() => handleEdit(m)}>编辑</Button>
<Button variant="ghost" size="sm" onClick={() => handleDelete(m.id)}>删除</Button>
</div>
),
},
]
return (
<div className="p-6">
<div className="flex items-center justify-between mb-4">
<h1 className="text-lg font-bold text-[var(--color-text-primary)]">用户管理</h1>
<Button variant="primary" size="sm" onClick={() => { resetForm(); setShowAdd(true) }}>
添加成员
</Button>
</div>
<DataTable
data={members}
columns={columns}
rowKey={(m) => m.id}
searchFields={['name', 'displayName', 'mobile']}
searchPlaceholder="搜索姓名 / 显示名 / 手机号…"
loading={loading}
emptyText="暂无家庭成员"
/>
{/* 添加/编辑弹窗 */}
<Modal open={showAdd || !!editing} onClose={() => { setShowAdd(false); setEditing(null) }} maxWidth="max-w-sm">
<div className="p-6">
<h3 className="text-sm font-semibold mb-4 text-[var(--color-text-primary)]">
{editing ? '编辑成员' : '添加成员'}
</h3>
<div className="space-y-3">
<InputField label="姓名 *" value={form.name} onChange={(v) => setForm((f) => ({ ...f, name: v }))} placeholder="张三" />
<InputField label="显示名" value={form.displayName} onChange={(v) => setForm((f) => ({ ...f, displayName: v }))} placeholder="爸爸" />
<InputField label="手机号" value={form.mobile} onChange={(v) => setForm((f) => ({ ...f, mobile: v }))} placeholder="可选" />
<div>
<label className="text-xs text-[var(--color-text-secondary)]">角色</label>
<Select
options={ROLE_OPTIONS}
value={form.role}
onChange={(v) => setForm((f) => ({ ...f, role: v }))}
className="mt-1"
/>
</div>
<InputField label="月度流量配额(GB,0=不限)" value={String(form.monthlyQuota)} onChange={(v) => setForm((f) => ({ ...f, monthlyQuota: Number(v) || 0 }))} type="number" />
</div>
<div className="flex justify-end gap-2 mt-4">
<Button variant="secondary" size="sm" onClick={() => { setShowAdd(false); setEditing(null) }}>取消</Button>
<Button variant="primary" size="sm" onClick={editing ? handleSaveEdit : handleAdd}>确定</Button>
</div>
</div>
</Modal>
</div>
)
}
function InputField({ label, value, onChange, placeholder, type = 'text' }: {
label: string; value: string; onChange: (v: string) => void; placeholder?: string; type?: string
}) {
return (
<label className="block">
<span className="text-xs text-[var(--color-text-secondary)]">{label}</span>
<input
type={type}
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
className="mt-1 w-full px-3 py-2 text-sm rounded-lg border border-[var(--color-border-default)] bg-[var(--color-surface-0)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-[color:var(--color-brand-500)]/40"
/>
</label>
)
}
|