diff --git a/frontend/src/pages/clients/ClientFormModal.tsx b/frontend/src/pages/clients/ClientFormModal.tsx index 132baff13..aa43317cc 100644 --- a/frontend/src/pages/clients/ClientFormModal.tsx +++ b/frontend/src/pages/clients/ClientFormModal.tsx @@ -8,6 +8,7 @@ import { Input, InputNumber, Modal, + Popconfirm, Row, Select, Space, @@ -17,7 +18,7 @@ import { Tooltip, message, } from 'antd'; -import { EyeOutlined, ReloadOutlined } from '@ant-design/icons'; +import { EyeOutlined, ReloadOutlined, RetweetOutlined } from '@ant-design/icons'; import dayjs from 'dayjs'; import type { Dayjs } from 'dayjs'; import { HttpUtil, RandomUtil } from '@/utils'; @@ -39,6 +40,7 @@ const CLIENT_IP_LOG_MODAL_Z_INDEX = CLIENT_FORM_MODAL_Z_INDEX + 1; interface ApiMsg { success?: boolean; + msg?: string; obj?: T; } @@ -72,6 +74,7 @@ interface ClientFormModalProps { payload: Record | SaveCreatePayload, meta: SaveMetaEdit | SaveMetaCreate, ) => Promise; + resetTraffic?: (client: ClientRecord) => Promise; onOpenChange: (open: boolean) => void; } @@ -140,6 +143,7 @@ export default function ClientFormModal({ tgBotEnable = false, groups = [], save, + resetTraffic, onOpenChange, }: ClientFormModalProps) { const { t } = useTranslation(); @@ -148,6 +152,7 @@ export default function ClientFormModal({ const [form, setForm] = useState(emptyForm); const [submitting, setSubmitting] = useState(false); + const [resetting, setResetting] = useState(false); const [clientIps, setClientIps] = useState([]); const [ipsLoading, setIpsLoading] = useState(false); const [ipsClearing, setIpsClearing] = useState(false); @@ -328,6 +333,21 @@ export default function ClientFormModal({ onOpenChange(false); } + async function onResetTraffic() { + if (!isEdit || !client?.email || !resetTraffic) return; + setResetting(true); + try { + const msg = await resetTraffic(client); + if (msg?.success) { + messageApi.success(t('pages.clients.toasts.trafficReset')); + } else { + messageApi.error(msg?.msg || t('somethingWentWrong')); + } + } finally { + setResetting(false); + } + } + async function onSubmit() { const schema = isEdit ? ClientFormSchema : ClientCreateFormSchema; const validated = schema.safeParse({ @@ -413,15 +433,35 @@ export default function ClientFormModal({ open={open} title={isEdit ? t('pages.clients.editClient') : t('pages.clients.addClient')} destroyOnHidden - okText={isEdit ? t('save') : t('create')} - cancelText={t('cancel')} - okButtonProps={{ loading: submitting }} width={720} zIndex={CLIENT_FORM_MODAL_Z_INDEX} style={{ top: 20 }} styles={{ body: { maxHeight: 'calc(100vh - 160px)', overflowY: 'auto', overflowX: 'hidden' } }} - onOk={onSubmit} onCancel={close} + footer={ +
+ {isEdit && resetTraffic && ( + + + + )} +
+ + +
+
+ } >
( 0 ? [ - { - key: 'adjust', - icon: , - label: t('pages.clients.adjust'), - onClick: () => setBulkAdjustOpen(true), - }, - { - key: 'subLinks', - icon: , - label: t('pages.clients.subLinks'), - onClick: () => setSubLinksOpen(true), - }, - ] + { + key: 'adjust', + icon: , + label: t('pages.clients.adjust'), + onClick: () => setBulkAdjustOpen(true), + }, + { + key: 'subLinks', + icon: , + label: t('pages.clients.subLinks'), + onClick: () => setSubLinksOpen(true), + }, + ] : [ - { - key: 'bulk', - icon: , - label: t('pages.clients.bulk'), - onClick: () => setBulkAddOpen(true), - }, - { - key: 'resetAll', - icon: , - label: t('pages.clients.resetAllTraffics'), - onClick: onResetAllTraffics, - }, - { - key: 'delDepleted', - icon: , - label: t('pages.clients.delDepleted'), - danger: true, - onClick: onDelDepleted, - }, - ], + { + key: 'bulk', + icon: , + label: t('pages.clients.bulk'), + onClick: () => setBulkAddOpen(true), + }, + { + key: 'resetAll', + icon: , + label: t('pages.clients.resetAllTraffics'), + onClick: onResetAllTraffics, + }, + { + key: 'delDepleted', + icon: , + label: t('pages.clients.delDepleted'), + danger: true, + onClick: onDelDepleted, + }, + ], }} >