This commit is contained in:
Baobhan Sith
2025-04-20 20:50:20 +08:00
parent f8e2067b3c
commit 337911d422
5 changed files with 49 additions and 28 deletions
@@ -143,14 +143,12 @@ const saveLayout = () => {
const resetToDefault = () => {
if (confirm(t('layoutConfigurator.confirmReset', '确定要恢复默认布局吗?当前更改将丢失。'))) {
// 重新调用 store 的初始化方法来获取默认布局
layoutStore.initializeLayout();
// 重新加载到本地副本
if (layoutStore.layoutTree) {
localLayoutTree.value = JSON.parse(JSON.stringify(layoutStore.layoutTree));
hasChanges.value = true; // 标记为有更改,因为是重置操作
console.log('[LayoutConfigurator] 已重置为默认布局。');
}
// 调用 store 中获取系统默认布局的方法
const defaultLayout = layoutStore.getSystemDefaultLayout();
// 直接将获取到的默认布局(深拷贝)赋值给本地副本
localLayoutTree.value = JSON.parse(JSON.stringify(defaultLayout));
hasChanges.value = true; // 标记为有更改,因为是重置操作
console.log('[LayoutConfigurator] 已重置为系统默认布局。');
}
};
+14 -7
View File
@@ -41,17 +41,24 @@ const i18n = createI18n<[MessageSchema], 'en' | 'zh'>({
* @param lang 要设置的语言代码 ('en', 'zh', etc.)
*/
export const setLocale = (lang: 'en' | 'zh') => {
console.log(`[i18n] Attempting to set locale to: ${lang}`); // <-- 添加日志
const globalComposer = i18n.global as unknown as Composer; // 强制类型断言
if (globalComposer.availableLocales.includes(lang)) {
globalComposer.locale.value = lang; // 访问 .value 属性
try {
localStorage.setItem(localStorageKey, lang); // 持久化到 localStorage
console.log(`[i18n] Locale set to "${lang}" and saved to localStorage.`); // 添加日志
} catch (e) {
console.error('[i18n] Failed to save locale to localStorage:', e);
const currentLocale = globalComposer.locale.value; // <-- 获取当前 locale
if (currentLocale !== lang) { // <-- 仅在 locale 实际改变时更新
globalComposer.locale.value = lang; // 访问 .value 属性
console.log(`[i18n] Successfully updated global locale from "${currentLocale}" to "${lang}".`); // <-- 修改日志
try {
localStorage.setItem(localStorageKey, lang); // 持久化到 localStorage
console.log(`[i18n] Locale "${lang}" saved to localStorage.`); // <-- 修改日志
} catch (e) {
console.error('[i18n] Failed to save locale to localStorage:', e);
}
} else {
console.log(`[i18n] Locale is already "${lang}". No update needed.`); // <-- 添加日志
}
} else {
console.warn(`[i18n] Locale "${lang}" is not available.`);
console.warn(`[i18n] Locale "${lang}" is not available. Available locales: ${globalComposer.availableLocales.join(', ')}`); // <-- 修改日志
}
};
@@ -251,6 +251,12 @@ export const useLayoutStore = defineStore('layout', () => {
}
}
// 新增 Action: 获取系统内置的默认布局
function getSystemDefaultLayout(): LayoutNode {
console.log('[Layout Store] Getting system default layout.');
return getDefaultLayout(); // 直接调用内部函数
}
// 新增 Action: 将当前布局树持久化到后端和 localStorage
async function persistLayoutTree() {
if (!layoutTree.value) {
@@ -328,5 +334,7 @@ export const useLayoutStore = defineStore('layout', () => {
isHeaderVisible,
loadHeaderVisibility,
toggleHeaderVisibility,
// 新增:暴露获取默认布局的方法
getSystemDefaultLayout,
};
});
+13 -6
View File
@@ -43,7 +43,8 @@ export const useSettingsStore = defineStore('settings', () => {
console.log('[SettingsStore] 加载通用设置...');
const response = await apiClient.get<Record<string, string>>('/settings'); // 使用 apiClient
settings.value = response.data; // Store fetched general settings
console.log('[SettingsStore] 通用设置已加载:', settings.value);
// --- 更详细的日志 ---
console.log('[SettingsStore] Fetched settings from backend:', JSON.stringify(settings.value));
// --- 设置默认值 (如果后端未返回) ---
if (settings.value.showPopupFileEditor === undefined) {
@@ -77,30 +78,34 @@ export const useSettingsStore = defineStore('settings', () => {
// --- 语言设置 ---
const langFromSettings = settings.value.language;
console.log(`[SettingsStore] Language from fetched settings: ${langFromSettings}`); // <-- 添加日志
if (langFromSettings === 'en' || langFromSettings === 'zh') {
fetchedLang = langFromSettings;
} else {
const navigatorLang = navigator.language?.split('-')[0];
fetchedLang = navigatorLang === 'zh' ? 'zh' : defaultLng;
console.warn(`[SettingsStore] 语言设置无效 ('${langFromSettings}'), 回退到 '${fetchedLang}'.`);
console.warn(`[SettingsStore] Invalid language setting ('${langFromSettings}') received from backend or missing. Falling back to '${fetchedLang}'.`); // <-- 修改日志
// Optionally save the fallback language back
// await updateSetting('language', fetchedLang);
}
if (fetchedLang) {
console.log(`[SettingsStore] 设置语言: ${fetchedLang}`);
console.log(`[SettingsStore] Determined language: ${fetchedLang}. Calling setLocale...`); // <-- 添加日志
setLocale(fetchedLang);
} else {
console.error('[SettingsStore] 无法确定有效语言。');
// This case should theoretically not happen with the fallback logic above
console.error('[SettingsStore] Could not determine a valid language. This should not happen.');
console.log(`[SettingsStore] Falling back to default: ${defaultLng}. Calling setLocale...`); // <-- 添加日志
setLocale(defaultLng);
}
} catch (err: any) {
console.error('加载通用设置失败:', err);
error.value = err.response?.data?.message || err.message || '加载设置失败';
console.error('Error loading general settings:', err); // <-- 修改日志
error.value = err.response?.data?.message || err.message || 'Failed to load settings';
// 出错时(例如未登录),根据浏览器语言设置回退语言
const navigatorLang = navigator.language?.split('-')[0];
const fallbackLang = navigatorLang === 'zh' ? 'zh' : defaultLng;
console.log(`[SettingsStore] Error loading settings. Falling back to language: ${fallbackLang}. Calling setLocale...`); // <-- 添加日志
setLocale(fallbackLang);
} finally {
isLoading.value = false;
@@ -134,6 +139,7 @@ export const useSettingsStore = defineStore('settings', () => {
// If updating language, also update i18n
if (key === 'language' && (value === 'en' || value === 'zh')) {
console.log(`[SettingsStore] updateSetting: Language updated to ${value}. Calling setLocale...`); // <-- 添加日志
setLocale(value);
}
} catch (err: any) {
@@ -180,6 +186,7 @@ export const useSettingsStore = defineStore('settings', () => {
// If language is updated, apply it
if (languageUpdate) {
console.log(`[SettingsStore] updateMultipleSettings: Language updated to ${languageUpdate}. Calling setLocale...`); // <-- 添加日志
setLocale(languageUpdate);
}
} catch (err: any) {
+8 -7
View File
@@ -251,15 +251,16 @@ const appearanceStore = useAppearanceStore(); // 实例化外观 store
const { t } = useI18n();
// --- Reactive state from store ---
// 使用 storeToRefs 获取响应式 getter
const { settings, isLoading: settingsLoading, error: settingsError, showPopupFileEditorBoolean, shareFileEditorTabsBoolean, autoCopyOnSelectBoolean, dockerDefaultExpandBoolean } = storeToRefs(settingsStore); // +++ 添加 dockerDefaultExpandBoolean +++
// 使用 storeToRefs 获取响应式 getter,包括 language
const { settings, isLoading: settingsLoading, error: settingsError, showPopupFileEditorBoolean, shareFileEditorTabsBoolean, autoCopyOnSelectBoolean, dockerDefaultExpandBoolean, language: storeLanguage } = storeToRefs(settingsStore); // +++ 添加 dockerDefaultExpandBoolean 和 language getter +++
// --- Local state for forms ---
const ipWhitelistInput = ref('');
const selectedLanguage = ref<'en' | 'zh'>('en'); // Default to 'en', will be updated by watcher
// 使用 store 的 language getter 初始化 selectedLanguage
const selectedLanguage = ref<'en' | 'zh'>(storeLanguage.value);
const blacklistSettingsForm = reactive({ // Renamed to avoid conflict with store state name
maxLoginAttempts: '5',
loginBanDuration: '300',
maxLoginAttempts: '5', // 初始值将在 watcher 中被 store 值覆盖
loginBanDuration: '300', // 初始值将在 watcher 中被 store 值覆盖
});
const popupEditorEnabled = ref(true); // 本地状态,用于 v-model
@@ -297,11 +298,11 @@ watch(settings, (newSettings, oldSettings) => {
const isInitialLoad = !oldSettings;
ipWhitelistInput.value = newSettings.ipWhitelist || '';
selectedLanguage.value = newSettings.language || 'en';
// selectedLanguage.value = newSettings.language || 'en'; // <-- 移除这一行,selectedLanguage 现在由 v-model 更新
blacklistSettingsForm.maxLoginAttempts = newSettings.maxLoginAttempts || '5';
blacklistSettingsForm.loginBanDuration = newSettings.loginBanDuration || '300';
// 始终将本地布尔状态与 store 的布尔 getter 同步
// 始终将本地布尔状态与 store 的布尔 getter 同步 (除了 language)
popupEditorEnabled.value = showPopupFileEditorBoolean.value;
shareTabsEnabled.value = shareFileEditorTabsBoolean.value;
autoCopyEnabled.value = autoCopyOnSelectBoolean.value; // 同步选中即复制状态