update
This commit is contained in:
@@ -33,7 +33,7 @@ export const settingsController = {
|
|||||||
const allowedSettingsKeys = [
|
const allowedSettingsKeys = [
|
||||||
'language', 'ipWhitelist', 'maxLoginAttempts', 'loginBanDuration',
|
'language', 'ipWhitelist', 'maxLoginAttempts', 'loginBanDuration',
|
||||||
'showPopupFileEditor', 'shareFileEditorTabs', 'ipWhitelistEnabled',
|
'showPopupFileEditor', 'shareFileEditorTabs', 'ipWhitelistEnabled',
|
||||||
'autoCopyOnSelect' // +++ 添加新设置键 +++
|
'autoCopyOnSelect', 'dockerStatusIntervalSeconds', 'dockerDefaultExpand' // +++ 添加 Docker 设置键 +++
|
||||||
];
|
];
|
||||||
const filteredSettings: Record<string, string> = {};
|
const filteredSettings: Record<string, string> = {};
|
||||||
for (const key in settingsToUpdate) {
|
for (const key in settingsToUpdate) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import * as SshService from './services/ssh.service';
|
|||||||
import { DockerService } from './services/docker.service'; // 导入 DockerService
|
import { DockerService } from './services/docker.service'; // 导入 DockerService
|
||||||
import { AuditLogService } from './services/audit.service'; // 导入 AuditLogService
|
import { AuditLogService } from './services/audit.service'; // 导入 AuditLogService
|
||||||
import { AuditLogActionType } from './types/audit.types'; // 导入 AuditLogActionType
|
import { AuditLogActionType } from './types/audit.types'; // 导入 AuditLogActionType
|
||||||
|
import { settingsService } from './services/settings.service'; // +++ 修正导入路径 +++
|
||||||
|
|
||||||
// 扩展 WebSocket 类型以包含会话 ID
|
// 扩展 WebSocket 类型以包含会话 ID
|
||||||
interface AuthenticatedWebSocket extends WebSocket {
|
interface AuthenticatedWebSocket extends WebSocket {
|
||||||
@@ -489,32 +490,52 @@ export const initializeWebSocket = async (server: http.Server, sessionParser: Re
|
|||||||
console.log(`WebSocket: 会话 ${newSessionId} 正在启动状态监控...`);
|
console.log(`WebSocket: 会话 ${newSessionId} 正在启动状态监控...`);
|
||||||
statusMonitorService.startStatusPolling(newSessionId);
|
statusMonitorService.startStatusPolling(newSessionId);
|
||||||
|
|
||||||
// 8. Start Docker status polling
|
// 8. Start Docker status polling (using setting)
|
||||||
console.log(`WebSocket: 会话 ${newSessionId} 正在启动 Docker 状态轮询...`);
|
console.log(`WebSocket: 会话 ${newSessionId} 正在启动 Docker 状态轮询...`);
|
||||||
const dockerIntervalId = setInterval(async () => {
|
// --- Get interval from settings ---
|
||||||
const currentState = clientStates.get(newSessionId); // Re-fetch state
|
let dockerPollIntervalMs = 2000; // Default interval
|
||||||
if (!currentState || currentState.ws.readyState !== WebSocket.OPEN) {
|
try {
|
||||||
console.log(`[Docker Polling] Session ${newSessionId} no longer valid or WS closed. Stopping poll.`);
|
const intervalSetting = await settingsService.getSetting('dockerStatusIntervalSeconds');
|
||||||
clearInterval(dockerIntervalId);
|
if (intervalSetting) {
|
||||||
return;
|
const intervalSeconds = parseInt(intervalSetting, 10);
|
||||||
}
|
if (!isNaN(intervalSeconds) && intervalSeconds >= 1) {
|
||||||
try {
|
dockerPollIntervalMs = intervalSeconds * 1000;
|
||||||
// console.log(`[Docker Polling] Fetching status for session ${newSessionId}...`);
|
console.log(`[Docker Polling] Using interval from settings: ${intervalSeconds}s (${dockerPollIntervalMs}ms) for session ${newSessionId}`);
|
||||||
const statusPayload = await fetchRemoteDockerStatus(currentState);
|
} else {
|
||||||
if (currentState.ws.readyState === WebSocket.OPEN) {
|
console.warn(`[Docker Polling] Invalid interval setting '${intervalSetting}' found. Using default ${dockerPollIntervalMs}ms for session ${newSessionId}`);
|
||||||
currentState.ws.send(JSON.stringify({ type: 'docker:status:update', payload: statusPayload }));
|
}
|
||||||
}
|
} else {
|
||||||
} catch (error: any) {
|
console.log(`[Docker Polling] No interval setting found. Using default ${dockerPollIntervalMs}ms for session ${newSessionId}`);
|
||||||
console.error(`[Docker Polling] Error fetching Docker status for session ${newSessionId}:`, error);
|
}
|
||||||
// Optionally send error to client, or just log
|
} catch (settingError) {
|
||||||
// if (currentState.ws.readyState === WebSocket.OPEN) {
|
console.error(`[Docker Polling] Error fetching interval setting for session ${newSessionId}. Using default ${dockerPollIntervalMs}ms:`, settingError);
|
||||||
// currentState.ws.send(JSON.stringify({ type: 'docker:status:error', payload: { message: `Polling failed: ${error.message}` } }));
|
}
|
||||||
// }
|
// --- End get interval ---
|
||||||
}
|
|
||||||
}, DOCKER_STATUS_INTERVAL);
|
|
||||||
newState.dockerStatusIntervalId = dockerIntervalId;
|
|
||||||
|
|
||||||
// 9. Trigger initial Docker status fetch immediately
|
const dockerIntervalId = setInterval(async () => {
|
||||||
|
const currentState = clientStates.get(newSessionId); // Re-fetch state
|
||||||
|
if (!currentState || currentState.ws.readyState !== WebSocket.OPEN) {
|
||||||
|
console.log(`[Docker Polling] Session ${newSessionId} no longer valid or WS closed. Stopping poll.`);
|
||||||
|
clearInterval(dockerIntervalId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// console.log(`[Docker Polling] Fetching status for session ${newSessionId}...`);
|
||||||
|
const statusPayload = await fetchRemoteDockerStatus(currentState);
|
||||||
|
if (currentState.ws.readyState === WebSocket.OPEN) {
|
||||||
|
currentState.ws.send(JSON.stringify({ type: 'docker:status:update', payload: statusPayload }));
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(`[Docker Polling] Error fetching Docker status for session ${newSessionId}:`, error);
|
||||||
|
// Optionally send error to client, or just log
|
||||||
|
// if (currentState.ws.readyState === WebSocket.OPEN) {
|
||||||
|
// currentState.ws.send(JSON.stringify({ type: 'docker:status:error', payload: { message: `Polling failed: ${error.message}` } }));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}, dockerPollIntervalMs); // <-- Use the determined interval
|
||||||
|
newState.dockerStatusIntervalId = dockerIntervalId;
|
||||||
|
|
||||||
|
// 9. Trigger initial Docker status fetch immediately
|
||||||
(async () => {
|
(async () => {
|
||||||
const currentState = clientStates.get(newSessionId);
|
const currentState = clientStates.get(newSessionId);
|
||||||
if (currentState && currentState.ws.readyState === WebSocket.OPEN) {
|
if (currentState && currentState.ws.readyState === WebSocket.OPEN) {
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ import { ref, onMounted, onUnmounted, watch, computed } from 'vue';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useSessionStore } from '../stores/session.store'; // Import session store
|
import { useSessionStore } from '../stores/session.store'; // Import session store
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useSettingsStore } from '../stores/settings.store'; // +++ Import settings store +++
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const sessionStore = useSessionStore();
|
const sessionStore = useSessionStore();
|
||||||
const { activeSession } = storeToRefs(sessionStore); // Get reactive active session
|
const { activeSession } = storeToRefs(sessionStore); // Get reactive active session
|
||||||
|
const settingsStore = useSettingsStore(); // +++ Get settings store instance +++
|
||||||
|
const { dockerDefaultExpandBoolean } = storeToRefs(settingsStore); // +++ Get reactive getter +++
|
||||||
|
|
||||||
// --- Interfaces ---
|
// --- Interfaces ---
|
||||||
interface PortInfo {
|
interface PortInfo {
|
||||||
@@ -63,6 +66,7 @@ let refreshInterval: ReturnType<typeof setInterval> | null = null;
|
|||||||
let wsUnsubscribeHooks: (() => void)[] = []; // To store unsubscribe functions
|
let wsUnsubscribeHooks: (() => void)[] = []; // To store unsubscribe functions
|
||||||
// --- State for expansion (multiple allowed) ---
|
// --- State for expansion (multiple allowed) ---
|
||||||
const expandedContainerIds = ref<Set<string>>(new Set()); // Use a Set to store multiple IDs
|
const expandedContainerIds = ref<Set<string>>(new Set()); // Use a Set to store multiple IDs
|
||||||
|
const initialLoadDone = ref(false); // +++ Flag for initial load processing +++
|
||||||
// REMOVED: containerStats, isStatsLoading, statsError maps
|
// REMOVED: containerStats, isStatsLoading, statsError maps
|
||||||
|
|
||||||
|
|
||||||
@@ -109,6 +113,18 @@ const setupWsListeners = () => {
|
|||||||
});
|
});
|
||||||
idsToRemove.forEach(id => expandedContainerIds.value.delete(id));
|
idsToRemove.forEach(id => expandedContainerIds.value.delete(id));
|
||||||
|
|
||||||
|
// +++ Handle default expand on initial load +++
|
||||||
|
if (!initialLoadDone.value && dockerDefaultExpandBoolean.value) {
|
||||||
|
console.log('[DockerManager] Applying default expand setting.');
|
||||||
|
containers.value.forEach(container => {
|
||||||
|
if (!expandedContainerIds.value.has(container.id)) {
|
||||||
|
expandedContainerIds.value.add(container.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
initialLoadDone.value = true; // Mark initial load processed
|
||||||
|
}
|
||||||
|
// +++ End handle default expand +++
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Docker available but no containers, or Docker unavailable
|
// Docker available but no containers, or Docker unavailable
|
||||||
containers.value = [];
|
containers.value = [];
|
||||||
@@ -256,6 +272,7 @@ watch([currentSessionId, sshConnectionStatus], ([newSessionId, newSshStatus], [o
|
|||||||
error.value = null;
|
error.value = null;
|
||||||
isDockerAvailable.value = true; // Assume available until fetch attempt
|
isDockerAvailable.value = true; // Assume available until fetch attempt
|
||||||
expandedContainerIds.value.clear(); // Clear expansion state
|
expandedContainerIds.value.clear(); // Clear expansion state
|
||||||
|
initialLoadDone.value = false; // +++ Reset initial load flag +++
|
||||||
|
|
||||||
if (refreshInterval) {
|
if (refreshInterval) {
|
||||||
clearInterval(refreshInterval);
|
clearInterval(refreshInterval);
|
||||||
|
|||||||
@@ -612,7 +612,21 @@
|
|||||||
"error": {
|
"error": {
|
||||||
"saveFailed": "Failed to save auto copy setting."
|
"saveFailed": "Failed to save auto copy setting."
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"docker": {
|
||||||
|
"title": "Docker Manager Settings",
|
||||||
|
"refreshIntervalLabel": "Status Refresh Interval (seconds):",
|
||||||
|
"refreshIntervalHint": "How often to fetch Docker container status and stats (minimum 1).",
|
||||||
|
"defaultExpandLabel": "Expand container details by default",
|
||||||
|
"saveButton": "Save Docker Settings",
|
||||||
|
"success": {
|
||||||
|
"saved": "Docker settings saved successfully."
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"saveFailed": "Failed to save Docker settings.",
|
||||||
|
"invalidInterval": "Refresh interval must be a positive integer."
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"loading": "Loading...",
|
"loading": "Loading...",
|
||||||
|
|||||||
@@ -612,7 +612,21 @@
|
|||||||
"error": {
|
"error": {
|
||||||
"saveFailed": "保存自动复制设置失败。"
|
"saveFailed": "保存自动复制设置失败。"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"docker": {
|
||||||
|
"title": "Docker 管理器设置",
|
||||||
|
"refreshIntervalLabel": "状态刷新间隔 (秒):",
|
||||||
|
"refreshIntervalHint": "获取 Docker 容器状态和统计信息的频率(最小为 1)。",
|
||||||
|
"defaultExpandLabel": "默认展开容器详情",
|
||||||
|
"saveButton": "保存 Docker 设置",
|
||||||
|
"success": {
|
||||||
|
"saved": "Docker 设置已成功保存。"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"saveFailed": "保存 Docker 设置失败。",
|
||||||
|
"invalidInterval": "刷新间隔必须是正整数。"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"loading": "加载中...",
|
"loading": "加载中...",
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ interface SettingsState {
|
|||||||
shareFileEditorTabs?: string; // 'true' or 'false'
|
shareFileEditorTabs?: string; // 'true' or 'false'
|
||||||
ipWhitelistEnabled?: string; // 添加 IP 白名单启用状态 'true' or 'false'
|
ipWhitelistEnabled?: string; // 添加 IP 白名单启用状态 'true' or 'false'
|
||||||
autoCopyOnSelect?: string; // 'true' or 'false' - 终端选中自动复制
|
autoCopyOnSelect?: string; // 'true' or 'false' - 终端选中自动复制
|
||||||
|
dockerStatusIntervalSeconds?: string; // NEW: Docker 状态刷新间隔 (秒)
|
||||||
|
dockerDefaultExpand?: string; // NEW: Docker 默认展开详情 'true' or 'false'
|
||||||
// Add other general settings keys here as needed
|
// Add other general settings keys here as needed
|
||||||
[key: string]: string | undefined; // Allow other string settings
|
[key: string]: string | undefined; // Allow other string settings
|
||||||
}
|
}
|
||||||
@@ -64,6 +66,14 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
if (settings.value.autoCopyOnSelect === undefined) {
|
if (settings.value.autoCopyOnSelect === undefined) {
|
||||||
settings.value.autoCopyOnSelect = 'false'; // 默认禁用选中即复制
|
settings.value.autoCopyOnSelect = 'false'; // 默认禁用选中即复制
|
||||||
}
|
}
|
||||||
|
// NEW: Docker setting defaults
|
||||||
|
if (settings.value.dockerStatusIntervalSeconds === undefined) {
|
||||||
|
settings.value.dockerStatusIntervalSeconds = '2'; // 默认 2 秒
|
||||||
|
}
|
||||||
|
if (settings.value.dockerDefaultExpand === undefined) {
|
||||||
|
settings.value.dockerDefaultExpand = 'false'; // 默认不展开
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- 语言设置 ---
|
// --- 语言设置 ---
|
||||||
const langFromSettings = settings.value.language;
|
const langFromSettings = settings.value.language;
|
||||||
@@ -109,7 +119,7 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
const allowedKeys: Array<keyof SettingsState> = [
|
const allowedKeys: Array<keyof SettingsState> = [
|
||||||
'language', 'ipWhitelist', 'maxLoginAttempts', 'loginBanDuration',
|
'language', 'ipWhitelist', 'maxLoginAttempts', 'loginBanDuration',
|
||||||
'showPopupFileEditor', 'shareFileEditorTabs', 'ipWhitelistEnabled',
|
'showPopupFileEditor', 'shareFileEditorTabs', 'ipWhitelistEnabled',
|
||||||
'autoCopyOnSelect' // +++ 添加新设置键 +++
|
'autoCopyOnSelect', 'dockerStatusIntervalSeconds', 'dockerDefaultExpand' // +++ 添加 Docker 设置键 +++
|
||||||
];
|
];
|
||||||
if (!allowedKeys.includes(key)) {
|
if (!allowedKeys.includes(key)) {
|
||||||
console.error(`[SettingsStore] 尝试更新不允许的设置键: ${key}`);
|
console.error(`[SettingsStore] 尝试更新不允许的设置键: ${key}`);
|
||||||
@@ -141,7 +151,7 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
const allowedKeys: Array<keyof SettingsState> = [
|
const allowedKeys: Array<keyof SettingsState> = [
|
||||||
'language', 'ipWhitelist', 'maxLoginAttempts', 'loginBanDuration',
|
'language', 'ipWhitelist', 'maxLoginAttempts', 'loginBanDuration',
|
||||||
'showPopupFileEditor', 'shareFileEditorTabs', 'ipWhitelistEnabled',
|
'showPopupFileEditor', 'shareFileEditorTabs', 'ipWhitelistEnabled',
|
||||||
'autoCopyOnSelect' // +++ 添加新设置键 +++
|
'autoCopyOnSelect', 'dockerStatusIntervalSeconds', 'dockerDefaultExpand' // +++ 添加 Docker 设置键 +++
|
||||||
];
|
];
|
||||||
const filteredUpdates: Partial<SettingsState> = {};
|
const filteredUpdates: Partial<SettingsState> = {};
|
||||||
let languageUpdate: 'en' | 'zh' | undefined = undefined;
|
let languageUpdate: 'en' | 'zh' | undefined = undefined;
|
||||||
@@ -202,6 +212,11 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
return settings.value.autoCopyOnSelect === 'true';
|
return settings.value.autoCopyOnSelect === 'true';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// NEW: Getter for Docker default expand setting, returning boolean
|
||||||
|
const dockerDefaultExpandBoolean = computed(() => {
|
||||||
|
return settings.value.dockerDefaultExpand === 'true';
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
settings, // 只包含通用设置
|
settings, // 只包含通用设置
|
||||||
isLoading,
|
isLoading,
|
||||||
@@ -210,7 +225,8 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
showPopupFileEditorBoolean,
|
showPopupFileEditorBoolean,
|
||||||
shareFileEditorTabsBoolean,
|
shareFileEditorTabsBoolean,
|
||||||
ipWhitelistEnabled, // 暴露 IP 白名单启用状态
|
ipWhitelistEnabled, // 暴露 IP 白名单启用状态
|
||||||
autoCopyOnSelectBoolean, // +++ 暴露新 getter +++
|
autoCopyOnSelectBoolean,
|
||||||
|
dockerDefaultExpandBoolean, // +++ 暴露 Docker 默认展开 getter +++
|
||||||
// 移除外观相关的 getters 和 actions
|
// 移除外观相关的 getters 和 actions
|
||||||
loadInitialSettings,
|
loadInitialSettings,
|
||||||
updateSetting,
|
updateSetting,
|
||||||
|
|||||||
@@ -137,6 +137,25 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- NEW: Docker Settings Section -->
|
||||||
|
<div class="settings-section">
|
||||||
|
<h2>{{ t('settings.docker.title') }}</h2>
|
||||||
|
<form @submit.prevent="handleUpdateDockerSettings">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="dockerInterval">{{ t('settings.docker.refreshIntervalLabel') }}</label>
|
||||||
|
<input type="number" id="dockerInterval" v-model.number="dockerInterval" min="1" step="1" required>
|
||||||
|
<small>{{ t('settings.docker.refreshIntervalHint') }}</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-group form-group-checkbox">
|
||||||
|
<input type="checkbox" id="dockerExpandDefault" v-model="dockerExpandDefault">
|
||||||
|
<label for="dockerExpandDefault">{{ t('settings.docker.defaultExpandLabel') }}</label>
|
||||||
|
</div>
|
||||||
|
<button type="submit" :disabled="dockerSettingsLoading">{{ dockerSettingsLoading ? $t('common.saving') : t('settings.docker.saveButton') }}</button>
|
||||||
|
<p v-if="dockerSettingsMessage" :class="{ 'success-message': dockerSettingsSuccess, 'error-message': !dockerSettingsSuccess }">{{ dockerSettingsMessage }}</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<!-- END: Docker Settings Section -->
|
||||||
|
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
<h2>{{ $t('settings.ipWhitelist.title') }}</h2>
|
<h2>{{ $t('settings.ipWhitelist.title') }}</h2>
|
||||||
<p>{{ $t('settings.ipWhitelist.description') }}</p>
|
<p>{{ $t('settings.ipWhitelist.description') }}</p>
|
||||||
@@ -233,7 +252,7 @@ const { t } = useI18n();
|
|||||||
|
|
||||||
// --- Reactive state from store ---
|
// --- Reactive state from store ---
|
||||||
// 使用 storeToRefs 获取响应式 getter
|
// 使用 storeToRefs 获取响应式 getter
|
||||||
const { settings, isLoading: settingsLoading, error: settingsError, showPopupFileEditorBoolean, shareFileEditorTabsBoolean, autoCopyOnSelectBoolean } = storeToRefs(settingsStore); // +++ 添加 autoCopyOnSelectBoolean +++
|
const { settings, isLoading: settingsLoading, error: settingsError, showPopupFileEditorBoolean, shareFileEditorTabsBoolean, autoCopyOnSelectBoolean, dockerDefaultExpandBoolean } = storeToRefs(settingsStore); // +++ 添加 dockerDefaultExpandBoolean +++
|
||||||
|
|
||||||
// --- Local state for forms ---
|
// --- Local state for forms ---
|
||||||
const ipWhitelistInput = ref('');
|
const ipWhitelistInput = ref('');
|
||||||
@@ -265,6 +284,12 @@ const autoCopyEnabled = ref(false); // 本地状态,用于选中即复制 v-mo
|
|||||||
const autoCopyLoading = ref(false);
|
const autoCopyLoading = ref(false);
|
||||||
const autoCopyMessage = ref('');
|
const autoCopyMessage = ref('');
|
||||||
const autoCopySuccess = ref(false);
|
const autoCopySuccess = ref(false);
|
||||||
|
const dockerInterval = ref(2); // 本地状态,用于 Docker 刷新间隔 v-model
|
||||||
|
const dockerExpandDefault = ref(false); // 本地状态,用于 Docker 默认展开 v-model
|
||||||
|
const dockerSettingsLoading = ref(false);
|
||||||
|
const dockerSettingsMessage = ref('');
|
||||||
|
const dockerSettingsSuccess = ref(false);
|
||||||
|
|
||||||
|
|
||||||
// --- Watcher to sync local form state with store state ---
|
// --- Watcher to sync local form state with store state ---
|
||||||
watch(settings, (newSettings, oldSettings) => {
|
watch(settings, (newSettings, oldSettings) => {
|
||||||
@@ -279,7 +304,9 @@ watch(settings, (newSettings, oldSettings) => {
|
|||||||
// 始终将本地布尔状态与 store 的布尔 getter 同步
|
// 始终将本地布尔状态与 store 的布尔 getter 同步
|
||||||
popupEditorEnabled.value = showPopupFileEditorBoolean.value;
|
popupEditorEnabled.value = showPopupFileEditorBoolean.value;
|
||||||
shareTabsEnabled.value = shareFileEditorTabsBoolean.value;
|
shareTabsEnabled.value = shareFileEditorTabsBoolean.value;
|
||||||
autoCopyEnabled.value = autoCopyOnSelectBoolean.value; // +++ 同步选中即复制状态 +++
|
autoCopyEnabled.value = autoCopyOnSelectBoolean.value; // 同步选中即复制状态
|
||||||
|
dockerInterval.value = parseInt(newSettings.dockerStatusIntervalSeconds || '2', 10); // 同步 Docker 间隔
|
||||||
|
dockerExpandDefault.value = dockerDefaultExpandBoolean.value; // 同步 Docker 默认展开状态
|
||||||
|
|
||||||
}, { deep: true, immediate: true }); // immediate: true to run on initial load
|
}, { deep: true, immediate: true }); // immediate: true to run on initial load
|
||||||
|
|
||||||
@@ -345,6 +372,32 @@ const handleUpdateAutoCopySetting = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- Docker settings method ---
|
||||||
|
const handleUpdateDockerSettings = async () => {
|
||||||
|
dockerSettingsLoading.value = true;
|
||||||
|
dockerSettingsMessage.value = '';
|
||||||
|
dockerSettingsSuccess.value = false;
|
||||||
|
try {
|
||||||
|
const intervalValue = dockerInterval.value;
|
||||||
|
if (isNaN(intervalValue) || intervalValue < 1) {
|
||||||
|
throw new Error(t('settings.docker.error.invalidInterval')); // 需要添加翻译
|
||||||
|
}
|
||||||
|
await settingsStore.updateMultipleSettings({
|
||||||
|
dockerStatusIntervalSeconds: String(intervalValue), // 保存为字符串
|
||||||
|
dockerDefaultExpand: dockerExpandDefault.value ? 'true' : 'false' // 保存为字符串 'true'/'false'
|
||||||
|
});
|
||||||
|
dockerSettingsMessage.value = t('settings.docker.success.saved'); // 需要添加翻译
|
||||||
|
dockerSettingsSuccess.value = true;
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('更新 Docker 设置失败:', error);
|
||||||
|
dockerSettingsMessage.value = error.message || t('settings.docker.error.saveFailed'); // 需要添加翻译
|
||||||
|
dockerSettingsSuccess.value = false;
|
||||||
|
} finally {
|
||||||
|
dockerSettingsLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// --- 外观设置 ---
|
// --- 外观设置 ---
|
||||||
const openStyleCustomizer = () => {
|
const openStyleCustomizer = () => {
|
||||||
appearanceStore.toggleStyleCustomizer(true);
|
appearanceStore.toggleStyleCustomizer(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user