增加配置项保存的实现
This commit is contained in:
@@ -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: '系统设置',
|
const handleTextConfigChange = debounce((item: TextConfigItem, group: ConfigGroup) => {
|
||||||
enabled: true,
|
configManager.updateConfig({
|
||||||
items: [
|
[`${group.key}.${item.key}`]: item.value
|
||||||
{
|
})
|
||||||
type: ConfigItemType.SELECT,
|
console.log('配置已更新:', configManager.getAllConfig())
|
||||||
key: 'language',
|
}, 300)
|
||||||
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 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"
|
||||||
|
|||||||
@@ -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
98
src/utils/ConfigStore.ts
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user