import { useCallback, useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import { Button, Popconfirm, Space, Table, Typography, message } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import type { PartnerAssocSummary, PartnerAssocUserItem } from '@dukang/shared-types'; import { request, type HqProfile, type Paginated } from '../lib/api'; import { fmtTime } from '../lib/constants'; function formatNicknameWithRemark(row: PartnerAssocUserItem) { const name = row.nickname?.trim() || '—'; const remark = row.hqRemark?.trim(); return remark ? `${name}(${remark})` : name; } type PartnerAssocPanelProps = { partnerId: string; }; export default function PartnerAssocPanel({ partnerId }: PartnerAssocPanelProps) { const [summary, setSummary] = useState(null); const [users, setUsers] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(1); const [loading, setLoading] = useState(false); const [issuing, setIssuing] = useState(false); const [canEditAssoc, setCanEditAssoc] = useState(false); const loadSummary = useCallback(async () => { const data = await request(`/admin/partners/${partnerId}/assoc`); setSummary(data); }, [partnerId]); const loadUsers = useCallback(async (p = 1) => { setLoading(true); try { const res = await request>( `/admin/partners/${partnerId}/assoc/users?page=${p}&pageSize=20`, ); setUsers(res.items ?? []); setTotal(res.total ?? 0); setPage(p); } finally { setLoading(false); } }, [partnerId]); useEffect(() => { void request('/admin/auth/me') .then((p) => setCanEditAssoc((p.permissionKeys ?? []).includes('users_partner_assoc'))) .catch(() => setCanEditAssoc(false)); }, []); useEffect(() => { void loadSummary().catch((e) => message.error(e instanceof Error ? e.message : '加载关联码失败')); void loadUsers(1).catch(() => undefined); }, [loadSummary, loadUsers]); async function reissue() { setIssuing(true); try { await request(`/admin/partners/${partnerId}/assoc/qrcode`, { method: 'POST' }); message.success('已重新生成关联码'); await loadSummary(); } catch (e) { message.error(e instanceof Error ? e.message : '生成失败'); } finally { setIssuing(false); } } async function unbind(userId: string) { try { await request(`/admin/partners/${partnerId}/assoc/users/${userId}/unbind`, { method: 'POST' }); message.success('已解绑'); await Promise.all([loadSummary(), loadUsers(page)]); } catch (e) { message.error(e instanceof Error ? e.message : '解绑失败'); } } const columns: ColumnsType = [ { title: '用户编号', dataIndex: 'userNo', width: 140 }, { title: '用户', dataIndex: 'nickname', render: (_, row) => ( {formatNicknameWithRemark(row)} ), }, { title: '手机', dataIndex: 'phone', render: (v) => v || '—' }, { title: '关联时间', dataIndex: 'boundAt', render: (v) => (v ? fmtTime(v) : '—') }, { title: '已付订单', dataIndex: 'orderCount', width: 90 }, ...(canEditAssoc ? [ { title: '操作', width: 90, render: (_: unknown, row: PartnerAssocUserItem) => ( void unbind(row.id)}> ), } satisfies ColumnsType[number], ] : []), ]; return (
{summary?.qrcodeUrl ? ( 关联码 ) : ( 尚未生成关联码 )}
关联用户 {summary?.userCount ?? 0} 人
void loadUsers(p), }} /> ); }