fix: 修复列表搜索翻页后丢失搜索条件的bug

This commit is contained in:
gaoyunqi
2024-09-09 11:20:06 +08:00
parent 6b6e7ad0a6
commit 78b05fc000
2 changed files with 944 additions and 965 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,377 +1,383 @@
import type { BasicTableProps, FetchParams, SorterResult } from '../types/table';
import type { PaginationProps } from '../types/pagination';
import type { BasicTableProps, FetchParams, SorterResult } from "../types/table";
import type { PaginationProps } from "../types/pagination";
import {
ref,
unref,
ComputedRef,
computed,
onMounted,
watch,
reactive,
Ref,
watchEffect,
} from 'vue';
import { useTimeoutFn } from '/@/hooks/core/useTimeout';
import { buildUUID } from '/@/utils/uuid';
import { isFunction, isBoolean } from '/@/utils/is';
import { get, cloneDeep, merge } from 'lodash-es';
import { FETCH_SETTING, ROW_KEY, PAGE_SIZE } from '../const';
ref,
unref,
ComputedRef,
computed,
onMounted,
watch,
reactive,
Ref,
watchEffect
} from "vue";
import { useTimeoutFn } from "/@/hooks/core/useTimeout";
import { buildUUID } from "/@/utils/uuid";
import { isFunction, isBoolean } from "/@/utils/is";
import { get, cloneDeep, merge } from "lodash-es";
import { FETCH_SETTING, ROW_KEY, PAGE_SIZE } from "../const";
interface ActionType {
getPaginationInfo: ComputedRef<boolean | PaginationProps>;
setPagination: (info: Partial<PaginationProps>) => void;
setLoading: (loading: boolean) => void;
getFieldsValue: () => Recordable;
clearSelectedRowKeys: () => void;
tableData: Ref<Recordable[]>;
getPaginationInfo: ComputedRef<boolean | PaginationProps>;
setPagination: (info: Partial<PaginationProps>) => void;
setLoading: (loading: boolean) => void;
getFieldsValue: () => Recordable;
clearSelectedRowKeys: () => void;
tableData: Ref<Recordable[]>;
}
interface SearchState {
sortInfo: Recordable;
filterInfo: Record<string, string[]>;
sortInfo: Recordable;
filterInfo: Record<string, string[]>;
}
export function useDataSource(
propsRef: ComputedRef<BasicTableProps>,
{
getPaginationInfo,
setPagination,
setLoading,
getFieldsValue,
clearSelectedRowKeys,
tableData,
}: ActionType,
emit: EmitType,
) {
const searchState = reactive<SearchState>({
sortInfo: {},
filterInfo: {},
});
const dataSourceRef = ref<Recordable[]>([]);
const rawDataSourceRef = ref<Recordable>({});
watchEffect(() => {
tableData.value = unref(dataSourceRef);
});
watch(
() => unref(propsRef).dataSource,
() => {
const { dataSource, api } = unref(propsRef);
!api && dataSource && (dataSourceRef.value = dataSource);
},
propsRef: ComputedRef<BasicTableProps>,
{
immediate: true,
},
);
function handleTableChange(
isPaginateByDataSource = false,
pagination: PaginationProps,
filters: Partial<Recordable<string[]>>,
sorter: SorterResult,
) {
const { clearSelectOnPageChange, sortFn, filterFn } = unref(propsRef);
if (clearSelectOnPageChange) {
clearSelectedRowKeys();
}
setPagination(pagination);
const params: Recordable = {};
if (sorter && isFunction(sortFn)) {
const sortInfo = sortFn(sorter);
searchState.sortInfo = sortInfo;
params.sortInfo = sortInfo;
}
if (filters && isFunction(filterFn)) {
const filterInfo = filterFn(filters);
searchState.filterInfo = filterInfo;
params.filterInfo = filterInfo;
}
if (!isPaginateByDataSource) {
fetch(params);
}
}
function setTableKey(items: any[]) {
if (!items || !Array.isArray(items)) return;
items.forEach((item) => {
if (!item[ROW_KEY]) {
item[ROW_KEY] = buildUUID();
}
if (item.children && item.children.length) {
setTableKey(item.children);
}
getPaginationInfo,
setPagination,
setLoading,
getFieldsValue,
clearSelectedRowKeys,
tableData
}: ActionType,
emit: EmitType
) {
const searchState = reactive<SearchState>({
sortInfo: {},
filterInfo: {}
});
}
const dataSourceRef = ref<Recordable[]>([]);
const rawDataSourceRef = ref<Recordable>({});
const searchFormData = ref({});
const getAutoCreateKey = computed(() => {
return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey;
});
watchEffect(() => {
tableData.value = unref(dataSourceRef);
});
const getRowKey = computed(() => {
const { rowKey } = unref(propsRef);
return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
});
watch(
() => unref(propsRef).dataSource,
() => {
const { dataSource, api } = unref(propsRef);
!api && dataSource && (dataSourceRef.value = dataSource);
},
{
immediate: true
}
);
const getDataSourceRef = computed(() => {
const dataSource = unref(dataSourceRef);
if (!dataSource || dataSource.length === 0) {
return unref(dataSourceRef);
function handleTableChange(
isPaginateByDataSource = false,
pagination: PaginationProps,
filters: Partial<Recordable<string[]>>,
sorter: SorterResult
) {
const { clearSelectOnPageChange, sortFn, filterFn } = unref(propsRef);
if (clearSelectOnPageChange) {
clearSelectedRowKeys();
}
setPagination(pagination);
const params: Recordable = {};
if (sorter && isFunction(sortFn)) {
const sortInfo = sortFn(sorter);
searchState.sortInfo = sortInfo;
params.sortInfo = sortInfo;
}
if (filters && isFunction(filterFn)) {
const filterInfo = filterFn(filters);
searchState.filterInfo = filterInfo;
params.filterInfo = filterInfo;
}
if (!isPaginateByDataSource) {
fetch(params);
}
}
if (unref(getAutoCreateKey)) {
const firstItem = dataSource[0];
const lastItem = dataSource[dataSource.length - 1];
if (firstItem && lastItem) {
if (!firstItem[ROW_KEY] || !lastItem[ROW_KEY]) {
const data = cloneDeep(unref(dataSourceRef));
data.forEach((item) => {
function setTableKey(items: any[]) {
if (!items || !Array.isArray(items)) return;
items.forEach((item) => {
if (!item[ROW_KEY]) {
item[ROW_KEY] = buildUUID();
item[ROW_KEY] = buildUUID();
}
if (item.children && item.children.length) {
setTableKey(item.children);
setTableKey(item.children);
}
});
dataSourceRef.value = data;
}
}
}
return unref(dataSourceRef);
});
async function updateTableData(index: number, key: string, value: any) {
const record = dataSourceRef.value[index];
if (record) {
dataSourceRef.value[index][key] = value;
}
return dataSourceRef.value[index];
}
function updateTableDataRecord(
rowKey: string | number,
record: Recordable,
): Recordable | undefined {
const row = findTableDataRecord(rowKey);
if (row) {
for (const field in row) {
if (Reflect.has(record, field)) row[field] = record[field];
}
return row;
}
}
function deleteTableDataRecord(rowKey: string | number | string[] | number[]) {
if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
const rowKeyName = unref(getRowKey);
if (!rowKeyName) return;
const rowKeys = !Array.isArray(rowKey) ? [rowKey] : rowKey;
for (const key of rowKeys) {
let index: number | undefined = dataSourceRef.value.findIndex((row) => {
let targetKeyName: string;
if (typeof rowKeyName === 'function') {
targetKeyName = rowKeyName(row);
} else {
targetKeyName = rowKeyName as string;
}
return row[targetKeyName] === key;
});
if (index >= 0) {
dataSourceRef.value.splice(index, 1);
}
index = unref(propsRef).dataSource?.findIndex((row) => {
let targetKeyName: string;
if (typeof rowKeyName === 'function') {
targetKeyName = rowKeyName(row);
} else {
targetKeyName = rowKeyName as string;
}
return row[targetKeyName] === key;
});
if (typeof index !== 'undefined' && index !== -1)
unref(propsRef).dataSource?.splice(index, 1);
}
setPagination({
total: unref(propsRef).dataSource?.length,
});
}
function insertTableDataRecord(record: Recordable, index: number): Recordable | undefined {
// if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
index = index ?? dataSourceRef.value?.length;
unref(dataSourceRef).splice(index, 0, record);
return unref(dataSourceRef);
}
function findTableDataRecord(rowKey: string | number) {
if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
const rowKeyName = unref(getRowKey);
if (!rowKeyName) return;
const { childrenColumnName = 'children' } = unref(propsRef);
const findRow = (array: any[]) => {
let ret;
array.some(function iter(r) {
if (typeof rowKeyName === 'function') {
if ((rowKeyName(r) as string) === rowKey) {
ret = r;
return true;
}
} else {
if (Reflect.has(r, rowKeyName) && r[rowKeyName] === rowKey) {
ret = r;
return true;
}
}
return r[childrenColumnName] && r[childrenColumnName].some(iter);
});
return ret;
};
// const row = dataSourceRef.value.find(r => {
// if (typeof rowKeyName === 'function') {
// return (rowKeyName(r) as string) === rowKey
// } else {
// return Reflect.has(r, rowKeyName) && r[rowKeyName] === rowKey
// }
// })
return findRow(dataSourceRef.value);
}
async function fetch(opt?: FetchParams) {
const {
api,
searchInfo,
defSort,
fetchSetting,
beforeFetch,
afterFetch,
useSearchForm,
pagination,
} = unref(propsRef);
if (!api || !isFunction(api)) return;
try {
setLoading(true);
const { pageField, sizeField, listField, totalField } = Object.assign(
{},
FETCH_SETTING,
fetchSetting,
);
let pageParams: Recordable = {};
const { current = 1, pageSize = PAGE_SIZE } = unref(getPaginationInfo) as PaginationProps;
if ((isBoolean(pagination) && !pagination) || isBoolean(getPaginationInfo)) {
pageParams = {};
} else {
pageParams[pageField] = (opt && opt.page) || current;
pageParams[sizeField] = pageSize;
}
const { sortInfo = {}, filterInfo } = searchState;
let params: Recordable = merge(
pageParams,
useSearchForm ? getFieldsValue() : {},
searchInfo,
opt?.searchInfo ?? {},
defSort,
sortInfo,
filterInfo,
opt?.sortInfo ?? {},
opt?.filterInfo ?? {},
);
if (beforeFetch && isFunction(beforeFetch)) {
params = (await beforeFetch(params)) || params;
}
const res = await api(params);
rawDataSourceRef.value = res;
const isArrayResult = Array.isArray(res);
let resultItems: Recordable[] = isArrayResult ? res : get(res, listField);
const resultTotal: number = isArrayResult ? res.length : get(res, totalField);
// 假如数据变少导致总页数变少并小于当前选中页码通过getPaginationRef获取到的页码是不正确的需获取正确的页码再次执行
if (resultTotal) {
const currentTotalPage = Math.ceil(resultTotal / pageSize);
if (current > currentTotalPage) {
setPagination({
current: currentTotalPage,
});
return await fetch(opt);
}
}
if (afterFetch && isFunction(afterFetch)) {
resultItems = (await afterFetch(resultItems)) || resultItems;
}
dataSourceRef.value = resultItems;
setPagination({
total: resultTotal || 0,
});
if (opt && opt.page) {
setPagination({
current: opt.page || 1,
});
}
emit('fetch-success', {
items: unref(resultItems),
total: resultTotal,
});
return resultItems;
} catch (error) {
emit('fetch-error', error);
dataSourceRef.value = [];
setPagination({
total: 0,
});
} finally {
setLoading(false);
}
}
function setTableData<T = Recordable>(values: T[]) {
dataSourceRef.value = values;
}
const getAutoCreateKey = computed(() => {
return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey;
});
function getDataSource<T = Recordable>() {
return getDataSourceRef.value as T[];
}
const getRowKey = computed(() => {
const { rowKey } = unref(propsRef);
return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
});
function getRawDataSource<T = Recordable>() {
return rawDataSourceRef.value as T;
}
const getDataSourceRef = computed(() => {
const dataSource = unref(dataSourceRef);
if (!dataSource || dataSource.length === 0) {
return unref(dataSourceRef);
}
if (unref(getAutoCreateKey)) {
const firstItem = dataSource[0];
const lastItem = dataSource[dataSource.length - 1];
async function reload(opt?: FetchParams) {
return await fetch(opt);
}
if (firstItem && lastItem) {
if (!firstItem[ROW_KEY] || !lastItem[ROW_KEY]) {
const data = cloneDeep(unref(dataSourceRef));
data.forEach((item) => {
if (!item[ROW_KEY]) {
item[ROW_KEY] = buildUUID();
}
if (item.children && item.children.length) {
setTableKey(item.children);
}
});
dataSourceRef.value = data;
}
}
}
return unref(dataSourceRef);
});
onMounted(() => {
useTimeoutFn(() => {
unref(propsRef).immediate && fetch();
}, 16);
});
async function updateTableData(index: number, key: string, value: any) {
const record = dataSourceRef.value[index];
if (record) {
dataSourceRef.value[index][key] = value;
}
return dataSourceRef.value[index];
}
return {
getDataSourceRef,
getDataSource,
getRawDataSource,
getRowKey,
setTableData,
getAutoCreateKey,
fetch,
reload,
updateTableData,
updateTableDataRecord,
deleteTableDataRecord,
insertTableDataRecord,
findTableDataRecord,
handleTableChange,
};
function updateTableDataRecord(
rowKey: string | number,
record: Recordable
): Recordable | undefined {
const row = findTableDataRecord(rowKey);
if (row) {
for (const field in row) {
if (Reflect.has(record, field)) row[field] = record[field];
}
return row;
}
}
function deleteTableDataRecord(rowKey: string | number | string[] | number[]) {
if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
const rowKeyName = unref(getRowKey);
if (!rowKeyName) return;
const rowKeys = !Array.isArray(rowKey) ? [rowKey] : rowKey;
for (const key of rowKeys) {
let index: number | undefined = dataSourceRef.value.findIndex((row) => {
let targetKeyName: string;
if (typeof rowKeyName === "function") {
targetKeyName = rowKeyName(row);
} else {
targetKeyName = rowKeyName as string;
}
return row[targetKeyName] === key;
});
if (index >= 0) {
dataSourceRef.value.splice(index, 1);
}
index = unref(propsRef).dataSource?.findIndex((row) => {
let targetKeyName: string;
if (typeof rowKeyName === "function") {
targetKeyName = rowKeyName(row);
} else {
targetKeyName = rowKeyName as string;
}
return row[targetKeyName] === key;
});
if (typeof index !== "undefined" && index !== -1)
unref(propsRef).dataSource?.splice(index, 1);
}
setPagination({
total: unref(propsRef).dataSource?.length
});
}
function insertTableDataRecord(record: Recordable, index: number): Recordable | undefined {
// if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
index = index ?? dataSourceRef.value?.length;
unref(dataSourceRef).splice(index, 0, record);
return unref(dataSourceRef);
}
function findTableDataRecord(rowKey: string | number) {
if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
const rowKeyName = unref(getRowKey);
if (!rowKeyName) return;
const { childrenColumnName = "children" } = unref(propsRef);
const findRow = (array: any[]) => {
let ret;
array.some(function iter(r) {
if (typeof rowKeyName === "function") {
if ((rowKeyName(r) as string) === rowKey) {
ret = r;
return true;
}
} else {
if (Reflect.has(r, rowKeyName) && r[rowKeyName] === rowKey) {
ret = r;
return true;
}
}
return r[childrenColumnName] && r[childrenColumnName].some(iter);
});
return ret;
};
// const row = dataSourceRef.value.find(r => {
// if (typeof rowKeyName === 'function') {
// return (rowKeyName(r) as string) === rowKey
// } else {
// return Reflect.has(r, rowKeyName) && r[rowKeyName] === rowKey
// }
// })
return findRow(dataSourceRef.value);
}
async function fetch(opt?: FetchParams) {
const {
api,
searchInfo,
defSort,
fetchSetting,
beforeFetch,
afterFetch,
useSearchForm,
pagination
} = unref(propsRef);
if (!api || !isFunction(api)) return;
try {
setLoading(true);
const { pageField, sizeField, listField, totalField } = Object.assign(
{},
FETCH_SETTING,
fetchSetting
);
let pageParams: Recordable = {};
const { current = 1, pageSize = PAGE_SIZE } = unref(getPaginationInfo) as PaginationProps;
if ((isBoolean(pagination) && !pagination) || isBoolean(getPaginationInfo)) {
pageParams = {};
} else {
pageParams[pageField] = (opt && opt.page) || current;
pageParams[sizeField] = pageSize;
}
const { sortInfo = {}, filterInfo } = searchState;
let params: Recordable = merge(
pageParams,
useSearchForm ? getFieldsValue() : {},
searchInfo,
opt?.searchInfo || searchFormData.value || {},
defSort,
sortInfo,
filterInfo,
opt?.sortInfo ?? {},
opt?.filterInfo ?? {}
);
if (beforeFetch && isFunction(beforeFetch)) {
params = (await beforeFetch(params)) || params;
}
const res = await api(params);
rawDataSourceRef.value = res;
const isArrayResult = Array.isArray(res);
let resultItems: Recordable[] = isArrayResult ? res : get(res, listField);
const resultTotal: number = isArrayResult ? res.length : get(res, totalField);
// 假如数据变少导致总页数变少并小于当前选中页码通过getPaginationRef获取到的页码是不正确的需获取正确的页码再次执行
if (resultTotal) {
const currentTotalPage = Math.ceil(resultTotal / pageSize);
if (current > currentTotalPage) {
setPagination({
current: currentTotalPage
});
return await fetch(opt);
}
}
if (afterFetch && isFunction(afterFetch)) {
resultItems = (await afterFetch(resultItems)) || resultItems;
}
dataSourceRef.value = resultItems;
setPagination({
total: resultTotal || 0
});
if (opt && opt.page) {
setPagination({
current: opt.page || 1
});
}
emit("fetch-success", {
items: unref(resultItems),
total: resultTotal
});
return resultItems;
} catch (error) {
emit("fetch-error", error);
dataSourceRef.value = [];
setPagination({
total: 0
});
} finally {
setLoading(false);
}
}
function setTableData<T = Recordable>(values: T[]) {
dataSourceRef.value = values;
}
function getDataSource<T = Recordable>() {
return getDataSourceRef.value as T[];
}
function getRawDataSource<T = Recordable>() {
return rawDataSourceRef.value as T;
}
async function reload(opt?: FetchParams) {
return await fetch(opt);
}
function setSearchFormData(data) {
searchFormData.value = data;
}
onMounted(() => {
useTimeoutFn(() => {
unref(propsRef).immediate && fetch();
}, 16);
});
return {
getDataSourceRef,
getDataSource,
getRawDataSource,
getRowKey,
setTableData,
getAutoCreateKey,
fetch,
reload,
updateTableData,
updateTableDataRecord,
deleteTableDataRecord,
insertTableDataRecord,
findTableDataRecord,
handleTableChange,
setSearchFormData
};
}