feat: 添加终端回滚行数设置
This commit is contained in:
@@ -268,6 +268,7 @@ export const ensureDefaultSettingsExist = async (db: sqlite3.Database): Promise<
|
|||||||
[SIDEBAR_CONFIG_KEY]: JSON.stringify(defaultSidebarPanesStructure),
|
[SIDEBAR_CONFIG_KEY]: JSON.stringify(defaultSidebarPanesStructure),
|
||||||
[CAPTCHA_CONFIG_KEY]: JSON.stringify(defaultCaptchaSettings),
|
[CAPTCHA_CONFIG_KEY]: JSON.stringify(defaultCaptchaSettings),
|
||||||
timezone: 'UTC', // NEW: 添加时区默认值
|
timezone: 'UTC', // NEW: 添加时区默认值
|
||||||
|
terminalScrollbackLimit: '5000', // NEW: 添加终端回滚行数默认值
|
||||||
};
|
};
|
||||||
const nowSeconds = Math.floor(Date.now() / 1000);
|
const nowSeconds = Math.floor(Date.now() / 1000);
|
||||||
const sqlInsertOrIgnore = `INSERT OR IGNORE INTO settings (key, value, created_at, updated_at) VALUES (?, ?, ?, ?)`;
|
const sqlInsertOrIgnore = `INSERT OR IGNORE INTO settings (key, value, created_at, updated_at) VALUES (?, ?, ?, ?)`;
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ export const settingsController = {
|
|||||||
'rdpModalWidth', // NEW: 添加 RDP 模态框宽度键
|
'rdpModalWidth', // NEW: 添加 RDP 模态框宽度键
|
||||||
'rdpModalHeight', // NEW: 添加 RDP 模态框高度键
|
'rdpModalHeight', // NEW: 添加 RDP 模态框高度键
|
||||||
'ipBlacklistEnabled', // <-- 添加 IP 黑名单启用键
|
'ipBlacklistEnabled', // <-- 添加 IP 黑名单启用键
|
||||||
'layoutLocked' // +++ 添加布局锁定键 +++
|
'layoutLocked', // +++ 添加布局锁定键 +++
|
||||||
|
'terminalScrollbackLimit' // NEW: 添加终端回滚行数键
|
||||||
];
|
];
|
||||||
const filteredSettings: Record<string, string> = {};
|
const filteredSettings: Record<string, string> = {};
|
||||||
for (const key in settingsToUpdate) {
|
for (const key in settingsToUpdate) {
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ const {
|
|||||||
|
|
||||||
// --- Settings Store ---
|
// --- Settings Store ---
|
||||||
const settingsStore = useSettingsStore(); // +++ 实例化设置 store +++
|
const settingsStore = useSettingsStore(); // +++ 实例化设置 store +++
|
||||||
const { autoCopyOnSelectBoolean } = storeToRefs(settingsStore); // +++ 获取选中即复制状态 +++
|
const {
|
||||||
|
autoCopyOnSelectBoolean,
|
||||||
|
terminalScrollbackLimitNumber // NEW: Import scrollback limit getter
|
||||||
|
} = storeToRefs(settingsStore); // +++ 获取选中即复制状态 +++
|
||||||
|
|
||||||
// 防抖函数
|
// 防抖函数
|
||||||
const debounce = (func: Function, delay: number) => {
|
const debounce = (func: Function, delay: number) => {
|
||||||
@@ -119,6 +122,14 @@ const debouncedSetTerminalFontSize = debounce(async (size: number) => {
|
|||||||
}
|
}
|
||||||
}, 500); // 500ms 防抖延迟,可以调整
|
}, 500); // 500ms 防抖延迟,可以调整
|
||||||
|
|
||||||
|
// NEW: Helper function to convert setting value to xterm scrollback value
|
||||||
|
const getScrollbackValue = (limit: number): number => {
|
||||||
|
if (limit === 0) {
|
||||||
|
return Infinity; // 0 means unlimited for xterm
|
||||||
|
}
|
||||||
|
return Math.max(0, limit); // Ensure non-negative, return the number otherwise
|
||||||
|
};
|
||||||
|
|
||||||
// 初始化终端
|
// 初始化终端
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (terminalRef.value) {
|
if (terminalRef.value) {
|
||||||
@@ -132,7 +143,7 @@ onMounted(() => {
|
|||||||
allowTransparency: true,
|
allowTransparency: true,
|
||||||
disableStdin: false,
|
disableStdin: false,
|
||||||
convertEol: true,
|
convertEol: true,
|
||||||
scrollback: 1000, // 减少可滚动历史行数
|
scrollback: getScrollbackValue(terminalScrollbackLimitNumber.value), // NEW: Use setting from store
|
||||||
scrollOnUserInput: true, // 输入时滚动到底部
|
scrollOnUserInput: true, // 输入时滚动到底部
|
||||||
...props.options, // 合并外部传入的选项
|
...props.options, // 合并外部传入的选项
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -640,6 +640,19 @@
|
|||||||
"showQuickCommandTagsLabel": "Show tags in quick command list",
|
"showQuickCommandTagsLabel": "Show tags in quick command list",
|
||||||
"showQuickCommandTagsDescription": "Disable to hide tags in the quick command list and exclude them from search."
|
"showQuickCommandTagsDescription": "Disable to hide tags in the quick command list and exclude them from search."
|
||||||
},
|
},
|
||||||
|
"terminalScrollback": {
|
||||||
|
"title": "Terminal Scrollback Limit",
|
||||||
|
"limitLabel": "Maximum Lines",
|
||||||
|
"limitHint": "Set the maximum number of output lines the terminal keeps. 0 means unlimited (uses default 5000). This setting takes effect the next time a terminal is opened.",
|
||||||
|
"saveButton": "Save",
|
||||||
|
"success": {
|
||||||
|
"saved": "Terminal scrollback limit setting saved successfully."
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"saveFailed": "Failed to save terminal scrollback limit setting.",
|
||||||
|
"invalidInput": "Please enter a valid non-negative integer."
|
||||||
|
}
|
||||||
|
},
|
||||||
"ipBlacklist": {
|
"ipBlacklist": {
|
||||||
"title": "IP Blacklist Management",
|
"title": "IP Blacklist Management",
|
||||||
"description": "Configure login attempt limits and automatic ban duration. Local addresses (127.0.0.1, ::1) will not be banned.",
|
"description": "Configure login attempt limits and automatic ban duration. Local addresses (127.0.0.1, ::1) will not be banned.",
|
||||||
|
|||||||
@@ -874,6 +874,19 @@
|
|||||||
"showQuickCommandTagsLabel": "クイックコマンドリストにタグを表示",
|
"showQuickCommandTagsLabel": "クイックコマンドリストにタグを表示",
|
||||||
"showQuickCommandTagsDescription": "無効にすると、クイックコマンドリストのタグが非表示になり、検索から除外されます。"
|
"showQuickCommandTagsDescription": "無効にすると、クイックコマンドリストのタグが非表示になり、検索から除外されます。"
|
||||||
},
|
},
|
||||||
|
"terminalScrollback": {
|
||||||
|
"title": "ターミナルスクロールバック制限",
|
||||||
|
"limitLabel": "最大行数",
|
||||||
|
"limitHint": "ターミナルが保持する最大出力行数を設定します。0 は無制限を意味します (デフォルト値 5000 を使用)。この設定は、次にターミナルを開いたときに有効になります。",
|
||||||
|
"saveButton": "保存",
|
||||||
|
"success": {
|
||||||
|
"saved": "ターミナルスクロールバック制限の設定が正常に保存されました。"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"saveFailed": "ターミナルスクロールバック制限の設定の保存に失敗しました。",
|
||||||
|
"invalidInput": "有効な非負整数を入力してください。"
|
||||||
|
}
|
||||||
|
},
|
||||||
"about": {
|
"about": {
|
||||||
"version": "バージョン",
|
"version": "バージョン",
|
||||||
"checkingUpdate": "更新を確認中...",
|
"checkingUpdate": "更新を確認中...",
|
||||||
|
|||||||
@@ -640,6 +640,19 @@
|
|||||||
"showQuickCommandTagsLabel": "在快捷指令列表中显示标签",
|
"showQuickCommandTagsLabel": "在快捷指令列表中显示标签",
|
||||||
"showQuickCommandTagsDescription": "关闭后将隐藏快捷指令列表中的标签,并从搜索中排除标签。"
|
"showQuickCommandTagsDescription": "关闭后将隐藏快捷指令列表中的标签,并从搜索中排除标签。"
|
||||||
},
|
},
|
||||||
|
"terminalScrollback": {
|
||||||
|
"title": "终端回滚行数",
|
||||||
|
"limitLabel": "最大行数",
|
||||||
|
"limitHint": "设置终端保留的最大输出行数。0 表示无限制 (使用默认值 5000)。此设置将在下次打开终端时生效。",
|
||||||
|
"saveButton": "保存",
|
||||||
|
"success": {
|
||||||
|
"saved": "终端回滚行数设置已保存。"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"saveFailed": "保存终端回滚行数设置失败。",
|
||||||
|
"invalidInput": "请输入一个有效的非负整数。"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ipBlacklist": {
|
"ipBlacklist": {
|
||||||
"title": "IP 黑名单管理",
|
"title": "IP 黑名单管理",
|
||||||
"description": "配置登录失败次数限制和自动封禁时长。本地地址 (127.0.0.1, ::1) 不会被封禁。",
|
"description": "配置登录失败次数限制和自动封禁时长。本地地址 (127.0.0.1, ::1) 不会被封禁。",
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ interface SettingsState {
|
|||||||
showConnectionTags?: string; // 'true' or 'false'
|
showConnectionTags?: string; // 'true' or 'false'
|
||||||
showQuickCommandTags?: string; // 'true' or 'false'
|
showQuickCommandTags?: string; // 'true' or 'false'
|
||||||
layoutLocked?: string; // 'true' or 'false' - NEW: 布局锁定状态
|
layoutLocked?: string; // 'true' or 'false' - NEW: 布局锁定状态
|
||||||
|
terminalScrollbackLimit?: string; // NEW: 终端回滚行数上限 (e.g., '5000', '0' for unlimited)
|
||||||
[key: string]: string | undefined;
|
[key: string]: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,6 +271,11 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
} else {
|
} else {
|
||||||
console.log(`[SettingsStore] layoutLocked found in fetched settings: ${settings.value.layoutLocked}`);
|
console.log(`[SettingsStore] layoutLocked found in fetched settings: ${settings.value.layoutLocked}`);
|
||||||
}
|
}
|
||||||
|
// NEW: Terminal scrollback limit default
|
||||||
|
if (settings.value.terminalScrollbackLimit === undefined) {
|
||||||
|
settings.value.terminalScrollbackLimit = '5000'; // 默认 5000 行
|
||||||
|
console.log(`[SettingsStore] terminalScrollbackLimit not found, set to default: ${settings.value.terminalScrollbackLimit}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- 语言设置 ---
|
// --- 语言设置 ---
|
||||||
@@ -357,7 +363,8 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
'dashboardSortOrder',
|
'dashboardSortOrder',
|
||||||
'showConnectionTags', // NEW
|
'showConnectionTags', // NEW
|
||||||
'showQuickCommandTags', // NEW
|
'showQuickCommandTags', // NEW
|
||||||
'layoutLocked' // NEW
|
'layoutLocked', // NEW
|
||||||
|
'terminalScrollbackLimit' // NEW
|
||||||
];
|
];
|
||||||
if (!allowedKeys.includes(key)) {
|
if (!allowedKeys.includes(key)) {
|
||||||
console.error(`[SettingsStore] 尝试更新不允许的设置键: ${key}`);
|
console.error(`[SettingsStore] 尝试更新不允许的设置键: ${key}`);
|
||||||
@@ -442,7 +449,8 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
'dashboardSortOrder',
|
'dashboardSortOrder',
|
||||||
'showConnectionTags', // NEW
|
'showConnectionTags', // NEW
|
||||||
'showQuickCommandTags', // NEW
|
'showQuickCommandTags', // NEW
|
||||||
'layoutLocked' // NEW
|
'layoutLocked', // NEW
|
||||||
|
'terminalScrollbackLimit' // NEW
|
||||||
];
|
];
|
||||||
const filteredUpdates: Partial<SettingsState> = {};
|
const filteredUpdates: Partial<SettingsState> = {};
|
||||||
let languageUpdate: string | undefined = undefined;
|
let languageUpdate: string | undefined = undefined;
|
||||||
@@ -717,6 +725,18 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
return settings.value.layoutLocked === 'true';
|
return settings.value.layoutLocked === 'true';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// NEW: Getter for terminal scrollback limit, returning number (0 means Infinity for xterm)
|
||||||
|
const terminalScrollbackLimitNumber = computed(() => {
|
||||||
|
const valStr = settings.value.terminalScrollbackLimit;
|
||||||
|
if (valStr === null || valStr === undefined || valStr.trim() === '') {
|
||||||
|
return 5000; // Default value if not set or empty
|
||||||
|
}
|
||||||
|
const val = parseInt(valStr, 10);
|
||||||
|
if (isNaN(val) || val < 0) {
|
||||||
|
return 5000; // Default value if invalid number or negative
|
||||||
|
}
|
||||||
|
return val; // Return 0 if it's 0, or the positive number
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
settings, // 只包含通用设置
|
settings, // 只包含通用设置
|
||||||
@@ -758,5 +778,6 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
showQuickCommandTagsBoolean,
|
showQuickCommandTagsBoolean,
|
||||||
// NEW: Expose layout locked getter
|
// NEW: Expose layout locked getter
|
||||||
layoutLockedBoolean,
|
layoutLockedBoolean,
|
||||||
|
terminalScrollbackLimitNumber, // NEW: Expose terminal scrollback limit getter
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -484,6 +484,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<hr class="border-border/50"> <!-- NEW: Separator -->
|
||||||
|
<!-- Terminal Scrollback Limit -->
|
||||||
|
<div class="settings-section-content">
|
||||||
|
<h3 class="text-base font-semibold text-foreground mb-3">{{ t('settings.terminalScrollback.title', '终端回滚行数') }}</h3>
|
||||||
|
<form @submit.prevent="handleUpdateTerminalScrollbackLimit" class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label for="terminalScrollbackLimitInput" class="block text-sm font-medium text-text-secondary mb-1">{{ t('settings.terminalScrollback.limitLabel', '最大行数') }}</label>
|
||||||
|
<input type="number" id="terminalScrollbackLimitInput" v-model.number="terminalScrollbackLimitLocal" min="0" step="1" placeholder="5000"
|
||||||
|
class="w-full px-3 py-2 border border-border rounded-md shadow-sm bg-background text-foreground focus:outline-none focus:ring-1 focus:ring-primary focus:border-primary">
|
||||||
|
<small class="block mt-1 text-xs text-text-secondary">{{ t('settings.terminalScrollback.limitHint', '设置终端保留的最大输出行数。0 或留空表示无限制 (使用默认值 5000)。此设置将在下次打开终端时生效。') }}</small>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<button type="submit" :disabled="terminalScrollbackLimitLoading"
|
||||||
|
class="px-4 py-2 bg-button text-button-text rounded-md shadow-sm hover:bg-button-hover focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary disabled:opacity-50 disabled:cursor-not-allowed transition duration-150 ease-in-out text-sm font-medium">
|
||||||
|
{{ terminalScrollbackLimitLoading ? t('common.loading') : t('settings.terminalScrollback.saveButton', '保存') }}
|
||||||
|
</button>
|
||||||
|
<p v-if="terminalScrollbackLimitMessage" :class="['text-sm', terminalScrollbackLimitSuccess ? 'text-success' : 'text-error']">{{ terminalScrollbackLimitMessage }}</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -666,6 +686,7 @@ const {
|
|||||||
ipBlacklistEnabledBoolean, // <-- Import IP Blacklist enabled getter
|
ipBlacklistEnabledBoolean, // <-- Import IP Blacklist enabled getter
|
||||||
showConnectionTagsBoolean, // NEW: Import connection tag visibility getter
|
showConnectionTagsBoolean, // NEW: Import connection tag visibility getter
|
||||||
showQuickCommandTagsBoolean, // NEW: Import quick command tag visibility getter
|
showQuickCommandTagsBoolean, // NEW: Import quick command tag visibility getter
|
||||||
|
terminalScrollbackLimitNumber, // NEW: Import terminal scrollback limit getter
|
||||||
} = storeToRefs(settingsStore);
|
} = storeToRefs(settingsStore);
|
||||||
|
|
||||||
// Removed Passkey state import from authStore
|
// Removed Passkey state import from authStore
|
||||||
@@ -692,6 +713,7 @@ const commandInputSyncTargetLocal = ref<'none' | 'quickCommands' | 'commandHisto
|
|||||||
const ipBlacklistEnabled = ref(true); // <-- Local state for IP Blacklist switch
|
const ipBlacklistEnabled = ref(true); // <-- Local state for IP Blacklist switch
|
||||||
const showConnectionTagsLocal = ref(true); // NEW: Local state for connection tags switch
|
const showConnectionTagsLocal = ref(true); // NEW: Local state for connection tags switch
|
||||||
const showQuickCommandTagsLocal = ref(true); // NEW: Local state for quick command tags switch
|
const showQuickCommandTagsLocal = ref(true); // NEW: Local state for quick command tags switch
|
||||||
|
const terminalScrollbackLimitLocal = ref<number | null>(null); // NEW: Local state for terminal scrollback limit input (allow null for empty input)
|
||||||
|
|
||||||
// --- Local UI feedback state ---
|
// --- Local UI feedback state ---
|
||||||
const ipWhitelistLoading = ref(false);
|
const ipWhitelistLoading = ref(false);
|
||||||
@@ -742,6 +764,9 @@ const showConnectionTagsSuccess = ref(false); // NEW
|
|||||||
const showQuickCommandTagsLoading = ref(false); // NEW
|
const showQuickCommandTagsLoading = ref(false); // NEW
|
||||||
const showQuickCommandTagsMessage = ref(''); // NEW
|
const showQuickCommandTagsMessage = ref(''); // NEW
|
||||||
const showQuickCommandTagsSuccess = ref(false); // NEW
|
const showQuickCommandTagsSuccess = ref(false); // NEW
|
||||||
|
const terminalScrollbackLimitLoading = ref(false); // NEW
|
||||||
|
const terminalScrollbackLimitMessage = ref(''); // NEW
|
||||||
|
const terminalScrollbackLimitSuccess = ref(false); // NEW
|
||||||
// CAPTCHA Form State
|
// CAPTCHA Form State
|
||||||
const captchaForm = reactive<UpdateCaptchaSettingsDto>({ // Use reactive for the form object
|
const captchaForm = reactive<UpdateCaptchaSettingsDto>({ // Use reactive for the form object
|
||||||
enabled: false,
|
enabled: false,
|
||||||
@@ -792,6 +817,8 @@ watch(settings, (newSettings, oldSettings) => {
|
|||||||
ipBlacklistEnabled.value = ipBlacklistEnabledBoolean.value; // <-- Sync IP Blacklist enabled state
|
ipBlacklistEnabled.value = ipBlacklistEnabledBoolean.value; // <-- Sync IP Blacklist enabled state
|
||||||
showConnectionTagsLocal.value = showConnectionTagsBoolean.value; // NEW: Sync connection tags state
|
showConnectionTagsLocal.value = showConnectionTagsBoolean.value; // NEW: Sync connection tags state
|
||||||
showQuickCommandTagsLocal.value = showQuickCommandTagsBoolean.value; // NEW: Sync quick command tags state
|
showQuickCommandTagsLocal.value = showQuickCommandTagsBoolean.value; // NEW: Sync quick command tags state
|
||||||
|
// NEW: Directly sync terminal scrollback limit from store getter to local state
|
||||||
|
terminalScrollbackLimitLocal.value = terminalScrollbackLimitNumber.value;
|
||||||
|
|
||||||
}, { deep: true, immediate: true }); // immediate: true to run on initial load
|
}, { deep: true, immediate: true }); // immediate: true to run on initial load
|
||||||
|
|
||||||
@@ -816,6 +843,9 @@ watch(captchaSettings, (newCaptchaSettings) => {
|
|||||||
}, { immediate: true }); // immediate: true to run on initial load
|
}, { immediate: true }); // immediate: true to run on initial load
|
||||||
|
|
||||||
|
|
||||||
|
// Watcher specifically for terminalScrollbackLimitNumber is redundant if the main settings watcher handles it.
|
||||||
|
// Let's remove the specific watcher for simplicity, the main one should suffice.
|
||||||
|
|
||||||
// --- Popup Editor setting method ---
|
// --- Popup Editor setting method ---
|
||||||
const handleUpdatePopupEditorSetting = async () => {
|
const handleUpdatePopupEditorSetting = async () => {
|
||||||
popupEditorLoading.value = true;
|
popupEditorLoading.value = true;
|
||||||
@@ -1020,6 +1050,34 @@ const handleUpdateShowQuickCommandTags = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- Terminal Scrollback Limit setting method ---
|
||||||
|
const handleUpdateTerminalScrollbackLimit = async () => {
|
||||||
|
terminalScrollbackLimitLoading.value = true;
|
||||||
|
terminalScrollbackLimitMessage.value = '';
|
||||||
|
terminalScrollbackLimitSuccess.value = false;
|
||||||
|
try {
|
||||||
|
const limitValue = terminalScrollbackLimitLocal.value;
|
||||||
|
|
||||||
|
// Validate: must be a non-negative integer or null/undefined (treat null/undefined as default 5000)
|
||||||
|
if (limitValue !== null && limitValue !== undefined && (isNaN(limitValue) || !Number.isInteger(limitValue) || limitValue < 0)) {
|
||||||
|
throw new Error(t('settings.terminalScrollback.error.invalidInput', '请输入一个有效的非负整数。'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If input is empty (null/undefined), save the default value '5000'. Otherwise, save the entered number as string.
|
||||||
|
const valueToSave = (limitValue === null || limitValue === undefined) ? '5000' : String(limitValue);
|
||||||
|
|
||||||
|
await settingsStore.updateSetting('terminalScrollbackLimit', valueToSave);
|
||||||
|
terminalScrollbackLimitMessage.value = t('settings.terminalScrollback.success.saved', '终端回滚行数设置已保存。');
|
||||||
|
terminalScrollbackLimitSuccess.value = true;
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('更新终端回滚行数设置失败:', error);
|
||||||
|
terminalScrollbackLimitMessage.value = error.message || t('settings.terminalScrollback.error.saveFailed', '保存终端回滚行数设置失败。');
|
||||||
|
terminalScrollbackLimitSuccess.value = false;
|
||||||
|
} finally {
|
||||||
|
terminalScrollbackLimitLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// --- 外观设置 ---
|
// --- 外观设置 ---
|
||||||
const openStyleCustomizer = () => {
|
const openStyleCustomizer = () => {
|
||||||
appearanceStore.toggleStyleCustomizer(true);
|
appearanceStore.toggleStyleCustomizer(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user