'use client'; import { useEffect, useMemo, useState } from 'react'; import useSWR from 'swr'; import { Plus, Pencil, Trash2, Loader2 } from 'lucide-react'; import { AdminHeader } from '@/components/admin/AdminHeader'; import { PaginationTable, type Column } from '@/components/admin/PaginationTable'; import { TableToolbar } from '@/components/admin/TableToolbar'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Badge } from '@/components/ui/badge'; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { ImageUpload } from '@/components/admin/ImageUpload'; import { adminApi } from '@/lib/admin-services'; import { useAdminStore } from '@/store/adminStore'; import { resolveUploadUrl } from '@/lib/utils'; import type { Team } from '@/lib/types'; interface FormState { name: string; position: string; avatar: string; desc: string; sort: number; isShow: number; } const DEFAULT: FormState = { name: '', position: '', avatar: '', desc: '', sort: 0, isShow: 1, }; export default function TeamAdminPage() { const [hydrated, setHydrated] = useState(false); const [page, setPage] = useState(1); const [keyword, setKeyword] = useState(''); const [searchKw, setSearchKw] = useState(''); const [open, setOpen] = useState(false); const [editId, setEditId] = useState(null); const [form, setForm] = useState(DEFAULT); const [saving, setSaving] = useState(false); const isSuperAdmin = useAdminStore((s) => s.admin?.role) === 'super_admin'; const PAGE_SIZE = 10; useEffect(() => setHydrated(true), []); const { data, isLoading, mutate } = useSWR( hydrated ? '/admin/team' : null, () => adminApi.teamAll(), ); // 防御性归一化:避免缓存/接口异常导致 data 不是数组 const list = Array.isArray(data) ? data : []; // 客户端搜索过滤:按姓名或职位模糊匹配 const filtered = useMemo(() => { const kw = searchKw.trim().toLowerCase(); if (!kw) return list; return list.filter( (m) => m.name.toLowerCase().includes(kw) || m.position.toLowerCase().includes(kw), ); }, [list, searchKw]); // 客户端分页 const total = filtered.length; const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE)); const safePage = Math.min(page, totalPages); const pagedRows = useMemo( () => filtered.slice((safePage - 1) * PAGE_SIZE, safePage * PAGE_SIZE), [filtered, safePage], ); // 搜索/过滤变化时,若超出范围自动回到第 1 页 useEffect(() => { if (page > totalPages) setPage(1); }, [page, totalPages]); const openCreate = () => { setEditId(null); setForm(DEFAULT); setOpen(true); }; const openEdit = async (id: number) => { const d = await adminApi.teamDetail(id); setEditId(id); setForm({ name: d.name, position: d.position, avatar: d.avatar, desc: d.desc ?? '', sort: d.sort, isShow: d.isShow, }); setOpen(true); }; const onSave = async () => { if (!form.name || !form.position || !form.avatar) { alert('请填写姓名、职位并上传头像'); return; } setSaving(true); try { if (editId) { await adminApi.teamUpdate(editId, form); } else { await adminApi.teamCreate(form); } setOpen(false); await mutate(); } catch (e) { alert((e as Error).message); } finally { setSaving(false); } }; const onDelete = async (id: number) => { if (!confirm('确认删除该成员?')) return; try { await adminApi.teamDelete(id); await mutate(); } catch (e) { alert((e as Error).message); } }; const columns: Column[] = [ { key: 'id', title: 'ID', width: 60 }, { key: 'avatar', title: '头像', width: 80, render: (r) => ( // eslint-disable-next-line @next/next/no-img-element {r.name} ), }, { key: 'name', title: '姓名', width: 120 }, { key: 'position', title: '职位', width: 160 }, { key: 'desc', title: '简介', render: (r) => ( {r.desc ?? '-'} ), }, { key: 'sort', title: '排序', width: 80 }, { key: 'isShow', title: '状态', width: 90, render: (r) => r.isShow === 1 ? ( 显示 ) : ( 隐藏 ), }, { key: '_op', title: '操作', width: 150, render: (r) => (
{isSuperAdmin && ( )}
), }, ]; return (
setKeyword(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { setSearchKw(keyword); setPage(1); } }} className="max-w-xs" /> } right={ } /> columns={columns} rows={pagedRows} total={total} page={safePage} pageSize={PAGE_SIZE} loading={isLoading} onPageChange={setPage} rowKey={(r) => String(r.id)} /> {editId ? '编辑成员' : '新增成员'}
setForm({ ...form, name: e.target.value })} />
setForm({ ...form, position: e.target.value })} />
setForm({ ...form, avatar: url })} hint="建议正方形头像,单图 ≤ 2M" />