import React, { useCallback, useImperativeHandle, forwardRef, useState, useMemo, useEffect } from 'react'; import type { ForwardedRef, Key } from 'react'; import { useMount } from '@fortissimo/hook'; import { checkFormEmpty } from '@fortissimo/util'; import type { SizeType } from 'antd/lib/config-provider/SizeContext'; import { DataList } from '../index'; import type { DataListTableMsg, DataListOptConfig, DataListRowData, OptEditFormField, RecordData, KeyType, ValueType } from '../index'; export type DataListProAllOptPosition = 'header' | 'row' | 'both'; export interface DataListProAllOptConfig< K extends string = string, T extends RecordData = RecordData > extends DataListOptConfig { position?: DataListProAllOptPosition; needSelect?: boolean; } export interface DataListProAllOptParams< K extends string = string, T extends RecordData = RecordData > { optKey: K; rowKey?: Key; rowsKey: Key[]; rowData?: T; rowsData: T[]; } export type DataListProAllMsgConfig = DataListTableMsg>; export type DataListProAllSearchConfig = OptEditFormField>; export type DataListProAllGetDataParams = Partial; export type DataListProAllGetDataRes = Partial[]; export interface DataListProAllProps< OPTK extends string = string, T extends RecordData = RecordData, S extends RecordData = RecordData > { msgs: DataListProAllMsgConfig>[]; rowKey: KeyType; disabledCheckedKey?: Key[]; opts?: DataListProAllOptConfig[]; optWidth?: number | string; search?: DataListProAllSearchConfig[]; canExport?: boolean; canTotalExport?: boolean; searchLabelCol?: number | null; searchColNum?: number; canSelect?: boolean; defaultSelectedValue?: ValueType[]; selectType?: 'checkbox' | 'radio'; size?: SizeType; unFixOpt?: boolean; unFixHeader?: boolean; fixedColumnWidth?: boolean; resizeBaseWidth?: number; emptyText?: string; onGetData?: ( params: DataListProAllGetDataParams ) => Promise>; onExportData?: (params: Partial) => Promise; onOpt?: ( params: DataListProAllOptParams> ) => Promise | void; onExpandData?: (params: Partial) => Promise; onSelect?: (keys?: any[], rows?: DataListRowData[]) => Promise; } export const DataListProAll = forwardRef(function ( props: DataListProAllProps, ref: ForwardedRef ) { const rowKey = useMemo(() => props.rowKey || 'id', [props.rowKey]); const [data, setData] = useState([]); const [selectedValue, setSelectedValue] = useState( props.defaultSelectedValue || [] ); const [selectedRows, setSelectedRows] = useState([]); const [searchData, setSearchData] = useState>>( {} ); const opts = useMemo(() => { const data: { header: DataListOptConfig[]; row: DataListOptConfig[]; } = { header: [], row: [] }; if (!props.opts) return data; props.opts.forEach((item) => { if (item.position === 'header' || item.position === 'both') { data.header.push({ ...item, disabled: item.disabled || (item.needSelect && selectedValue.length === 0) }); } if (item.position === 'row' || item.position === 'both') { data.row.push({ ...item, icon: undefined }); } }); return data; }, [props.opts, selectedValue]); const getData = useCallback( async (params: DataListProAllGetDataParams) => { setSelectedValue([]); setSelectedRows([]); if (!props.onGetData) return; const res = await props.onGetData(params || searchData); setData(res); }, [props, searchData] ); const [exportLoading, setExportLoading] = useState(false); const [exportDisabled, setExportDisabled] = useState(!props.canTotalExport); useEffect(() => { if (props.canTotalExport) setExportDisabled(false); }, [props.canTotalExport]); const exportData = useCallback( async (params?: Partial) => { if (!props.onExportData) return; const data = params || searchData; setExportLoading(true); try { await props.onExportData(data); setExportLoading(false); } catch (e) { setExportLoading(false); } }, [searchData, props] ); const opt = useCallback( async (params: DataListProAllOptParams) => { props.onOpt && (await props.onOpt(params)); }, [props] ); useImperativeHandle(ref, () => ({ getData, opt, getSelectedValue: () => selectedValue, getSelectedRows: () => selectedRows, setSelectedValue: (value: any[]) => { setSelectedValue(value); const newData: DataListRowData[] = []; data.forEach((item) => { if (value.includes(item[props.rowKey])) newData.push(item); }); setSelectedRows(newData); } })); useMount(async () => { await getData({}); const newData: DataListRowData[] = []; data.forEach((item) => { if (selectedValue.includes(item[props.rowKey])) newData.push(item); }); setSelectedRows(newData); }); return ( <> { setSearchData(data); if (optKey === 'export') await exportData(data); else { if (optKey === 'reset' && !props.canTotalExport) { setExportDisabled(checkFormEmpty(data)); } await getData(data); } }} headerOpts={opts.header} onHeaderOpt={async (optKey) => { await opt({ optKey, rowsKey: selectedValue, rowsData: selectedRows }); }} onValueChange={(value) => { if (props.canTotalExport) return; setExportDisabled(checkFormEmpty(value)); }} /> { setSelectedValue(keys || []); setSelectedRows(rows || []); props.onSelect && props.onSelect(keys, rows); }} onOpt={async (optKey, rowKey, rowData) => { await opt({ optKey, rowKey, rowsKey: [rowKey], rowData, rowsData: [rowData] }); }} onExpand={async (open, item) => { if (!props.onExpandData) return; if (!open) return; if (item.children?.length > 0) return; await props.onExpandData(item); }} /> ); });