import type { StepType, StepStatus } from '../types'; // 流程步骤配置 export interface StepConfig { type: StepType; name: string; icon: string; description: string; required: boolean; allowSkip: boolean; validate?: (data: any) => boolean | string; onComplete?: (data: any) => void; onEnter?: (data: any) => void; } // 流程引擎配置 export interface ProcessEngineConfig { steps: StepConfig[]; allowParallel: boolean; autoAdvance: boolean; requireAllCompleted: boolean; } // 流程状态 export interface ProcessState { currentStepIndex: number; completedSteps: Set; skippedSteps: Set; stepData: Record; isComplete: boolean; } // 默认步骤顺序 export const DEFAULT_STEP_ORDER: StepType[] = [ 'confirm', 'yarn_purchase', 'dyeing', 'machine_start', 'fabric_warehouse', ]; // 步骤名称映射 export const STEP_NAMES: Record = { confirm: '确认计划', yarn_purchase: '采购纱线', dyeing: '染纱', machine_start: '上机生产', fabric_warehouse: '坯布生产', }; // 步骤图标映射 export const STEP_ICONS: Record = { confirm: 'CheckCircle', yarn_purchase: 'Package', dyeing: 'Droplet', machine_start: 'Settings', fabric_warehouse: 'Warehouse', }; // 流程引擎类 export class ProcessEngine { private config: ProcessEngineConfig; private state: ProcessState; private listeners: Set<(state: ProcessState) => void> = new Set(); constructor(config: ProcessEngineConfig) { this.config = config; this.state = { currentStepIndex: 0, completedSteps: new Set(), skippedSteps: new Set(), stepData: {}, isComplete: false, }; } // 获取当前步骤 getCurrentStep(): StepConfig | null { return this.config.steps[this.state.currentStepIndex] || null; } // 获取当前步骤索引 getCurrentStepIndex(): number { return this.state.currentStepIndex; } // 获取步骤状态 getStepStatus(stepType: StepType): StepStatus { if (this.state.completedSteps.has(stepType)) { return 'completed'; } const stepIndex = this.config.steps.findIndex((s) => s.type === stepType); if (stepIndex === this.state.currentStepIndex) { return 'active'; } return 'pending'; } // 获取所有步骤 getSteps(): StepConfig[] { return this.config.steps; } // 获取流程状态 getState(): ProcessState { return { ...this.state }; } // 检查是否可以进入下一步 canAdvance(): boolean { const currentStep = this.getCurrentStep(); if (!currentStep) return false; // 如果当前步骤已完成或允许跳过 if ( this.state.completedSteps.has(currentStep.type) || this.state.skippedSteps.has(currentStep.type) ) { return true; } // 检查验证 if (currentStep.validate) { const data = this.state.stepData[currentStep.type]; const result = currentStep.validate(data); return result === true; } return !currentStep.required; } // 进入下一步 advance(): boolean { if (!this.canAdvance()) return false; const currentStep = this.getCurrentStep(); if (currentStep?.onComplete) { currentStep.onComplete(this.state.stepData[currentStep.type]); } if (this.state.currentStepIndex < this.config.steps.length - 1) { this.state.currentStepIndex++; const nextStep = this.getCurrentStep(); if (nextStep?.onEnter) { nextStep.onEnter(this.state.stepData[nextStep.type]); } } else { this.state.isComplete = true; } this.notifyListeners(); return true; } // 跳转到指定步骤 jumpToStep(stepType: StepType): boolean { const stepIndex = this.config.steps.findIndex((s) => s.type === stepType); if (stepIndex === -1) return false; // 检查是否可以跳转(只能跳转到已完成步骤的下一步) if (!this.config.allowParallel) { for (let i = 0; i < stepIndex; i++) { const step = this.config.steps[i]; if ( step.required && !this.state.completedSteps.has(step.type) && !this.state.skippedSteps.has(step.type) ) { return false; } } } this.state.currentStepIndex = stepIndex; const step = this.getCurrentStep(); if (step?.onEnter) { step.onEnter(this.state.stepData[step.type]); } this.notifyListeners(); return true; } // 完成当前步骤 completeStep(data?: any): boolean { const currentStep = this.getCurrentStep(); if (!currentStep) return false; // 验证数据 if (currentStep.validate && data !== undefined) { const result = currentStep.validate(data); if (result !== true) { return false; } } this.state.completedSteps.add(currentStep.type); if (data !== undefined) { this.state.stepData[currentStep.type] = data; } if (currentStep.onComplete) { currentStep.onComplete(data); } if (this.config.autoAdvance) { this.advance(); } this.notifyListeners(); return true; } // 跳过当前步骤 skipStep(): boolean { const currentStep = this.getCurrentStep(); if (!currentStep || !currentStep.allowSkip) return false; this.state.skippedSteps.add(currentStep.type); this.advance(); this.notifyListeners(); return true; } // 设置步骤数据 setStepData(stepType: StepType, data: any): void { this.state.stepData[stepType] = data; this.notifyListeners(); } // 获取步骤数据 getStepData(stepType: StepType): any { return this.state.stepData[stepType]; } // 重置流程 reset(): void { this.state = { currentStepIndex: 0, completedSteps: new Set(), skippedSteps: new Set(), stepData: {}, isComplete: false, }; this.notifyListeners(); } // 订阅状态变化 subscribe(listener: (state: ProcessState) => void): () => void { this.listeners.add(listener); return () => { this.listeners.delete(listener); }; } // 通知监听器 private notifyListeners(): void { this.listeners.forEach((listener) => listener(this.getState())); } } // 创建默认流程引擎 export function createDefaultProcessEngine( customSteps?: Partial[] ): ProcessEngine { const defaultSteps: StepConfig[] = DEFAULT_STEP_ORDER.map((type) => ({ type, name: STEP_NAMES[type], icon: STEP_ICONS[type], description: '', required: true, allowSkip: false, ...(customSteps?.find((s) => s.type === type) || {}), })); return new ProcessEngine({ steps: defaultSteps, allowParallel: false, autoAdvance: false, requireAllCompleted: true, }); } // React Hook 封装 import { useState, useEffect, useCallback } from 'react'; export function useProcessEngine(engine: ProcessEngine) { const [state, setState] = useState(engine.getState()); useEffect(() => { return engine.subscribe((newState) => { setState(newState); }); }, [engine]); const advance = useCallback(() => engine.advance(), [engine]); const completeStep = useCallback( (data?: any) => engine.completeStep(data), [engine] ); const skipStep = useCallback(() => engine.skipStep(), [engine]); const jumpToStep = useCallback( (stepType: StepType) => engine.jumpToStep(stepType), [engine] ); const setStepData = useCallback( (stepType: StepType, data: any) => engine.setStepData(stepType, data), [engine] ); const reset = useCallback(() => engine.reset(), [engine]); return { state, currentStep: engine.getCurrentStep(), currentStepIndex: engine.getCurrentStepIndex(), steps: engine.getSteps(), getStepStatus: engine.getStepStatus.bind(engine), canAdvance: engine.canAdvance.bind(engine), advance, completeStep, skipStep, jumpToStep, setStepData, reset, }; }