update
This commit is contained in:
@@ -5,6 +5,7 @@ const DEFAULT_FOCUS_SEQUENCE = ["quickCommandsSearch", "commandHistorySearch", "
|
|||||||
const FOCUS_SEQUENCE_KEY = 'focusSwitcherSequence'; // 焦点切换顺序设置键
|
const FOCUS_SEQUENCE_KEY = 'focusSwitcherSequence'; // 焦点切换顺序设置键
|
||||||
const NAV_BAR_VISIBLE_KEY = 'navBarVisible'; // 导航栏可见性设置键
|
const NAV_BAR_VISIBLE_KEY = 'navBarVisible'; // 导航栏可见性设置键
|
||||||
const LAYOUT_TREE_KEY = 'layoutTree'; // 布局树设置键
|
const LAYOUT_TREE_KEY = 'layoutTree'; // 布局树设置键
|
||||||
|
const AUTO_COPY_ON_SELECT_KEY = 'autoCopyOnSelect'; // 终端选中自动复制设置键
|
||||||
|
|
||||||
export const settingsService = {
|
export const settingsService = {
|
||||||
/**
|
/**
|
||||||
@@ -204,5 +205,40 @@ export const settingsService = {
|
|||||||
console.error(`[Service] Error calling settingsRepository.setSetting for key ${LAYOUT_TREE_KEY}:`, error);
|
console.error(`[Service] Error calling settingsRepository.setSetting for key ${LAYOUT_TREE_KEY}:`, error);
|
||||||
throw new Error('Failed to save layout tree setting.');
|
throw new Error('Failed to save layout tree setting.');
|
||||||
}
|
}
|
||||||
|
}, // *** 确保这里有逗号 ***
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取终端选中自动复制设置
|
||||||
|
* @returns 返回是否启用该功能 (boolean),如果未设置则默认为 false
|
||||||
|
*/
|
||||||
|
async getAutoCopyOnSelect(): Promise<boolean> {
|
||||||
|
console.log(`[Service] Attempting to get setting for key: ${AUTO_COPY_ON_SELECT_KEY}`);
|
||||||
|
try {
|
||||||
|
const enabledStr = await settingsRepository.getSetting(AUTO_COPY_ON_SELECT_KEY);
|
||||||
|
console.log(`[Service] Raw value from repository for ${AUTO_COPY_ON_SELECT_KEY}:`, enabledStr);
|
||||||
|
// 如果设置存在且值为 'true',则返回 true,否则都返回 false (包括未设置或值为 'false' 的情况)
|
||||||
|
return enabledStr === 'true';
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[Service] Error getting auto copy on select setting (key: ${AUTO_COPY_ON_SELECT_KEY}):`, error);
|
||||||
|
// 出错时返回默认值 false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}, // *** 确保这里有逗号 ***
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置终端选中自动复制
|
||||||
|
* @param enabled 是否启用 (boolean)
|
||||||
|
*/
|
||||||
|
async setAutoCopyOnSelect(enabled: boolean): Promise<void> {
|
||||||
|
console.log(`[Service] setAutoCopyOnSelect called with: ${enabled}`);
|
||||||
|
try {
|
||||||
|
const enabledStr = String(enabled); // 将布尔值转换为 'true' 或 'false'
|
||||||
|
console.log(`[Service] Attempting to save setting. Key: ${AUTO_COPY_ON_SELECT_KEY}, Value: ${enabledStr}`);
|
||||||
|
await settingsRepository.setSetting(AUTO_COPY_ON_SELECT_KEY, enabledStr);
|
||||||
|
console.log(`[Service] Successfully saved setting for key: ${AUTO_COPY_ON_SELECT_KEY}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[Service] Error calling settingsRepository.setSetting for key ${AUTO_COPY_ON_SELECT_KEY}:`, error);
|
||||||
|
throw new Error('Failed to save auto copy on select setting.');
|
||||||
|
}
|
||||||
} // *** 最后的方法后面不需要逗号 ***
|
} // *** 最后的方法后面不需要逗号 ***
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ export const settingsController = {
|
|||||||
|
|
||||||
const allowedSettingsKeys = [
|
const allowedSettingsKeys = [
|
||||||
'language', 'ipWhitelist', 'maxLoginAttempts', 'loginBanDuration',
|
'language', 'ipWhitelist', 'maxLoginAttempts', 'loginBanDuration',
|
||||||
'showPopupFileEditor', 'shareFileEditorTabs', 'ipWhitelistEnabled'
|
'showPopupFileEditor', 'shareFileEditorTabs', 'ipWhitelistEnabled',
|
||||||
|
'autoCopyOnSelect' // +++ 添加新设置键 +++
|
||||||
];
|
];
|
||||||
const filteredSettings: Record<string, string> = {};
|
const filteredSettings: Record<string, string> = {};
|
||||||
for (const key in settingsToUpdate) {
|
for (const key in settingsToUpdate) {
|
||||||
@@ -245,5 +246,49 @@ export const settingsController = {
|
|||||||
console.error(`从 IP 黑名单删除 ${req.params.ip} 时出错:`, error);
|
console.error(`从 IP 黑名单删除 ${req.params.ip} 时出错:`, error);
|
||||||
res.status(500).json({ message: '从 IP 黑名单删除失败', error: error.message });
|
res.status(500).json({ message: '从 IP 黑名单删除失败', error: error.message });
|
||||||
}
|
}
|
||||||
|
}, // *** 确保这里有逗号 ***
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取终端选中自动复制设置
|
||||||
|
*/
|
||||||
|
async getAutoCopyOnSelect(req: Request, res: Response): Promise<void> {
|
||||||
|
try {
|
||||||
|
console.log('[Controller] Received request to get auto copy on select setting.');
|
||||||
|
const isEnabled = await settingsService.getAutoCopyOnSelect();
|
||||||
|
console.log(`[Controller] Sending auto copy on select setting to client: ${isEnabled}`);
|
||||||
|
res.json({ enabled: isEnabled });
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('[Controller] 获取终端选中自动复制设置时出错:', error);
|
||||||
|
res.status(500).json({ message: '获取终端选中自动复制设置失败', error: error.message });
|
||||||
}
|
}
|
||||||
|
}, // *** 确保这里有逗号 ***
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置终端选中自动复制
|
||||||
|
*/
|
||||||
|
async setAutoCopyOnSelect(req: Request, res: Response): Promise<void> {
|
||||||
|
console.log('[Controller] Received request to set auto copy on select setting.');
|
||||||
|
try {
|
||||||
|
const { enabled } = req.body;
|
||||||
|
console.log('[Controller] Request body enabled:', enabled);
|
||||||
|
|
||||||
|
if (typeof enabled !== 'boolean') {
|
||||||
|
console.warn('[Controller] Invalid enabled format received:', enabled);
|
||||||
|
res.status(400).json({ message: '无效的请求体,"enabled" 必须是一个布尔值' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[Controller] Calling settingsService.setAutoCopyOnSelect...');
|
||||||
|
await settingsService.setAutoCopyOnSelect(enabled);
|
||||||
|
console.log('[Controller] settingsService.setAutoCopyOnSelect completed successfully.');
|
||||||
|
|
||||||
|
// auditLogService.logAction('AUTO_COPY_ON_SELECT_UPDATED', { enabled }); // 可选:添加审计日志
|
||||||
|
|
||||||
|
console.log('[Controller] Sending success response.');
|
||||||
|
res.status(200).json({ message: '终端选中自动复制设置已成功更新' });
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('[Controller] 设置终端选中自动复制时出错:', error);
|
||||||
|
res.status(500).json({ message: '设置终端选中自动复制失败', error: error.message });
|
||||||
|
}
|
||||||
|
} // *** 最后的方法后面不需要逗号 ***
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,4 +37,10 @@ router.get('/ip-blacklist', settingsController.getIpBlacklist);
|
|||||||
router.delete('/ip-blacklist/:ip', settingsController.deleteIpFromBlacklist);
|
router.delete('/ip-blacklist/:ip', settingsController.deleteIpFromBlacklist);
|
||||||
|
|
||||||
|
|
||||||
|
// +++ 新增:终端选中自动复制路由 +++
|
||||||
|
// GET /api/v1/settings/auto-copy-on-select - 获取设置
|
||||||
|
router.get('/auto-copy-on-select', settingsController.getAutoCopyOnSelect);
|
||||||
|
// PUT /api/v1/settings/auto-copy-on-select - 更新设置
|
||||||
|
router.put('/auto-copy-on-select', settingsController.setAutoCopyOnSelect);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue';
|
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue';
|
||||||
import { ITheme } from 'xterm';
|
import { ITheme } from 'xterm';
|
||||||
import { Terminal } from 'xterm';
|
import { Terminal, ITerminalAddon, IDisposable } from 'xterm'; // +++ 导入 ITerminalAddon 和 IDisposable +++
|
||||||
import { useAppearanceStore } from '../stores/appearance.store'; // 导入外观 store
|
import { useAppearanceStore } from '../stores/appearance.store'; // 导入外观 store
|
||||||
|
import { useSettingsStore } from '../stores/settings.store'; // +++ 导入设置 store +++
|
||||||
import { storeToRefs } from 'pinia'; // 导入 storeToRefs
|
import { storeToRefs } from 'pinia'; // 导入 storeToRefs
|
||||||
import { FitAddon } from 'xterm-addon-fit';
|
import { FitAddon } from 'xterm-addon-fit';
|
||||||
import { WebLinksAddon } from 'xterm-addon-web-links';
|
import { WebLinksAddon } from 'xterm-addon-web-links';
|
||||||
@@ -31,12 +32,17 @@ let fitAddon: FitAddon | null = null;
|
|||||||
let searchAddon: SearchAddon | null = null; // *** 添加 searchAddon 变量 ***
|
let searchAddon: SearchAddon | null = null; // *** 添加 searchAddon 变量 ***
|
||||||
let resizeObserver: ResizeObserver | null = null;
|
let resizeObserver: ResizeObserver | null = null;
|
||||||
let debounceTimer: number | null = null; // 用于防抖的计时器 ID
|
let debounceTimer: number | null = null; // 用于防抖的计时器 ID
|
||||||
|
let selectionListenerDisposable: IDisposable | null = null; // +++ 提升声明并添加类型 +++
|
||||||
// const fontSize = ref(14); // 移除本地字体大小状态,将由 store 管理
|
// const fontSize = ref(14); // 移除本地字体大小状态,将由 store 管理
|
||||||
|
|
||||||
// --- Appearance Store ---
|
// --- Appearance Store ---
|
||||||
const appearanceStore = useAppearanceStore();
|
const appearanceStore = useAppearanceStore();
|
||||||
const { currentTerminalTheme, currentTerminalFontFamily, terminalBackgroundImage, currentTerminalFontSize } = storeToRefs(appearanceStore); // <-- 添加 currentTerminalFontSize
|
const { currentTerminalTheme, currentTerminalFontFamily, terminalBackgroundImage, currentTerminalFontSize } = storeToRefs(appearanceStore); // <-- 添加 currentTerminalFontSize
|
||||||
|
|
||||||
|
// --- Settings Store ---
|
||||||
|
const settingsStore = useSettingsStore(); // +++ 实例化设置 store +++
|
||||||
|
const { autoCopyOnSelectBoolean } = storeToRefs(settingsStore); // +++ 获取选中即复制状态 +++
|
||||||
|
|
||||||
// 防抖函数
|
// 防抖函数
|
||||||
const debounce = (func: Function, delay: number) => {
|
const debounce = (func: Function, delay: number) => {
|
||||||
let timeoutId: number | null = null; // Use a local variable for the timeout ID
|
let timeoutId: number | null = null; // Use a local variable for the timeout ID
|
||||||
@@ -210,6 +216,43 @@ onMounted(() => {
|
|||||||
emit('ready', { sessionId: props.sessionId, terminal: terminal, searchAddon: searchAddon });
|
emit('ready', { sessionId: props.sessionId, terminal: terminal, searchAddon: searchAddon });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 监听并处理选中即复制 ---
|
||||||
|
let currentSelection = ''; // 存储当前选区内容,避免重复复制空内容
|
||||||
|
const handleSelectionChange = () => {
|
||||||
|
if (terminal && autoCopyOnSelectBoolean.value) {
|
||||||
|
const newSelection = terminal.getSelection();
|
||||||
|
// 仅在选区内容发生变化且不为空时执行复制
|
||||||
|
if (newSelection && newSelection !== currentSelection) {
|
||||||
|
currentSelection = newSelection;
|
||||||
|
navigator.clipboard.writeText(newSelection).then(() => {
|
||||||
|
// console.log('[Terminal] 文本已自动复制到剪贴板:', newSelection); // 可选:成功日志
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('[Terminal] 自动复制到剪贴板失败:', err);
|
||||||
|
// 可以在这里向用户显示一个短暂的错误提示
|
||||||
|
});
|
||||||
|
} else if (!newSelection) {
|
||||||
|
// 如果新选区为空,重置 currentSelection
|
||||||
|
currentSelection = '';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果设置关闭,也重置 currentSelection
|
||||||
|
currentSelection = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加防抖以避免过于频繁地触发 handleSelectionChange
|
||||||
|
const debouncedSelectionChange = debounce(handleSelectionChange, 50); // 50ms 防抖
|
||||||
|
|
||||||
|
// 监听 xterm 的 selectionChange 事件
|
||||||
|
selectionListenerDisposable = terminal.onSelectionChange(debouncedSelectionChange); // Assign to outer variable
|
||||||
|
|
||||||
|
// 监听设置变化,如果关闭了自动复制,确保清除可能存在的旧选区状态
|
||||||
|
watch(autoCopyOnSelectBoolean, (newValue) => {
|
||||||
|
if (!newValue) {
|
||||||
|
currentSelection = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// --- 监听外观变化 ---
|
// --- 监听外观变化 ---
|
||||||
watch(currentTerminalTheme, (newTheme) => {
|
watch(currentTerminalTheme, (newTheme) => {
|
||||||
if (terminal) {
|
if (terminal) {
|
||||||
@@ -320,6 +363,11 @@ onBeforeUnmount(() => {
|
|||||||
terminal.dispose();
|
terminal.dispose();
|
||||||
terminal = null;
|
terminal = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 在卸载前清理选择监听器
|
||||||
|
if (selectionListenerDisposable) {
|
||||||
|
selectionListenerDisposable.dispose();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 暴露 write 方法给父组件 (可选)
|
// 暴露 write 方法给父组件 (可选)
|
||||||
|
|||||||
@@ -591,6 +591,17 @@
|
|||||||
"title": "Appearance Settings",
|
"title": "Appearance Settings",
|
||||||
"description": "Customize the visual theme and background of the application.",
|
"description": "Customize the visual theme and background of the application.",
|
||||||
"customizeButton": "Customize Appearance"
|
"customizeButton": "Customize Appearance"
|
||||||
|
},
|
||||||
|
"autoCopyOnSelect": {
|
||||||
|
"title": "Terminal Auto Copy",
|
||||||
|
"enableLabel": "Copy text automatically on selection release",
|
||||||
|
"saveButton": "Save",
|
||||||
|
"success": {
|
||||||
|
"saved": "Auto copy setting saved successfully."
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"saveFailed": "Failed to save auto copy setting."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
|||||||
@@ -591,6 +591,17 @@
|
|||||||
"title": "外观设置",
|
"title": "外观设置",
|
||||||
"description": "自定义应用程序的视觉主题和背景。",
|
"description": "自定义应用程序的视觉主题和背景。",
|
||||||
"customizeButton": "自定义外观"
|
"customizeButton": "自定义外观"
|
||||||
|
},
|
||||||
|
"autoCopyOnSelect": {
|
||||||
|
"title": "终端自动复制",
|
||||||
|
"enableLabel": "松开鼠标时自动复制选中文本",
|
||||||
|
"saveButton": "保存",
|
||||||
|
"success": {
|
||||||
|
"saved": "自动复制设置已成功保存。"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"saveFailed": "保存自动复制设置失败。"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ interface SettingsState {
|
|||||||
showPopupFileEditor?: string; // 'true' or 'false'
|
showPopupFileEditor?: string; // 'true' or 'false'
|
||||||
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' - 终端选中自动复制
|
||||||
// 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
|
||||||
}
|
}
|
||||||
@@ -60,6 +61,10 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (settings.value.autoCopyOnSelect === undefined) {
|
||||||
|
settings.value.autoCopyOnSelect = 'false'; // 默认禁用选中即复制
|
||||||
|
}
|
||||||
|
|
||||||
// --- 语言设置 ---
|
// --- 语言设置 ---
|
||||||
const langFromSettings = settings.value.language;
|
const langFromSettings = settings.value.language;
|
||||||
if (langFromSettings === 'en' || langFromSettings === 'zh') {
|
if (langFromSettings === 'en' || langFromSettings === 'zh') {
|
||||||
@@ -103,7 +108,8 @@ 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' // +++ 添加新设置键 +++
|
||||||
];
|
];
|
||||||
if (!allowedKeys.includes(key)) {
|
if (!allowedKeys.includes(key)) {
|
||||||
console.error(`[SettingsStore] 尝试更新不允许的设置键: ${key}`);
|
console.error(`[SettingsStore] 尝试更新不允许的设置键: ${key}`);
|
||||||
@@ -134,7 +140,8 @@ 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' // +++ 添加新设置键 +++
|
||||||
];
|
];
|
||||||
const filteredUpdates: Partial<SettingsState> = {};
|
const filteredUpdates: Partial<SettingsState> = {};
|
||||||
let languageUpdate: 'en' | 'zh' | undefined = undefined;
|
let languageUpdate: 'en' | 'zh' | undefined = undefined;
|
||||||
@@ -190,6 +197,11 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
const ipWhitelistEnabled = computed(() => settings.value.ipWhitelistEnabled === 'true');
|
const ipWhitelistEnabled = computed(() => settings.value.ipWhitelistEnabled === 'true');
|
||||||
|
|
||||||
|
|
||||||
|
// Getter for auto copy on select setting, returning boolean
|
||||||
|
const autoCopyOnSelectBoolean = computed(() => {
|
||||||
|
return settings.value.autoCopyOnSelect === 'true';
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
settings, // 只包含通用设置
|
settings, // 只包含通用设置
|
||||||
isLoading,
|
isLoading,
|
||||||
@@ -198,6 +210,7 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
showPopupFileEditorBoolean,
|
showPopupFileEditorBoolean,
|
||||||
shareFileEditorTabsBoolean,
|
shareFileEditorTabsBoolean,
|
||||||
ipWhitelistEnabled, // 暴露 IP 白名单启用状态
|
ipWhitelistEnabled, // 暴露 IP 白名单启用状态
|
||||||
|
autoCopyOnSelectBoolean, // +++ 暴露新 getter +++
|
||||||
// 移除外观相关的 getters 和 actions
|
// 移除外观相关的 getters 和 actions
|
||||||
loadInitialSettings,
|
loadInitialSettings,
|
||||||
updateSetting,
|
updateSetting,
|
||||||
|
|||||||
@@ -125,6 +125,18 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-section">
|
||||||
|
<h2>{{ $t('settings.autoCopyOnSelect.title') }}</h2>
|
||||||
|
<form @submit.prevent="handleUpdateAutoCopySetting">
|
||||||
|
<div class="form-group form-group-checkbox">
|
||||||
|
<input type="checkbox" id="autoCopyOnSelect" v-model="autoCopyEnabled">
|
||||||
|
<label for="autoCopyOnSelect">{{ $t('settings.autoCopyOnSelect.enableLabel') }}</label>
|
||||||
|
</div>
|
||||||
|
<button type="submit" :disabled="autoCopyLoading">{{ autoCopyLoading ? $t('common.saving') : $t('settings.autoCopyOnSelect.saveButton') }}</button>
|
||||||
|
<p v-if="autoCopyMessage" :class="{ 'success-message': autoCopySuccess, 'error-message': !autoCopySuccess }">{{ autoCopyMessage }}</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
<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>
|
||||||
@@ -220,7 +232,7 @@ const { t } = useI18n();
|
|||||||
|
|
||||||
// --- Reactive state from store ---
|
// --- Reactive state from store ---
|
||||||
// 使用 storeToRefs 获取响应式 getter
|
// 使用 storeToRefs 获取响应式 getter
|
||||||
const { settings, isLoading: settingsLoading, error: settingsError, showPopupFileEditorBoolean, shareFileEditorTabsBoolean } = storeToRefs(settingsStore);
|
const { settings, isLoading: settingsLoading, error: settingsError, showPopupFileEditorBoolean, shareFileEditorTabsBoolean, autoCopyOnSelectBoolean } = storeToRefs(settingsStore); // +++ 添加 autoCopyOnSelectBoolean +++
|
||||||
|
|
||||||
// --- Local state for forms ---
|
// --- Local state for forms ---
|
||||||
const ipWhitelistInput = ref('');
|
const ipWhitelistInput = ref('');
|
||||||
@@ -248,6 +260,10 @@ const shareTabsEnabled = ref(true); // 本地状态,用于共享标签页 v-mo
|
|||||||
const shareTabsLoading = ref(false);
|
const shareTabsLoading = ref(false);
|
||||||
const shareTabsMessage = ref('');
|
const shareTabsMessage = ref('');
|
||||||
const shareTabsSuccess = ref(false);
|
const shareTabsSuccess = ref(false);
|
||||||
|
const autoCopyEnabled = ref(false); // 本地状态,用于选中即复制 v-model
|
||||||
|
const autoCopyLoading = ref(false);
|
||||||
|
const autoCopyMessage = ref('');
|
||||||
|
const autoCopySuccess = 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) => {
|
||||||
@@ -262,6 +278,7 @@ 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; // +++ 同步选中即复制状态 +++
|
||||||
|
|
||||||
}, { deep: true, immediate: true }); // immediate: true to run on initial load
|
}, { deep: true, immediate: true }); // immediate: true to run on initial load
|
||||||
|
|
||||||
@@ -308,6 +325,25 @@ const handleUpdateShareTabsSetting = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- Auto Copy on Select setting method ---
|
||||||
|
const handleUpdateAutoCopySetting = async () => {
|
||||||
|
autoCopyLoading.value = true;
|
||||||
|
autoCopyMessage.value = '';
|
||||||
|
autoCopySuccess.value = false;
|
||||||
|
try {
|
||||||
|
const valueToSave = autoCopyEnabled.value ? 'true' : 'false';
|
||||||
|
await settingsStore.updateSetting('autoCopyOnSelect', valueToSave);
|
||||||
|
autoCopyMessage.value = t('settings.autoCopyOnSelect.success.saved'); // 需要添加翻译
|
||||||
|
autoCopySuccess.value = true;
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('更新自动复制设置失败:', error);
|
||||||
|
autoCopyMessage.value = error.message || t('settings.autoCopyOnSelect.error.saveFailed'); // 需要添加翻译
|
||||||
|
autoCopySuccess.value = false;
|
||||||
|
} finally {
|
||||||
|
autoCopyLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// --- 外观设置 ---
|
// --- 外观设置 ---
|
||||||
const openStyleCustomizer = () => {
|
const openStyleCustomizer = () => {
|
||||||
appearanceStore.toggleStyleCustomizer(true);
|
appearanceStore.toggleStyleCustomizer(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user