fix(dashboard): resolve JSON syntax errors and BOM in auth.json

This commit is contained in:
LIghtJUNction
2026-04-04 17:14:04 +08:00
parent f429c7203a
commit 6bff35d40c
6 changed files with 221 additions and 33 deletions

View File

@@ -54,7 +54,7 @@ def _validate_dashboard_port(value: str) -> int:
try:
port = int(value)
except ValueError:
raise click.ClickException(t("config_port_must_be_number"))
raise click.ClickException(t("config_port_must_be_number")) from None
if port < 1 or port > 65535:
raise click.ClickException(t("config_port_range_invalid"))
return port

View File

@@ -28,16 +28,16 @@
"event-source-polyfill": "^1.0.31",
"highlight.js": "^11.11.1",
"js-md5": "^0.8.3",
"katex": "^0.16.43",
"katex": "^0.16.44",
"lodash": "4.18.1",
"markdown-it": "^14.1.1",
"markstream-vue": "^0.0.9",
"mermaid": "^11.13.0",
"mermaid": "^11.14.0",
"monaco-editor": "^0.55.1",
"pinia": "3.0.0",
"pinyin-pro": "^3.28.0",
"qrcode": "^1.5.4",
"shiki": "^3.13.0",
"shiki": "^3.23.0",
"stream-markdown": "^0.0.14",
"vee-validate": "4.15.1",
"vite-plugin-vuetify": "2.1.3",
@@ -54,7 +54,7 @@
"@rushstack/eslint-patch": "1.16.1",
"@types/chance": "1.1.7",
"@types/markdown-it": "^14.1.2",
"@types/node": "^25.5.0",
"@types/node": "^25.5.2",
"@vitejs/plugin-vue": "6.0.5",
"@vue/eslint-config-prettier": "10.2.0",
"@vue/eslint-config-typescript": "14.7.0",
@@ -64,11 +64,11 @@
"prettier": "3.8.1",
"sass": "1.98.0",
"sass-loader": "16.0.7",
"subset-font": "^2.4.0",
"typescript": "~6.0.0",
"subset-font": "^2.5.0",
"typescript": "~6.0.2",
"vite": "8.0.3",
"vite-plugin-webfont-dl": "^3.12.0",
"vue-tsc": "^3.0.0"
"vue-tsc": "^3.2.6"
},
"overrides": {
"flatted": "3.4.2",

View File

@@ -10,5 +10,16 @@
"theme": {
"switchToDark": "Switch to Dark Theme",
"switchToLight": "Switch to Light Theme"
},
"serverConfig": {
"title": "Server Configuration",
"description": "If the backend is not on the same origin (host/port), please specify the full URL here.",
"label": "API Base URL",
"placeholder": "e.g. http://localhost:6185",
"hint": "Empty for default (relative path)",
"presetLabel": "Quick Select Preset",
"save": "Save & Reload",
"cancel": "Cancel",
"tooltip": "Server Configuration"
}
}
}

View File

@@ -1,14 +1,25 @@
{
"login": "Вход",
"username": "Имя пользователя",
"password": "Пароль",
"defaultHint": "Учетные данные по умолчанию: astrbot / astrbot",
"logo": {
"title": "Панель управления AstrBot",
"subtitle": "Добро пожаловать"
},
"theme": {
"switchToDark": "Перейти на темную тему",
"switchToLight": "Перейти на светлую тему"
}
}
{
"login": "Вход",
"username": "Имя пользователя",
"password": "Пароль",
"defaultHint": "Учетные данные по умолчанию: astrbot / astrbot",
"logo": {
"title": "Панель управления AstrBot",
"subtitle": "Добро пожаловать"
},
"theme": {
"switchToDark": "Перейти на темную тему",
"switchToLight": "Перейти на светлую тему"
},
"serverConfig": {
"title": "Настройки сервера",
"description": "Если бэкенд не на том же домене, укажите полный URL здесь.",
"label": "Базовый URL API",
"placeholder": "Например: http://localhost:6185",
"hint": "Оставьте пустым для настроек по умолчанию (относительный путь)",
"presetLabel": "Быстрый выбор",
"save": "Сохранить и обновить",
"cancel": "Отмена",
"tooltip": "Настройки сервера"
}
}

View File

@@ -10,5 +10,16 @@
"theme": {
"switchToDark": "切换到深色主题",
"switchToLight": "切换到浅色主题"
},
"serverConfig": {
"title": "服务器配置",
"description": "如果后端服务不在同源(主机/端口不同),请在此指定完整 URL。",
"label": "API 基础地址",
"placeholder": "例如http://localhost:6185",
"hint": "留空以使用默认设置(相对路径)",
"presetLabel": "快速选择预设",
"save": "保存并刷新",
"cancel": "取消",
"tooltip": "服务器配置"
}
}
}

View File

