列表显隐
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>
|
||||
@@ -1,152 +1,73 @@
|
||||
<template>
|
||||
<div
|
||||
class="low-table relative"
|
||||
:class="[
|
||||
<div class="low-table relative" :class="[
|
||||
`low-table__${tableId}`,
|
||||
{
|
||||
summary: tableOption.showSummary,
|
||||
'low-table-grid': tableOption.grid,
|
||||
'no-menu': !tableOption.menu
|
||||
}
|
||||
]"
|
||||
>
|
||||
]">
|
||||
<span prop="delegateUserId" style="display:none">
|
||||
|
||||
<userSelect
|
||||
id="costomUserSelect"
|
||||
v-model="formData"
|
||||
v-bind="userVBind"
|
||||
class="w-100%"
|
||||
></userSelect>
|
||||
<userSelect id="costomUserSelect" v-model="formData" v-bind="userVBind" class="w-100%"></userSelect>
|
||||
</span>
|
||||
<span prop="delegateDictId" style="display:none">
|
||||
|
||||
<DicTableSelect
|
||||
id="costomDictSelect"
|
||||
:column="distSelectColumn"
|
||||
size="default"
|
||||
type="add"
|
||||
prop="fields_7897245"
|
||||
:scope="dictSelectScope"
|
||||
@set-form-data="handleSetFormData"
|
||||
></DicTableSelect>
|
||||
<DicTableSelect id="costomDictSelect" :column="distSelectColumn" size="default" type="add" prop="fields_7897245"
|
||||
:scope="dictSelectScope" @set-form-data="handleSetFormData"></DicTableSelect>
|
||||
</span>
|
||||
<!-- 顶部统计 -->
|
||||
<div
|
||||
v-if="summaryTop.show"
|
||||
class="low-table-summary absolute left-0 top-0 w-100% h-auto z-999"
|
||||
v-hasResize="onSummaryTopResize"
|
||||
>
|
||||
<SummaryTop
|
||||
ref="summaryTopRef"
|
||||
v-if="tableSummary.topList?.length"
|
||||
:summaryList="tableSummary.topList"
|
||||
></SummaryTop>
|
||||
<div v-if="summaryTop.show" class="low-table-summary absolute left-0 top-0 w-100% h-auto z-999"
|
||||
v-hasResize="onSummaryTopResize">
|
||||
<SummaryTop ref="summaryTopRef" v-if="tableSummary.topList?.length" :summaryList="tableSummary.topList">
|
||||
</SummaryTop>
|
||||
</div>
|
||||
<div
|
||||
class="low-table-content gap-x-10px w-100%"
|
||||
:class="{
|
||||
<div class="low-table-content gap-x-10px w-100%" :class="{
|
||||
show_fixed_bar: isShowFixedBar,
|
||||
[`low-table-grid__${tableInfo.singleCardSpan}`]: tableOption.grid
|
||||
}"
|
||||
:style="{ paddingTop: summaryTop.height + 'px' }"
|
||||
>
|
||||
}" :style="{ paddingTop: summaryTop.height + 'px' }">
|
||||
<!-- 左树右表(树表) -->
|
||||
<div
|
||||
class="left-tree-box flex-basis-200px flex-shrink-0"
|
||||
v-if="tableInfo.tableType == 'treeAround'"
|
||||
>
|
||||
<avue-tree
|
||||
ref="treeRef"
|
||||
:option="treeAroundOption"
|
||||
:data="treeAroundData"
|
||||
@node-click="treeAroundNodeClick"
|
||||
>
|
||||
<div class="left-tree-box flex-basis-200px flex-shrink-0" v-if="tableInfo.tableType == 'treeAround'">
|
||||
<avue-tree ref="treeRef" :option="treeAroundOption" :data="treeAroundData" @node-click="treeAroundNodeClick">
|
||||
<template #default="{ data }">
|
||||
<span
|
||||
class="el-tree-node__label"
|
||||
:class="{
|
||||
<span class="el-tree-node__label" :class="{
|
||||
active:
|
||||
data[treeAroundOption.props.value] == treeAroundRow[treeAroundOption.props.value]
|
||||
}"
|
||||
>
|
||||
}">
|
||||
{{ data[treeAroundOption.props.label] }}
|
||||
</span>
|
||||
</template>
|
||||
</avue-tree>
|
||||
</div>
|
||||
<div
|
||||
class="flex-1 w-100%"
|
||||
:class="{ 'table-content': tableInfo.tableType == 'treeAround' }"
|
||||
v-if="isInit"
|
||||
>
|
||||
<!-- 列配置抽屉 -->
|
||||
<ColumnConfigDialog v-if="props.model === 'default'" v-model="showColumnConfigDrawer"
|
||||
:columns="tableOption.column" @confirm="handleColumnConfigConfirm" />
|
||||
<div class="flex-1 w-100%" :class="{ 'table-content': tableInfo.tableType == 'treeAround' }" v-if="isInit">
|
||||
<!-- 主体表格 -->
|
||||
<avue-crud
|
||||
ref="crudRef"
|
||||
v-model="tableForm"
|
||||
v-model:search="tableSearch"
|
||||
v-bind="crudBind"
|
||||
:table-loading="loading"
|
||||
:data="tableData"
|
||||
:option="tableOption"
|
||||
:before-open="beforeOpen"
|
||||
:before-close="beforeClose"
|
||||
:row-style="tableDefaultFun.rowStyle"
|
||||
:cell-style="tableDefaultFun.cellStyle"
|
||||
:summary-method="tableDefaultFun.summaryMethod"
|
||||
:span-method="tableDefaultFun.spanMethod"
|
||||
@search-change="searchChange"
|
||||
@search-reset="resetChange"
|
||||
@row-save="rowSave"
|
||||
@row-update="rowUpdate"
|
||||
@row-del="rowDel"
|
||||
@refresh-change="refreshChange"
|
||||
@size-change="sizeChange"
|
||||
@current-change="currentChange"
|
||||
@selection-change="selectionChange"
|
||||
@sort-change="sortChange"
|
||||
@select-all="selectAll"
|
||||
@row-click="tableDefaultFun.rowClick"
|
||||
@row-dblclick="tableDefaultFun.rowDblclick"
|
||||
@cell-click="tableDefaultFun.cellClick"
|
||||
@cell-dblclick="tableDefaultFun.cellDblclick"
|
||||
@tree-load="treeLoad"
|
||||
@expand-change="expandChanges"
|
||||
:upload-before="uploadBefore"
|
||||
:upload-exceed="uploadExceed"
|
||||
:upload-sized="uploadSized"
|
||||
:upload-preview="uploadPreview"
|
||||
>
|
||||
<avue-crud ref="crudRef" v-model="tableForm" v-model:search="tableSearch" v-bind="crudBind"
|
||||
:table-loading="loading" :data="tableData" :option="tableOption" :before-open="beforeOpen"
|
||||
:before-close="beforeClose" :row-style="tableDefaultFun.rowStyle" :cell-style="tableDefaultFun.cellStyle"
|
||||
:summary-method="tableDefaultFun.summaryMethod" :span-method="tableDefaultFun.spanMethod"
|
||||
@search-change="searchChange" @search-reset="resetChange" @row-save="rowSave" @row-update="rowUpdate"
|
||||
@row-del="rowDel" @refresh-change="refreshChange" @size-change="sizeChange" @current-change="currentChange"
|
||||
@selection-change="selectionChange" @sort-change="sortChange" @select-all="selectAll"
|
||||
@row-click="tableDefaultFun.rowClick" @row-dblclick="tableDefaultFun.rowDblclick"
|
||||
@cell-click="tableDefaultFun.cellClick" @cell-dblclick="tableDefaultFun.cellDblclick" @tree-load="treeLoad"
|
||||
@expand-change="expandChanges" :upload-before="uploadBefore" :upload-exceed="uploadExceed"
|
||||
:upload-sized="uploadSized" :upload-preview="uploadPreview">
|
||||
<!-- 自定义表格头部操作 -->
|
||||
<template #menu-left="{ size }">
|
||||
<TableButton
|
||||
v-show="menuLeftShow"
|
||||
type="header"
|
||||
:size="size"
|
||||
:buttonObj="buttonObj"
|
||||
:selectLength="tableSelect.length"
|
||||
@menu-left-handle="menuLeftHandle"
|
||||
></TableButton>
|
||||
<TableButton v-show="menuLeftShow" type="header" :size="size" :buttonObj="buttonObj"
|
||||
:selectLength="tableSelect.length" @menu-left-handle="menuLeftHandle"></TableButton>
|
||||
</template>
|
||||
<!-- 自定义操作列 -->
|
||||
<template #menu="{ size, row, index }">
|
||||
<TableButton
|
||||
:type="tableInfo.menuStyle == 'more' ? 'more' : 'menu'"
|
||||
:max-num="tableInfo.maxMenuNum"
|
||||
:size="size"
|
||||
:buttonObj="buttonObj"
|
||||
:row="row"
|
||||
:index="index"
|
||||
@menu-handle="menuHandle"
|
||||
></TableButton>
|
||||
<TableButton :type="tableInfo.menuStyle == 'more' ? 'more' : 'menu'" :max-num="tableInfo.maxMenuNum"
|
||||
:size="size" :buttonObj="buttonObj" :row="row" :index="index" @menu-handle="menuHandle"></TableButton>
|
||||
</template>
|
||||
<!-- 自定义多选提示 -->
|
||||
<template #tip>
|
||||
<span
|
||||
class="inline-block pl-10px c-#999"
|
||||
v-if="model == 'dicTable' && dicMaxLimit"
|
||||
type="danger"
|
||||
>
|
||||
<span class="inline-block pl-10px c-#999" v-if="model == 'dicTable' && dicMaxLimit" type="danger">
|
||||
{{ t('Avue.crud.selectMaxPrepend') }}
|
||||
{{ dicMaxLimit }}
|
||||
{{ t('Avue.crud.selectMaxAppend') }}
|
||||
@@ -154,42 +75,22 @@
|
||||
</template>
|
||||
<!-- 单选 -->
|
||||
<template #lowSelectRadio="{ row, index }">
|
||||
<el-radio
|
||||
class="low-select-radio"
|
||||
v-model="radioValue"
|
||||
:label="row[tableOption.rowKey || 'id']"
|
||||
:disabled="!tableOption.selectable(row, index)"
|
||||
@click.stop="radioClick(row, index)"
|
||||
/>
|
||||
<el-radio class="low-select-radio" v-model="radioValue" :label="row[tableOption.rowKey || 'id']"
|
||||
:disabled="!tableOption.selectable(row, index)" @click.stop="radioClick(row, index)" />
|
||||
</template>
|
||||
<!-- 自定义表头 -->
|
||||
<template v-for="prop in inlineSearch" :key="prop" #[`${prop}-header`]="{ column }">
|
||||
<InlineSearch
|
||||
v-model="tableSearch[prop]"
|
||||
:prop="prop"
|
||||
:column="column"
|
||||
:crudRef="crudRef"
|
||||
@execute-search="searchChange"
|
||||
></InlineSearch>
|
||||
<InlineSearch v-model="tableSearch[prop]" :prop="prop" :column="column" :crudRef="crudRef"
|
||||
@execute-search="searchChange"></InlineSearch>
|
||||
</template>
|
||||
<!-- 自定义表单 -->
|
||||
<template v-for="c in slotData.form" :key="c.prop" #[`${c.prop}-form`]="scope">
|
||||
<!-- <div>{{scope}}</div> -->
|
||||
<AvueSlot
|
||||
slotType="form"
|
||||
:scope="scope"
|
||||
:control="c"
|
||||
v-model="tableForm[c.prop]"
|
||||
></AvueSlot>
|
||||
<AvueSlot slotType="form" :scope="scope" :control="c" v-model="tableForm[c.prop]"></AvueSlot>
|
||||
</template>
|
||||
<!-- 自定义搜索 -->
|
||||
<template v-for="c in slotData.search" :key="c.prop" #[`${c.prop}-search`]="scope">
|
||||
<AvueSlot
|
||||
slotType="search"
|
||||
:scope="scope"
|
||||
:control="c"
|
||||
v-model="tableSearch[c.prop]"
|
||||
></AvueSlot>
|
||||
<AvueSlot slotType="search" :scope="scope" :control="c" v-model="tableSearch[c.prop]"></AvueSlot>
|
||||
</template>
|
||||
<!-- 自定义列 -->
|
||||
<template v-for="c in slotData.list" :key="c.prop" #[c.prop]="scope">
|
||||
@@ -197,36 +98,18 @@
|
||||
</template>
|
||||
<!-- 自定义附表表单 -->
|
||||
<template #lowCustomSubTable-form="{ type, disabled, column }">
|
||||
<avue-tabs
|
||||
ref="subTabsRef"
|
||||
:option="column.tabsOption"
|
||||
@change="(tab) => (subTabsValue = tab)"
|
||||
></avue-tabs>
|
||||
<avue-tabs ref="subTabsRef" :option="column.tabsOption" @change="(tab) => (subTabsValue = tab)"></avue-tabs>
|
||||
<template v-for="sub in column.tabsOption.column" :key="sub.prop">
|
||||
<template v-if="sub.subType == 'many'">
|
||||
<SubTable
|
||||
:ref="(el) => (subTableRef[sub.prop] = el)"
|
||||
v-model="tableForm[sub.prop]"
|
||||
v-show="sub.prop == subTabsValue.prop"
|
||||
:prop="sub.prop"
|
||||
:tableId="sub.tableId"
|
||||
:optionData="subTableObj[sub.tableId]"
|
||||
:type="type"
|
||||
:disabled="disabled"
|
||||
@execute-custom-btn-enhance="executeCustomBtnEnhance"
|
||||
></SubTable>
|
||||
<SubTable :ref="(el) => (subTableRef[sub.prop] = el)" v-model="tableForm[sub.prop]"
|
||||
v-show="sub.prop == subTabsValue.prop" :prop="sub.prop" :tableId="sub.tableId"
|
||||
:optionData="subTableObj[sub.tableId]" :type="type" :disabled="disabled"
|
||||
@execute-custom-btn-enhance="executeCustomBtnEnhance"></SubTable>
|
||||
</template>
|
||||
<template v-if="sub.subType == 'one'">
|
||||
<SubForm
|
||||
:ref="(el) => (subFormRef[sub.prop] = el)"
|
||||
v-model="tableForm[sub.prop]"
|
||||
v-show="sub.prop == subTabsValue.prop"
|
||||
:prop="sub.prop"
|
||||
:tableId="sub.tableId"
|
||||
:optionData="subTableObj[sub.tableId]"
|
||||
:type="type"
|
||||
:disabled="disabled"
|
||||
></SubForm>
|
||||
<SubForm :ref="(el) => (subFormRef[sub.prop] = el)" v-model="tableForm[sub.prop]"
|
||||
v-show="sub.prop == subTabsValue.prop" :prop="sub.prop" :tableId="sub.tableId"
|
||||
:optionData="subTableObj[sub.tableId]" :type="type" :disabled="disabled"></SubForm>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
@@ -234,18 +117,11 @@
|
||||
<!-- 主附表内嵌 -->
|
||||
<template v-if="tableInfo.subTemplate == 'innerTable'">
|
||||
<div class="p-20px pt-0 pb-10px" v-if="tableOption.expandRowKeys.includes(row.id)">
|
||||
<avue-tabs
|
||||
:option="innerTabsOption"
|
||||
@change="(tab) => (innerTabsValue = tab)"
|
||||
></avue-tabs>
|
||||
<avue-tabs :option="innerTabsOption" @change="(tab) => (innerTabsValue = tab)"></avue-tabs>
|
||||
<template v-for="sub in innerTabsOption.column" :key="sub.prop">
|
||||
<div class="w-100%" v-show="sub.prop == innerTabsValue.prop">
|
||||
<LowTable
|
||||
:ref="(el) => (innerTableRef[sub.prop] = el)"
|
||||
:tableId="sub.tableId"
|
||||
v-bind="sub.vBind"
|
||||
:fixedSearch="{ ...(innerSubSearch[row.id]?.[sub.prop] || {}) }"
|
||||
></LowTable>
|
||||
<LowTable :ref="(el) => (innerTableRef[sub.prop] = el)" :tableId="sub.tableId" v-bind="sub.vBind"
|
||||
:fixedSearch="{ ...(innerSubSearch[row.id]?.[sub.prop] || {}) }"></LowTable>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -254,11 +130,7 @@
|
||||
<template v-if="tableInfo.singleStyle == 'expand'">
|
||||
<div class="expand-table-box px-20px py-10px">
|
||||
<el-row>
|
||||
<el-form-item
|
||||
v-for="prop in expandProp"
|
||||
:key="prop"
|
||||
:label="tableOption.column[prop].label + ':'"
|
||||
>
|
||||
<el-form-item v-for="prop in expandProp" :key="prop" :label="tableOption.column[prop].label + ':'">
|
||||
{{ row[`$${prop}`] || row[prop] }}
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
@@ -271,11 +143,8 @@
|
||||
<avue-tabs :option="erpTabsOption" @change="(tab) => (subTabsValue = tab)"></avue-tabs>
|
||||
<template v-for="sub in erpTabsOption.column" :key="sub.prop">
|
||||
<div class="w-100%" v-show="sub.prop == subTabsValue.prop">
|
||||
<LowTable
|
||||
:ref="(el) => (erpTableRef[sub.prop] = el)"
|
||||
:tableId="sub.tableId"
|
||||
v-bind="sub.vBind"
|
||||
></LowTable>
|
||||
<LowTable :ref="(el) => (erpTableRef[sub.prop] = el)" :tableId="sub.tableId" v-bind="sub.vBind">
|
||||
</LowTable>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -284,67 +153,32 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 代码编辑器 -->
|
||||
<DesignPopup
|
||||
v-if="popShowObj.mEditor"
|
||||
v-model="MEDialog.value"
|
||||
v-bind="MEDialog.params"
|
||||
:isBodyFull="true"
|
||||
>
|
||||
<DesignPopup v-if="popShowObj.mEditor" v-model="MEDialog.value" v-bind="MEDialog.params" :isBodyFull="true">
|
||||
<template #default>
|
||||
<MonacoEditor v-model="MEData.value" v-bind="MEData.params"></MonacoEditor>
|
||||
</template>
|
||||
</DesignPopup>
|
||||
<!-- 导入 -->
|
||||
<DesignPopup
|
||||
v-if="popShowObj.import"
|
||||
v-model="importDialog"
|
||||
:title="t('Avue.crud.importTitle')"
|
||||
width="80%"
|
||||
:dialog-params="{ alignCenter: true }"
|
||||
:handleClose="importRef?.handleClose"
|
||||
>
|
||||
<DesignPopup v-if="popShowObj.import" v-model="importDialog" :title="t('Avue.crud.importTitle')" width="80%"
|
||||
:dialog-params="{ alignCenter: true }" :handleClose="importRef?.handleClose">
|
||||
<template #default="{ isFull }">
|
||||
<ImportData
|
||||
ref="importRef"
|
||||
:importId="tableId"
|
||||
:columns="tableOption.column"
|
||||
:tableDescribe="tableInfo.tableDescribe"
|
||||
:show="importDialog"
|
||||
:isFull="isFull"
|
||||
@close-popup="importDialog = false"
|
||||
@reset-change="resetData"
|
||||
></ImportData>
|
||||
<ImportData ref="importRef" :importId="tableId" :columns="tableOption.column"
|
||||
:tableDescribe="tableInfo.tableDescribe" :show="importDialog" :isFull="isFull"
|
||||
@close-popup="importDialog = false" @reset-change="resetData"></ImportData>
|
||||
</template>
|
||||
</DesignPopup>
|
||||
<!-- 自定义表单 -->
|
||||
<DesignPopup
|
||||
v-if="popShowObj.form"
|
||||
v-model="customForm.open"
|
||||
:controlType="tableOption.dialogType || 'dialog'"
|
||||
:title="tableOption[`${customForm.formType}Title`] || customForm.title"
|
||||
:width="tableOption.dialogWidth || '60%'"
|
||||
:footer-btn="customForm.footerBtn"
|
||||
:fullscreen = "true"
|
||||
>
|
||||
<LowForm
|
||||
v-if="customForm.open"
|
||||
ref="customFormRef"
|
||||
:formType="customForm.formType"
|
||||
:formOption="customForm.formOption"
|
||||
:defaultData="customForm.defaultData"
|
||||
:formId="tableInfo.formId"
|
||||
handleType="returnData"
|
||||
:beforeClose="customFormClose"
|
||||
></LowForm>
|
||||
<DesignPopup v-if="popShowObj.form" v-model="customForm.open" :controlType="tableOption.dialogType || 'dialog'"
|
||||
:title="tableOption[`${customForm.formType}Title`] || customForm.title" :width="tableOption.dialogWidth || '60%'"
|
||||
:footer-btn="customForm.footerBtn" :fullscreen="true">
|
||||
<LowForm v-if="customForm.open" ref="customFormRef" :formType="customForm.formType"
|
||||
:formOption="customForm.formOption" :defaultData="customForm.defaultData" :formId="tableInfo.formId"
|
||||
handleType="returnData" :beforeClose="customFormClose"></LowForm>
|
||||
</DesignPopup>
|
||||
<!-- 增强注册的控件 -->
|
||||
<template v-for="item in rendControlData" :key="item.key">
|
||||
<component
|
||||
:ref="(el) => (componentRef[item.key] = el)"
|
||||
:is="componentObj[item.random]"
|
||||
v-bind="item.params || {}"
|
||||
v-model="item.show"
|
||||
></component>
|
||||
<component :ref="(el) => (componentRef[item.key] = el)" :is="componentObj[item.random]" v-bind="item.params || {}"
|
||||
v-model="item.show"></component>
|
||||
</template>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
@@ -377,6 +211,8 @@ import * as Vue from 'vue'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { Value } from 'sass'
|
||||
import { object } from 'vue-types'
|
||||
import ColumnConfigDialog from './components/ColumnConfigDialog.vue'
|
||||
import { saveColumnConfig, getColumnConfig, type ColumnConfig } from '@/utils/indexedDB'
|
||||
defineOptions({ name: 'LowTable' })
|
||||
|
||||
let funcInteface = (value1, value2) => { }
|
||||
@@ -642,6 +478,10 @@ const crudRef = ref()
|
||||
const componentRef = ref({})
|
||||
const summaryTopRef = ref()
|
||||
|
||||
// 列配置相关
|
||||
const showColumnConfigDrawer = ref(false)
|
||||
const fieldListRef = ref<any[]>([]) // 保存 fieldList 的引用,用于修改 webEntity.isShowColumn
|
||||
|
||||
const { uploadBefore, uploadExceed, uploadSized, uploadPreview } = useAvueUpload(jsEnhanceObj)
|
||||
|
||||
const isShowFixedBar = computed(() => {
|
||||
@@ -732,7 +572,7 @@ const fixed_bar_left = computed(() => {
|
||||
const initTable = async () => {
|
||||
isInit.value = false
|
||||
loading.value = true
|
||||
let data = {}
|
||||
let data: any = {}
|
||||
if (props.model == 'default') {
|
||||
data = await TableApi.getWebConfig(props.tableId)
|
||||
} else if (props.model == 'erpTable' || props.model == 'innerTable') {
|
||||
@@ -740,6 +580,15 @@ const initTable = async () => {
|
||||
} else if (isDicTable.value) {
|
||||
data = await getDicTableConfig(props.tableId, props.dicConfigStr)
|
||||
}
|
||||
|
||||
// 保存 fieldList 的引用,用于列配置时修改 webEntity.isShowColumn
|
||||
if (props.model === 'default' && data.fieldList) {
|
||||
fieldListRef.value = data.fieldList
|
||||
|
||||
// 在初始化 tableOption 之前,先从 IndexedDB 加载列配置并应用到 fieldList
|
||||
await loadColumnConfigToFieldList()
|
||||
}
|
||||
|
||||
const optionData = initTableOption(data, {
|
||||
tableId: props.tableId,
|
||||
calcHeight: props.calcHeight,
|
||||
@@ -855,10 +704,24 @@ const initTable = async () => {
|
||||
initInlineSearch()
|
||||
initExpandTable()
|
||||
isInit.value = true
|
||||
|
||||
// 从 IndexedDB 加载列配置并应用到 crudRef(此时 tableOption 已初始化,需要同步到 crudRef)
|
||||
if (props.model === 'default') {
|
||||
await loadColumnConfigToCrudRef()
|
||||
}
|
||||
|
||||
if (optionData.tableInfo.isGetData || isDicTable.value) {
|
||||
getTableData(true, { type: 'init', isGetSummary: true })
|
||||
} else loading.value = false
|
||||
initTableLayout()
|
||||
|
||||
// 初始化完成后,尝试替换列显隐按钮
|
||||
if (props.model === 'default') {
|
||||
await nextTick()
|
||||
setTimeout(() => {
|
||||
replaceColumnButton()
|
||||
}, 300)
|
||||
}
|
||||
if (optionData.tableInfo.subTable?.length) {
|
||||
optionData.tableInfo.subTable.forEach(
|
||||
(id, index) => (subTableObj.value[id] = { tableId: id, index })
|
||||
@@ -1532,6 +1395,271 @@ const refreshChange = () => {
|
||||
getTableData(true, { isGetSummary: true })
|
||||
}
|
||||
|
||||
// 替换列显隐按钮
|
||||
let buttonReplaced = false
|
||||
let observerInstance: MutationObserver | null = null
|
||||
|
||||
const replaceColumnButton = () => {
|
||||
if (buttonReplaced || props.model !== 'default') return
|
||||
|
||||
const tryReplace = () => {
|
||||
const originalButton = document.querySelector('.avue-crud__columnBtn:not([data-custom-replaced])')
|
||||
if (originalButton && !buttonReplaced) {
|
||||
buttonReplaced = true
|
||||
|
||||
// 创建新按钮
|
||||
const newButton = originalButton.cloneNode(true) as HTMLElement
|
||||
newButton.setAttribute('data-custom-replaced', 'true')
|
||||
|
||||
// 清除原按钮的所有事件监听器
|
||||
const newButtonClone = newButton.cloneNode(true) as HTMLElement
|
||||
newButtonClone.setAttribute('data-custom-replaced', 'true')
|
||||
|
||||
// 添加新的事件监听器
|
||||
newButtonClone.addEventListener('click', (e) => {
|
||||
debugger
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
showColumnConfigDrawer.value = true
|
||||
})
|
||||
|
||||
// 替换原按钮
|
||||
if (originalButton.parentNode) {
|
||||
originalButton.parentNode.replaceChild(newButtonClone, originalButton)
|
||||
}
|
||||
|
||||
// 停止观察
|
||||
if (observerInstance) {
|
||||
observerInstance.disconnect()
|
||||
observerInstance = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 立即尝试一次
|
||||
tryReplace()
|
||||
|
||||
// 如果还没替换成功,使用观察者
|
||||
if (!buttonReplaced) {
|
||||
observerInstance = new MutationObserver(() => {
|
||||
if (!buttonReplaced) {
|
||||
tryReplace()
|
||||
}
|
||||
})
|
||||
|
||||
// 只观察 crudRef 所在的区域,避免观察整个 body
|
||||
const crudElement = crudRef.value?.$el
|
||||
if (crudElement) {
|
||||
observerInstance.observe(crudElement, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
})
|
||||
} else {
|
||||
// 如果 crudRef 还没准备好,观察 body 但限制范围
|
||||
observerInstance.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
})
|
||||
}
|
||||
|
||||
// 设置超时,避免无限观察
|
||||
setTimeout(() => {
|
||||
if (observerInstance) {
|
||||
observerInstance.disconnect()
|
||||
observerInstance = null
|
||||
}
|
||||
}, 10000) // 10秒后停止观察
|
||||
}
|
||||
}
|
||||
|
||||
// 列配置确认处理
|
||||
const handleColumnConfigConfirm = async (config: Record<string, ColumnConfig>) => {
|
||||
if (props.model !== 'default') return
|
||||
|
||||
// 修改 fieldList 中的 webEntity.isShowColumn
|
||||
if (fieldListRef.value && fieldListRef.value.length > 0) {
|
||||
fieldListRef.value.forEach((field: any) => {
|
||||
if (field.webEntity && field.fieldCode && config[field.fieldCode] !== undefined) {
|
||||
const colConfig = config[field.fieldCode]
|
||||
// hide === true 表示 checkbox 选中,对应 isShowColumn = 'N'
|
||||
// hide === false 表示 checkbox 不选中,对应 isShowColumn = 'Y'
|
||||
if (colConfig.hide !== undefined) {
|
||||
field.webEntity.isShowColumn = colConfig.hide ? 'N' : 'Y'
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 应用列配置到 tableOption
|
||||
Object.keys(config).forEach(prop => {
|
||||
if (tableOption.value.column[prop]) {
|
||||
const colConfig = config[prop]
|
||||
if (colConfig.hide !== undefined) {
|
||||
tableOption.value.column[prop].hide = colConfig.hide
|
||||
}
|
||||
if (colConfig.fixed !== undefined) {
|
||||
tableOption.value.column[prop].fixed = colConfig.fixed
|
||||
}
|
||||
if (colConfig.filterable !== undefined) {
|
||||
tableOption.value.column[prop].filterable = colConfig.filterable
|
||||
}
|
||||
if (colConfig.sortable !== undefined) {
|
||||
tableOption.value.column[prop].sortable = colConfig.sortable
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 同步到 crudRef
|
||||
await nextTick()
|
||||
if (crudRef.value && crudRef.value.columnOption) {
|
||||
crudRef.value.columnOption.forEach((column: any) => {
|
||||
if (config[column.prop]) {
|
||||
const colConfig = config[column.prop]
|
||||
if (colConfig.hide !== undefined) {
|
||||
column.hide = colConfig.hide
|
||||
}
|
||||
if (colConfig.fixed !== undefined) {
|
||||
column.fixed = colConfig.fixed
|
||||
}
|
||||
if (colConfig.filterable !== undefined) {
|
||||
column.filterable = colConfig.filterable
|
||||
}
|
||||
if (colConfig.sortable !== undefined) {
|
||||
column.sortable = colConfig.sortable
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 强制更新表格布局
|
||||
if (crudRef.value.$refs && crudRef.value.$refs.table) {
|
||||
crudRef.value.$refs.table.doLayout()
|
||||
}
|
||||
}
|
||||
|
||||
// 保存到 IndexedDB(保存 isShowColumn 的值)
|
||||
const pageId = (route.params.id as string) || props.tableId
|
||||
const saveConfig: Record<string, ColumnConfig> = {}
|
||||
Object.keys(config).forEach(prop => {
|
||||
saveConfig[prop] = {
|
||||
...config[prop],
|
||||
isShowColumn: config[prop].hide ? 'N' : 'Y' // hide=true checkbox选中→'N',hide=false checkbox不选中→'Y'
|
||||
}
|
||||
})
|
||||
await saveColumnConfig(pageId, saveConfig)
|
||||
}
|
||||
|
||||
// 从 IndexedDB 加载列配置并应用到 fieldList(在 initTableOption 之前调用)
|
||||
const loadColumnConfigToFieldList = async () => {
|
||||
if (props.model !== 'default' || !fieldListRef.value || fieldListRef.value.length === 0) return
|
||||
|
||||
try {
|
||||
const pageId = (route.params.id as string) || props.tableId
|
||||
const savedConfig = await getColumnConfig(pageId)
|
||||
debugger
|
||||
|
||||
if (savedConfig) {
|
||||
// 修改 fieldList 中的 webEntity.isShowColumn
|
||||
fieldListRef.value.forEach((field: any) => {
|
||||
debugger
|
||||
if (field.webEntity && field.fieldCode && savedConfig[field.fieldCode] !== undefined) {
|
||||
const colConfig = savedConfig[field.fieldCode]
|
||||
// 优先使用 isShowColumn,如果没有则使用 hide 转换
|
||||
if (colConfig.isShowColumn !== undefined) {
|
||||
field.webEntity.isShowColumn = colConfig.isShowColumn
|
||||
} else if (colConfig.hide !== undefined) {
|
||||
// hide=true checkbox选中→'N',hide=false checkbox不选中→'Y'
|
||||
field.webEntity.isShowColumn = colConfig.hide ? 'N' : 'Y'
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载列配置到 fieldList 失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 从 IndexedDB 加载列配置并应用到 crudRef(在 tableOption 初始化之后调用)
|
||||
const loadColumnConfigToCrudRef = async () => {
|
||||
if (props.model !== 'default' || !tableOption.value.column) return
|
||||
|
||||
try {
|
||||
const pageId = (route.params.id as string) || props.tableId
|
||||
const savedConfig = await getColumnConfig(pageId)
|
||||
|
||||
if (savedConfig && tableOption.value.column) {
|
||||
// 应用配置到 tableOption.column
|
||||
Object.keys(savedConfig).forEach(prop => {
|
||||
if (tableOption.value.column[prop]) {
|
||||
const colConfig = savedConfig[prop]
|
||||
// 优先使用 isShowColumn 转换,如果没有则使用 hide
|
||||
// isShowColumn='Y' 表示 checkbox 未选中,所以 hide=false
|
||||
// isShowColumn='N' 表示 checkbox 选中,所以 hide=true
|
||||
if (colConfig.isShowColumn !== undefined) {
|
||||
tableOption.value.column[prop].hide = colConfig.isShowColumn === 'N'
|
||||
} else if (colConfig.hide !== undefined) {
|
||||
tableOption.value.column[prop].hide = colConfig.hide
|
||||
}
|
||||
if (colConfig.fixed !== undefined) {
|
||||
tableOption.value.column[prop].fixed = colConfig.fixed
|
||||
}
|
||||
if (colConfig.filterable !== undefined) {
|
||||
tableOption.value.column[prop].filterable = colConfig.filterable
|
||||
}
|
||||
if (colConfig.sortable !== undefined) {
|
||||
tableOption.value.column[prop].sortable = colConfig.sortable
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 等待 DOM 更新后同步到 crudRef
|
||||
await nextTick()
|
||||
await nextTick()
|
||||
|
||||
// 使用重试机制确保 crudRef 准备好
|
||||
let retryCount = 0
|
||||
const maxRetries = 10
|
||||
const tryApplyToCrudRef = () => {
|
||||
if (crudRef.value && crudRef.value.columnOption) {
|
||||
crudRef.value.columnOption.forEach((column: any) => {
|
||||
if (savedConfig[column.prop]) {
|
||||
const colConfig = savedConfig[column.prop]
|
||||
// isShowColumn='Y' 表示 checkbox 未选中,所以 hide=false
|
||||
// isShowColumn='N' 表示 checkbox 选中,所以 hide=true
|
||||
if (colConfig.isShowColumn !== undefined) {
|
||||
column.hide = colConfig.isShowColumn === 'N'
|
||||
} else if (colConfig.hide !== undefined) {
|
||||
column.hide = colConfig.hide
|
||||
}
|
||||
if (colConfig.fixed !== undefined) {
|
||||
column.fixed = colConfig.fixed
|
||||
}
|
||||
if (colConfig.filterable !== undefined) {
|
||||
column.filterable = colConfig.filterable
|
||||
}
|
||||
if (colConfig.sortable !== undefined) {
|
||||
column.sortable = colConfig.sortable
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (crudRef.value.$refs && crudRef.value.$refs.table) {
|
||||
crudRef.value.$refs.table.doLayout()
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
while (retryCount < maxRetries && !tryApplyToCrudRef()) {
|
||||
retryCount++
|
||||
await new Promise(resolve => setTimeout(resolve, 100))
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载列配置到 crudRef 失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const subDataFormatting = (data, type) => {
|
||||
if (tabsColumn.value) {
|
||||
tabsColumn.value.forEach((item) => {
|
||||
@@ -2137,6 +2265,11 @@ const beforeUnload = (event) => {
|
||||
|
||||
onMounted(async () => {
|
||||
window.addEventListener('beforeunload', beforeUnload)
|
||||
|
||||
// 监听并替换列显隐按钮
|
||||
if (props.model === 'default') {
|
||||
replaceColumnButton()
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -2181,15 +2314,7 @@ defineExpose({
|
||||
max-width: calc(100% - 210px);
|
||||
}
|
||||
|
||||
&.show_fixed_bar
|
||||
> div
|
||||
> ::v-deep(.avue-crud)
|
||||
> .avue-crud__body
|
||||
> .el-card__body
|
||||
> .el-form
|
||||
> div
|
||||
> .el-table__inner-wrapper
|
||||
> .el-table__body-wrapper {
|
||||
&.show_fixed_bar>div> ::v-deep(.avue-crud)>.avue-crud__body>.el-card__body>.el-form>div>.el-table__inner-wrapper>.el-table__body-wrapper {
|
||||
.el-scrollbar__bar.is-horizontal {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
@@ -2304,6 +2429,7 @@ defineExpose({
|
||||
|
||||
.el-form--default {
|
||||
.el-table--border {
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
width: 0;
|
||||
|
||||
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