6.9 KiB
6.9 KiB
设置面板 UI 改进总结
问题修复
1. 保存后未立即生效 ✅
原因分析:
tabs数组中的visible属性与visibleTabs数组不同步watch(selectedTabs)覆盖了拖拽排序的顺序
修复方案:
- 在
handleTabVisibilityChange中同步更新tabs数组的visible属性 - 移除
watch(selectedTabs),避免覆盖排序 - 在
handleSave中确保数据完全同步 - 在
loadConfig中从后端加载时同步visible属性
2. UI 合并优化 ✅
改进前:
- Tab 显示、默认 Tab、拖拽排序分成三个独立的卡片
- 用户需要在不同区域操作,不够直观
改进后:
- 统一到一个列表中,每行包含所有控制项
- 更直观、更高效的配置体验
新的 UI 设计
Tab 配置列表结构
┌─────────────────────────────────────────────────────┐
│ ℹ️ 拖拽可调整 Tab 顺序,勾选复选框控制显示,单选按钮 │
│ 设置默认打开的 Tab │
├─────────────────────────────────────────────────────┤
│ ⋮ ☑ 数据库 ○ 默认打开 │
│ ⋮ ☑ 文件管理 ○ 默认打开 │
│ ⋮ ☑ 设备调用测试 ⦿ 默认打开 │
├─────────────────────────────────────────────────────┤
│ 隐藏的 Tabs │
├─────────────────────────────────────────────────────┤
│ ⋮ ☐ (其他隐藏的 Tab) │
└─────────────────────────────────────────────────────┘
每行包含的元素
- 拖拽手柄 (⋮) - 拖拽调整顺序
- 复选框 (☑/☐) - 控制显示/隐藏
- Tab 标题 - 显示 Tab 名称
- 单选按钮 (⦿) - 设置默认打开的 Tab
技术实现
新增辅助函数
// 判断 Tab 是否可见
const isTabVisible = (key) => {
return localConfig.value.visibleTabs.includes(key)
}
// 判断 Tab 是否启用
const isTabEnabled = (key) => {
const tab = localConfig.value.tabs.find(t => t.key === key)
return tab ? tab.enabled : false
}
// 隐藏的 Tabs 计算属性
const hiddenTabs = computed(() => {
return localConfig.value.tabs.filter(
tab => !localConfig.value.visibleTabs.includes(tab.key)
)
})
改进的可见性处理
// 处理单个 Tab 可见性变化
const handleTabVisibilityChange = (tabKey, visible) => {
if (visible) {
// 显示 Tab:添加到 visibleTabs 末尾
localConfig.value.visibleTabs.push(tabKey)
} else {
// 隐藏 Tab:从 visibleTabs 中移除
// 至少保留一个 Tab
if (localConfig.value.visibleTabs.length <= 1) {
Message.warning('至少需要保留一个可见的 Tab')
return
}
// 如果隐藏的是默认 Tab,需要更改默认 Tab
if (localConfig.value.defaultTab === tabKey) {
const remainingTabs = localConfig.value.visibleTabs.filter(k => k !== tabKey)
localConfig.value.defaultTab = remainingTabs[0] || ''
}
localConfig.value.visibleTabs = localConfig.value.visibleTabs.filter(
k => k !== tabKey
)
}
// 同步更新 tabs 数组中的 visible 属性
localConfig.value.tabs = localConfig.value.tabs.map(tab => ({
...tab,
visible: localConfig.value.visibleTabs.includes(tab.key)
}))
}
保存前数据同步
// 保存配置
const handleSave = async () => {
// ... 验证逻辑 ...
// 确保 tabs 数组中的 visible 属性与 visibleTabs 完全同步
const syncedTabs = localConfig.value.tabs.map(tab => ({
...tab,
visible: localConfig.value.visibleTabs.includes(tab.key)
}))
const configToSave = {
tabs: syncedTabs,
visibleTabs: [...localConfig.value.visibleTabs],
defaultTab: localConfig.value.defaultTab
}
// ... 保存逻辑 ...
}
样式改进
配置项样式
.tab-config-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
background: var(--color-fill-1);
border: 1px solid var(--color-border);
border-radius: 6px;
cursor: move;
transition: all 0.2s;
}
.tab-config-item:hover {
background: var(--color-fill-2);
border-color: var(--color-border-2);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.tab-config-item.dragging {
opacity: 0.5;
background: var(--color-fill-2);
transform: scale(0.98);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
隐藏项样式
.tab-config-item.hidden {
opacity: 0.6;
cursor: default;
}
.tab-config-item.hidden:hover {
border-color: var(--color-border);
box-shadow: none;
}
用户体验改进
- 一目了然 - 所有配置集中在一行,无需来回查看
- 即时反馈 - 拖拽时有视觉反馈(透明度、缩放、阴影)
- 智能提示 - 顶部说明文字告知用户如何操作
- 分组显示 - 可见和隐藏的 Tab 分开展示
- 保护机制 - 至少保留一个可见 Tab,最后一个 Tab 的复选框禁用
数据流保证
配置加载
后端 → GetAppConfig → loadConfig → 同步 visible 属性 → 显示
配置保存
用户操作 → localConfig → handleSave → 同步数据 → 后端保存 → 刷新 UI
关键同步点
- 复选框改变 → 同步
visibleTabs和tabs[].visible - 拖拽排序 → 更新
visibleTabs顺序 - 保存前 → 确保所有
visible属性与visibleTabs一致 - 加载后 → 根据后端数据同步
visible属性
测试清单
基础功能
- ✅ 拖拽排序 Tab
- ✅ 勾选/取消勾选复选框
- ✅ 设置默认 Tab
- ✅ 保存配置后立即生效
- ✅ 刷新页面后配置保持
边界情况
- ✅ 至少保留一个可见 Tab
- ✅ 隐藏默认 Tab 时自动切换
- ✅ 禁用的 Tab 不可操作
- ✅ 配置为空时显示默认值
UI 交互
- ✅ 拖拽时视觉反馈
- ✅ hover 状态提示
- ✅ 隐藏项分组显示
- ✅ 说明文字清晰
修复文件
frontend/src/components/SettingsPanel.vue- UI 合并和逻辑修复frontend/src/App.vue- loadConfig 和 handleSaveConfig 数据同步
总结
本次改进解决了两个主要问题:
- 保存后未立即生效 - 通过数据同步机制修复
- UI 不够直观 - 通过统一配置列表优化
用户体验得到显著提升,配置操作更加高效和直观。