@@ -3,6 +3,7 @@ import AuthLogin from "../authForms/AuthLogin.vue";
import LanguageSwitcher from "@/components/shared/LanguageSwitcher.vue";
import { onMounted, ref } from "vue";
import { useAuthStore } from "@/stores/auth";
import { useApiStore } from "@/stores/api";
import { useRouter } from "vue-router";
import { useCustomizerStore } from "@/stores/customizer";
import { useModuleI18n } from "@/i18n/composables";
@@ -11,10 +12,39 @@ import { useTheme } from "vuetify";
const cardVisible = ref(false);
const router = useRouter();
const authStore = useAuthStore();
const apiStore = useApiStore();
const customizer = useCustomizerStore();
const { tm: t } = useModuleI18n("features/auth");
const theme = useTheme();
const serverConfigDialog = ref(false);
const apiUrl = ref(apiStore.apiBaseUrl);
const showAddPreset = ref(false);
const newPresetName = ref("");
const newPresetUrl = ref("");
function saveApiUrl() {
apiStore.setApiBaseUrl(apiUrl.value);
serverConfigDialog.value = false;
window.location.reload();
}
function savePreset() {
if (!newPresetName.value || !newPresetUrl.value) return;
apiStore.addPreset({
name: newPresetName.value,
url: newPresetUrl.value,
});
showAddPreset.value = false;
newPresetName.value = "";
newPresetUrl.value = "";
}
function isCustomPreset(name: string) {
return apiStore.customPresets.some((p) => p.name === name);
}
// 主题切换函数
function toggleTheme() {
const newTheme =
@@ -25,15 +55,10 @@ function toggleTheme() {
theme.global.name.value = newTheme;
}
onMounted(async () => {
onMounted(() => {
// 检查用户是否已登录,如果已登录则重定向
if (authStore.has_token()) {
const onboardingCompleted = await authStore.checkOnboardingCompleted();
if (onboardingCompleted) {
router.push("/dashboard/default");
} else {
router.push("/welcome");
}
router.push(authStore.returnUrl || "/");
return;
}
@@ -63,9 +88,31 @@ onMounted(async () => {
height: 24px !important;
opacity: 0.9 !important;
align-self: center !important;
border-color: rgba(var(--v-theme-primary), 0.45) !important;
border-color: rgba(180, 148, 246, 0.8) !important;
"
></v-divider>
<v-btn
@click="serverConfigDialog = true"
icon
variant="text"
size="small"
>
<v-icon
size="18"
:color="
useCustomizerStore().uiTheme === 'PurpleTheme'
? '#5e35b1'
: '#d7c5fa'
"
>
mdi-server
</v-icon>
<v-tooltip activator="parent" location="top">
{{ t("serverConfig.tooltip") }}
</v-tooltip>
</v-btn>
<v-btn
@click="toggleTheme"
class="theme-toggle-btn"
@@ -73,7 +120,14 @@ onMounted(async () => {
variant="text"
size="small"
>
<v-icon size="18" :color="'rgb(var(--v-theme-primary))'">
<v-icon
size="18"
:color="
useCustomizerStore().uiTheme === 'PurpleTheme'
? '#5e35b1'
: '#d7c5fa'
"
>
mdi-white-balance-sunny
</v-icon>
<v-tooltip activator="parent" location="top">
@@ -91,6 +145,107 @@ onMounted(async () => {
<AuthLogin />
</v-card-text>
</v-card>
<v-dialog v-model="serverConfigDialog" max-width="450">
<v-card>
<v-card-title>{{ t("serverConfig.title") }}</v-card-title>
<v-card-text>
<div class="text-body-2 text-medium-emphasis mb-4">
{{ t("serverConfig.description") }}
</div>
<div
v-if="
(apiStore.presets && apiStore.presets.length > 0) ||
apiStore.customPresets
"
class="mb-4"
>
<div class="d-flex justify-space-between align-center mb-2">
<div class="text-caption text-medium-emphasis">
{{ t("serverConfig.presetLabel") }}
</div>
<v-btn
size="x-small"
variant="text"
icon
@click="showAddPreset = !showAddPreset"
>
<v-icon>mdi-plus</v-icon>
</v-btn>
</div>
<v-expand-transition>
<div
v-if="showAddPreset"
class="mb-2 pa-2 bg-grey-lighten-4 rounded border"
>
<v-text-field
v-model="newPresetName"
label="Name"
density="compact"
hide-details
class="mb-2"
variant="outlined"
bg-color="white"
></v-text-field>
<v-text-field
v-model="newPresetUrl"
label="URL"
density="compact"
hide-details
class="mb-2"
variant="outlined"
bg-color="white"
></v-text-field>
<v-btn
size="small"
block
color="primary"
variant="flat"
@click="savePreset"
>Add Preset</v-btn
>
</div>
</v-expand-transition>
<v-chip-group column>
<v-chip
v-for="preset in apiStore.presets"
:key="preset.name"
size="small"
@click="apiUrl = preset.url"
:variant="apiUrl === preset.url ? 'flat' : 'tonal'"
:color="apiUrl === preset.url ? 'primary' : undefined"
:closable="isCustomPreset(preset.name)"
@click:close="apiStore.removePreset(preset.name)"
>
{{ preset.name }}
</v-chip>
</v-chip-group>
</div>
<v-text-field
v-model="apiUrl"
:label="t('serverConfig.label')"
:placeholder="t('serverConfig.placeholder')"
:hint="t('serverConfig.hint')"
persistent-hint
variant="outlined"
density="compact"
></v-text-field>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn variant="text" @click="serverConfigDialog = false">{{
t("serverConfig.cancel")
}}</v-btn>
<v-btn color="primary" variant="flat" @click="saveApiUrl">{{
t("serverConfig.save")
}}</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>