增加配置项保存的实现

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">
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 configGroups = ref<ConfigGroup[]>([
{
title: '外观设置',
enabled: 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 configManager = ConfigManager.getInstance(new LocalStorageConfigStore())
// 防抖函数
const debounce = (fn: Function, delay: number) => {
let timer: number | null = null
return (...args: any[]) => {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn(...args)
timer = null
}, delay)
}
])
}
// 处理文本配置项实时更新
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 config = configGroups.value.reduce((acc, group) => {
group.items.forEach(item => {
acc[item.key] = item.value
})
return acc
}, {} as Record<string, any>)
console.log('配置已更新:', config)
const handleConfigItemChange = (item: any, group: ConfigGroup) => {
configManager.updateConfig({
[`${group.key}.${item.key}`]: item.value
})
console.log('配置已更新:', configManager.getAllConfig())
}
// 处理配置组启用状态变更
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)
configManager.updateConfig({
[`${group.key}.enabled`]: group.enabled
})
console.log('配置已更新:', configManager.getAllConfig())
}
// 使用构造函数定义配置组
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>
<template>
@@ -129,7 +130,7 @@ const handleGroupEnableChange = (group: ConfigGroup) => {
type="text"
v-model="item.value"
:placeholder="(item as any).placeholder"
@change="handleConfigItemChange(item)"
@input="handleTextConfigChange(item, group)"
>
</div>
@@ -138,7 +139,7 @@ const handleGroupEnableChange = (group: ConfigGroup) => {
<input
type="checkbox"
v-model="item.value"
@change="handleConfigItemChange(item)"
@change="handleConfigItemChange(item, group)"
>
<span class="slider"></span>
</label>
@@ -147,7 +148,7 @@ const handleGroupEnableChange = (group: ConfigGroup) => {
<div v-else-if="item.type === ConfigItemType.SELECT" class="select-wrapper">
<select
v-model="item.value"
@change="handleConfigItemChange(item)"
@change="handleConfigItemChange(item, group)"
>
<option
v-for="option in (item as any).options"

View File

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