重构前端逻辑
This commit is contained in:
parent
9acae67438
commit
03814728f1
@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState, useMemo } from 'react';
|
import React, { useEffect, useState, useMemo } from 'react';
|
||||||
import { ReactFlowProvider, ReactFlow, Background, Controls, MiniMap, Node, Edge, Handle, Position, BackgroundVariant } from '@xyflow/react';
|
import { ReactFlowProvider, ReactFlow, Background, Node, Edge, Handle, Position, BackgroundVariant } from '@xyflow/react';
|
||||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
@ -43,7 +43,7 @@ interface DeployFlowGraphModalProps {
|
|||||||
* 自定义流程节点组件
|
* 自定义流程节点组件
|
||||||
*/
|
*/
|
||||||
const CustomFlowNode: React.FC<any> = ({ data }) => {
|
const CustomFlowNode: React.FC<any> = ({ data }) => {
|
||||||
const { nodeName, nodeType, status, startTime, endTime, duration, errorMessage } = data;
|
const { nodeName, nodeType, status, startTime, endTime, duration, errorMessage, isUnreachable } = data;
|
||||||
const statusColor = getNodeStatusColor(status);
|
const statusColor = getNodeStatusColor(status);
|
||||||
const isNotStarted = status === 'NOT_STARTED';
|
const isNotStarted = status === 'NOT_STARTED';
|
||||||
const isRunning = status === 'RUNNING';
|
const isRunning = status === 'RUNNING';
|
||||||
@ -68,7 +68,8 @@ const CustomFlowNode: React.FC<any> = ({ data }) => {
|
|||||||
'px-4 py-3 rounded-md min-w-[160px] transition-all',
|
'px-4 py-3 rounded-md min-w-[160px] transition-all',
|
||||||
isNotStarted && 'border-2 border-dashed',
|
isNotStarted && 'border-2 border-dashed',
|
||||||
!isNotStarted && 'border-2 border-solid shadow-sm',
|
!isNotStarted && 'border-2 border-solid shadow-sm',
|
||||||
isRunning && 'animate-pulse'
|
isRunning && 'animate-pulse',
|
||||||
|
isUnreachable && 'opacity-40' // 不可达节点半透明
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
borderColor: statusColor,
|
borderColor: statusColor,
|
||||||
@ -399,10 +400,41 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
|||||||
return map;
|
return map;
|
||||||
}, [flowData]);
|
}, [flowData]);
|
||||||
|
|
||||||
// 转换为 React Flow 节点(按执行顺序重新布局)
|
// 计算可达节点(从已执行节点出发能到达的节点)
|
||||||
|
const reachableNodes = useMemo(() => {
|
||||||
|
if (!flowData?.graph?.edges || !flowData?.nodeInstances) return new Set<string>();
|
||||||
|
|
||||||
|
const executedNodeIds = flowData.nodeInstances
|
||||||
|
.filter(ni => ni.status !== 'NOT_STARTED')
|
||||||
|
.map(ni => ni.nodeId);
|
||||||
|
|
||||||
|
if (executedNodeIds.length === 0) return new Set<string>();
|
||||||
|
|
||||||
|
const reachable = new Set<string>(executedNodeIds);
|
||||||
|
const queue = [...executedNodeIds];
|
||||||
|
|
||||||
|
// BFS 遍历所有可达节点
|
||||||
|
while (queue.length > 0) {
|
||||||
|
const currentId = queue.shift()!;
|
||||||
|
const outgoingEdges = flowData.graph.edges.filter(e => e.from === currentId);
|
||||||
|
|
||||||
|
for (const edge of outgoingEdges) {
|
||||||
|
if (!reachable.has(edge.to)) {
|
||||||
|
reachable.add(edge.to);
|
||||||
|
queue.push(edge.to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return reachable;
|
||||||
|
}, [flowData]);
|
||||||
|
|
||||||
|
// 转换为 React Flow 节点(显示所有节点,但对不可达节点置灰)
|
||||||
const flowNodes: Node[] = useMemo(() => {
|
const flowNodes: Node[] = useMemo(() => {
|
||||||
if (!flowData?.graph?.nodes || !flowData?.nodeInstances) return [];
|
if (!flowData?.graph?.nodes || !flowData?.nodeInstances) return [];
|
||||||
|
|
||||||
|
const isRunning = flowData.runningNodeCount > 0;
|
||||||
|
|
||||||
// 按执行顺序排序已执行的节点
|
// 按执行顺序排序已执行的节点
|
||||||
const executedInstances = flowData.nodeInstances
|
const executedInstances = flowData.nodeInstances
|
||||||
.filter(ni => ni.status !== 'NOT_STARTED')
|
.filter(ni => ni.status !== 'NOT_STARTED')
|
||||||
@ -412,12 +444,14 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
|||||||
return timeA - timeB;
|
return timeA - timeB;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 创建节点位置映射(已执行的节点)
|
// 线性布局:从左到右排列
|
||||||
const nodePositionMap = new Map<string, { x: number; y: number }>();
|
const nodePositionMap = new Map<string, { x: number; y: number }>();
|
||||||
const horizontalSpacing = 250;
|
const horizontalSpacing = 300; // 水平间距
|
||||||
const startX = 50;
|
const verticalSpacing = 150; // 垂直间距(用于分支)
|
||||||
const startY = 150;
|
const startX = 100; // 起始X坐标
|
||||||
|
const startY = 150; // 起始Y坐标
|
||||||
|
|
||||||
|
// 已执行的节点:从左到右线性排列
|
||||||
executedInstances.forEach((instance, index) => {
|
executedInstances.forEach((instance, index) => {
|
||||||
nodePositionMap.set(instance.nodeId, {
|
nodePositionMap.set(instance.nodeId, {
|
||||||
x: startX + index * horizontalSpacing,
|
x: startX + index * horizontalSpacing,
|
||||||
@ -425,19 +459,31 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 为所有节点生成位置(包括未执行的)
|
// 未执行的节点:根据在图中的位置和层级布局
|
||||||
|
const notStartedNodes = flowData.graph.nodes.filter(
|
||||||
|
node => !nodePositionMap.has(node.id)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 简单布局:按节点在edges中的出现顺序,从左到右、上到下排列
|
||||||
|
let currentX = startX + executedInstances.length * horizontalSpacing;
|
||||||
|
let currentRow = 0;
|
||||||
|
const nodesPerRow = 3;
|
||||||
|
|
||||||
|
notStartedNodes.forEach((node, index) => {
|
||||||
|
const row = Math.floor(index / nodesPerRow);
|
||||||
|
const col = index % nodesPerRow;
|
||||||
|
nodePositionMap.set(node.id, {
|
||||||
|
x: currentX + col * horizontalSpacing,
|
||||||
|
y: startY + row * verticalSpacing,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 生成所有节点
|
||||||
return flowData.graph.nodes.map((node) => {
|
return flowData.graph.nodes.map((node) => {
|
||||||
const instance = nodeInstanceMap.get(node.id);
|
const instance = nodeInstanceMap.get(node.id);
|
||||||
|
const position = nodePositionMap.get(node.id) || { x: 0, y: 0 };
|
||||||
// 如果节点已执行,使用计算的位置;否则使用原始位置但偏移到下方
|
const isReachable = reachableNodes.has(node.id);
|
||||||
let position = nodePositionMap.get(node.id);
|
const isNotStarted = !instance || instance.status === 'NOT_STARTED';
|
||||||
if (!position) {
|
|
||||||
// 未执行的节点放在下方,使用原始相对位置
|
|
||||||
position = {
|
|
||||||
x: node.position.x + 500,
|
|
||||||
y: node.position.y + 400,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: node.id,
|
id: node.id,
|
||||||
@ -451,51 +497,90 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
|||||||
endTime: instance?.endTime,
|
endTime: instance?.endTime,
|
||||||
duration: instance?.duration,
|
duration: instance?.duration,
|
||||||
errorMessage: instance?.errorMessage,
|
errorMessage: instance?.errorMessage,
|
||||||
|
// 新增:不可达且未执行的节点标记为置灰
|
||||||
|
isUnreachable: isRunning && isNotStarted && !isReachable,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}, [flowData, nodeInstanceMap]);
|
}, [flowData, nodeInstanceMap, reachableNodes]);
|
||||||
|
|
||||||
// 转换为 React Flow 边
|
// 转换为 React Flow 边
|
||||||
const flowEdges: Edge[] = useMemo(() => {
|
const flowEdges: Edge[] = useMemo(() => {
|
||||||
if (!flowData?.graph?.edges) return [];
|
if (!flowData?.graph?.edges) return [];
|
||||||
|
|
||||||
return flowData.graph.edges.map((edge, index) => {
|
const isRunning = flowData.runningNodeCount > 0;
|
||||||
const source = edge.from;
|
const displayedNodeIds = new Set(flowNodes.map(n => n.id));
|
||||||
const target = edge.to;
|
|
||||||
const sourceInstance = nodeInstanceMap.get(source);
|
|
||||||
const sourceStatus = sourceInstance?.status || 'NOT_STARTED';
|
|
||||||
|
|
||||||
// 根据源节点状态确定边的颜色
|
|
||||||
let strokeColor = '#d1d5db'; // 默认灰色
|
|
||||||
if (sourceStatus === 'COMPLETED') {
|
|
||||||
strokeColor = '#10b981'; // 绿色
|
|
||||||
} else if (sourceStatus === 'FAILED') {
|
|
||||||
strokeColor = '#ef4444'; // 红色
|
|
||||||
} else if (sourceStatus === 'RUNNING') {
|
|
||||||
strokeColor = '#3b82f6'; // 蓝色
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return flowData.graph.edges
|
||||||
id: edge.id || `edge-${source}-${target}-${index}`,
|
.filter(edge => {
|
||||||
source,
|
// 只显示连接已显示节点的边
|
||||||
target,
|
return displayedNodeIds.has(edge.from) && displayedNodeIds.has(edge.to);
|
||||||
type: 'smoothstep',
|
})
|
||||||
// 不显示边的标签(条件表达式等)
|
.map((edge, index) => {
|
||||||
animated: sourceStatus === 'RUNNING',
|
const source = edge.from;
|
||||||
style: {
|
const target = edge.to;
|
||||||
stroke: strokeColor,
|
const sourceInstance = nodeInstanceMap.get(source);
|
||||||
strokeWidth: 2,
|
const targetInstance = nodeInstanceMap.get(target);
|
||||||
},
|
const sourceStatus = sourceInstance?.status || 'NOT_STARTED';
|
||||||
markerEnd: {
|
const targetStatus = targetInstance?.status || 'NOT_STARTED';
|
||||||
type: 'arrowclosed',
|
|
||||||
color: strokeColor,
|
// 判断这条边是否在可达路径上
|
||||||
width: 20,
|
const isReachableEdge = reachableNodes.has(source) && reachableNodes.has(target);
|
||||||
height: 20,
|
|
||||||
},
|
// 根据节点状态确定边的样式
|
||||||
};
|
let strokeColor = '#d1d5db'; // 默认灰色
|
||||||
});
|
let strokeWidth = 2;
|
||||||
}, [flowData, nodeInstanceMap]);
|
let animated = false;
|
||||||
|
let opacity = 1;
|
||||||
|
|
||||||
|
// 源节点已完成 + 目标节点也已完成/运行中 = 绿色实线
|
||||||
|
if (sourceStatus === 'COMPLETED' && (targetStatus === 'COMPLETED' || targetStatus === 'RUNNING')) {
|
||||||
|
strokeColor = '#10b981'; // 绿色
|
||||||
|
}
|
||||||
|
// 源节点失败 = 红色
|
||||||
|
else if (sourceStatus === 'FAILED') {
|
||||||
|
strokeColor = '#ef4444'; // 红色
|
||||||
|
}
|
||||||
|
// 源节点运行中 = 蓝色动画
|
||||||
|
else if (sourceStatus === 'RUNNING') {
|
||||||
|
strokeColor = '#3b82f6'; // 蓝色
|
||||||
|
animated = true;
|
||||||
|
}
|
||||||
|
// 源节点完成 + 目标节点未开始
|
||||||
|
else if (sourceStatus === 'COMPLETED' && targetStatus === 'NOT_STARTED') {
|
||||||
|
if (isReachableEdge && isRunning) {
|
||||||
|
strokeColor = '#9ca3af'; // 浅灰色(即将执行)
|
||||||
|
} else {
|
||||||
|
strokeColor = '#d1d5db'; // 默认灰色
|
||||||
|
opacity = 0.3; // 不可达路径半透明
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 两端都未执行
|
||||||
|
else if (sourceStatus === 'NOT_STARTED' && targetStatus === 'NOT_STARTED') {
|
||||||
|
opacity = isRunning && !isReachableEdge ? 0.3 : 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: edge.id || `edge-${source}-${target}-${index}`,
|
||||||
|
source,
|
||||||
|
target,
|
||||||
|
type: 'smoothstep',
|
||||||
|
animated,
|
||||||
|
style: {
|
||||||
|
stroke: strokeColor,
|
||||||
|
strokeWidth,
|
||||||
|
opacity,
|
||||||
|
strokeDasharray: (sourceStatus === 'COMPLETED' && targetStatus === 'NOT_STARTED' && isReachableEdge) ? '5,5' : undefined,
|
||||||
|
},
|
||||||
|
markerEnd: {
|
||||||
|
type: 'arrowclosed',
|
||||||
|
color: strokeColor,
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, [flowData, nodeInstanceMap, flowNodes, reachableNodes]);
|
||||||
|
|
||||||
// 获取部署状态信息
|
// 获取部署状态信息
|
||||||
const deployStatusInfo = flowData
|
const deployStatusInfo = flowData
|
||||||
@ -559,7 +644,11 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
|||||||
nodeTypes={nodeTypes}
|
nodeTypes={nodeTypes}
|
||||||
fitView
|
fitView
|
||||||
className="bg-muted/10"
|
className="bg-muted/10"
|
||||||
fitViewOptions={{ padding: 0.15, maxZoom: 1.2 }}
|
fitViewOptions={{ padding: 0.2, maxZoom: 1, minZoom: 0.5 }}
|
||||||
|
panOnScroll={true}
|
||||||
|
zoomOnScroll={true}
|
||||||
|
zoomOnPinch={true}
|
||||||
|
preventScrolling={false}
|
||||||
>
|
>
|
||||||
<Background
|
<Background
|
||||||
variant={BackgroundVariant.Dots}
|
variant={BackgroundVariant.Dots}
|
||||||
@ -567,21 +656,6 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
|||||||
size={1}
|
size={1}
|
||||||
className="opacity-30"
|
className="opacity-30"
|
||||||
/>
|
/>
|
||||||
<Controls
|
|
||||||
className="bg-background/80 backdrop-blur-sm border shadow-sm"
|
|
||||||
showZoom={true}
|
|
||||||
showFitView={true}
|
|
||||||
showInteractive={true}
|
|
||||||
/>
|
|
||||||
<MiniMap
|
|
||||||
nodeColor={(node: any) => {
|
|
||||||
const status = node.data?.status || 'NOT_STARTED';
|
|
||||||
return getNodeStatusColor(status);
|
|
||||||
}}
|
|
||||||
className="bg-background/80 backdrop-blur-sm border shadow-sm"
|
|
||||||
pannable={true}
|
|
||||||
zoomable={true}
|
|
||||||
/>
|
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
</ReactFlowProvider>
|
</ReactFlowProvider>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -38,11 +38,13 @@ import { DeployFlowGraphModal } from './DeployFlowGraphModal';
|
|||||||
interface PendingApprovalModalProps {
|
interface PendingApprovalModalProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onOpenChange: (open: boolean) => void;
|
onOpenChange: (open: boolean) => void;
|
||||||
|
workflowDefinitionKeys?: string[]; // 工作流定义键列表
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PendingApprovalModal: React.FC<PendingApprovalModalProps> = ({
|
export const PendingApprovalModal: React.FC<PendingApprovalModalProps> = ({
|
||||||
open,
|
open,
|
||||||
onOpenChange,
|
onOpenChange,
|
||||||
|
workflowDefinitionKeys,
|
||||||
}) => {
|
}) => {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@ -59,7 +61,7 @@ export const PendingApprovalModal: React.FC<PendingApprovalModalProps> = ({
|
|||||||
const loadApprovalList = async () => {
|
const loadApprovalList = async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const response = await getMyApprovalTasks();
|
const response = await getMyApprovalTasks(workflowDefinitionKeys);
|
||||||
if (response) {
|
if (response) {
|
||||||
setApprovalList(response || []);
|
setApprovalList(response || []);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,10 +56,22 @@ const Dashboard: React.FC = () => {
|
|||||||
// 从 Redux store 中获取当前登录用户信息
|
// 从 Redux store 中获取当前登录用户信息
|
||||||
const currentUserId = useSelector((state: RootState) => state.user.userInfo?.id);
|
const currentUserId = useSelector((state: RootState) => state.user.userInfo?.id);
|
||||||
|
|
||||||
|
// 提取所有工作流定义键(去重)
|
||||||
|
const workflowDefinitionKeys = React.useMemo(() => {
|
||||||
|
const workflowKeys = teams.flatMap(team =>
|
||||||
|
team.environments.flatMap(env =>
|
||||||
|
env.applications
|
||||||
|
.map(app => app.workflowDefinitionKey)
|
||||||
|
.filter((key): key is string => !!key)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return Array.from(new Set(workflowKeys));
|
||||||
|
}, [teams]);
|
||||||
|
|
||||||
// 加载待审批数量
|
// 加载待审批数量
|
||||||
const loadPendingApprovalCount = React.useCallback(async () => {
|
const loadPendingApprovalCount = React.useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const response = await getMyApprovalTasks();
|
const response = await getMyApprovalTasks(workflowDefinitionKeys);
|
||||||
if (response) {
|
if (response) {
|
||||||
setPendingApprovalCount(response.length || 0);
|
setPendingApprovalCount(response.length || 0);
|
||||||
}
|
}
|
||||||
@ -67,7 +79,7 @@ const Dashboard: React.FC = () => {
|
|||||||
// 静默失败,不影响主页面
|
// 静默失败,不影响主页面
|
||||||
console.error('Failed to load pending approval count:', error);
|
console.error('Failed to load pending approval count:', error);
|
||||||
}
|
}
|
||||||
}, []);
|
}, [workflowDefinitionKeys]);
|
||||||
|
|
||||||
// 加载部署环境数据
|
// 加载部署环境数据
|
||||||
const loadData = React.useCallback(async (showLoading = false) => {
|
const loadData = React.useCallback(async (showLoading = false) => {
|
||||||
@ -324,12 +336,6 @@ const Dashboard: React.FC = () => {
|
|||||||
{currentTeam && (
|
{currentTeam && (
|
||||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
<span className="font-medium text-foreground">{currentTeam.teamName}</span>
|
<span className="font-medium text-foreground">{currentTeam.teamName}</span>
|
||||||
{currentTeam.teamRole && (
|
|
||||||
<>
|
|
||||||
<span>·</span>
|
|
||||||
<span>{currentTeam.teamRole}</span>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{currentTeam.description && (
|
{currentTeam.description && (
|
||||||
<>
|
<>
|
||||||
<span>·</span>
|
<span>·</span>
|
||||||
@ -453,6 +459,7 @@ const Dashboard: React.FC = () => {
|
|||||||
<PendingApprovalModal
|
<PendingApprovalModal
|
||||||
open={approvalModalOpen}
|
open={approvalModalOpen}
|
||||||
onOpenChange={setApprovalModalOpen}
|
onOpenChange={setApprovalModalOpen}
|
||||||
|
workflowDefinitionKeys={workflowDefinitionKeys}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -25,9 +25,14 @@ export const getDeployRecordFlowGraph = (deployRecordId: number) =>
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取我的待审批任务列表
|
* 获取我的待审批任务列表
|
||||||
|
* @param workflowDefinitionKeys 工作流定义键列表(可选)
|
||||||
*/
|
*/
|
||||||
export const getMyApprovalTasks = () =>
|
export const getMyApprovalTasks = (workflowDefinitionKeys?: string[]) => {
|
||||||
request.get<PendingApprovalTask[]>(`${DEPLOY_URL}/my-approval-tasks`);
|
const params = workflowDefinitionKeys && workflowDefinitionKeys.length > 0
|
||||||
|
? { workflowDefinitionKeys: workflowDefinitionKeys.join(',') }
|
||||||
|
: {};
|
||||||
|
return request.get<PendingApprovalTask[]>(`${DEPLOY_URL}/my-approval-tasks`, { params });
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 完成审批
|
* 完成审批
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
} from '@/components/ui/dialog';
|
} from '@/components/ui/dialog';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { CheckCircle2, FileText, Loader2 } from 'lucide-react';
|
import { CheckCircle2, FileText, Loader2, Rocket } from 'lucide-react';
|
||||||
import type { WorkflowDefinition } from '../types';
|
import type { WorkflowDefinition } from '../types';
|
||||||
import { getDefinitionById as getFormDefinitionById } from '@/pages/Form/Definition/List/service';
|
import { getDefinitionById as getFormDefinitionById } from '@/pages/Form/Definition/List/service';
|
||||||
import type { FormDefinitionResponse } from '@/pages/Form/Definition/List/types';
|
import type { FormDefinitionResponse } from '@/pages/Form/Definition/List/types';
|
||||||
@ -56,7 +56,7 @@ const DeployDialog: React.FC<DeployDialogProps> = ({
|
|||||||
<DialogContent className="sm:max-w-[500px]">
|
<DialogContent className="sm:max-w-[500px]">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle className="flex items-center gap-2 text-green-600">
|
<DialogTitle className="flex items-center gap-2 text-green-600">
|
||||||
<CheckCircle2 className="h-5 w-5" /> 确认发布工作流?
|
<Rocket className="h-5 w-5" /> 确认发布工作流?
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
您确定要发布工作流 "<span className="font-semibold text-foreground">{record.name}</span>" 吗?
|
您确定要发布工作流 "<span className="font-semibold text-foreground">{record.name}</span>" 吗?
|
||||||
@ -104,7 +104,7 @@ const DeployDialog: React.FC<DeployDialogProps> = ({
|
|||||||
取消
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={onConfirm}>
|
<Button onClick={onConfirm}>
|
||||||
<CheckCircle2 className="h-4 w-4 mr-2" />
|
<Rocket className="h-4 w-4 mr-2" />
|
||||||
确认发布
|
确认发布
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { Input } from '@/components/ui/input';
|
|||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { DataTablePagination } from '@/components/ui/pagination';
|
import { DataTablePagination } from '@/components/ui/pagination';
|
||||||
import {
|
import {
|
||||||
Loader2, Plus, Search, Edit, Trash2, Play, CheckCircle2,
|
Loader2, Plus, Search, Edit, Trash2, Play, CheckCircle2, Rocket,
|
||||||
Clock, Activity, Workflow, Eye, Pencil, FolderKanban
|
Clock, Activity, Workflow, Eye, Pencil, FolderKanban
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { useToast } from '@/components/ui/use-toast';
|
import { useToast } from '@/components/ui/use-toast';
|
||||||
@ -486,7 +486,7 @@ const WorkflowDefinitionList: React.FC = () => {
|
|||||||
title="发布"
|
title="发布"
|
||||||
className="text-green-600 hover:text-green-700 hover:bg-green-50"
|
className="text-green-600 hover:text-green-700 hover:bg-green-50"
|
||||||
>
|
>
|
||||||
<CheckCircle2 className="h-4 w-4" />
|
<Rocket className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@ -371,6 +371,12 @@ const NodeConfigModal: React.FC<NodeConfigModalProps> = ({
|
|||||||
return Array.isArray(currentValue) && currentValue.includes(expectedValue);
|
return Array.isArray(currentValue) && currentValue.includes(expectedValue);
|
||||||
case 'notIncludes':
|
case 'notIncludes':
|
||||||
return Array.isArray(currentValue) && !currentValue.includes(expectedValue);
|
return Array.isArray(currentValue) && !currentValue.includes(expectedValue);
|
||||||
|
case 'in':
|
||||||
|
// 检查 currentValue 是否在 expectedValue 数组中
|
||||||
|
return Array.isArray(expectedValue) && expectedValue.includes(currentValue);
|
||||||
|
case 'notIn':
|
||||||
|
// 检查 currentValue 是否不在 expectedValue 数组中
|
||||||
|
return Array.isArray(expectedValue) && !expectedValue.includes(currentValue);
|
||||||
default:
|
default:
|
||||||
return currentValue === expectedValue;
|
return currentValue === expectedValue;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user