feat(node): split node page into local and remote sections

This commit is contained in:
Su-cyber-art
2026-03-08 18:45:56 +08:00
parent 4c69ff491d
commit 61b71a11c7
+12 -38
View File
@@ -1,6 +1,6 @@
import { useState, useEffect, useMemo, useCallback } from "react"; import { useState, useEffect, useMemo, useCallback } from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import { useNavigate } from "react-router-dom";
import { import {
DndContext, DndContext,
KeyboardSensor, KeyboardSensor,
@@ -66,7 +66,7 @@ import { useNodeOfflineTimers } from "@/pages/node/use-node-offline-timers";
import { useNodeRealtime } from "@/pages/node/use-node-realtime"; import { useNodeRealtime } from "@/pages/node/use-node-realtime";
import { useLocalStorageState } from "@/hooks/use-local-storage-state"; import { useLocalStorageState } from "@/hooks/use-local-storage-state";
import { loadStoredOrder, saveOrder } from "@/utils/order-storage"; import { loadStoredOrder, saveOrder } from "@/utils/order-storage";
import { PlusIcon, DeleteIcon, CheckAllIcon, XCircleIcon, ListCheckIcon, XIcon, ArrowUpIcon, ShareIcon } from "@/components/icons";
interface Node { interface Node {
id: number; id: number;
@@ -190,7 +190,6 @@ const SortableItem = ({
}; };
export default function NodePage() { export default function NodePage() {
const navigate = useNavigate();
const [nodeList, setNodeList] = useState<Node[]>([]); const [nodeList, setNodeList] = useState<Node[]>([]);
const [nodeOrder, setNodeOrder] = useState<number[]>([]); const [nodeOrder, setNodeOrder] = useState<number[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -1222,95 +1221,70 @@ export default function NodePage() {
{selectMode ? ( {selectMode ? (
<> <>
<span className="text-sm text-default-600 shrink-0"> <span className="text-sm text-default-600 shrink-0">
已选择 {selectedIds.size} 项 已选 {selectedIds.size} 项
</span> </span>
<Button <Button
isIconOnly
color="primary" color="primary"
size="sm" size="sm"
title="全选"
variant="flat" variant="flat"
onPress={selectAll} onPress={selectAll}
> >
<CheckAllIcon className="w-4 h-4" /> 全选
</Button> </Button>
<Button <Button
isIconOnly
color="secondary" color="secondary"
size="sm" size="sm"
title="清空"
variant="flat" variant="flat"
onPress={deselectAll} onPress={deselectAll}
> >
<XCircleIcon className="w-4 h-4" /> 清空
</Button> </Button>
<Button <Button
isIconOnly
color="warning" color="warning"
isDisabled={selectedIds.size === 0} isDisabled={selectedIds.size === 0}
isLoading={batchUpgradeLoading} isLoading={batchUpgradeLoading}
size="sm" size="sm"
title="升级"
variant="flat" variant="flat"
onPress={() => openUpgradeModal("batch")} onPress={() => openUpgradeModal("batch")}
> >
<ArrowUpIcon className="w-4 h-4" /> 升级
</Button> </Button>
<Button <Button
isIconOnly
color="danger" color="danger"
isDisabled={selectedIds.size === 0} isDisabled={selectedIds.size === 0}
size="sm" size="sm"
title="删除"
variant="flat" variant="flat"
onPress={() => setBatchDeleteModalOpen(true)} onPress={() => setBatchDeleteModalOpen(true)}
> >
<DeleteIcon className="w-4 h-4" /> 删除
</Button> </Button>
<Button <Button
isIconOnly color="secondary"
color="default"
size="sm" size="sm"
title="退出"
variant="solid" variant="solid"
onPress={toggleSelectMode} onPress={toggleSelectMode}
> >
<XIcon className="w-4 h-4" /> 退出
</Button> </Button>
</> </>
) : ( ) : (
<> <>
<Button <Button
isIconOnly className="bg-sky-100 text-sky-700 hover:bg-sky-200 dark:bg-sky-900/30 dark:text-sky-300 dark:hover:bg-sky-900/45"
className="bg-violet-100 text-violet-700 hover:bg-violet-200 dark:bg-violet-900/30 dark:text-violet-300 dark:hover:bg-violet-900/45"
color="default" color="default"
size="sm" size="sm"
title="选择"
variant="flat" variant="flat"
onPress={toggleSelectMode} onPress={toggleSelectMode}
> >
<ListCheckIcon className="w-4 h-4" /> 批量
</Button> </Button>
<Button <Button
isIconOnly
className="bg-indigo-100 text-indigo-700 hover:bg-indigo-200 dark:bg-indigo-900/30 dark:text-indigo-300 dark:hover:bg-indigo-900/45"
color="default"
size="sm"
title="面板共享"
variant="flat"
onPress={() => navigate("/panel-sharing")}
>
<ShareIcon className="w-4 h-4" />
</Button>
<Button
isIconOnly
color="primary" color="primary"
size="sm" size="sm"
title="新增"
variant="flat" variant="flat"
onPress={handleAdd} onPress={handleAdd}
> >
<PlusIcon className="w-4 h-4" /> 新增
</Button> </Button>
</> </>
)} )}