动火作业

master
LiuJiaNan 2026-03-27 17:33:03 +08:00
parent 89e45c97fe
commit 566d594fef
5 changed files with 213 additions and 193 deletions

View File

@ -8,6 +8,18 @@ export const eightworkInfo = declareRequest(
"eightworkLoading", "eightworkLoading",
`Get > /eightwork/eightworkInfo/{id}`, `Get > /eightwork/eightworkInfo/{id}`,
); );
export const eightworkSupplementaryInfo = declareRequest(
"eightworkLoading",
`Post > @/eightwork/eightworkSupplementaryInfo/list`,
);
export const eightworkMeasuresLogs = declareRequest(
"eightworkLoading",
`Get > /eightwork/measuresLogs/listAll/{workId}`,
);
export const eightworkTaskLogFlowChart = declareRequest(
"eightworkLoading",
`Get > /eightwork/taskLog/flowChart/{workId}`,
);
export const eightworkType = declareRequest( export const eightworkType = declareRequest(
"eightworkLoading", "eightworkLoading",
`Post > @/eightwork/eightworkTask/listByWorkType`, `Post > @/eightwork/eightworkTask/listByWorkType`,

View File

@ -16,10 +16,11 @@ export {};
export const STATUS_ENUM = [ export const STATUS_ENUM = [
{ name: "未开始", bianma: "0" }, { name: "未开始", bianma: "0" },
{ name: "进行中", bianma: "1" }, { name: "进行中", bianma: "1" },
{ name: "打回", bianma: "2" },
{ name: "强制归档", bianma: "998" }, { name: "强制归档", bianma: "998" },
{ name: "归档", bianma: "999" }, { name: "归档", bianma: "999" },
]; ];
export const WORK_TYPE_ENUM = [ export const WORK_TYPE_ENUM = [
{ name: "相关方", bianma: "1" }, { name: "相关方", bianma: "1" },
{ name: "内部", bianma: "998" }, { name: "内部", bianma: "2" },
]; ];

View File

@ -89,14 +89,22 @@ function List(props) {
dataIndex: "xgfFlag", dataIndex: "xgfFlag",
render: (_, record) => getLabelName({ list: WORK_TYPE_ENUM, status: record.xgfFlag }), render: (_, record) => getLabelName({ list: WORK_TYPE_ENUM, status: record.xgfFlag }),
}, },
{ title: "动火等级", dataIndex: "workLevel" }, {
{ title: "申请人", dataIndex: "createName" }, title: "动火等级",
{ title: "申请单位", dataIndex: "todo" }, dataIndex: "workLevel",
{ title: "申请时间", dataIndex: "createTime" }, render: (_, record) => getLabelName({ list: eightworkType, status: record.workLevel, idKey: "workLevel", nameKey: "taskName" }),
{ title: "作业人", dataIndex: "todo" }, },
{ title: "作业单位", dataIndex: "todo" }, { title: "申请人", dataIndex: ["info", "applyUser"] },
{ title: "作业时间", dataIndex: "todo" }, { title: "申请单位", dataIndex: ["info", "applyUnit"] },
{ title: "作业内容", dataIndex: "todo" }, { title: "申请时间", dataIndex: ["info", "applyTime"] },
// { title: "作业人", dataIndex: ["info", "step_1", "actUserName"] },
// { title: "作业单位", dataIndex: ["info", "step_1", "actUserDepartmentName"] },
{
title: "作业时间",
dataIndex: ["info", "workStartTime"],
render: (_, record) => `${record.info.workStartTime}${record.info.workEndTime}`,
},
{ title: "作业内容", dataIndex: ["info", "workContent"] },
{ {
title: "审核状态", title: "审核状态",
dataIndex: "status", dataIndex: "status",
@ -112,7 +120,7 @@ function List(props) {
<Button <Button
type="link" type="link"
onClick={() => { onClick={() => {
setCurrentId(record.id); setCurrentId(record.workId);
setFlowModalOpen(true); setFlowModalOpen(true);
}} }}
> >
@ -121,12 +129,12 @@ function List(props) {
<Button <Button
type="link" type="link"
onClick={() => { onClick={() => {
props.history.push(`./view?id=${record.id}`); props.history.push(`./view?id=${record.id}&workId=${record.workId}`);
}} }}
> >
审批表详情 审批表详情
</Button> </Button>
{(!props.status && !props.entrance) && ( {(!props.status && !props.entrance && ![998, 999].includes(record.status)) && (
<Button <Button
type="link" type="link"
danger danger
@ -211,35 +219,8 @@ function FlowModalComponent(props) {
const [flowEdges, setFlowEdges] = useState([]); const [flowEdges, setFlowEdges] = useState([]);
const getData = async () => { const getData = async () => {
// 模拟分叉流程数据 const { data } = await props["eightworkTaskLogFlowChart"]({ workId: props.id });
// 主线流程:申请人提报 → 部门审批 → 安全部门审批 → 审批通过 const { nodes, edges } = getFlowData(data);
// 分支流程:从"部门审批"分出"值班领导审批",分支结束后汇入"安全部门审批"
const data = {
flowCOList: [
// 节点0申请人提报
{ status: 1, flowList: ["申请人提报", "张三", "2024-01-15 09:30"] },
// 节点1部门审批从这里开始分叉
{
status: 2,
type: 1,
flowList: ["部门审批", "李四"],
branches: [
{
status: 2,
flowList: ["值班领导审批", "赵六"],
mergeIndex: 2, // 分支结束后汇入到节点2安全部门审批
},
],
},
// 节点2安全部门审批分支汇入点
{ status: 2, flowList: ["安全部门审批", "王五"] },
// 节点3审批通过
{ status: 2, flowList: ["审批通过", "系统"] },
],
thisFlow: 1,
};
const { nodes, edges } = getFlowData(data.flowCOList, data.thisFlow);
setFlowNodes(nodes); setFlowNodes(nodes);
setFlowEdges(edges); setFlowEdges(edges);
}; };

View File

@ -1,9 +1,10 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime"; import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, Divider, Image } from "antd"; import { Button, Divider, Image } from "antd";
import { useEffect, useRef, useState } from "react"; import { Fragment, useEffect, useRef, useState } from "react";
import { useReactToPrint } from "react-to-print"; import { useReactToPrint } from "react-to-print";
import Page from "zy-react-library/components/Page"; import Page from "zy-react-library/components/Page";
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery"; import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
import { getFileUrl } from "zy-react-library/utils";
import { NS_EIGHTWORK } from "~/enumerate/namespace"; import { NS_EIGHTWORK } from "~/enumerate/namespace";
import "./index.less"; import "./index.less";
@ -27,31 +28,21 @@ function View(props) {
}); });
const [info, setInfo] = useState({}); const [info, setInfo] = useState({});
const [safetyMeasures, setSafetyMeasures] = useState([ const [safetyMeasures, setSafetyMeasures] = useState([]);
{ content: "动火操作人(焊工)、参与人(电工)及其他特种作业人员须持有效证书方可作业;动火相关设备、必须符合国家、行业标准;", status: "1" }, const [otherSafetyMeasures, setOtherSafetyMeasures] = useState([]);
{ content: "在动火部位配备2具以上适合现场灭火的相应介质合格灭火器 及(1)桶水", status: "1" }, const [delayedFireMonitoringRecord, setDelayedFireMonitoringRecord] = useState([]);
{ content: "动火前须设置警戒线,清理现场易燃物,对无法清理的要用水浇湿或进行有效隔离,对于有油污等易燃物或狭窄危险部位须铺垫方防火石棉布;", status: "1" }, const [gasFireMonitoringRecord, setGasFireMonitoringRecord] = useState([]);
{ content: "动火前,现场管辖单位人员须检查确认动火安全措施落实到位;", status: "1" },
{ content: "动火中,现场人员须严格遵守消防相关规章制度和操作规程;", status: "1" },
{ content: "动火中,监火人不得离开动火现场;", status: "1" },
{ content: "动火中,发现事故隐患须立即停止动火,待事故隐患排除后方可继续动火;", status: "0" },
{ content: "动火结束,现场管辖单位人员与动火现场负责人共同对动火现场检查,确认现场清理完毕,无遗留火种,有延时监火要求的,现场管辖单位指定人员延时监火。", status: "1" },
]);
const [otherSafetyMeasures, setOtherSafetyMeasures] = useState([
{ content: "监火人不得离开动火现场;", preparedBy: "张三" },
{ content: "动火前,现场管辖单位人员须检查确认动火安全措施落实到位;", preparedBy: "张三" },
{ content: "动火中,现场人员须严格遵守消防相关规章制度和操作规程;", preparedBy: "张三" },
]);
const [delayedFireMonitoringRecord, setDelayedFireMonitoringRecord] = useState([
{ time: "2023-04-01 10:00:00", monitor: "张三", signature: "https://pic1.arkoo.com/56D0B40F99F841DF8A2425762AE2565D/picture/o_1i4qop009177v1tgf14db15he1iaj1is.jpg" },
{ time: "2023-04-01 10:00:00", monitor: "张三", signature: "https://pic1.arkoo.com/56D0B40F99F841DF8A2425762AE2565D/picture/o_1i4qop009177v1tgf14db15he1iaj1is.jpg" },
{ time: "2023-04-01 10:00:00", monitor: "张三", signature: "https://pic1.arkoo.com/56D0B40F99F841DF8A2425762AE2565D/picture/o_1i4qop009177v1tgf14db15he1iaj1is.jpg" },
{ time: "2023-04-01 10:00:00", monitor: "张三", signature: "https://pic1.arkoo.com/56D0B40F99F841DF8A2425762AE2565D/picture/o_1i4qop009177v1tgf14db15he1iaj1is.jpg" },
]);
const getData = async () => { const getData = async () => {
const { data } = await props["eightworkInfo"]({ id: query.id }); const { data: basicInfo } = await props["eightworkInfo"]({ id: query.id });
setInfo(data); setInfo(basicInfo);
const { data: supplementaryInfo } = await props["eightworkSupplementaryInfo"]({ eqWorkId: query.workId, pageSize: 999, pageIndex: 1 });
setDelayedFireMonitoringRecord(supplementaryInfo.filter(item => item.type === "delay"));
setGasFireMonitoringRecord(supplementaryInfo.filter(item => item.type === "gas"));
const { data: measuresLogs } = await props["eightworkMeasuresLogs"]({ workId: query.workId });
console.log(measuresLogs);
setSafetyMeasures(measuresLogs.filter(item => item.type === 1));
setOtherSafetyMeasures(measuresLogs.filter(item => item.type === 2));
}; };
useEffect(() => { useEffect(() => {
@ -77,7 +68,7 @@ function View(props) {
<tr> <tr>
<td colSpan={4} style={{ border: "none" }}> <td colSpan={4} style={{ border: "none" }}>
<span>编号</span> <span>编号</span>
<span>{info.xx}</span> <span>{info.checkNo}</span>
</td> </td>
</tr> </tr>
</thead> </thead>
@ -90,51 +81,59 @@ function View(props) {
)} )}
<tr> <tr>
<td className="title">申请单位</td> <td className="title">申请单位</td>
<td>{info.xx}</td> <td>{info?.info?.applyUnit}</td>
<td className="title">申请时间</td> <td className="title">申请时间</td>
<td>{info.xx}</td> <td>{info?.info?.applyTime}</td>
</tr> </tr>
<tr> <tr>
<td className="title">动火部位</td> <td className="title">动火部位</td>
<td>{info.xx}</td> <td>{info?.info?.work_place}</td>
<td className="title">动火方法</td> <td className="title">动火方法</td>
<td>{info.xx}</td> <td>{info?.info?.work_way}</td>
</tr> </tr>
<tr> <tr>
<td className="title">动火等级</td> <td className="title">动火等级</td>
<td>{info.xx}</td> <td>{info?.info?.workLevelName}</td>
<td className="title">作业内容</td> <td className="title">作业内容</td>
<td>{info.xx}</td> <td>{info?.info?.workContent}</td>
</tr> </tr>
<tr> <tr>
<td className="title">动火时间</td> <td className="title">动火时间</td>
<td colSpan={3}>{info.xx}</td> <td colSpan={3}>{`${info?.info?.workStartTime} - ${info?.info?.workEndTime}`}</td>
</tr> </tr>
<tr> <tr>
<td className="title">现场管辖</td> <td className="title">现场负责</td>
<td>{info.xx}</td> <td>{info?.info?.step_10?.actUserName}</td>
<td className="title">动火操作人</td> <td className="title">动火操作人</td>
<td>{info.xx}</td> <td>{info?.info?.hotWorkActUser?.map(item => item.name).join(", ")}</td>
</tr> </tr>
<tr> <tr>
<td className="title">动火监火人</td> <td className="title">动火监火人</td>
<td colSpan={3}>{info.xx}</td> <td colSpan={3}>{info?.info?.workMonitor}</td>
</tr> </tr>
{gasFireMonitoringRecord.length > 0 && (
<tr> <tr>
<td className="title center" colSpan={4}>可燃气体分析运行的生产装置罐区和具有火灾爆炸危险场所</td> <td className="title center" colSpan={4}>可燃气体分析运行的生产装置罐区和具有火灾爆炸危险场所</td>
</tr> </tr>
)}
{
gasFireMonitoringRecord.map(item => (
<Fragment key={item.id}>
<tr> <tr>
<td className="title">分析时间</td> <td className="title">分析时间</td>
<td>{info.xx}</td> <td>{item?.details?.analysisTime}</td>
<td className="title">分析点</td> <td className="title">分析点</td>
<td>{info.xx}</td> <td>{item?.details?.analysisPointName}</td>
</tr> </tr>
<tr> <tr>
<td className="title">可燃气体检测结果</td> <td className="title">可燃气体检测结果</td>
<td>{info.xx}</td> <td>{item?.details?.analysisResult}</td>
<td className="title">分析人</td> <td className="title">分析人</td>
<td>{info.xx}</td> <td>{item?.details?.analysisUserName}</td>
</tr> </tr>
</Fragment>
))
}
<tr> <tr>
<td className="title center" colSpan={4}>动火要求安全措施安全提示</td> <td className="title center" colSpan={4}>动火要求安全措施安全提示</td>
</tr> </tr>
@ -152,9 +151,9 @@ function View(props) {
<tr key={index}> <tr key={index}>
<td className="center">{index + 1}</td> <td className="center">{index + 1}</td>
<td>{item.content}</td> <td>{item.content}</td>
<td className="center">{item.status === "1" ? "是" : "否"}</td> <td className="center">符合</td>
<td className="center"> <td className="center">
<Image src="https://pic1.arkoo.com/56D0B40F99F841DF8A2425762AE2565D/picture/o_1i4qop009177v1tgf14db15he1iaj1is.jpg" width={50} height={50} /> {item.signPath && <Image src={getFileUrl() + item.signPath} width={50} height={50} />}
</td> </td>
</tr> </tr>
))} ))}
@ -170,7 +169,7 @@ function View(props) {
</div> </div>
<div> <div>
<span>编制人</span> <span>编制人</span>
<span>{item.preparedBy}</span> <span>{item.createName}</span>
</div> </div>
</div> </div>
)) ))
@ -185,48 +184,48 @@ function View(props) {
<td className="title">动火单位(部门)负责人意见</td> <td className="title">动火单位(部门)负责人意见</td>
<td className="right"> <td className="right">
<div> <div>
<Image src="https://pic1.arkoo.com/56D0B40F99F841DF8A2425762AE2565D/picture/o_1i4qop009177v1tgf14db15he1iaj1is.jpg" width={50} height={50} /> {info?.info?.step_4?.signPath && <Image src={getFileUrl() + info?.info?.step_4?.signPath} width={50} height={50} />}
</div> </div>
<div>{info.xx}</div> <div>{info?.info?.step_4?.signTime}</div>
</td> </td>
<td className="title">项目发包单位(部门)人员意见</td> <td className="title">项目发包单位(部门)人员意见</td>
<td className="right"> <td className="right">
<div> <div>
<Image src="https://pic1.arkoo.com/56D0B40F99F841DF8A2425762AE2565D/picture/o_1i4qop009177v1tgf14db15he1iaj1is.jpg" width={50} height={50} /> {info?.info?.step_5?.signPath && <Image src={getFileUrl() + info?.info?.step_5?.signPath} width={50} height={50} />}
</div> </div>
<div>{info.xx}</div> <div>{info?.info?.step_5?.signTime}</div>
</td> </td>
</tr> </tr>
<tr> <tr>
<td className="title">现场管辖单位(部门)负责人意见</td> <td className="title">现场管辖单位(部门)负责人意见</td>
<td className="right"> <td className="right">
<div> <div>
<Image src="https://pic1.arkoo.com/56D0B40F99F841DF8A2425762AE2565D/picture/o_1i4qop009177v1tgf14db15he1iaj1is.jpg" width={50} height={50} /> {info?.info?.step_6?.signPath && <Image src={getFileUrl() + info?.info?.step_6?.signPath} width={50} height={50} />}
</div> </div>
<div>{info.xx}</div> <div>{info?.info?.step_6?.signTime}</div>
</td> </td>
<td className="title">动火许可证签发单位意见</td> <td className="title">动火许可证签发单位意见</td>
<td className="right"> <td className="right">
<div> <div>
<Image src="https://pic1.arkoo.com/56D0B40F99F841DF8A2425762AE2565D/picture/o_1i4qop009177v1tgf14db15he1iaj1is.jpg" width={50} height={50} /> {info?.info?.step_7?.signPath && <Image src={getFileUrl() + info?.info?.step_7?.signPath} width={50} height={50} />}
</div> </div>
<div>{info.xx}</div> <div>{info?.info?.step_7?.signTime}</div>
</td> </td>
</tr> </tr>
<tr> <tr>
<td className="title">动火前管辖单位现场人员许可</td> <td className="title">动火前管辖单位现场人员许可</td>
<td className="right"> <td className="right">
<div> <div>
<Image src="https://pic1.arkoo.com/56D0B40F99F841DF8A2425762AE2565D/picture/o_1i4qop009177v1tgf14db15he1iaj1is.jpg" width={50} height={50} /> {info?.info?.step_9?.signPath && <Image src={getFileUrl() + info?.info?.step_9?.signPath} width={50} height={50} />}
</div> </div>
<div>{info.xx}</div> <div>{info?.info?.step_9?.signTime}</div>
</td> </td>
<td className="title">动火后管辖单位现场人员验收</td> <td className="title">动火后管辖单位现场人员验收</td>
<td className="right"> <td className="right">
<div> <div>
<Image src="https://pic1.arkoo.com/56D0B40F99F841DF8A2425762AE2565D/picture/o_1i4qop009177v1tgf14db15he1iaj1is.jpg" width={50} height={50} /> {info?.info?.step_11?.signPath && <Image src={getFileUrl() + info?.info?.step_11?.signPath} width={50} height={50} />}
</div> </div>
<div>{info.xx}</div> <div>{info?.info?.step_11?.signTime}</div>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -243,10 +242,10 @@ function View(props) {
</tr> </tr>
{delayedFireMonitoringRecord.map((item, index) => ( {delayedFireMonitoringRecord.map((item, index) => (
<tr key={index}> <tr key={index}>
<td className="center">{item.monitor}</td> <td className="center">{item?.details?.actUserName}</td>
<td className="center">{item.time}</td> <td className="center">{item?.details?.delayHotTime}</td>
<td className="center"> <td className="center">
<Image src={item.signature} width={50} height={50} /> {item?.details?.delayHotPhoto && <Image src={getFileUrl() + item?.details?.delayHotPhoto} width={50} height={50} />}
</td> </td>
</tr> </tr>
))} ))}

View File

@ -1,12 +1,12 @@
// 根据状态获取颜色 // 根据状态获取颜色
export const getStatusColor = (status, type, thisFlow) => { export const getStatusColor = (status) => {
// 进行中节点(当前待审批节点)显示红色 // 进行中节点(当前待审批节点)显示红色
if (thisFlow && type === thisFlow) { if (status === 0) {
return "#ff4d4f"; // 红色(进行中) return "#ff4d4f"; // 红色(进行中)
} }
// 已完成节点显示绿色 // 已完成节点显示绿色
if (status === 1) { if (status === 1 || status === 2) {
return "#52c41a"; // 绿色(已完成) return "#52c41a"; // 绿色(已完成)
} }
@ -18,15 +18,14 @@ export const getStatusColor = (status, type, thisFlow) => {
export const getNodeLabel = (flowItem) => { export const getNodeLabel = (flowItem) => {
return ( return (
<div style={{ padding: "10px", textAlign: "center" }}> <div style={{ padding: "10px", textAlign: "center" }}>
<div style={{ fontSize: "16px" }}>{flowItem.flowList[0]}</div> <div style={{ fontSize: "16px" }}>{flowItem.stepName}</div>
{flowItem.flowList.slice(1).map((item, index) => ( <div style={{ fontSize: "16px" }}>{flowItem.actUserName}</div>
<div key={index} style={{ fontSize: "16px", marginTop: "5px" }}>{item}</div> <div style={{ fontSize: "16px" }}>{flowItem.updateTime}</div>
))}
</div> </div>
); );
}; };
export const getFlowData = (list, thisFlow) => { export const getFlowData = (list) => {
const nodes = []; const nodes = [];
const edges = []; const edges = [];
@ -36,8 +35,11 @@ export const getFlowData = (list, thisFlow) => {
const horizontalSpacing = 350; const horizontalSpacing = 350;
const verticalSpacing = 300; const verticalSpacing = 300;
// 收集分支信息 // 创建 stepId 到 index 的映射
const branchInfos = []; const stepIdToIndex = {};
list.forEach((item, index) => {
stepIdToIndex[item.stepId] = index;
});
// 第一遍:创建主线节点 // 第一遍:创建主线节点
list.forEach((flowItem, index) => { list.forEach((flowItem, index) => {
@ -50,9 +52,9 @@ export const getFlowData = (list, thisFlow) => {
status: flowItem.status, status: flowItem.status,
}, },
style: { style: {
background: getStatusColor(flowItem.status, flowItem.type, thisFlow), background: getStatusColor(flowItem.status),
color: "white", color: "white",
borderColor: getStatusColor(flowItem.status, flowItem.type, thisFlow), borderColor: getStatusColor(flowItem.status),
width: nodeWidth, width: nodeWidth,
minHeight: nodeHeight, minHeight: nodeHeight,
padding: "10px", padding: "10px",
@ -67,27 +69,20 @@ export const getFlowData = (list, thisFlow) => {
position: { x: index * horizontalSpacing, y: 100 }, position: { x: index * horizontalSpacing, y: 100 },
}); });
// 记录分支信息 // 创建主线边(只有当没有分支汇入时才连接到下一个节点)
if (flowItem.branches && flowItem.branches.length > 0) { // 如果当前节点的分支会汇入到下一个节点,则不画主线边
flowItem.branches.forEach((branch, branchIdx) => { const hasBranchMergingToNext = flowItem.branches?.some(
branchInfos.push({ branch => branch.mergeStepId === list[index + 1]?.stepId,
startIndex: index, );
branchIndex: branchIdx,
branch,
mergeIndex: branch.mergeIndex,
});
});
}
// 创建主线边 if (index < list.length - 1 && !hasBranchMergingToNext) {
if (index < list.length - 1) {
edges.push({ edges.push({
id: `edge-main-${index}`, id: `edge-main-${index}`,
source: `node-${index}`, source: `node-${index}`,
target: `node-${index + 1}`, target: `node-${index + 1}`,
type: "smoothstep", type: "smoothstep",
animated: true, animated: true,
style: { stroke: "#1890ff", strokeWidth: 2 }, style: { stroke: "#1890ff", strokeWidth: 3 },
markerEnd: { markerEnd: {
type: "arrowclosed", type: "arrowclosed",
color: "#1890ff", color: "#1890ff",
@ -97,16 +92,27 @@ export const getFlowData = (list, thisFlow) => {
}); });
// 第二遍:创建分支节点 // 第二遍:创建分支节点
branchInfos.forEach((info) => { list.forEach((flowItem, index) => {
const { startIndex, branchIndex, branch, mergeIndex } = info; if (flowItem.branches && flowItem.branches.length > 0) {
const branchNodeId = `branch-${startIndex}-${branchIndex}`; const branches = flowItem.branches;
const branchCount = branches.length;
// 计算分支节点位置:在分叉节点和汇入节点中间,下方 // 根据 mergeStepId 找到汇入节点的索引
const startX = startIndex * horizontalSpacing; let mergeIndex = -1;
const mergeX = mergeIndex * horizontalSpacing; if (branches[branchCount - 1].mergeStepId && stepIdToIndex[branches[branchCount - 1].mergeStepId] !== undefined) {
const branchX = (startX + mergeX) / 2; mergeIndex = stepIdToIndex[branches[branchCount - 1].mergeStepId];
}
// 计算分支节点位置:横向排列在主线下方
const startX = index * horizontalSpacing;
const totalBranchWidth = (branchCount - 1) * horizontalSpacing;
const branchStartX = startX - totalBranchWidth / 2;
const branchY = 100 + verticalSpacing; const branchY = 100 + verticalSpacing;
branches.forEach((branch, branchIdx) => {
const branchNodeId = `branch-${index}-${branchIdx}`;
const branchX = branchStartX + branchIdx * horizontalSpacing;
nodes.push({ nodes.push({
id: branchNodeId, id: branchNodeId,
data: { data: {
@ -114,9 +120,9 @@ export const getFlowData = (list, thisFlow) => {
status: branch.status, status: branch.status,
}, },
style: { style: {
background: getStatusColor(branch.status, branch.type, thisFlow), background: getStatusColor(branch.status),
color: "white", color: "white",
borderColor: getStatusColor(branch.status, branch.type, thisFlow), borderColor: getStatusColor(branch.status),
width: nodeWidth, width: nodeWidth,
minHeight: nodeHeight, minHeight: nodeHeight,
padding: "10px", padding: "10px",
@ -131,36 +137,57 @@ export const getFlowData = (list, thisFlow) => {
position: { x: branchX, y: branchY }, position: { x: branchX, y: branchY },
}); });
// 从分叉节点连接到分支节点 // 从主节点连接到第一个分支节点
if (branchIdx === 0) {
edges.push({ edges.push({
id: `edge-branch-start-${startIndex}-${branchIndex}`, id: `edge-branch-start-${index}`,
source: `node-${startIndex}`, source: `node-${index}`,
target: branchNodeId, target: branchNodeId,
type: "smoothstep", type: "smoothstep",
animated: true, animated: true,
style: { stroke: "#fa8c16", strokeWidth: 2 }, style: { stroke: "#c41a1a", strokeWidth: 3 },
markerEnd: { markerEnd: {
type: "arrowclosed", type: "arrowclosed",
color: "#fa8c16", color: "#c41a1a",
}, },
}); });
}
// 从分支节点连接到汇入节点 // 分支节点之间相互连接
if (mergeIndex !== undefined && mergeIndex < list.length) { if (branchIdx > 0) {
const prevBranchNodeId = `branch-${index}-${branchIdx - 1}`;
edges.push({ edges.push({
id: `edge-branch-end-${startIndex}-${branchIndex}`, id: `edge-branch-connection-${index}-${branchIdx}`,
source: prevBranchNodeId,
target: branchNodeId,
type: "smoothstep",
animated: true,
style: { stroke: "#c41a1a", strokeWidth: 3 },
markerEnd: {
type: "arrowclosed",
color: "#c41a1a",
},
});
}
// 从最后一个分支节点连接到汇入节点
if (branchIdx === branchCount - 1 && mergeIndex >= 0) {
edges.push({
id: `edge-branch-end-${index}`,
source: branchNodeId, source: branchNodeId,
target: `node-${mergeIndex}`, target: `node-${mergeIndex}`,
type: "smoothstep", type: "smoothstep",
animated: true, animated: true,
style: { stroke: "#52c41a", strokeWidth: 2 }, style: { stroke: "#c41a1a", strokeWidth: 3 },
markerEnd: { markerEnd: {
type: "arrowclosed", type: "arrowclosed",
color: "#52c41a", color: "#c41a1a",
}, },
}); });
} }
}); });
}
});
return { nodes, edges }; return { nodes, edges };
}; };