import { debounce } from 'lodash' import { computed, ref, watch, type Ref, } from 'vue' import { type CachedTableColumn, type CachedTableData, type ColumnInterface, type ComputedColumnInterface, } from '../DefaultTableInterfaces' import { filterDeserializationFabric, filterFabric } from '../filters/Filters' import { type FilterData } from '../filters/Filters' export default function useColumns( sourceColumns: Ref, defaultQueryParams: Record, cacheKey?: string, saveDefaultFilterValueOnReset?: boolean, ) { const calculateColumns = (sourceColumns: ColumnInterface[], alreadyCreatedColumns: ComputedColumnInterface[]) => { const cachedData: CachedTableData = cacheKey && localStorage.getItem(cacheKey) ? JSON.parse(localStorage.getItem(cacheKey) as string) : undefined return sourceColumns .filter(({ condition }) => typeof condition === 'undefined' || condition()) .map((column, order) => { const cachedColumn: CachedTableColumn | undefined = column.isStatic ? cachedData?.columns?.find((cachedColumn) => column.name === cachedColumn.name) : undefined const cachedFilter = cachedColumn && cachedColumn.filter ? filterDeserializationFabric(cachedColumn.filter) : null const currentFilter = filterFabric(column) const areCachedAndCurrentFilterTheSameType = cachedFilter && cachedFilter.constructor.name === currentFilter.constructor.name if (cachedFilter && !areCachedAndCurrentFilterTheSameType) { console.error(`Тип фильтра в колонке ${column.name} был изменен с ${cachedFilter.constructor.name} на ${currentFilter.constructor.name}. Кешированные данные фильтра будут стерты`) } const filter = areCachedAndCurrentFilterTheSameType ? cachedFilter : currentFilter const hash = JSON.stringify(column) const alreadyCreatedColumn = alreadyCreatedColumns.find((c) => c.hash === hash) if (alreadyCreatedColumn) { alreadyCreatedColumn.order = order return alreadyCreatedColumn } return { hash, ...column, overflow: column.overflow || 'hidden', header: { saveDefaultFilterValueOnReset, ...column.header, }, defaultOrder: order, isResizing: false, width: cachedColumn?.width ?? (column.width || 200), defaultWidth: cachedColumn?.width ?? (column.width || 200), order: cachedColumn?.order ?? order, isVisible: cachedColumn ? cachedColumn.isVisible : typeof column.visibleByDefault === 'undefined' || column.visibleByDefault, filter, wasResized: cachedColumn ? cachedColumn.wasResized : false, horizontalEyesight: cachedColumn?.horizontalEyesight ?? (column.horizontalEyesight || undefined), } as ComputedColumnInterface }) } const columns: Ref = ref([]) columns.value = calculateColumns(sourceColumns.value, columns.value) watch(sourceColumns, () => { const newColumns = calculateColumns(sourceColumns.value, columns.value) const alreadyCreatedColumnsWithFilter = columns.value.filter((c) => c.filter.hasValues() && (newColumns.indexOf(c) === -1)) columns.value = [...newColumns, ...alreadyCreatedColumnsWithFilter] }) const computedColumns: Ref = computed(() => columns.value.filter((column) => column.isVisible).sort((a, b) => a.order - b.order)) const params = computed((): FilterData[] => { const smartFilterParams: FilterData[] = [] columns.value.forEach((column) => { Object.entries(column.filter.getQueryParams()).forEach(([k, v]) => { smartFilterParams.push({ code: k, value: Array.isArray(v) ? v.map((v) => String(v)) : String(v), column, }) }) }) Object.entries(defaultQueryParams).forEach(([code, value]) => { smartFilterParams.push({ code, value, column: undefined, }) }) return smartFilterParams }) const makeCache = debounce(() => { const cachedColumns: CachedTableColumn[] = columns.value.map((column) => ({ name: column.name, isVisible: column.isVisible, order: column.order, width: column.width, filter: column.filter.serialize(), wasResized: column.wasResized, horizontalEyesight: column.horizontalEyesight, })) const cachedData: CachedTableData = { columns: cachedColumns } localStorage.setItem(cacheKey as string, JSON.stringify(cachedData)) }, 500) if (cacheKey) { watch(columns, makeCache, { deep: true }) } return { columns, computedColumns, params } }