优化配置界面
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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
48
src/types/config.ts
Normal 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)[]
|
||||||
|
}
|
||||||
@@ -23,8 +23,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"types": [
|
"types": [
|
||||||
"vue-router",
|
"vue-router"
|
||||||
"mousetrap"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
|||||||
Reference in New Issue
Block a user