update at 2026-03-05 19:48:59

This commit is contained in:
douboer@gmail.com
2026-03-05 19:48:59 +08:00
parent 5fbfdc651f
commit bfec154c52
4 changed files with 65 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
<path d="M4 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V2z"/>
<path d="M2 6a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2v-1H6a3 3 0 0 1-3-3V6H2z"/>
</svg>

After

Width:  |  Height:  |  Size: 284 B

View File

@@ -198,6 +198,41 @@ export const useServerStore = defineStore("server", () => {
} }
} }
async function copyServer(serverId: string): Promise<void> {
const sourceServer = servers.value.find((item) => item.id === serverId);
if (!sourceServer) {
throw new Error("源服务器不存在");
}
// 创建新服务器,复制所有信息
const copiedServer: ServerProfile = {
...sourceServer,
id: `srv-${crypto.randomUUID()}`,
name: `${sourceServer.name}-copy`,
projectPresets: [...sourceServer.projectPresets],
tags: [...sourceServer.tags],
lastConnectedAt: ""
};
// 复制凭据
try {
const sourceCredential = await getCredentialInput(serverId);
if (sourceCredential) {
await saveCredential(copiedServer.id, sourceCredential);
}
} catch (error) {
// 如果凭据复制失败,仍然创建服务器,但不复制凭据
console.warn("复制凭据失败:", error);
}
// 保存新服务器(插入到源服务器后面)
const sourceIndex = servers.value.findIndex((item) => item.id === serverId);
const nextServers = [...servers.value];
nextServers.splice(sourceIndex + 1, 0, copiedServer);
await persistServerOrder(nextServers);
selectedServerId.value = copiedServer.id;
}
/** /**
* 将指定服务器上移一位。 * 将指定服务器上移一位。
* 返回: * 返回:
@@ -371,6 +406,7 @@ export const useServerStore = defineStore("server", () => {
createServer, createServer,
saveServer, saveServer,
deleteServer, deleteServer,
copyServer,
moveServerUp, moveServerUp,
moveServerDown, moveServerDown,
applyServerOrder, applyServerOrder,

View File

@@ -637,6 +637,7 @@ select.input {
margin-left: 3px; margin-left: 3px;
} }
.server-copy-btn,
.server-ai-btn, .server-ai-btn,
.server-move-btn, .server-move-btn,
.connect-icon-btn { .connect-icon-btn {
@@ -652,12 +653,18 @@ select.input {
transition: background-color 0.16s ease, box-shadow 0.16s ease, opacity 0.16s ease; transition: background-color 0.16s ease, box-shadow 0.16s ease, opacity 0.16s ease;
} }
.server-copy-icon,
.server-ai-icon { .server-ai-icon {
width: 22px; width: 22px;
height: 22px; height: 22px;
background-color: var(--btn); background-color: var(--btn);
} }
.server-copy-btn:hover:not(:disabled) {
background: color-mix(in srgb, var(--accent) 16%, transparent);
border-radius: 6px;
}
.server-move-btn { .server-move-btn {
border-radius: 6px; border-radius: 6px;
cursor: grab; cursor: grab;

View File

@@ -68,6 +68,15 @@
<div class="server-info-top"> <div class="server-info-top">
<p class="server-name">{{ item.name }}</p> <p class="server-name">{{ item.name }}</p>
<div class="server-row-actions" @click.stop> <div class="server-row-actions" @click.stop>
<button
class="server-copy-btn"
type="button"
title="复制服务器"
aria-label="复制服务器"
@click.stop="copyServer(item)"
>
<span class="icon-mask server-copy-icon" style="--icon: url('/icons/copy.svg')" aria-hidden="true"></span>
</button>
<button <button
class="server-ai-btn" class="server-ai-btn"
type="button" type="button"
@@ -283,6 +292,15 @@ async function openCodexForServer(server: ServerProfile): Promise<void> {
} }
} }
async function copyServer(server: ServerProfile): Promise<void> {
try {
await serverStore.copyServer(server.id);
appStore.notify("info", `已复制服务器: ${server.name}-copy`);
} catch (error) {
appStore.notify("error", formatActionError("复制服务器失败", error));
}
}
function canDragReorder(serverId: string): boolean { function canDragReorder(serverId: string): boolean {
return serverStore.servers.some((item) => item.id === serverId); return serverStore.servers.some((item) => item.id === serverId);
} }