feat: 添加显隐标签的设置

This commit is contained in:
Baobhan Sith
2025-05-03 20:34:52 +08:00
parent c3470a5419
commit 6144633a5e
10 changed files with 592 additions and 137 deletions
+137 -87
View File
@@ -26,88 +26,123 @@
</div>
<!-- List Area -->
<div class="flex-grow overflow-y-auto p-2">
<!-- Loading State (Show if loading and no groups are ready yet) -->
<div v-if="isLoading && filteredAndGroupedCommands.length === 0" class="p-6 text-center text-text-secondary text-sm flex flex-col items-center justify-center h-full">
<!-- Loading State -->
<div v-if="isLoading && quickCommandsStore.quickCommandsList.length === 0" class="p-6 text-center text-text-secondary text-sm flex flex-col items-center justify-center h-full">
<i class="fas fa-spinner fa-spin text-xl mb-2"></i>
<p>{{ t('common.loading', '加载中...') }}</p>
</div>
<!-- Empty State (Show if not loading and no groups exist) -->
<div v-else-if="!isLoading && filteredAndGroupedCommands.length === 0" class="p-6 text-center text-text-secondary text-sm flex flex-col items-center justify-center h-full">
<!-- Empty State (No commands at all) -->
<div v-else-if="!isLoading && quickCommandsStore.quickCommandsList.length === 0" class="p-6 text-center text-text-secondary text-sm flex flex-col items-center justify-center h-full">
<i class="fas fa-bolt text-xl mb-2"></i>
<p class="mb-3">{{ $t('quickCommands.empty', '没有快捷指令。') }}</p>
<button @click="openAddForm" class="px-4 py-2 bg-primary text-white border-none rounded-lg text-sm font-semibold cursor-pointer shadow-md transition-colors duration-200 ease-in-out hover:bg-primary-dark focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary">
{{ $t('quickCommands.addFirst', '创建第一个快捷指令') }}
</button>
</div>
<!-- Grouped Command List -->
<!-- No Results State (Commands exist, but filter yields no results) -->
<div v-else-if="!isLoading && ((showQuickCommandTagsBoolean && filteredAndGroupedCommands.length === 0) || (!showQuickCommandTagsBoolean && flatFilteredCommands.length === 0)) && searchTerm" class="p-6 text-center text-text-secondary text-sm flex flex-col items-center justify-center h-full">
<i class="fas fa-search text-xl mb-2"></i>
<p>{{ t('quickCommands.noResults', '没有找到匹配的指令') }} "{{ searchTerm }}"</p>
</div>
<!-- Command List (Grouped or Flat) -->
<div v-else class="list-none p-0 m-0" ref="commandListContainerRef"> <!-- Changed ref name -->
<div v-for="groupData in filteredAndGroupedCommands" :key="groupData.groupName" class="mb-1 last:mb-0">
<!-- Group Header -->
<!-- Group Header - Modified for inline editing -->
<div
class="group px-3 py-2 font-semibold flex items-center text-foreground rounded-md hover:bg-header/80 transition-colors duration-150"
:class="{ 'cursor-pointer': editingTagId !== (groupData.tagId === null ? 'untagged' : groupData.tagId) }"
@click="editingTagId !== (groupData.tagId === null ? 'untagged' : groupData.tagId) ? toggleGroup(groupData.groupName) : null"
>
<i
:class="['fas', expandedGroups[groupData.groupName] ? 'fa-chevron-down' : 'fa-chevron-right', 'mr-2 w-4 text-center text-text-secondary group-hover:text-foreground transition-transform duration-200 ease-in-out', {'transform rotate-0': !expandedGroups[groupData.groupName]}]"
@click.stop="toggleGroup(groupData.groupName)"
class="cursor-pointer flex-shrink-0"
></i>
<!-- Editing State -->
<input
v-if="editingTagId === (groupData.tagId === null ? 'untagged' : groupData.tagId)"
:key="groupData.tagId === null ? 'untagged-input' : `tag-input-${groupData.tagId}`"
:ref="(el) => setTagInputRef(el, groupData.tagId === null ? 'untagged' : groupData.tagId)"
type="text"
v-model="editedTagName"
class="text-sm bg-input border border-primary rounded px-1 py-0 w-full"
@blur="finishEditingTag"
@keydown.enter.prevent="finishEditingTag"
@keydown.esc.prevent="cancelEditingTag"
@click.stop
/>
<!-- Display State -->
<span
v-else
class="text-sm inline-block overflow-hidden text-ellipsis whitespace-nowrap"
:class="{ 'cursor-pointer hover:underline': true }"
:title="t('quickCommands.tags.clickToEditTag', '点击编辑标签')"
@click.stop="startEditingTag(groupData.tagId, groupData.groupName)"
>
{{ groupData.groupName }}
</span>
<!-- Optional: Add count? -->
<!-- <span v-if="editingTagId !== (groupData.tagId === null ? 'untagged' : groupData.tagId)" class="ml-auto text-xs text-text-secondary pl-2">({{ groupData.commands.length }})</span> -->
</div>
<!-- Command Items List (only show if expanded) -->
<ul v-show="quickCommandsStore.expandedGroups[groupData.groupName]" class="list-none p-0 m-0 pl-3">
<li
v-for="(cmd) in groupData.commands"
:key="cmd.id"
:data-command-id="cmd.id"
class="group flex justify-between items-center px-3 py-2.5 mb-1 cursor-pointer rounded-md hover:bg-primary/10 transition-colors duration-150"
:class="{ 'bg-primary/20 font-medium': isCommandSelected(cmd.id) }"
@click="executeCommand(cmd)"
>
<!-- Command Info (Structure remains the same) -->
<div class="flex flex-col overflow-hidden mr-2 flex-grow">
<span v-if="cmd.name" class="font-medium text-sm truncate mb-0.5 text-foreground">{{ cmd.name }}</span>
<span class="text-xs truncate font-mono" :class="{ 'text-sm': !cmd.name, 'text-text-secondary': true }">{{ cmd.command }}</span>
</div>
<!-- Actions (Structure remains the same) -->
<div class="flex items-center flex-shrink-0 opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity duration-150">
<span class="text-xs bg-border px-1.5 py-0.5 rounded mr-2 text-text-secondary" :title="t('quickCommands.usageCount', '使用次数')">{{ cmd.usage_count }}</span>
<button @click.stop="openEditForm(cmd)" class="p-1.5 rounded hover:bg-black/10 transition-colors duration-150 text-text-secondary hover:text-primary" :title="$t('common.edit', '编辑')">
<i class="fas fa-edit text-sm"></i>
</button>
<button @click.stop="confirmDelete(cmd)" class="p-1.5 rounded hover:bg-black/10 transition-colors duration-150 text-text-secondary hover:text-error" :title="$t('common.delete', '删除')">
<i class="fas fa-times text-sm"></i>
</button>
</div>
</li>
</ul>
</div>
<!-- Grouped View -->
<div v-if="showQuickCommandTagsBoolean">
<div v-for="groupData in filteredAndGroupedCommands" :key="groupData.groupName" class="mb-1 last:mb-0">
<!-- Group Header - Modified for inline editing -->
<div
class="group px-3 py-2 font-semibold flex items-center text-foreground rounded-md hover:bg-header/80 transition-colors duration-150"
:class="{ 'cursor-pointer': editingTagId !== (groupData.tagId === null ? 'untagged' : groupData.tagId) }"
@click="editingTagId !== (groupData.tagId === null ? 'untagged' : groupData.tagId) ? toggleGroup(groupData.groupName) : null"
>
<i
:class="['fas', expandedGroups[groupData.groupName] ? 'fa-chevron-down' : 'fa-chevron-right', 'mr-2 w-4 text-center text-text-secondary group-hover:text-foreground transition-transform duration-200 ease-in-out', {'transform rotate-0': !expandedGroups[groupData.groupName]}]"
@click.stop="toggleGroup(groupData.groupName)"
class="cursor-pointer flex-shrink-0"
></i>
<!-- Editing State -->
<input
v-if="editingTagId === (groupData.tagId === null ? 'untagged' : groupData.tagId)"
:key="groupData.tagId === null ? 'untagged-input' : `tag-input-${groupData.tagId}`"
:ref="(el) => setTagInputRef(el, groupData.tagId === null ? 'untagged' : groupData.tagId)"
type="text"
v-model="editedTagName"
class="text-sm bg-input border border-primary rounded px-1 py-0 w-full"
@blur="finishEditingTag"
@keydown.enter.prevent="finishEditingTag"
@keydown.esc.prevent="cancelEditingTag"
@click.stop
/>
<!-- Display State -->
<span
v-else
class="text-sm inline-block overflow-hidden text-ellipsis whitespace-nowrap"
:class="{ 'cursor-pointer hover:underline': true }"
:title="t('quickCommands.tags.clickToEditTag', '点击编辑标签')"
@click.stop="startEditingTag(groupData.tagId, groupData.groupName)"
>
{{ groupData.groupName }}
</span>
<!-- Optional: Add count? -->
<!-- <span v-if="editingTagId !== (groupData.tagId === null ? 'untagged' : groupData.tagId)" class="ml-auto text-xs text-text-secondary pl-2">({{ groupData.commands.length }})</span> -->
</div>
<!-- Command Items List (only show if expanded) -->
<ul v-show="quickCommandsStore.expandedGroups[groupData.groupName]" class="list-none p-0 m-0 pl-3">
<li
v-for="(cmd) in groupData.commands"
:key="cmd.id"
:data-command-id="cmd.id"
class="group flex justify-between items-center px-3 py-2.5 mb-1 cursor-pointer rounded-md hover:bg-primary/10 transition-colors duration-150"
:class="{ 'bg-primary/20 font-medium': isCommandSelected(cmd.id) }"
@click="executeCommand(cmd)"
>
<!-- Command Info (Structure remains the same) -->
<div class="flex flex-col overflow-hidden mr-2 flex-grow">
<span v-if="cmd.name" class="font-medium text-sm truncate mb-0.5 text-foreground">{{ cmd.name }}</span>
<span class="text-xs truncate font-mono" :class="{ 'text-sm': !cmd.name, 'text-text-secondary': true }">{{ cmd.command }}</span>
</div>
<!-- Actions (Structure remains the same) -->
<div class="flex items-center flex-shrink-0 opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity duration-150">
<span class="text-xs bg-border px-1.5 py-0.5 rounded mr-2 text-text-secondary" :title="t('quickCommands.usageCount', '使用次数')">{{ cmd.usage_count }}</span>
<button @click.stop="openEditForm(cmd)" class="p-1.5 rounded hover:bg-black/10 transition-colors duration-150 text-text-secondary hover:text-primary" :title="$t('common.edit', '编辑')">
<i class="fas fa-edit text-sm"></i>
</button>
<button @click.stop="confirmDelete(cmd)" class="p-1.5 rounded hover:bg-black/10 transition-colors duration-150 text-text-secondary hover:text-error" :title="$t('common.delete', '删除')">
<i class="fas fa-times text-sm"></i>
</button>
</div>
</li>
</ul>
</div>
</div>
<!-- Flat View -->
<ul v-else class="list-none p-0 m-0">
<li
v-for="(cmd) in flatFilteredCommands"
:key="cmd.id"
:data-command-id="cmd.id"
class="group flex justify-between items-center px-3 py-2.5 mb-1 cursor-pointer rounded-md hover:bg-primary/10 transition-colors duration-150"
:class="{ 'bg-primary/20 font-medium': isCommandSelected(cmd.id) }"
@click="executeCommand(cmd)"
>
<!-- Command Info -->
<div class="flex flex-col overflow-hidden mr-2 flex-grow">
<span v-if="cmd.name" class="font-medium text-sm truncate mb-0.5 text-foreground">{{ cmd.name }}</span>
<span class="text-xs truncate font-mono" :class="{ 'text-sm': !cmd.name, 'text-text-secondary': true }">{{ cmd.command }}</span>
</div>
<!-- Actions -->
<div class="flex items-center flex-shrink-0 opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity duration-150">
<span class="text-xs bg-border px-1.5 py-0.5 rounded mr-2 text-text-secondary" :title="t('quickCommands.usageCount', '使用次数')">{{ cmd.usage_count }}</span>
<button @click.stop="openEditForm(cmd)" class="p-1.5 rounded hover:bg-black/10 transition-colors duration-150 text-text-secondary hover:text-primary" :title="$t('common.edit', '编辑')">
<i class="fas fa-edit text-sm"></i>
</button>
<button @click.stop="confirmDelete(cmd)" class="p-1.5 rounded hover:bg-black/10 transition-colors duration-150 text-text-secondary hover:text-error" :title="$t('common.delete', '删除')">
<i class="fas fa-times text-sm"></i>
</button>
</div>
</li>
</ul>
</div>
</div>
</div>
@@ -130,12 +165,14 @@ import { useUiNotificationsStore } from '../stores/uiNotifications.store';
import { useI18n } from 'vue-i18n';
import AddEditQuickCommandForm from '../components/AddEditQuickCommandForm.vue'; // 导入表单组件
import { useFocusSwitcherStore } from '../stores/focusSwitcher.store'; // +++ 导入焦点切换 Store +++
import { useSettingsStore } from '../stores/settings.store'; // 新增:导入设置 store
const quickCommandsStore = useQuickCommandsStore();
const quickCommandTagsStore = useQuickCommandTagsStore(); // +++ Instantiate the new tag store +++
const uiNotificationsStore = useUiNotificationsStore(); // 如果需要显示通知
const { t } = useI18n();
const focusSwitcherStore = useFocusSwitcherStore(); // +++ 实例化焦点切换 Store +++
const settingsStore = useSettingsStore(); // 新增:实例化设置 store
const hoveredItemId = ref<number | null>(null);
const isFormVisible = ref(false);
@@ -159,9 +196,17 @@ const isLoading = computed(() => quickCommandsStore.isLoading);
// selectedIndex now refers to the index within the flatVisibleCommands list
// Also get expandedGroups reactively for the template
const { selectedIndex: storeSelectedIndex, flatVisibleCommands, expandedGroups } = storeToRefs(quickCommandsStore);
const { showQuickCommandTagsBoolean } = storeToRefs(settingsStore); // 新增:获取设置项
// 新增:计算属性,仅过滤和排序,不分组
const flatFilteredCommands = computed(() => {
// 直接使用 store 中的 flatVisibleCommands,因为它已经处理了过滤和排序
return quickCommandsStore.flatVisibleCommands;
});
// --- Helper function for selection check ---
const isCommandSelected = (commandId: number): boolean => {
// 使用 store 的 flatVisibleCommands 和 storeSelectedIndex
if (storeSelectedIndex.value < 0 || !flatVisibleCommands.value[storeSelectedIndex.value]) {
return false;
}
@@ -181,8 +226,18 @@ onMounted(async () => { // Make onMounted async
await quickCommandsStore.fetchQuickCommands();
// Also fetch the quick command tags using the correct store instance
await quickCommandTagsStore.fetchTags();
// +++ 注册自定义聚焦动作 +++
unregisterFocus = focusSwitcherStore.registerFocusAction('quickCommandsSearch', focusSearchInput);
});
onBeforeUnmount(() => {
// +++ 调用保存的注销函数 +++
if (unregisterFocus) {
unregisterFocus();
}
});
// +++ Watcher to focus input when editing starts +++
watch(editingTagId, async (newId) => {
if (newId !== null) {
@@ -197,18 +252,11 @@ watch(editingTagId, async (newId) => {
}
});
// 新增:监听显示模式变化,重置选择
watch(showQuickCommandTagsBoolean, () => {
quickCommandsStore.resetSelection();
});
// +++ 注册/注销自定义聚焦动作 +++
onMounted(() => {
// +++ 保存返回的注销函数 +++
unregisterFocus = focusSwitcherStore.registerFocusAction('quickCommandsSearch', focusSearchInput);
});
onBeforeUnmount(() => {
// +++ 调用保存的注销函数 +++
if (unregisterFocus) {
unregisterFocus();
}
});
// --- 事件处理 ---
@@ -221,12 +269,13 @@ const updateSearchTerm = (event: Event) => {
// +++ 重构滚动逻辑 +++
const scrollToSelected = async (index: number) => {
await nextTick(); // 等待 DOM 更新
// 使用 store 的 flatVisibleCommands
if (index < 0 || !commandListContainerRef.value || !flatVisibleCommands.value[index]) return;
const selectedCommandId = flatVisibleCommands.value[index].id;
const listContainer = commandListContainerRef.value;
// Find the element using the data attribute
// Find the element using the data attribute (works for both views)
const selectedElement = listContainer.querySelector(`li[data-command-id="${selectedCommandId}"]`) as HTMLLIElement;
if (selectedElement) {
@@ -244,9 +293,9 @@ watch(storeSelectedIndex, (newIndex) => {
scrollToSelected(newIndex);
});
// Keyboard navigation now operates on the flat visible list
// Keyboard navigation now operates on the flat visible list from the store
const handleSearchInputKeydown = (event: KeyboardEvent) => {
// Use flatVisibleCommands for navigation logic
// 使用 store 的 flatVisibleCommands
const commands = flatVisibleCommands.value;
if (!commands.length) return;
@@ -263,6 +312,7 @@ const handleSearchInputKeydown = (event: KeyboardEvent) => {
break;
case 'Enter':
event.preventDefault();
// 使用 store 的 storeSelectedIndex
if (storeSelectedIndex.value >= 0 && storeSelectedIndex.value < commands.length) {
executeCommand(commands[storeSelectedIndex.value]);
}
@@ -294,6 +344,7 @@ const toggleGroup = (groupName: string) => {
// After toggling, selection might become invalid if the selected item is now hidden
// Reset selection or check if the selected item is still visible
nextTick(() => { // Wait for DOM update potentially caused by v-show
// 使用 store 的 flatVisibleCommands 和 storeSelectedIndex
const selectedCmdId = storeSelectedIndex.value >= 0 && flatVisibleCommands.value[storeSelectedIndex.value]
? flatVisibleCommands.value[storeSelectedIndex.value].id
: null;
@@ -476,4 +527,3 @@ const cancelEditingTag = () => {
};
</script>
@@ -444,6 +444,46 @@
</div>
</form>
</div>
<hr class="border-border/50"> <!-- NEW: Separator -->
<!-- Show Connection Tags -->
<div class="settings-section-content">
<h3 class="text-base font-semibold text-foreground mb-3">{{ $t('settings.workspace.showConnectionTagsTitle', '显示连接标签') }}</h3>
<form @submit.prevent="handleUpdateShowConnectionTags" class="space-y-4">
<div class="flex items-center">
<input type="checkbox" id="showConnectionTags" v-model="showConnectionTagsLocal"
class="h-4 w-4 rounded border-border text-primary focus:ring-primary mr-2 cursor-pointer">
<label for="showConnectionTags" class="text-sm text-foreground cursor-pointer select-none">{{ $t('settings.workspace.showConnectionTagsLabel', '在连接列表中显示标签') }}</label>
</div>
<p class="text-xs text-text-secondary mt-1">{{ $t('settings.workspace.showConnectionTagsDescription', '关闭后将隐藏连接列表中的标签,并从搜索中排除标签。') }}</p>
<div class="flex items-center justify-between pt-2">
<button type="submit" :disabled="showConnectionTagsLoading"
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">
{{ $t('common.save') }}
</button>
<p v-if="showConnectionTagsMessage" :class="['text-sm', showConnectionTagsSuccess ? 'text-success' : 'text-error']">{{ showConnectionTagsMessage }}</p>
</div>
</form>
</div>
<hr class="border-border/50"> <!-- NEW: Separator -->
<!-- Show Quick Command Tags -->
<div class="settings-section-content">
<h3 class="text-base font-semibold text-foreground mb-3">{{ $t('settings.workspace.showQuickCommandTagsTitle', '显示快捷指令标签') }}</h3>
<form @submit.prevent="handleUpdateShowQuickCommandTags" class="space-y-4">
<div class="flex items-center">
<input type="checkbox" id="showQuickCommandTags" v-model="showQuickCommandTagsLocal"
class="h-4 w-4 rounded border-border text-primary focus:ring-primary mr-2 cursor-pointer">
<label for="showQuickCommandTags" class="text-sm text-foreground cursor-pointer select-none">{{ $t('settings.workspace.showQuickCommandTagsLabel', '在快捷指令列表中显示标签') }}</label>
</div>
<p class="text-xs text-text-secondary mt-1">{{ $t('settings.workspace.showQuickCommandTagsDescription', '关闭后将隐藏快捷指令列表中的标签,并从搜索中排除标签。') }}</p>
<div class="flex items-center justify-between pt-2">
<button type="submit" :disabled="showQuickCommandTagsLoading"
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">
{{ $t('common.save') }}
</button>
<p v-if="showQuickCommandTagsMessage" :class="['text-sm', showQuickCommandTagsSuccess ? 'text-success' : 'text-error']">{{ showQuickCommandTagsMessage }}</p>
</div>
</form>
</div>
</div>
</div>
@@ -624,6 +664,8 @@ const {
captchaSettings, // <-- Import CAPTCHA settings state
commandInputSyncTarget, // NEW: Import command input sync target getter
ipBlacklistEnabledBoolean, // <-- Import IP Blacklist enabled getter
showConnectionTagsBoolean, // NEW: Import connection tag visibility getter
showQuickCommandTagsBoolean, // NEW: Import quick command tag visibility getter
} = storeToRefs(settingsStore);
// Removed Passkey state import from authStore
@@ -648,6 +690,8 @@ const popupEditorEnabled = ref(true); // 本地状态,用于 v-model
const workspaceSidebarPersistentEnabled = ref(false); // 新增:侧边栏固定设置的本地状态
const commandInputSyncTargetLocal = ref<'none' | 'quickCommands' | 'commandHistory'>('none'); // NEW: Local state for command input sync target
const ipBlacklistEnabled = ref(true); // <-- Local state for IP Blacklist switch
const showConnectionTagsLocal = ref(true); // NEW: Local state for connection tags switch
const showQuickCommandTagsLocal = ref(true); // NEW: Local state for quick command tags switch
// --- Local UI feedback state ---
const ipWhitelistLoading = ref(false);
@@ -692,6 +736,12 @@ const selectedTimezone = ref('UTC'); // 本地状态,用于时区 v-model
const timezoneLoading = ref(false);
const timezoneMessage = ref('');
const timezoneSuccess = ref(false);
const showConnectionTagsLoading = ref(false); // NEW
const showConnectionTagsMessage = ref(''); // NEW
const showConnectionTagsSuccess = ref(false); // NEW
const showQuickCommandTagsLoading = ref(false); // NEW
const showQuickCommandTagsMessage = ref(''); // NEW
const showQuickCommandTagsSuccess = ref(false); // NEW
// CAPTCHA Form State
const captchaForm = reactive<UpdateCaptchaSettingsDto>({ // Use reactive for the form object
enabled: false,
@@ -740,6 +790,8 @@ watch(settings, (newSettings, oldSettings) => {
commandInputSyncTargetLocal.value = commandInputSyncTarget.value; // NEW: Sync command input sync target
selectedTimezone.value = newSettings.timezone || 'UTC'; // 同步时区设置
ipBlacklistEnabled.value = ipBlacklistEnabledBoolean.value; // <-- Sync IP Blacklist enabled state
showConnectionTagsLocal.value = showConnectionTagsBoolean.value; // NEW: Sync connection tags state
showQuickCommandTagsLocal.value = showQuickCommandTagsBoolean.value; // NEW: Sync quick command tags state
}, { deep: true, immediate: true }); // immediate: true to run on initial load
@@ -928,6 +980,46 @@ const handleUpdateTimezone = async () => {
}
};
// --- Show Connection Tags setting method ---
const handleUpdateShowConnectionTags = async () => {
showConnectionTagsLoading.value = true;
showConnectionTagsMessage.value = '';
showConnectionTagsSuccess.value = false;
try {
await settingsStore.updateSetting('showConnectionTags', showConnectionTagsLocal.value);
showConnectionTagsMessage.value = t('settings.workspace.success.showConnectionTagsSaved', '连接标签显示设置已保存'); // 需要添加翻译
showConnectionTagsSuccess.value = true;
} catch (error: any) {
console.error('更新显示连接标签设置失败:', error);
showConnectionTagsMessage.value = error.message || t('settings.workspace.error.showConnectionTagsSaveFailed', '保存连接标签显示设置失败'); // 需要添加翻译
showConnectionTagsSuccess.value = false;
// No need to revert local state on failure with explicit save button
} finally {
showConnectionTagsLoading.value = false;
// Keep message visible until next save attempt
}
};
// --- Show Quick Command Tags setting method ---
const handleUpdateShowQuickCommandTags = async () => {
showQuickCommandTagsLoading.value = true;
showQuickCommandTagsMessage.value = '';
showQuickCommandTagsSuccess.value = false;
try {
await settingsStore.updateSetting('showQuickCommandTags', showQuickCommandTagsLocal.value);
showQuickCommandTagsMessage.value = t('settings.workspace.success.showQuickCommandTagsSaved', '快捷指令标签显示设置已保存'); // 需要添加翻译
showQuickCommandTagsSuccess.value = true;
} catch (error: any) {
console.error('更新显示快捷指令标签设置失败:', error);
showQuickCommandTagsMessage.value = error.message || t('settings.workspace.error.showQuickCommandTagsSaveFailed', '保存快捷指令标签显示设置失败'); // 需要添加翻译
showQuickCommandTagsSuccess.value = false;
// No need to revert local state on failure with explicit save button
} finally {
showQuickCommandTagsLoading.value = false;
// Keep message visible until next save attempt
}
};
// --- 外观设置 ---
const openStyleCustomizer = () => {
appearanceStore.toggleStyleCustomizer(true);