Skip to content

Commit bcb0f8e

Browse files
committed
feat: 主控支持更改密钥
1 parent f9d98a9 commit bcb0f8e

1 file changed

Lines changed: 80 additions & 1 deletion

File tree

app/endpoints/page.tsx

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,12 @@ import {
5858
faTable,
5959
faFileLines,
6060
faLayerGroup,
61-
faSync
61+
faSync,
62+
faKey
6263
} from "@fortawesome/free-solid-svg-icons";
6364
import AddEndpointModal from "./components/add-endpoint-modal";
6465
import RenameEndpointModal from "./components/rename-endpoint-modal";
66+
import EditApiKeyModal from "./components/edit-apikey-modal";
6567
import { buildApiUrl } from '@/lib/utils';
6668
import { copyToClipboard } from '@/lib/utils/clipboard';
6769
import ManualCopyModal from '@/components/ui/manual-copy-modal';
@@ -115,6 +117,7 @@ export default function EndpointsPage() {
115117
const {isOpen: isAddOpen, onOpen: onAddOpen, onOpenChange: onAddOpenChange} = useDisclosure();
116118
const {isOpen: isDeleteOpen, onOpen: onDeleteOpen, onOpenChange: onDeleteOpenChange} = useDisclosure();
117119
const {isOpen: isRenameOpen, onOpen: onRenameOpen, onOpenChange: onRenameOpenChange} = useDisclosure();
120+
const {isOpen: isEditApiKeyOpen, onOpen: onEditApiKeyOpen, onOpenChange: onEditApiKeyOpenChange} = useDisclosure();
118121
const [selectedEndpoint, setSelectedEndpoint] = useState<FormattedEndpoint | null>(null);
119122
// Next.js 路由
120123
const router = useRouter();
@@ -509,6 +512,9 @@ export default function EndpointsPage() {
509512
case 'rename':
510513
handleCardClick(endpoint);
511514
break;
515+
case 'editApiKey':
516+
handleEditApiKeyClick(endpoint);
517+
break;
512518
case 'copy':
513519
handleCopyConfig(endpoint);
514520
break;
@@ -525,6 +531,7 @@ export default function EndpointsPage() {
525531
<DropdownItem key="addTunnel" startContent={<FontAwesomeIcon icon={faPlus}/>} className="text-primary" color="primary">添加实例</DropdownItem>
526532
<DropdownItem key="refresTunnel" startContent={<FontAwesomeIcon icon={faSync}/>} className="text-secondary" color="secondary">同步实例</DropdownItem>
527533
<DropdownItem key="rename" startContent={<FontAwesomeIcon icon={faPen} />} className="text-warning" color="warning">重命名</DropdownItem>
534+
<DropdownItem key="editApiKey" startContent={<FontAwesomeIcon icon={faKey} />} className="text-warning" color="warning">修改密钥</DropdownItem>
528535
<DropdownItem key="copy" startContent={<FontAwesomeIcon icon={faCopy}/>} className="text-success" color="success">复制配置</DropdownItem>
529536
<DropdownItem
530537
key="toggle"
@@ -618,6 +625,61 @@ export default function EndpointsPage() {
618625
}
619626
};
620627

628+
// 处理修改密钥
629+
const handleEditApiKey = async (newApiKey: string) => {
630+
if (!selectedEndpoint?.id) return;
631+
632+
try {
633+
// 1. 先断开连接
634+
await handleDisconnect(selectedEndpoint.id);
635+
636+
// 2. 更新密钥
637+
const response = await fetch(buildApiUrl(`/api/endpoints/${selectedEndpoint.id}`), {
638+
method: 'PUT',
639+
headers: {
640+
'Content-Type': 'application/json',
641+
},
642+
body: JSON.stringify({
643+
apiKey: newApiKey,
644+
action: 'editApiKey'
645+
}),
646+
});
647+
648+
if (!response.ok) {
649+
const errorData = await response.json();
650+
throw new Error(errorData.error || '修改密钥失败');
651+
}
652+
653+
addToast({
654+
title: "密钥修改成功",
655+
description: "API Key 已更新,正在重新连接...",
656+
color: "success",
657+
});
658+
659+
// 3. 刷新主控列表
660+
await fetchEndpoints();
661+
662+
// 4. 重新连接
663+
setTimeout(async () => {
664+
await handleConnect(selectedEndpoint.id);
665+
}, 1000);
666+
667+
} catch (error) {
668+
addToast({
669+
title: "修改密钥失败",
670+
description: error instanceof Error ? error.message : "请稍后重试",
671+
color: "danger",
672+
});
673+
throw error; // 重新抛出错误以便模态框处理
674+
}
675+
};
676+
677+
// 打开修改密钥弹窗
678+
const handleEditApiKeyClick = (endpoint: FormattedEndpoint) => {
679+
setSelectedEndpoint(endpoint);
680+
onEditApiKeyOpen();
681+
};
682+
621683
// 打开添加隧道弹窗
622684
const {isOpen: isAddTunnelOpen, onOpen: onAddTunnelOpen, onOpenChange: onAddTunnelOpenChange} = useDisclosure();
623685
const [tunnelUrl, setTunnelUrl] = useState('');
@@ -1014,6 +1076,12 @@ export default function EndpointsPage() {
10141076
<FontAwesomeIcon icon={faSync} />
10151077
</Button>
10161078
</Tooltip>
1079+
{/* 修改密钥 */}
1080+
<Tooltip content="修改密钥">
1081+
<Button isIconOnly size="sm" variant="light" color="warning" onPress={()=>handleEditApiKeyClick(ep)}>
1082+
<FontAwesomeIcon icon={faKey} />
1083+
</Button>
1084+
</Tooltip>
10171085
{/* 复制配置 */}
10181086
<Tooltip content="复制配置">
10191087
<Button isIconOnly size="sm" variant="light" color="success" onPress={()=>handleCopyConfig(ep)}>
@@ -1074,6 +1142,17 @@ export default function EndpointsPage() {
10741142
/>
10751143
)}
10761144

1145+
{/* 修改密钥模态框 */}
1146+
{selectedEndpoint && (
1147+
<EditApiKeyModal
1148+
isOpen={isEditApiKeyOpen}
1149+
onOpenChange={onEditApiKeyOpenChange}
1150+
currentApiKey={selectedEndpoint.apiKey}
1151+
endpointName={selectedEndpoint.name}
1152+
onSave={handleEditApiKey}
1153+
/>
1154+
)}
1155+
10771156
{/* 添加隧道弹窗 */}
10781157
<Modal isOpen={isAddTunnelOpen} onOpenChange={onAddTunnelOpenChange} placement="center">
10791158
<ModalContent>

0 commit comments

Comments
 (0)