mirror of
https://github.com/perfect-panel/ppanel-web.git
synced 2026-02-06 11:40:28 -05:00
✨ feat: Add log cleanup settings and update localization files
- Introduced log cleanup settings in the admin panel, allowing configuration of automatic log clearing and retention periods. - Updated English, Spanish, French, German, and other localization files to include new log cleanup settings. - Added new fields for referral percentage and first purchase only in user settings. - Implemented API endpoints for getting and updating log settings. - Enhanced the admin dashboard with a new log cleanup form component.
This commit is contained in:
parent
d4b37e4997
commit
6ccf9b8bdc
@ -6,6 +6,7 @@ import {
|
||||
deleteNode,
|
||||
filterNodeList,
|
||||
filterServerList,
|
||||
resetSortWithNode,
|
||||
toggleNodeStatus,
|
||||
updateNode,
|
||||
} from '@/services/admin/server';
|
||||
@ -235,6 +236,35 @@ export default function NodesPage() {
|
||||
];
|
||||
},
|
||||
}}
|
||||
onSort={async (source, target, items) => {
|
||||
const sourceIndex = items.findIndex((item) => String(item.id) === source);
|
||||
const targetIndex = items.findIndex((item) => String(item.id) === target);
|
||||
|
||||
const originalSorts = items.map((item) => item.sort);
|
||||
|
||||
const [movedItem] = items.splice(sourceIndex, 1);
|
||||
items.splice(targetIndex, 0, movedItem!);
|
||||
|
||||
const updatedItems = items.map((item, index) => {
|
||||
const originalSort = originalSorts[index];
|
||||
const newSort = originalSort !== undefined ? originalSort : item.sort;
|
||||
return { ...item, sort: newSort };
|
||||
});
|
||||
|
||||
const changedItems = updatedItems.filter((item, index) => {
|
||||
return item.sort !== items[index]?.sort;
|
||||
});
|
||||
|
||||
if (changedItems.length > 0) {
|
||||
resetSortWithNode({
|
||||
sort: changedItems.map((item) => ({
|
||||
id: item.id,
|
||||
sort: item.sort,
|
||||
})) as API.SortItem[],
|
||||
});
|
||||
}
|
||||
return updatedItems;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
import { UserDetail } from '@/app/dashboard/user/user-detail';
|
||||
import { IpLink } from '@/components/ip-link';
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { filterServerList } from '@/services/admin/server';
|
||||
import { getUserSubscribeById } from '@/services/admin/user';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Badge } from '@workspace/ui/components/badge';
|
||||
import {
|
||||
@ -13,55 +13,85 @@ import {
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from '@workspace/ui/components/sheet';
|
||||
import type { useTranslations } from 'next-intl';
|
||||
import { formatBytes, formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useState } from 'react';
|
||||
|
||||
function mapOnlineUsers(online: API.ServerStatus['online'] = []): {
|
||||
uid: string;
|
||||
ips: string[];
|
||||
subscribe?: string;
|
||||
subscribe_id?: number;
|
||||
traffic?: number;
|
||||
expired_at?: number;
|
||||
}[] {
|
||||
return (online || []).map((u) => ({
|
||||
uid: String(u.user_id || ''),
|
||||
ips: Array.isArray(u.ip) ? u.ip.map(String) : [],
|
||||
subscribe: (u as any).subscribe,
|
||||
subscribe_id: (u as any).subscribe_id,
|
||||
traffic: (u as any).traffic,
|
||||
expired_at: (u as any).expired_at,
|
||||
}));
|
||||
}
|
||||
|
||||
export default function OnlineUsersCell({
|
||||
serverId,
|
||||
status,
|
||||
t,
|
||||
function UserSubscribeInfo({
|
||||
subscribeId,
|
||||
open,
|
||||
type,
|
||||
}: {
|
||||
serverId?: number;
|
||||
status?: API.ServerStatus;
|
||||
t: ReturnType<typeof useTranslations>;
|
||||
subscribeId: number;
|
||||
open: boolean;
|
||||
type: 'account' | 'subscribeName' | 'subscribeId' | 'trafficUsage' | 'expireTime';
|
||||
}) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const { data: latest } = useQuery({
|
||||
queryKey: ['serverStatusById', serverId, open],
|
||||
enabled: !!serverId && open,
|
||||
const t = useTranslations('servers');
|
||||
const { data } = useQuery({
|
||||
enabled: subscribeId !== 0 && open,
|
||||
queryKey: ['getUserSubscribeById', subscribeId],
|
||||
queryFn: async () => {
|
||||
const { data } = await filterServerList({ page: 1, size: 1, search: String(serverId) });
|
||||
const list = (data?.data?.list || []) as API.Server[];
|
||||
return list[0]?.status as API.ServerStatus | undefined;
|
||||
const { data } = await getUserSubscribeById({ id: subscribeId });
|
||||
return data.data;
|
||||
},
|
||||
});
|
||||
|
||||
const rows = mapOnlineUsers((latest || status)?.online);
|
||||
const count = rows.length;
|
||||
if (!data) return <span className='text-muted-foreground'>--</span>;
|
||||
|
||||
switch (type) {
|
||||
case 'account':
|
||||
if (!data.user_id) return <span className='text-muted-foreground'>--</span>;
|
||||
return <UserDetail id={data.user_id} />;
|
||||
|
||||
case 'subscribeName':
|
||||
if (!data.subscribe?.name) return <span className='text-muted-foreground'>--</span>;
|
||||
return <span className='text-sm'>{data.subscribe.name}</span>;
|
||||
|
||||
case 'subscribeId':
|
||||
if (!data.id) return <span className='text-muted-foreground'>--</span>;
|
||||
return <span className='font-mono text-sm'>{data.id}</span>;
|
||||
|
||||
case 'trafficUsage': {
|
||||
const usedTraffic = data.upload + data.download;
|
||||
const totalTraffic = data.traffic || 0;
|
||||
return (
|
||||
<div className='min-w-0 text-sm'>
|
||||
<div className='break-words'>
|
||||
{formatBytes(usedTraffic)} / {totalTraffic > 0 ? formatBytes(totalTraffic) : '无限制'}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
case 'expireTime': {
|
||||
if (!data.expire_time) return <span className='text-muted-foreground'>--</span>;
|
||||
const isExpired = data.expire_time < Date.now() / 1000;
|
||||
return (
|
||||
<div className='flex flex-col gap-1 sm:flex-row sm:items-center sm:gap-2'>
|
||||
<span className='text-sm'>{formatDate(data.expire_time)}</span>
|
||||
{isExpired && (
|
||||
<Badge variant='destructive' className='w-fit px-1 py-0 text-xs'>
|
||||
{t('expired')}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
default:
|
||||
return <span className='text-muted-foreground'>--</span>;
|
||||
}
|
||||
}
|
||||
|
||||
export default function OnlineUsersCell({ status }: { status?: API.ServerStatus }) {
|
||||
const t = useTranslations('servers');
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
<SheetTrigger asChild>
|
||||
<button className='hover:text-foreground text-muted-foreground flex items-center gap-2 bg-transparent p-0 text-sm'>
|
||||
<Badge variant='secondary'>{count}</Badge>
|
||||
<Badge variant='secondary'>{status?.online.length}</Badge>
|
||||
<span>{t('onlineUsers')}</span>
|
||||
</button>
|
||||
</SheetTrigger>
|
||||
@ -70,36 +100,20 @@ export default function OnlineUsersCell({
|
||||
<SheetTitle>{t('onlineUsers')}</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className='-mx-6 h-[calc(100vh-48px-16px)] overflow-y-auto px-6 py-4 sm:h-[calc(100dvh-48px-16px-env(safe-area-inset-top))]'>
|
||||
<ProTable<
|
||||
{
|
||||
uid: string;
|
||||
ips: string[];
|
||||
subscribe?: string;
|
||||
subscribe_id?: number;
|
||||
traffic?: number;
|
||||
expired_at?: number;
|
||||
},
|
||||
Record<string, unknown>
|
||||
>
|
||||
<ProTable<API.ServerOnlineUser, Record<string, unknown>>
|
||||
header={{ hidden: true }}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'ips',
|
||||
accessorKey: 'ip',
|
||||
header: t('ipAddresses'),
|
||||
cell: ({ row }) => {
|
||||
const ips = row.original.ips;
|
||||
const ips = row.original.ip;
|
||||
return (
|
||||
<div className='flex min-w-0 flex-col gap-1'>
|
||||
{ips.map((ip, i) => (
|
||||
<div
|
||||
key={`${row.original.uid}-${ip}`}
|
||||
className='whitespace-nowrap text-sm'
|
||||
>
|
||||
{i === 0 ? (
|
||||
<IpLink ip={ip} className='font-medium' />
|
||||
) : (
|
||||
<IpLink ip={ip} className='text-muted-foreground' />
|
||||
)}
|
||||
{ips.map((item, i) => (
|
||||
<div className='whitespace-nowrap text-sm' key={i}>
|
||||
<Badge>{item.protocol}</Badge>
|
||||
<IpLink ip={item.ip} className='font-medium' />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@ -109,51 +123,63 @@ export default function OnlineUsersCell({
|
||||
{
|
||||
accessorKey: 'user',
|
||||
header: t('user'),
|
||||
cell: ({ row }) => <UserDetail id={Number(row.original.uid)} />,
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo
|
||||
subscribeId={Number(row.original.subscribe_id)}
|
||||
open={open}
|
||||
type='account'
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'subscription',
|
||||
header: t('subscription'),
|
||||
cell: ({ row }) => (
|
||||
<span className='text-sm'>{row.original.subscribe || '--'}</span>
|
||||
<UserSubscribeInfo
|
||||
subscribeId={Number(row.original.subscribe_id)}
|
||||
open={open}
|
||||
type='subscribeName'
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'subscribeId',
|
||||
header: t('subscribeId'),
|
||||
cell: ({ row }) => (
|
||||
<span className='font-mono text-sm'>{row.original.subscribe_id || '--'}</span>
|
||||
<UserSubscribeInfo
|
||||
subscribeId={Number(row.original.subscribe_id)}
|
||||
open={open}
|
||||
type='subscribeId'
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'traffic',
|
||||
header: t('traffic'),
|
||||
cell: ({ row }) => {
|
||||
const v = Number(row.original.traffic || 0);
|
||||
return <span className='text-sm'>{(v / 1024 ** 3).toFixed(2)} GB</span>;
|
||||
},
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo
|
||||
subscribeId={Number(row.original.subscribe_id)}
|
||||
open={open}
|
||||
type='trafficUsage'
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'expireTime',
|
||||
header: t('expireTime'),
|
||||
cell: ({ row }) => {
|
||||
const ts = Number(row.original.expired_at || 0);
|
||||
if (!ts) return <span className='text-muted-foreground'>--</span>;
|
||||
const expired = ts < Date.now() / 1000;
|
||||
return (
|
||||
<div className='flex items-center gap-2'>
|
||||
<span className='text-sm'>{new Date(ts * 1000).toLocaleString()}</span>
|
||||
{expired && (
|
||||
<Badge variant='destructive' className='w-fit px-1 py-0 text-xs'>
|
||||
{t('expired')}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo
|
||||
subscribeId={Number(row.original.subscribe_id)}
|
||||
open={open}
|
||||
type='expireTime'
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
request={async () => ({ list: rows, total: rows.length })}
|
||||
request={async () => ({
|
||||
list: status?.online || [],
|
||||
total: status?.online?.length || 0,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</SheetContent>
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
createServer,
|
||||
deleteServer,
|
||||
filterServerList,
|
||||
resetSortWithServer,
|
||||
updateServer,
|
||||
} from '@/services/admin/server';
|
||||
import { Badge } from '@workspace/ui/components/badge';
|
||||
@ -195,13 +196,7 @@ export default function ServersPage() {
|
||||
{
|
||||
id: 'online_users',
|
||||
header: t('onlineUsers'),
|
||||
cell: ({ row }) => (
|
||||
<OnlineUsersCell
|
||||
serverId={row.original.id}
|
||||
status={row.original.status as API.ServerStatus}
|
||||
t={t}
|
||||
/>
|
||||
),
|
||||
cell: ({ row }) => <OnlineUsersCell status={row.original.status as API.ServerStatus} />,
|
||||
},
|
||||
{
|
||||
id: 'traffic_ratio',
|
||||
@ -288,6 +283,35 @@ export default function ServersPage() {
|
||||
</Button>,
|
||||
],
|
||||
}}
|
||||
onSort={async (source, target, items) => {
|
||||
const sourceIndex = items.findIndex((item) => String(item.id) === source);
|
||||
const targetIndex = items.findIndex((item) => String(item.id) === target);
|
||||
|
||||
const originalSorts = items.map((item) => item.sort);
|
||||
|
||||
const [movedItem] = items.splice(sourceIndex, 1);
|
||||
items.splice(targetIndex, 0, movedItem!);
|
||||
|
||||
const updatedItems = items.map((item, index) => {
|
||||
const originalSort = originalSorts[index];
|
||||
const newSort = originalSort !== undefined ? originalSort : item.sort;
|
||||
return { ...item, sort: newSort };
|
||||
});
|
||||
|
||||
const changedItems = updatedItems.filter((item, index) => {
|
||||
return item.sort !== items[index]?.sort;
|
||||
});
|
||||
|
||||
if (changedItems.length > 0) {
|
||||
resetSortWithServer({
|
||||
sort: changedItems.map((item) => ({
|
||||
id: item.id,
|
||||
sort: item.sort,
|
||||
})) as API.SortItem[],
|
||||
});
|
||||
}
|
||||
return updatedItems;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
164
apps/admin/app/dashboard/system/log-cleanup/log-cleanup-form.tsx
Normal file
164
apps/admin/app/dashboard/system/log-cleanup/log-cleanup-form.tsx
Normal file
@ -0,0 +1,164 @@
|
||||
'use client';
|
||||
|
||||
import { getLogSetting, updateLogSetting } from '@/services/admin/log';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@workspace/ui/components/form';
|
||||
import { ScrollArea } from '@workspace/ui/components/scroll-area';
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from '@workspace/ui/components/sheet';
|
||||
import { Switch } from '@workspace/ui/components/switch';
|
||||
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
|
||||
import { Icon } from '@workspace/ui/custom-components/icon';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { toast } from 'sonner';
|
||||
import { z } from 'zod';
|
||||
|
||||
const logCleanupSchema = z.object({
|
||||
auto_clear: z.boolean(),
|
||||
clear_days: z.number().min(1),
|
||||
});
|
||||
|
||||
type LogCleanupFormData = z.infer<typeof logCleanupSchema>;
|
||||
|
||||
export default function LogCleanupForm() {
|
||||
const t = useTranslations('system');
|
||||
const [open, setOpen] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const { data, refetch } = useQuery({
|
||||
queryKey: ['getLogSetting'],
|
||||
queryFn: async () => {
|
||||
const { data } = await getLogSetting();
|
||||
return data.data;
|
||||
},
|
||||
enabled: open,
|
||||
});
|
||||
|
||||
const form = useForm<LogCleanupFormData>({
|
||||
resolver: zodResolver(logCleanupSchema),
|
||||
defaultValues: {
|
||||
auto_clear: false,
|
||||
clear_days: 30,
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
form.reset(data);
|
||||
}
|
||||
}, [data, form]);
|
||||
|
||||
async function onSubmit(values: LogCleanupFormData) {
|
||||
setLoading(true);
|
||||
try {
|
||||
await updateLogSetting(values as API.LogSetting);
|
||||
toast.success(t('common.saveSuccess'));
|
||||
refetch();
|
||||
setOpen(false);
|
||||
} catch (error) {
|
||||
toast.error(t('common.saveFailed'));
|
||||
} finally {
|
||||
setLoading(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:delete-sweep' className='text-primary h-5 w-5' />
|
||||
</div>
|
||||
<div className='flex-1'>
|
||||
<p className='font-medium'>{t('logCleanup.title')}</p>
|
||||
<p className='text-muted-foreground text-sm'>{t('logCleanup.description')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<Icon icon='mdi:chevron-right' className='size-6' />
|
||||
</div>
|
||||
</SheetTrigger>
|
||||
<SheetContent className='w-[600px] max-w-full md:max-w-screen-md'>
|
||||
<SheetHeader>
|
||||
<SheetTitle>{t('logCleanup.title')}</SheetTitle>
|
||||
</SheetHeader>
|
||||
<ScrollArea className='-mx-6 h-[calc(100dvh-48px-36px-36px-env(safe-area-inset-top))] px-6'>
|
||||
<Form {...form}>
|
||||
<form
|
||||
id='log-cleanup-form'
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className='space-y-2 pt-4'
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='auto_clear'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('logCleanup.autoClear')}</FormLabel>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
className='float-end !mt-0'
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>{t('logCleanup.autoClearDescription')}</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='clear_days'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('logCleanup.clearDays')}</FormLabel>
|
||||
<FormControl>
|
||||
<EnhancedInput
|
||||
type='number'
|
||||
placeholder={t('logCleanup.clearDaysPlaceholder')}
|
||||
value={field.value?.toString()}
|
||||
onValueChange={(value) => field.onChange(Number(value))}
|
||||
disabled={!form.watch('auto_clear')}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>{t('logCleanup.clearDaysDescription')}</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</form>
|
||||
</Form>
|
||||
</ScrollArea>
|
||||
<SheetFooter className='flex-row justify-end gap-2 pt-3'>
|
||||
<Button variant='outline' disabled={loading} onClick={() => setOpen(false)}>
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
<Button disabled={loading} type='submit' form='log-cleanup-form'>
|
||||
{loading && <Icon icon='mdi:loading' className='mr-2 animate-spin' />}
|
||||
{t('common.save')}
|
||||
</Button>
|
||||
</SheetFooter>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
}
|
||||
@ -6,6 +6,7 @@ import CurrencyForm from './basic-settings/currency-form';
|
||||
import PrivacyPolicyForm from './basic-settings/privacy-policy-form';
|
||||
import SiteForm from './basic-settings/site-form';
|
||||
import TosForm from './basic-settings/tos-form';
|
||||
import LogCleanupForm from './log-cleanup/log-cleanup-form';
|
||||
import InviteForm from './user-security/invite-form';
|
||||
import RegisterForm from './user-security/register-form';
|
||||
import VerifyCodeForm from './user-security/verify-code-form';
|
||||
@ -14,7 +15,6 @@ import VerifyForm from './user-security/verify-form';
|
||||
export default function Page() {
|
||||
const t = useTranslations('system');
|
||||
|
||||
// 定义表单配置
|
||||
const formSections = [
|
||||
{
|
||||
title: t('basicSettings'),
|
||||
@ -34,6 +34,10 @@ export default function Page() {
|
||||
{ component: VerifyCodeForm },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: t('logSettings'),
|
||||
forms: [{ component: LogCleanupForm }],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
|
||||
@ -58,6 +58,8 @@ export default function UserForm<T extends Record<string, any>>({
|
||||
password: z.string().optional(),
|
||||
referer_id: z.number().optional(),
|
||||
refer_code: z.string().optional(),
|
||||
referral_percentage: z.number().optional(),
|
||||
only_first_purchase: z.boolean().optional(),
|
||||
is_admin: z.boolean().optional(),
|
||||
balance: z.number().optional(),
|
||||
gift_amount: z.number().optional(),
|
||||
@ -218,6 +220,41 @@ export default function UserForm<T extends Record<string, any>>({
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='referral_percentage'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('referralPercentage')}</FormLabel>
|
||||
<FormControl>
|
||||
<EnhancedInput
|
||||
type='number'
|
||||
min={0}
|
||||
max={100}
|
||||
placeholder={t('referralPercentagePlaceholder')}
|
||||
{...field}
|
||||
suffix='%'
|
||||
onValueChange={(value) => {
|
||||
form.setValue(field.name, Number(value));
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='only_first_purchase'
|
||||
render={({ field }) => (
|
||||
<FormItem className='flex items-center justify-between space-x-2'>
|
||||
<FormLabel>{t('onlyFirstPurchase')}</FormLabel>
|
||||
<FormControl>
|
||||
<Switch checked={field.value} onCheckedChange={field.onChange} />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='balance'
|
||||
|
||||
@ -30,6 +30,8 @@ const basicInfoSchema = z.object({
|
||||
gift_amount: z.number().optional(),
|
||||
refer_code: z.string().optional(),
|
||||
referer_id: z.number().optional(),
|
||||
referral_percentage: z.number().optional(),
|
||||
only_first_purchase: z.boolean().optional(),
|
||||
is_admin: z.boolean().optional(),
|
||||
password: z.string().optional(),
|
||||
enable: z.boolean(),
|
||||
@ -52,6 +54,8 @@ export function BasicInfoForm({ user, refetch }: { user: API.User; refetch: () =
|
||||
gift_amount: user.gift_amount,
|
||||
refer_code: user.refer_code,
|
||||
referer_id: user.referer_id,
|
||||
referral_percentage: user.referral_percentage,
|
||||
only_first_purchase: user.only_first_purchase,
|
||||
is_admin: user.is_admin,
|
||||
enable: user.enable,
|
||||
},
|
||||
@ -216,6 +220,41 @@ export function BasicInfoForm({ user, refetch }: { user: API.User; refetch: () =
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='referral_percentage'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('referralPercentage')}</FormLabel>
|
||||
<FormControl>
|
||||
<EnhancedInput
|
||||
type='number'
|
||||
min={0}
|
||||
max={100}
|
||||
value={field.value}
|
||||
suffix='%'
|
||||
onValueChange={(value) => {
|
||||
form.setValue(field.name, value as number);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='only_first_purchase'
|
||||
render={({ field }) => (
|
||||
<FormItem className='flex items-center justify-between space-x-2'>
|
||||
<FormLabel>{t('onlyFirstPurchase')}</FormLabel>
|
||||
<FormControl>
|
||||
<Switch checked={field.value} onCheckedChange={field.onChange} />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='avatar'
|
||||
|
||||
@ -79,8 +79,8 @@ export default function Statistics() {
|
||||
<div className='grid grid-cols-2 gap-2 md:grid-cols-4'>
|
||||
{[
|
||||
{
|
||||
title: t('onlineIPCount'),
|
||||
value: ServerTotal?.online_user_ips || 0,
|
||||
title: t('onlineUsersCount'),
|
||||
value: ServerTotal?.online_users || 0,
|
||||
icon: 'uil:users-alt',
|
||||
href: '/dashboard/servers',
|
||||
},
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Provoz uzlu",
|
||||
"nodes": "uzly",
|
||||
"offlineNodeCount": "Počet offline uzlů",
|
||||
"onlineIPCount": "Počet online IP",
|
||||
"onlineNodeCount": "Počet online uzlů",
|
||||
"onlineUsersCount": "Uživatelé online",
|
||||
"pendingTickets": "Čekající lístky",
|
||||
"register": "Registrovat se",
|
||||
"repurchase": "opětovný nákup",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Uložení úspěšné",
|
||||
"title": "Nastavení pozvánek"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Povolit automatické čištění",
|
||||
"autoClearDescription": "Pokud je povoleno, systém automaticky vymaže vypršené záznamy protokolů",
|
||||
"clearDays": "Dny uchovávání",
|
||||
"clearDaysDescription": "Počet dní pro uchovávání protokolů; protokoly starší než toto budou vyčištěny",
|
||||
"clearDaysPlaceholder": "Zadejte dny uchovávání",
|
||||
"description": "Nastavte pravidla automatického čištění protokolů a dobu uchovávání",
|
||||
"title": "Nastavení čištění protokolů"
|
||||
},
|
||||
"logSettings": "Nastavení protokolů",
|
||||
"privacyPolicy": {
|
||||
"description": "Upravte a spravujte obsah zásad ochrany osobních údajů",
|
||||
"title": "Zásady ochrany osobních údajů"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Více",
|
||||
"notifySettingsTitle": "Nastavení oznámení",
|
||||
"onlineDevices": "Online zařízení",
|
||||
"onlyFirstPurchase": "Pouze první nákup",
|
||||
"orderList": "Seznam objednávek",
|
||||
"password": "Heslo",
|
||||
"passwordPlaceholder": "Zadejte nové heslo (volitelné)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "ID doporučitele",
|
||||
"refererIdPlaceholder": "Zadejte ID doporučitele",
|
||||
"referralCode": "Doporučovací kód",
|
||||
"referralPercentage": "Procento doporučení",
|
||||
"referralPercentagePlaceholder": "Zadejte procento doporučení (0-100)",
|
||||
"referrerUserId": "Odesílatel (uživatelské ID)",
|
||||
"remove": "Odstranit",
|
||||
"resetLogs": "Protokoly resetování",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Knotenverkehr",
|
||||
"nodes": "Knoten",
|
||||
"offlineNodeCount": "Anzahl der Offline-Knoten",
|
||||
"onlineIPCount": "Online-IP-Anzahl",
|
||||
"onlineNodeCount": "Anzahl der Online-Knoten",
|
||||
"onlineUsersCount": "Online-Benutzer",
|
||||
"pendingTickets": "Ausstehende Tickets",
|
||||
"register": "Registrieren",
|
||||
"repurchase": "Wiederkauf",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Speichern erfolgreich",
|
||||
"title": "Einladungseinstellungen"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Automatische Bereinigung aktivieren",
|
||||
"autoClearDescription": "Wenn aktiviert, wird das System abgelaufene Protokolle automatisch löschen",
|
||||
"clearDays": "Aufbewahrungstage",
|
||||
"clearDaysDescription": "Anzahl der Tage, an denen Protokolle aufbewahrt werden; Protokolle, die älter sind als dies, werden gelöscht",
|
||||
"clearDaysPlaceholder": "Geben Sie die Aufbewahrungstage ein",
|
||||
"description": "Konfigurieren Sie automatische Protokollbereinigungsregeln und Aufbewahrungsfristen",
|
||||
"title": "Protokollbereinigungseinstellungen"
|
||||
},
|
||||
"logSettings": "Protokolleinstellungen",
|
||||
"privacyPolicy": {
|
||||
"description": "Bearbeiten und verwalten Sie den Inhalt der Datenschutzrichtlinie",
|
||||
"title": "Datenschutzrichtlinie"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Mehr",
|
||||
"notifySettingsTitle": "Benachrichtigungseinstellungen",
|
||||
"onlineDevices": "Online-Geräte",
|
||||
"onlyFirstPurchase": "Nur Erstkäufe",
|
||||
"orderList": "Bestellliste",
|
||||
"password": "Passwort",
|
||||
"passwordPlaceholder": "Neues Passwort eingeben (optional)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "Referenz-ID",
|
||||
"refererIdPlaceholder": "Geben Sie die Referenz-ID ein",
|
||||
"referralCode": "Empfehlungscode",
|
||||
"referralPercentage": "Empfehlungsprozent",
|
||||
"referralPercentagePlaceholder": "Geben Sie den Empfehlungsprozentsatz ein (0-100)",
|
||||
"referrerUserId": "Empfehler (Benutzer-ID)",
|
||||
"remove": "Entfernen",
|
||||
"resetLogs": "Zurücksetzprotokolle",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Node Traffic",
|
||||
"nodes": "Nodes",
|
||||
"offlineNodeCount": "Offline Nodes",
|
||||
"onlineIPCount": "Online IPs",
|
||||
"onlineNodeCount": "Online Nodes",
|
||||
"onlineUsersCount": "Online Users",
|
||||
"pendingTickets": "Pending Tickets",
|
||||
"register": "Register",
|
||||
"repurchase": "Repurchase",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Save Successful",
|
||||
"saveFailed": "Save Failed"
|
||||
},
|
||||
"logCleanup": {
|
||||
"title": "Log Cleanup Settings",
|
||||
"description": "Configure automatic log cleanup rules and retention period",
|
||||
"autoClear": "Enable Auto Cleanup",
|
||||
"autoClearDescription": "When enabled, the system will automatically clear expired log records",
|
||||
"clearDays": "Retention Days",
|
||||
"clearDaysDescription": "Number of days to retain logs; logs older than this will be cleaned up",
|
||||
"clearDaysPlaceholder": "Enter retention days"
|
||||
},
|
||||
"logSettings": "Log Settings",
|
||||
"privacyPolicy": {
|
||||
"title": "Privacy Policy",
|
||||
"description": "Edit and manage privacy policy content"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "More",
|
||||
"notifySettingsTitle": "Notification Settings",
|
||||
"onlineDevices": "Online Devices",
|
||||
"onlyFirstPurchase": "First Purchase Only",
|
||||
"orderList": "Order List",
|
||||
"password": "Password",
|
||||
"passwordPlaceholder": "Enter new password (optional)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "Referer ID",
|
||||
"refererIdPlaceholder": "Enter referer ID",
|
||||
"referralCode": "Referral Code",
|
||||
"referralPercentage": "Referral Percentage",
|
||||
"referralPercentagePlaceholder": "Enter referral percentage (0-100)",
|
||||
"referrerUserId": "Referrer (User ID)",
|
||||
"remove": "Remove",
|
||||
"resetLogs": "Reset Logs",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Tráfico de nodo",
|
||||
"nodes": "nodos",
|
||||
"offlineNodeCount": "Número de nodos fuera de línea",
|
||||
"onlineIPCount": "Número de IPs en línea",
|
||||
"onlineNodeCount": "Número de nodos en línea",
|
||||
"onlineUsersCount": "Usuarios en línea",
|
||||
"pendingTickets": "Tickets pendientes",
|
||||
"register": "registrar",
|
||||
"repurchase": "recompra",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Guardado Exitoso",
|
||||
"title": "Configuración de Invitaciones"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Habilitar limpieza automática",
|
||||
"autoClearDescription": "Cuando está habilitado, el sistema eliminará automáticamente los registros de log expirados",
|
||||
"clearDays": "Días de retención",
|
||||
"clearDaysDescription": "Número de días para retener los registros; los registros más antiguos que esto serán eliminados",
|
||||
"clearDaysPlaceholder": "Introduce los días de retención",
|
||||
"description": "Configura las reglas de limpieza automática de registros y el período de retención",
|
||||
"title": "Configuración de limpieza de registros"
|
||||
},
|
||||
"logSettings": "Configuración de registros",
|
||||
"privacyPolicy": {
|
||||
"description": "Editar y gestionar el contenido de la política de privacidad",
|
||||
"title": "Política de Privacidad"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Más",
|
||||
"notifySettingsTitle": "Configuración de Notificaciones",
|
||||
"onlineDevices": "Dispositivos en línea",
|
||||
"onlyFirstPurchase": "Solo Primera Compra",
|
||||
"orderList": "Lista de Pedidos",
|
||||
"password": "Contraseña",
|
||||
"passwordPlaceholder": "Ingrese nueva contraseña (opcional)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "ID del Referente",
|
||||
"refererIdPlaceholder": "Ingrese el ID del referente",
|
||||
"referralCode": "Código de Referencia",
|
||||
"referralPercentage": "Porcentaje de Referencia",
|
||||
"referralPercentagePlaceholder": "Introduce el porcentaje de referencia (0-100)",
|
||||
"referrerUserId": "Referente (ID de usuario)",
|
||||
"remove": "Eliminar",
|
||||
"resetLogs": "Registros de Reinicio",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Tráfico de nodo",
|
||||
"nodes": "nodos",
|
||||
"offlineNodeCount": "Número de nodos fuera de línea",
|
||||
"onlineIPCount": "Número de IPs en línea",
|
||||
"onlineNodeCount": "Número de nodos en línea",
|
||||
"onlineUsersCount": "Usuarios en línea",
|
||||
"pendingTickets": "Tickets pendientes",
|
||||
"register": "Registrarse",
|
||||
"repurchase": "recompra",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Guardado Exitoso",
|
||||
"title": "Configuración de Invitaciones"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Habilitar Limpieza Automática",
|
||||
"autoClearDescription": "Cuando está habilitado, el sistema eliminará automáticamente los registros de log expirados",
|
||||
"clearDays": "Días de Retención",
|
||||
"clearDaysDescription": "Número de días para retener los registros; los registros más antiguos que esto serán eliminados",
|
||||
"clearDaysPlaceholder": "Ingresa los días de retención",
|
||||
"description": "Configura las reglas de limpieza automática de registros y el período de retención",
|
||||
"title": "Configuración de Limpieza de Registros"
|
||||
},
|
||||
"logSettings": "Configuración de Registros",
|
||||
"privacyPolicy": {
|
||||
"description": "Editar y gestionar el contenido de la política de privacidad",
|
||||
"title": "Política de Privacidad"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Más",
|
||||
"notifySettingsTitle": "Configuración de Notificaciones",
|
||||
"onlineDevices": "Dispositivos en línea",
|
||||
"onlyFirstPurchase": "Solo Primera Compra",
|
||||
"orderList": "Lista de Pedidos",
|
||||
"password": "Contraseña",
|
||||
"passwordPlaceholder": "Ingresa nueva contraseña (opcional)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "ID del Referente",
|
||||
"refererIdPlaceholder": "Ingrese ID del referente",
|
||||
"referralCode": "Código de Referencia",
|
||||
"referralPercentage": "Porcentaje de Referencia",
|
||||
"referralPercentagePlaceholder": "Ingresa el porcentaje de referencia (0-100)",
|
||||
"referrerUserId": "Referente (ID de Usuario)",
|
||||
"remove": "Eliminar",
|
||||
"resetLogs": "Registros de Reinicio",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "ترافیک نود",
|
||||
"nodes": "گرهها",
|
||||
"offlineNodeCount": "گرههای آفلاین",
|
||||
"onlineIPCount": "آیپیهای آنلاین",
|
||||
"onlineNodeCount": "گرههای آنلاین",
|
||||
"onlineUsersCount": "کاربران آنلاین",
|
||||
"pendingTickets": "بلیطهای در انتظار",
|
||||
"register": "ثبت نام",
|
||||
"repurchase": "بازخرید",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "ذخیره با موفقیت انجام شد",
|
||||
"title": "تنظیمات دعوتنامه"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "فعالسازی پاکسازی خودکار",
|
||||
"autoClearDescription": "با فعالسازی این گزینه، سیستم بهطور خودکار رکوردهای لاگ منقضی شده را پاک میکند",
|
||||
"clearDays": "روزهای نگهداری",
|
||||
"clearDaysDescription": "تعداد روزهایی که لاگها نگهداری میشوند؛ لاگهای قدیمیتر از این مدت پاک خواهند شد",
|
||||
"clearDaysPlaceholder": "تعداد روزهای نگهداری را وارد کنید",
|
||||
"description": "پیکربندی قوانین پاکسازی خودکار لاگ و دوره نگهداری",
|
||||
"title": "تنظیمات پاکسازی لاگ"
|
||||
},
|
||||
"logSettings": "تنظیمات لاگ",
|
||||
"privacyPolicy": {
|
||||
"description": "محتوای سیاست حفظ حریم خصوصی را ویرایش و مدیریت کنید",
|
||||
"title": "سیاست حفظ حریم خصوصی"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "بیشتر",
|
||||
"notifySettingsTitle": "تنظیمات اعلانها",
|
||||
"onlineDevices": "دستگاههای آنلاین",
|
||||
"onlyFirstPurchase": "فقط خرید اول",
|
||||
"orderList": "لیست سفارشات",
|
||||
"password": "رمز عبور",
|
||||
"passwordPlaceholder": "رمز عبور جدید را وارد کنید (اختیاری)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "شناسه معرف",
|
||||
"refererIdPlaceholder": "شناسه معرف را وارد کنید",
|
||||
"referralCode": "کد ارجاع",
|
||||
"referralPercentage": "درصد ارجاع",
|
||||
"referralPercentagePlaceholder": "درصد ارجاع را وارد کنید (۰-۱۰۰)",
|
||||
"referrerUserId": "ارجاعدهنده (شناسه کاربر)",
|
||||
"remove": "حذف",
|
||||
"resetLogs": "گزارشات بازنشانی",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Solmun liikenne",
|
||||
"nodes": "solmut",
|
||||
"offlineNodeCount": "Offline-solmujen määrä",
|
||||
"onlineIPCount": "Verkossa olevien IP-osoitteiden määrä",
|
||||
"onlineNodeCount": "Verkossa olevien solmujen määrä",
|
||||
"onlineUsersCount": "Verkkokäyttäjät",
|
||||
"pendingTickets": "Odottavat liput",
|
||||
"register": "Rekisteröidy",
|
||||
"repurchase": "uudelleenosto",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Tallennus onnistui",
|
||||
"title": "Kutsuasetukset"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Ota automaattinen puhdistus käyttöön",
|
||||
"autoClearDescription": "Kun tämä on käytössä, järjestelmä puhdistaa automaattisesti vanhentuneet lokitiedot",
|
||||
"clearDays": "Säilytyspäivät",
|
||||
"clearDaysDescription": "Päivien määrä, jolloin lokit säilytetään; tätä vanhemmat lokit poistetaan",
|
||||
"clearDaysPlaceholder": "Syötä säilytyspäivät",
|
||||
"description": "Määritä automaattiset lokin puhdistus säännöt ja säilytysaika",
|
||||
"title": "Lokin puhdistuksen asetukset"
|
||||
},
|
||||
"logSettings": "Lokiasetukset",
|
||||
"privacyPolicy": {
|
||||
"description": "Muokkaa ja hallinnoi tietosuojakäytännön sisältöä",
|
||||
"title": "Tietosuojakäytäntö"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Lisää",
|
||||
"notifySettingsTitle": "Ilmoitusasetukset",
|
||||
"onlineDevices": "Verkossa olevat laitteet",
|
||||
"onlyFirstPurchase": "Vain ensimmäinen ostos",
|
||||
"orderList": "Tilaukset",
|
||||
"password": "Salasana",
|
||||
"passwordPlaceholder": "Syötä uusi salasana (valinnainen)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "Viittaajan ID",
|
||||
"refererIdPlaceholder": "Syötä suosittelijan ID",
|
||||
"referralCode": "Suosituskoodi",
|
||||
"referralPercentage": "Suositusprosentti",
|
||||
"referralPercentagePlaceholder": "Syötä suositusprosentti (0-100)",
|
||||
"referrerUserId": "Viittaaja (Käyttäjän ID)",
|
||||
"remove": "Poista",
|
||||
"resetLogs": "Nollauslokit",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Trafic du nœud",
|
||||
"nodes": "nœuds",
|
||||
"offlineNodeCount": "Nombre de nœuds hors ligne",
|
||||
"onlineIPCount": "Nombre d'IP en ligne",
|
||||
"onlineNodeCount": "Nombre de nœuds en ligne",
|
||||
"onlineUsersCount": "Utilisateurs en ligne",
|
||||
"pendingTickets": "Tickets en attente",
|
||||
"register": "S'inscrire",
|
||||
"repurchase": "Rachat",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Enregistrement réussi",
|
||||
"title": "Paramètres d'invitation"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Activer le nettoyage automatique",
|
||||
"autoClearDescription": "Lorsque cette option est activée, le système supprimera automatiquement les enregistrements de journaux expirés",
|
||||
"clearDays": "Jours de conservation",
|
||||
"clearDaysDescription": "Nombre de jours pour conserver les journaux ; les journaux plus anciens seront supprimés",
|
||||
"clearDaysPlaceholder": "Entrez le nombre de jours de conservation",
|
||||
"description": "Configurer les règles de nettoyage automatique des journaux et la période de conservation",
|
||||
"title": "Paramètres de nettoyage des journaux"
|
||||
},
|
||||
"logSettings": "Paramètres des journaux",
|
||||
"privacyPolicy": {
|
||||
"description": "Modifier et gérer le contenu de la politique de confidentialité",
|
||||
"title": "Politique de confidentialité"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Plus",
|
||||
"notifySettingsTitle": "Paramètres de notification",
|
||||
"onlineDevices": "Appareils en ligne",
|
||||
"onlyFirstPurchase": "Premier achat uniquement",
|
||||
"orderList": "Liste des commandes",
|
||||
"password": "Mot de passe",
|
||||
"passwordPlaceholder": "Entrez un nouveau mot de passe (facultatif)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "ID du référent",
|
||||
"refererIdPlaceholder": "Entrez l'ID du référent",
|
||||
"referralCode": "Code de parrainage",
|
||||
"referralPercentage": "Pourcentage de parrainage",
|
||||
"referralPercentagePlaceholder": "Entrez le pourcentage de parrainage (0-100)",
|
||||
"referrerUserId": "Référent (ID utilisateur)",
|
||||
"remove": "Supprimer",
|
||||
"resetLogs": "Journaux de réinitialisation",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "नोड ट्रैफिक",
|
||||
"nodes": "नोड्स",
|
||||
"offlineNodeCount": "ऑफ़लाइन नोड की संख्या",
|
||||
"onlineIPCount": "ऑनलाइन IP संख्या",
|
||||
"onlineNodeCount": "ऑनलाइन नोड की संख्या",
|
||||
"onlineUsersCount": "ऑनलाइन उपयोगकर्ता",
|
||||
"pendingTickets": "लंबित टिकट",
|
||||
"register": "पंजीकरण",
|
||||
"repurchase": "पुनः खरीद",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "सहेजना सफल",
|
||||
"title": "आमंत्रण सेटिंग्स"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "स्वचालित क्लीनअप सक्षम करें",
|
||||
"autoClearDescription": "जब सक्षम किया जाता है, तो सिस्टम स्वचालित रूप से समाप्त लॉग रिकॉर्ड को साफ करेगा",
|
||||
"clearDays": "संरक्षण दिन",
|
||||
"clearDaysDescription": "लॉग को बनाए रखने के लिए दिनों की संख्या; इससे पुराने लॉग को साफ किया जाएगा",
|
||||
"clearDaysPlaceholder": "संरक्षण दिन दर्ज करें",
|
||||
"description": "स्वचालित लॉग क्लीनअप नियम और संरक्षण अवधि कॉन्फ़िगर करें",
|
||||
"title": "लॉग क्लीनअप सेटिंग्स"
|
||||
},
|
||||
"logSettings": "लॉग सेटिंग्स",
|
||||
"privacyPolicy": {
|
||||
"description": "गोपनीयता नीति सामग्री को संपादित और प्रबंधित करें",
|
||||
"title": "गोपनीयता नीति"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "और",
|
||||
"notifySettingsTitle": "सूचना सेटिंग्स",
|
||||
"onlineDevices": "ऑनलाइन डिवाइस",
|
||||
"onlyFirstPurchase": "पहली खरीदारी केवल",
|
||||
"orderList": "ऑर्डर सूची",
|
||||
"password": "पासवर्ड",
|
||||
"passwordPlaceholder": "नया पासवर्ड दर्ज करें (वैकल्पिक)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "रेफरर आईडी",
|
||||
"refererIdPlaceholder": "रेफरर आईडी दर्ज करें",
|
||||
"referralCode": "रेफरल कोड",
|
||||
"referralPercentage": "रेफरल प्रतिशत",
|
||||
"referralPercentagePlaceholder": "रेफरल प्रतिशत दर्ज करें (0-100)",
|
||||
"referrerUserId": "रेफरर (उपयोगकर्ता आईडी)",
|
||||
"remove": "हटाएं",
|
||||
"resetLogs": "रीसेट लॉग",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Csomópont forgalom",
|
||||
"nodes": "csomópontok",
|
||||
"offlineNodeCount": "Offline csomópontok száma",
|
||||
"onlineIPCount": "Online IP-szám",
|
||||
"onlineNodeCount": "Online csomópontok száma",
|
||||
"onlineUsersCount": "Online Felhasználók",
|
||||
"pendingTickets": "Függőben lévő jegyek",
|
||||
"register": "Regisztráció",
|
||||
"repurchase": "újravásárlás",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Mentés sikeres",
|
||||
"title": "Meghívási beállítások"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Automatikus Tisztítás Engedélyezése",
|
||||
"autoClearDescription": "Ha engedélyezve van, a rendszer automatikusan törli a lejárt naplóbejegyzéseket",
|
||||
"clearDays": "Megőrzési Napok",
|
||||
"clearDaysDescription": "A naplók megőrzésének napjai; a régebbi naplók törlésre kerülnek",
|
||||
"clearDaysPlaceholder": "Adja meg a megőrzési napokat",
|
||||
"description": "Automatikus napló tisztítási szabályok és megőrzési időszak konfigurálása",
|
||||
"title": "Napló Tisztítási Beállítások"
|
||||
},
|
||||
"logSettings": "Napló Beállítások",
|
||||
"privacyPolicy": {
|
||||
"description": "Adatvédelmi irányelvek tartalmának szerkesztése és kezelése",
|
||||
"title": "Adatvédelmi irányelvek"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Több",
|
||||
"notifySettingsTitle": "Értesítési beállítások",
|
||||
"onlineDevices": "Online eszközök",
|
||||
"onlyFirstPurchase": "Csak első vásárlás",
|
||||
"orderList": "Rendelések listája",
|
||||
"password": "Jelszó",
|
||||
"passwordPlaceholder": "Adjon meg új jelszót (opcionális)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "Hivatkozó azonosító",
|
||||
"refererIdPlaceholder": "Adja meg az ajánló azonosítóját",
|
||||
"referralCode": "Ajánlókód",
|
||||
"referralPercentage": "Ajánlási százalék",
|
||||
"referralPercentagePlaceholder": "Írd be az ajánlási százalékot (0-100)",
|
||||
"referrerUserId": "Ajánló (Felhasználói azonosító)",
|
||||
"remove": "Eltávolítás",
|
||||
"resetLogs": "Visszaállítási naplók",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "ノードトラフィック",
|
||||
"nodes": "ノード",
|
||||
"offlineNodeCount": "オフラインノード数",
|
||||
"onlineIPCount": "オンラインIP数",
|
||||
"onlineNodeCount": "オンラインノード数",
|
||||
"onlineUsersCount": "オンラインユーザー",
|
||||
"pendingTickets": "保留中のチケット",
|
||||
"register": "登録",
|
||||
"repurchase": "再購入",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "保存成功",
|
||||
"title": "招待設定"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "自動クリーンアップを有効にする",
|
||||
"autoClearDescription": "有効にすると、システムは期限切れのログレコードを自動的にクリアします",
|
||||
"clearDays": "保持日数",
|
||||
"clearDaysDescription": "ログを保持する日数; これを超える古いログはクリーンアップされます",
|
||||
"clearDaysPlaceholder": "保持日数を入力してください",
|
||||
"description": "自動ログクリーンアップルールと保持期間を設定します",
|
||||
"title": "ログクリーンアップ設定"
|
||||
},
|
||||
"logSettings": "ログ設定",
|
||||
"privacyPolicy": {
|
||||
"description": "プライバシーポリシーの内容を編集・管理します",
|
||||
"title": "プライバシーポリシー"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "もっと見る",
|
||||
"notifySettingsTitle": "通知設定",
|
||||
"onlineDevices": "オンラインデバイス",
|
||||
"onlyFirstPurchase": "初回購入のみ",
|
||||
"orderList": "注文リスト",
|
||||
"password": "パスワード",
|
||||
"passwordPlaceholder": "新しいパスワードを入力してください(任意)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "リファラーID",
|
||||
"refererIdPlaceholder": "紹介者IDを入力してください",
|
||||
"referralCode": "紹介コード",
|
||||
"referralPercentage": "紹介割合",
|
||||
"referralPercentagePlaceholder": "紹介割合を入力してください(0-100)",
|
||||
"referrerUserId": "紹介者(ユーザーID)",
|
||||
"remove": "削除",
|
||||
"resetLogs": "リセット履歴",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "노드 트래픽",
|
||||
"nodes": "노드",
|
||||
"offlineNodeCount": "오프라인 노드 수",
|
||||
"onlineIPCount": "온라인 IP 수",
|
||||
"onlineNodeCount": "온라인 노드 수",
|
||||
"onlineUsersCount": "온라인 사용자",
|
||||
"pendingTickets": "처리 대기 중인 티켓",
|
||||
"register": "등록",
|
||||
"repurchase": "재구매",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "저장 성공",
|
||||
"title": "초대 설정"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "자동 정리 활성화",
|
||||
"autoClearDescription": "활성화되면 시스템이 만료된 로그 기록을 자동으로 삭제합니다",
|
||||
"clearDays": "보존 일수",
|
||||
"clearDaysDescription": "로그를 보존할 일수; 이보다 오래된 로그는 삭제됩니다",
|
||||
"clearDaysPlaceholder": "보존 일수를 입력하세요",
|
||||
"description": "자동 로그 정리 규칙 및 보존 기간 구성",
|
||||
"title": "로그 정리 설정"
|
||||
},
|
||||
"logSettings": "로그 설정",
|
||||
"privacyPolicy": {
|
||||
"description": "개인정보 처리방침 내용 편집 및 관리",
|
||||
"title": "개인정보 처리방침"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "더보기",
|
||||
"notifySettingsTitle": "알림 설정",
|
||||
"onlineDevices": "온라인 기기",
|
||||
"onlyFirstPurchase": "첫 구매 전용",
|
||||
"orderList": "주문 목록",
|
||||
"password": "비밀번호",
|
||||
"passwordPlaceholder": "새 비밀번호 입력 (선택 사항)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "추천인 ID",
|
||||
"refererIdPlaceholder": "추천인 ID를 입력하세요",
|
||||
"referralCode": "추천 코드",
|
||||
"referralPercentage": "추천 비율",
|
||||
"referralPercentagePlaceholder": "추천 비율 입력 (0-100)",
|
||||
"referrerUserId": "추천인 (사용자 ID)",
|
||||
"remove": "제거",
|
||||
"resetLogs": "초기화 기록",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Nodetrafikk",
|
||||
"nodes": "noder",
|
||||
"offlineNodeCount": "Antall frakoblede noder",
|
||||
"onlineIPCount": "Antall IP-er på nett",
|
||||
"onlineNodeCount": "Antall noder på nett",
|
||||
"onlineUsersCount": "Nettbrukere",
|
||||
"pendingTickets": "Ventende billetter",
|
||||
"register": "Registrer",
|
||||
"repurchase": "gjenkjøp",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Lagring vellykket",
|
||||
"title": "Invitasjonsinnstillinger"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Aktiver automatisk rensing",
|
||||
"autoClearDescription": "Når aktivert, vil systemet automatisk fjerne utløpte loggposter",
|
||||
"clearDays": "Oppbevaringsdager",
|
||||
"clearDaysDescription": "Antall dager for å oppbevare logger; logger eldre enn dette vil bli renset",
|
||||
"clearDaysPlaceholder": "Skriv inn oppbevaringsdager",
|
||||
"description": "Konfigurer automatiske regler for loggrensing og oppbevaringsperiode",
|
||||
"title": "Innstillinger for loggrensing"
|
||||
},
|
||||
"logSettings": "Logginnstillinger",
|
||||
"privacyPolicy": {
|
||||
"description": "Rediger og administrer innholdet i personvernerklæringen",
|
||||
"title": "Personvernerklæring"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Mer",
|
||||
"notifySettingsTitle": "Varslingsinnstillinger",
|
||||
"onlineDevices": "Tilkoblede enheter",
|
||||
"onlyFirstPurchase": "Første kjøp bare",
|
||||
"orderList": "Ordreliste",
|
||||
"password": "Passord",
|
||||
"passwordPlaceholder": "Skriv inn nytt passord (valgfritt)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "Henvisnings-ID",
|
||||
"refererIdPlaceholder": "Skriv inn referanse-ID",
|
||||
"referralCode": "Henvisningskode",
|
||||
"referralPercentage": "Henvisningsprosent",
|
||||
"referralPercentagePlaceholder": "Skriv inn henvisningsprosent (0-100)",
|
||||
"referrerUserId": "Henviser (Bruker-ID)",
|
||||
"remove": "Fjern",
|
||||
"resetLogs": "Tilbakestill Logg",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Ruch węzła",
|
||||
"nodes": "węzły",
|
||||
"offlineNodeCount": "Liczba węzłów offline",
|
||||
"onlineIPCount": "Liczba IP online",
|
||||
"onlineNodeCount": "Liczba węzłów online",
|
||||
"onlineUsersCount": "Użytkownicy online",
|
||||
"pendingTickets": "Oczekujące zgłoszenia",
|
||||
"register": "Rejestracja",
|
||||
"repurchase": "ponowny zakup",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Zapisano pomyślnie",
|
||||
"title": "Ustawienia zaproszeń"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Włącz automatyczne czyszczenie",
|
||||
"autoClearDescription": "Po włączeniu system automatycznie usunie przestarzałe rekordy logów",
|
||||
"clearDays": "Dni przechowywania",
|
||||
"clearDaysDescription": "Liczba dni, przez które logi będą przechowywane; logi starsze niż ten okres zostaną usunięte",
|
||||
"clearDaysPlaceholder": "Wprowadź dni przechowywania",
|
||||
"description": "Skonfiguruj zasady automatycznego czyszczenia logów i okres przechowywania",
|
||||
"title": "Ustawienia czyszczenia logów"
|
||||
},
|
||||
"logSettings": "Ustawienia logów",
|
||||
"privacyPolicy": {
|
||||
"description": "Edytuj i zarządzaj treścią polityki prywatności",
|
||||
"title": "Polityka prywatności"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Więcej",
|
||||
"notifySettingsTitle": "Ustawienia powiadomień",
|
||||
"onlineDevices": "Urządzenia online",
|
||||
"onlyFirstPurchase": "Tylko pierwsze zakupy",
|
||||
"orderList": "Lista Zamówień",
|
||||
"password": "Hasło",
|
||||
"passwordPlaceholder": "Wprowadź nowe hasło (opcjonalnie)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "Identyfikator polecającego",
|
||||
"refererIdPlaceholder": "Wprowadź identyfikator polecającego",
|
||||
"referralCode": "Kod polecający",
|
||||
"referralPercentage": "Procent polecenia",
|
||||
"referralPercentagePlaceholder": "Wprowadź procent polecenia (0-100)",
|
||||
"referrerUserId": "Polecający (ID użytkownika)",
|
||||
"remove": "Usuń",
|
||||
"resetLogs": "Logi Resetowania",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Tráfego do Nó",
|
||||
"nodes": "nós",
|
||||
"offlineNodeCount": "Contagem de nós offline",
|
||||
"onlineIPCount": "Contagem de IPs Online",
|
||||
"onlineNodeCount": "Contagem de nós online",
|
||||
"onlineUsersCount": "Usuários Online",
|
||||
"pendingTickets": "Tickets pendentes",
|
||||
"register": "Registrar",
|
||||
"repurchase": "recompra",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Salvo com Sucesso",
|
||||
"title": "Configurações de Convite"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Ativar Limpeza Automática",
|
||||
"autoClearDescription": "Quando ativado, o sistema limpará automaticamente os registros de log expirados",
|
||||
"clearDays": "Dias de Retenção",
|
||||
"clearDaysDescription": "Número de dias para reter logs; logs mais antigos que isso serão limpos",
|
||||
"clearDaysPlaceholder": "Insira os dias de retenção",
|
||||
"description": "Configure regras de limpeza automática de logs e período de retenção",
|
||||
"title": "Configurações de Limpeza de Logs"
|
||||
},
|
||||
"logSettings": "Configurações de Logs",
|
||||
"privacyPolicy": {
|
||||
"description": "Edite e gerencie o conteúdo da política de privacidade",
|
||||
"title": "Política de Privacidade"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Mais",
|
||||
"notifySettingsTitle": "Configurações de Notificação",
|
||||
"onlineDevices": "Dispositivos Online",
|
||||
"onlyFirstPurchase": "Apenas a Primeira Compra",
|
||||
"orderList": "Lista de Pedidos",
|
||||
"password": "Senha",
|
||||
"passwordPlaceholder": "Digite a nova senha (opcional)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "ID do Referente",
|
||||
"refererIdPlaceholder": "Digite o ID do referenciador",
|
||||
"referralCode": "Código de Indicação",
|
||||
"referralPercentage": "Porcentagem de Referência",
|
||||
"referralPercentagePlaceholder": "Insira a porcentagem de referência (0-100)",
|
||||
"referrerUserId": "Referente (ID do Usuário)",
|
||||
"remove": "Remover",
|
||||
"resetLogs": "Registros de Redefinição",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Traficul nodului",
|
||||
"nodes": "noduri",
|
||||
"offlineNodeCount": "Număr de noduri offline",
|
||||
"onlineIPCount": "Număr de IP-uri online",
|
||||
"onlineNodeCount": "Număr de noduri online",
|
||||
"onlineUsersCount": "Utilizatori online",
|
||||
"pendingTickets": "Tichete în așteptare",
|
||||
"register": "Înregistrare",
|
||||
"repurchase": "recomandare",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Salvare cu Succes",
|
||||
"title": "Setări de Invitație"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Activează curățarea automată",
|
||||
"autoClearDescription": "Când este activat, sistemul va curăța automat înregistrările de jurnal expirate",
|
||||
"clearDays": "Zile de păstrare",
|
||||
"clearDaysDescription": "Numărul de zile pentru care se păstrează jurnalele; jurnalele mai vechi de atât vor fi curățate",
|
||||
"clearDaysPlaceholder": "Introdu zilele de păstrare",
|
||||
"description": "Configurează regulile de curățare automată a jurnalelor și perioada de păstrare",
|
||||
"title": "Setări de curățare a jurnalelor"
|
||||
},
|
||||
"logSettings": "Setări jurnal",
|
||||
"privacyPolicy": {
|
||||
"description": "Editează și gestionează conținutul politicii de confidențialitate",
|
||||
"title": "Politica de Confidențialitate"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Mai mult",
|
||||
"notifySettingsTitle": "Setări notificări",
|
||||
"onlineDevices": "Dispozitive Online",
|
||||
"onlyFirstPurchase": "Doar prima achiziție",
|
||||
"orderList": "Lista de comenzi",
|
||||
"password": "Parolă",
|
||||
"passwordPlaceholder": "Introduceți o parolă nouă (opțional)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "ID Referent",
|
||||
"refererIdPlaceholder": "Introduceți ID-ul referentului",
|
||||
"referralCode": "Cod de recomandare",
|
||||
"referralPercentage": "Procentaj de recomandare",
|
||||
"referralPercentagePlaceholder": "Introduceți procentajul de recomandare (0-100)",
|
||||
"referrerUserId": "Referent (ID Utilizator)",
|
||||
"remove": "Elimină",
|
||||
"resetLogs": "Jurnale de resetare",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Трафик узла",
|
||||
"nodes": "узлы",
|
||||
"offlineNodeCount": "Количество офлайн-узлов",
|
||||
"onlineIPCount": "Количество онлайн IP",
|
||||
"onlineNodeCount": "Количество онлайн-узлов",
|
||||
"onlineUsersCount": "Пользователи онлайн",
|
||||
"pendingTickets": "Ожидающие заявки",
|
||||
"register": "Регистрация",
|
||||
"repurchase": "повторная покупка",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Сохранение успешно",
|
||||
"title": "Настройки приглашений"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Включить автоматическую очистку",
|
||||
"autoClearDescription": "При включении система будет автоматически очищать устаревшие записи журналов",
|
||||
"clearDays": "Дни хранения",
|
||||
"clearDaysDescription": "Количество дней для хранения журналов; журналы старше этого будут очищены",
|
||||
"clearDaysPlaceholder": "Введите количество дней хранения",
|
||||
"description": "Настройте правила автоматической очистки журналов и период хранения",
|
||||
"title": "Настройки очистки журналов"
|
||||
},
|
||||
"logSettings": "Настройки журналов",
|
||||
"privacyPolicy": {
|
||||
"description": "Редактирование и управление содержимым политики конфиденциальности",
|
||||
"title": "Политика конфиденциальности"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Больше",
|
||||
"notifySettingsTitle": "Настройки уведомлений",
|
||||
"onlineDevices": "Подключенные устройства",
|
||||
"onlyFirstPurchase": "Только первая покупка",
|
||||
"orderList": "Список заказов",
|
||||
"password": "Пароль",
|
||||
"passwordPlaceholder": "Введите новый пароль (необязательно)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "ID реферера",
|
||||
"refererIdPlaceholder": "Введите ID реферера",
|
||||
"referralCode": "Реферальный код",
|
||||
"referralPercentage": "Процент вознаграждения за рекомендацию",
|
||||
"referralPercentagePlaceholder": "Введите процент вознаграждения за рекомендацию (0-100)",
|
||||
"referrerUserId": "Реферер (ID пользователя)",
|
||||
"remove": "Удалить",
|
||||
"resetLogs": "Журналы сброса",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "ปริมาณการใช้งานของโหนด",
|
||||
"nodes": "โหนด",
|
||||
"offlineNodeCount": "จำนวนโหนดออฟไลน์",
|
||||
"onlineIPCount": "จำนวน IP ออนไลน์",
|
||||
"onlineNodeCount": "จำนวนโหนดออนไลน์",
|
||||
"onlineUsersCount": "ผู้ใช้งานออนไลน์",
|
||||
"pendingTickets": "บัตรงานที่รอดำเนินการ",
|
||||
"register": "ลงทะเบียน",
|
||||
"repurchase": "ซื้อซ้ำ",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "บันทึกสำเร็จ",
|
||||
"title": "การตั้งค่าการเชิญ"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "เปิดใช้งานการล้างอัตโนมัติ",
|
||||
"autoClearDescription": "เมื่อเปิดใช้งาน ระบบจะล้างบันทึกที่หมดอายุโดยอัตโนมัติ",
|
||||
"clearDays": "จำนวนวันในการเก็บรักษา",
|
||||
"clearDaysDescription": "จำนวนวันที่จะเก็บบันทึก; บันทึกที่เก่ากว่านี้จะถูกลบออก",
|
||||
"clearDaysPlaceholder": "กรอกจำนวนวันในการเก็บรักษา",
|
||||
"description": "กำหนดกฎการล้างบันทึกอัตโนมัติและระยะเวลาการเก็บรักษา",
|
||||
"title": "การตั้งค่าการล้างบันทึก"
|
||||
},
|
||||
"logSettings": "การตั้งค่าบันทึก",
|
||||
"privacyPolicy": {
|
||||
"description": "แก้ไขและจัดการเนื้อหานโยบายความเป็นส่วนตัว",
|
||||
"title": "นโยบายความเป็นส่วนตัว"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "เพิ่มเติม",
|
||||
"notifySettingsTitle": "การตั้งค่าการแจ้งเตือน",
|
||||
"onlineDevices": "อุปกรณ์ที่ออนไลน์",
|
||||
"onlyFirstPurchase": "การซื้อครั้งแรกเท่านั้น",
|
||||
"orderList": "รายการสั่งซื้อ",
|
||||
"password": "รหัสผ่าน",
|
||||
"passwordPlaceholder": "กรุณาใส่รหัสผ่านใหม่ (ไม่บังคับ)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "รหัสผู้แนะนำ",
|
||||
"refererIdPlaceholder": "กรอก ID ผู้แนะนำ",
|
||||
"referralCode": "รหัสแนะนำ",
|
||||
"referralPercentage": "เปอร์เซ็นต์การแนะนำ",
|
||||
"referralPercentagePlaceholder": "กรอกเปอร์เซ็นต์การแนะนำ (0-100)",
|
||||
"referrerUserId": "ผู้อ้างอิง (รหัสผู้ใช้)",
|
||||
"remove": "ลบ",
|
||||
"resetLogs": "บันทึกการรีเซ็ต",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Düğüm Trafiği",
|
||||
"nodes": "düğümler",
|
||||
"offlineNodeCount": "Çevrimdışı Düğüm Sayısı",
|
||||
"onlineIPCount": "Çevrimiçi IP Sayısı",
|
||||
"onlineNodeCount": "Çevrimiçi Düğüm Sayısı",
|
||||
"onlineUsersCount": "Çevrimiçi Kullanıcılar",
|
||||
"pendingTickets": "Bekleyen Biletler",
|
||||
"register": "Kayıt Ol",
|
||||
"repurchase": "yeniden satın alma",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Başarıyla Kaydedildi",
|
||||
"title": "Davet Ayarları"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Otomatik Temizlemeyi Etkinleştir",
|
||||
"autoClearDescription": "Etkinleştirildiğinde, sistem süresi dolmuş log kayıtlarını otomatik olarak temizleyecektir",
|
||||
"clearDays": "Saklama Günleri",
|
||||
"clearDaysDescription": "Logların saklanacağı gün sayısı; bu süreden daha eski loglar temizlenecektir",
|
||||
"clearDaysPlaceholder": "Saklama günlerini girin",
|
||||
"description": "Otomatik log temizleme kurallarını ve saklama süresini yapılandırın",
|
||||
"title": "Log Temizleme Ayarları"
|
||||
},
|
||||
"logSettings": "Log Ayarları",
|
||||
"privacyPolicy": {
|
||||
"description": "Gizlilik politikası içeriğini düzenleyin ve yönetin",
|
||||
"title": "Gizlilik Politikası"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Daha Fazla",
|
||||
"notifySettingsTitle": "Bildirim Ayarları",
|
||||
"onlineDevices": "Çevrimiçi Cihazlar",
|
||||
"onlyFirstPurchase": "Sadece İlk Alım",
|
||||
"orderList": "Sipariş Listesi",
|
||||
"password": "Şifre",
|
||||
"passwordPlaceholder": "Yeni şifreyi girin (isteğe bağlı)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "Referans Kimliği",
|
||||
"refererIdPlaceholder": "Referans kimliğini girin",
|
||||
"referralCode": "Referans Kodu",
|
||||
"referralPercentage": "Referans Yüzdesi",
|
||||
"referralPercentagePlaceholder": "Referans yüzdesini girin (0-100)",
|
||||
"referrerUserId": "Yönlendiren (Kullanıcı Kimliği)",
|
||||
"remove": "Kaldır",
|
||||
"resetLogs": "Sıfırlama Kayıtları",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Трафік вузла",
|
||||
"nodes": "вузли",
|
||||
"offlineNodeCount": "Кількість офлайн-вузлів",
|
||||
"onlineIPCount": "Кількість онлайн IP",
|
||||
"onlineNodeCount": "Кількість онлайн-вузлів",
|
||||
"onlineUsersCount": "Користувачі онлайн",
|
||||
"pendingTickets": "Невирішені заявки",
|
||||
"register": "Реєстрація",
|
||||
"repurchase": "повторна покупка",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Успішно збережено",
|
||||
"title": "Налаштування запрошень"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Увімкнути автоматичне очищення",
|
||||
"autoClearDescription": "При увімкненні система автоматично очищатиме застарілі записи журналів",
|
||||
"clearDays": "Дні зберігання",
|
||||
"clearDaysDescription": "Кількість днів для зберігання журналів; журнали старші за цей термін будуть очищені",
|
||||
"clearDaysPlaceholder": "Введіть дні зберігання",
|
||||
"description": "Налаштуйте правила автоматичного очищення журналів та період зберігання",
|
||||
"title": "Налаштування очищення журналів"
|
||||
},
|
||||
"logSettings": "Налаштування журналів",
|
||||
"privacyPolicy": {
|
||||
"description": "Редагуйте та керуйте змістом політики конфіденційності",
|
||||
"title": "Політика конфіденційності"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Більше",
|
||||
"notifySettingsTitle": "Налаштування сповіщень",
|
||||
"onlineDevices": "Пристрої в мережі",
|
||||
"onlyFirstPurchase": "Тільки перша покупка",
|
||||
"orderList": "Список замовлень",
|
||||
"password": "Пароль",
|
||||
"passwordPlaceholder": "Введіть новий пароль (необов'язково)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "Ідентифікатор реферера",
|
||||
"refererIdPlaceholder": "Введіть ID реферера",
|
||||
"referralCode": "Реферальний код",
|
||||
"referralPercentage": "Відсоток рефералів",
|
||||
"referralPercentagePlaceholder": "Введіть відсоток рефералів (0-100)",
|
||||
"referrerUserId": "Реферер (ID користувача)",
|
||||
"remove": "Видалити",
|
||||
"resetLogs": "Журнали скидання",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "Lưu lượng nút",
|
||||
"nodes": "nút",
|
||||
"offlineNodeCount": "Số lượng nút ngoại tuyến",
|
||||
"onlineIPCount": "Số lượng IP trực tuyến",
|
||||
"onlineNodeCount": "Số lượng nút trực tuyến",
|
||||
"onlineUsersCount": "Người dùng trực tuyến",
|
||||
"pendingTickets": "Phiếu hỗ trợ đang chờ xử lý",
|
||||
"register": "Đăng ký",
|
||||
"repurchase": "mua lại",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "Lưu thành công",
|
||||
"title": "Cài đặt mời"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "Bật Dọn dẹp Tự động",
|
||||
"autoClearDescription": "Khi được bật, hệ thống sẽ tự động xóa các bản ghi nhật ký đã hết hạn",
|
||||
"clearDays": "Số Ngày Lưu giữ",
|
||||
"clearDaysDescription": "Số ngày để lưu giữ nhật ký; nhật ký cũ hơn sẽ bị xóa",
|
||||
"clearDaysPlaceholder": "Nhập số ngày lưu giữ",
|
||||
"description": "Cấu hình quy tắc dọn dẹp nhật ký tự động và thời gian lưu giữ",
|
||||
"title": "Cài đặt Dọn dẹp Nhật ký"
|
||||
},
|
||||
"logSettings": "Cài đặt Nhật ký",
|
||||
"privacyPolicy": {
|
||||
"description": "Chỉnh sửa và quản lý nội dung chính sách bảo mật",
|
||||
"title": "Chính sách bảo mật"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "Thêm",
|
||||
"notifySettingsTitle": "Cài Đặt Thông Báo",
|
||||
"onlineDevices": "Thiết bị trực tuyến",
|
||||
"onlyFirstPurchase": "Chỉ Mua Hàng Đầu Tiên",
|
||||
"orderList": "Danh sách đơn hàng",
|
||||
"password": "Mật khẩu",
|
||||
"passwordPlaceholder": "Nhập mật khẩu mới (không bắt buộc)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "ID người giới thiệu",
|
||||
"refererIdPlaceholder": "Nhập mã người giới thiệu",
|
||||
"referralCode": "Mã Giới Thiệu",
|
||||
"referralPercentage": "Tỷ Lệ Giới Thiệu",
|
||||
"referralPercentagePlaceholder": "Nhập tỷ lệ giới thiệu (0-100)",
|
||||
"referrerUserId": "Người giới thiệu (ID người dùng)",
|
||||
"remove": "Xóa",
|
||||
"resetLogs": "Nhật ký đặt lại",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "节点流量",
|
||||
"nodes": "节点",
|
||||
"offlineNodeCount": "离线节点数",
|
||||
"onlineIPCount": "在线IP数",
|
||||
"onlineNodeCount": "在线节点数",
|
||||
"onlineUsersCount": "在线用户数",
|
||||
"pendingTickets": "待处理工单",
|
||||
"register": "注册",
|
||||
"repurchase": "复购",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "保存成功",
|
||||
"saveFailed": "保存失败"
|
||||
},
|
||||
"logCleanup": {
|
||||
"title": "日志清理设置",
|
||||
"description": "配置系统日志自动清理规则和保留时间",
|
||||
"autoClear": "启用自动清理",
|
||||
"autoClearDescription": "启用后系统将自动清理过期的日志记录",
|
||||
"clearDays": "保留天数",
|
||||
"clearDaysDescription": "日志保留的天数,超过此时间的日志将被清理",
|
||||
"clearDaysPlaceholder": "请输入保留天数"
|
||||
},
|
||||
"logSettings": "日志设置",
|
||||
"privacyPolicy": {
|
||||
"title": "隐私政策",
|
||||
"description": "编辑和管理隐私政策内容"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "更多",
|
||||
"notifySettingsTitle": "通知设置",
|
||||
"onlineDevices": "在线设备",
|
||||
"onlyFirstPurchase": "仅首次购买奖励",
|
||||
"orderList": "订单列表",
|
||||
"password": "密码",
|
||||
"passwordPlaceholder": "输入新密码(选填)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "推荐人ID",
|
||||
"refererIdPlaceholder": "输入推荐人ID",
|
||||
"referralCode": "推荐码",
|
||||
"referralPercentage": "推荐奖励比例",
|
||||
"referralPercentagePlaceholder": "输入推荐奖励比例(0-100)",
|
||||
"referrerUserId": "推荐人(用户ID)",
|
||||
"remove": "移除",
|
||||
"resetLogs": "重置日志",
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
"nodeTraffic": "節點流量",
|
||||
"nodes": "節點",
|
||||
"offlineNodeCount": "離線節點數",
|
||||
"onlineIPCount": "線上IP數",
|
||||
"onlineNodeCount": "線上節點數",
|
||||
"onlineUsersCount": "線上用戶數",
|
||||
"pendingTickets": "待處理工單",
|
||||
"register": "註冊",
|
||||
"repurchase": "回購",
|
||||
|
||||
@ -33,6 +33,16 @@
|
||||
"saveSuccess": "保存成功",
|
||||
"title": "邀請設置"
|
||||
},
|
||||
"logCleanup": {
|
||||
"autoClear": "啟用自動清理",
|
||||
"autoClearDescription": "啟用後,系統將自動清除過期的日誌記錄",
|
||||
"clearDays": "保留天數",
|
||||
"clearDaysDescription": "保留日誌的天數;超過此天數的日誌將被清除",
|
||||
"clearDaysPlaceholder": "輸入保留天數",
|
||||
"description": "配置自動日誌清理規則和保留期限",
|
||||
"title": "日誌清理設置"
|
||||
},
|
||||
"logSettings": "日誌設置",
|
||||
"privacyPolicy": {
|
||||
"description": "編輯和管理隱私政策內容",
|
||||
"title": "隱私政策"
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"more": "更多",
|
||||
"notifySettingsTitle": "通知設定",
|
||||
"onlineDevices": "在線裝置",
|
||||
"onlyFirstPurchase": "首次購買專享",
|
||||
"orderList": "訂單列表",
|
||||
"password": "密碼",
|
||||
"passwordPlaceholder": "輸入新密碼(可選)",
|
||||
@ -59,6 +60,8 @@
|
||||
"refererId": "推薦人 ID",
|
||||
"refererIdPlaceholder": "輸入推薦人 ID",
|
||||
"referralCode": "推薦碼",
|
||||
"referralPercentage": "推薦百分比",
|
||||
"referralPercentagePlaceholder": "輸入推薦百分比(0-100)",
|
||||
"referrerUserId": "推薦人(用戶 ID)",
|
||||
"remove": "移除",
|
||||
"resetLogs": "重置日誌",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// @ts-ignore
|
||||
|
||||
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
import * as ads from './ads';
|
||||
|
||||
@ -155,6 +155,26 @@ export async function filterServerTrafficLog(
|
||||
);
|
||||
}
|
||||
|
||||
/** Get log setting GET /v1/admin/log/setting */
|
||||
export async function getLogSetting(options?: { [key: string]: any }) {
|
||||
return request<API.Response & { data?: API.LogSetting }>('/v1/admin/log/setting', {
|
||||
method: 'GET',
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Update log setting POST /v1/admin/log/setting */
|
||||
export async function updateLogSetting(body: API.LogSetting, options?: { [key: string]: any }) {
|
||||
return request<API.Response & { data?: any }>('/v1/admin/log/setting', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Filter subscribe log GET /v1/admin/log/subscribe/list */
|
||||
export async function filterSubscribeLog(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
|
||||
@ -111,6 +111,21 @@ export async function filterNodeList(
|
||||
);
|
||||
}
|
||||
|
||||
/** Reset node sort POST /v1/admin/server/node/sort */
|
||||
export async function resetSortWithNode(
|
||||
body: API.ResetSortRequest,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<API.Response & { data?: any }>('/v1/admin/server/node/sort', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Toggle Node Status POST /v1/admin/server/node/status/toggle */
|
||||
export async function toggleNodeStatus(
|
||||
body: API.ToggleNodeStatusRequest,
|
||||
@ -156,6 +171,21 @@ export async function getServerProtocols(
|
||||
);
|
||||
}
|
||||
|
||||
/** Reset server sort POST /v1/admin/server/server/sort */
|
||||
export async function resetSortWithServer(
|
||||
body: API.ResetSortRequest,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<API.Response & { data?: any }>('/v1/admin/server/server/sort', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Update Server POST /v1/admin/server/update */
|
||||
export async function updateServer(
|
||||
body: API.UpdateServerRequest,
|
||||
|
||||
28
apps/admin/services/admin/typings.d.ts
vendored
28
apps/admin/services/admin/typings.d.ts
vendored
@ -366,6 +366,8 @@ declare namespace API {
|
||||
password: string;
|
||||
product_id: number;
|
||||
duration: number;
|
||||
referral_percentage: number;
|
||||
only_first_purchase: boolean;
|
||||
referer_user: string;
|
||||
refer_code: string;
|
||||
balance: number;
|
||||
@ -1289,6 +1291,11 @@ declare namespace API {
|
||||
list: Record<string, any>;
|
||||
};
|
||||
|
||||
type LogSetting = {
|
||||
auto_clear: boolean;
|
||||
clear_days: number;
|
||||
};
|
||||
|
||||
type MessageLog = {
|
||||
id: number;
|
||||
type: number;
|
||||
@ -1321,6 +1328,7 @@ declare namespace API {
|
||||
server_id: number;
|
||||
protocol: string;
|
||||
enabled: boolean;
|
||||
sort?: number;
|
||||
created_at: number;
|
||||
updated_at: number;
|
||||
};
|
||||
@ -1622,6 +1630,10 @@ declare namespace API {
|
||||
order_no: string;
|
||||
};
|
||||
|
||||
type ResetSortRequest = {
|
||||
sort: SortItem[];
|
||||
};
|
||||
|
||||
type ResetSubscribeLog = {
|
||||
type: number;
|
||||
user_id: number;
|
||||
@ -1696,8 +1708,13 @@ declare namespace API {
|
||||
updated_at: number;
|
||||
};
|
||||
|
||||
type ServerOnlineIP = {
|
||||
ip: string;
|
||||
protocol: string;
|
||||
};
|
||||
|
||||
type ServerOnlineUser = {
|
||||
ip: string[];
|
||||
ip: ServerOnlineIP[];
|
||||
user_id: number;
|
||||
subscribe: string;
|
||||
subscribe_id: number;
|
||||
@ -1719,14 +1736,15 @@ declare namespace API {
|
||||
};
|
||||
|
||||
type ServerStatus = {
|
||||
online: ServerOnlineUser[];
|
||||
cpu: number;
|
||||
mem: number;
|
||||
disk: number;
|
||||
protocol: string;
|
||||
online: ServerOnlineUser[];
|
||||
};
|
||||
|
||||
type ServerTotalDataResponse = {
|
||||
online_user_ips: number;
|
||||
online_users: number;
|
||||
online_servers: number;
|
||||
offline_servers: number;
|
||||
today_upload: number;
|
||||
@ -2161,6 +2179,8 @@ declare namespace API {
|
||||
avatar: string;
|
||||
balance: number;
|
||||
commission: number;
|
||||
referral_percentage: number;
|
||||
only_first_purchase: boolean;
|
||||
gift_amount: number;
|
||||
telegram: number;
|
||||
refer_code: string;
|
||||
@ -2191,6 +2211,8 @@ declare namespace API {
|
||||
avatar: string;
|
||||
balance: number;
|
||||
commission: number;
|
||||
referral_percentage: number;
|
||||
only_first_purchase: boolean;
|
||||
gift_amount: number;
|
||||
telegram: number;
|
||||
refer_code: string;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// @ts-ignore
|
||||
|
||||
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
import * as auth from './auth';
|
||||
|
||||
2
apps/admin/services/common/typings.d.ts
vendored
2
apps/admin/services/common/typings.d.ts
vendored
@ -890,6 +890,8 @@ declare namespace API {
|
||||
avatar: string;
|
||||
balance: number;
|
||||
commission: number;
|
||||
referral_percentage: number;
|
||||
only_first_purchase: boolean;
|
||||
gift_amount: number;
|
||||
telegram: number;
|
||||
refer_code: string;
|
||||
|
||||
@ -46,7 +46,8 @@ export default function Affiliate() {
|
||||
<Display type='currency' value={data?.total_commission} />
|
||||
</span>
|
||||
<span className='text-muted-foreground text-sm'>
|
||||
({t('commissionRate')}: {common?.invite?.referral_percentage}%)
|
||||
({t('commissionRate')}:{' '}
|
||||
{user?.referral_percentage || common?.invite?.referral_percentage}%)
|
||||
</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// @ts-ignore
|
||||
|
||||
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
import * as auth from './auth';
|
||||
|
||||
2
apps/user/services/common/typings.d.ts
vendored
2
apps/user/services/common/typings.d.ts
vendored
@ -890,6 +890,8 @@ declare namespace API {
|
||||
avatar: string;
|
||||
balance: number;
|
||||
commission: number;
|
||||
referral_percentage: number;
|
||||
only_first_purchase: boolean;
|
||||
gift_amount: number;
|
||||
telegram: number;
|
||||
refer_code: string;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// @ts-ignore
|
||||
|
||||
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
import * as announcement from './announcement';
|
||||
|
||||
2
apps/user/services/user/typings.d.ts
vendored
2
apps/user/services/user/typings.d.ts
vendored
@ -971,6 +971,8 @@ declare namespace API {
|
||||
avatar: string;
|
||||
balance: number;
|
||||
commission: number;
|
||||
referral_percentage: number;
|
||||
only_first_purchase: boolean;
|
||||
gift_amount: number;
|
||||
telegram: number;
|
||||
refer_code: string;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user