✨ feat(logs): Add various log pages for tracking user activities and system events
This commit is contained in:
@@ -1,48 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { ScrollArea } from '@workspace/ui/components/scroll-area';
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from '@workspace/ui/components/sheet';
|
||||
import { Icon } from '@workspace/ui/custom-components/icon';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useState } from 'react';
|
||||
import { LogsTable } from '../log';
|
||||
|
||||
export default function EmailLogsTable() {
|
||||
const t = useTranslations('auth-control');
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
<SheetTrigger asChild>
|
||||
<div className='flex cursor-pointer items-center justify-between transition-colors'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<div className='bg-primary/10 flex h-10 w-10 items-center justify-center rounded-lg'>
|
||||
<Icon icon='mdi:email-newsletter' className='text-primary h-5 w-5' />
|
||||
</div>
|
||||
<div className='flex-1'>
|
||||
<p className='font-medium'>{t('email.logs')}</p>
|
||||
<p className='text-muted-foreground text-sm'>{t('email.logsDescription')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<Icon icon='mdi:chevron-right' className='size-6' />
|
||||
</div>
|
||||
</SheetTrigger>
|
||||
<SheetContent className='w-[800px] max-w-full md:max-w-screen-lg'>
|
||||
<SheetHeader>
|
||||
<SheetTitle>{t('email.logs')}</SheetTitle>
|
||||
</SheetHeader>
|
||||
<ScrollArea className='-mx-6 h-[calc(100dvh-48px-36px-36px-env(safe-area-inset-top))]'>
|
||||
<div className='px-6 pt-4'>
|
||||
<LogsTable type='email' />
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { ScrollArea } from '@workspace/ui/components/scroll-area';
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from '@workspace/ui/components/sheet';
|
||||
import { Icon } from '@workspace/ui/custom-components/icon';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useState } from 'react';
|
||||
import { LogsTable } from '../log';
|
||||
|
||||
export default function PhoneLogsTable() {
|
||||
const t = useTranslations('auth-control');
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
<SheetTrigger asChild>
|
||||
<div className='flex cursor-pointer items-center justify-between transition-colors'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<div className='bg-primary/10 flex h-10 w-10 items-center justify-center rounded-lg'>
|
||||
<Icon icon='mdi:phone-log' className='text-primary h-5 w-5' />
|
||||
</div>
|
||||
<div className='flex-1'>
|
||||
<p className='font-medium'>{t('phone.logs')}</p>
|
||||
<p className='text-muted-foreground text-sm'>{t('phone.logsDescription')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<Icon icon='mdi:chevron-right' className='size-6' />
|
||||
</div>
|
||||
</SheetTrigger>
|
||||
<SheetContent className='w-[800px] max-w-full md:max-w-screen-lg'>
|
||||
<SheetHeader>
|
||||
<SheetTitle>{t('phone.logs')}</SheetTitle>
|
||||
</SheetHeader>
|
||||
<ScrollArea className='-mx-6 h-[calc(100dvh-48px-36px-36px-env(safe-area-inset-top))]'>
|
||||
<div className='px-6 pt-4'>
|
||||
<LogsTable type='mobile' />
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
import { ProTable, ProTableActions } from '@/components/pro-table';
|
||||
import { getMessageLogList } from '@/services/admin/log';
|
||||
import { Badge } from '@workspace/ui/components/badge';
|
||||
import { formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useRef } from 'react';
|
||||
|
||||
export function LogsTable({ type }: { type: 'email' | 'mobile' }) {
|
||||
const t = useTranslations('auth-control.log');
|
||||
const ref = useRef<ProTableActions>(null);
|
||||
|
||||
return (
|
||||
<ProTable<
|
||||
API.MessageLog,
|
||||
{
|
||||
platform?: string;
|
||||
to?: string;
|
||||
subject?: string;
|
||||
content?: string;
|
||||
status?: number;
|
||||
}
|
||||
>
|
||||
action={ref}
|
||||
header={{
|
||||
title: t(`${type}Log`),
|
||||
}}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'id',
|
||||
header: 'ID',
|
||||
},
|
||||
{
|
||||
accessorKey: 'platform',
|
||||
header: t('platform'),
|
||||
},
|
||||
{
|
||||
accessorKey: 'to',
|
||||
header: t('to'),
|
||||
},
|
||||
{
|
||||
accessorKey: 'subject',
|
||||
header: t('subject'),
|
||||
},
|
||||
{
|
||||
accessorKey: 'content',
|
||||
header: t('content'),
|
||||
},
|
||||
{
|
||||
accessorKey: 'status',
|
||||
header: t('status'),
|
||||
cell: ({ row }) => {
|
||||
const status = row.getValue('status');
|
||||
const text = status === 1 ? t('sendSuccess') : t('sendFailed');
|
||||
return <Badge variant={status === 1 ? 'default' : 'destructive'}>{text}</Badge>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'created_at',
|
||||
header: t('createdAt'),
|
||||
cell: ({ row }) => formatDate(row.getValue('created_at')),
|
||||
},
|
||||
{
|
||||
accessorKey: 'updated_at',
|
||||
header: t('updatedAt'),
|
||||
cell: ({ row }) => formatDate(row.getValue('updated_at')),
|
||||
},
|
||||
]}
|
||||
params={[
|
||||
{
|
||||
key: 'to',
|
||||
placeholder: t('to'),
|
||||
},
|
||||
{
|
||||
key: 'subject',
|
||||
placeholder: t('subject'),
|
||||
},
|
||||
{
|
||||
key: 'content',
|
||||
placeholder: t('content'),
|
||||
},
|
||||
{
|
||||
key: 'status',
|
||||
placeholder: t('status'),
|
||||
options: [
|
||||
{ label: t('sendSuccess'), value: '1' },
|
||||
{ label: t('sendFailed'), value: '0' },
|
||||
],
|
||||
},
|
||||
]}
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await getMessageLogList({
|
||||
...pagination,
|
||||
...filter,
|
||||
status: filter.status === undefined ? undefined : Number(filter.status),
|
||||
type: type,
|
||||
});
|
||||
return {
|
||||
list: data.data?.list || [],
|
||||
total: data.data?.total || 0,
|
||||
};
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -4,12 +4,10 @@ import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/
|
||||
import { useTranslations } from 'next-intl';
|
||||
import AppleForm from './forms/apple-form';
|
||||
import DeviceForm from './forms/device-form';
|
||||
import EmailLogsTable from './forms/email-logs-table';
|
||||
import EmailSettingsForm from './forms/email-settings-form';
|
||||
import FacebookForm from './forms/facebook-form';
|
||||
import GithubForm from './forms/github-form';
|
||||
import GoogleForm from './forms/google-form';
|
||||
import PhoneLogsTable from './forms/phone-logs-table';
|
||||
import PhoneSettingsForm from './forms/phone-settings-form';
|
||||
import TelegramForm from './forms/telegram-form';
|
||||
|
||||
@@ -22,9 +20,8 @@ export default function Page() {
|
||||
title: t('communicationMethods'),
|
||||
forms: [
|
||||
{ component: EmailSettingsForm },
|
||||
{ component: EmailLogsTable },
|
||||
{ component: PhoneSettingsForm },
|
||||
{ component: PhoneLogsTable },
|
||||
// Removed EmailLogsTable and PhoneLogsTable modules
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
'use client';
|
||||
|
||||
import { UserDetail } from '@/app/dashboard/user/user-detail';
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { filterBalanceLog } from '@/services/admin/log';
|
||||
import { formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function BalanceLogPage() {
|
||||
const t = useTranslations('log');
|
||||
return (
|
||||
<ProTable<API.BalanceLog, { search?: string }>
|
||||
header={{ title: t('title.balance') }}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'user',
|
||||
header: t('column.user'),
|
||||
cell: ({ row }) => <UserDetail id={Number(row.original.user_id)} />,
|
||||
},
|
||||
{ accessorKey: 'amount', header: t('column.amount') },
|
||||
{ accessorKey: 'order_id', header: t('column.orderId') },
|
||||
{ accessorKey: 'balance', header: t('column.balance') },
|
||||
{ accessorKey: 'type', header: t('column.type') },
|
||||
{
|
||||
accessorKey: 'timestamp',
|
||||
header: t('column.time'),
|
||||
cell: ({ row }) => formatDate(row.original.timestamp),
|
||||
},
|
||||
]}
|
||||
params={[
|
||||
{ key: 'search' },
|
||||
{ key: 'date', type: 'date' },
|
||||
{ key: 'user_id', placeholder: t('column.userId') },
|
||||
]}
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await filterBalanceLog({
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: filter?.search,
|
||||
date: (filter as any)?.date,
|
||||
user_id: (filter as any)?.user_id,
|
||||
});
|
||||
const list = (data?.data?.list || []) as any[];
|
||||
const total = Number(data?.data?.total || list.length);
|
||||
return { list, total };
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
'use client';
|
||||
|
||||
import { UserDetail } from '@/app/dashboard/user/user-detail';
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { filterCommissionLog } from '@/services/admin/log';
|
||||
import { formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function CommissionLogPage() {
|
||||
const t = useTranslations('log');
|
||||
return (
|
||||
<ProTable<API.CommissionLog, { search?: string }>
|
||||
header={{ title: t('title.commission') }}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'user',
|
||||
header: t('column.user'),
|
||||
cell: ({ row }) => <UserDetail id={Number(row.original.user_id)} />,
|
||||
},
|
||||
{ accessorKey: 'amount', header: t('column.amount') },
|
||||
{ accessorKey: 'order_no', header: t('column.orderNo') },
|
||||
{ accessorKey: 'type', header: t('column.type') },
|
||||
{
|
||||
accessorKey: 'created_at',
|
||||
header: t('column.createdAt'),
|
||||
cell: ({ row }) => formatDate(row.original.created_at),
|
||||
},
|
||||
]}
|
||||
params={[
|
||||
{ key: 'search' },
|
||||
{ key: 'date', type: 'date' },
|
||||
{ key: 'user_id', placeholder: t('column.userId') },
|
||||
]}
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await filterCommissionLog({
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: filter?.search,
|
||||
date: (filter as any)?.date,
|
||||
user_id: (filter as any)?.user_id,
|
||||
});
|
||||
const list = (data?.data?.list || []) as any[];
|
||||
const total = Number(data?.data?.total || list.length);
|
||||
return { list, total };
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
'use client';
|
||||
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { filterEmailLog } from '@/services/admin/log';
|
||||
import { Badge } from '@workspace/ui/components/badge';
|
||||
import { formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function EmailLogPage() {
|
||||
const t = useTranslations('log');
|
||||
return (
|
||||
<ProTable<API.MessageLog, { search?: string }>
|
||||
header={{ title: t('title.email') }}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'id',
|
||||
header: t('column.id'),
|
||||
cell: ({ row }) => <Badge>{row.getValue('id')}</Badge>,
|
||||
},
|
||||
{ accessorKey: 'platform', header: t('column.platform') },
|
||||
{ accessorKey: 'to', header: t('column.to') },
|
||||
{ accessorKey: 'subject', header: t('column.subject') },
|
||||
{
|
||||
accessorKey: 'content',
|
||||
header: t('column.content'),
|
||||
cell: ({ row }) => (
|
||||
<pre className='max-w-[480px] overflow-auto whitespace-pre-wrap break-words text-xs'>
|
||||
{JSON.stringify(row.original.content || {}, null, 2)}
|
||||
</pre>
|
||||
),
|
||||
},
|
||||
{ accessorKey: 'status', header: t('column.status') },
|
||||
{
|
||||
accessorKey: 'created_at',
|
||||
header: t('column.createdAt'),
|
||||
cell: ({ row }) => formatDate(row.original.created_at),
|
||||
},
|
||||
]}
|
||||
params={[{ key: 'search' }, { key: 'date', type: 'date' }]}
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await filterEmailLog({
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: filter?.search,
|
||||
date: (filter as any)?.date,
|
||||
});
|
||||
const list = ((data?.data?.list || []) as API.MessageLog[]) || [];
|
||||
const total = Number(data?.data?.total || list.length);
|
||||
return { list, total };
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
'use client';
|
||||
|
||||
import { UserDetail } from '@/app/dashboard/user/user-detail';
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { filterGiftLog } from '@/services/admin/log';
|
||||
import { formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function GiftLogPage() {
|
||||
const t = useTranslations('log');
|
||||
return (
|
||||
<ProTable<API.GiftLog, { search?: string }>
|
||||
header={{ title: t('title.gift') }}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'user',
|
||||
header: t('column.user'),
|
||||
cell: ({ row }) => <UserDetail id={Number(row.original.user_id)} />,
|
||||
},
|
||||
{ accessorKey: 'subscribe_id', header: t('column.subscribeId') },
|
||||
{ accessorKey: 'order_no', header: t('column.orderNo') },
|
||||
{ accessorKey: 'amount', header: t('column.amount') },
|
||||
{ accessorKey: 'balance', header: t('column.balance') },
|
||||
{ accessorKey: 'remark', header: t('column.remark') },
|
||||
{
|
||||
accessorKey: 'created_at',
|
||||
header: t('column.createdAt'),
|
||||
cell: ({ row }) => formatDate(row.original.created_at),
|
||||
},
|
||||
]}
|
||||
params={[
|
||||
{ key: 'search' },
|
||||
{ key: 'date', type: 'date' },
|
||||
{ key: 'user_id', placeholder: t('column.userId') },
|
||||
]}
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await filterGiftLog({
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: filter?.search,
|
||||
date: (filter as any)?.date,
|
||||
user_id: (filter as any)?.user_id,
|
||||
});
|
||||
const list = (data?.data?.list || []) as any[];
|
||||
const total = Number(data?.data?.total || list.length);
|
||||
return { list, total };
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
'use client';
|
||||
|
||||
import { UserDetail } from '@/app/dashboard/user/user-detail';
|
||||
import { IpLink } from '@/components/ip-link';
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { filterLoginLog } from '@/services/admin/log';
|
||||
import { Badge } from '@workspace/ui/components/badge';
|
||||
import { formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function LoginLogPage() {
|
||||
const t = useTranslations('log');
|
||||
return (
|
||||
<ProTable<API.LoginLog, { search?: string }>
|
||||
header={{ title: t('title.login') }}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'user',
|
||||
header: t('column.user'),
|
||||
cell: ({ row }) => <UserDetail id={Number(row.original.user_id)} />,
|
||||
},
|
||||
{ accessorKey: 'method', header: t('column.method') },
|
||||
{
|
||||
accessorKey: 'login_ip',
|
||||
header: t('column.ip'),
|
||||
cell: ({ row }) => <IpLink ip={String((row.original as any).login_ip || '')} />,
|
||||
},
|
||||
{ accessorKey: 'user_agent', header: t('column.userAgent') },
|
||||
{
|
||||
accessorKey: 'success',
|
||||
header: t('column.success'),
|
||||
cell: ({ row }) => (
|
||||
<Badge variant={row.original.success ? 'default' : 'destructive'}>
|
||||
{row.original.success ? t('success') : t('failed')}
|
||||
</Badge>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'login_time',
|
||||
header: t('column.time'),
|
||||
cell: ({ row }) => formatDate(row.original.login_time),
|
||||
},
|
||||
]}
|
||||
params={[
|
||||
{ key: 'search' },
|
||||
{ key: 'date', type: 'date' },
|
||||
{ key: 'user_id', placeholder: t('column.userId') },
|
||||
]}
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await filterLoginLog({
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: filter?.search,
|
||||
date: (filter as any)?.date,
|
||||
user_id: (filter as any)?.user_id,
|
||||
});
|
||||
const list = ((data?.data?.list || []) as API.LoginLog[]) || [];
|
||||
const total = Number(data?.data?.total || list.length);
|
||||
return { list, total };
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
'use client';
|
||||
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { filterMobileLog } from '@/services/admin/log';
|
||||
import { Badge } from '@workspace/ui/components/badge';
|
||||
import { formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
export default function MobileLogPage() {
|
||||
const t = useTranslations('log');
|
||||
return (
|
||||
<ProTable<API.MessageLog, { search?: string }>
|
||||
header={{ title: t('title.mobile') }}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'id',
|
||||
header: t('column.id'),
|
||||
cell: ({ row }) => <Badge>{row.getValue('id')}</Badge>,
|
||||
},
|
||||
{ accessorKey: 'platform', header: t('column.platform') },
|
||||
{ accessorKey: 'to', header: t('column.to') },
|
||||
{ accessorKey: 'subject', header: t('column.subject') },
|
||||
{
|
||||
accessorKey: 'content',
|
||||
header: t('column.content'),
|
||||
cell: ({ row }) => (
|
||||
<pre className='max-w-[480px] overflow-auto whitespace-pre-wrap break-words text-xs'>
|
||||
{JSON.stringify(row.original.content || {}, null, 2)}
|
||||
</pre>
|
||||
),
|
||||
},
|
||||
{ accessorKey: 'status', header: t('column.status') },
|
||||
{
|
||||
accessorKey: 'created_at',
|
||||
header: t('column.createdAt'),
|
||||
cell: ({ row }) => formatDate(row.original.created_at),
|
||||
},
|
||||
]}
|
||||
params={[{ key: 'search' }, { key: 'date', type: 'date' }]}
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await filterMobileLog({
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: filter?.search,
|
||||
date: (filter as any)?.date,
|
||||
});
|
||||
const list = ((data?.data?.list || []) as API.MessageLog[]) || [];
|
||||
const total = Number(data?.data?.total || list.length);
|
||||
return { list, total };
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
'use client';
|
||||
|
||||
import { UserDetail } from '@/app/dashboard/user/user-detail';
|
||||
import { IpLink } from '@/components/ip-link';
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { filterRegisterLog } from '@/services/admin/log';
|
||||
import { formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function RegisterLogPage() {
|
||||
const t = useTranslations('log');
|
||||
return (
|
||||
<ProTable<API.RegisterLog, { search?: string }>
|
||||
header={{ title: t('title.register') }}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'user',
|
||||
header: t('column.user'),
|
||||
cell: ({ row }) => <UserDetail id={Number(row.original.user_id)} />,
|
||||
},
|
||||
{ accessorKey: 'auth_method', header: t('column.method') },
|
||||
{ accessorKey: 'identifier', header: t('column.identifier') },
|
||||
{
|
||||
accessorKey: 'register_ip',
|
||||
header: t('column.ip'),
|
||||
cell: ({ row }) => <IpLink ip={String((row.original as any).register_ip || '')} />,
|
||||
},
|
||||
{ accessorKey: 'user_agent', header: t('column.userAgent') },
|
||||
{
|
||||
accessorKey: 'register_time',
|
||||
header: t('column.time'),
|
||||
cell: ({ row }) => formatDate(row.original.register_time),
|
||||
},
|
||||
]}
|
||||
params={[
|
||||
{ key: 'search' },
|
||||
{ key: 'date', type: 'date' },
|
||||
{ key: 'user_id', placeholder: t('column.userId') },
|
||||
]}
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await filterRegisterLog({
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: filter?.search,
|
||||
date: (filter as any)?.date,
|
||||
user_id: (filter as any)?.user_id,
|
||||
});
|
||||
const list = (data?.data?.list || []) as any[];
|
||||
const total = Number(data?.data?.total || list.length);
|
||||
return { list, total };
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
'use client';
|
||||
|
||||
import { UserDetail } from '@/app/dashboard/user/user-detail';
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { filterResetSubscribeLog } from '@/services/admin/log';
|
||||
import { formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function ResetSubscribeLogPage() {
|
||||
const t = useTranslations('log');
|
||||
return (
|
||||
<ProTable<API.ResetSubscribeLog, { search?: string }>
|
||||
header={{ title: t('title.resetSubscribe') }}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'user',
|
||||
header: t('column.user'),
|
||||
cell: ({ row }) => <UserDetail id={Number(row.original.user_id)} />,
|
||||
},
|
||||
{ accessorKey: 'user_subscribe_id', header: t('column.subscribeId') },
|
||||
{ accessorKey: 'type', header: t('column.type') },
|
||||
{ accessorKey: 'order_no', header: t('column.orderNo') },
|
||||
{
|
||||
accessorKey: 'reset_at',
|
||||
header: t('column.resetAt'),
|
||||
cell: ({ row }) => formatDate(row.original.reset_at),
|
||||
},
|
||||
]}
|
||||
params={[
|
||||
{ key: 'search' },
|
||||
{ key: 'date', type: 'date' },
|
||||
{ key: 'user_subscribe_id', placeholder: t('column.subscribeId') },
|
||||
]}
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await filterResetSubscribeLog({
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: filter?.search,
|
||||
date: (filter as any)?.date,
|
||||
user_subscribe_id: (filter as any)?.user_subscribe_id,
|
||||
});
|
||||
const list = (data?.data?.list || []) as any[];
|
||||
const total = Number(data?.data?.total || list.length);
|
||||
return { list, total };
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
'use client';
|
||||
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { filterServerTrafficLog } from '@/services/admin/log';
|
||||
import { formatBytes } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function ServerTrafficLogPage() {
|
||||
const t = useTranslations('log');
|
||||
return (
|
||||
<ProTable<API.ServerTrafficLog, { search?: string }>
|
||||
header={{ title: t('title.serverTraffic') }}
|
||||
columns={[
|
||||
{ accessorKey: 'server_id', header: t('column.serverId') },
|
||||
{
|
||||
accessorKey: 'upload',
|
||||
header: t('column.upload'),
|
||||
cell: ({ row }) => formatBytes(row.original.upload),
|
||||
},
|
||||
{
|
||||
accessorKey: 'download',
|
||||
header: t('column.download'),
|
||||
cell: ({ row }) => formatBytes(row.original.download),
|
||||
},
|
||||
{
|
||||
accessorKey: 'total',
|
||||
header: t('column.total'),
|
||||
cell: ({ row }) => formatBytes(row.original.total),
|
||||
},
|
||||
{ accessorKey: 'date', header: t('column.date') },
|
||||
]}
|
||||
params={[
|
||||
{ key: 'search' },
|
||||
{ key: 'date', type: 'date' },
|
||||
{ key: 'server_id', placeholder: t('column.serverId') },
|
||||
]}
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await filterServerTrafficLog({
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: filter?.search,
|
||||
date: (filter as any)?.date,
|
||||
server_id: (filter as any)?.server_id,
|
||||
});
|
||||
const list = (data?.data?.list || []) as any[];
|
||||
const total = Number(data?.data?.total || list.length);
|
||||
return { list, total };
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
'use client';
|
||||
|
||||
import { UserDetail } from '@/app/dashboard/user/user-detail';
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { filterUserSubscribeTrafficLog } from '@/services/admin/log';
|
||||
import { formatBytes, formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function SubscribeTrafficLogPage() {
|
||||
const t = useTranslations('log');
|
||||
return (
|
||||
<ProTable<API.UserSubscribeTrafficLog, { search?: string }>
|
||||
header={{ title: t('title.subscribeTraffic') }}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'user',
|
||||
header: t('column.user'),
|
||||
cell: ({ row }) => <UserDetail id={Number(row.original.user_id)} />,
|
||||
},
|
||||
{ accessorKey: 'subscribe_id', header: t('column.subscribeId') },
|
||||
{
|
||||
accessorKey: 'upload',
|
||||
header: t('column.upload'),
|
||||
cell: ({ row }) => formatBytes(row.original.upload),
|
||||
},
|
||||
{
|
||||
accessorKey: 'download',
|
||||
header: t('column.download'),
|
||||
cell: ({ row }) => formatBytes(row.original.download),
|
||||
},
|
||||
{
|
||||
accessorKey: 'total',
|
||||
header: t('column.total'),
|
||||
cell: ({ row }) => formatBytes(row.original.total),
|
||||
},
|
||||
{
|
||||
accessorKey: 'date',
|
||||
header: t('column.date'),
|
||||
cell: ({ row }) => formatDate(new Date(row.original.date)),
|
||||
},
|
||||
]}
|
||||
params={[
|
||||
{ key: 'search' },
|
||||
{ key: 'date', type: 'date' },
|
||||
{ key: 'user_id', placeholder: t('column.userId') },
|
||||
{ key: 'user_subscribe_id', placeholder: t('column.subscribeId') },
|
||||
]}
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await filterUserSubscribeTrafficLog({
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: filter?.search,
|
||||
date: (filter as any)?.date,
|
||||
user_id: (filter as any)?.user_id,
|
||||
user_subscribe_id: (filter as any)?.user_subscribe_id,
|
||||
});
|
||||
const list = ((data?.data?.list || []) as API.UserSubscribeTrafficLog[]) || [];
|
||||
const total = Number(data?.data?.total || list.length);
|
||||
return { list, total };
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
'use client';
|
||||
|
||||
import { UserDetail } from '@/app/dashboard/user/user-detail';
|
||||
import { IpLink } from '@/components/ip-link';
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { filterSubscribeLog } from '@/services/admin/log';
|
||||
import { formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function SubscribeLogPage() {
|
||||
const t = useTranslations('log');
|
||||
return (
|
||||
<ProTable<API.SubscribeLog, { search?: string }>
|
||||
header={{ title: t('title.subscribe') }}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'user',
|
||||
header: t('column.user'),
|
||||
cell: ({ row }) => <UserDetail id={Number(row.original.user_id)} />,
|
||||
},
|
||||
{ accessorKey: 'user_subscribe_id', header: t('column.subscribeId') },
|
||||
{ accessorKey: 'token', header: t('column.token') },
|
||||
{
|
||||
accessorKey: 'client_ip',
|
||||
header: t('column.ip'),
|
||||
cell: ({ row }) => <IpLink ip={String((row.original as any).client_ip || '')} />,
|
||||
},
|
||||
{ accessorKey: 'user_agent', header: t('column.userAgent') },
|
||||
{
|
||||
accessorKey: 'subscribed_at',
|
||||
header: t('column.time'),
|
||||
cell: ({ row }) => formatDate(row.original.subscribed_at),
|
||||
},
|
||||
]}
|
||||
params={[
|
||||
{ key: 'search' },
|
||||
{ key: 'date', type: 'date' },
|
||||
{ key: 'user_id', placeholder: t('column.userId') },
|
||||
]}
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await filterSubscribeLog({
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: filter?.search,
|
||||
date: (filter as any)?.date,
|
||||
user_id: (filter as any)?.user_id,
|
||||
});
|
||||
const list = (data?.data?.list || []) as any[];
|
||||
const total = Number(data?.data?.total || list.length);
|
||||
return { list, total };
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
'use client';
|
||||
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { filterTrafficLogDetails } from '@/services/admin/log';
|
||||
import { formatBytes, formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function TrafficDetailsPage() {
|
||||
const t = useTranslations('log');
|
||||
return (
|
||||
<ProTable<any, { search?: string }>
|
||||
header={{ title: t('title.trafficDetails') }}
|
||||
columns={[
|
||||
{ accessorKey: 'server_id', header: t('column.serverId') },
|
||||
{ accessorKey: 'user_id', header: t('column.userId') },
|
||||
{ accessorKey: 'subscribe_id', header: t('column.subscribeId') },
|
||||
{
|
||||
accessorKey: 'upload',
|
||||
header: t('column.upload'),
|
||||
cell: ({ row }) => formatBytes(row.original.upload),
|
||||
},
|
||||
{
|
||||
accessorKey: 'download',
|
||||
header: t('column.download'),
|
||||
cell: ({ row }) => formatBytes(row.original.download),
|
||||
},
|
||||
{
|
||||
accessorKey: 'timestamp',
|
||||
header: t('column.time'),
|
||||
cell: ({ row }) => formatDate(row.original.timestamp),
|
||||
},
|
||||
]}
|
||||
params={[
|
||||
{ key: 'search' },
|
||||
{ key: 'date', type: 'date' },
|
||||
{ key: 'server_id', placeholder: t('column.serverId') },
|
||||
{ key: 'user_id', placeholder: t('column.userId') },
|
||||
{ key: 'subscribe_id', placeholder: t('column.subscribeId') },
|
||||
]}
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await filterTrafficLogDetails({
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: (filter as any)?.search,
|
||||
date: (filter as any)?.date,
|
||||
server_id: (filter as any)?.server_id,
|
||||
user_id: (filter as any)?.user_id,
|
||||
subscribe_id: (filter as any)?.subscribe_id,
|
||||
});
|
||||
const list = (data?.data?.list || []) as any[];
|
||||
const total = Number(data?.data?.total || list.length);
|
||||
return { list, total };
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user