'use client'; import { ProTable, ProTableActions } from '@/components/pro-table'; import { createUser, deleteUser, getUserDetail, getUserList, updateUserBasicInfo, } from '@/services/admin/user'; import { useSubscribe } from '@/store/subscribe'; import { formatDate } from '@/utils/common'; import { useQuery } from '@tanstack/react-query'; import { Button } from '@workspace/ui/components/button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@workspace/ui/components/dropdown-menu'; import { Input } from '@workspace/ui/components/input'; import { Popover, PopoverClose, PopoverContent, PopoverTrigger, } from '@workspace/ui/components/popover'; import { ScrollArea } from '@workspace/ui/components/scroll-area'; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger, } from '@workspace/ui/components/sheet'; import { Switch } from '@workspace/ui/components/switch'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs'; import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button'; import { FilePenLine } from 'lucide-react'; import { useTranslations } from 'next-intl'; import Link from 'next/link'; import { useSearchParams } from 'next/navigation'; import { useRef, useState } from 'react'; import { toast } from 'sonner'; import { UserDetail } from './user-detail'; import UserForm from './user-form'; import { BasicInfoForm } from './user-profile/basic-info-form'; import { NotifySettingsForm } from './user-profile/notify-settings-form'; import UserSubscription from './user-subscription'; function getDeviceTypeInfo(userAgent = '') { let deviceType = 'Unknown'; const ua = userAgent.toLowerCase(); if (ua.includes('android')) { deviceType = 'Android'; } else if (ua.includes('iphone') || ua.includes('ios')) { deviceType = 'iPhone'; } else if (ua.includes('ipad')) { deviceType = 'iPad'; } else if (ua.includes('mac os') || ua.includes('mac')) { deviceType = 'Mac'; } else if (ua.includes('windows')) { deviceType = 'Windows'; } else if (ua.includes('linux')) { deviceType = 'Linux'; } return { deviceType }; } // 为 RemarkForm 组件定义 props 类型 interface RemarkFormProps { initialRemark?: string | null; onSave: (remark: string) => void; CloseComponent: React.ComponentType<{ asChild?: boolean; children: React.ReactNode }>; } // 新的子组件,在管理它自己的备注状态 const RemarkForm: React.FC = ({ onSave, initialRemark, CloseComponent }) => { const [remark, setRemark] = useState(initialRemark ?? ''); const handleInputChange = (event: React.ChangeEvent) => { setRemark(event.target.value); }; const handleSaveClick = () => { onSave(remark); }; return ( <>
备注
); }; export default function Page() { const t = useTranslations('user'); const [loading, setLoading] = useState(false); const ref = useRef(null); const sp = useSearchParams(); const { subscribes } = useSubscribe(); const initialFilters = { search: sp.get('search') || undefined, user_id: sp.get('user_id') || undefined, subscribe_id: sp.get('subscribe_id') || undefined, user_subscribe_id: sp.get('user_subscribe_id') || undefined, device_id: sp.get('device_id') || undefined, }; return ( key={initialFilters.user_id} action={ref} initialFilters={initialFilters} header={{ title: t('userList'), toolbar: ( key='create' trigger={t('create')} title={t('createUser')} loading={loading} onSubmit={async (values) => { setLoading(true); try { await createUser(values); toast.success(t('createSuccess')); ref.current?.refresh(); setLoading(false); return true; } catch (error) { setLoading(false); return false; } }} /> ), }} columns={[ { accessorKey: 'enable', header: t('enable'), cell: ({ row }) => { return ( { const { auth_methods, user_devices, enable_balance_notify, enable_login_notify, enable_subscribe_notify, enable_trade_notify, updated_at, created_at, id, ...rest } = row.original; await updateUserBasicInfo({ user_id: id, ...rest, enable: checked, } as unknown as API.UpdateUserBasiceInfoRequest); toast.success(t('updateSuccess')); ref.current?.refresh(); }} /> ); }, }, { accessorKey: 'id', header: 'ID', }, { accessorKey: 'auth_methods', header: '绑定邮箱', cell: ({ row }) => { const method = row.original.auth_methods; return (
{method?.find((v) => v.auth_type === 'email')?.auth_identifier || '待绑定'} {row.original?.remark ? `(${row.original.remark})` : ''}
{ const { auth_methods, user_devices, enable_balance_notify, enable_login_notify, enable_subscribe_notify, enable_trade_notify, updated_at, created_at, id, ...rest } = row.original; await updateUserBasicInfo({ user_id: id, ...rest, remark, } as unknown as API.UpdateUserBasiceInfoRequest); toast.success(t('updateSuccess')); ref.current?.refresh(); }} />
); }, }, { accessorKey: 'user_devices', header: '绑定设备', cell: ({ row }) => { const devices = row?.original.user_devices ?? []; return (
{devices.map((v, index) => { const { deviceType } = getDeviceTypeInfo(v.user_agent); return (
ID:{v.id}({deviceType})
{index !== devices.length - 1 && (
)}
); })}
); }, }, /*{ accessorKey: 'balance', header: t('balance'), cell: ({ row }) => , }, { accessorKey: 'gift_amount', header: t('giftAmount'), cell: ({ row }) => , }, { accessorKey: 'commission', header: t('commission'), cell: ({ row }) => , },*/ { accessorKey: 'refer_code', header: t('inviteCode'), cell: ({ row }) => row.getValue('refer_code') || '--', }, { accessorKey: 'last_login_time', header: '最后登录时间', cell: ({ row }) => { const v = (row.original as any)?.last_login_time; if (!v) return '---'; const ts = Number(v); const ms = ts < 1e12 ? ts * 1000 : ts; return formatDate(ms) as any; }, }, { accessorKey: 'member_status', header: '会员状态', cell: ({ row }) => { const v = (row.original as any)?.member_status; return {v ?? '---'}; }, }, { accessorKey: 'referer_id', header: t('referer'), cell: ({ row }) => , }, { accessorKey: 'created_at', header: t('createdAt'), cell: ({ row }) => formatDate(row.getValue('created_at')), }, ]} request={async (pagination, filter) => { const { data } = await getUserList({ ...pagination, ...filter, }); return { list: data.data?.list || [], total: data.data?.total || 0, }; }} params={[ { key: 'subscribe_id', placeholder: t('subscription'), options: subscribes?.map((item) => ({ label: item.name!, value: String(item.id!), })), }, { key: 'search', placeholder: 'Search', }, { key: 'user_id', placeholder: t('userId'), }, { key: 'user_subscribe_id', placeholder: t('subscriptionId'), }, { key: 'device_id', placeholder: '设备id', }, ]} actions={{ render: (row) => { return [ , , {t('delete')}} title={t('confirmDelete')} description={t('deleteDescription')} onConfirm={async () => { await deleteUser({ id: row.id }); toast.success(t('deleteSuccess')); ref.current?.refresh(); }} cancelText={t('cancel')} confirmText={t('confirm')} />, {t('orderList')} {t('loginLogs')} {t('balanceLogs')} {t('commissionLogs')} {t('giftLogs')} , ]; }, }} /> ); } function ProfileSheet({ userId }: { userId: number }) { const t = useTranslations('user'); const [open, setOpen] = useState(false); const { data: user, refetch } = useQuery({ enabled: open, queryKey: ['user', userId], queryFn: async () => { const { data } = await getUserDetail({ id: userId }); return data.data as API.User; }, }); return ( {t('userProfile')} · ID: {userId} {user && ( {t('basicInfoTitle')} {t('notifySettingsTitle')} {/*{t('authMethodsTitle')}*/} {/* */} )} ); } function SubscriptionSheet({ userId }: { userId: number }) { const t = useTranslations('user'); const [open, setOpen] = useState(false); return ( {t('subscriptionList')} · ID: {userId}
); }