mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-09-28 07:36:38 +08:00
feat: add forward flow reset action
This commit is contained in:
@@ -217,6 +217,8 @@ export const pauseForwardService = (forwardId: number) =>
|
||||
Network.post("/forward/pause", { id: forwardId });
|
||||
export const resumeForwardService = (forwardId: number) =>
|
||||
Network.post("/forward/resume", { id: forwardId });
|
||||
export const resetForwardFlow = (forwardId: number) =>
|
||||
Network.post("/forward/reset-flow", { id: forwardId });
|
||||
|
||||
// 转发诊断操作
|
||||
export const diagnoseForward = (forwardId: number) =>
|
||||
|
||||
@@ -69,6 +69,7 @@ import {
|
||||
getNodeList,
|
||||
pauseForwardService,
|
||||
resumeForwardService,
|
||||
resetForwardFlow,
|
||||
diagnoseForward,
|
||||
updateForwardOrder,
|
||||
getConfigByName,
|
||||
@@ -230,7 +231,7 @@ const FORWARD_GROUPED_TABLE_COLUMN_CLASS = {
|
||||
strategy: "w-[100px]",
|
||||
totalFlow: "w-[120px]",
|
||||
status: "w-[100px]",
|
||||
actions: "w-[144px] text-right",
|
||||
actions: "w-[176px] text-right",
|
||||
} as const;
|
||||
|
||||
const normalizeForwardUserName = (userName?: string): string => {
|
||||
@@ -764,6 +765,7 @@ const SortableTableRow = ({
|
||||
handleEdit,
|
||||
handleDelete,
|
||||
handleDiagnose,
|
||||
handleResetFlow,
|
||||
showAddressModal,
|
||||
formatFlow,
|
||||
}: any) => {
|
||||
@@ -919,6 +921,29 @@ const SortableTableRow = ({
|
||||
/>
|
||||
</svg>
|
||||
</Button>
|
||||
<Button
|
||||
isIconOnly
|
||||
className="bg-secondary/10 text-secondary hover:bg-secondary/20"
|
||||
isDisabled={(forward.inFlow || 0) + (forward.outFlow || 0) <= 0}
|
||||
size="sm"
|
||||
title="流量清零"
|
||||
onPress={() => handleResetFlow(forward)}
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="h-4 w-4"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M4 4v6h6M20 20v-6h-6M20 9a8 8 0 00-13.657-3.657L4 8m16 8-2.343 2.657A8 8 0 014 15"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
/>
|
||||
</svg>
|
||||
</Button>
|
||||
<Button
|
||||
isIconOnly
|
||||
className="bg-danger/10 text-danger hover:bg-danger/20"
|
||||
@@ -958,6 +983,7 @@ const SortableCompactTableRow = ({
|
||||
handleEdit,
|
||||
handleDelete,
|
||||
handleDiagnose,
|
||||
handleResetFlow,
|
||||
showAddressModal,
|
||||
hasMultipleAddresses,
|
||||
formatFlow,
|
||||
@@ -1144,6 +1170,29 @@ const SortableCompactTableRow = ({
|
||||
/>
|
||||
</svg>
|
||||
</Button>
|
||||
<Button
|
||||
isIconOnly
|
||||
className="bg-secondary/10 text-secondary hover:bg-secondary/20"
|
||||
isDisabled={(forward.inFlow || 0) + (forward.outFlow || 0) <= 0}
|
||||
size="sm"
|
||||
title="流量清零"
|
||||
onPress={() => handleResetFlow(forward)}
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="h-4 w-4"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M4 4v6h6M20 20v-6h-6M20 9a8 8 0 00-13.657-3.657L4 8m16 8-2.343 2.657A8 8 0 014 15"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
/>
|
||||
</svg>
|
||||
</Button>
|
||||
<Button
|
||||
isIconOnly
|
||||
className="bg-danger/10 text-danger hover:bg-danger/20"
|
||||
@@ -1289,13 +1338,18 @@ export default function ForwardPage() {
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
// isFilterModalOpen removed
|
||||
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
|
||||
const [resetFlowModalOpen, setResetFlowModalOpen] = useState(false);
|
||||
const [addressModalOpen, setAddressModalOpen] = useState(false);
|
||||
const [diagnosisModalOpen, setDiagnosisModalOpen] = useState(false);
|
||||
const [isEdit, setIsEdit] = useState(false);
|
||||
const [submitLoading, setSubmitLoading] = useState(false);
|
||||
const [deleteLoading, setDeleteLoading] = useState(false);
|
||||
const [resetFlowLoading, setResetFlowLoading] = useState(false);
|
||||
const [diagnosisLoading, setDiagnosisLoading] = useState(false);
|
||||
const [forwardToDelete, setForwardToDelete] = useState<Forward | null>(null);
|
||||
const [forwardToResetFlow, setForwardToResetFlow] = useState<Forward | null>(
|
||||
null,
|
||||
);
|
||||
const [currentDiagnosisForward, setCurrentDiagnosisForward] =
|
||||
useState<Forward | null>(null);
|
||||
const [diagnosisResult, setDiagnosisResult] =
|
||||
@@ -2171,7 +2225,8 @@ export default function ForwardPage() {
|
||||
maxConn: forward.maxConn ?? 0,
|
||||
proxyProtocol: forward.proxyProtocol ?? 0,
|
||||
proxyProtocolReceive: forward.proxyProtocolReceive ?? 0,
|
||||
proxyProtocolSend: forward.proxyProtocolSend ?? forward.proxyProtocol ?? 0,
|
||||
proxyProtocolSend:
|
||||
forward.proxyProtocolSend ?? forward.proxyProtocol ?? 0,
|
||||
});
|
||||
setErrors({});
|
||||
setModalOpen(true);
|
||||
@@ -2183,6 +2238,46 @@ export default function ForwardPage() {
|
||||
setDeleteModalOpen(true);
|
||||
};
|
||||
|
||||
const handleResetFlow = (forward: Forward) => {
|
||||
if ((forward.inFlow || 0) + (forward.outFlow || 0) <= 0) return;
|
||||
|
||||
setForwardToResetFlow(forward);
|
||||
setResetFlowModalOpen(true);
|
||||
};
|
||||
|
||||
const handleResetFlowModalOpenChange = (isOpen: boolean) => {
|
||||
if (resetFlowLoading) return;
|
||||
|
||||
setResetFlowModalOpen(isOpen);
|
||||
if (!isOpen) {
|
||||
setForwardToResetFlow(null);
|
||||
}
|
||||
};
|
||||
|
||||
const confirmResetFlow = async () => {
|
||||
if (!forwardToResetFlow) return;
|
||||
|
||||
setResetFlowLoading(true);
|
||||
try {
|
||||
const res = await resetForwardFlow(forwardToResetFlow.id);
|
||||
|
||||
if (res.code !== 0) {
|
||||
toast.error(res.msg || "流量清零失败");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
toast.success("规则流量已清零");
|
||||
setResetFlowModalOpen(false);
|
||||
setForwardToResetFlow(null);
|
||||
await refreshForwardList(false);
|
||||
} catch {
|
||||
toast.error("流量清零失败");
|
||||
} finally {
|
||||
setResetFlowLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 确认删除规则
|
||||
const confirmDelete = async () => {
|
||||
if (!forwardToDelete) return;
|
||||
@@ -3957,7 +4052,7 @@ export default function ForwardPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-1.5 mt-3">
|
||||
<div className="grid grid-cols-2 gap-1.5 mt-3">
|
||||
<Button
|
||||
className="flex-1 min-h-8"
|
||||
color="primary"
|
||||
@@ -4000,6 +4095,32 @@ export default function ForwardPage() {
|
||||
>
|
||||
诊断
|
||||
</Button>
|
||||
<Button
|
||||
className="flex-1 min-h-8"
|
||||
color="secondary"
|
||||
isDisabled={(forward.inFlow || 0) + (forward.outFlow || 0) <= 0}
|
||||
size="sm"
|
||||
startContent={
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="w-3 h-3"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M4 4v6h6M20 20v-6h-6M20 9a8 8 0 00-13.657-3.657L4 8m16 8-2.343 2.657A8 8 0 014 15"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
variant="flat"
|
||||
onPress={() => handleResetFlow(forward)}
|
||||
>
|
||||
清零
|
||||
</Button>
|
||||
<Button
|
||||
className="flex-1 min-h-8"
|
||||
color="danger"
|
||||
@@ -4302,7 +4423,7 @@ export default function ForwardPage() {
|
||||
<TableColumn className="w-[80px]">策略</TableColumn>
|
||||
<TableColumn className="w-[100px]">用量</TableColumn>
|
||||
<TableColumn className="w-[80px]">状态</TableColumn>
|
||||
<TableColumn align="left" className="w-[120px] pl-4">
|
||||
<TableColumn align="left" className="w-[160px] pl-4">
|
||||
操作
|
||||
</TableColumn>
|
||||
</TableHeader>
|
||||
@@ -4321,6 +4442,7 @@ export default function ForwardPage() {
|
||||
handleDelete={handleDelete}
|
||||
handleDiagnose={handleDiagnose}
|
||||
handleEdit={handleEdit}
|
||||
handleResetFlow={handleResetFlow}
|
||||
handleServiceToggle={handleServiceToggle}
|
||||
hasMultipleAddresses={hasMultipleAddresses}
|
||||
selectMode={selectMode}
|
||||
@@ -4616,6 +4738,7 @@ export default function ForwardPage() {
|
||||
handleDelete={handleDelete}
|
||||
handleDiagnose={handleDiagnose}
|
||||
handleEdit={handleEdit}
|
||||
handleResetFlow={handleResetFlow}
|
||||
handleServiceToggle={
|
||||
handleServiceToggle
|
||||
}
|
||||
@@ -5172,6 +5295,59 @@ export default function ForwardPage() {
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
|
||||
{/* 规则流量清零确认模态框 */}
|
||||
<Modal
|
||||
backdrop="blur"
|
||||
classNames={{
|
||||
base: "!w-[calc(100%-32px)] !mx-auto sm:!w-full rounded-2xl overflow-hidden",
|
||||
}}
|
||||
isOpen={resetFlowModalOpen}
|
||||
placement="center"
|
||||
scrollBehavior="inside"
|
||||
size="lg"
|
||||
onOpenChange={handleResetFlowModalOpenChange}
|
||||
>
|
||||
<ModalContent>
|
||||
{(onClose) => (
|
||||
<>
|
||||
<ModalHeader className="flex flex-col gap-1">
|
||||
<h2 className="text-lg font-bold text-secondary">
|
||||
确认流量清零
|
||||
</h2>
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<p className="text-default-600">
|
||||
确定要清零规则{" "}
|
||||
<span className="font-semibold text-foreground">
|
||||
"{forwardToResetFlow?.name}"
|
||||
</span>{" "}
|
||||
当前显示的上传和下载流量吗?
|
||||
</p>
|
||||
<p className="text-small text-default-500 mt-2">
|
||||
此操作不可撤销,但不会影响用户总流量、用户隧道配额和历史统计。
|
||||
</p>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
isDisabled={resetFlowLoading}
|
||||
variant="light"
|
||||
onPress={onClose}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
color="secondary"
|
||||
isLoading={resetFlowLoading}
|
||||
onPress={confirmResetFlow}
|
||||
>
|
||||
确认清零
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</>
|
||||
)}
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
|
||||
{/* 地址列表弹窗 */}
|
||||
<Modal
|
||||
classNames={{
|
||||
|
||||
Reference in New Issue
Block a user