优化配置界面

This commit is contained in:
2024-12-13 00:30:03 +08:00
parent 8f1964c374
commit f8df3d2681
4 changed files with 304 additions and 74 deletions

View File

@@ -2,7 +2,7 @@
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const router = useRouter() const router = useRouter()
router.push('/project') router.push('/config')
</script> </script>
<template> <template>

View File

@@ -1,18 +1,91 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref } from 'vue'
import { ConfigItemType, type ConfigGroup } from '@/types/config'
// 配置项状态 // 定义配置组
const config = ref({ const configGroups = ref<ConfigGroup[]>([
theme: 'light', {
language: 'zh-CN', title: '外观设置',
autoSave: true, enabled: true,
notifications: true items: [
}) {
type: ConfigItemType.TEXT,
key: 'projectName',
label: '项目名称',
value: '',
placeholder: '请输入默认项目名称',
description: '设置新建项目时的默认项目名称'
},
{
type: ConfigItemType.SELECT,
key: 'theme',
label: '主题',
value: 'light',
description: '切换应用的显示主题',
options: [
{ label: '浅色', value: 'light' },
{ label: '深色', value: 'dark' }
]
}
]
},
{
title: '系统设置',
enabled: true,
items: [
{
type: ConfigItemType.SELECT,
key: 'language',
label: '语言',
value: 'zh-CN',
description: '设置应用界面显示的语言',
options: [
{ label: '中文', value: 'zh-CN' },
{ label: 'English', value: 'en-US' }
]
},
{
type: ConfigItemType.SWITCH,
key: 'autoSave',
label: '自动保存',
value: true,
description: '开启后将自动保存您的修改'
},
{
type: ConfigItemType.SWITCH,
key: 'notifications',
label: '通知提醒',
value: true,
description: '是否显示系统通知提醒'
}
]
}
])
// 处理配置更改 // 处理单个配置更改
const handleConfigChange = () => { const handleConfigItemChange = (item: any) => {
// 这里可以添加保存配置的逻辑 const config = configGroups.value.reduce((acc, group) => {
console.log('配置已更新:', config.value) group.items.forEach(item => {
acc[item.key] = item.value
})
return acc
}, {} as Record<string, any>)
console.log('配置已更新:', config)
}
// 处理配置组启用状态变更
const handleGroupEnableChange = (group: ConfigGroup) => {
const config = configGroups.value.reduce((acc, group) => {
if (group.enabled) {
group.items.forEach(item => {
acc[item.key] = item.value
})
}
return acc
}, {} as Record<string, any>)
console.log('配置已更新:', config)
} }
</script> </script>
@@ -20,47 +93,73 @@ const handleConfigChange = () => {
<div class="config-container"> <div class="config-container">
<h2 class="config-title">系统设置</h2> <h2 class="config-title">系统设置</h2>
<div class="config-section"> <div
<div class="config-item"> v-for="(group, groupIndex) in configGroups"
<label>主题</label> :key="groupIndex"
<select v-model="config.theme"> class="config-section"
<option value="light">浅色</option> >
<option value="dark">深色</option> <div class="group-header">
</select> <h3 class="group-title">{{ group.title }}</h3>
<label class="switch">
<input
type="checkbox"
v-model="group.enabled"
@change="handleGroupEnableChange(group)"
>
<span class="slider"></span>
</label>
</div> </div>
<div class="config-item"> <div
<label>语言</label> v-if="group.enabled"
<select v-model="config.language"> v-for="(item, itemIndex) in group.items"
<option value="zh-CN">中文</option> :key="itemIndex"
<option value="en-US">English</option> class="config-item"
</select>
</div>
<div class="config-item">
<label>自动保存</label>
<input
type="checkbox"
v-model="config.autoSave"
>
</div>
<div class="config-item">
<label>通知提醒</label>
<input
type="checkbox"
v-model="config.notifications"
>
</div>
</div>
<div class="config-actions">
<button
class="save-button"
@click="handleConfigChange"
> >
保存设置 <div class="item-info">
</button> <div class="item-label">{{ item.label }}</div>
<div v-if="item.description" class="item-description">
{{ item.description }}
</div>
</div>
<!-- 文本输入 -->
<div v-if="item.type === ConfigItemType.TEXT" class="input-wrapper">
<input
type="text"
v-model="item.value"
:placeholder="(item as any).placeholder"
@change="handleConfigItemChange(item)"
>
</div>
<!-- 开关 -->
<label v-else-if="item.type === ConfigItemType.SWITCH" class="switch">
<input
type="checkbox"
v-model="item.value"
@change="handleConfigItemChange(item)"
>
<span class="slider"></span>
</label>
<!-- 下拉选择 -->
<div v-else-if="item.type === ConfigItemType.SELECT" class="select-wrapper">
<select
v-model="item.value"
@change="handleConfigItemChange(item)"
>
<option
v-for="option in (item as any).options"
:key="option.value"
:value="option.value"
>
{{ option.label }}
</option>
</select>
<div class="select-arrow"></div>
</div>
</div>
</div> </div>
</div> </div>
</template> </template>
@@ -82,8 +181,21 @@ const handleConfigChange = () => {
.config-section { .config-section {
background: #fff; background: #fff;
border-radius: 8px; border-radius: 8px;
padding: 20px; padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
margin-bottom: 24px;
}
.group-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
.group-title {
font-size: 18px;
color: #333;
} }
.config-item { .config-item {
@@ -91,43 +203,114 @@ const handleConfigChange = () => {
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 12px 0; padding: 12px 0;
border-bottom: 1px solid #eee;
} }
.config-item:last-child { .item-info {
border-bottom: none; flex: 1;
margin-right: 24px;
} }
.config-item label { .item-label {
font-size: 14px; font-size: 14px;
color: #333; color: rgba(0, 0, 0, 0.87);
} }
.config-item select { .item-description {
padding: 6px 12px; font-size: 12px;
color: rgba(0, 0, 0, 0.45);
margin-top: 4px;
line-height: 1.5;
}
/* 输入框通用包装器 */
.input-wrapper {
position: relative;
width: 200px;
}
.input-wrapper input {
width: 100%;
padding: 8px 12px;
outline: none;
font-size: 14px;
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 4px; border-radius: 4px;
font-size: 14px; transition: all 0.2s;
min-width: 120px; box-sizing: border-box;
} }
.config-actions { .input-wrapper input:focus {
margin-top: 24px; border-color: #1976d2;
text-align: right;
} }
.save-button { /* 开关样式 */
background: #1976d2; .switch {
color: white; position: relative;
border: none; display: inline-block;
padding: 8px 24px; width: 40px;
height: 20px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: 0.3s;
border-radius: 20px;
}
.slider:before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 2px;
bottom: 2px;
background-color: white;
transition: 0.3s;
border-radius: 50%;
box-shadow: 0 1px 2px rgba(0,0,0,0.2);
}
.switch input:checked + .slider {
background-color: #1976d2;
}
.switch input:checked + .slider:before {
transform: translateX(20px);
background-color: white;
}
/* 下拉选择框样式 */
.select-wrapper {
position: relative;
width: 200px;
}
.select-wrapper select {
width: 100%;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px; border-radius: 4px;
appearance: none;
background: white;
font-size: 14px; font-size: 14px;
cursor: pointer; cursor: pointer;
transition: background-color 0.2s; outline: none;
transition: all 0.2s;
} }
.save-button:hover { .select-wrapper select:focus {
background: #1565c0; border-color: #1976d2;
} }
</style> </style>

48
src/types/config.ts Normal file
View File

@@ -0,0 +1,48 @@
// 配置项类型枚举
export enum ConfigItemType {
TEXT = 'text',
SWITCH = 'switch',
SELECT = 'select'
}
// 配置项选项接口
export interface ConfigOption {
label: string
value: string | number | boolean
}
// 基础配置项接口
export interface BaseConfigItem {
type: ConfigItemType
key: string
label: string
value: any
description?: string // 配置项的详细说明
}
// 文本配置项
export interface TextConfigItem extends BaseConfigItem {
type: ConfigItemType.TEXT
value: string
placeholder?: string
}
// 开关配置项
export interface SwitchConfigItem extends BaseConfigItem {
type: ConfigItemType.SWITCH
value: boolean
}
// 选择配置项
export interface SelectConfigItem extends BaseConfigItem {
type: ConfigItemType.SELECT
value: string
options: ConfigOption[]
}
// 配置项组
export interface ConfigGroup {
title: string
enabled: boolean
items: (TextConfigItem | SwitchConfigItem | SelectConfigItem)[]
}

View File

@@ -23,8 +23,7 @@
] ]
}, },
"types": [ "types": [
"vue-router", "vue-router"
"mousetrap"
] ]
}, },
"include": [ "include": [