增加审批组件
This commit is contained in:
parent
114d549a5c
commit
50c8b4240b
@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* 表单预览弹窗组件
|
||||||
|
* 用于在工作流设计页面预览启动表单
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
} from '@/components/ui/dialog';
|
||||||
|
import { FormRenderer } from '@/components/FormDesigner';
|
||||||
|
import type { FormDefinitionResponse } from '@/pages/Form/Definition/types';
|
||||||
|
|
||||||
|
interface FormPreviewModalProps {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
formDefinition: FormDefinitionResponse | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FormPreviewModal: React.FC<FormPreviewModalProps> = ({
|
||||||
|
open,
|
||||||
|
onClose,
|
||||||
|
formDefinition
|
||||||
|
}) => {
|
||||||
|
if (!formDefinition) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onOpenChange={onClose}>
|
||||||
|
<DialogContent className="max-w-5xl max-h-[90vh] overflow-y-auto">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>
|
||||||
|
预览表单:{formDefinition.name}
|
||||||
|
{formDefinition.description && (
|
||||||
|
<span className="text-sm font-normal text-muted-foreground ml-2">
|
||||||
|
{formDefinition.description}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<div className="py-4">
|
||||||
|
<FormRenderer
|
||||||
|
schema={formDefinition.schema}
|
||||||
|
readonly={false}
|
||||||
|
showSubmit={false}
|
||||||
|
showCancel={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-xs text-muted-foreground border-t pt-3 space-y-1">
|
||||||
|
<div>表单标识:{formDefinition.key}</div>
|
||||||
|
<div>表单版本:v{formDefinition.formVersion}</div>
|
||||||
|
<div>状态:
|
||||||
|
<span className={`ml-1 ${
|
||||||
|
formDefinition.status === 'PUBLISHED' ? 'text-green-600' :
|
||||||
|
formDefinition.status === 'DRAFT' ? 'text-yellow-600' :
|
||||||
|
'text-gray-600'
|
||||||
|
}`}>
|
||||||
|
{formDefinition.status === 'PUBLISHED' ? '已发布' :
|
||||||
|
formDefinition.status === 'DRAFT' ? '草稿' :
|
||||||
|
formDefinition.status}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FormPreviewModal;
|
||||||
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Save, Undo, Redo, ZoomIn, ZoomOut, Maximize2, ArrowLeft } from 'lucide-react';
|
import { Save, Undo, Redo, ZoomIn, ZoomOut, Maximize2, ArrowLeft, Eye } from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Separator } from '@/components/ui/separator';
|
import { Separator } from '@/components/ui/separator';
|
||||||
import {
|
import {
|
||||||
@ -12,6 +12,8 @@ import {
|
|||||||
interface WorkflowToolbarProps {
|
interface WorkflowToolbarProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
onSave?: () => void;
|
onSave?: () => void;
|
||||||
|
onPreviewForm?: () => void;
|
||||||
|
hasFormDefinition?: boolean;
|
||||||
onUndo?: () => void;
|
onUndo?: () => void;
|
||||||
onRedo?: () => void;
|
onRedo?: () => void;
|
||||||
onZoomIn?: () => void;
|
onZoomIn?: () => void;
|
||||||
@ -27,6 +29,8 @@ interface WorkflowToolbarProps {
|
|||||||
const WorkflowToolbar: React.FC<WorkflowToolbarProps> = ({
|
const WorkflowToolbar: React.FC<WorkflowToolbarProps> = ({
|
||||||
title = '工作流设计器',
|
title = '工作流设计器',
|
||||||
onSave,
|
onSave,
|
||||||
|
onPreviewForm,
|
||||||
|
hasFormDefinition = false,
|
||||||
onUndo,
|
onUndo,
|
||||||
onRedo,
|
onRedo,
|
||||||
onZoomIn,
|
onZoomIn,
|
||||||
@ -146,6 +150,23 @@ const WorkflowToolbar: React.FC<WorkflowToolbarProps> = ({
|
|||||||
|
|
||||||
<Separator orientation="vertical" className="h-6 mx-2" />
|
<Separator orientation="vertical" className="h-6 mx-2" />
|
||||||
|
|
||||||
|
{/* 预览表单按钮 */}
|
||||||
|
{hasFormDefinition && (
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={onPreviewForm}
|
||||||
|
className="gap-1.5"
|
||||||
|
>
|
||||||
|
<Eye className="h-4 w-4" />
|
||||||
|
预览表单
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>预览启动表单</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* 保存按钮(最右侧) */}
|
{/* 保存按钮(最右侧) */}
|
||||||
<Button
|
<Button
|
||||||
onClick={onSave}
|
onClick={onSave}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import NodePanel from './components/NodePanel';
|
|||||||
import FlowCanvas from './components/FlowCanvas';
|
import FlowCanvas from './components/FlowCanvas';
|
||||||
import NodeConfigModal from './components/NodeConfigModal';
|
import NodeConfigModal from './components/NodeConfigModal';
|
||||||
import EdgeConfigModal, { type EdgeCondition } from './components/EdgeConfigModal';
|
import EdgeConfigModal, { type EdgeCondition } from './components/EdgeConfigModal';
|
||||||
|
import FormPreviewModal from './components/FormPreviewModal';
|
||||||
import type { FlowNode, FlowEdge, FlowNodeData } from './types';
|
import type { FlowNode, FlowEdge, FlowNodeData } from './types';
|
||||||
import type { WorkflowNodeDefinition } from './nodes/types';
|
import type { WorkflowNodeDefinition } from './nodes/types';
|
||||||
import { isConfigurableNode } from './nodes/types';
|
import { isConfigurableNode } from './nodes/types';
|
||||||
@ -15,6 +16,8 @@ import { useWorkflowSave } from './hooks/useWorkflowSave';
|
|||||||
import { useWorkflowLoad } from './hooks/useWorkflowLoad';
|
import { useWorkflowLoad } from './hooks/useWorkflowLoad';
|
||||||
import { useHistory } from './hooks/useHistory';
|
import { useHistory } from './hooks/useHistory';
|
||||||
import { generateNodeId, generateEdgeId } from './utils/idGenerator';
|
import { generateNodeId, generateEdgeId } from './utils/idGenerator';
|
||||||
|
import { getDefinitionById as getFormDefinitionById } from '@/pages/Form/Definition/service';
|
||||||
|
import type { FormDefinitionResponse } from '@/pages/Form/Definition/types';
|
||||||
|
|
||||||
// 样式
|
// 样式
|
||||||
import '@xyflow/react/dist/style.css';
|
import '@xyflow/react/dist/style.css';
|
||||||
@ -50,6 +53,10 @@ const WorkflowDesignInner: React.FC = () => {
|
|||||||
const [edgeConfigModalVisible, setEdgeConfigModalVisible] = useState(false);
|
const [edgeConfigModalVisible, setEdgeConfigModalVisible] = useState(false);
|
||||||
const [configEdge, setConfigEdge] = useState<FlowEdge | null>(null);
|
const [configEdge, setConfigEdge] = useState<FlowEdge | null>(null);
|
||||||
|
|
||||||
|
// 表单定义数据和预览弹窗状态
|
||||||
|
const [formDefinition, setFormDefinition] = useState<FormDefinitionResponse | null>(null);
|
||||||
|
const [formPreviewVisible, setFormPreviewVisible] = useState(false);
|
||||||
|
|
||||||
// 保存和加载hooks
|
// 保存和加载hooks
|
||||||
const { hasUnsavedChanges, saveWorkflow, markUnsaved } = useWorkflowSave();
|
const { hasUnsavedChanges, saveWorkflow, markUnsaved } = useWorkflowSave();
|
||||||
const { workflowDefinition, loadWorkflow } = useWorkflowLoad();
|
const { workflowDefinition, loadWorkflow } = useWorkflowLoad();
|
||||||
@ -69,6 +76,19 @@ const WorkflowDesignInner: React.FC = () => {
|
|||||||
setNodes(data.nodes);
|
setNodes(data.nodes);
|
||||||
setEdges(data.edges);
|
setEdges(data.edges);
|
||||||
setWorkflowTitle(data.definition?.name || '未命名工作流');
|
setWorkflowTitle(data.definition?.name || '未命名工作流');
|
||||||
|
|
||||||
|
// 如果工作流关联了表单,加载表单定义数据
|
||||||
|
if (data.definition?.formDefinitionId) {
|
||||||
|
try {
|
||||||
|
const formDef = await getFormDefinitionById(data.definition.formDefinitionId);
|
||||||
|
setFormDefinition(formDef);
|
||||||
|
console.log('表单定义数据已加载:', formDef);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载表单定义失败:', error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setFormDefinition(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -125,6 +145,16 @@ const WorkflowDesignInner: React.FC = () => {
|
|||||||
navigate('/workflow/definition');
|
navigate('/workflow/definition');
|
||||||
}, [navigate]);
|
}, [navigate]);
|
||||||
|
|
||||||
|
// 预览表单
|
||||||
|
const handlePreviewForm = useCallback(() => {
|
||||||
|
if (!formDefinition) {
|
||||||
|
message.warning('当前工作流未关联启动表单');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setFormPreviewVisible(true);
|
||||||
|
}, [formDefinition]);
|
||||||
|
|
||||||
// 撤销操作
|
// 撤销操作
|
||||||
const handleUndo = useCallback(() => {
|
const handleUndo = useCallback(() => {
|
||||||
const state = history.undo();
|
const state = history.undo();
|
||||||
@ -494,6 +524,8 @@ const WorkflowDesignInner: React.FC = () => {
|
|||||||
title={`${workflowTitle}${hasUnsavedChanges ? ' *' : ''}`}
|
title={`${workflowTitle}${hasUnsavedChanges ? ' *' : ''}`}
|
||||||
onSave={handleSave}
|
onSave={handleSave}
|
||||||
onBack={handleBack}
|
onBack={handleBack}
|
||||||
|
onPreviewForm={handlePreviewForm}
|
||||||
|
hasFormDefinition={!!formDefinition}
|
||||||
onUndo={handleUndo}
|
onUndo={handleUndo}
|
||||||
onRedo={handleRedo}
|
onRedo={handleRedo}
|
||||||
onZoomIn={handleZoomIn}
|
onZoomIn={handleZoomIn}
|
||||||
@ -545,6 +577,13 @@ const WorkflowDesignInner: React.FC = () => {
|
|||||||
onOk={handleEdgeConditionUpdate}
|
onOk={handleEdgeConditionUpdate}
|
||||||
onCancel={handleCloseEdgeConfigModal}
|
onCancel={handleCloseEdgeConfigModal}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* 表单预览弹窗 */}
|
||||||
|
<FormPreviewModal
|
||||||
|
open={formPreviewVisible}
|
||||||
|
onClose={() => setFormPreviewVisible(false)}
|
||||||
|
formDefinition={formDefinition}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user