feat: 表格相关缓存存入前端indexDB

This commit is contained in:
RubyLiu 2023-10-30 19:19:04 +08:00 committed by rubylliu
parent 6f26154738
commit 8038acdd22
9 changed files with 238 additions and 35 deletions

View File

@ -50,6 +50,7 @@
"hotbox-minder": "1.0.15",
"jsencrypt": "^3.3.2",
"jsonpath-picker-vanilla": "^1.2.4",
"localforage": "^1.10.0",
"lodash-es": "^4.17.21",
"mitt": "^3.0.1",
"monaco-editor": "^0.39.0",

View File

@ -53,7 +53,13 @@
:tooltip="item.tooltip"
>
<template #title>
<div v-if="props.showSetting && idx === lastColumnIndex" class="flex flex-row flex-nowrap items-center">
<div
v-if="
props.showSetting &&
(item.slotName === SpecialColumnEnum.OPERATION || item.slotName === SpecialColumnEnum.ACTION)
"
class="flex flex-row flex-nowrap items-center"
>
<slot :name="item.titleSlotName">
<div class="text-[var(--color-text-3)]">{{ t(item.title as string) }}</div>
</slot>
@ -240,8 +246,6 @@
(e: 'clearSelector'): void;
}>();
const attrs = useAttrs();
const lastColumnIndex = computed(() => currentColumns.value.length - 1);
// -
const selectTotal = computed(() => {
const { selectorStatus } = props;
@ -300,14 +304,19 @@
return undefined;
});
const initColumn = (arr?: MsTableColumn) => {
let tmpArr: MsTableColumn = [];
if (props.showSetting) {
tmpArr = tableStore.getShowInTableColumns(attrs.tableKey as string) || [];
} else {
tmpArr = props.columns;
const initColumn = async (arr?: MsTableColumn) => {
try {
let tmpArr: MsTableColumn = [];
if (props.showSetting) {
tmpArr = await tableStore.getShowInTableColumns(attrs.tableKey as string);
} else {
tmpArr = props.columns;
}
currentColumns.value = arr || tmpArr;
} catch (error) {
// eslint-disable-next-line no-console
console.error('InitColumn failed', error);
}
currentColumns.value = arr || tmpArr;
};
// change
@ -415,8 +424,8 @@
}
};
const handleColumnSelectorClose = () => {
initColumn();
const handleColumnSelectorClose = async () => {
await initColumn();
};
function getRowClass(record: TableData, rowIndex: number) {
@ -429,8 +438,8 @@
}
}
onMounted(() => {
initColumn();
onMounted(async () => {
await initColumn();
batchLeft.value = getBatchLeft();
});

View File

@ -12,7 +12,7 @@
<template v-if="showJumpMethod">
<div class="mb-2 flex items-center">
<span class="text-[var(--color-text-4)]">{{ t('msTable.columnSetting.mode') }}</span>
<a-tooltip :content="t('msTable.columnSetting.tooltipContent')">
<a-tooltip>
<template #content>
<span>{{ t('msTable.columnSetting.tooltipContentDrawer') }}</span
><br />
@ -39,14 +39,14 @@
</a-radio>
</a-radio-group>
</template>
<tmplate v-if="props.showPagination">
<template v-if="props.showPagination">
<div class="text-[var(--color-text-4)]">{{ t('msTable.columnSetting.pageSize') }} </div>
<PageSizeSelector
v-model:model-value="pageSize"
class="mt-2"
@page-size-change="(v: number) => emit('pageSizeChange',v)"
/>
</tmplate>
</template>
<a-divider />
<div class="mb-2 flex items-center justify-between">
<div class="text-[var(--color-text-4)]">{{ t('msTable.columnSetting.header') }}</div>
@ -91,7 +91,7 @@
import PageSizeSelector from './comp/pageSizeSelector.vue';
import { useI18n } from '@/hooks/useI18n';
import { useAppStore, useTableStore } from '@/store';
import { useTableStore } from '@/store';
import { TableOpenDetailMode } from '@/store/modules/ms-table/types';
import { MsTableColumn } from './type';
@ -100,8 +100,7 @@
const tableStore = useTableStore();
const { t } = useI18n();
const currentMode = ref('');
const appStore = useAppStore();
const pageSize = ref(appStore.pageSize);
const pageSize = ref();
//
const nonSortColumn = ref<MsTableColumn>([]);
//
@ -126,8 +125,8 @@
visible.value = true;
};
const handleCancel = () => {
tableStore.setColumns(
const handleCancel = async () => {
await tableStore.setColumns(
props.tableKey,
[...nonSortColumn.value, ...couldSortColumn.value],
currentMode.value as TableOpenDetailMode
@ -137,9 +136,11 @@
};
const loadColumn = (key: string) => {
const { nonSort, couldSort } = tableStore.getColumns(key);
nonSortColumn.value = nonSort;
couldSortColumn.value = couldSort;
tableStore.getColumns(key).then((res) => {
const { nonSort, couldSort } = res;
nonSortColumn.value = nonSort;
couldSortColumn.value = couldSort;
});
};
const handleReset = () => {
@ -153,7 +154,12 @@
onBeforeMount(() => {
if (props.tableKey) {
currentMode.value = tableStore.getMode(props.tableKey);
tableStore.getMode(props.tableKey).then((res) => {
currentMode.value = res;
});
tableStore.getPageSize(props.tableKey).then((res) => {
pageSize.value = res;
});
loadColumn(props.tableKey);
}
});

View File

@ -111,8 +111,11 @@ export default function useTableProps<T>(
// 如果表格设置了tableKey设置缓存的分页大小
if (propsRes.value.msPagination && typeof propsRes.value.msPagination === 'object' && propsRes.value.tableKey) {
const pageSize = tableStore.getPageSize(propsRes.value.tableKey);
propsRes.value.msPagination.pageSize = pageSize;
tableStore.getPageSize(propsRes.value.tableKey).then((res) => {
if (propsRes.value.msPagination && res) {
propsRes.value.msPagination.pageSize = res;
}
});
}
/**
@ -162,12 +165,17 @@ export default function useTableProps<T>(
if (propsRes.value.showPagination) {
const { current, pageSize } = propsRes.value.msPagination as Pagination;
const { rowKey, selectorStatus, excludeKeys } = propsRes.value;
let currentPageSize = pageSize;
if (propsRes.value.tableKey) {
// 如果表格设置了tableKey缓存分页大小
currentPageSize = await tableStore.getPageSize(propsRes.value.tableKey);
}
try {
if (loadListFunc) {
setLoading(true);
const data = await loadListFunc({
current,
pageSize,
pageSize: currentPageSize,
sort: sortItem.value,
filter: filterItem.value,
keyword: keyword.value,

View File

@ -0,0 +1,173 @@
import { filter, orderBy } from 'lodash-es';
import { MsTableColumn, MsTableColumnData } from '@/components/pure/ms-table/type';
import { useAppStore } from '@/store';
import { PageSizeMap, SelectorColumnMap, TableOpenDetailMode } from '@/store/modules/ms-table/types';
import { SpecialColumnEnum } from '@/enums/tableEnum';
import localforage from 'localforage';
export default function useTableStore() {
const state = reactive({
baseSortIndex: 10,
operationBaseIndex: 100,
});
const getSelectorColumnMap = async () => {
try {
const selectorColumnMap = await localforage.getItem<SelectorColumnMap>('selectorColumnMap');
if (!selectorColumnMap) {
return {};
}
return selectorColumnMap;
} catch (e) {
// eslint-disable-next-line no-console
console.log(e);
return {};
}
};
const getPageSizeMap = async () => {
try {
const pageSizeMap = await localforage.getItem<PageSizeMap>('pageSizeMap');
if (!pageSizeMap) {
return {};
}
return pageSizeMap;
} catch (e) {
// eslint-disable-next-line no-console
console.log(e);
return {};
}
};
async function initColumn(tableKey: string, column: MsTableColumn, mode: TableOpenDetailMode) {
try {
const selectorColumnMap = await getSelectorColumnMap();
if (!selectorColumnMap[tableKey]) {
column.forEach((item, idx) => {
if (item.sortIndex === undefined) {
// 如果没有设置sortIndex则默认按照顺序排序
item.sortIndex = state.baseSortIndex + idx;
}
if (item.showDrag === undefined) {
// 默认不可以拖拽
item.showDrag = false;
}
if (item.showInTable === undefined) {
// 默认在表格中展示
item.showInTable = true;
}
if (item.dataIndex === SpecialColumnEnum.ID) {
// dataIndex 为 id 的列默认不排序,且展示在列的最前面
item.showDrag = false;
item.sortIndex = 0;
}
if (item.dataIndex === SpecialColumnEnum.NAME) {
// dataIndex 为 name 的列默认不排序,且展示在列的第二位
item.showDrag = false;
item.sortIndex = 1;
}
if (item.dataIndex === SpecialColumnEnum.OPERATION || item.dataIndex === SpecialColumnEnum.ACTION) {
// dataIndex 为 operation 或 action 的列默认不排序,且展示在列的最后面
item.showDrag = false;
item.sortIndex = state.operationBaseIndex;
}
});
selectorColumnMap[tableKey] = { mode, column };
await localforage.setItem('selectorColumnMap', selectorColumnMap);
}
} catch (e) {
// eslint-disable-next-line no-console
console.log(e);
}
}
async function setMode(key: string, mode: TableOpenDetailMode) {
try {
const selectorColumnMap = await getSelectorColumnMap();
if (selectorColumnMap[key]) {
const item = selectorColumnMap[key];
if (item) {
item.mode = mode;
}
await localforage.setItem('selectorColumnMap', selectorColumnMap);
}
} catch (e) {
// eslint-disable-next-line no-console
console.log(e);
}
}
async function setColumns(key: string, columns: MsTableColumn, mode: TableOpenDetailMode) {
try {
columns.forEach((item, idx) => {
if (item.showDrag) {
item.sortIndex = state.baseSortIndex + idx;
}
});
const selectorColumnMap = await getSelectorColumnMap();
if (!selectorColumnMap) {
return;
}
selectorColumnMap[key] = { mode, column: JSON.parse(JSON.stringify(columns)) };
await localforage.setItem('selectorColumnMap', selectorColumnMap);
} catch (e) {
// eslint-disable-next-line no-console
console.error('tableStore.setColumns', e);
}
}
async function setPageSize(key: string, pageSize: number) {
const pageSizeMap = await getPageSizeMap();
pageSizeMap[key] = pageSize;
await localforage.setItem('pageSizeMap', pageSizeMap);
}
async function getMode(key: string) {
const selectorColumnMap = await getSelectorColumnMap();
if (selectorColumnMap[key]) {
return selectorColumnMap[key].mode;
}
return 'drawer';
}
async function getColumns(key: string) {
const selectorColumnMap = await getSelectorColumnMap();
if (selectorColumnMap[key]) {
const tmpArr = selectorColumnMap[key].column;
const nonSortableColumns = tmpArr.filter((item: MsTableColumnData) => !item.showDrag);
const couldSortableColumns = tmpArr.filter((item: MsTableColumnData) => !!item.showDrag);
return { nonSort: nonSortableColumns, couldSort: couldSortableColumns };
}
return { nonSort: [], couldSort: [] };
}
async function getShowInTableColumns(key: string) {
const selectorColumnMap = await getSelectorColumnMap();
if (selectorColumnMap[key]) {
const tmpArr: MsTableColumn = selectorColumnMap[key].column;
return orderBy(
filter(tmpArr, (i) => i.showInTable),
['sortIndex'],
['asc']
) as MsTableColumn;
}
return [];
}
async function getPageSize(key: string) {
const pageSizeMap = await getPageSizeMap();
if (pageSizeMap[key]) {
return pageSizeMap[key];
}
return useAppStore().pageSize;
}
return {
initColumn,
setMode,
setColumns,
setPageSize,
getMode,
getColumns,
getShowInTableColumns,
getPageSize,
};
}

View File

@ -15,6 +15,7 @@ import router from './router';
import store from './store';
import ArcoVueIcon from '@arco-design/web-vue/es/icon';
import '@/assets/style/global.less';
import localforage from 'localforage';
async function bootstrap() {
const app = createApp(App);
@ -28,6 +29,14 @@ async function bootstrap() {
app.component('SvgIcon', SvgIcon);
app.component('MsIcon', MsIcon);
// 初始化本地存储
localforage.config({
driver: localforage.INDEXEDDB, // 选择后端存储,这里使用 IndexedDB
name: 'MeterSphere', // 数据库名称
version: 1.0, // 数据库版本
storeName: 'msTable', // 存储空间名称
});
app.use(directive);
app.mount('#app');

View File

@ -1,8 +1,9 @@
import { createPinia } from 'pinia';
import useTableStore from '@/hooks/useTableStore';
import useAppStore from './modules/app';
import useVisitStore from './modules/app/visit';
import useTableStore from './modules/ms-table';
import useUserStore from './modules/user';
import { debouncePlugin } from './plugins';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';

View File

@ -10,9 +10,6 @@ import { MsTableState, TableOpenDetailMode } from './types';
const msTableStore = defineStore('msTable', {
// 开启数据持久化
persist: {
paths: ['selectorColumnMap', 'pageSizeMap'],
},
state: (): MsTableState => ({
selectorColumnMap: {},
baseSortIndex: 10,

View File

@ -51,7 +51,6 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsFormCreate from '@/components/pure/ms-form-create/formCreate.vue';
@ -232,7 +231,7 @@
watch(
() => props.data,
(val) => {
totalData.value = props.data;
totalData.value = val;
}
);
const tableRef = ref();