feat(pixelle): 连接管理页加 Pixelle 连接卡片

Accounts 页加 Pixelle 连接卡片(URL+2key+保存),api.ts adminApi 加 get/savePixelleConnection。
api.ts 一并带入此前累积的 files URL 改写改动。

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
boos
2026-06-18 13:13:57 +08:00
parent 92d38bb309
commit 1d19401424
2 changed files with 87 additions and 2 deletions
+23 -2
View File
@@ -2102,8 +2102,22 @@ export const api = {
{ preserveAuthErrors: true }, { preserveAuthErrors: true },
), ),
fileUrl: (path: string) => { fileUrl: (path: string) => {
if (/^(https?:|blob:|data:)/i.test(path) || path.startsWith("/api/")) return path; if (/^(blob:|data:)/i.test(path) || path.startsWith("/api/")) return path;
const trimmed = String(path || "").replace(/^\/+/, ""); let trimmed = String(path || "").trim();
if (/^https?:/i.test(trimmed)) {
try {
const url = new URL(trimmed);
if ((url.hostname === "127.0.0.1" || url.hostname === "localhost") && url.pathname.startsWith("/api/files/")) {
trimmed = url.pathname.replace(/^\/api\/files\/?/, "");
} else {
return trimmed;
}
} catch {
return trimmed;
}
}
trimmed = trimmed.replace(/^\/+/, "");
trimmed = trimmed.replace(/^api\/files\/?/, "");
const segments = trimmed.split("/").map((segment) => encodeURIComponent(segment)); const segments = trimmed.split("/").map((segment) => encodeURIComponent(segment));
return `/api/digital-human/pixelle/files/${segments.join("/")}`; return `/api/digital-human/pixelle/files/${segments.join("/")}`;
}, },
@@ -2912,6 +2926,13 @@ export const api = {
request<MoneyPrinterJobResponse>(`/api/money-printer/jobs/${encodeURIComponent(id)}/cancel`, { method: "POST" }), request<MoneyPrinterJobResponse>(`/api/money-printer/jobs/${encodeURIComponent(id)}/cancel`, { method: "POST" }),
clearMoneyPrinterJobs: () => clearMoneyPrinterJobs: () =>
request<{ success: boolean; cleared: number }>("/api/money-printer/jobs/clear", { method: "POST" }), request<{ success: boolean; cleared: number }>("/api/money-printer/jobs/clear", { method: "POST" }),
getPixelleConnection: () =>
request<{ success: boolean; connection: { comfyuiUrl?: string | null; runninghubApiKey?: string | null; comfyuiApiKey?: string | null } }>("/api/admin/pixelle/connection"),
savePixelleConnection: (data: { runninghubApiKey?: string; comfyuiUrl?: string; comfyuiApiKey?: string }) =>
request<{ success: boolean; backup?: string; restarted?: boolean; warning?: string }>("/api/admin/pixelle/connection", {
method: "PUT",
body: JSON.stringify(data),
}),
}; };
export const userApi = { export const userApi = {
register: (data: { register: (data: {
+64
View File
@@ -203,6 +203,36 @@ export default function Accounts() {
const lastRebindTargetRef = useRef<any | null>(null); const lastRebindTargetRef = useRef<any | null>(null);
const modelModalRequestSeqRef = useRef(0); const modelModalRequestSeqRef = useRef(0);
const toast = useToast(); const toast = useToast();
const [pxConn, setPxConn] = useState({ comfyuiUrl: "", runninghubApiKey: "", comfyuiApiKey: "" });
const [pxSaving, setPxSaving] = useState(false);
useEffect(() => {
api
.getPixelleConnection()
.then((r) =>
setPxConn({
comfyuiUrl: r.connection?.comfyuiUrl || "",
runninghubApiKey: r.connection?.runninghubApiKey || "",
comfyuiApiKey: r.connection?.comfyuiApiKey || "",
}),
)
.catch(() => {});
}, []);
const savePxConn = async () => {
setPxSaving(true);
try {
const res = await api.savePixelleConnection({
runninghubApiKey: pxConn.runninghubApiKey || undefined,
comfyuiUrl: pxConn.comfyuiUrl || undefined,
comfyuiApiKey: pxConn.comfyuiApiKey || undefined,
});
if (res.warning) toast.error(res.warning);
else toast.success("已保存并重启 Pixelle,约数秒生效");
} catch (e: any) {
toast.error(e?.message || "保存失败");
} finally {
setPxSaving(false);
}
};
if (rebindTarget) lastRebindTargetRef.current = rebindTarget; if (rebindTarget) lastRebindTargetRef.current = rebindTarget;
const activeRebindTarget = rebindTarget || lastRebindTargetRef.current; const activeRebindTarget = rebindTarget || lastRebindTargetRef.current;
const isRebindSub2Api = const isRebindSub2Api =
@@ -3677,6 +3707,40 @@ export default function Accounts() {
} }
onAddManualModels={handleAddManualModels} onAddManualModels={handleAddManualModels}
/> />
<div className="card" style={{ marginTop: 16, padding: 16 }}>
<h3>Pixelle 连接</h3>
<label style={{ display: "block", marginBottom: 8 }}>
<span>ComfyUI URL</span>
<input
value={pxConn.comfyuiUrl}
onChange={(e) => setPxConn((s) => ({ ...s, comfyuiUrl: e.target.value }))}
placeholder="http://172.17.0.1:4000/comfy-cloud"
style={{ width: "100%" }}
/>
</label>
<label style={{ display: "block", marginBottom: 8 }}>
<span>RunningHub API Key</span>
<input
value={pxConn.runninghubApiKey}
onChange={(e) => setPxConn((s) => ({ ...s, runninghubApiKey: e.target.value }))}
placeholder="留空或 •••• 表示不改"
style={{ width: "100%" }}
/>
</label>
<label style={{ display: "block", marginBottom: 8 }}>
<span>Comfy Cloud API Key</span>
<input
value={pxConn.comfyuiApiKey}
onChange={(e) => setPxConn((s) => ({ ...s, comfyuiApiKey: e.target.value }))}
placeholder="留空或 •••• 表示不改"
style={{ width: "100%" }}
/>
</label>
<button type="button" className="btn btn-primary" disabled={pxSaving} onClick={savePxConn}>
{pxSaving ? "保存中..." : "保存并重启 Pixelle"}
</button>
</div>
</div> </div>
); );
} }