feat: add backend URL preset sharing via URL parameters

- Add URL param support (?api_url=, ?username=) for shareable config
- Add share link button to server config dialog
- Fix ToolSet API bug: tools.func_list -> tools.list_tools()
- Fix Vue template bugs in CommandTable.vue (orphaned v-else, wrong prop)
- Use master version of InstalledPluginsTab.vue (dev had pre-existing bugs)

BREAKING CHANGE: Uses master version for InstalledPluginsTab.vue
This commit is contained in:
LIghtJUNction
2026-03-26 00:20:52 +08:00
parent c529c716f4
commit 292199dcac
7 changed files with 398 additions and 769 deletions

View File

@@ -549,7 +549,7 @@ class ProviderOpenAIOfficial(Provider):
# 工具集未提供
# Should be unreachable
raise Exception("工具集未提供")
for tool in tools.func_list:
for tool in tools.list_tools():
if (
tool_call.type == "function"
and tool.name == tool_call.function.name

View File

@@ -101,7 +101,7 @@ const canEditPermission = (cmd: CommandItem): boolean => cmd.supports_permission
<v-data-table
:headers="commandHeaders"
:items="items"
item-value="command_key"
item-key="handler_full_name"
hover
:row-props="getRowProps"
:loading="props.loading"
@@ -201,14 +201,6 @@ const canEditPermission = (cmd: CommandItem): boolean => cmd.supports_permission
</v-list-item>
</v-list>
</v-menu>
<v-chip
v-else
:color="getPermissionColor(item.permission)"
size="small"
class="font-weight-medium"
>
{{ getPermissionLabel(item.permission) }}
</v-chip>
</template>
<template #item.enabled="{ item }">

View File

@@ -3,6 +3,9 @@
"username": "Username",
"password": "Password",
"defaultHint": "Default username: astrbot. Run `astrbot conf admin` before the first login.",
"shareLink": "Share Link",
"linkCopied": "Link copied to clipboard",
"linkCopyFailed": "Failed to copy link",
"logo": {
"title": "AstrBot Dashboard",
"subtitle": "Welcome"

View File

@@ -3,6 +3,9 @@
"username": "用户名",
"password": "密码",
"defaultHint": "默认账户为astrbot请先执行 `astrbot conf admin` 设置密码",
"shareLink": "分享链接",
"linkCopied": "链接已复制到剪贴板",
"linkCopyFailed": "复制链接失败",
"logo": {
"title": "AstrBot WebUI",
"subtitle": "欢迎使用"

View File

@@ -21,6 +21,42 @@ const toast = useToast();
const serverConfigDialog = ref(false);
const apiUrl = ref(apiStore.apiBaseUrl);
// URL parameter handling for shareable config
function applyUrlParams() {
const params = new URLSearchParams(window.location.search);
const apiUrlParam = params.get("api_url");
const usernameParam = params.get("username");
if (apiUrlParam) {
apiUrl.value = apiUrlParam;
const validationError = getApiBaseUrlValidationError(apiUrlParam);
if (!validationError) {
apiStore.setApiBaseUrl(apiUrlParam);
}
}
if (usernameParam) {
window.dispatchEvent(
new CustomEvent("astrbot-url-param-username", {
detail: { username: usernameParam },
})
);
}
}
function getShareableUrl() {
const url = new URL(window.location.href);
url.searchParams.set("api_url", apiUrl.value);
return url.toString();
}
async function copyShareableUrl() {
try {
await navigator.clipboard.writeText(getShareableUrl());
toast.success(t("linkCopied"));
} catch {
toast.error(t("linkCopyFailed"));
}
}
const showAddPreset = ref(false);
const newPresetName = ref("");
const newPresetUrl = ref("");
@@ -58,6 +94,9 @@ function toggleTheme() {
}
onMounted(() => {
// 应用URL参数用于分享预设配置
applyUrlParams();
// 检查用户是否已登录,如果已登录则重定向
if (authStore.has_token()) {
router.push(authStore.returnUrl || "/");
@@ -257,6 +296,17 @@ onMounted(() => {
variant="outlined"
density="compact"
/>
<v-btn
variant="tonal"
size="small"
block
class="mt-2"
prepend-icon="mdi-share-variant"
@click="copyShareableUrl"
>
{{ t("shareLink") }}
</v-btn>
</v-card-text>
<v-card-actions>
<v-spacer />

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref } from "vue";
import { ref, onMounted, onUnmounted } from "vue";
import { useAuthStore } from "@/stores/auth";
import { Form } from "vee-validate";
import { useModuleI18n } from "@/i18n/composables";
@@ -11,6 +11,27 @@ const password = ref("");
const username = ref("");
const loading = ref(false);
// 从URL参数读取用户名
const params = new URLSearchParams(window.location.search);
const usernameParam = params.get("username");
if (usernameParam) {
username.value = usernameParam;
}
// 监听从LoginPage传来的用户名参数
function handleUsernameParam(event: Event) {
const customEvent = event as CustomEvent<{ username: string }>;
username.value = customEvent.detail.username;
}
onMounted(() => {
window.addEventListener("astrbot-url-param-username", handleUsernameParam);
});
onUnmounted(() => {
window.removeEventListener("astrbot-url-param-username", handleUsernameParam);
});
/* eslint-disable @typescript-eslint/no-explicit-any */
async function validate(_values: any, { setErrors }: any) {
loading.value = true;

File diff suppressed because it is too large Load Diff