import { callable, isArray } from 'mixlea-utils-js'; import { type CellClickExtensionConfig, cellClickExtension } from './cell-click'; import { type CellRequiredConfig, cellRequired } from './cell-required'; import { type ColumnHiddenConfig, columnHidden } from './column-hidden'; import { type ColumnVisibleConfig, columnVisible } from './column-visible'; import type { MlBaseFormColumn, MlBaseFormProps } from '@/components/ml-base-form'; import type { JSXElement, Nullable } from '@/components/types'; import { headerLeftSlotExtension, type HeaderLeftSlotExtensionConfig } from './header-left-slot'; import { footerRightSlotExtension, type FooterRightSlotExtensionConfig } from './footer-right-slot'; import { footerLeftSlotExtension, type FooterLeftSlotExtensionConfig } from './footer-left-slot'; import { headerRightSlotExtension, type HeaderRightSlotExtensionConfig } from './header-right-slot'; import type { MlFormProps } from '../types'; import { headerLeftButtonListExtension, type HeaderLeftButtonListExtensionConfig } from './header-left-button-list'; import { headerRightButtonListExtension, type HeaderRightButtonListExtensionConfig } from './header-right-button-list'; import { footerLeftButtonListExtension, type FooterLeftButtonListExtensionConfig } from './footer-left-button-list'; import { footerRightButtonListExtension, type FooterRightButtonListExtensionConfig } from './footer-right-button-list'; import type { UseCallbackStateSetter } from 'mixlea-hooks-react'; import { useCallbackState } from 'mixlea-hooks-react'; type PipelineTransform = (input: T) => T; export interface PipelineExtensions { cellRequired?: CellRequiredConfig; columnHidden?: ColumnHiddenConfig; columnVisible?: ColumnVisibleConfig; cellClick?: CellClickExtensionConfig; headerLeftSlot?: HeaderLeftSlotExtensionConfig; headerRightSlot?: HeaderRightSlotExtensionConfig; footerLeftSlot?: FooterLeftSlotExtensionConfig; footerRightSlot?: FooterRightSlotExtensionConfig; headerLeftButtonList?: HeaderLeftButtonListExtensionConfig; headerRightButtonList?: HeaderRightButtonListExtensionConfig; footerLeftButtonList?: FooterLeftButtonListExtensionConfig; footerRightButtonList?: FooterRightButtonListExtensionConfig; } interface PipelineCtx { extensions?: PipelineExtensions; [key: string]: any; } interface PipelineState { formData: MlBaseFormProps['formData']; cellRequired?: string[]; headerLeftSlot?: any; headerRightSlot?: any; footerLeftSlot?: any; footerRightSlot?: any; headerLeftButtonList?: any; headerRightButtonList?: any; footerLeftButtonList?: any; footerRightButtonList?: any; } export type { PipelineState }; export class Pipeline { public ctx: PipelineCtx = {}; private readonly _state: PipelineState; private readonly _setState: UseCallbackStateSetter; private _formData: Nullable = null; private _columns: MlBaseFormColumn[] = []; private _headerLeftSlots: MlBaseFormProps['headerLeftSlots']; private _headerRightSlots: MlBaseFormProps['headerRightSlots']; private _footerLeftSlots: MlBaseFormProps['footerLeftSlots']; private _footerRightSlots: MlBaseFormProps['footerRightSlots']; public constructor({ extensions, columns, state, setState, headerLeftSlot, headerRightSlot, footerLeftSlot, footerRightSlot, }: Pick & { columns: MlBaseFormColumn[]; extensions: PipelineExtensions; state: PipelineState; setState: UseCallbackStateSetter; }) { this._columns = columns; this._state = state; this._setState = setState; this.ctx.extensions = extensions; if (headerLeftSlot) { this._headerLeftSlots = [headerLeftSlot]; } if (headerRightSlot) { this._headerRightSlots = [headerRightSlot]; } if (footerLeftSlot) { this._footerLeftSlots = [footerLeftSlot]; } if (footerRightSlot) { this._footerRightSlots = [footerRightSlot]; } } public use(step: (pipeline: this) => this) { return step(this); } /** 获取数据源 */ public getFormData() { return this._formData ?? this._state.formData ?? {}; } /** 获取项配置 */ public getColumns() { return this._columns; } /** 获取状态 */ public getState() { return this._state; } /** 设置状态 */ public setState(nextState: Parameters>[0]) { return this._setState(nextState); } /** 根据键获取状态 */ public getStateAtKey(stateKey: K): PipelineState[K] { return this._state[stateKey]; } /** 根据键设置状态 */ public setStateAtKey(stateKey: K, state: PipelineState[K]) { return this._setState((prev) => ({ ...prev, [stateKey]: state })); } /** 设置部分状态 */ public setPartialState(state: Partial | ((state: PipelineState) => Partial)) { return this._setState((prev) => ({ ...prev, ...callable(state, prev) })); } /** 转换 columns */ public mapColumns(mapper: PipelineTransform) { return this.inputColumns(mapper(this.getColumns())); } /** 设置 formData */ public inputFormData(formData: Record) { this._formData = formData; return this; } /** 设置 columns */ public inputColumns(cols: MlBaseFormColumn[]) { this._columns = cols; return this; } public appendHeaderLeftSlots(slot: () => JSXElement) { if (isArray(this._headerLeftSlots)) { this._headerLeftSlots.push(slot); } else { this._headerLeftSlots = [slot]; } } public appendHeaderRightSlots(slot: () => JSXElement) { if (isArray(this._headerRightSlots)) { this._headerRightSlots.push(slot); } else { this._headerRightSlots = [slot]; } } public appendFooterLeftSlots(slot: () => JSXElement) { if (isArray(this._footerLeftSlots)) { this._footerLeftSlots.push(slot); } else { this._footerLeftSlots = [slot]; } } public appendFooterRightSlots(slot: () => JSXElement) { if (isArray(this._footerRightSlots)) { this._footerRightSlots.push(slot); } else { this._footerRightSlots = [slot]; } } /** 生成 props */ public buildProps() { const result: Omit & { columns: MlBaseFormColumn[]; } = { formData: this.getFormData(), columns: this.getColumns(), headerLeftSlots: this._headerLeftSlots, headerRightSlots: this._headerRightSlots, footerLeftSlots: this._footerLeftSlots, footerRightSlots: this._footerRightSlots, }; return result; } } export function usePipeline({ defaultFormData = {}, columns, extensions = {}, headerLeftSlot, headerRightSlot, footerLeftSlot, footerRightSlot, }: Pick & { defaultFormData?: Record; columns: MlBaseFormColumn[]; extensions?: PipelineExtensions; }) { const [state, setState] = useCallbackState(() => ({ formData: defaultFormData, })); return new Pipeline({ columns, state: state, setState, extensions, headerLeftSlot, headerRightSlot, footerLeftSlot, footerRightSlot, }) .use(columnHidden(extensions.columnHidden)) .use(columnVisible(extensions.columnVisible)) .use(cellRequired(extensions.cellRequired)) .use(cellClickExtension(extensions.cellClick)) .use(headerLeftSlotExtension(extensions.headerLeftSlot)) .use(headerRightSlotExtension(extensions.headerRightSlot)) .use(footerLeftSlotExtension(extensions.footerLeftSlot)) .use(footerRightSlotExtension(extensions.footerRightSlot)) .use(headerLeftButtonListExtension(extensions.headerLeftButtonList)) .use(headerRightButtonListExtension(extensions.headerRightButtonList)) .use(footerLeftButtonListExtension(extensions.footerLeftButtonList)) .use(footerRightButtonListExtension(extensions.footerRightButtonList)); }