列表显隐
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