feat(config): 支持通过URL参数自动配置API设置
- 新增通过URL查询参数baseUrl/baseurl和apiKey/apikey自动填充配置的功能 - 实现读取参数后从地址栏自动移除相关参数的安全机制 - 添加后台是否允许自定义渠道的检查逻辑 - 集成Ant Design的消息提示和对话框组件用于用户反馈 - 更新文档说明New API自动配置的使用方法和参数格式 - 优化配置初始化流程以处理外部软件跳转场景
This commit is contained in:
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
+ [新增] 支持New API跳转并自动填入Base URL和API Key配置。
|
||||||
|
|
||||||
|
## v0.1.0 - 2026-05-30
|
||||||
|
|
||||||
## v0.1.0 - 2026-05-26
|
## v0.1.0 - 2026-05-26
|
||||||
|
|
||||||
+ [优化] 优化我的画布、我的素材导出功能
|
+ [优化] 优化我的画布、我的素材导出功能
|
||||||
|
|||||||
@@ -51,6 +51,17 @@ docker compose -f docker-compose.local.yml up -d --build
|
|||||||
|
|
||||||
如需要拉取提示词,可前往:`http://localhost:3000/admin/prompts`
|
如需要拉取提示词,可前往:`http://localhost:3000/admin/prompts`
|
||||||
|
|
||||||
|
## New API 自动配置
|
||||||
|
|
||||||
|
如果使用 New API,可在 `系统设置 -> 聊天方式 -> 添加聊天设置` 中填入:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://infinite-canvas-cpco.onrender.com?apiKey={key}&baseUrl={address}
|
||||||
|
```
|
||||||
|
|
||||||
|
跳转后会自动打开配置弹窗并填入 API Key 和 Base URL。
|
||||||
|
如果自己部署了,可以把 `https://infinite-canvas-cpco.onrender.com` 替换成你部署的地址。
|
||||||
|
|
||||||
## 效果展示
|
## 效果展示
|
||||||
|
|
||||||
<table width="100%">
|
<table width="100%">
|
||||||
@@ -89,7 +100,6 @@ docker compose -f docker-compose.local.yml up -d --build
|
|||||||
|
|
||||||
本项目使用 GNU Affero General Public License v3.0,见 [LICENSE](LICENSE)。
|
本项目使用 GNU Affero General Public License v3.0,见 [LICENSE](LICENSE)。
|
||||||
|
|
||||||
|
|
||||||
## Star History
|
## Star History
|
||||||
|
|
||||||
<a href="https://www.star-history.com/?repos=basketikun%2Finfinite-canvas&type=date&legend=top-left">
|
<a href="https://www.star-history.com/?repos=basketikun%2Finfinite-canvas&type=date&legend=top-left">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# 待测试
|
# 待测试
|
||||||
|
|
||||||
|
- 外部软件可通过 URL 查询参数 `baseUrl`/`baseurl` 和 `apiKey`/`apikey` 跳转到前端;读取后会从地址栏移除这些参数,后台允许自定义渠道时会自动切到自定义渠道、填入配置并打开配置弹窗,未允许时会打开配置弹窗并提示无法导入。
|
||||||
- 画布项目导出改为下载 `.zip` 压缩包,包内包含 `projects.json` 和当前画布引用到的本地图片、视频文件,避免只导出 JSON 时丢失媒体内容。
|
- 画布项目导出改为下载 `.zip` 压缩包,包内包含 `projects.json` 和当前画布引用到的本地图片、视频文件,避免只导出 JSON 时丢失媒体内容。
|
||||||
- 画布库支持多选后一键导出多个画布项目,导出的压缩包可一次恢复多个项目。
|
- 画布库支持多选后一键导出多个画布项目,导出的压缩包可一次恢复多个项目。
|
||||||
- 画布项目导入改为读取新版 `.zip` 压缩包,会先按 `projects.json` 中的文件映射恢复图片、视频到本地存储,再插入画布项目,导入成功后仍停留在画布库。
|
- 画布项目导入改为读取新版 `.zip` 压缩包,会先按 `projects.json` 中的文件映射恢复图片、视频到本地存储,再插入画布项目,导入成功后仍停留在画布库。
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
import { useEffect } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
|
import { App } from "antd";
|
||||||
|
|
||||||
import { useConfigStore } from "@/stores/use-config-store";
|
import { useConfigStore } from "@/stores/use-config-store";
|
||||||
import { useUserStore } from "@/stores/use-user-store";
|
import { useUserStore } from "@/stores/use-user-store";
|
||||||
|
|
||||||
export function ClientRootInit({ children }: { children: ReactNode }) {
|
export function ClientRootInit({ children }: { children: ReactNode }) {
|
||||||
|
const { message } = App.useApp();
|
||||||
|
const handledConfigParams = useRef(false);
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const hydrateUser = useUserStore((state) => state.hydrateUser);
|
const hydrateUser = useUserStore((state) => state.hydrateUser);
|
||||||
const loadPublicSettings = useConfigStore((state) => state.loadPublicSettings);
|
const loadPublicSettings = useConfigStore((state) => state.loadPublicSettings);
|
||||||
|
const publicSettings = useConfigStore((state) => state.publicSettings);
|
||||||
|
const updateConfig = useConfigStore((state) => state.updateConfig);
|
||||||
|
const openConfigDialog = useConfigStore((state) => state.openConfigDialog);
|
||||||
const isLoginPage = pathname === "/login" || pathname === "/admin/login";
|
const isLoginPage = pathname === "/login" || pathname === "/admin/login";
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -21,5 +27,29 @@ export function ClientRootInit({ children }: { children: ReactNode }) {
|
|||||||
if (!isLoginPage) void hydrateUser();
|
if (!isLoginPage) void hydrateUser();
|
||||||
}, [hydrateUser, isLoginPage]);
|
}, [hydrateUser, isLoginPage]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (handledConfigParams.current) return;
|
||||||
|
const searchParams = new URLSearchParams(window.location.search);
|
||||||
|
const baseUrl = searchParams.get("baseUrl") || searchParams.get("baseurl");
|
||||||
|
const apiKey = searchParams.get("apiKey") || searchParams.get("apikey");
|
||||||
|
if (!baseUrl && !apiKey) return;
|
||||||
|
if (!publicSettings) return;
|
||||||
|
handledConfigParams.current = true;
|
||||||
|
searchParams.delete("baseUrl");
|
||||||
|
searchParams.delete("baseurl");
|
||||||
|
searchParams.delete("apiKey");
|
||||||
|
searchParams.delete("apikey");
|
||||||
|
window.history.replaceState(null, "", `${window.location.pathname}${searchParams.size ? `?${searchParams}` : ""}${window.location.hash}`);
|
||||||
|
if (!publicSettings.modelChannel.allowCustomChannel) {
|
||||||
|
openConfigDialog(false);
|
||||||
|
message.error("后台未允许用户自定义渠道,请联系管理员进行配置");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateConfig("channelMode", "local");
|
||||||
|
if (baseUrl) updateConfig("baseUrl", baseUrl);
|
||||||
|
if (apiKey) updateConfig("apiKey", apiKey);
|
||||||
|
openConfigDialog(false);
|
||||||
|
}, [message, openConfigDialog, publicSettings, updateConfig]);
|
||||||
|
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user