diff --git a/frontend/src/components/pure/ms-table/base-table.vue b/frontend/src/components/pure/ms-table/base-table.vue index 5b48bfcd89..dd1dda45c2 100644 --- a/frontend/src/components/pure/ms-table/base-table.vue +++ b/frontend/src/components/pure/ms-table/base-table.vue @@ -84,7 +84,7 @@ props.showSetting && (item.slotName === SpecialColumnEnum.OPERATION || item.slotName === SpecialColumnEnum.ACTION) " - :table-key="(attrs.tableKey as string)" + :table-key="(attrs.tableKey as TableKeyEnum)" :is-simple="(attrs.isSimpleSetting as boolean)" @show-setting="handleShowSetting" @init-data="handleInitColumn" @@ -245,7 +245,7 @@ v-if="props.showSetting" v-model:visible="columnSelectorVisible" :show-jump-method="(attrs.showJumpMethod as boolean)" - :table-key="(attrs.tableKey as string)" + :table-key="(attrs.tableKey as TableKeyEnum)" :show-pagination="!!attrs.showPagination" :show-subdirectory="!!attrs.showSubdirectory" @init-data="handleInitColumn" @@ -273,7 +273,7 @@ import { useAppStore, useTableStore } from '@/store'; import { DragSortParams } from '@/models/common'; - import { ColumnEditTypeEnum, SelectAllEnum, SpecialColumnEnum } from '@/enums/tableEnum'; + import { ColumnEditTypeEnum, SelectAllEnum, SpecialColumnEnum, TableKeyEnum } from '@/enums/tableEnum'; import type { BatchActionConfig, @@ -376,7 +376,7 @@ try { let tmpArr: MsTableColumn = []; if (props.showSetting) { - tmpArr = await tableStore.getShowInTableColumns(attrs.tableKey as string); + tmpArr = await tableStore.getShowInTableColumns(attrs.tableKey as TableKeyEnum); } else { tmpArr = props.columns; } diff --git a/frontend/src/components/pure/ms-table/columnSelector.vue b/frontend/src/components/pure/ms-table/columnSelector.vue index 29ab815c48..804b2cd3d9 100644 --- a/frontend/src/components/pure/ms-table/columnSelector.vue +++ b/frontend/src/components/pure/ms-table/columnSelector.vue @@ -116,6 +116,8 @@ import { useTableStore } from '@/store'; import { TableOpenDetailMode } from '@/store/modules/components/ms-table/types'; + import { TableKeyEnum } from '@/enums/tableEnum'; + import { MsTableColumn } from './type'; const tableStore = useTableStore(); @@ -139,7 +141,7 @@ const props = defineProps<{ visible: boolean; - tableKey: string; + tableKey: TableKeyEnum; showJumpMethod: boolean; showPagination: boolean; showSubdirectory: boolean; @@ -156,7 +158,7 @@ emit('initData'); }; - const loadColumn = (key: string) => { + const loadColumn = (key: TableKeyEnum) => { tableStore.getColumns(key).then((res) => { const { nonSort, couldSort } = res; nonSortColumn.value = nonSort; diff --git a/frontend/src/components/pure/ms-table/columnSelectorIcon.vue b/frontend/src/components/pure/ms-table/columnSelectorIcon.vue index 95d3e6ba0d..159604a8c5 100644 --- a/frontend/src/components/pure/ms-table/columnSelectorIcon.vue +++ b/frontend/src/components/pure/ms-table/columnSelectorIcon.vue @@ -61,7 +61,7 @@ import { useI18n } from '@/hooks/useI18n'; import { useTableStore } from '@/store'; - import { SpecialColumnEnum } from '@/enums/tableEnum'; + import { SpecialColumnEnum, TableKeyEnum } from '@/enums/tableEnum'; import { MsTableColumn } from './type'; @@ -81,7 +81,7 @@ }; const props = defineProps<{ - tableKey: string; + tableKey: TableKeyEnum; isSimple: boolean; }>(); @@ -102,7 +102,7 @@ emit('initData'); }; - const loadColumn = (key: string) => { + const loadColumn = (key: TableKeyEnum) => { tableStore.getColumns(key, true).then((res) => { const { nonSort, couldSort } = res; nonSortColumn.value = nonSort; diff --git a/frontend/src/components/pure/ms-table/type.ts b/frontend/src/components/pure/ms-table/type.ts index 068efacf2e..e880d85f57 100644 --- a/frontend/src/components/pure/ms-table/type.ts +++ b/frontend/src/components/pure/ms-table/type.ts @@ -1,5 +1,5 @@ import type { TableQueryParams } from '@/models/common'; -import { ColumnEditTypeEnum, SelectAllEnum } from '@/enums/tableEnum'; +import { ColumnEditTypeEnum, SelectAllEnum, TableKeyEnum } from '@/enums/tableEnum'; import type { TableChangeExtra, TableColumnData, TableData, TableDraggable } from '@arco-design/web-vue'; @@ -65,7 +65,7 @@ export type MsTableDataItem = T & { export interface MsTableProps { // 表格数据 - 详见 TableData https://arco.design/web-vue/components/table-data; data: MsTableDataItem[]; - tableKey: string; // 表格key, 用于存储表格列配置,pageSize等 + tableKey?: TableKeyEnum; // 表格key, 用于存储表格列配置,pageSize等 rowKey: string; // 表格行的key rowId // 表格列 - 详见 TableColumn https://arco.design/web-vue/components/table-column; columns: MsTableColumnData[]; diff --git a/frontend/src/components/pure/ms-table/useTable.ts b/frontend/src/components/pure/ms-table/useTable.ts index 94fa7b5c4a..bfe1c89b5f 100644 --- a/frontend/src/components/pure/ms-table/useTable.ts +++ b/frontend/src/components/pure/ms-table/useTable.ts @@ -38,9 +38,7 @@ export default function useTableProps( ) { const defaultHeightUsed = 286; // 底部操作栏的height和marginTop - const footerActionWrapHeight = 48; const defaultProps: MsTableProps = { - tableKey: '', // 缓存pageSize 或 column 的 key bordered: true, // 是否显示边框 showPagination: true, // 是否显示分页 showSubdirectory: false, // 是否显示子目录开关 diff --git a/frontend/src/hooks/useLocalForage.ts b/frontend/src/hooks/useLocalForage.ts new file mode 100644 index 0000000000..9d071c48c5 --- /dev/null +++ b/frontend/src/hooks/useLocalForage.ts @@ -0,0 +1,50 @@ +import localforage from 'localforage'; + +import useAppStore from '@/store/modules/app'; + +import { Recordable } from '#/global'; + +export default function useLocalForage() { + const appStore = useAppStore(); + + /** + * 读取本地存储的数据 + * @param key 唯一 key + * @param notIsolatedByProject 存储数据时是否不按项目隔离数据 + */ + const getItem = async (key: string, notIsolatedByProject = false): Promise => { + const itemKey = notIsolatedByProject ? key : `${appStore.currentProjectId}-${key}`; + try { + const res = await localforage.getItem(itemKey); + if (!res) { + return null; + } + return res; + } catch (e) { + // eslint-disable-next-line no-console + console.log(e); + return null; + } + }; + + /** + * 永久存储数据 + * @param key 唯一 key + * @param val 存储的值 + * @param notIsolatedByProject 是否不按项目隔离数据 + */ + const setItem = async (key: string, val: string | number | boolean | Recordable, notIsolatedByProject = false) => { + try { + const itemKey = notIsolatedByProject ? key : `${appStore.currentProjectId}-${key}`; + await localforage.setItem(itemKey, val); + } catch (e) { + // eslint-disable-next-line no-console + console.log(e); + } + }; + + return { + getItem, + setItem, + }; +} diff --git a/frontend/src/hooks/useTableStore.ts b/frontend/src/hooks/useTableStore.ts index 95fb3e9128..0304623dbc 100644 --- a/frontend/src/hooks/useTableStore.ts +++ b/frontend/src/hooks/useTableStore.ts @@ -1,33 +1,21 @@ import { filter, orderBy, sortBy } from 'lodash-es'; -import localforage from 'localforage'; import { MsTableColumn, MsTableColumnData } from '@/components/pure/ms-table/type'; -import { useAppStore } from '@/store'; -import { MsTableSelectorItem, PageSizeMap, TableOpenDetailMode } from '@/store/modules/components/ms-table/types'; +import useAppStore from '@/store/modules/app'; +import { MsTableSelectorItem, TableOpenDetailMode } from '@/store/modules/components/ms-table/types'; import { isArraysEqualWithOrder } from '@/utils/equal'; -import { SpecialColumnEnum } from '@/enums/tableEnum'; +import { SpecialColumnEnum, TableKeyEnum } from '@/enums/tableEnum'; + +import useLocalForage from './useLocalForage'; export default function useTableStore() { const state = reactive({ baseSortIndex: 10, operationBaseIndex: 100, }); - - const getPageSizeMap = async () => { - try { - const pageSizeMap = await localforage.getItem('pageSizeMap'); - if (!pageSizeMap) { - return {}; - } - return pageSizeMap; - } catch (e) { - // eslint-disable-next-line no-console - console.log(e); - return {}; - } - }; + const { getItem, setItem } = useLocalForage(); const columnsTransform = (columns: MsTableColumn) => { columns.forEach((item, idx) => { @@ -58,36 +46,49 @@ export default function useTableStore() { }; async function initColumn( - tableKey: string, + tableKey: TableKeyEnum, column: MsTableColumn, mode?: TableOpenDetailMode, showSubdirectory?: boolean ) { try { - const tableColumnsMap = await localforage.getItem(tableKey); + const tableColumnsMap = await getItem( + tableKey, + tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION') + ); if (!tableColumnsMap) { // 如果没有在indexDB里初始化 column = columnsTransform(column); - localforage.setItem(tableKey, { - mode, - showSubdirectory, - column, - columnBackup: JSON.parse(JSON.stringify(column)), - }); - } else { - // 初始化过了,但是可能有新变动,如列的顺序,列的显示隐藏,列的拖拽 - column = columnsTransform(column); - const { columnBackup: oldColumn } = tableColumnsMap; - // 比较页面上定义的 column 和 浏览器备份的column 是否相同 - const isEqual = isArraysEqualWithOrder(oldColumn, column); - if (!isEqual) { - // 如果不相等,说明有变动将新的column存入indexDB - localforage.setItem(tableKey, { + setItem( + tableKey, + { mode, showSubdirectory, column, columnBackup: JSON.parse(JSON.stringify(column)), - }); + pageSize: useAppStore().pageSize, + }, + tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION') + ); + } else { + // 初始化过了,但是可能有新变动,如列的顺序,列的显示隐藏,列的拖拽 + column = columnsTransform(column); + const { columnBackup: oldColumn, pageSize } = tableColumnsMap; + // 比较页面上定义的 column 和 浏览器备份的column 是否相同 + const isEqual = isArraysEqualWithOrder(oldColumn, column); + if (!isEqual) { + // 如果不相等,说明有变动将新的column存入indexDB + setItem( + tableKey, + { + mode, + showSubdirectory, + column, + columnBackup: JSON.parse(JSON.stringify(column)), + pageSize: pageSize || useAppStore().pageSize, + }, + tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION') + ); } } } catch (e) { @@ -95,12 +96,16 @@ export default function useTableStore() { console.log(e); } } - async function setMode(key: string, mode: TableOpenDetailMode) { + + async function setSubdirectory(tableKey: string, val: boolean) { try { - const tableColumnsMap = await localforage.getItem(key); + const tableColumnsMap = await getItem( + tableKey, + tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION') + ); if (tableColumnsMap) { - tableColumnsMap.mode = mode; - await localforage.setItem(key, tableColumnsMap); + tableColumnsMap.showSubdirectory = val; + await setItem(tableKey, tableColumnsMap, tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION')); } } catch (e) { // eslint-disable-next-line no-console @@ -108,21 +113,19 @@ export default function useTableStore() { } } - async function setSubdirectory(key: string, val: boolean) { - try { - const tableColumnsMap = await localforage.getItem(key); - if (tableColumnsMap) { - tableColumnsMap.showSubdirectory = val; - await localforage.setItem(key, tableColumnsMap); - } - } catch (e) { - // eslint-disable-next-line no-console - console.log(e); + async function getSubShow(tableKey: TableKeyEnum) { + const tableColumnsMap = await getItem( + tableKey, + tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION') + ); + if (tableColumnsMap) { + return tableColumnsMap.showSubdirectory; } + return true as boolean; } async function setColumns( - key: string, + tableKey: TableKeyEnum, columns: MsTableColumn, mode?: TableOpenDetailMode, showSubdirectory?: boolean, @@ -134,7 +137,10 @@ export default function useTableStore() { item.sortIndex = state.baseSortIndex + idx; } }); - const tableColumnsMap = await localforage.getItem(key); + const tableColumnsMap = await getItem( + tableKey, + tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION') + ); if (!tableColumnsMap) { return; } @@ -144,41 +150,28 @@ export default function useTableStore() { if (operationColumn) columns.push(operationColumn); } - await localforage.setItem(key, { - mode, - showSubdirectory, - column: JSON.parse(JSON.stringify(columns)), - columnBackup: tableColumnsMap.columnBackup, - }); + await setItem( + tableKey, + { + mode, + showSubdirectory, + column: JSON.parse(JSON.stringify(columns)), + columnBackup: tableColumnsMap.columnBackup, + pageSize: tableColumnsMap.pageSize || useAppStore().pageSize, + }, + tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION') + ); } 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 tableColumnsMap = await localforage.getItem(key); - if (tableColumnsMap) { - return tableColumnsMap.mode; - } - return 'drawer'; - } - - async function getSubShow(key: string) { - const tableColumnsMap = await localforage.getItem(key); - if (tableColumnsMap) { - return tableColumnsMap.showSubdirectory; - } - return true as boolean; - } - - async function getColumns(key: string, isSimple?: boolean) { - const tableColumnsMap = await localforage.getItem(key); + async function getColumns(tableKey: TableKeyEnum, isSimple?: boolean) { + const tableColumnsMap = await getItem( + tableKey, + tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION') + ); if (tableColumnsMap) { const tmpArr = tableColumnsMap.column; const { nonSortableColumns, couldSortableColumns } = tmpArr.reduce( @@ -199,8 +192,39 @@ export default function useTableStore() { } return { nonSort: [], couldSort: [] }; } - async function getShowInTableColumns(key: string) { - const tableColumnsMap = await localforage.getItem(key); + + async function getMode(tableKey: TableKeyEnum) { + const tableColumnsMap = await getItem( + tableKey, + tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION') + ); + if (tableColumnsMap) { + return tableColumnsMap.mode; + } + return 'drawer'; + } + + async function setMode(tableKey: string, mode: TableOpenDetailMode) { + try { + const tableColumnsMap = await getItem( + tableKey, + tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION') + ); + if (tableColumnsMap) { + tableColumnsMap.mode = mode; + await setItem(tableKey, tableColumnsMap, tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION')); + } + } catch (e) { + // eslint-disable-next-line no-console + console.log(e); + } + } + + async function getShowInTableColumns(tableKey: TableKeyEnum) { + const tableColumnsMap = await getItem( + tableKey, + tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION') + ); if (tableColumnsMap) { const tmpArr: MsTableColumn = tableColumnsMap.column; return orderBy( @@ -211,13 +235,32 @@ export default function useTableStore() { } return []; } - async function getPageSize(key: string) { - const pageSizeMap = await getPageSizeMap(); - if (pageSizeMap[key]) { - return pageSizeMap[key]; + + async function getPageSize(tableKey: TableKeyEnum) { + const tableColumnsMap = await getItem( + tableKey, + tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION') + ); + if (tableColumnsMap) { + return tableColumnsMap.pageSize; } return useAppStore().pageSize; } + async function setPageSize(tableKey: TableKeyEnum, pageSize: number) { + try { + const tableColumnsMap = await getItem( + tableKey, + tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION') + ); + if (tableColumnsMap) { + tableColumnsMap.pageSize = pageSize; + await setItem(tableKey, tableColumnsMap, tableKey.startsWith('SYSTEM') || tableKey.startsWith('ORGANIZATION')); + } + } catch (e) { + // eslint-disable-next-line no-console + console.log(e); + } + } return { initColumn, diff --git a/frontend/src/store/modules/case/featureCase.ts b/frontend/src/store/modules/case/featureCase.ts index a8cd2b0a58..24add73f1f 100644 --- a/frontend/src/store/modules/case/featureCase.ts +++ b/frontend/src/store/modules/case/featureCase.ts @@ -7,6 +7,7 @@ import { getCaseModulesCounts, getRecycleModulesCounts, } from '@/api/modules/case-management/featureCase'; +import useLocalForage from '@/hooks/useLocalForage'; import { isArraysEqualWithOrder } from '@/utils/equal'; import type { ContentTabsMap, CustomAttributes, TabItemType } from '@/models/caseManagement/featureCase'; @@ -132,17 +133,18 @@ const useFeatureCaseStore = defineStore('featureCase', { }, async initContentTabList(arr: TabItemType[]) { try { - const tabsMap = await localforage.getItem('caseTabsMap'); + const { getItem, setItem } = useLocalForage(); + const tabsMap = await getItem('caseTabsMap'); if (tabsMap) { const { backupTabList } = tabsMap; const isEqual = isArraysEqualWithOrder(backupTabList, arr); if (!isEqual) { tabsMap.tabList = arr; tabsMap.backupTabList = arr; - await localforage.setItem('caseTabsMap', tabsMap); + await setItem('caseTabsMap', tabsMap); } } else { - await localforage.setItem('caseTabsMap', { tabList: arr, backupTabList: arr }); + await setItem('caseTabsMap', { tabList: arr, backupTabList: arr }); } } catch (e) { console.log(e); @@ -150,7 +152,8 @@ const useFeatureCaseStore = defineStore('featureCase', { }, async getContentTabList() { try { - const tabsMap = await localforage.getItem('caseTabsMap'); + const { getItem } = useLocalForage(); + const tabsMap = await getItem('caseTabsMap'); if (tabsMap) { return tabsMap.tabList; } @@ -160,11 +163,12 @@ const useFeatureCaseStore = defineStore('featureCase', { } }, async setContentTabList(arr: TabItemType[]) { - const tabsMap = await localforage.getItem('caseTabsMap'); + const { getItem, setItem } = useLocalForage(); + const tabsMap = await getItem('caseTabsMap'); if (tabsMap) { const tmpArrList = JSON.parse(JSON.stringify(arr)); tabsMap.tabList = tmpArrList; - await localforage.setItem('caseTabsMap', tabsMap); + await setItem('caseTabsMap', tabsMap); } }, }, diff --git a/frontend/src/store/modules/components/ms-table/types.ts b/frontend/src/store/modules/components/ms-table/types.ts index ad19c17f2f..3651d69fa3 100644 --- a/frontend/src/store/modules/components/ms-table/types.ts +++ b/frontend/src/store/modules/components/ms-table/types.ts @@ -10,14 +10,12 @@ export interface MsTableSelectorItem { column: MsTableColumn; // 列配置的备份,用于比较当前定义的列配置是否和备份的列配置相同 columnBackup: MsTableColumn; + pageSize: number; } export interface SelectorColumnMap { [key: string]: MsTableSelectorItem; } -export interface PageSizeMap { - [key: string]: number; -} export interface MsTableState { // 列配置, 持久化 selectorColumnMap: SelectorColumnMap; @@ -25,6 +23,4 @@ export interface MsTableState { baseSortIndex: number; // 操作列基数 operationBaseIndex: number; - // 分页大小 - pageSizeMap: PageSizeMap; } diff --git a/frontend/src/store/modules/setting/useProjectEnvStore.ts b/frontend/src/store/modules/setting/useProjectEnvStore.ts index 716dc053b2..1560f0b552 100644 --- a/frontend/src/store/modules/setting/useProjectEnvStore.ts +++ b/frontend/src/store/modules/setting/useProjectEnvStore.ts @@ -3,6 +3,7 @@ import { cloneDeep } from 'lodash-es'; import localforage from 'localforage'; import { getDetailEnv, getGlobalParamDetail } from '@/api/modules/project-management/envManagement'; +import useLocalForage from '@/hooks/useLocalForage'; import { useAppStore } from '@/store'; import { isArraysEqualWithOrder } from '@/utils/equal'; @@ -128,7 +129,8 @@ const useProjectEnvStore = defineStore( // 初始化内容tab列表 async function initContentTabList(arr: ContentTabItem[]) { try { - const tabsMap = await localforage.getItem('bugTabsMap'); + const { getItem, setItem } = useLocalForage(); + const tabsMap = await getItem('bugTabsMap'); if (tabsMap) { // 初始化过了 const { backupTabList } = tabsMap; @@ -136,11 +138,11 @@ const useProjectEnvStore = defineStore( if (!isEqual) { tabsMap.tabList = arr; tabsMap.backupTabList = arr; - await localforage.setItem('bugTabsMap', tabsMap); + await setItem('bugTabsMap', tabsMap); } } else { // 没初始化过 - await localforage.setItem('bugTabsMap', { tabList: arr, backupTabList: arr }); + await setItem('bugTabsMap', { tabList: arr, backupTabList: arr }); } } catch (e) { // eslint-disable-next-line no-console @@ -150,7 +152,8 @@ const useProjectEnvStore = defineStore( // 获取Tab列表 async function getContentTabList() { try { - const tabsMap = await localforage.getItem('bugTabsMap'); + const { getItem } = useLocalForage(); + const tabsMap = await getItem('bugTabsMap'); if (tabsMap) { return tabsMap.tabList; } @@ -163,11 +166,12 @@ const useProjectEnvStore = defineStore( // 设置Tab列表 async function setContentTabList(arr: ContentTabItem[]) { - const tabsMap = await localforage.getItem('bugTabsMap'); + const { getItem, setItem } = useLocalForage(); + const tabsMap = await getItem('bugTabsMap'); if (tabsMap) { const tmpArrList = JSON.parse(JSON.stringify(arr)); tabsMap.tabList = tmpArrList; - await localforage.setItem('bugTabsMap', tabsMap); + await setItem('bugTabsMap', tabsMap); } }