列表显隐
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<ElDrawer
|
||||
v-model="drawerVisible"
|
||||
title="列显隐"
|
||||
direction="rtl"
|
||||
size="560px"
|
||||
:z-index="3000"
|
||||
>
|
||||
<div class="column-config-drawer">
|
||||
<el-table
|
||||
:data="columnConfigList"
|
||||
border
|
||||
stripe
|
||||
max-height="calc(100vh - 200px)"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column prop="label" label="列名" width="200" fixed="left">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.label }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="隐藏" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox
|
||||
v-model="row.hide"
|
||||
@change="handleConfigChange"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="冻结" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox
|
||||
:model-value="row.fixed === 'left'"
|
||||
@change="(val) => { row.fixed = val ? 'left' : false; handleConfigChange() }"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="过滤" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox
|
||||
v-model="row.filterable"
|
||||
@change="handleConfigChange"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排序" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox
|
||||
:model-value="row.sortable === 'custom'"
|
||||
@change="(val) => { row.sortable = val ? 'custom' : false; handleConfigChange() }"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</ElDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { debounce } from 'lodash-es'
|
||||
|
||||
defineOptions({ name: 'ColumnConfigDialog' })
|
||||
|
||||
interface ColumnConfig {
|
||||
prop: string
|
||||
label: string
|
||||
hide: boolean
|
||||
fixed: string | boolean
|
||||
filterable: boolean
|
||||
sortable: string | boolean
|
||||
showColumn: boolean
|
||||
}
|
||||
|
||||
interface Props {
|
||||
modelValue: boolean
|
||||
columns: Record<string, any>
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: boolean]
|
||||
'confirm': [config: Record<string, any>]
|
||||
}>()
|
||||
|
||||
const drawerVisible = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (val) => emit('update:modelValue', val)
|
||||
})
|
||||
|
||||
const columnConfigList = ref<ColumnConfig[]>([])
|
||||
|
||||
const initColumnConfig = () => {
|
||||
if (!props.columns) return
|
||||
|
||||
columnConfigList.value = Object.keys(props.columns)
|
||||
.filter(key => {
|
||||
const column = props.columns[key]
|
||||
return column.showColumn !== false && column.prop
|
||||
})
|
||||
.map(key => {
|
||||
const column = props.columns[key]
|
||||
return {
|
||||
prop: column.prop || key,
|
||||
label: column.label || key,
|
||||
hide: column.hide || false,
|
||||
fixed: column.fixed || false,
|
||||
filterable: column.filterable || false,
|
||||
sortable: column.sortable || false,
|
||||
showColumn: column.showColumn !== false
|
||||
}
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const labelA = a.label || ''
|
||||
const labelB = b.label || ''
|
||||
return labelA.localeCompare(labelB, 'zh-CN')
|
||||
})
|
||||
}
|
||||
|
||||
// 防抖保存配置
|
||||
const saveConfig = debounce(() => {
|
||||
const config: Record<string, any> = {}
|
||||
|
||||
columnConfigList.value.forEach(item => {
|
||||
config[item.prop] = {
|
||||
hide: item.hide,
|
||||
fixed: item.fixed,
|
||||
filterable: item.filterable,
|
||||
sortable: item.sortable
|
||||
}
|
||||
})
|
||||
|
||||
emit('confirm', config)
|
||||
}, 300)
|
||||
|
||||
const handleConfigChange = () => {
|
||||
// 配置变化时直接触发保存(防抖处理)
|
||||
saveConfig()
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
if (val) {
|
||||
initColumnConfig()
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.columns,
|
||||
() => {
|
||||
if (props.modelValue) {
|
||||
initColumnConfig()
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.column-config-drawer {
|
||||
:deep(.el-table) {
|
||||
.el-table__header {
|
||||
th {
|
||||
background-color: var(--el-fill-color-light);
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
243
src/utils/indexedDB.ts
Normal file
243
src/utils/indexedDB.ts
Normal file
@@ -0,0 +1,243 @@
|
||||
/**
|
||||
* IndexedDB 工具类
|
||||
* 用于存储和读取表格列配置(显隐/冻结/过滤/排序)
|
||||
*/
|
||||
|
||||
const DB_NAME = 'lc_frontend_db'
|
||||
const DB_VERSION = 1
|
||||
const STORE_NAME = 'table_column_config'
|
||||
|
||||
let dbInstance: IDBDatabase | null = null
|
||||
|
||||
/**
|
||||
* 打开数据库并确保对象存储存在
|
||||
*/
|
||||
const openDBWithStore = (version: number): Promise<IDBDatabase> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open(DB_NAME, version)
|
||||
|
||||
request.onerror = () => {
|
||||
reject(request.error)
|
||||
}
|
||||
|
||||
request.onsuccess = () => {
|
||||
const db = request.result
|
||||
|
||||
// 检查对象存储是否存在
|
||||
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
||||
// 对象存储不存在,需要升级数据库
|
||||
db.close()
|
||||
|
||||
// 用更高版本打开以触发升级
|
||||
const upgradeRequest = indexedDB.open(DB_NAME, db.version + 1)
|
||||
|
||||
upgradeRequest.onerror = () => {
|
||||
reject(upgradeRequest.error)
|
||||
}
|
||||
|
||||
upgradeRequest.onupgradeneeded = (event) => {
|
||||
const upgradeDb = (event.target as IDBOpenDBRequest).result
|
||||
// 如果对象存储不存在,创建它
|
||||
if (!upgradeDb.objectStoreNames.contains(STORE_NAME)) {
|
||||
upgradeDb.createObjectStore(STORE_NAME, { keyPath: 'key' })
|
||||
}
|
||||
}
|
||||
|
||||
upgradeRequest.onsuccess = () => {
|
||||
resolve(upgradeRequest.result)
|
||||
}
|
||||
} else {
|
||||
resolve(db)
|
||||
}
|
||||
}
|
||||
|
||||
request.onupgradeneeded = (event) => {
|
||||
const db = (event.target as IDBOpenDBRequest).result
|
||||
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
||||
db.createObjectStore(STORE_NAME, { keyPath: 'key' })
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化 IndexedDB
|
||||
*/
|
||||
const initDB = (): Promise<IDBDatabase> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (dbInstance) {
|
||||
// 检查对象存储是否存在
|
||||
if (dbInstance.objectStoreNames.contains(STORE_NAME)) {
|
||||
resolve(dbInstance)
|
||||
return
|
||||
} else {
|
||||
// 对象存储不存在,需要重新初始化
|
||||
dbInstance.close()
|
||||
dbInstance = null
|
||||
}
|
||||
}
|
||||
|
||||
// 先尝试获取当前数据库版本(不指定版本号打开)
|
||||
const checkRequest = indexedDB.open(DB_NAME)
|
||||
|
||||
checkRequest.onsuccess = () => {
|
||||
const checkDb = checkRequest.result
|
||||
const currentVersion = checkDb.version
|
||||
checkDb.close()
|
||||
|
||||
// 使用当前版本或更高版本打开
|
||||
const targetVersion = Math.max(currentVersion, DB_VERSION)
|
||||
openDBWithStore(targetVersion)
|
||||
.then((db) => {
|
||||
dbInstance = db
|
||||
resolve(dbInstance)
|
||||
})
|
||||
.catch(reject)
|
||||
}
|
||||
|
||||
checkRequest.onerror = () => {
|
||||
// 如果检查失败,直接使用默认版本尝试打开
|
||||
openDBWithStore(DB_VERSION)
|
||||
.then((db) => {
|
||||
dbInstance = db
|
||||
resolve(dbInstance)
|
||||
})
|
||||
.catch(reject)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 列配置接口
|
||||
*/
|
||||
export interface ColumnConfig {
|
||||
hide?: boolean
|
||||
fixed?: string | boolean
|
||||
filterable?: boolean
|
||||
sortable?: string | boolean
|
||||
isShowColumn?: string // 'Y' 表示显示,'N' 表示隐藏
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存列配置
|
||||
* @param key 唯一标识(通常是 route.params.id)
|
||||
* @param config 列配置对象,格式:{ prop: { hide, fixed, filterable, sortable } }
|
||||
*/
|
||||
export const saveColumnConfig = async (key: string, config: Record<string, ColumnConfig>): Promise<void> => {
|
||||
try {
|
||||
const db = await initDB()
|
||||
const transaction = db.transaction([STORE_NAME], 'readwrite')
|
||||
const store = transaction.objectStore(STORE_NAME)
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const request = store.put({ key, config, updateTime: Date.now() })
|
||||
request.onsuccess = () => resolve()
|
||||
request.onerror = () => reject(request.error)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('保存列配置失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取列配置
|
||||
* @param key 唯一标识(通常是 route.params.id)
|
||||
* @returns 列配置对象,格式:{ prop: { hide, fixed, filterable, sortable } }
|
||||
*/
|
||||
export const getColumnConfig = async (key: string): Promise<Record<string, ColumnConfig> | null> => {
|
||||
try {
|
||||
const db = await initDB()
|
||||
const transaction = db.transaction([STORE_NAME], 'readonly')
|
||||
const store = transaction.objectStore(STORE_NAME)
|
||||
|
||||
return new Promise<Record<string, ColumnConfig> | null>((resolve, reject) => {
|
||||
const request = store.get(key)
|
||||
request.onsuccess = () => {
|
||||
const result = request.result
|
||||
resolve(result ? result.config : null)
|
||||
}
|
||||
request.onerror = () => reject(request.error)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('读取列配置失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除列配置
|
||||
* @param key 唯一标识(通常是 route.params.id)
|
||||
*/
|
||||
export const deleteColumnConfig = async (key: string): Promise<void> => {
|
||||
try {
|
||||
const db = await initDB()
|
||||
const transaction = db.transaction([STORE_NAME], 'readwrite')
|
||||
const store = transaction.objectStore(STORE_NAME)
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const request = store.delete(key)
|
||||
request.onsuccess = () => resolve()
|
||||
request.onerror = () => reject(request.error)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('删除列配置失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存搜索区域显示状态
|
||||
* @param key 唯一标识(通常是 route.params.id)
|
||||
* @param visible 是否显示
|
||||
*/
|
||||
export const saveSearchVisible = async (key: string, visible: boolean): Promise<void> => {
|
||||
try {
|
||||
const db = await initDB()
|
||||
const transaction = db.transaction([STORE_NAME], 'readwrite')
|
||||
const store = transaction.objectStore(STORE_NAME)
|
||||
|
||||
const data = await new Promise<any>((resolve, reject) => {
|
||||
const request = store.get(key)
|
||||
request.onsuccess = () => resolve(request.result)
|
||||
request.onerror = () => reject(request.error)
|
||||
})
|
||||
|
||||
const config = data?.config || {}
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const request = store.put({
|
||||
key,
|
||||
config,
|
||||
searchVisible: visible,
|
||||
updateTime: Date.now()
|
||||
})
|
||||
request.onsuccess = () => resolve()
|
||||
request.onerror = () => reject(request.error)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('保存搜索区域显示状态失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取搜索区域显示状态
|
||||
* @param key 唯一标识(通常是 route.params.id)
|
||||
* @returns 是否显示
|
||||
*/
|
||||
export const getSearchVisible = async (key: string): Promise<boolean | null> => {
|
||||
try {
|
||||
const db = await initDB()
|
||||
const transaction = db.transaction([STORE_NAME], 'readonly')
|
||||
const store = transaction.objectStore(STORE_NAME)
|
||||
|
||||
return new Promise<boolean | null>((resolve, reject) => {
|
||||
const request = store.get(key)
|
||||
request.onsuccess = () => {
|
||||
const result = request.result
|
||||
resolve(result && result.searchVisible !== undefined ? result.searchVisible : null)
|
||||
}
|
||||
request.onerror = () => reject(request.error)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('读取搜索区域显示状态失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user