增加配置项保存的实现

This commit is contained in:
2024-12-13 09:36:12 +08:00
parent f8df3d2681
commit 57a669df71
3 changed files with 226 additions and 101 deletions

View File

@@ -1,92 +1,93 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref } from 'vue'
import { ConfigItemType, type ConfigGroup } from '@/types/config' import { ConfigGroup, TextConfigItem, SelectConfigItem, SwitchConfigItem, ConfigItemType } from '@/types/config'
import { ConfigManager, LocalStorageConfigStore } from '@/utils/ConfigStore'
// 定义配置组 const configManager = ConfigManager.getInstance(new LocalStorageConfigStore())
const configGroups = ref<ConfigGroup[]>([
{ // 防抖函数
title: '外观设置', const debounce = (fn: Function, delay: number) => {
enabled: true, let timer: number | null = null
items: [ return (...args: any[]) => {
{ if (timer) clearTimeout(timer)
type: ConfigItemType.TEXT, timer = setTimeout(() => {
key: 'projectName', fn(...args)
label: '项目名称', timer = null
value: '', }, delay)
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 handleTextConfigChange = debounce((item: TextConfigItem, group: ConfigGroup) => {
configManager.updateConfig({
[`${group.key}.${item.key}`]: item.value
})
console.log('配置已更新:', configManager.getAllConfig())
}, 300)
// 处理单个配置项更改 // 处理单个配置项更改
const handleConfigItemChange = (item: any) => { const handleConfigItemChange = (item: any, group: ConfigGroup) => {
const config = configGroups.value.reduce((acc, group) => { configManager.updateConfig({
group.items.forEach(item => { [`${group.key}.${item.key}`]: item.value
acc[item.key] = item.value
}) })
return acc console.log('配置已更新:', configManager.getAllConfig())
}, {} as Record<string, any>)
console.log('配置已更新:', config)
} }
// 处理配置组启用状态变更 // 处理配置组启用状态变更
const handleGroupEnableChange = (group: ConfigGroup) => { const handleGroupEnableChange = (group: ConfigGroup) => {
const config = configGroups.value.reduce((acc, group) => { configManager.updateConfig({
if (group.enabled) { [`${group.key}.enabled`]: group.enabled
group.items.forEach(item => {
acc[item.key] = item.value
}) })
console.log('配置已更新:', configManager.getAllConfig())
} }
return acc
}, {} as Record<string, any>)
console.log('配置已更新:', config) // 使用构造函数定义配置组
} const configGroups = ref([
new ConfigGroup('appearance', '外观设置', false, [
new TextConfigItem(
'projectName',
'项目名称',
'设置新建项目时的默认项目名称',
'',
'请输入默认项目名称'
),
new SelectConfigItem(
'theme',
'主题',
'切换应用的显示主题',
[
{ label: '浅色', value: 'light' },
{ label: '深色', value: 'dark' }
],
'light'
)
]),
new ConfigGroup('system', '系统设置', true, [
new SelectConfigItem(
'language',
'语言',
'设置应用界面显示的语言',
[
{ label: '中文', value: 'zh-CN' },
{ label: 'English', value: 'en-US' }
],
'zh-CN'
),
new SwitchConfigItem(
'autoSave',
'自动保存',
'开启后将自动保存您的修改',
true
),
new SwitchConfigItem(
'notifications',
'通知提醒',
'是否显示系统通知提醒',
true
)
])
])
</script> </script>
<template> <template>
@@ -129,7 +130,7 @@ const handleGroupEnableChange = (group: ConfigGroup) => {
type="text" type="text"
v-model="item.value" v-model="item.value"
:placeholder="(item as any).placeholder" :placeholder="(item as any).placeholder"
@change="handleConfigItemChange(item)" @input="handleTextConfigChange(item, group)"
> >
</div> </div>
@@ -138,7 +139,7 @@ const handleGroupEnableChange = (group: ConfigGroup) => {
<input <input
type="checkbox" type="checkbox"
v-model="item.value" v-model="item.value"
@change="handleConfigItemChange(item)" @change="handleConfigItemChange(item, group)"
> >
<span class="slider"></span> <span class="slider"></span>
</label> </label>
@@ -147,7 +148,7 @@ const handleGroupEnableChange = (group: ConfigGroup) => {
<div v-else-if="item.type === ConfigItemType.SELECT" class="select-wrapper"> <div v-else-if="item.type === ConfigItemType.SELECT" class="select-wrapper">
<select <select
v-model="item.value" v-model="item.value"
@change="handleConfigItemChange(item)" @change="handleConfigItemChange(item, group)"
> >
<option <option
v-for="option in (item as any).options" v-for="option in (item as any).options"

View File

@@ -5,44 +5,70 @@ export enum ConfigItemType {
SELECT = 'select' SELECT = 'select'
} }
// 配置项选项接口
export interface ConfigOption {
label: string
value: string | number | boolean
}
// 基础配置项接口 // 基础配置项接口
export interface BaseConfigItem { export interface BaseConfigItem {
type: ConfigItemType type: ConfigItemType
key: string key: string
label: string label: string
value: any value: any
description?: string // 配置项的详细说明 description: string
} }
// 文本配置项 // 文本配置项
export interface TextConfigItem extends BaseConfigItem { export class TextConfigItem implements BaseConfigItem {
type: ConfigItemType.TEXT readonly type = ConfigItemType.TEXT
value: string value: string
placeholder?: string
constructor(
public key: string,
public label: string,
public description: string,
defaultValue: string = '',
public placeholder?: string
) {
this.value = defaultValue
}
} }
// 开关配置项 // 开关配置项
export interface SwitchConfigItem extends BaseConfigItem { export class SwitchConfigItem implements BaseConfigItem {
type: ConfigItemType.SWITCH readonly type = ConfigItemType.SWITCH
value: boolean value: boolean
constructor(
public key: string,
public label: string,
public description: string,
defaultValue: boolean = false
) {
this.value = defaultValue
}
} }
// 选择配置项 // 选择配置项
export interface SelectConfigItem extends BaseConfigItem { export class SelectConfigItem implements BaseConfigItem {
type: ConfigItemType.SELECT readonly type = ConfigItemType.SELECT
value: string value: string
options: ConfigOption[]
constructor(
public key: string,
public label: string,
public description: string,
public options: Array<{ label: string; value: string }>,
defaultValue: string
) {
this.value = defaultValue
}
} }
// 配置项组 export type ConfigItem = TextConfigItem | SelectConfigItem | SwitchConfigItem
export interface ConfigGroup {
title: string // 配置组
enabled: boolean export class ConfigGroup {
items: (TextConfigItem | SwitchConfigItem | SelectConfigItem)[] constructor(
public key: string,
public title: string,
public enabled: boolean,
public items: ConfigItem[]
) {}
} }

98
src/utils/ConfigStore.ts Normal file
View File

@@ -0,0 +1,98 @@
// 配置存储接口
export interface ConfigStore {
get<T>(key: string): T | undefined
set<T>(key: string, value: T): void
getAll(): Record<string, any>
clear(): void
}
// 内存存储实现
export class MemoryConfigStore implements ConfigStore {
private store: Record<string, any> = {}
get<T>(key: string): T | undefined {
return this.store[key] as T
}
set<T>(key: string, value: T): void {
this.store[key] = value
}
getAll(): Record<string, any> {
return { ...this.store }
}
clear(): void {
this.store = {}
}
}
// LocalStorage存储实现
export class LocalStorageConfigStore implements ConfigStore {
private readonly prefix = 'app_config.'
private getKey(key: string): string {
return this.prefix + key
}
get<T>(key: string): T | undefined {
const value = localStorage.getItem(this.getKey(key))
return value ? JSON.parse(value) : undefined
}
set<T>(key: string, value: T): void {
localStorage.setItem(this.getKey(key), JSON.stringify(value))
}
getAll(): Record<string, any> {
const result: Record<string, any> = {}
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i)
if (key?.startsWith(this.prefix)) {
const realKey = key.slice(this.prefix.length)
result[realKey] = JSON.parse(localStorage.getItem(key) || '{}')
}
}
return result
}
clear(): void {
for (let i = localStorage.length - 1; i >= 0; i--) {
const key = localStorage.key(i)
if (key?.startsWith(this.prefix)) {
localStorage.removeItem(key)
}
}
}
}
// 配置管理器
export class ConfigManager {
private static instance: ConfigManager
private store: ConfigStore
private constructor(store: ConfigStore) {
this.store = store
}
static getInstance(store: ConfigStore = new MemoryConfigStore()): ConfigManager {
if (!ConfigManager.instance) {
ConfigManager.instance = new ConfigManager(store)
}
return ConfigManager.instance
}
updateConfig(config: Record<string, any>): void {
Object.entries(config).forEach(([key, value]) => {
this.store.set(key, value)
})
}
getConfig<T>(key: string): T | undefined {
return this.store.get<T>(key)
}
getAllConfig(): Record<string, any> {
return this.store.getAll()
}
}