From e88cc9e197406f2faae7698565e1cf88c4987af8 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Thu, 27 Jun 2024 09:42:54 +0800 Subject: [PATCH 01/13] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=85=A8?= =?UTF-8?q?=E5=B1=80loading=E8=A7=A3=E5=86=B3=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/src/components/KFSpin/index.less | 19 ++++++ react-ui/src/components/KFSpin/index.tsx | 13 ++++ .../src/pages/Experiment/Comparison/index.tsx | 6 +- react-ui/src/utils/loading.tsx | 66 +++++++++++++++++++ 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 react-ui/src/components/KFSpin/index.less create mode 100644 react-ui/src/components/KFSpin/index.tsx create mode 100644 react-ui/src/utils/loading.tsx diff --git a/react-ui/src/components/KFSpin/index.less b/react-ui/src/components/KFSpin/index.less new file mode 100644 index 00000000..931e7ea0 --- /dev/null +++ b/react-ui/src/components/KFSpin/index.less @@ -0,0 +1,19 @@ +.kf-spin { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1000; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: rgba(255, 255, 255, 0.5); + + &__label { + margin-top: 20px; + color: @text-color; + font-size: @font-size-content; + } +} diff --git a/react-ui/src/components/KFSpin/index.tsx b/react-ui/src/components/KFSpin/index.tsx new file mode 100644 index 00000000..64d315a9 --- /dev/null +++ b/react-ui/src/components/KFSpin/index.tsx @@ -0,0 +1,13 @@ +import { Spin, SpinProps } from 'antd'; +import styles from './index.less'; + +function KFSpin(props: SpinProps) { + return ( +
+ +
加载中
+
+ ); +} + +export default KFSpin; diff --git a/react-ui/src/pages/Experiment/Comparison/index.tsx b/react-ui/src/pages/Experiment/Comparison/index.tsx index 59cd3f8b..12b60416 100644 --- a/react-ui/src/pages/Experiment/Comparison/index.tsx +++ b/react-ui/src/pages/Experiment/Comparison/index.tsx @@ -7,7 +7,7 @@ import { import { to } from '@/utils/promise'; import tableCellRender, { arrayFormatter, dateFormatter } from '@/utils/table'; import { useSearchParams } from '@umijs/max'; -import { App, Button, Table, /*TablePaginationConfig,*/ TableProps } from 'antd'; +import { App, Button, Table, /* TablePaginationConfig,*/ TableProps } from 'antd'; import classNames from 'classnames'; import { useEffect, useMemo, useState } from 'react'; import ExperimentStatusCell from '../components/ExperimentStatusCell'; @@ -38,6 +38,7 @@ function ExperimentComparison() { // const [cacheState, setCacheState] = useCacheState(); // const [total, setTotal] = useState(0); const [selectedRowKeys, setSelectedRowKeys] = useState([]); + const [loading, setLoading] = useState(false); const { message } = App.useApp(); // const [pagination, setPagination] = useState( // cacheState?.pagination ?? { @@ -52,9 +53,11 @@ function ExperimentComparison() { // 获取对比数据列表 const getComparisonData = async () => { + setLoading(true); const request = comparisonType === ComparisonType.Train ? getExpTrainInfosReq : getExpEvaluateInfosReq; const [res] = await to(request(experimentId)); + setLoading(false); if (res && res.data) { // const { content = [], totalElements = 0 } = res.data; setTableData(res.data); @@ -180,6 +183,7 @@ function ExperimentComparison() { scroll={{ y: 'calc(100% - 55px)' }} pagination={false} bordered={true} + loading={loading} // pagination={{ // ...pagination, // total: total, diff --git a/react-ui/src/utils/loading.tsx b/react-ui/src/utils/loading.tsx new file mode 100644 index 00000000..aba4a16c --- /dev/null +++ b/react-ui/src/utils/loading.tsx @@ -0,0 +1,66 @@ +/* + * @Author: 赵伟 + * @Date: 2024-06-26 16:37:39 + * @Description: 全局网络请求 Loading + */ + +import KFSpin from '@/components/KFSpin'; +import { ConfigProvider, SpinProps } from 'antd'; +import { globalConfig } from 'antd/es/config-provider'; +import zhCN from 'antd/locale/zh_CN'; +import { createRoot } from 'react-dom/client'; + +export class Loading { + static total = 0; + static show(props?: SpinProps) { + Loading.total += 1; + if (Loading.total > 1) { + return; + } + const container = document.createElement('div'); + container.id = 'loading'; + const rootContainer = document.getElementsByTagName('main')[0]; + rootContainer?.appendChild(container); + const root = createRoot(container); + const global = globalConfig(); + let timeoutId: ReturnType; + + function render(spinProps: SpinProps) { + clearTimeout(timeoutId); + + timeoutId = setTimeout(() => { + const rootPrefixCls = global.getPrefixCls(); + const iconPrefixCls = global.getIconPrefixCls(); + const theme = global.getTheme(); + const dom = ; + + root.render( + + {global.holderRender ? global.holderRender(dom) : dom} + , + ); + }); + } + + render({ size: 'large', ...props, spinning: true }); + } + + static hide(force: boolean = false) { + Loading.total -= 1; + if (Loading.total <= 0 || force) { + Loading.total = 0; + const rootContainer = document.getElementsByTagName('main')[0]; + const container = document.getElementById('loading'); + if (container) { + rootContainer?.removeChild(container); + } + } + } +} + +export default Loading; From 4ccf5555e5ca7b2672504e41d4ef251d307f9847 Mon Sep 17 00:00:00 2001 From: fanshuai <1141904845@qq.com> Date: Fri, 28 Jun 2024 14:08:31 +0800 Subject: [PATCH 02/13] =?UTF-8?q?=E6=8C=87=E6=A0=87=E5=AF=B9=E6=AF=94?= =?UTF-8?q?=E5=8E=BB=E9=99=A4=E8=84=8F=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ruoyi/platform/service/impl/AimServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AimServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AimServiceImpl.java index fdd7b5c9..09dcc04f 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AimServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AimServiceImpl.java @@ -111,9 +111,10 @@ public class AimServiceImpl implements AimService { List datasetList = getTrainDateSet(records, aimrunId); aimRunInfo.setDataset(datasetList); } + aimRunInfoList.add(aimRunInfo); } } - aimRunInfoList.add(aimRunInfo); + } //判断哪个最长 From 03ea2ef74a43a194dce7b65ad577196c254208a5 Mon Sep 17 00:00:00 2001 From: fanshuai <1141904845@qq.com> Date: Fri, 28 Jun 2024 14:15:12 +0800 Subject: [PATCH 03/13] =?UTF-8?q?=E6=8C=87=E6=A0=87=E5=AF=B9=E6=AF=94?= =?UTF-8?q?=E5=8E=BB=E9=99=A4=E8=84=8F=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ruoyi/platform/service/impl/AimServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AimServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AimServiceImpl.java index 09dcc04f..338fab19 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AimServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AimServiceImpl.java @@ -59,7 +59,7 @@ public class AimServiceImpl implements AimService { return new ArrayList<>(); } //查询实例数据 - List byExperimentId = experimentInsService.getByExperimentId(experimentId); + List byExperimentId = experimentInsService.queryByExperimentId(experimentId); if (byExperimentId == null || byExperimentId.size() == 0){ return new ArrayList<>(); From 2cc70b1f00633694ac7321330d2fe7a35abde668 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Mon, 1 Jul 2024 11:45:39 +0800 Subject: [PATCH 04/13] =?UTF-8?q?feat:=20=E6=A8=A1=E5=9E=8B=E6=BC=94?= =?UTF-8?q?=E5=8C=96=E6=B7=BB=E5=8A=A0=E7=82=B9=E5=87=BB=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E5=B1=95=E5=BC=80=E6=95=B0=E6=8D=AE=E9=9B=86=E5=92=8C=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Model/components/ModelEvolution/index.tsx | 67 +++++-- .../Model/components/ModelEvolution/utils.tsx | 163 +++++++++++++----- .../Model/components/NodeTooltips/index.tsx | 14 +- .../src/pages/ModelDeployment/List/index.tsx | 2 +- 4 files changed, 180 insertions(+), 66 deletions(-) diff --git a/react-ui/src/pages/Model/components/ModelEvolution/index.tsx b/react-ui/src/pages/Model/components/ModelEvolution/index.tsx index f46d77ec..a0e9beaf 100644 --- a/react-ui/src/pages/Model/components/ModelEvolution/index.tsx +++ b/react-ui/src/pages/Model/components/ModelEvolution/index.tsx @@ -1,9 +1,15 @@ +/* + * @Author: 赵伟 + * @Date: 2024-06-07 11:24:10 + * @Description: 模型演化 + */ + import { useEffectWhen } from '@/hooks'; import { ResourceVersionData } from '@/pages/Dataset/config'; import { getModelAtlasReq } from '@/services/dataset/index.js'; import themes from '@/styles/theme.less'; import { to } from '@/utils/promise'; -import G6, { G6GraphEvent, Graph } from '@antv/g6'; +import G6, { G6GraphEvent, Graph, INode } from '@antv/g6'; // @ts-ignore import { Flex, Select } from 'antd'; import { useEffect, useRef, useState } from 'react'; @@ -11,7 +17,15 @@ import GraphLegend from '../GraphLegend'; import NodeTooltips from '../NodeTooltips'; import styles from './index.less'; import type { ModelDepsData, ProjectDependency, TrainDataset } from './utils'; -import { getGraphData, nodeFontSize, nodeHeight, nodeWidth, normalizeTreeData } from './utils'; +import { + NodeType, + getGraphData, + nodeFontSize, + nodeHeight, + nodeWidth, + normalizeTreeData, + traverseHierarchically, +} from './utils'; type modeModelEvolutionProps = { resourceId: number; @@ -37,6 +51,8 @@ function ModelEvolution({ const [hoverNodeData, setHoverNodeData] = useState< ModelDepsData | ProjectDependency | TrainDataset | undefined >(undefined); + const apiData = useRef(undefined); // 接口返回的树形结构 + const hierarchyNodes = useRef([]); // 层级迭代树形结构,得到的节点列表 useEffect(() => { initGraph(); @@ -111,18 +127,7 @@ function ModelEvolution({ }, }, modes: { - default: [ - 'drag-canvas', - 'zoom-canvas', - // { - // type: 'collapse-expand', - // onChange(item?: Item, collapsed?: boolean) { - // const data = item!.getModel(); - // data.collapsed = collapsed; - // return true; - // }, - // }, - ], + default: ['drag-canvas', 'zoom-canvas'], }, }); @@ -161,11 +166,26 @@ function ModelEvolution({ }); graph.on('node:click', (e: G6GraphEvent) => { - const nodeItem = e.item; + const nodeItem = e.item as INode; const model = nodeItem.getModel() as ModelDepsData | ProjectDependency | TrainDataset; const { model_type } = model; - switch (model_type) { + if ( + model_type === NodeType.Project || + model_type === NodeType.TrainDataset || + model_type === NodeType.TestDataset || + !apiData.current || + !hierarchyNodes.current + ) { + return; } + + setShowNodeTooltip(false); + setEnterTooltip(false); + toggleExpended(model.id); + const graphData = getGraphData(apiData.current, hierarchyNodes.current); + graph.data(graphData); + graph.render(); + graph.fitView(); }); // 鼠标滚轮缩放时,隐藏 tooltip @@ -175,6 +195,17 @@ function ModelEvolution({ }); }; + // toggle 展开 + const toggleExpended = (id: string) => { + const nodes = hierarchyNodes.current; + for (const node of nodes) { + if (node.id === id) { + node.expanded = !node.expanded; + break; + } + } + }; + const handleTooltipsMouseEnter = () => { setEnterTooltip(true); }; @@ -192,7 +223,9 @@ function ModelEvolution({ const [res] = await to(getModelAtlasReq(params)); if (res && res.data) { const data = normalizeTreeData(res.data); - const graphData = getGraphData(data); + apiData.current = data; + hierarchyNodes.current = traverseHierarchically(data); + const graphData = getGraphData(data, hierarchyNodes.current); graph.data(graphData); graph.render(); diff --git a/react-ui/src/pages/Model/components/ModelEvolution/utils.tsx b/react-ui/src/pages/Model/components/ModelEvolution/utils.tsx index a878321a..30a06817 100644 --- a/react-ui/src/pages/Model/components/ModelEvolution/utils.tsx +++ b/react-ui/src/pages/Model/components/ModelEvolution/utils.tsx @@ -6,21 +6,22 @@ import Hierarchy from '@antv/hierarchy'; export const nodeWidth = 90; export const nodeHeight = 40; export const vGap = nodeHeight + 20; -export const hGap = nodeWidth; +export const hGap = nodeHeight + 20; export const ellipseWidth = nodeWidth; export const labelPadding = 30; export const nodeFontSize = 8; +export const datasetHGap = 20; // 数据集节点 const datasetNodes: NodeConfig[] = []; export enum NodeType { - current = 'current', - parent = 'parent', - children = 'children', - project = 'project', - trainDataset = 'trainDataset', - testDataset = 'testDataset', + Current = 'Current', // 当前模型 + Parent = 'Parent', // 父模型 + Children = 'Children', // 子模型 + Project = 'Project', // 项目 + TrainDataset = 'TrainDataset', // 训练数据集 + TestDataset = 'TestDataset', // 测试数据集 } export type Rect = { @@ -40,14 +41,14 @@ export interface TrainDataset extends NodeConfig { dataset_id: number; dataset_name: string; dataset_version: string; - model_type: NodeType.testDataset | NodeType.trainDataset; + model_type: NodeType.TestDataset | NodeType.TrainDataset; } export interface ProjectDependency extends NodeConfig { url: string; name: string; branch: string; - model_type: NodeType.project; + model_type: NodeType.Project; } export type ModalDetail = { @@ -66,9 +67,9 @@ export interface ModelDepsAPIData { version: string; workflow_id: number; exp_ins_id: number; - model_type: NodeType.children | NodeType.current | NodeType.parent; + model_type: NodeType.Children | NodeType.Current | NodeType.Parent; current_model_name: string; - project_dependency: ProjectDependency; + project_dependency?: ProjectDependency; test_dataset: TrainDataset[]; train_dataset: TrainDataset[]; train_task: TrainTask; @@ -79,16 +80,22 @@ export interface ModelDepsAPIData { export interface ModelDepsData extends Omit, TreeGraphData { children: ModelDepsData[]; + expanded: boolean; // 是否展开 + level: number; // 层级,从 0 开始 + datasetLen: number; // 数据集数量 } // 规范化子数据 export function normalizeChildren(data: ModelDepsData[]) { if (Array.isArray(data)) { data.forEach((item) => { - item.model_type = NodeType.children; + item.model_type = NodeType.Children; + item.expanded = false; + item.level = 0; + item.datasetLen = item.train_dataset.length + item.test_dataset.length; item.id = `$M_${item.current_model_id}_${item.version}`; item.label = getLabel(item); - item.style = getStyle(NodeType.children); + item.style = getStyle(NodeType.Children); normalizeChildren(item.children); }); } @@ -111,22 +118,22 @@ export function getLabel(node: ModelDepsData | ModelDepsAPIData) { export function getStyle(model_type: NodeType) { let fill = ''; switch (model_type) { - case NodeType.current: + case NodeType.Current: fill = 'l(0) 0:#72a1ff 1:#1664ff'; break; - case NodeType.parent: + case NodeType.Parent: fill = 'l(0) 0:#93dfd1 1:#43c9b1'; break; - case NodeType.children: + case NodeType.Children: fill = 'l(0) 0:#72b4ff 1:#169aff'; break; - case NodeType.project: + case NodeType.Project: fill = 'l(0) 0:#b3a9ff 1:#8981ff'; break; - case NodeType.trainDataset: + case NodeType.TrainDataset: fill = '#a5d878'; break; - case NodeType.testDataset: + case NodeType.TestDataset: fill = '#d8b578'; break; default: @@ -145,11 +152,15 @@ export function normalizeTreeData(apiData: ModelDepsAPIData): ModelDepsData { }) as ModelDepsData; // 设置当前模型的数据 - normalizedData.model_type = NodeType.current; + normalizedData.model_type = NodeType.Current; normalizedData.id = `$M_${normalizedData.current_model_id}_${normalizedData.version}`; normalizedData.label = getLabel(normalizedData); - normalizedData.style = getStyle(NodeType.current); + normalizedData.style = getStyle(NodeType.Current); + normalizedData.expanded = true; + normalizedData.datasetLen = + normalizedData.train_dataset.length + normalizedData.test_dataset.length; normalizeChildren(normalizedData.children as ModelDepsData[]); + normalizedData.level = 0; // 将 parent_models 转换成树形结构 let parent_models = normalizedData.parent_models || []; @@ -157,10 +168,13 @@ export function normalizeTreeData(apiData: ModelDepsAPIData): ModelDepsData { const parent = parent_models[0]; normalizedData = { ...parent, - model_type: NodeType.parent, + expanded: false, + level: 0, + datasetLen: parent.train_dataset.length + parent.test_dataset.length, + model_type: NodeType.Parent, id: `$M_${parent.current_model_id}_${parent.version}`, label: getLabel(parent), - style: getStyle(NodeType.parent), + style: getStyle(NodeType.Parent), children: [ { ...normalizedData, @@ -174,13 +188,34 @@ export function normalizeTreeData(apiData: ModelDepsAPIData): ModelDepsData { } // 将树形数据,使用 Hierarchy 进行布局,计算出坐标,然后转换成 G6 的数据 -export function getGraphData(data: ModelDepsData): GraphData { +export function getGraphData(data: ModelDepsData, hierarchyNodes: ModelDepsData[]): GraphData { const config = { direction: 'LR', getHeight: () => nodeHeight, getWidth: () => nodeWidth, - getVGap: () => vGap / 2, - getHGap: () => hGap / 2, + getVGap: (node: NodeConfig) => { + const model = node as ModelDepsData; + const { model_type, expanded, project_dependency } = model; + if (model_type === NodeType.Current || model_type === NodeType.Parent) { + return vGap / 2; + } + const selfGap = expanded && project_dependency?.url ? nodeHeight + vGap : 0; + const nextNode = getSameHierarchyNextNode(model, hierarchyNodes); + if (!nextNode) { + return vGap / 2; + } + const nextGap = nextNode.expanded === true && nextNode.datasetLen > 0 ? nodeHeight + vGap : 0; + return (selfGap + nextGap + vGap) / 2; + }, + getHGap: (node: NodeConfig) => { + const model = node as ModelDepsData; + return ( + (getHierarchyWidth(model.level, hierarchyNodes) + + getHierarchyWidth(model.level + 1, hierarchyNodes) + + hGap) / + 2 + ); + }, }; // 树形布局计算出坐标 @@ -191,11 +226,11 @@ export function getGraphData(data: ModelDepsData): GraphData { Util.traverseTree(treeLayoutData, (node: NodeConfig, parent: NodeConfig) => { const data = node.data as ModelDepsData; // 当前模型显示数据集和项目 - if (data.model_type === NodeType.current) { + if (data.expanded === true) { addDatasetDependency(data, node, nodes, edges); addProjectDependency(data, node, nodes, edges); - } else if (data.model_type === NodeType.children) { - adjustDatasetPosition(node); + } else if (data.model_type === NodeType.Children) { + // adjustDatasetPosition(node); } nodes.push({ ...data, @@ -219,16 +254,16 @@ const addDatasetDependency = ( nodes: NodeConfig[], edges: EdgeConfig[], ) => { - const { train_dataset, test_dataset } = data; + const { train_dataset, test_dataset, id } = data; train_dataset.forEach((item) => { - item.id = `$DTrain_${item.dataset_id}_${item.dataset_version}`; - item.model_type = NodeType.trainDataset; - item.style = getStyle(NodeType.trainDataset); + item.id = `$DTrain_${id}_${item.dataset_id}_${item.dataset_version}`; + item.model_type = NodeType.TrainDataset; + item.style = getStyle(NodeType.TrainDataset); }); test_dataset.forEach((item) => { - item.id = `$DTest_${item.dataset_id}_${item.dataset_version}`; - item.model_type = NodeType.testDataset; - item.style = getStyle(NodeType.testDataset); + item.id = `$DTest_${id}_${item.dataset_id}_${item.dataset_version}`; + item.model_type = NodeType.TestDataset; + item.style = getStyle(NodeType.TestDataset); }); datasetNodes.length = 0; @@ -243,7 +278,7 @@ const addDatasetDependency = ( fittingString(node.dataset_version, ellipseWidth - labelPadding, nodeFontSize); const half = len / 2 - 0.5; - node.x = currentNode.x! - (half - index) * (ellipseWidth + 20); + node.x = currentNode.x! - (half - index) * (ellipseWidth + datasetHGap); node.y = currentNode.y! - nodeHeight - vGap; nodes.push(node); datasetNodes.push(node); @@ -264,14 +299,14 @@ const addProjectDependency = ( nodes: NodeConfig[], edges: EdgeConfig[], ) => { - const { project_dependency } = data; + const { project_dependency, id } = data; if (project_dependency?.url) { const node = { ...project_dependency }; - node.id = `$P_${node.url}_${node.branch}`; - node.model_type = NodeType.project; + node.id = `$P_${id}_${node.url}_${node.branch}`; + node.model_type = NodeType.Project; node.type = 'rect'; node.label = fittingString(node.name, nodeWidth - labelPadding, nodeFontSize); - node.style = getStyle(NodeType.project); + node.style = getStyle(NodeType.Project); node.style.radius = nodeHeight / 2; node.x = currentNode.x; node.y = currentNode.y! + nodeHeight + vGap; @@ -331,3 +366,49 @@ function adjustDatasetPosition(node: NodeConfig) { }); } } + +// 层级遍历树结构 +export function traverseHierarchically(data: ModelDepsData | undefined): ModelDepsData[] { + if (!data) return []; + let level = 0; + data.level = level; + const result: ModelDepsData[] = [data]; + let index = 0; + + while (index < result.length) { + const item = result[index]; + if (item.children) { + item.children.forEach((child) => { + child.level = item.level + 1; + result.push(child); + }); + } + index++; + } + + return result; +} + +// 找到同层次的下一个节点 +export function getSameHierarchyNextNode(node: ModelDepsData, nodes: ModelDepsData[]) { + const index = nodes.findIndex((item) => item.id === node.id); + if (index >= 0 && index < nodes.length - 1) { + const nextNode = nodes[index + 1]; + if (nextNode.level === node.level) { + return nextNode; + } + } + return null; +} + +// 得到层级的宽度 +export function getHierarchyWidth(level: number, nodes: ModelDepsData[]) { + const hierarchyNodes = nodes + .filter((item) => item.level === level && item.expanded === true) + .sort((a, b) => b.datasetLen - a.datasetLen); + const first = hierarchyNodes[0]; + if (first) { + return Math.max(((first.datasetLen - 1) * (nodeWidth + datasetHGap)) / 2, 0); + } + return 0; +} diff --git a/react-ui/src/pages/Model/components/NodeTooltips/index.tsx b/react-ui/src/pages/Model/components/NodeTooltips/index.tsx index 217222da..f5bb2c82 100644 --- a/react-ui/src/pages/Model/components/NodeTooltips/index.tsx +++ b/react-ui/src/pages/Model/components/NodeTooltips/index.tsx @@ -22,7 +22,7 @@ function ModelInfo({ resourceId, data, onVersionChange }: ModelInfoProps) { }; const gotoModelPage = () => { - if (data.model_type === NodeType.current) { + if (data.model_type === NodeType.Current) { return; } if (data.current_model_id === resourceId) { @@ -39,7 +39,7 @@ function ModelInfo({ resourceId, data, onVersionChange }: ModelInfoProps) {
模型名称: - {data.model_type === NodeType.current ? ( + {data.model_type === NodeType.Current ? ( {data.model_version_dependcy_vo?.name || '--'} @@ -199,14 +199,14 @@ function NodeTooltips({ if (!data) return null; let Component = null; const { model_type } = data; - if (model_type === NodeType.testDataset || model_type === NodeType.trainDataset) { + if (model_type === NodeType.TestDataset || model_type === NodeType.TrainDataset) { Component = ; - } else if (model_type === NodeType.project) { + } else if (model_type === NodeType.Project) { Component = ; } else if ( - model_type === NodeType.children || - model_type === NodeType.parent || - model_type === NodeType.current + model_type === NodeType.Children || + model_type === NodeType.Parent || + model_type === NodeType.Current ) { Component = ; } diff --git a/react-ui/src/pages/ModelDeployment/List/index.tsx b/react-ui/src/pages/ModelDeployment/List/index.tsx index 934b4cbd..af8fba44 100644 --- a/react-ui/src/pages/ModelDeployment/List/index.tsx +++ b/react-ui/src/pages/ModelDeployment/List/index.tsx @@ -223,7 +223,7 @@ function ModelDeployment() { { title: '操作', dataIndex: 'operation', - width: 350, + width: 250, key: 'operation', render: (_: any, record: ModelDeploymentData) => (
From 566aa26cd9d61b5d02b83352687875e534c2be43 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Mon, 1 Jul 2024 11:47:17 +0800 Subject: [PATCH 05/13] =?UTF-8?q?feat:=20=E5=AE=9E=E9=AA=8C=E5=AF=B9?= =?UTF-8?q?=E6=AF=94=E6=B7=BB=E5=8A=A0=E6=A8=AA=E5=90=91=E6=BB=91=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/mock/model.ts | 236 ++++++++++++++---- react-ui/src/components/PageTitle/index.less | 2 +- .../pages/Experiment/Comparison/config.tsx | 17 ++ .../pages/Experiment/Comparison/index.less | 6 + .../src/pages/Experiment/Comparison/index.tsx | 54 ++-- react-ui/src/pages/Experiment/index.jsx | 2 +- 6 files changed, 255 insertions(+), 62 deletions(-) create mode 100644 react-ui/src/pages/Experiment/Comparison/config.tsx diff --git a/react-ui/mock/model.ts b/react-ui/mock/model.ts index 02054802..af637db0 100644 --- a/react-ui/mock/model.ts +++ b/react-ui/mock/model.ts @@ -48,12 +48,33 @@ export default defineMock({ exp_ins_id: null, version: 'v0.1.0', ref_item: null, - train_task: {}, - train_dataset: [], - train_params: [], - train_image: null, - test_dataset: [], - project_dependency: {}, + train_task: { + name: '模型训练测试导出0529', + ins_id: 229, + task_id: 'model-train-5d76f002', + }, + train_dataset: [ + { + dataset_id: 20, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + ], + train_params: ['256', '2'], + train_image: + '172.20.32.187/machine-learning/pytorch:pytorch_1.9.1_cuda11.1_detection_aim', + test_dataset: [ + { + dataset_id: 20, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + ], + project_dependency: { + url: 'https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git', + name: 'somun202304241505581', + branch: 'train_ci_test', + }, parent_models_map: [], parent_models: [], children_models: null, @@ -80,12 +101,38 @@ export default defineMock({ exp_ins_id: null, version: 'v0.3.0', ref_item: null, - train_task: {}, - train_dataset: [], - train_params: [], - train_image: null, - test_dataset: [], - project_dependency: {}, + train_task: { + name: '模型训练测试导出0529', + ins_id: 229, + task_id: 'model-train-5d76f002', + }, + train_dataset: [ + { + dataset_id: 120, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + { + dataset_id: 20, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + ], + train_params: ['256', '2'], + train_image: + '172.20.32.187/machine-learning/pytorch:pytorch_1.9.1_cuda11.1_detection_aim', + test_dataset: [ + { + dataset_id: 20, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + ], + project_dependency: { + url: 'https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git', + name: 'somun202304241505581', + branch: 'train_ci_test', + }, parent_models_map: [], parent_models: [], children_models: [], @@ -110,12 +157,33 @@ export default defineMock({ exp_ins_id: null, version: 'v0.31.0', ref_item: null, - train_task: {}, - train_dataset: [], - train_params: [], - train_image: null, - test_dataset: [], - project_dependency: {}, + train_task: { + name: '模型训练测试导出0529', + ins_id: 229, + task_id: 'model-train-5d76f002', + }, + train_dataset: [ + { + dataset_id: 20, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + ], + train_params: ['256', '2'], + train_image: + '172.20.32.187/machine-learning/pytorch:pytorch_1.9.1_cuda11.1_detection_aim', + test_dataset: [ + { + dataset_id: 20, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + ], + project_dependency: { + url: 'https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git', + name: 'somun202304241505581', + branch: 'train_ci_test', + }, parent_models_map: [], parent_models: [], children_models: [], @@ -140,12 +208,33 @@ export default defineMock({ exp_ins_id: null, version: 'v0.4.0', ref_item: null, - train_task: {}, - train_dataset: [], - train_params: [], - train_image: null, - test_dataset: [], - project_dependency: {}, + train_task: { + name: '模型训练测试导出0529', + ins_id: 229, + task_id: 'model-train-5d76f002', + }, + train_dataset: [ + { + dataset_id: 20, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + ], + train_params: ['256', '2'], + train_image: + '172.20.32.187/machine-learning/pytorch:pytorch_1.9.1_cuda11.1_detection_aim', + test_dataset: [ + { + dataset_id: 20, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + ], + project_dependency: { + url: 'https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git', + name: 'somun202304241505581', + branch: 'train_ci_test', + }, parent_models_map: [], parent_models: [], children_models: [ @@ -154,12 +243,33 @@ export default defineMock({ exp_ins_id: null, version: 'v0.6.0', ref_item: null, - train_task: {}, - train_dataset: [], - train_params: [], - train_image: null, - test_dataset: [], - project_dependency: {}, + train_task: { + name: '模型训练测试导出0529', + ins_id: 229, + task_id: 'model-train-5d76f002', + }, + train_dataset: [ + { + dataset_id: 20, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + ], + train_params: ['256', '2'], + train_image: + '172.20.32.187/machine-learning/pytorch:pytorch_1.9.1_cuda11.1_detection_aim', + test_dataset: [ + { + dataset_id: 20, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + ], + project_dependency: { + url: 'https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git', + name: 'somun202304241505581', + branch: 'train_ci_test', + }, parent_models_map: [], parent_models: [], children_models: [], @@ -231,12 +341,33 @@ export default defineMock({ exp_ins_id: null, version: 'v0.5.0', ref_item: null, - train_task: {}, - train_dataset: [], - train_params: [], - train_image: null, - test_dataset: [], - project_dependency: {}, + train_task: { + name: '模型训练测试导出0529', + ins_id: 229, + task_id: 'model-train-5d76f002', + }, + train_dataset: [ + { + dataset_id: 20, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + ], + train_params: ['256', '2'], + train_image: + '172.20.32.187/machine-learning/pytorch:pytorch_1.9.1_cuda11.1_detection_aim', + test_dataset: [ + { + dataset_id: 20, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + ], + project_dependency: { + url: 'https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git', + name: 'somun202304241505581', + branch: 'train_ci_test', + }, parent_models_map: [], parent_models: [], children_models: [ @@ -275,12 +406,33 @@ export default defineMock({ exp_ins_id: null, version: 'v0.11.0', ref_item: null, - train_task: {}, - train_dataset: [], - train_params: [], - train_image: null, - test_dataset: [], - project_dependency: {}, + train_task: { + name: '模型训练测试导出0529', + ins_id: 229, + task_id: 'model-train-5d76f002', + }, + train_dataset: [ + { + dataset_id: 20, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + ], + train_params: ['256', '2'], + train_image: + '172.20.32.187/machine-learning/pytorch:pytorch_1.9.1_cuda11.1_detection_aim', + test_dataset: [ + { + dataset_id: 20, + dataset_version: 'v0.1.0', + dataset_name: '手写体识别模型依赖测试训练数据集', + }, + ], + project_dependency: { + url: 'https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git', + name: 'somun202304241505581', + branch: 'train_ci_test', + }, parent_models_map: [], parent_models: [], children_models: [], diff --git a/react-ui/src/components/PageTitle/index.less b/react-ui/src/components/PageTitle/index.less index d120009b..47907246 100644 --- a/react-ui/src/components/PageTitle/index.less +++ b/react-ui/src/components/PageTitle/index.less @@ -6,5 +6,5 @@ background-image: url(@/assets/img/page-title-bg.png); background-repeat: no-repeat; background-position: top center; - background-size: 100%; + background-size: 100% 100%; } diff --git a/react-ui/src/pages/Experiment/Comparison/config.tsx b/react-ui/src/pages/Experiment/Comparison/config.tsx new file mode 100644 index 00000000..c6c53971 --- /dev/null +++ b/react-ui/src/pages/Experiment/Comparison/config.tsx @@ -0,0 +1,17 @@ +export enum ComparisonType { + Train = 'Train', // 训练 + Evaluate = 'Evaluate', // 评估 +} + +type ComparisonTypeInfo = { + title: string; +}; + +export const comparisonConfig: Record = { + [ComparisonType.Train]: { + title: '训练', + }, + [ComparisonType.Evaluate]: { + title: '评估', + }, +}; diff --git a/react-ui/src/pages/Experiment/Comparison/index.less b/react-ui/src/pages/Experiment/Comparison/index.less index a491c621..7a97a588 100644 --- a/react-ui/src/pages/Experiment/Comparison/index.less +++ b/react-ui/src/pages/Experiment/Comparison/index.less @@ -22,6 +22,12 @@ .ant-table-container { border: none !important; } + .ant-table-thead { + .ant-table-cell { + background-color: rgb(247, 247, 247); + border-color: #e8e8e8 !important; + } + } .ant-table-tbody { .ant-table-cell { border-right: none !important; diff --git a/react-ui/src/pages/Experiment/Comparison/index.tsx b/react-ui/src/pages/Experiment/Comparison/index.tsx index 12b60416..3aca2028 100644 --- a/react-ui/src/pages/Experiment/Comparison/index.tsx +++ b/react-ui/src/pages/Experiment/Comparison/index.tsx @@ -7,17 +7,13 @@ import { import { to } from '@/utils/promise'; import tableCellRender, { arrayFormatter, dateFormatter } from '@/utils/table'; import { useSearchParams } from '@umijs/max'; -import { App, Button, Table, /* TablePaginationConfig,*/ TableProps } from 'antd'; +import { App, Button, Table, /* TablePaginationConfig,*/ TableProps, Tooltip } from 'antd'; import classNames from 'classnames'; import { useEffect, useMemo, useState } from 'react'; import ExperimentStatusCell from '../components/ExperimentStatusCell'; +import { ComparisonType, comparisonConfig } from './config'; import styles from './index.less'; -export enum ComparisonType { - Train = 'Train', // 训练 - Evaluate = 'Evaluate', // 评估 -} - type TableData = { experiment_ins_id: number; run_id: string; @@ -32,7 +28,7 @@ type TableData = { function ExperimentComparison() { const [searchParams] = useSearchParams(); - const comparisonType = searchParams.get('type'); + const comparisonType = searchParams.get('type') as ComparisonType; const experimentId = searchParams.get('id'); const [tableData, setTableData] = useState([]); // const [cacheState, setCacheState] = useCacheState(); @@ -40,6 +36,7 @@ function ExperimentComparison() { const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [loading, setLoading] = useState(false); const { message } = App.useApp(); + const config = useMemo(() => comparisonConfig[comparisonType], [comparisonType]); // const [pagination, setPagination] = useState( // cacheState?.pagination ?? { // current: 1, @@ -94,6 +91,7 @@ function ExperimentComparison() { // 选择行 const rowSelection: TableProps['rowSelection'] = { type: 'checkbox', + fixed: 'left', selectedRowKeys, onChange: (selectedRowKeys: React.Key[], selectedRows: any[]) => { console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows); @@ -111,7 +109,9 @@ function ExperimentComparison() { title: '实例 ID', dataIndex: 'experiment_ins_id', key: 'experiment_ins_id', - width: '20%', + width: 100, + fixed: 'left', + align: 'center', render: tableCellRender(), }, { @@ -119,43 +119,61 @@ function ExperimentComparison() { dataIndex: 'start_time', key: 'start_time', width: 180, + fixed: 'left', + align: 'center', render: tableCellRender(false, dateFormatter), }, { title: '运行状态', dataIndex: 'status', key: 'status', - width: '20%', + width: 100, + fixed: 'left', + align: 'center', render: ExperimentStatusCell, }, { - title: '训练数据集', + title: `${config.title}数据集`, dataIndex: 'dataset', key: 'dataset', - width: '20%', + width: 180, + fixed: 'left', + align: 'center', render: tableCellRender(true, arrayFormatter()), ellipsis: { showTitle: false }, }, ], }, { - title: '训练参数', + title: `${config.title}参数`, + align: 'center', children: first?.params_names.map((name) => ({ - title: name, + title: ( + + {name} + + ), dataIndex: ['params', name], key: name, - width: '20%', + width: 120, + align: 'center', render: tableCellRender(true), ellipsis: { showTitle: false }, })), }, { - title: '训练指标', + title: `${config.title}指标`, + align: 'center', children: first?.metrics_names.map((name) => ({ - title: name, + title: ( + + {name} + + ), dataIndex: ['metrics', name], key: name, - width: '20%', + width: 120, + align: 'center', render: tableCellRender(true), ellipsis: { showTitle: false }, })), @@ -180,7 +198,7 @@ function ExperimentComparison() { dataSource={tableData} columns={columns} rowSelection={rowSelection} - scroll={{ y: 'calc(100% - 55px)' }} + scroll={{ y: 'calc(100% - 55px)', x: '100%' }} pagination={false} bordered={true} loading={loading} diff --git a/react-ui/src/pages/Experiment/index.jsx b/react-ui/src/pages/Experiment/index.jsx index 68f4fd96..3bbecbb8 100644 --- a/react-ui/src/pages/Experiment/index.jsx +++ b/react-ui/src/pages/Experiment/index.jsx @@ -23,7 +23,7 @@ import { App, Button, ConfigProvider, Dropdown, Space, Table, Tooltip } from 'an import classNames from 'classnames'; import { useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { ComparisonType } from './Comparison'; +import { ComparisonType } from './Comparison/config'; import AddExperimentModal from './components/AddExperimentModal'; import TensorBoardStatusCell from './components/TensorBoardStatus'; import Styles from './index.less'; From 16fc554008a430e777c2ceaff2e0950c2f1c96d7 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Mon, 1 Jul 2024 14:49:56 +0800 Subject: [PATCH 06/13] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9=E6=B5=81?= =?UTF-8?q?=E6=B0=B4=E7=BA=BF=E4=B8=8A=E4=B8=8B=E6=96=87=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/src/components/KFIcon/index.tsx | 2 +- react-ui/src/iconfont/iconfont.js | 2 +- react-ui/src/pages/Experiment/Info/index.jsx | 52 ++++++++++++----- .../src/pages/Pipeline/editPipeline/index.jsx | 58 +++++++++++-------- .../pages/Pipeline/editPipeline/index.less | 33 +++++++++++ 5 files changed, 109 insertions(+), 38 deletions(-) diff --git a/react-ui/src/components/KFIcon/index.tsx b/react-ui/src/components/KFIcon/index.tsx index 65239957..e50dabec 100644 --- a/react-ui/src/components/KFIcon/index.tsx +++ b/react-ui/src/components/KFIcon/index.tsx @@ -1,7 +1,7 @@ /* * @Author: 赵伟 * @Date: 2024-04-17 12:53:06 - * @Description: + * @Description: 封装 iconfont 组件 */ import '@/iconfont/iconfont-menu.js'; import '@/iconfont/iconfont.js'; diff --git a/react-ui/src/iconfont/iconfont.js b/react-ui/src/iconfont/iconfont.js index 1ec213e7..6d617cfb 100644 --- a/react-ui/src/iconfont/iconfont.js +++ b/react-ui/src/iconfont/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_4511447='',function(t){var a=(a=document.getElementsByTagName("script"))[a.length-1],h=a.getAttribute("data-injectcss"),a=a.getAttribute("data-disable-injectsvg");if(!a){var l,v,z,i,o,m=function(a,h){h.parentNode.insertBefore(a,h)};if(h&&!t.__iconfont__svg__cssinject__){t.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}l=function(){var a,h=document.createElement("div");h.innerHTML=t._iconfont_svg_string_4511447,(h=h.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",h=h,(a=document.body).firstChild?m(h,a.firstChild):a.appendChild(h))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(l,0):(v=function(){document.removeEventListener("DOMContentLoaded",v,!1),l()},document.addEventListener("DOMContentLoaded",v,!1)):document.attachEvent&&(z=l,i=t.document,o=!1,d(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,p())})}function p(){o||(o=!0,z())}function d(){try{i.documentElement.doScroll("left")}catch(a){return void setTimeout(d,50)}p()}}(window); \ No newline at end of file +window._iconfont_svg_string_4511447='',function(t){var a=(a=document.getElementsByTagName("script"))[a.length-1],h=a.getAttribute("data-injectcss"),a=a.getAttribute("data-disable-injectsvg");if(!a){var l,v,z,i,o,m=function(a,h){h.parentNode.insertBefore(a,h)};if(h&&!t.__iconfont__svg__cssinject__){t.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}l=function(){var a,h=document.createElement("div");h.innerHTML=t._iconfont_svg_string_4511447,(h=h.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",h=h,(a=document.body).firstChild?m(h,a.firstChild):a.appendChild(h))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(l,0):(v=function(){document.removeEventListener("DOMContentLoaded",v,!1),l()},document.addEventListener("DOMContentLoaded",v,!1)):document.attachEvent&&(z=l,i=t.document,o=!1,d(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,p())})}function p(){o||(o=!0,z())}function d(){try{i.documentElement.doScroll("left")}catch(a){return void setTimeout(d,50)}p()}}(window); \ No newline at end of file diff --git a/react-ui/src/pages/Experiment/Info/index.jsx b/react-ui/src/pages/Experiment/Info/index.jsx index db217197..03398efb 100644 --- a/react-ui/src/pages/Experiment/Info/index.jsx +++ b/react-ui/src/pages/Experiment/Info/index.jsx @@ -25,10 +25,6 @@ function ExperimentText() { const getGraphData = (data) => { if (graph) { - // 修改历史数据有蓝色边框的问题 - data.nodes.forEach((item) => { - item.style.stroke = '#fff'; - }); graph.data(data); graph.render(); } else { @@ -70,6 +66,18 @@ function ExperimentText() { useEffect(() => { initGraph(); getFirstWorkflow(locationParams.workflowId); + + const changeSize = () => { + if (!graph || graph.get('destroyed')) return; + if (!graphRef.current) return; + graph.changeSize(graphRef.current.clientWidth, graphRef.current.clientHeight); + graph.fitView(); + }; + + window.addEventListener('resize', changeSize); + return () => { + window.removeEventListener('resize', changeSize); + }; }, []); const initGraph = () => { @@ -144,7 +152,7 @@ function ExperimentText() { if (value) { shape.attr('stroke', themes['primaryColor']); } else { - shape.attr('stroke', '#fff'); + shape.attr('stroke', 'transparent'); } } }, @@ -196,8 +204,14 @@ function ExperimentText() { }, style: { fill: '#fff', - stroke: '#fff', - radius: 10, + stroke: 'transparent', + cursor: 'pointer', + radius: 8, + shadowColor: 'rgba(75, 84, 137, 0.4)', + shadowBlur: 6, + shadowOffsetX: 0, + shadowOffsetY: 0, + overflow: 'hidden', lineWidth: 0.5, }, }, @@ -224,6 +238,23 @@ function ExperimentText() { }, }, }); + + // 修改历史数据样式问题 + graph.node((node) => { + return { + style: { + stroke: 'transparent', + radius: 8, + }, + }; + }); + + // 绑定事件 + bindEvents(); + }; + + // 绑定事件 + const bindEvents = () => { graph.on('node:click', (e) => { if (e.target.get('name') !== 'anchor-point' && e.item) { propsRef.current.showDrawer(e, locationParams.id, messageRef.current); @@ -235,13 +266,8 @@ function ExperimentText() { graph.on('node:mouseleave', (e) => { graph.setItemState(e.item, 'hover', false); }); - window.onresize = () => { - if (!graph || graph.get('destroyed')) return; - if (!graphRef.current) return; - graph.changeSize(graphRef.current.clientWidth, graphRef.current.clientHeight); - graph.fitView(); - }; }; + return (
diff --git a/react-ui/src/pages/Pipeline/editPipeline/index.jsx b/react-ui/src/pages/Pipeline/editPipeline/index.jsx index 2f434cb0..1fc2f62b 100644 --- a/react-ui/src/pages/Pipeline/editPipeline/index.jsx +++ b/react-ui/src/pages/Pipeline/editPipeline/index.jsx @@ -122,10 +122,6 @@ const EditPipeline = () => { // 渲染数据 const getGraphData = (data) => { if (graph) { - // 修改历史数据有蓝色边框的问题 - data.nodes.forEach((item) => { - item.style.stroke = '#fff'; - }); graph.data(data); graph.render(); } else { @@ -371,7 +367,7 @@ const EditPipeline = () => { point.show(); }); } else { - shape.attr('stroke', '#fff'); + shape.attr('stroke', 'transparent'); anchorPoints.forEach((point) => { point.hide(); }); @@ -467,9 +463,13 @@ const EditPipeline = () => { }, style: { fill: '#fff', - stroke: '#fff', + stroke: 'transparent', cursor: 'pointer', - radius: 10, + radius: 8, + shadowColor: 'rgba(75, 84, 137, 0.4)', + shadowBlur: 6, + shadowOffsetX: 0, + shadowOffsetY: 0, overflow: 'hidden', lineWidth: 0.5, }, @@ -500,9 +500,21 @@ const EditPipeline = () => { }, }); + // 修改历史数据样式问题 + graph.node((node) => { + return { + style: { + stroke: 'transparent', + radius: 8, + }, + }; + }); + + // 绑定事件 bindEvents(); }; + // 绑定事件 const bindEvents = () => { graph.on('node:click', (e) => { if (e.target.get('name') !== 'anchor-point' && e.item) { @@ -599,25 +611,25 @@ const EditPipeline = () => { // 上下文菜单 const initMenu = () => { const contextMenu = new G6.Menu({ + className: 'pipeline-context-menu', getContent(evt) { const type = evt.item.getType(); - const cloneDisplay = type === 'node' ? 'block' : 'none'; + const cloneDisplay = type === 'node' ? 'flex' : 'none'; return ` -
    -
  • 复制
  • -
  • 删除
  • -
`; +
+
+ + + + 复制 +
+
+ + + + 删除 +
+
`; }, handleMenuClick: (target, item) => { switch (target.getAttribute('code')) { diff --git a/react-ui/src/pages/Pipeline/editPipeline/index.less b/react-ui/src/pages/Pipeline/editPipeline/index.less index 1189e4f8..7a2cf09f 100644 --- a/react-ui/src/pages/Pipeline/editPipeline/index.less +++ b/react-ui/src/pages/Pipeline/editPipeline/index.less @@ -28,3 +28,36 @@ } } } + +:global { + .pipeline-context-menu { + width: 78px; + padding: 10px 0; + background: #ffffff; + border-radius: 6px; + box-shadow: 0px 0px 6px rgba(40, 84, 168, 0.21); + + &__item { + display: flex; + align-items: center; + width: 100%; + height: 34px; + padding-left: 12px; + color: @text-color-secondary; + font-size: 15px; + cursor: pointer; + + &:hover { + color: @primary-color; + background-color: .addAlpha(#8895a8, 0.11) []; + } + + &__icon { + width: 1em; + height: 1em; + margin-right: 9px; + fill: currentColor; + } + } + } +} From 15376cb7a0c6907a6cb2081a2beb7b319f1981e1 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Mon, 1 Jul 2024 17:34:40 +0800 Subject: [PATCH 07/13] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9=E5=9B=BE?= =?UTF-8?q?=E6=A0=87=E5=92=8C=E6=A0=87=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/config/config.ts | 2 +- react-ui/config/defaultSettings.ts | 2 +- react-ui/config/routes.ts | 2 +- .../public/assets/images/left-top-logo-1.png | Bin 0 -> 4760 bytes .../public/assets/images/left-top-logo.png | Bin 4760 -> 5270 bytes react-ui/src/pages/User/Login/index.tsx | 6 +++--- 6 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 react-ui/public/assets/images/left-top-logo-1.png diff --git a/react-ui/config/config.ts b/react-ui/config/config.ts index 3b681f86..759d7c56 100644 --- a/react-ui/config/config.ts +++ b/react-ui/config/config.ts @@ -76,7 +76,7 @@ export default defineConfig({ * @name layout 插件 * @doc https://umijs.org/docs/max/layout-menu */ - title: '智能软件开发平台', + title: '智能材料科研平台', layout: { locale: false, ...defaultSettings, diff --git a/react-ui/config/defaultSettings.ts b/react-ui/config/defaultSettings.ts index 97a26343..d1842286 100644 --- a/react-ui/config/defaultSettings.ts +++ b/react-ui/config/defaultSettings.ts @@ -16,7 +16,7 @@ const Settings: ProLayoutProps & { fixSiderbar: false, splitMenus: false, colorWeak: false, - title: '智能软件开发平台', + title: '智能材料科研平台', pwa: true, logo: '/assets/images/left-top-logo.png', token: { diff --git a/react-ui/config/routes.ts b/react-ui/config/routes.ts index e89d5d60..960a3cb0 100644 --- a/react-ui/config/routes.ts +++ b/react-ui/config/routes.ts @@ -112,7 +112,7 @@ export default [ { name: '开发环境', path: '', - component: './DevelopmentEnvironment/List', + component: './DevelopmentEnvironment/Editor', }, { name: '创建编辑器', diff --git a/react-ui/public/assets/images/left-top-logo-1.png b/react-ui/public/assets/images/left-top-logo-1.png new file mode 100644 index 0000000000000000000000000000000000000000..64bdaf2cf55b78ae2e07835a6bf4adbdbd2def0f GIT binary patch literal 4760 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 literal 4760 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 { style={{ height: '42px', marginRight: '10px' }} alt="" /> - 智能软件开发平台 + 智能材料科研平台
- 智能软件开发平台 + 智能材料科研平台 {
hello~ 欢迎登陆 - 智能软件开发平台 + 智能材料科研平台
Date: Tue, 2 Jul 2024 11:22:40 +0800 Subject: [PATCH 08/13] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=AD=98=E5=82=A8?= =?UTF-8?q?=E5=9C=B0=E5=9D=80BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruoyi/platform/service/impl/DatasetVersionServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/DatasetVersionServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/DatasetVersionServiceImpl.java index afbd96bf..25b0df74 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/DatasetVersionServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/DatasetVersionServiceImpl.java @@ -240,7 +240,7 @@ public class DatasetVersionServiceImpl implements DatasetVersionService { datasetVersion.setFileName(dataset.getName()+"_"+labelDatasetVersionVo.getVersion()+"."+labelDatasetVersionVo.getExportType()); datasetVersion.setFileSize(formattedSize); - datasetVersion.setUrl(url); + datasetVersion.setUrl(objectName); datasetVersion.setDescription(labelDatasetVersionVo.getDesc()); this.insert(datasetVersion); } From 5ee8a6bc17b1c2910c5b753af66e43e83e00cd95 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Tue, 2 Jul 2024 17:05:24 +0800 Subject: [PATCH 09/13] =?UTF-8?q?feat:=20=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E5=BF=85=E5=A1=AB=E9=A1=B9=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/assets/img/experiment-running.png | Bin 0 -> 2097 bytes react-ui/src/assets/img/pipeline-warning.png | Bin 0 -> 1652 bytes .../src/components/ParameterInput/index.tsx | 68 ++++++++----- react-ui/src/pages/Experiment/Info/index.jsx | 2 +- .../pages/ModelDeployment/Create/index.tsx | 37 ++++++-- .../src/pages/Pipeline/editPipeline/index.jsx | 69 ++++++++------ .../pages/Pipeline/editPipeline/index.less | 3 +- .../src/pages/Pipeline/editPipeline/props.tsx | 89 +++++++++++------- react-ui/src/utils/index.ts | 23 +++++ react-ui/src/utils/promise.ts | 8 +- 10 files changed, 195 insertions(+), 104 deletions(-) create mode 100644 react-ui/src/assets/img/experiment-running.png create mode 100644 react-ui/src/assets/img/pipeline-warning.png diff --git a/react-ui/src/assets/img/experiment-running.png b/react-ui/src/assets/img/experiment-running.png new file mode 100644 index 0000000000000000000000000000000000000000..3155302a67febe5f321b51c9ae34f25244b2b12d GIT binary patch literal 2097 zcmV-12+sG3P)%f%Q9^nx#74MvUf;Ekx&2LU4iRH!#VLM-$W z#RN=*00}DKgCaa21~9aR5=B6ii%Q@@kQX3P6EP~mTR>1FyDiXat+uA53ovQb;>5NpuWrydDkFW?CmM2eDQlK$OmuqhRw5U^YAmp>%lwkY8ky z>RQ%|&voZG(fI;m@C-RL9Htdu^0Z$;{LBX+TPaR2#+t>SUio+iqNGla3`_bD3lH&4rqERBIEt&z2uv<{)r zc&@2%Ug!aYguj{Ff9}sXhnNGK@Xg57T>zbvfM zKQW_1i4JaiN`Eft=;bg~o?R!}a!qsv0uka(4(W0?Mt^hmG;g+)X0?pVUDgq^(eGoo1CJ)dqL)Ac=K}~C91qR69D@f49N12 zi9R^2ySg47z*vTm3h6RORv_3xhWpb=JS^5*f@t1jsg3feLZ)%(ht%&3z*{qj?gs#- zBWOSX#JPBwDzZ7wtU#34%Eb`+RTIIp0ikM%#f#N`&)1peQw-B$Z5ek*3Oscj1gO=k ziQ3PbNaRSn1dfyUmo_qicu+>lhtnTOpgUS4V#E|m?4mthL)v@-qNt1%e+U+JRp3oiPpzebxxg(DCHt7S!>2pu;Cf$8l) zwEdGE1kN$oUziTnOgNg1TxiN6o&HjsZaCL0PFR0UGmWyDvKqBKl-YbZnMO8FqnCOE z z49ysgAn2^STterg!(^?<+Q3@D!w(Q{QNvTgWeLgk0M`ZFJ8)~)d37VF8@guZFOTq% zS+XW@3d|#jS|A%xYWAAn%+g1#!GiBVxokC4e8%_;9JmZ;po_0bJ@Q-G=BzdRRG%!I z8rnFOW*hdCPOE6B86~&u?waqfTa~l=#Rp+&5sWP><*Vs(BXW6h% zUwj5~DPG5TbhWL)AWRCNfveTCB<^D0NWZg{=!>06X$QlKCfvH)i!PN@uEFy-PvGK8 z9Sp*=2+O{66iG3(=`!}_^j(9$X)N{w1kdHSx)BKwZ_Ym0WLQ(I4?*l`ncn^xkmqsp zchMGq&QV!^F=~t@c6qV_F{oY^M-p@bS>~1M%nvB+?D!4aKis(St37WQh(jZP+2XHZK>^^V4g5T?ui*vx=da<+wD)|30xe8rJN{c``o;^19@?-S{mCbC$>e%;h#hB9 zf{wt5Dhg?Hy0Y*Ab~wm;vN=eVhbs^rCNe|b84A%sfN`a@r7OtQq=P2>l}OUPXEunV zZgOY=(HTV^2fEvO)HzE@598dFRz9l@1cT9W23ycdH*^c+`79((YjtHY0-{4R>g02{ zBeABC&tgM!>sy*cqb>+J^N3tba3*^y&LO{VvQT%?qM&*Phd_*vL>g;^wV~eo8p^93 zP$LK9v)F2w$&~JT;|}X=x*%zGdy_chRSwS@p)UBpztfe5K5qGyCuu4i)k2_~_gj9H z#Np8hZ7Qf+es*;%sg)DM=%e88!KUVtcH-VvGfukf@@fK3^8zsqC+5mc;4z>XqkFDf z;ddMwwjYt;K+n4goa0rc-3^c6emLI|SMP>PYC(NNBJdn+6o46>${q@6Gw-N{80jOFNK*%W9U`nq8h57VH8`qNrk|>DMRM!FD)$t5-<`0fe1WWPIq>e z>63Txm7PtmJ(2}4u?m&1a1rHP6kw@6S3LFDgD8F6bp|YQ zEzklfv1Vs+T)1#Tm7dkT1=s2kY=JD%CziS4(m4Xo7`nTEffT`D3+L11tB@b%@v71)gY=Pv5%dsCLjk!Gg zvLu|k{kqb2Z6IXfvTfulknUF^fuQ$(fXc#K#>1%=5VCxN1PGTZLb7nGD-Y2E0=)sJ z1nJ`$wjaxv(k@uaa@=DR9vK9B!!?xO&hTsv94^t_Szh6RVEIRYU8gjhq5_Vath1^Q!2Nhp8p*3wG`O_B9uRLO)OOv`U3K&Zm0 ztV$*XAq$r(-Qci1!kcmtt7KddQu(d_JlI2mT0;;5wP#Fu1nWMEtk(oWYqd%O#v}+; zI8Bqku^!TRyr2n$?rN2Yg;5a9D?(Pu8bIif--6B#(;&iz(*_VSZwQ+is({2!!&NU3 z>{a%f`AYx|AVgbfQ}SDbFvHZXi$4c2FWe&{Se=k}6q!n!XQ0w1Lu5y9_gK6VKL{4eI-^7kd96AOvT!@RZ(DdttP3u`Fb8 z>iDjZqN<568mmvq)JW%w`}X^yMrH*M9G>*Q*zO<0-Q;Af@f=EH)F~kmAgFuePEb%8qgl^r%BG96DyqSCXG>Ya8Rn=x*;X4wW(CCwT z4SIuPJ?g37W;buKCC3Ak8mIC1a1<+U_9+u&j1SWA3qQhq literal 0 HcmV?d00001 diff --git a/react-ui/src/components/ParameterInput/index.tsx b/react-ui/src/components/ParameterInput/index.tsx index 0fc08551..0c422bff 100644 --- a/react-ui/src/components/ParameterInput/index.tsx +++ b/react-ui/src/components/ParameterInput/index.tsx @@ -1,18 +1,28 @@ import { CloseOutlined } from '@ant-design/icons'; import { Input } from 'antd'; +import { RuleObject } from 'antd/es/form'; import classNames from 'classnames'; import './index.less'; -type ParameterInputData = { - value?: any; - showValue?: any; - fromSelect?: boolean; -} & Record; +// 对象 +export type ParameterInputObject = { + value?: any; // 值 + showValue?: any; // 显示值 + fromSelect?: boolean; // 是否来自选择 + activeTab?: string; // 选择镜像、数据集、模型时,保存当前激活的tab + expandedKeys?: string[]; // 选择镜像、数据集、模型时,保存展开的keys + checkedKeys?: string[]; // 选择镜像、数据集、模型时,保存选中的keys + [key: string]: any; +}; -interface ParameterInputProps { - value?: ParameterInputData; - onChange?: (value: ParameterInputData) => void; +// 值类型 +export type ParameterInputValue = ParameterInputObject | string; + +export interface ParameterInputProps { + value?: ParameterInputValue; + onChange?: (value?: ParameterInputValue) => void; onClick?: () => void; + onRemove?: () => void; canInput?: boolean; textArea?: boolean; placeholder?: string; @@ -27,6 +37,7 @@ function ParameterInput({ value, onChange, onClick, + onRemove, canInput = true, textArea = false, allowClear, @@ -42,8 +53,23 @@ function ParameterInput({ valueObj.showValue = valueObj.value; } const isSelect = valueObj?.fromSelect; - const InputComponent = textArea ? Input.TextArea : Input; const placeholder = valueObj?.placeholder || rest?.placeholder; + const InputComponent = textArea ? Input.TextArea : Input; + + // 删除 + const handleRemove = (e: React.MouseEvent) => { + e.stopPropagation(); + onChange?.({ + ...valueObj, + value: undefined, + showValue: undefined, + fromSelect: false, + activeTab: undefined, + expandedKeys: [], + checkedKeys: [], + }); + onRemove?.(); + }; return ( <> @@ -62,18 +88,7 @@ function ParameterInput({ {valueObj?.showValue} { - e.stopPropagation(); - onChange?.({ - ...valueObj, - value: undefined, - showValue: undefined, - fromSelect: false, - activeTab: undefined, - expandedKeys: undefined, - checkedKeys: undefined, - }); - }} + onClick={handleRemove} />
) : ( @@ -93,9 +108,9 @@ function ParameterInput({ onChange={(e) => onChange?.({ ...valueObj, - fromSelect: false, value: e.target.value, showValue: e.target.value, + fromSelect: false, }) } /> @@ -105,3 +120,12 @@ function ParameterInput({ } export default ParameterInput; + +// 必填校验 +export const requiredValidator = (rule: RuleObject, value: any) => { + const trueValue = typeof value === 'object' ? value?.value : value; + if (!trueValue) { + return Promise.reject(rule.message || '必填项'); + } + return Promise.resolve(); +}; diff --git a/react-ui/src/pages/Experiment/Info/index.jsx b/react-ui/src/pages/Experiment/Info/index.jsx index 03398efb..f8325562 100644 --- a/react-ui/src/pages/Experiment/Info/index.jsx +++ b/react-ui/src/pages/Experiment/Info/index.jsx @@ -19,7 +19,7 @@ function ExperimentText() { const [message, setMessage, messageRef] = useStateRef({}); const propsRef = useRef(); const navgite = useNavigate(); - const locationParams = useParams(); //新版本获取路由参数接口 + const locationParams = useParams(); // 新版本获取路由参数接口 const [paramsModalOpen, openParamsModal, closeParamsModal] = useVisible(false); const graphRef = useRef(); diff --git a/react-ui/src/pages/ModelDeployment/Create/index.tsx b/react-ui/src/pages/ModelDeployment/Create/index.tsx index 669130e6..d9836195 100644 --- a/react-ui/src/pages/ModelDeployment/Create/index.tsx +++ b/react-ui/src/pages/ModelDeployment/Create/index.tsx @@ -5,7 +5,7 @@ */ import KFIcon from '@/components/KFIcon'; import PageTitle from '@/components/PageTitle'; -import ParameterInput from '@/components/ParameterInput'; +import ParameterInput, { requiredValidator } from '@/components/ParameterInput'; import SubAreaTitle from '@/components/SubAreaTitle'; import { CommonTabKeys } from '@/enums'; import { useComputingResource } from '@/hooks/resource'; @@ -87,7 +87,7 @@ function ModelDeploymentCreate() { }; // 选择模型、镜像 - const selectResource = (name: string, type: ResourceSelectorType) => { + const selectResource = (formItemName: string, type: ResourceSelectorType) => { let resource: ResourceSelectorResponse | undefined; switch (type) { case ResourceSelectorType.Model: @@ -105,13 +105,25 @@ function ModelDeploymentCreate() { onOk: (res) => { if (res) { if (type === ResourceSelectorType.Mirror) { - form.setFieldValue(name, res.path); + form.setFieldValue(formItemName, res.path); setSelectedMirror(res); } else { - const showValue = `${res.name}:${res.version}`; - form.setFieldValue(name, { - ...pick(res, ['id', 'version', 'path']), + const { activeTab, id, name, version, path } = res; + const jsonObj = { + id, + version, + path, + }; + const value = JSON.stringify(jsonObj); + const showValue = `${name}:${version}`; + form.setFieldValue(formItemName, { + value, showValue, + fromSelect: true, + activeTab, + expandedKeys: [id], + checkedKeys: [`${id}-${version}`], + ...jsonObj, }); setSelectedModel(res); } @@ -121,8 +133,9 @@ function ModelDeploymentCreate() { } else { setSelectedMirror(undefined); } - form.setFieldValue(name, ''); + form.setFieldValue(formItemName, ''); } + form.validateFields([formItemName]); close(); }, }); @@ -258,10 +271,11 @@ function ModelDeploymentCreate() { name="model" rules={[ { - required: true, + validator: requiredValidator, message: '请选择模型', }, ]} + required > selectResource('model', ResourceSelectorType.Model)} + onChange={() => setSelectedModel(undefined)} /> @@ -291,16 +306,18 @@ function ModelDeploymentCreate() { name="image" rules={[ { - required: true, - message: '请输入镜像', + validator: requiredValidator, + message: '请选择镜像', }, ]} + required > selectResource('image', ResourceSelectorType.Mirror)} + onChange={() => setSelectedMirror(undefined)} /> diff --git a/react-ui/src/pages/Pipeline/editPipeline/index.jsx b/react-ui/src/pages/Pipeline/editPipeline/index.jsx index 1fc2f62b..c67c40ed 100644 --- a/react-ui/src/pages/Pipeline/editPipeline/index.jsx +++ b/react-ui/src/pages/Pipeline/editPipeline/index.jsx @@ -93,15 +93,17 @@ const EditPipeline = () => { return; } - const [propsRes, propsError] = await to(propsRef.current.getFieldsValue()); - if (propsError) { - message.error('节点必填项必须配置'); - return; - } propsRef.current.propClose(); setTimeout(() => { const data = graph.save(); console.log(data); + const errorNode = data.nodes.find((item) => { + return item.formError === true; + }); + if (errorNode) { + message.error(`【${errorNode.label}】节点必填项必须配置`); + return; + } const params = { ...locationParams, dag: JSON.stringify(data), @@ -298,7 +300,7 @@ const EditPipeline = () => { ); }, afterDraw(cfg, group) { - const image = group.addShape('image', { + group.addShape('image', { attrs: { x: -45, y: -10, @@ -325,7 +327,26 @@ const EditPipeline = () => { draggable: true, }); } + if (cfg.formError) { + group.addShape('image', { + attrs: { + x: 43, + y: -24, + width: 18, + height: 18, + img: require('@/assets/img/pipeline-warning.png'), + cursor: 'pointer', + }, + draggable: false, + capture: false, + }); + } const bbox = group.getBBox(); + if (cfg.formError) { + bbox.y += 6; + bbox.width -= 6; + bbox.height -= 6; + } const anchorPoints = this.getAnchorPoints(cfg); anchorPoints.forEach((anchorPos, i) => { group.addShape('circle', { @@ -345,18 +366,10 @@ const EditPipeline = () => { draggable: true, }); }); - return image; }, // response the state changes and show/hide the link-point circles setState(name, value, item) { - // const anchorPoints = item - // .getContainer() - // .findAll((ele) => ele.get('name') === 'anchor-point'); - // anchorPoints.forEach((point) => { - // if (value || point.get('links') > 0) point.show(); - // else point.hide(); - // }); const group = item.getContainer(); const shape = group.get('children')[0]; const anchorPoints = group.findAll((item) => item.get('name') === 'anchor-point'); @@ -617,30 +630,26 @@ const EditPipeline = () => { const cloneDisplay = type === 'node' ? 'flex' : 'none'; return `
-
- +
+ - 复制 + 复制
-
- +
+ - 删除 + 删除
`; }, handleMenuClick: (target, item) => { - switch (target.getAttribute('code')) { - case 'delete': - graph.removeItem(item); - break; - case 'clone': - cloneElement(item); - break; - default: - break; + const id = target.id; + if (id.startsWith('clone')) { + cloneElement(item); + } else if (id.startsWith('delete')) { + graph.removeItem(item); } }, // offsetX and offsetY include the padding of the parent container @@ -697,7 +706,7 @@ const EditPipeline = () => {
- + void; + onFormChange: (data: PipelineNodeModelSerialize) => void; }; -const PipelineNodeParameter = forwardRef(({ onParentChange }: PipelineNodeParameterProps, ref) => { +const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParameterProps, ref) => { const [form] = Form.useForm(); const [stagingItem, setStagingItem] = useState( {} as PipelineNodeModelSerialize, @@ -37,19 +37,28 @@ const PipelineNodeParameter = forwardRef(({ onParentChange }: PipelineNodeParame const [resourceStandardList, filterResourceStandard] = useComputingResource(); // 资源规模 const [menuItems, setMenuItems] = useState([]); - const afterOpenChange = () => { + const afterOpenChange = async () => { if (!open) { - console.log('getFieldsValue', form.getFieldsValue()); - const control_strategy = form.getFieldValue('control_strategy'); - const in_parameters = form.getFieldValue('in_parameters'); - const out_parameters = form.getFieldValue('out_parameters'); - onParentChange({ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [_values, error] = await to(form.validateFields()); + const fields = form.getFieldsValue(); + const control_strategy = JSON.stringify(fields.control_strategy); + const in_parameters = JSON.stringify(fields.in_parameters); + const out_parameters = JSON.stringify(fields.out_parameters); + console.log('getFieldsValue', fields); + + const res = { ...stagingItem, - ...form.getFieldsValue(), - control_strategy: JSON.stringify(control_strategy), - in_parameters: JSON.stringify(in_parameters), - out_parameters: JSON.stringify(out_parameters), - }); + ...fields, + control_strategy: control_strategy, + in_parameters: in_parameters, + out_parameters: out_parameters, + formError: !!error, + }; + + console.log('res', res); + + onFormChange(res); } }; const onClose = () => { @@ -57,15 +66,6 @@ const PipelineNodeParameter = forwardRef(({ onParentChange }: PipelineNodeParame }; useImperativeHandle(ref, () => ({ - getFieldsValue: async () => { - const [propsRes, propsError] = await to(form.validateFields()); - if (propsRes && !propsError) { - const values = form.getFieldsValue(); - return values; - } else { - return Promise.reject(propsError); - } - }, showDrawer(e: any, params: PipelineGlobalParam[], parentNodes: INode[]) { if (e.item && e.item.getModel()) { form.resetFields(); @@ -115,7 +115,6 @@ const PipelineNodeParameter = forwardRef(({ onParentChange }: PipelineNodeParame type = ResourceSelectorType.Mirror; break; } - const fieldValue = form.getFieldValue(formItemName); const activeTab = fieldValue?.activeTab as CommonTabKeys | undefined; const expandedKeys = Array.isArray(fieldValue?.expandedKeys) ? fieldValue?.expandedKeys : []; @@ -162,8 +161,21 @@ const PipelineNodeParameter = forwardRef(({ onParentChange }: PipelineNodeParame }); } } else { - form.setFieldValue(formItemName, ''); + if (type === ResourceSelectorType.Mirror && formItemName === 'image') { + form.setFieldValue(formItemName, undefined); + } else { + form.setFieldValue(formItemName, { + ...item, + value: undefined, + showValue: undefined, + fromSelect: false, + activeTab: undefined, + expandedKeys: [], + checkedKeys: [], + }); + } } + form.validateFields([formItemName]); close(); }, }); @@ -212,6 +224,18 @@ const PipelineNodeParameter = forwardRef(({ onParentChange }: PipelineNodeParame ); }; + // 必填项校验规则 + const getFormRules = (item: { key: string; value: PipelineNodeModelParameter }) => { + return item.value.require + ? [ + { + validator: requiredValidator, + message: '必填项', + }, + ] + : []; + }; + // 控制策略 const controlStrategyList = Object.entries(stagingItem.control_strategy ?? {}).map( ([key, value]) => ({ key, value }), @@ -232,7 +256,7 @@ const PipelineNodeParameter = forwardRef(({ onParentChange }: PipelineNodeParame