'use client' import { useEffect, useMemo, useState } from 'react' type Row = { id: string name: string email: string phone: string rfmScore: number lastActiveAt: string tags: string[] } type ApiResp = { data: Row[] pagination: { page: number; pageSize: number; total: number; totalPages: number } } export default function UserList({ queryString }: { queryString: string }) { const [data, setData] = useState([]) const [total, setTotal] = useState(0) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) useEffect(() => { let aborted = false const controller = new AbortController() async function load() { setLoading(true) setError(null) try { const res = await fetch(`/api/users?${queryString}`, { signal: controller.signal, cache: 'no-store' }) if (!res.ok) throw new Error(`请求失败: ${res.status}`) const json: ApiResp = await res.json() if (!aborted) { setData(json.data || []) setTotal(json.pagination?.total || 0) } } catch (e: any) { if (!aborted) setError(e?.message || '未知错误') } finally { if (!aborted) setLoading(false) } } load() return () => { aborted = true controller.abort() } }, [queryString]) const rows = useMemo(() => data, [data]) if (loading) { return
加载中...
} if (error) { return
加载失败:{error}
} return (
共 {total} 条
{rows.map((r) => ( ))} {!rows.length && ( )}
姓名 邮箱 手机号 RFM 最近活跃 标签
{r.name} {r.email} {r.phone} {r.rfmScore} {formatDateTime(r.lastActiveAt)}
{(r.tags || []).slice(0, 3).map((t) => ( {t} ))} {(r.tags || []).length > 3 && +{r.tags.length - 3}}
无匹配数据
) } function formatDateTime(iso: string) { try { const d = new Date(iso) return `${d.toLocaleDateString()} ${d.toLocaleTimeString()}` } catch { return iso } }