Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
B
bkunyun
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
bkunyun
Commits
d16c0cda
Commit
d16c0cda
authored
Jul 15, 2022
by
wuyongsheng
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feat-20220705-customTemplate' into 'master'
Feat 20220705 custom template See merge request
!24
parents
c2a9a9b4
76e598af
Show whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
2161 additions
and
668 deletions
+2161
-668
api_manager.ts
src/api/api_manager.ts
+2
-1
workbench_api.ts
src/api/workbench_api.ts
+14
-2
index.module.css
...components/BusinessComponents/FileSelect/index.module.css
+65
-0
index.tsx
src/components/BusinessComponents/FileSelect/index.tsx
+465
-0
Table.jsx
src/components/Material.Ui/Table.jsx
+9
-2
Dialog.tsx
src/components/mui/Dialog.tsx
+8
-0
MyInput.tsx
src/components/mui/MyInput.tsx
+4
-2
MyMenu.tsx
src/components/mui/MyMenu.tsx
+0
-1
MyPopconfirm.tsx
src/components/mui/MyPopconfirm.tsx
+0
-104
index.tsx
src/views/ConsoleLayout/components/FileItem/index.tsx
+4
-2
index.tsx
src/views/Project/ProjectData/index.tsx
+2
-1
index.tsx
src/views/Project/ProjectJobDetail/index.tsx
+7
-3
index.tsx
src/views/Project/ProjectSetting/index.tsx
+4
-1
index.tsx
src/views/Project/ProjectSubmitWork/ConfigForm/index.tsx
+39
-29
index.tsx
src/views/Project/ProjectSubmitWork/WorkFlow/index.tsx
+12
-5
index.tsx
src/views/Project/ProjectSubmitWork/index.tsx
+6
-14
interface.ts
src/views/Project/ProjectSubmitWork/interface.ts
+5
-4
index.tsx
...kbench/workbenchTemplate/components/AddTemplate/index.tsx
+55
-14
addTemplate.tsx
...ectWorkbench/workbenchTemplate/components/addTemplate.tsx
+1
-1
templateBox.tsx
...ectWorkbench/workbenchTemplate/components/templateBox.tsx
+22
-1
index.module.css
...oject/ProjectWorkbench/workbenchTemplate/index.module.css
+1
-0
index.module.css
...ect/components/Flow/components/BatchNode/index.module.css
+4
-10
index.tsx
...ws/Project/components/Flow/components/BatchNode/index.tsx
+115
-0
index.module.css
...ject/components/Flow/components/FlowNode/index.module.css
+25
-0
index.tsx
...ews/Project/components/Flow/components/FlowNode/index.tsx
+76
-0
index.tsx
src/views/Project/components/Flow/index.tsx
+299
-160
interface.ts
src/views/Project/components/Flow/interface.ts
+12
-2
index.module.css
...ews/WorkFlowEdit/components/OperatorList/index.module.css
+15
-0
index.tsx
src/views/WorkFlowEdit/components/OperatorList/index.tsx
+13
-3
index.module.css
...WorkFlowEdit/components/ParameterSetting/index.module.css
+22
-11
index.tsx
src/views/WorkFlowEdit/components/ParameterSetting/index.tsx
+389
-267
index.module.css
...rkFlowEdit/components/SaveCustomTemplate/index.module.css
+3
-0
index.tsx
...iews/WorkFlowEdit/components/SaveCustomTemplate/index.tsx
+256
-0
index.tsx
src/views/WorkFlowEdit/index.tsx
+116
-23
util.ts
src/views/WorkFlowEdit/util.ts
+91
-5
No files found.
src/api/api_manager.ts
View file @
d16c0cda
...
...
@@ -27,7 +27,7 @@ const RESTAPI = {
API_USER_PERMISSION_LIST
:
`
${
BACKEND_API_URI_PREFIX
}
/uaa/routes/privilege/list`
,
//获取用户包含的权限列表
API_WORKBENCH_TEMPLATE_LIST
:
`
${
BACKEND_API_URI_PREFIX
}
/cpp/workbench/project/workflowspec`
,
//查询项目下工作流模板列表
API_WORKBENCH_DELETE_TEMPLATE
:
`
${
BACKEND_API_URI_PREFIX
}
/cpp/workbench/project/workflowspec`
,
//项目管理员-删除工作流模板
API_WORKBENCH_ADD_TEMPLATE_LIST
:
`
${
BACKEND_API_URI_PREFIX
}
/cpp/workbench/pro
duct/
workflowspec`
,
//项目管理员-添加工作流模板-模板列表
API_WORKBENCH_ADD_TEMPLATE_LIST
:
`
${
BACKEND_API_URI_PREFIX
}
/cpp/workbench/pro
ject/notfavorited
workflowspec`
,
//项目管理员-添加工作流模板-模板列表
API_WORKBENCH_ADD_TEMPLATE
:
`
${
BACKEND_API_URI_PREFIX
}
/cpp/workbench/project/workflowspec`
,
//项目管理员-添加工作流模板-提交
API_FETCH_TEMPLATE_INFO
:
`
${
BACKEND_API_URI_PREFIX
}
/cpp/workbench/workflowspec`
,
//点击使用模版查看模版详情
API_WORK_FLOW_JOB
:
`
${
BACKEND_API_URI_PREFIX
}
/cpp/workbench/workflowjob`
,
//点击任务列表查看任务详情
...
...
@@ -38,6 +38,7 @@ const RESTAPI = {
API_WORKBENCH_WORKFLOW_TASKINFO
:
`
${
BACKEND_API_URI_PREFIX
}
/cpp/workbench/workflowjob/task-info`
,
//查询任务某个算子详情
API_OPERATOR_LIST
:
`
${
BACKEND_API_URI_PREFIX
}
/cpp/workflow/actorspecs`
,
// 获取算子列表
API_VERSION_OPERATOR
:
`
${
BACKEND_API_URI_PREFIX
}
/cpp/workflow/actorversion`
,
// 获取指定版本算子
API_SAVE_USERSPEC
:
`
${
BACKEND_API_URI_PREFIX
}
/cpp/workflow/saveuserspec`
,
// 保存用户自定义工作流模板
};
export
default
RESTAPI
;
src/api/workbench_api.ts
View file @
d16c0cda
...
...
@@ -55,7 +55,8 @@ const deleteWorkbenchTemplate = (params: workflowspecDeleteTemplateParams) => {
type
workflowspecGetAddTemplateParams
=
{
projectId
?:
string
;
productId
:
string
;
title
?:
string
;
keyword
?:
string
;
creator
?:
string
;
};
// 项目管理员-添加工作流模板-模板列表
...
...
@@ -146,6 +147,16 @@ const fetchVersionOperator = (params: IFetchOperatorListParams) => {
params
,
});
};
// 保存用户自定义工作流模板
const
saveUserSpec
=
(
params
:
any
)
=>
{
return
request
({
url
:
Api
.
API_SAVE_USERSPEC
,
method
:
"post"
,
data
:
params
,
});
};
export
{
current
,
menu
,
...
...
@@ -157,5 +168,6 @@ export {
deleteWorkflowJob
,
cancelWorkflowJob
,
fetchOperatorList
,
fetchVersionOperator
fetchVersionOperator
,
saveUserSpec
};
src/components/BusinessComponents/FileSelect/index.module.css
0 → 100644
View file @
d16c0cda
.FSBox
{
width
:
900px
;
position
:
relative
;
}
.FSTop
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
margin-bottom
:
16px
;
}
.showPathSpan
{
cursor
:
pointer
;
line-height
:
22px
;
font-size
:
14px
;
color
:
#1e2633
;
}
.showPathI
{
margin
:
0
10px
;
line-height
:
22px
;
font-size
:
20px
;
color
:
#c2c6cc
;
cursor
:
default
;
}
.showPathSpan
:hover
{
color
:
#1370ff
;
}
.showPathSpanActive
{
color
:
#1370ff
;
}
.noDataBox
{
background-color
:
#fff
;
height
:
calc
(
100vh
-
377px
);
display
:
flex
;
flex-direction
:
column
;
justify-content
:
center
;
align-items
:
center
;
position
:
relative
;
top
:
-53px
;
}
.noDataText
{
margin-top
:
8px
;
font-size
:
14px
;
line-height
:
22px
;
color
:
#8a9099
;
}
.folderIconBox
{
display
:
flex
;
justify-content
:
flex-start
;
align-items
:
center
;
}
.folderPointer
{
cursor
:
pointer
;
}
.folderIcon
{
margin-right
:
12px
;
}
src/components/BusinessComponents/FileSelect/index.tsx
0 → 100644
View file @
d16c0cda
import
React
,
{
useState
,
useCallback
,
useEffect
,
useMemo
}
from
"react"
;
import
style
from
"./index.module.css"
;
import
MyDialog
from
"../../mui/Dialog"
;
import
{
useStores
}
from
"@/store"
;
import
{
observer
}
from
"mobx-react-lite"
;
import
{
toJS
}
from
"mobx"
;
import
CloudEController
from
"@/api/fileserver/CloudEController"
;
import
{
getDataFind
,
getDataFileSearch
}
from
"@/api/project_api"
;
import
Table
from
"@/components/Material.Ui/Table"
;
import
noFile
from
"@/assets/project/noFile.svg"
;
import
folderIcon
from
"@/assets/project/folderIcon.svg"
;
import
SearchIcon
from
"@mui/icons-material/Search"
;
import
dataSetIcon
from
"@/assets/project/dataSetIcon.svg"
;
import
fileIcon
from
"@/assets/project/fileIcon.svg"
;
import
OutlinedInput
from
"@mui/material/OutlinedInput"
;
import
useMyRequest
from
"@/hooks/useMyRequest"
;
import
{
storageUnitFromB
}
from
"@/utils/util"
;
import
classnames
from
"classnames"
;
import
{
useMessage
}
from
"@/components/MySnackbar"
;
import
moment
from
"moment"
;
export
type
FileSelectType
=
"file"
|
"dataset"
|
"path"
;
// file 文件选择 dataset数据集选择 path文件夹选择
type
FileSelectProps
=
{
open
:
boolean
;
onConfirm
:
any
;
onClose
:
any
;
type
?:
FileSelectType
;
// file 文件选择 dataset数据集选择 path文件夹选择
};
const
FileSelect
=
observer
((
props
:
FileSelectProps
)
=>
{
const
{
onConfirm
,
type
=
"path"
}
=
props
;
const
{
currentProjectStore
}
=
useStores
();
const
Message
=
useMessage
();
const
projectId
=
toJS
(
currentProjectStore
.
currentProjectInfo
.
id
);
const
fileToken
=
toJS
(
currentProjectStore
.
currentProjectInfo
.
filetoken
);
const
[
path
,
setPath
]
=
useState
<
String
>
(
"/"
);
const
[
selectFileName
,
setSelectFileName
]
=
useState
(
""
);
const
[
selectItem
,
setSelectItem
]
=
useState
<
any
>
({});
// 防止用户连续点击文件夹造成路径显示错误
const
[
debounce
,
setDebounce
]
=
useState
(
false
);
// 文件夹、文件列表
const
[
list
,
setList
]
=
useState
<
any
>
([]);
// 数据集列表 不带文件
const
[
dataSetList
,
setDataSetList
]
=
useState
<
any
>
([]);
const
[
keyWord
,
setKeyWord
]
=
useState
(
""
);
// 点击确认时返回的路径
const
resultPath
=
useMemo
(()
=>
{
if
(
keyWord
)
{
if
(
selectFileName
)
{
console
.
log
(
"selectFileName"
,
selectFileName
);
console
.
log
(
"selectItem"
,
selectItem
.
dir
);
// dataset path: "/test/" path: "/"
// 其他 dir: "//call_logs/stdout/slurm/536f1e38-9357-470b-a0e9-fa5a9fbafe35/call-task_B/execution/"
//
if
(
type
===
"dataset"
)
{
return
`
${
selectItem
.
path
}${
selectFileName
}
`
;
}
else
if
(
type
===
"file"
)
{
return
`
${
selectItem
.
dir
.
slice
(
1
)}${
selectFileName
}
`
;
}
}
}
else
{
if
(
selectFileName
)
{
return
`
${
path
===
"/"
?
""
:
path
}
/
${
selectFileName
}
`
;
}
else
{
return
path
;
}
}
},
[
path
,
selectFileName
,
keyWord
,
selectItem
,
type
]);
console
.
log
(
"resultPath"
,
resultPath
);
const
fileSelectOnConfirm
=
()
=>
{
if
(
type
===
"file"
)
{
if
(
!
selectFileName
)
{
Message
.
error
(
"请选择一个文件"
);
return
;
}
else
if
(
selectItem
.
type
===
"directory"
)
{
Message
.
error
(
"现在选择的是文件夹,请重新选择"
);
return
;
}
}
else
if
(
type
===
"dataset"
)
{
if
(
!
selectFileName
)
{
Message
.
error
(
"请选择数据集"
);
return
;
}
else
if
(
selectItem
.
type
===
"directory"
)
{
Message
.
error
(
"现在选择的是文件夹,请重新选择"
);
return
;
}
}
onConfirm
(
resultPath
);
};
// 搜索值改变
const
handleKeyWordChange
=
(
e
:
any
)
=>
{
if
(
e
.
target
.
value
.
length
>
30
)
{
return
;
}
setKeyWord
(
e
.
target
.
value
);
};
// 文件夹下钻
const
handleViewFolders
=
(
item
:
any
)
=>
{
if
(
debounce
)
{
return
;
}
else
{
setDebounce
(
true
);
if
(
path
===
"/"
)
{
setPath
(
`/
${
item
.
name
}
`
);
}
else
{
setPath
(
`
${
path
}
/
${
item
.
name
}
`
);
}
}
};
// 获取某路径下的数据集fun
const
{
run
:
getDataFindRun
}
=
useMyRequest
(
getDataFind
,
{
onSuccess
:
(
res
:
any
)
=>
{
const
dataSetList
=
res
.
data
.
map
((
item
:
any
)
=>
{
return
{
...
item
,
type
:
"dataSet"
,
};
});
setDataSetList
(
dataSetList
);
setDebounce
(
false
);
},
});
// 获取某路径下的数据集
const
getDataSetList
=
useCallback
(()
=>
{
if
(
keyWord
)
{
return
;
}
else
if
(
projectId
)
{
return
getDataFindRun
({
projectId
:
projectId
as
string
,
path
:
path
===
"/"
?
"/"
:
`
${
path
}
/`
,
});
}
},
[
keyWord
,
path
,
projectId
,
getDataFindRun
]);
// 全局搜索数据集fun
const
{
run
:
getDataFileSearchRun
}
=
useMyRequest
(
getDataFileSearch
,
{
onSuccess
:
(
res
:
any
)
=>
{
const
dataSetList
=
res
.
data
.
map
((
item
:
any
)
=>
{
return
{
...
item
,
type
:
"dataSet"
,
};
});
setDataSetList
(
dataSetList
);
},
});
// 全局搜索数据集
const
getDataSetListSearch
=
useCallback
(()
=>
{
if
(
keyWord
&&
projectId
)
{
return
getDataFileSearchRun
({
projectId
:
projectId
as
string
,
name
:
keyWord
,
});
}
else
{
return
getDataSetList
();
}
},
[
keyWord
,
projectId
,
getDataFileSearchRun
,
getDataSetList
]);
// 获取某路径下的文件目录
const
getList
=
useCallback
(()
=>
{
if
(
keyWord
)
{
return
;
}
else
if
(
fileToken
&&
projectId
)
{
return
CloudEController
.
JobOutFileList
(
path
,
fileToken
,
projectId
,
false
)?.
then
((
res
)
=>
{
if
(
Array
.
isArray
(
res
.
data
))
{
setList
(
res
.
data
);
}
else
{
setList
([]);
}
setDebounce
(
false
);
});
}
},
[
fileToken
,
path
,
projectId
,
keyWord
]);
// 全局搜索文件列表
const
searchFileList
=
useCallback
(()
=>
{
if
(
!
keyWord
)
{
getList
();
}
else
{
if
(
fileToken
&&
projectId
)
{
setPath
(
"/"
);
return
CloudEController
.
JobSearchFileList
(
keyWord
,
"/"
,
fileToken
,
projectId
,
false
)?.
then
((
res
)
=>
{
if
(
Array
.
isArray
(
res
.
data
))
{
setList
(
res
.
data
);
}
else
{
setList
([]);
}
setDebounce
(
false
);
});
}
}
},
[
fileToken
,
projectId
,
keyWord
,
getList
]);
// table配置
const
renderName
=
(
item
:
any
)
=>
{
if
(
item
.
type
===
"directory"
)
{
return
(
<
span
className=
{
classnames
({
[
style
.
folderIconBox
]:
true
,
[
style
.
folderPointer
]:
true
,
})
}
onClick=
{
()
=>
!
keyWord
&&
handleViewFolders
(
item
)
}
>
<
img
className=
{
style
.
folderIcon
}
src=
{
folderIcon
}
alt=
""
/>
{
item
.
name
}
</
span
>
);
}
else
if
(
item
.
type
===
"dataSet"
)
{
return
(
<
span
className=
{
style
.
folderIconBox
}
>
<
img
className=
{
style
.
folderIcon
}
src=
{
dataSetIcon
}
alt=
""
/>
{
item
.
name
}
</
span
>
);
}
else
{
return
(
<
span
className=
{
style
.
folderIconBox
}
>
<
img
className=
{
style
.
folderIcon
}
src=
{
fileIcon
}
alt=
""
/>
{
item
.
name
}
</
span
>
);
}
};
// table配置
const
renderSize
=
(
item
:
any
)
=>
{
if
(
item
.
type
===
"dataSet"
)
{
return
`
${
item
.
size
}
条`
;
}
return
`
${
item
.
size
?
storageUnitFromB
(
Number
(
item
.
size
))
:
"-"
}
`
;
};
// table配置
const
renderMtime
=
(
item
:
any
)
=>
{
return
String
(
moment
(
item
.
mtime
).
format
(
"YYYY-MM-DD HH:mm:ss"
));
};
// table配置
const
versionsHeadCells
=
[
{
id
:
"name"
,
numeric
:
false
,
label
:
"名称"
,
width
:
"50%"
},
{
id
:
"size"
,
numeric
:
false
,
label
:
"大小"
,
width
:
"15%"
,
sort
:
true
},
{
id
:
"mtime"
,
numeric
:
false
,
label
:
"创建时间"
,
width
:
"20%"
,
sort
:
true
,
},
];
// 列表展示的数据
const
showList
=
useMemo
(()
=>
{
let
folderList
:
any
=
[];
let
fileList
:
any
=
[];
list
.
forEach
((
item
:
any
)
=>
{
if
(
item
.
type
===
"directory"
)
{
folderList
.
push
(
item
);
}
else
{
fileList
.
push
(
item
);
}
});
if
(
keyWord
)
{
if
(
type
===
"file"
)
{
return
fileList
;
}
else
if
(
type
===
"dataset"
)
{
return
dataSetList
;
}
else
{
return
folderList
;
}
}
else
{
if
(
type
===
"file"
)
{
return
[...
folderList
,
...
fileList
];
}
else
if
(
type
===
"dataset"
)
{
return
[...
folderList
,
...
dataSetList
];
}
else
{
return
[...
folderList
];
}
}
},
[
list
,
dataSetList
,
type
,
keyWord
]);
// 前端展示的文件路径
const
showPath
=
useMemo
(()
=>
{
if
(
path
===
"/"
)
{
return
<
span
className=
{
style
.
showPathSpan
}
>
ProjectData
</
span
>;
}
else
{
const
pathArr
=
path
.
split
(
"/"
);
if
(
pathArr
.
length
<=
4
)
{
return
pathArr
.
map
((
item
,
index
)
=>
{
return
(
<
span
key=
{
index
}
onClick=
{
()
=>
setPath
(
pathArr
.
slice
(
0
,
index
+
1
).
join
(
"/"
)
===
""
?
"/"
:
pathArr
.
slice
(
0
,
index
+
1
).
join
(
"/"
)
)
}
className=
{
classnames
({
[
style
.
showPathSpan
]:
true
,
[
style
.
showPathSpanActive
]:
index
===
pathArr
.
length
-
1
,
})
}
>
{
index
===
0
?
"ProjectData"
:
item
}{
" "
}
{
index
===
pathArr
.
length
-
1
?
null
:
(
<
i
className=
{
style
.
showPathI
}
>
{
">"
}
</
i
>
)
}
</
span
>
);
});
}
else
{
return
pathArr
.
map
((
item
,
index
)
=>
{
return
(
<
span
key=
{
index
}
onClick=
{
()
=>
{
if
(
index
===
1
)
{
return
;
}
setPath
(
pathArr
.
slice
(
0
,
index
+
1
).
join
(
"/"
)
===
""
?
"/"
:
pathArr
.
slice
(
0
,
index
+
1
).
join
(
"/"
)
);
}
}
className=
{
classnames
({
[
style
.
showPathSpan
]:
true
,
[
style
.
showPathSpanActive
]:
index
===
pathArr
.
length
-
1
,
})
}
>
{
index
===
0
?
"ProjectData"
:
index
>
pathArr
.
length
-
4
?
item
:
""
}
{
index
===
pathArr
.
length
-
1
||
(
index
<=
pathArr
.
length
-
4
&&
index
>
0
)
?
null
:
(
<
i
className=
{
style
.
showPathI
}
>
{
">"
}
</
i
>
)
}
{
index
===
1
&&
"..."
}
{
index
===
1
&&
<
i
className=
{
style
.
showPathI
}
>
{
">"
}
</
i
>
}
</
span
>
);
});
}
}
},
[
path
]);
const
getAllData
=
useCallback
(()
=>
{
setDataSetList
([]);
setList
([]);
setSelectFileName
(
""
);
setSelectItem
({});
if
(
type
===
"file"
||
type
===
"path"
)
{
// 不需要获取数据集
if
(
keyWord
)
{
// 搜索的话是全局搜
searchFileList
();
}
else
{
getList
();
}
}
else
{
// 需要获取数据集
if
(
keyWord
)
{
// 搜索的话是全局搜
searchFileList
();
getDataSetListSearch
();
}
else
{
getList
();
getDataSetList
();
}
}
},
[
type
,
keyWord
,
searchFileList
,
getList
,
getDataSetListSearch
,
getDataSetList
,
]);
useEffect
(()
=>
{
getAllData
();
},
[
getAllData
]);
const
radioClick
=
(
rowItem
:
any
)
=>
{
console
.
log
(
rowItem
);
setSelectItem
(
rowItem
);
let
name
=
rowItem
.
id
;
setSelectFileName
(
name
.
slice
(
5
,
name
.
indexOf
(
"&index="
)));
};
return
(
<
MyDialog
open=
{
props
.
open
}
onClose=
{
props
.
onClose
}
onConfirm=
{
fileSelectOnConfirm
}
title=
"文件选择器"
>
<
div
className=
{
style
.
FSBox
}
>
<
div
className=
{
style
.
FSTop
}
>
<
div
className=
{
style
.
FSPath
}
>
{
showPath
}
</
div
>
{
type
!==
"path"
&&
(
<
div
className=
{
style
.
FSKeyWord
}
>
<
OutlinedInput
value=
{
keyWord
}
onChange=
{
handleKeyWordChange
}
placeholder=
"输入关键词搜索"
size=
"small"
sx=
{
{
width
:
240
,
height
:
32
}
}
endAdornment=
{
<
SearchIcon
style=
{
{
color
:
"#8A9099"
}
}
/>
}
// onKeyUp=
{
handleKeyWordChangeKeyUp
}
/>
</
div
>
)
}
</
div
>
<
Table
footer=
{
false
}
rowHover=
{
true
}
nopadding=
{
true
}
stickyheader=
{
true
}
headCells=
{
versionsHeadCells
}
rowsPerPage=
{
"99"
}
rows=
{
showList
.
map
((
item
:
any
,
index
:
number
)
=>
({
...
item
,
id
:
`name=${item.name}&index=${index}`
,
name
:
renderName
(
item
),
size
:
renderSize
(
item
),
mtime
:
renderMtime
(
item
),
}))
}
radioClick=
{
radioClick
}
cursor=
"name"
></
Table
>
{
showList
.
length
===
0
&&
(
<
div
className=
{
style
.
noDataBox
}
>
<
img
className=
{
style
.
noDataImg
}
src=
{
noFile
}
alt=
""
/>
<
span
className=
{
style
.
noDataText
}
>
暂无数据
</
span
>
</
div
>
)
}
</
div
>
</
MyDialog
>
);
});
export
default
FileSelect
;
src/components/Material.Ui/Table.jsx
View file @
d16c0cda
...
...
@@ -20,7 +20,7 @@ export default function EnhancedTable(props) {
const
[
order
,
setOrder
]
=
React
.
useState
(
"asc"
);
const
[
orderBy
,
setOrderBy
]
=
React
.
useState
(
""
);
const
{
headCells
,
rows
,
footer
=
true
,
elevation1
,
tableStyle
,
tablecellstyle
,
tableContainerStyle
,
stickyheader
,
onRowClick
,
defaultRow
,
minHeight
=
''
,
borderBottom
=
''
,
onDoubleClick
,
load
,
size
,
checkboxData
,
rowsPerPage
=
10
,
initSelected
,
page
=
0
,
changePage
=
function
()
{
},
toolbar
,
count
,
param
,
disabledparam
=
"id"
,
headTableCellCheckbox
,
RowHeight
=
''
,
CellWidth
=
''
,
rowHover
,
TableNodataPadding
=
''
,
TableNodataLineHeight
=
''
,
tableBoySx
}
=
props
;
load
,
size
,
checkboxData
,
rowsPerPage
=
10
,
initSelected
,
page
=
0
,
changePage
=
function
()
{
},
toolbar
,
count
,
param
,
disabledparam
=
"id"
,
headTableCellCheckbox
,
RowHeight
=
''
,
CellWidth
=
''
,
rowHover
,
TableNodataPadding
=
''
,
TableNodataLineHeight
=
''
,
tableBoySx
,
radioClick
}
=
props
;
const
[
selected
,
setSelected
]
=
React
.
useState
(
initSelected
||
[]);
const
[
rowsPerPageOptions
]
=
React
.
useState
(
initSelected
||
[
5
,
10
,
20
,
50
,
{
value
:
-
1
,
label
:
'All'
}]);
const
[
onRow
,
setOnRow
]
=
React
.
useState
(
''
)
...
...
@@ -81,6 +81,10 @@ export default function EnhancedTable(props) {
setSelected
(
newSelected
);
};
const
handleRadioClick
=
(
id
)
=>
{
setSelected
(
id
)
}
const
handleOnPageChange
=
(
event
,
newPage
)
=>
{
changePage
(
newPage
,
rowsPerPage
);
};
...
...
@@ -149,7 +153,6 @@ export default function EnhancedTable(props) {
return
(
<
TableRow
hover=
{
rowHover
?
false
:
(
row
[
disabledparam
||
"enabled"
]
?
true
:
false
)
}
onDoubleClick=
{
()
=>
{
onDoubleClick
&&
onDoubleClick
(
row
)
}
}
...
...
@@ -164,6 +167,10 @@ export default function EnhancedTable(props) {
tabIndex=
{
-
1
}
key=
{
row
[
param
||
"id"
]
||
index
}
selected=
{
isItemSelected
}
onClick=
{
()
=>
{
radioClick
&&
radioClick
(
row
)
radioClick
&&
handleRadioClick
(
row
[
param
||
"id"
])
}
}
>
{
headCells
.
filter
(
k
=>
k
.
id
===
"checkbox"
).
length
>
0
&&
<
TableCell
...
...
src/components/mui/Dialog.tsx
View file @
d16c0cda
...
...
@@ -105,6 +105,14 @@ const MyDialog: React.FunctionComponent<IDialogProps> = (props) => {
className=
{
className
}
aria
-
labelledby=
"alert-dialog-title"
aria
-
describedby=
"alert-dialog-description"
sx=
{
{
"& .MuiDialog-container"
:
{
"& .MuiPaper-root"
:
{
// 设置最大宽度, 实际宽度让子元素撑大
maxWidth
:
"1920px"
,
},
},
}
}
>
{
isHideHeader
?
null
:
(
<
DialogTitle
id=
"alert-dialog-title"
>
...
...
src/components/mui/MyInput.tsx
View file @
d16c0cda
...
...
@@ -9,7 +9,7 @@
import
TextField
,
{
TextFieldProps
}
from
"@mui/material/TextField"
;
interface
MyInputProps
extends
Omit
<
TextFieldProps
,
"value"
>
{
value
:
any
;
value
?
:
any
;
inputSx
?:
any
;
onChange
?:
any
;
onFocus
?:
any
;
...
...
@@ -22,7 +22,7 @@ interface MyInputProps extends Omit<TextFieldProps, "value"> {
InputProps
?:
any
;
// input加前后icon可以用这个
error
?:
boolean
;
helperText
?:
string
;
}
;
}
const
MyInput
=
(
props
:
MyInputProps
)
=>
{
const
{
...
...
@@ -39,6 +39,7 @@ const MyInput = (props: MyInputProps) => {
InputProps
,
error
=
false
,
helperText
,
disabled
,
}
=
props
;
return
(
...
...
@@ -58,6 +59,7 @@ const MyInput = (props: MyInputProps) => {
InputProps=
{
{
...
InputProps
,
}
}
disabled=
{
disabled
}
value=
{
value
}
/>
);
...
...
src/components/mui/MyMenu.tsx
View file @
d16c0cda
...
...
@@ -21,7 +21,6 @@ const theme = createTheme({
MuiMenu
:
{
styleOverrides
:
{
root
:
{
// maxHeight: "260px",
overflowY
:
"scroll"
,
},
},
...
...
src/components/mui/MyPopconfirm.tsx
View file @
d16c0cda
// import * as React from "react";
// import { ReactNode, useEffect } from "react";
// import Box from "@mui/material/Box";
// import ButtonComponent from "./Button";
// import tipsIcon from "@/assets/project/information-outline.svg";
// import Popper from "@mui/material/Popper";
// type IMyPopconfirmProps = {
// title: string | ReactNode;
// cancelText?: string;
// okText?: string;
// showCancel?: boolean;
// onCancel?: any;
// onConfirm?: any;
// children: ReactNode;
// };
// const MyPopconfirm = (props: IMyPopconfirmProps) => {
// const {
// title,
// cancelText = "取消",
// okText = "确认",
// showCancel = true,
// onCancel,
// onConfirm,
// } = props;
// const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
// const handleClick = (event: React.MouseEvent<HTMLElement>) => {
// event.nativeEvent.stopImmediatePropagation();
// setAnchorEl(anchorEl ? null : event.currentTarget);
// };
// const open = Boolean(anchorEl);
// const id = open ? "simple-popper" : undefined;
// const handleCancel = () => {
// setAnchorEl(null);
// onCancel && onCancel();
// };
// const handleOk = () => {
// setAnchorEl(null);
// onConfirm && onConfirm();
// };
// useEffect(() => {
// document.addEventListener("click", (e) => {
// setAnchorEl(null);
// });
// }, []);
// return (
// <div>
// <div aria-describedby={id} onClick={handleClick}>
// {props.children && props.children}
// </div>
// <Popper
// id={id}
// open={open}
// anchorEl={anchorEl}
// sx={{
// zIndex: 2000,
// bgcolor: "#fff",
// minWidth: "200px",
// borderRadius: "2px",
// padding: "20px 16px",
// boxShadow: "0px 3px 10px 0px rgba(0, 24, 57, 0.14)",
// }}
// >
// {/* "0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d", */}
// <Box sx={{ marginBottom: "16px" }}>
// <img
// style={{ marginRight: "12px", position: "relative", top: "3px" }}
// src={tipsIcon}
// alt=""
// />
// {title}
// </Box>
// <Box sx={{ display: "flex", justifyContent: "flex-end" }}>
// {showCancel && (
// <ButtonComponent
// text={cancelText}
// // variant="text"
// size="small"
// color="inherit"
// click={handleCancel}
// style={{ marginRight: "12px" }}
// ></ButtonComponent>
// )}
// <ButtonComponent
// text={okText}
// // variant="text"
// size="small"
// click={handleOk}
// ></ButtonComponent>
// </Box>
// </Popper>
// </div>
// );
// };
// export default MyPopconfirm;
// 确认提示框, 支持同一页面多个提示框
import
*
as
React
from
"react"
;
import
{
ReactNode
,
useMemo
}
from
"react"
;
...
...
src/views/ConsoleLayout/components/FileItem/index.tsx
View file @
d16c0cda
...
...
@@ -141,9 +141,11 @@ const FileItem = observer((props: IProps) => {
<
span
className=
{
styles
.
span
}
>
{
`${storageUnitFromB(
itemInfo?.bytesUploaded || 0
)}/${storageUnitFromB(itemInfo?.bytesTotal || 0)}`
}
</
span
>
{
statusMsg
!==
'上传失败'
?
<
span
className=
{
styles
.
span
}
>
{
`${storageUnitFromB(
{
statusMsg
!==
"上传失败"
?
(
<
span
className=
{
styles
.
span
}
>
{
`${storageUnitFromB(
speed
)}/s`
}
</
span
>
:
null
}
)}/s`
}
</
span
>
)
:
null
}
</
div
>
)
}
</
div
>
...
...
src/views/Project/ProjectData/index.tsx
View file @
d16c0cda
...
...
@@ -25,6 +25,7 @@ import NoProject from "@/components/NoProject";
import
usePass
from
"@/hooks/usePass"
;
import
{
storageUnitFromB
}
from
"@/utils/util"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
FileSelect
from
"@/components/BusinessComponents/FileSelect"
;
import
{
getDataFind
,
getDataFileSearch
}
from
"@/api/project_api"
;
const
theme
=
createTheme
({
...
...
@@ -679,7 +680,7 @@ const ProjectData = observer(() => {
{
showList
.
length
===
0
&&
(
<
div
className=
{
style
.
noDataBox
}
>
<
img
className=
{
style
.
noDataImg
}
src=
{
noFile
}
alt=
""
/>
<
span
className=
{
style
.
noDataText
}
>
暂
未开启模板
</
span
>
<
span
className=
{
style
.
noDataText
}
>
暂
无数据
</
span
>
</
div
>
)
}
</
div
>
...
...
src/views/Project/ProjectJobDetail/index.tsx
View file @
d16c0cda
...
...
@@ -377,7 +377,8 @@ const ProjectSubmitWork = observer(() => {
{
!
activePatchId
&&
(
<
div
className=
{
styles
.
taskInfo
}
>
<
div
className=
{
styles
.
title
}
>
任务结果
</
div
>
{
workFlowJobInfo
?.
outputs
&&
(
{
workFlowJobInfo
?.
outputs
&&
Object
.
keys
(
workFlowJobInfo
?.
outputs
).
length
>
0
&&
(
<
div
className=
{
styles
.
taskResults
}
>
{
randerOutputs1
.
map
((
item
,
index
)
=>
{
return
(
...
...
@@ -395,7 +396,9 @@ const ProjectSubmitWork = observer(() => {
e
,
"即将跳转至项目数据内该任务的结果目录,确认继续吗?"
);
setGoToProjectDataPath
(
getFolderPath
(
item
.
path
));
setGoToProjectDataPath
(
getFolderPath
(
item
.
path
)
);
}
}
>
<
img
...
...
@@ -416,7 +419,8 @@ const ProjectSubmitWork = observer(() => {
})
}
</
div
>
)
}
{
!
workFlowJobInfo
?.
outputs
&&
(
{
(
!
workFlowJobInfo
?.
outputs
||
Object
.
keys
(
workFlowJobInfo
?.
outputs
).
length
===
0
)
&&
(
<
div
className=
{
styles
.
notResults
}
>
暂无结果文件
</
div
>
)
}
<
div
className=
{
styles
.
title
}
>
任务信息
</
div
>
...
...
src/views/Project/ProjectSetting/index.tsx
View file @
d16c0cda
...
...
@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:18:13
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-0
6-07 20:23:02
* @LastEditTime: 2022-0
7-13 16:51:56
* @FilePath: /bkunyun/src/views/Project/ProjectSetting/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
...
...
@@ -16,14 +16,17 @@ import projectImg from "@/assets/project/projectIconSmall.svg";
import
ProjectMembers
from
"./ProjectMembers"
;
import
BaseInfo
from
"./BaseInfo"
;
import
Tabs
from
"@/components/mui/Tabs"
;
import
usePass
from
"@/hooks/usePass"
;
const
ProjectSetting
=
observer
(()
=>
{
const
{
currentProjectStore
}
=
useStores
();
const
isPass
=
usePass
();
const
tabList
=
useMemo
(()
=>
{
return
[
{
label
:
"项目成员"
,
value
:
"projectMember"
,
hide
:
!
isPass
(
"PROJECT_SETTING_MEMBER"
),
component
:
<
ProjectMembers
/>,
},
{
...
...
src/views/Project/ProjectSubmitWork/ConfigForm/index.tsx
View file @
d16c0cda
...
...
@@ -4,7 +4,9 @@ import MyInput from "@/components/mui/MyInput";
import
Tooltip
from
"@mui/material/Tooltip"
;
import
classnames
from
"classnames"
;
import
{
useState
,
useMemo
,
useImperativeHandle
}
from
"react"
;
import
FileSelect
from
"@/components/FileSelect"
;
import
FileSelect
,
{
FileSelectType
,
}
from
"@/components/BusinessComponents/FileSelect"
;
import
moment
from
"moment"
;
import
MySelect
,
{
optionsTransform
}
from
"../components/MySelect"
;
import
MyCheckBox
from
"@/components/mui/MyCheckBox"
;
...
...
@@ -20,12 +22,13 @@ type ConfigFormProps = {
templateConfigInfo
?:
ITemplateConfig
;
setParameter
:
any
;
onRef
?:
React
.
Ref
<
any
>
;
setSelectedNodeId
:
(
val
:
string
)
=>
void
;
setSelected
Batch
NodeId
:
(
val
:
string
)
=>
void
;
};
const
ConfigForm
=
(
props
:
ConfigFormProps
)
=>
{
const
{
templateConfigInfo
,
setParameter
,
setSelectedNodeId
}
=
props
;
const
{
templateConfigInfo
,
setParameter
,
setSelected
Batch
NodeId
}
=
props
;
const
[
name
,
setName
]
=
useState
<
string
>
(
""
);
// 任务名称
const
[
fileSelectType
,
setFileSelectType
]
=
useState
<
FileSelectType
>
(
"path"
);
const
[
nameHelp
,
setNameHelp
]
=
useState
({
error
:
false
,
...
...
@@ -212,15 +215,16 @@ const ConfigForm = (props: ConfigFormProps) => {
<
div
className=
{
styles
.
parameterContent
}
>
{
parameter
.
domType
.
toLowerCase
()
===
"file"
&&
(
<
MyInput
onFocus=
{
()
=>
setSelectedNodeId
(
batchId
||
""
)
}
onBlur=
{
()
=>
setSelectedNodeId
(
""
)
}
onFocus=
{
()
=>
setSelected
Batch
NodeId
(
batchId
||
""
)
}
onBlur=
{
()
=>
setSelected
Batch
NodeId
(
""
)
}
value=
{
parameter
.
value
||
""
}
InputProps=
{
{
endAdornment
:
(
<
img
onClick=
{
()
=>
handleOpenFileSelect
(
taskId
,
parameter
.
name
)
}
onClick=
{
()
=>
{
setFileSelectType
(
"file"
);
handleOpenFileSelect
(
taskId
,
parameter
.
name
);
}
}
src=
{
fileSelectIcon
}
alt=
""
className=
{
styles
.
fileSelectImg
}
...
...
@@ -234,15 +238,16 @@ const ConfigForm = (props: ConfigFormProps) => {
)
}
{
parameter
.
domType
.
toLowerCase
()
===
"path"
&&
(
<
MyInput
onFocus=
{
()
=>
setSelectedNodeId
(
batchId
||
""
)
}
onBlur=
{
()
=>
setSelectedNodeId
(
""
)
}
onFocus=
{
()
=>
setSelected
Batch
NodeId
(
batchId
||
""
)
}
onBlur=
{
()
=>
setSelected
Batch
NodeId
(
""
)
}
value=
{
parameter
.
value
||
""
}
InputProps=
{
{
endAdornment
:
(
<
img
onClick=
{
()
=>
handleOpenFileSelect
(
taskId
,
parameter
.
name
)
}
onClick=
{
()
=>
{
setFileSelectType
(
"path"
);
handleOpenFileSelect
(
taskId
,
parameter
.
name
);
}
}
src=
{
fileSelectIcon
}
alt=
""
className=
{
styles
.
fileSelectImg
}
...
...
@@ -256,15 +261,16 @@ const ConfigForm = (props: ConfigFormProps) => {
)
}
{
parameter
.
domType
.
toLowerCase
()
===
"dataset"
&&
(
<
MyInput
onFocus=
{
()
=>
setSelectedNodeId
(
taskId
)
}
onBlur=
{
()
=>
setSelectedNodeId
(
""
)
}
onFocus=
{
()
=>
setSelected
Batch
NodeId
(
taskId
)
}
onBlur=
{
()
=>
setSelected
Batch
NodeId
(
""
)
}
value=
{
parameter
.
value
||
""
}
InputProps=
{
{
endAdornment
:
(
<
img
onClick=
{
()
=>
handleOpenFileSelect
(
taskId
,
parameter
.
name
)
}
onClick=
{
()
=>
{
setFileSelectType
(
"dataset"
);
handleOpenFileSelect
(
taskId
,
parameter
.
name
);
}
}
src=
{
fileSelectIcon
}
alt=
""
className=
{
styles
.
fileSelectImg
}
...
...
@@ -279,10 +285,10 @@ const ConfigForm = (props: ConfigFormProps) => {
{
parameter
.
domType
.
toLowerCase
()
===
"input"
&&
(
<
MyInput
onFocus=
{
()
=>
{
setSelectedNodeId
(
batchId
||
""
);
setSelected
Batch
NodeId
(
batchId
||
""
);
console
.
log
(
batchId
,
"111"
);
}
}
onBlur=
{
()
=>
setSelectedNodeId
(
""
)
}
onBlur=
{
()
=>
setSelected
Batch
NodeId
(
""
)
}
value=
{
parameter
.
value
||
""
}
onChange=
{
(
e
:
any
)
=>
handleParameterChange
(
e
,
taskId
,
parameter
.
name
||
""
)
...
...
@@ -294,8 +300,8 @@ const ConfigForm = (props: ConfigFormProps) => {
)
}
{
parameter
.
domType
.
toLowerCase
()
===
"select"
&&
(
<
MySelect
onFocus=
{
()
=>
setSelectedNodeId
(
batchId
||
""
)
}
onBlur=
{
()
=>
setSelectedNodeId
(
""
)
}
onFocus=
{
()
=>
setSelected
Batch
NodeId
(
batchId
||
""
)
}
onBlur=
{
()
=>
setSelected
Batch
NodeId
(
""
)
}
value=
{
parameter
.
value
}
onChange=
{
(
e
:
any
)
=>
handleParameterChange
(
e
,
taskId
,
parameter
.
name
||
""
)
...
...
@@ -307,8 +313,8 @@ const ConfigForm = (props: ConfigFormProps) => {
)
}
{
parameter
.
domType
.
toLowerCase
()
===
"multipleselect"
&&
(
<
MySelect
onFocus=
{
()
=>
setSelectedNodeId
(
batchId
||
""
)
}
onBlur=
{
()
=>
setSelectedNodeId
(
""
)
}
onFocus=
{
()
=>
setSelected
Batch
NodeId
(
batchId
||
""
)
}
onBlur=
{
()
=>
setSelected
Batch
NodeId
(
""
)
}
value=
{
parameter
.
value
}
onChange=
{
(
e
:
any
)
=>
handleParameterChange
(
e
,
taskId
,
parameter
.
name
||
""
)
...
...
@@ -325,8 +331,8 @@ const ConfigForm = (props: ConfigFormProps) => {
onChange=
{
(
e
:
any
)
=>
handleParameterChange
(
e
,
taskId
,
parameter
.
name
||
""
)
}
onFocus=
{
()
=>
setSelectedNodeId
(
batchId
||
""
)
}
onBlur=
{
()
=>
setSelectedNodeId
(
""
)
}
onFocus=
{
()
=>
setSelected
Batch
NodeId
(
batchId
||
""
)
}
onBlur=
{
()
=>
setSelected
Batch
NodeId
(
""
)
}
options=
{
optionsTransform
(
parameter
.
choices
,
"label"
)
}
error=
{
parameter
.
error
||
false
}
helperText=
{
parameter
.
helperText
}
...
...
@@ -347,8 +353,8 @@ const ConfigForm = (props: ConfigFormProps) => {
)
}
options=
{
optionsTransform
(
parameter
.
choices
,
"label"
)
}
onFocus=
{
()
=>
setSelectedNodeId
(
batchId
||
""
)
}
onBlur=
{
()
=>
setSelectedNodeId
(
""
)
}
onFocus=
{
()
=>
setSelected
Batch
NodeId
(
batchId
||
""
)
}
onBlur=
{
()
=>
setSelected
Batch
NodeId
(
""
)
}
error=
{
parameter
.
error
||
false
}
helperText=
{
parameter
.
helperText
}
></
MyCheckBox
>
...
...
@@ -420,7 +426,10 @@ const ConfigForm = (props: ConfigFormProps) => {
InputProps=
{
{
endAdornment
:
(
<
img
onClick=
{
()
=>
handleOpenFileSelect
()
}
onClick=
{
()
=>
{
setFileSelectType
(
"path"
);
handleOpenFileSelect
();
}
}
src=
{
fileSelectIcon
}
alt=
"选择输出路径"
className=
{
styles
.
fileSelectImg
}
...
...
@@ -496,6 +505,7 @@ const ConfigForm = (props: ConfigFormProps) => {
onClose=
{
handleFileSelectOnClose
}
open=
{
fileSelectOpen
}
onConfirm=
{
onFileSelectConfirm
}
type=
{
fileSelectType
}
/>
)
}
</
div
>
...
...
src/views/Project/ProjectSubmitWork/WorkFlow/index.tsx
View file @
d16c0cda
...
...
@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-21 15:25:25
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-
06 11:55:41
* @LastEditTime: 2022-07-
12 14:09:20
* @FilePath: /bkunyun/src/views/Project/ProjectSubmitWork/WorkFlow/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
...
...
@@ -11,12 +11,19 @@ import { ITemplateConfig } from "../interface";
interface
IProps
{
templateConfigInfo
?:
ITemplateConfig
;
setSelectedNodeId
?:
(
val
:
string
)
=>
void
;
selected
NodeId
?:
string
;
setSelectedBatchNodeId
?:
(
val
:
string
)
=>
void
;
selectedBatch
NodeId
?:
string
;
}
const
WorkFlow
=
(
props
:
IProps
)
=>
{
const
{
templateConfigInfo
,
setSelectedNodeId
,
selectedNodeId
}
=
props
;
return
<
Flow
tasks=
{
templateConfigInfo
?.
tasks
}
setSelectedNodeId=
{
setSelectedNodeId
}
selectedNodeId=
{
selectedNodeId
}
/>;
const
{
templateConfigInfo
,
setSelectedBatchNodeId
,
selectedBatchNodeId
}
=
props
;
return
(
<
Flow
tasks=
{
templateConfigInfo
?.
tasks
}
setSelectedBatchNodeId=
{
setSelectedBatchNodeId
}
selectedBatchNodeId=
{
selectedBatchNodeId
}
/>
);
};
export
default
WorkFlow
;
src/views/Project/ProjectSubmitWork/index.tsx
View file @
d16c0cda
...
...
@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-21 20:03:56
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-
07 10:53:41
* @LastEditTime: 2022-07-
13 16:24:06
* @FilePath: /bkunyun/src/views/Project/ProjectSubmitWork/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
...
...
@@ -42,7 +42,7 @@ const ProjectSubmitWork = observer(() => {
let
configFormRef
:
any
=
React
.
createRef
();
/** 是否全屏 */
const
[
fullScreenShow
,
setFullScreenShow
]
=
useState
<
boolean
>
(
false
);
const
[
selected
NodeId
,
setSelected
NodeId
]
=
useState
<
string
>
(
""
);
const
[
selected
BatchNodeId
,
setSelectedBatch
NodeId
]
=
useState
<
string
>
(
""
);
// 前往工作台
const
goToWorkbench
=
(
toWorkbenchList
=
false
)
=>
{
...
...
@@ -228,17 +228,10 @@ const ProjectSubmitWork = observer(() => {
{
fullScreenShow
?
null
:
(
<
div
className=
{
styles
.
swHeader
}
>
<
div
className=
{
styles
.
swHeaderLeft
}
>
{
/* <MyPopconfirm
title="返回后,当前页面已填写内容将不保存,确认返回吗?"
onConfirm={handleGoBack}
> */
}
<
IconButton
color=
"primary"
onClick=
{
(
e
:
any
)
=>
handleShowPopper
(
e
,
"返回后,当前页面已填写内容将不保存,确认返回吗?"
)
handleShowPopper
(
e
,
"返回将放弃当前页面所有操作,确认返回吗?"
)
}
aria
-
label=
"upload picture"
component=
"span"
...
...
@@ -252,7 +245,6 @@ const ProjectSubmitWork = observer(() => {
}
}
/>
</
IconButton
>
{
/* </MyPopconfirm> */
}
<
div
className=
{
styles
.
swTemplateTitle
}
>
{
templateConfigInfo
?.
title
}
...
...
@@ -298,7 +290,7 @@ const ProjectSubmitWork = observer(() => {
onRef=
{
configFormRef
}
templateConfigInfo=
{
templateConfigInfo
}
setParameter=
{
setParameter
}
setSelected
NodeId=
{
setSelected
NodeId
}
setSelected
BatchNodeId=
{
setSelectedBatch
NodeId
}
/>
</
div
>
)
}
...
...
@@ -308,8 +300,8 @@ const ProjectSubmitWork = observer(() => {
>
<
WorkFlow
templateConfigInfo=
{
templateConfigInfo
}
setSelected
NodeId=
{
setSelected
NodeId
}
selected
NodeId=
{
selected
NodeId
}
setSelected
BatchNodeId=
{
setSelectedBatch
NodeId
}
selected
BatchNodeId=
{
selectedBatch
NodeId
}
/>
</
div
>
</
div
>
...
...
src/views/Project/ProjectSubmitWork/interface.ts
View file @
d16c0cda
...
...
@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-21 20:03:56
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-
09 15:57:24
* @LastEditTime: 2022-07-
12 11:51:17
* @FilePath: /bkunyun/src/views/Project/ProjectSubmitWork/interface.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
...
...
@@ -23,7 +23,8 @@ export interface IParameter {
tags
:
Array
<
string
>
;
source
:
string
;
productId
:
string
;
tasks
:
ITask
[];
// tasks: ITask[];
linked
?:
boolean
;
validators
:
Array
<
IValidator
>
;
choices
:
Array
<
IChoice
>
;
error
?:
boolean
;
...
...
@@ -83,7 +84,7 @@ export type IValidator = {
};
export
interface
IChoice
{
key
:
string
;
label
:
string
;
value
:
boolean
|
string
|
number
;
}
...
...
@@ -93,7 +94,7 @@ export interface IEdge {
sourceHandle
:
string
;
target
:
string
;
targetHandle
:
string
;
label
:
string
;
label
?
:
string
;
}
// 提交任务时的动态表单的数据结构
...
...
src/views/Project/ProjectWorkbench/workbenchTemplate/components/AddTemplate/index.tsx
View file @
d16c0cda
import
{
useEffect
,
useState
,
useMemo
}
from
"react"
;
import
{
useEffect
,
useState
,
useMemo
,
useCallback
}
from
"react"
;
import
style
from
"./index.module.css"
;
import
classNames
from
"classnames"
;
import
CloseOutlinedIcon
from
"@mui/icons-material/CloseOutlined"
;
...
...
@@ -16,6 +16,7 @@ import _ from "lodash";
import
{
observer
}
from
"mobx-react-lite"
;
import
noData
from
"../../../../../../assets/project/noTemplate.svg"
;
import
{
ICustomTemplate
}
from
"../../interface"
;
import
{
useMessage
}
from
"@/components/MySnackbar"
;
import
{
getAddWorkbenchTemplate
,
addWorkbenchTemplate
,
...
...
@@ -40,11 +41,11 @@ const radioOptions = [
const
AddTemplate
=
observer
((
props
:
IAddTemplateProps
)
=>
{
const
{
currentProjectStore
}
=
useStores
();
const
Message
=
useMessage
();
const
projectId
=
toJS
(
currentProjectStore
.
currentProjectInfo
.
id
);
const
productId
=
toJS
(
currentProjectStore
.
currentProductInfo
.
id
);
const
{
setShowAddTemplate
,
getTemplateInfo
}
=
props
;
const
handleSearch
=
(
value
:
string
)
=>
{};
const
[
title
,
setTitle
]
=
useState
(
""
);
/** 可增加模板列表 */
const
[
addTemplateList
,
setAddTemplateList
]
=
useState
([]);
...
...
@@ -72,6 +73,7 @@ const AddTemplate = observer((props: IAddTemplateProps) => {
// 项目管理员-添加工作流模板-提交
const
{
run
:
addTemplate
}
=
useMyRequest
(
addWorkbenchTemplate
,
{
onSuccess
:
(
result
:
any
)
=>
{
Message
.
success
(
"添加成功"
);
setSelectTemplateData
([]);
setShowAddTemplate
(
false
);
getTemplateInfo
({
...
...
@@ -81,10 +83,14 @@ const AddTemplate = observer((props: IAddTemplateProps) => {
});
const
handleAddTemplate
=
()
=>
{
if
(
selectTemplateData
.
length
===
0
)
{
Message
.
error
(
"请选择要添加的模板"
);
}
else
{
addTemplate
({
projectId
:
projectId
as
string
,
workflowSpecIds
:
selectTemplateData
,
});
}
};
// 添加工作流模板-获取模板列表
...
...
@@ -109,12 +115,47 @@ const AddTemplate = observer((props: IAddTemplateProps) => {
});
};
useEffect
(()
=>
{
// 编辑模板
const
handleEditTemplate
=
(
item
:
any
)
=>
{
setCustomTemplateInfo
({
show
:
true
,
id
:
item
.
id
,
});
};
// 获取模板列表
const
getAddTemplateListFun
=
useCallback
(()
=>
{
const
userName
=
JSON
.
parse
(
localStorage
.
getItem
(
"userInfo"
)
||
"{}"
)?.
name
;
setSelectTemplateData
([]);
setAddTemplateList
([]);
if
(
templateType
===
"public"
)
{
getAddTemplateList
({
projectId
:
projectId
as
string
,
productId
:
productId
as
string
,
creator
:
"root"
,
keyword
:
title
,
});
}
else
{
getAddTemplateList
({
projectId
:
projectId
as
string
,
productId
:
productId
as
string
,
creator
:
userName
,
keyword
:
title
,
});
},
[
getAddTemplateList
,
projectId
,
productId
]);
}
},
[
setSelectTemplateData
,
getAddTemplateList
,
productId
,
projectId
,
templateType
,
title
,
]);
// title,
useEffect
(()
=>
{
getAddTemplateListFun
();
},
[
getAddTemplateListFun
]);
const
hiddenBoxArr
=
useMemo
(()
=>
{
const
length
=
...
...
@@ -151,11 +192,9 @@ const AddTemplate = observer((props: IAddTemplateProps) => {
}
}
>
<
OutlinedInput
value=
{
title
}
onChange=
{
(
e
:
any
)
=>
{
_
.
debounce
(()
=>
{
// searchTemplateNameCallback(e.target.value);
handleSearch
(
e
.
target
.
value
);
},
200
)();
setTitle
(
e
.
target
.
value
);
}
}
placeholder=
"输入关键词搜索"
size=
"small"
...
...
@@ -251,14 +290,14 @@ const AddTemplate = observer((props: IAddTemplateProps) => {
版本:
{
item
.
version
}
</
span
>
<
span
className=
{
style
.
templateLiInfoText
}
>
更新时间:
{
item
.
updateTime
}
更新时间:
{
item
.
update
d
Time
}
</
span
>
</
div
>
<
div
className=
{
style
.
templateLiDesc
}
>
{
item
.
description
}
</
div
>
{
templateType
!==
"public"
&&
(
<
div
className=
{
style
.
templateLiEditBox
}
>
<
Button
click=
{
handleAddTemplate
}
click=
{
()
=>
handleEditTemplate
(
item
)
}
size=
{
"small"
}
style=
{
{
height
:
"32px"
,
...
...
@@ -288,12 +327,14 @@ const AddTemplate = observer((props: IAddTemplateProps) => {
</
div
>
{
customTemplateInfo
?.
show
?
(
<
WorkFlowEdit
onBack=
{
()
=>
id=
{
customTemplateInfo
.
id
||
""
}
onBack=
{
()
=>
{
setCustomTemplateInfo
({
id
:
""
,
show
:
false
,
})
}
});
getAddTemplateListFun
();
}
}
/>
)
:
null
}
</
div
>
...
...
src/views/Project/ProjectWorkbench/workbenchTemplate/components/addTemplate.tsx
View file @
d16c0cda
...
...
@@ -119,7 +119,7 @@ const AddTemplate = (props: any) => {
<
Typography
sx=
{
{
fontSize
:
"12px"
,
fontWeight
:
"400"
,
color
:
"#8A9099"
}
}
>
暂未
相关模版
暂无
相关模版
</
Typography
>
</
Box
>
)
}
...
...
src/views/Project/ProjectWorkbench/workbenchTemplate/components/templateBox.tsx
View file @
d16c0cda
...
...
@@ -30,6 +30,13 @@ const TemplateBox = (props: any) => {
return
(
<
Box
className=
{
styles
.
templateBlock
}
>
<
Box
>
<
Box
sx=
{
{
display
:
"flex"
,
justifyContent
:
"space-between"
,
alignItems
:
"center"
,
}
}
>
<
Typography
sx=
{
{
fontSize
:
"14px"
,
...
...
@@ -42,6 +49,20 @@ const TemplateBox = (props: any) => {
>
{
info
.
title
}
</
Typography
>
{
info
.
creator
!==
"root"
&&
(
<
Box
sx=
{
{
backgroundColor
:
"rgba(227, 250, 236, 1)"
,
color
:
"rgba(2, 171, 131, 1)"
,
lineHeight
:
"20px"
,
padding
:
"1px 9px"
,
fontSize
:
"12px"
,
}
}
>
自定义
</
Box
>
)
}
</
Box
>
<
Box
sx=
{
{
display
:
"flex"
,
marginBottom
:
"8px"
}
}
>
<
Typography
sx=
{
{
...
...
@@ -56,7 +77,7 @@ const TemplateBox = (props: any) => {
<
Typography
sx=
{
{
fontSize
:
"12px"
,
fontWeight
:
"400"
,
color
:
"#1370FF"
}
}
>
更新时间:
{
info
.
updateTime
}
更新时间:
{
info
.
update
d
Time
}
</
Typography
>
</
Box
>
<
Typography
className=
{
styles
.
templateDescText
}
>
...
...
src/views/Project/ProjectWorkbench/workbenchTemplate/index.module.css
View file @
d16c0cda
...
...
@@ -27,6 +27,7 @@
flex-direction
:
column
;
justify-content
:
space-between
;
margin
:
8px
;
position
:
relative
;
}
.addTemplateMask
{
...
...
src/views/Project/components/Flow/index.module.css
→
src/views/Project/components/Flow/
components/BatchNode/
index.module.css
View file @
d16c0cda
...
...
@@ -20,16 +20,6 @@
border-left
:
4px
solid
#ff4e4e
;
}
.batchRotate
{
transform
:
translateX
(
-50%
)
rotate
(
-90deg
);
}
.flowNode
{
background-color
:
#f5f6f7
;
border-radius
:
2px
;
padding
:
6px
12px
;
}
.successDot
{
display
:
inline-block
;
line-height
:
22px
;
...
...
@@ -45,3 +35,7 @@
border
:
1px
solid
#1370ff
;
border-left
:
4px
solid
#1370ff
;
}
.batchRotate
{
transform
:
translateX
(
-50%
)
rotate
(
-90deg
);
}
src/views/Project/components/Flow/components/BatchNode/index.tsx
0 → 100644
View file @
d16c0cda
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-07-12 11:20:29
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-15 10:48:22
* @FilePath: /bkunyun/src/views/Project/components/Flow/components/BatchNode.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import
{
Tooltip
}
from
"@mui/material"
;
import
classNames
from
"classnames"
;
import
{
useMemo
}
from
"react"
;
import
{
Handle
,
Position
}
from
"react-flow-renderer"
;
import
{
uuid
}
from
"@/utils/util"
;
import
{
IBatchNode
}
from
"../../interface"
;
import
styles
from
"./index.module.css"
;
/** 自定义batch节点 */
const
BatchNode
=
(
props
:
IBatchNode
)
=>
{
const
{
data
}
=
props
;
const
{
style
,
isFlowNode
,
selectedStatus
,
info
:
{
title
,
isCheck
,
executionStatus
,
parameters
},
flowType
,
}
=
data
;
/** 获取输入参数数组 */
const
inParamsArr
=
useMemo
(()
=>
{
return
(
(
parameters
?.
length
&&
parameters
?.
filter
((
item
)
=>
{
return
item
.
parameterGroup
===
"in"
;
}))
||
[]
);
},
[
parameters
]);
/** 获取输出参数数组 */
const
outParamsArr
=
useMemo
(()
=>
{
return
(
(
parameters
?.
length
&&
parameters
?.
filter
((
item
)
=>
{
return
item
.
parameterGroup
===
"out"
;
}))
||
[]
);
},
[
parameters
]);
return
(
<
div
className=
{
classNames
({
[
styles
.
batchNode
]:
true
,
[
styles
.
selectedBatchBox
]:
selectedStatus
,
[
styles
.
runBatchNode
]:
executionStatus
===
"Running"
,
[
styles
.
doneBatchNode
]:
executionStatus
===
"Done"
,
[
styles
.
errorBatchNode
]:
executionStatus
===
"Failed"
,
})
}
style=
{
style
}
>
{
inParamsArr
?.
length
?
inParamsArr
.
map
((
item
,
index
)
=>
{
return
(
<
Tooltip
title=
{
item
.
name
}
key=
{
uuid
()
}
>
<
Handle
id=
{
item
.
name
}
style=
{
{
background
:
"#fff "
,
border
:
item
.
error
?
"1px solid #FF4E4E"
:
"1px solid #D1D6DE"
,
left
:
index
*
20
+
20
,
}
}
type=
"target"
position=
{
Position
.
Top
}
/>
</
Tooltip
>
);
})
:
null
}
<
div
className=
{
classNames
({
[
styles
.
batchRotate
]:
isFlowNode
,
})
}
>
{
title
||
""
}
{
isCheck
&&
flowType
!==
"edit"
?
(
<
span
className=
{
styles
.
successDot
}
></
span
>
)
:
null
}
</
div
>
{
outParamsArr
?.
length
?
outParamsArr
.
map
((
item
,
index
)
=>
{
return
(
<
Tooltip
title=
{
item
.
name
}
key=
{
uuid
()
}
>
<
Handle
id=
{
item
.
name
}
style=
{
{
background
:
"#fff "
,
border
:
"1px solid #D1D6DE"
,
left
:
index
*
20
+
20
,
}
}
type=
"source"
position=
{
Position
.
Bottom
}
/>
</
Tooltip
>
);
})
:
null
}
</
div
>
);
};
export
default
BatchNode
;
src/views/Project/components/Flow/components/FlowNode/index.module.css
0 → 100644
View file @
d16c0cda
.flowNode
{
background-color
:
#f5f6f7
;
border-radius
:
2px
;
padding
:
6px
12px
;
}
.flowNode
:hover
{
border
:
1px
solid
#1370ff
;
}
.selectedFlowBox
{
color
:
#1370ff
;
border
:
1px
solid
#1370ff
;
background-color
:
#ebf3ff
;
}
.successDot
{
display
:
inline-block
;
line-height
:
22px
;
vertical-align
:
middle
;
width
:
8px
;
height
:
8px
;
background-color
:
#0dd09b
;
border-radius
:
8px
;
margin-left
:
8px
;
}
src/views/Project/components/Flow/components/FlowNode/index.tsx
0 → 100644
View file @
d16c0cda
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-07-12 11:29:46
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-12 21:06:48
* @FilePath: /bkunyun/src/views/Project/components/Flow/components/FlowNode/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import
classNames
from
"classnames"
;
import
{
Handle
,
Position
}
from
"react-flow-renderer"
;
import
{
IExecutionStatus
}
from
"@/views/Project/ProjectSubmitWork/interface"
;
import
jobFail
from
"@/assets/project/jobFail.svg"
;
import
jobRun
from
"@/assets/project/jobRun.svg"
;
import
jobSue
from
"@/assets/project/jobSue.svg"
;
import
styles
from
"./index.module.css"
;
/** 自定义flow节点 */
const
FlowNode
=
(
props
:
any
)
=>
{
/** 获取imgUrl */
const
getImgUrl
=
(
type
:
IExecutionStatus
)
=>
{
if
(
type
===
"Done"
)
{
return
jobSue
;
}
if
(
type
===
"Failed"
)
{
return
jobFail
;
}
if
(
type
===
"Running"
)
{
return
jobRun
;
}
return
undefined
;
};
const
{
data
}
=
props
;
const
{
dotStatus
,
selectedStatus
,
info
:
{
title
,
isCheck
,
executionStatus
},
}
=
data
;
return
(
<
div
className=
{
classNames
({
[
styles
.
flowNode
]:
true
,
[
styles
.
selectedFlowBox
]:
selectedStatus
,
})
}
>
{
dotStatus
?.
isInput
?
(
<
Handle
style=
{
{
background
:
"#C2C6CC "
,
left
:
12
}
}
type=
"target"
position=
{
Position
.
Top
}
/>
)
:
null
}
<
div
style=
{
{
display
:
"flex"
,
alignItems
:
"center"
}
}
>
{
title
||
""
}
{
isCheck
&&
<
span
className=
{
styles
.
successDot
}
></
span
>
}
{
getImgUrl
(
executionStatus
)
&&
(
<
img
style=
{
{
marginLeft
:
"6px"
}
}
src=
{
getImgUrl
(
executionStatus
)
}
alt=
""
/>
)
}
</
div
>
{
dotStatus
?.
isOutput
?
(
<
Handle
style=
{
{
background
:
"#C2C6CC "
,
left
:
12
}
}
type=
"source"
position=
{
Position
.
Bottom
}
/>
)
:
null
}
</
div
>
);
};
export
default
FlowNode
;
src/views/Project/components/Flow/index.tsx
View file @
d16c0cda
...
...
@@ -3,25 +3,22 @@ import ReactFlow, {
Background
,
useNodesState
,
useEdgesState
,
Handle
,
Position
,
ReactFlowProps
,
Node
,
Connection
,
Edge
,
}
from
"react-flow-renderer"
;
import
{
useCallback
,
useEffect
,
useMemo
,
useState
}
from
"react"
;
import
classNames
from
"classnames
"
;
import
_
from
"lodash
"
;
import
jobFail
from
"@/assets/project/jobFail.svg"
;
import
jobRun
from
"@/assets/project/jobRun.svg"
;
import
jobSue
from
"@/assets/project/jobSue.svg"
;
import
{
IEdge
,
IExecutionStatus
,
ITask
,
}
from
"../../ProjectSubmitWork/interface"
;
import
{
IBatchNode
,
ILine
}
from
"./interface"
;
import
{
uuid
}
from
"@/utils/util"
;
import
{
IEdge
,
IParameter
,
ITask
}
from
"../../ProjectSubmitWork/interface"
;
import
{
ILine
}
from
"./interface"
;
import
BatchNode
from
"./components/BatchNode"
;
import
FlowNode
from
"./components/FlowNode"
;
import
{
getCustomTemplateParameterCheckResult
}
from
"@/views/WorkFlowEdit/util"
;
import
{
useMessage
}
from
"@/components/MySnackbar"
;
import
styles
from
"./index.module.css"
;
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-22 10:15:22
...
...
@@ -34,139 +31,122 @@ interface IProps extends ReactFlowProps {
tasks
?:
ITask
[];
/** 点击batch事件 */
onBatchClick
?:
(
val
:
string
)
=>
void
;
/** 设置选中节点id */
setSelectedNodeId
?:
(
val
:
string
)
=>
void
;
/** 选中的节点id */
selectedNodeId
?:
string
;
/** 设置选中
的batch
节点id */
setSelected
Batch
NodeId
?:
(
val
:
string
)
=>
void
;
/** 选中的
batch
节点id */
selected
Batch
NodeId
?:
string
;
/** 类型, edit为编辑类型 */
type
?:
"edit"
|
"default"
;
/** 设置组件数据 组件为编辑状态使用 */
setTasks
?:
(
val
:
ITask
[])
=>
void
;
/** 点击流程node 节点 返回唯一标识符 */
onFlowNodeClick
?:
(
val
:
string
)
=>
void
;
}
/** 获取imgUrl */
const
getImgUrl
=
(
type
:
IExecutionStatus
)
=>
{
if
(
type
===
"Done"
)
{
return
jobSue
;
}
if
(
type
===
"Failed"
)
{
return
jobFail
;
}
if
(
type
===
"Running"
)
{
return
jobRun
;
}
return
undefined
;
};
/** 自定义batch节点 */
const
BatchNode
=
(
props
:
IBatchNode
)
=>
{
const
{
data
}
=
props
;
const
{
dotStatus
,
style
,
isFlowNode
,
label
,
selectedStatus
}
=
data
;
return
(
<
div
className=
{
classNames
({
[
styles
.
batchNode
]:
true
,
[
styles
.
selectedBatchBox
]:
selectedStatus
,
[
styles
.
runBatchNode
]:
data
.
executionStatus
===
"Running"
,
[
styles
.
doneBatchNode
]:
data
.
executionStatus
===
"Done"
,
[
styles
.
errorBatchNode
]:
data
.
executionStatus
===
"Failed"
,
})
}
style=
{
style
}
>
{
dotStatus
?.
isInput
?
(
<
Handle
style=
{
{
background
:
"#fff "
,
border
:
"1px solid #D1D6DE"
,
left
:
20
}
}
type=
"target"
position=
{
Position
.
Top
}
/>
)
:
null
}
<
div
className=
{
classNames
({
[
styles
.
batchRotate
]:
isFlowNode
,
})
}
>
{
label
||
""
}
{
data
.
isCheck
&&
<
span
className=
{
styles
.
successDot
}
></
span
>
}
</
div
>
{
dotStatus
?.
isOutput
?
(
<
Handle
style=
{
{
background
:
"#fff "
,
border
:
"1px solid #D1D6DE"
,
left
:
20
}
}
type=
"source"
position=
{
Position
.
Bottom
}
/>
)
:
null
}
</
div
>
);
};
/** 自定义flow节点 */
const
FlowNode
=
(
props
:
any
)
=>
{
const
{
data
}
=
props
;
return
(
<
div
className=
{
classNames
({
[
styles
.
flowNode
]:
true
,
})
}
>
{
data
?.
dotStatus
?.
isInput
?
(
<
Handle
style=
{
{
background
:
"#C2C6CC "
,
left
:
12
}
}
type=
"target"
position=
{
Position
.
Top
}
/>
)
:
null
}
<
div
style=
{
{
display
:
"flex"
,
alignItems
:
"center"
}
}
>
{
data
?.
label
||
""
}
{
data
.
isCheck
&&
<
span
className=
{
styles
.
successDot
}
></
span
>
}
{
getImgUrl
(
data
.
executionStatus
)
&&
(
<
img
style=
{
{
marginLeft
:
"6px"
}
}
src=
{
getImgUrl
(
data
.
executionStatus
)
}
alt=
""
/>
)
}
</
div
>
{
data
?.
dotStatus
?.
isOutput
?
(
<
Handle
style=
{
{
background
:
"#C2C6CC "
,
left
:
12
}
}
type=
"source"
position=
{
Position
.
Bottom
}
id=
"a"
/>
)
:
null
}
</
div
>
);
};
const
Flow
=
(
props
:
IProps
)
=>
{
const
{
tasks
,
onBatchClick
,
setSelectedNodeId
,
selectedNodeId
,
setSelected
Batch
NodeId
,
selected
Batch
NodeId
,
type
:
flowType
=
"default"
,
setTasks
,
onFlowNodeClick
,
...
other
}
=
props
;
/** 自定义的节点类型 */
const
nodeTypes
=
useMemo
(()
=>
{
return
{
batchNode
:
BatchNode
,
flowNode
:
FlowNode
};
},
[]);
/** 内部维护的选择的节点Id */
const
[
inSideNodeId
,
setInSideNodeId
]
=
useState
<
string
>
(
""
);
console
.
log
(
tasks
,
"11111"
);
/** 内部维护的选择的batch节点Id */
const
[
inSideBatchNodeId
,
setInSideBatchNodeId
]
=
useState
<
string
>
(
""
);
/** 内部维护的选择的flow节点Id */
const
[
inSideFlowNodeId
,
setInSideFlowNodeId
]
=
useState
<
string
>
(
""
);
/** 选中的线 */
const
[
selectedEdge
,
setSelectedEdge
]
=
useState
<
Edge
>
();
const
Message
=
useMessage
();
/** 原始数据删除线 */
const
tasksDeleteLine
=
useCallback
(
(
connection
:
Connection
|
Edge
)
=>
{
const
result
=
(
tasks
?.
length
&&
tasks
.
map
((
item
)
=>
{
/** 删除batch起始的edges中的一项 === 等于删除了一根连线 */
if
(
item
.
id
===
connection
.
source
&&
item
.
type
===
"BATCH"
)
{
const
newEdges
=
(
item
.
edges
?.
length
&&
item
.
edges
?.
filter
(
(
every
)
=>
every
.
sourceHandle
!==
connection
.
sourceHandle
))
||
[];
/** 删除批节点 */
return
{
...
item
,
edges
:
newEdges
,
};
/** 选中batch结束位置&&更新校验值 */
}
else
if
(
item
.
id
===
connection
.
target
&&
item
.
type
===
"BATCH"
)
{
const
newParameters
=
(
item
.
parameters
?.
length
&&
item
.
parameters
.
map
((
every
)
=>
{
if
(
every
.
name
===
connection
.
targetHandle
)
{
const
{
error
,
helperText
}
=
getCustomTemplateParameterCheckResult
({
...
every
,
linked
:
false
,
hidden
:
false
,
});
return
{
...
every
,
hidden
:
false
,
error
,
helperText
,
};
}
else
{
return
every
;
}
}))
||
[];
return
{
...
item
,
parameters
:
newParameters
,
};
}
else
{
return
item
;
}
}))
||
[];
return
result
;
},
[
tasks
]
);
/** 删除批节点或者线 */
const
deleteSelectBatchNode
=
useCallback
(
(
e
:
any
)
=>
{
if
(
e
.
keyCode
===
8
)
{
const
val
=
tasks
?.
length
&&
/** 删除批节点逻辑 */
if
(
inSideBatchNodeId
)
{
const
newVal
=
(
tasks
?.
length
&&
tasks
.
filter
((
item
)
=>
{
return
item
.
id
!==
inSideNodeId
&&
item
.
parentNode
!==
inSideNodeId
;
});
setTasks
&&
setTasks
(
val
||
[]);
return
(
item
.
id
!==
inSideBatchNodeId
&&
item
.
parentNode
!==
inSideBatchNodeId
);
}))
||
[];
setTasks
&&
setTasks
(
newVal
);
}
if
(
selectedEdge
)
{
const
newVal
=
tasksDeleteLine
(
selectedEdge
);
setTasks
&&
setTasks
(
newVal
);
}
}
},
[
inSide
NodeId
,
setTasks
,
tasks
]
[
inSide
BatchNodeId
,
selectedEdge
,
setTasks
,
tasks
,
tasksDeleteLine
]
);
/** 监听鼠标按下事件 */
...
...
@@ -236,7 +216,7 @@ const Flow = (props: IProps) => {
width
=
val
>
176
?
val
:
width
;
}
if
(
positionYArr
?.
length
)
{
const
val
=
positionYArr
[
positionYArr
.
length
-
1
];
const
val
=
positionYArr
[
positionYArr
.
length
-
1
]
+
6
;
height
=
val
>
22
?
val
:
height
;
}
return
{
...
...
@@ -257,24 +237,24 @@ const Flow = (props: IProps) => {
type
:
item
.
type
===
"BATCH"
?
"batchNode"
:
"flowNode"
,
/** 每一项的数据 */
data
:
{
label
:
item
.
title
||
""
,
info
:
item
,
...(
item
.
type
===
"BATCH"
?
{
/** flow组件类型 */
flowType
,
/** 是否有流节点 */
isFlowNode
:
isFlowNode
(
item
.
id
),
/** 选中状态 */
selectedStatus
:
selectedNodeId
?
selectedNodeId
===
item
.
id
:
inSideNodeId
===
item
.
id
,
selectedStatus
:
selectedBatchNodeId
?
selectedBatchNodeId
===
item
.
id
:
inSideBatchNodeId
===
item
.
id
,
/** tasks 数据 */
tasks
:
tasks
,
}
:
{}),
/** 是否选中 */
isCheck
:
item
.
isCheck
,
/** 运行状态 */
executionStatus
:
item
.
executionStatus
,
:
{
selectedStatus
:
inSideFlowNodeId
===
item
.
id
}),
/** 输入输出圆点状态 */
dotStatus
:
nodesInputAndOutputStatus
(
item
.
id
),
/** 样式 */
style
:
{
...
getBatchStyle
(
item
),
...
...
@@ -300,9 +280,11 @@ const Flow = (props: IProps) => {
return
val
;
},
[
tasks
,
flowType
,
isFlowNode
,
selectedNodeId
,
inSideNodeId
,
selectedBatchNodeId
,
inSideBatchNodeId
,
inSideFlowNodeId
,
nodesInputAndOutputStatus
,
getBatchStyle
,
]);
...
...
@@ -322,12 +304,20 @@ const Flow = (props: IProps) => {
},
[]);
});
return
val
.
map
((
item
:
ILine
)
=>
{
const
newSelectId
=
selectedNodeId
?
selectedNodeId
:
inSideNodeId
;
const
newSelectId
=
selectedBatchNodeId
?
selectedBatchNodeId
:
inSideBatchNodeId
;
return
{
id
:
item
.
id
,
source
:
item
.
source
,
target
:
item
.
target
,
type
:
"smoothstep"
,
...
item
,
// type: "smoothstep",
/** 点击线选中 */
...(
selectedEdge
?.
id
===
item
.
id
?
{
style
:
{
stroke
:
"#1370FF"
,
strokeWidth
:
2
},
animated
:
true
,
}
:
{}),
/** 点击batch节点选中 */
...(
item
?.
batchId
===
newSelectId
?
{
style
:
{
stroke
:
"#1370FF"
},
animated
:
true
}
:
{}),
...
...
@@ -336,34 +326,49 @@ const Flow = (props: IProps) => {
label
:
item
.
label
?
`(
${
item
.
label
}
)`
:
""
,
};
});
},
[
inSideNodeId
,
selectedNodeId
,
tasks
]);
},
[
inSideBatchNodeId
,
selectedBatchNodeId
,
selectedEdge
?.
id
,
tasks
]);
/** 设置nodeId方法 */
const
setNodeIdFun
=
useCallback
(
(
id
:
string
)
=>
{
setSelectedBatchNodeId
?
setSelectedBatchNodeId
(
id
)
:
setInSideBatchNodeId
(
id
);
onBatchClick
&&
onBatchClick
(
id
);
setInSideFlowNodeId
(
""
);
document
.
getElementById
(
`point
${
id
}
`
)?.
scrollIntoView
(
true
);
},
[
onBatchClick
,
setSelectedBatchNodeId
]
);
/** flowNode点击事件 */
const
onNodeClick
=
(
e
:
any
,
node
:
Node
)
=>
{
tasks
?.
forEach
((
item
)
=>
{
if
(
item
.
id
===
node
.
id
)
{
if
(
item
.
parentNode
)
{
setSelectedNodeId
?
setSelectedNodeId
(
item
.
parentNode
)
:
setInSideNodeId
(
item
.
parentNode
);
onBatchClick
&&
onBatchClick
(
item
.
parentNode
);
document
.
getElementById
(
`point
${
item
.
parentNode
}
`
)
?.
scrollIntoView
(
true
);
if
(
item
.
type
===
"BATCH"
)
{
setNodeIdFun
(
node
.
id
);
}
else
{
setSelectedNodeId
?
setSelectedNodeId
(
node
.
id
)
:
setInSideNodeId
(
node
.
id
);
onBatchClick
&&
onBatchClick
(
node
.
id
||
""
);
document
.
getElementById
(
`point
${
node
.
id
}
`
)?.
scrollIntoView
(
true
);
setInSideFlowNodeId
(
node
.
id
);
setInSideBatchNodeId
(
""
);
setSelectedBatchNodeId
&&
setSelectedBatchNodeId
(
""
);
}
}
});
if
(
onFlowNodeClick
)
{
onFlowNodeClick
(
node
.
id
);
}
/** 点击node统一清除选中的edge */
setSelectedEdge
(
undefined
);
};
const
handlePaneClick
=
()
=>
{
setSelectedNodeId
?
setSelectedNodeId
(
""
)
:
setInSideNodeId
(
""
);
setSelectedBatchNodeId
?
setSelectedBatchNodeId
(
""
)
:
setInSideBatchNodeId
(
""
);
setInSideFlowNodeId
(
""
);
onBatchClick
&&
onBatchClick
(
""
);
setSelectedEdge
(
undefined
);
};
/** node节点 */
...
...
@@ -379,20 +384,154 @@ const Flow = (props: IProps) => {
setNodes
(
initialNodes
);
},
[
initialNodes
,
setNodes
]);
/** 节点拖动停止 */
const
onNodeDragStop
=
useCallback
(
(
event
:
React
.
MouseEvent
,
node
:
Node
)
=>
{
const
newVal
=
(
tasks
?.
length
&&
tasks
.
map
((
item
)
=>
{
if
(
item
.
id
===
node
.
id
)
{
return
{
...
item
,
position
:
node
.
position
,
};
}
else
{
return
item
;
}
}))
||
[];
setTasks
&&
setTasks
(
newVal
);
},
[
setTasks
,
tasks
]
);
const
connectModifyParameters
=
useCallback
(
(
parameters
:
IParameter
[],
edgeItem
:
Connection
)
=>
{
return
parameters
.
map
((
item
)
=>
{
if
(
item
.
name
===
edgeItem
.
targetHandle
)
{
const
{
error
,
helperText
}
=
getCustomTemplateParameterCheckResult
({
...
item
,
linked
:
true
,
hidden
:
true
,
});
return
{
...
item
,
linked
:
true
,
hidden
:
true
,
helperText
,
error
};
}
else
{
return
item
;
}
});
},
[]
);
/** 获取连接线的端点类型 */
const
getClassType
=
useCallback
(
(
connection
:
Connection
)
=>
{
let
inputClassType
=
""
,
outClassType
:
string
|
undefined
=
undefined
;
tasks
?.
length
&&
tasks
.
forEach
((
item
)
=>
{
if
([
connection
.
source
,
connection
.
target
].
includes
(
item
.
id
))
{
item
.
parameters
.
forEach
((
every
)
=>
{
if
(
every
.
name
===
connection
.
targetHandle
)
{
inputClassType
=
every
.
classType
;
}
if
(
every
.
name
===
connection
.
sourceHandle
)
{
outClassType
=
every
.
classType
;
}
});
}
});
return
{
inputClassType
,
outClassType
};
},
[
tasks
]
);
/** 连接校验并修改值 */
const
connectCheck
=
useCallback
(
(
connection
:
Connection
)
=>
{
const
newVal
=
(
tasks
?.
length
&&
tasks
?.
map
((
item
)
=>
{
if
(
item
.
id
===
connection
.
source
)
{
return
{
...
item
,
edges
:
[
...
item
.
edges
,
{
...
connection
,
id
:
uuid
(),
},
],
};
}
else
if
(
item
.
id
===
connection
.
target
)
{
return
{
...
item
,
parameters
:
connectModifyParameters
(
item
.
parameters
,
connection
),
};
}
else
{
return
item
;
}
}))
||
[];
return
newVal
;
},
[
connectModifyParameters
,
tasks
]
);
/** 已经连接线啦 */
const
onConnect
=
useCallback
(
(
connection
:
Connection
)
=>
{
const
{
inputClassType
,
outClassType
}
=
getClassType
(
connection
);
let
result
:
ITask
[]
=
[];
if
(
inputClassType
===
outClassType
)
{
result
=
connectCheck
(
connection
)
as
ITask
[];
}
else
{
Message
.
error
(
"端口数据类型不一致,无法连接!"
);
result
=
tasksDeleteLine
(
connection
);
}
setTasks
&&
setTasks
(
result
);
},
[
Message
,
connectCheck
,
getClassType
,
setTasks
,
tasksDeleteLine
]
);
/** 点击连线 */
const
onEdgeClick
=
useCallback
(
(
e
:
any
,
val
:
Edge
)
=>
{
setSelectedEdge
(
val
);
/** 点击连线清除选中的node ID */
setInSideFlowNodeId
(
""
);
setInSideBatchNodeId
(
""
);
setSelectedBatchNodeId
&&
setSelectedBatchNodeId
(
""
);
},
[
setSelectedBatchNodeId
]
);
const
reactFlowParams
=
flowType
===
"edit"
?
{
onNodesChange
,
onEdgesChange
,
onNodeDragStop
,
onConnect
,
onEdgeClick
,
}
:
{};
return
(
<
ReactFlow
nodes=
{
nodes
}
edges=
{
edges
}
fitView=
{
flowType
===
"default"
?
true
:
false
}
onNodesChange=
{
onNodesChange
}
onEdgesChange=
{
onEdgesChange
}
deleteKeyCode=
{
[
"13"
]
}
// onConnect={onConnect}
{
...
reactFlowParams
}
// proOptions={{ hideAttribution: true, account: "" }}
nodeTypes=
{
nodeTypes
}
onPaneClick=
{
handlePaneClick
}
onNodeClick=
{
onNodeClick
}
{
...
props
}
{
...
other
}
>
<
Controls
/>
<
Background
color=
"#aaa"
gap=
{
16
}
/>
...
...
src/views/Project/components/Flow/interface.ts
View file @
d16c0cda
...
...
@@ -2,20 +2,23 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-23 11:00:29
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-
07 11:23:14
* @LastEditTime: 2022-07-
14 10:11:50
* @FilePath: /bkunyun/src/views/Project/components/Flow/interface.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import
{
CSSProperties
}
from
"react"
;
import
{
ITask
}
from
"../../ProjectSubmitWork/interface"
;
/** 线的参数 */
export
interface
ILine
{
id
:
string
,
label
:
string
,
label
?
:
string
,
batchId
?:
string
,
source
:
string
,
target
:
string
,
sourceHandle
:
string
,
targetHandle
:
string
,
}
export
interface
IDotStatus
{
...
...
@@ -40,7 +43,13 @@ export interface IBatchNodeData {
isCheck
?:
boolean
;
/** 运行状态 */
executionStatus
:
string
/** 每一项信息 */
info
:
ITask
/** flow组件类型 */
flowType
:
'edit'
|
'default'
}
export
interface
IBatchNode
{
data
:
IBatchNodeData
}
\ No newline at end of file
src/views/WorkFlowEdit/components/OperatorList/index.module.css
View file @
d16c0cda
...
...
@@ -59,3 +59,18 @@
padding
:
0
8px
;
border-radius
:
2px
;
}
.noData
{
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
flex-direction
:
column
;
}
.noDataImg
{
margin
:
160px
0
8px
0
;
}
.noDataText
{
font-size
:
14px
;
line-height
:
22px
;
color
:
rgba
(
138
,
144
,
153
,
1
);
}
src/views/WorkFlowEdit/components/OperatorList/index.tsx
View file @
d16c0cda
...
...
@@ -12,9 +12,10 @@ import useMyRequest from "@/hooks/useMyRequest";
import
{
IResponse
}
from
"@/api/http"
;
import
{
fetchOperatorList
,
fetchVersionOperator
}
from
"@/api/workbench_api"
;
import
{
useStores
}
from
"@/store"
;
import
noTemplate
from
"@/assets/project/noTemplate.svg"
;
import
MyMenu
from
"@/components/mui/MyMenu"
;
import
styles
from
"./index.module.css"
;
import
MyMenu
from
"@/components/mui/MyMenu"
;
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
...
...
@@ -245,8 +246,10 @@ const OperatorList = observer((props: IOperatorListProps) => {
<
div
className=
{
styles
.
searchBox
}
>
<
OutlinedInput
onChange=
{
(
e
)
=>
{
if
(
e
.
target
.
value
?.
length
>
30
)
return
;
setKeyword
(
e
.
target
.
value
);
}
}
value=
{
keyword
}
placeholder=
"输入关键词搜索"
onKeyUp=
{
handleEnterCode
}
size=
"small"
...
...
@@ -255,7 +258,8 @@ const OperatorList = observer((props: IOperatorListProps) => {
/>
</
div
>
<
div
className=
{
styles
.
listBox
}
>
{
operatorListData
{
operatorListData
.
filter
((
item
)
=>
item
.
type
===
"BATCH"
)?.
length
?
(
operatorListData
.
filter
((
item
)
=>
item
.
type
===
"BATCH"
)
.
map
((
item
)
=>
{
return
(
...
...
@@ -268,7 +272,13 @@ const OperatorList = observer((props: IOperatorListProps) => {
setTemplateConfigInfo=
{
setTemplateConfigInfo
}
/>
);
})
}
})
)
:
(
<
div
className=
{
styles
.
noData
}
>
<
img
src=
{
noTemplate
}
alt=
""
className=
{
styles
.
noDataImg
}
/>
<
span
className=
{
styles
.
noDataText
}
>
没有找到相关算子
</
span
>
</
div
>
)
}
</
div
>
</
div
>
);
...
...
src/views/WorkFlowEdit/components/ParameterSetting/index.module.css
View file @
d16c0cda
...
...
@@ -93,6 +93,12 @@
.parameterBox
:last-child
{
margin-bottom
:
0
;
}
.inOutParameterBox
{
margin-bottom
:
12px
;
}
.inOutParameterBox
:last-child
{
margin-bottom
:
0px
;
}
.inOutParameterTop
{
display
:
flex
;
justify-content
:
space-between
;
...
...
@@ -117,6 +123,12 @@
font-size
:
12px
;
line-height
:
20px
;
}
.inOutParameterHelperText
{
margin-top
:
6px
;
font-size
:
12px
;
line-height
:
20px
;
color
:
rgba
(
255
,
78
,
78
,
1
);
}
.noData
{
height
:
calc
(
100vh
-
140px
);
...
...
@@ -133,34 +145,33 @@
line-height
:
22px
;
color
:
rgba
(
138
,
144
,
153
,
1
);
}
.paramsGroup
{
.paramsGroup
{
padding-bottom
:
24px
;
}
.parameter
{
.parameter
{
padding
:
16px
0
24px
;
border-bottom
:
1px
solid
#
F0F2F
5
;
border-bottom
:
1px
solid
#
f0f2f
5
;
}
.parameter
:last-child
{
.parameter
:last-child
{
border-bottom
:
none
;
}
.parameterTop
{
.parameterTop
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
margin-bottom
:
16px
;
}
.parameterLeft
{
.parameterLeft
{
}
.parameterName
{
.parameterName
{
font-size
:
14px
;
color
:
#1
E
2633
;
color
:
#1
e
2633
;
line-height
:
22px
;
font-weight
:
600
;
}
.parameterClassTypeName
{
.parameterClassTypeName
{
font-size
:
14px
;
color
:
#8
A
9099
;
color
:
#8
a
9099
;
line-height
:
22px
;
}
src/views/WorkFlowEdit/components/ParameterSetting/index.tsx
View file @
d16c0cda
...
...
@@ -8,11 +8,13 @@ import { useCallback, useEffect, useMemo, useState } from "react";
import
MyInput
from
"@/components/mui/MyInput"
;
import
Tooltip
from
"@mui/material/Tooltip"
;
import
MyCheckBox
from
"@/components/mui/MyCheckBox"
;
// import MySelect, { optionsTransform } from "../components/MySelect";
import
MySelect
,
{
optionsTransform
,
}
from
"../../../Project/ProjectSubmitWork/components/MySelect"
;
import
_
from
"lodash"
;
import
FileSelect
,
{
FileSelectType
,
}
from
"@/components/BusinessComponents/FileSelect"
;
import
MyRadio
from
"@/components/mui/MyRadio"
;
import
questionMark
from
"@/assets/project/questionMark.svg"
;
import
fileSelectIcon
from
"@/assets/project/fileSelect.svg"
;
...
...
@@ -24,210 +26,240 @@ import { getCustomTemplateParameterCheckResult } from "../../util";
type
IParameterSettingProps
=
{
templateConfigInfo
:
ITask
[];
taskId
:
string
;
setTemplateConfigInfo
:
any
;
};
const
templateConfigInfoMock
=
[
{
id
:
"id"
,
title
:
"title"
,
description
:
"阿斯蒂芬吉林集安拉开圣诞节疯狂拉升阶段阿斯蒂芬吉林集安拉开圣诞节疯狂拉升阶段阿斯蒂芬吉林集安拉开圣诞节疯狂拉升阶段阿斯蒂芬吉林集安拉开圣诞节疯狂拉升阶段阿斯蒂芬吉林集安拉开圣诞节疯狂拉升阶段阿斯蒂芬吉林集安拉开圣诞节疯狂拉升阶段"
,
version
:
"version"
,
position
:
{
x
:
10
,
y
:
100
,
},
tags
:
[
"string[]"
],
type
:
"BATCH"
,
parentNode
:
"string"
,
parameters
:
[
{
hidden
:
true
,
id
:
"1"
,
name
:
"smi_in"
,
required
:
true
,
defaultValue
:
""
,
domType
:
"input"
,
classType
:
"STRING"
,
classTypeName
:
"String"
,
value
:
""
,
description
:
"123"
,
language
:
""
,
languageVersion
:
""
,
tags
:
[],
source
:
"string"
,
productId
:
""
,
tasks
:
[],
validators
:
[
{
message
:
"请选择smi文件作为输入"
,
regex
:
"^.[s][m][i]$"
,
},
],
choices
:
[],
parameterGroup
:
"in"
,
},
{
hidden
:
true
,
id
:
"2"
,
name
:
"out"
,
required
:
true
,
defaultValue
:
""
,
domType
:
"select"
,
classType
:
"STRING"
,
classTypeName
:
"String"
,
value
:
""
,
description
:
""
,
language
:
""
,
languageVersion
:
""
,
tags
:
[],
source
:
"string"
,
productId
:
""
,
tasks
:
[],
validators
:
[
{
message
:
"请选择smi文件作为输入"
,
regex
:
"^.[s][m][i]$"
,
},
],
choices
:
[],
parameterGroup
:
"out"
,
},
{
hidden
:
true
,
id
:
"3"
,
name
:
"basis999"
,
required
:
true
,
defaultValue
:
""
,
domType
:
"select"
,
classType
:
"STRING"
,
classTypeName
:
"String"
,
value
:
""
,
description
:
"789"
,
language
:
""
,
languageVersion
:
""
,
tags
:
[],
source
:
"string"
,
productId
:
""
,
tasks
:
[],
validators
:
[
{
message
:
"请选择smi文件作为输入"
,
regex
:
"^.[s][m][i]$"
,
},
],
choices
:
[],
parameterGroup
:
"basis"
,
},
{
hidden
:
true
,
id
:
"4"
,
name
:
"basis"
,
required
:
true
,
defaultValue
:
""
,
domType
:
"select"
,
classType
:
"STRING"
,
classTypeName
:
"String"
,
value
:
""
,
description
:
""
,
language
:
""
,
languageVersion
:
""
,
tags
:
[],
source
:
"string"
,
productId
:
""
,
tasks
:
[],
validators
:
[
{
message
:
"请选择smi文件作为输入"
,
regex
:
"^.[s][m][i]$"
,
},
],
choices
:
[],
parameterGroup
:
"basis"
,
},
{
hidden
:
true
,
id
:
"5"
,
name
:
"senior"
,
required
:
true
,
defaultValue
:
""
,
domType
:
"select"
,
classType
:
"STRING"
,
classTypeName
:
"String"
,
value
:
""
,
description
:
""
,
language
:
""
,
languageVersion
:
""
,
tags
:
[],
source
:
"string"
,
productId
:
""
,
tasks
:
[],
validators
:
[
{
message
:
"请选择smi文件作为输入"
,
regex
:
"^.[s][m][i]$"
,
},
],
choices
:
[],
parameterGroup
:
"senior"
,
},
{
hidden
:
true
,
id
:
"6"
,
name
:
"hardware"
,
required
:
true
,
defaultValue
:
""
,
domType
:
"select"
,
classType
:
"STRING"
,
classTypeName
:
"String"
,
value
:
""
,
description
:
""
,
language
:
""
,
languageVersion
:
""
,
tags
:
[],
source
:
"string"
,
productId
:
""
,
tasks
:
[],
validators
:
[
{
message
:
"请选择smi文件作为输入"
,
regex
:
"^.[s][m][i]$"
,
},
],
choices
:
[],
parameterGroup
:
"hardware"
,
},
],
edges
:
[],
isCheck
:
false
,
executionStatus
:
"Pending"
,
},
];
const
taskId
=
"id"
;
// 页面调试数据 暂不删除
// const templateConfigInfoMock = [
// {
// id: "id",
// title: "title",
// description:
// "阿斯蒂芬吉林集安拉开圣诞节疯狂拉升阶段阿斯蒂芬吉林集安拉开圣诞节疯狂拉升阶段阿斯蒂芬吉林集安拉开圣诞节疯狂拉升阶段阿斯蒂芬吉林集安拉开圣诞节疯狂拉升阶段阿斯蒂芬吉林集安拉开圣诞节疯狂拉升阶段阿斯蒂芬吉林集安拉开圣诞节疯狂拉升阶段",
// version: "version",
// position: {
// x: 10,
// y: 100,
// },
// tags: ["string[]"],
// type: "BATCH",
// parentNode: "string",
// parameters: [
// {
// hidden: true,
// id: "1",
// name: "smi_in",
// required: true,
// defaultValue: "",
// domType: "input",
// classType: "STRING",
// classTypeName: "String",
// value: "",
// description: "123",
// language: "",
// languageVersion: "",
// tags: [],
// source: "string",
// productId: "",
// tasks: [],
// validators: [
// {
// message: "请选择smi文件作为输入",
// regex: "^.[s][m][i]$",
// },
// ],
// choices: [],
// parameterGroup: "in",
// },
// {
// hidden: true,
// id: "2",
// name: "out",
// required: true,
// defaultValue: "",
// domType: "select",
// classType: "STRING",
// classTypeName: "String",
// value: "",
// description: "",
// language: "",
// languageVersion: "",
// tags: [],
// source: "string",
// productId: "",
// tasks: [],
// validators: [
// {
// message: "请选择smi文件作为输入",
// regex: "^.[s][m][i]$",
// },
// ],
// choices: [],
// parameterGroup: "out",
// },
// {
// hidden: true,
// id: "3",
// name: "basis999",
// required: true,
// defaultValue: "",
// domType: "select",
// classType: "STRING",
// classTypeName: "String",
// value: "",
// description: "789",
// language: "",
// languageVersion: "",
// tags: [],
// source: "string",
// productId: "",
// tasks: [],
// validators: [
// {
// message: "请选择smi文件作为输入",
// regex: "^.[s][m][i]$",
// },
// ],
// choices: [],
// parameterGroup: "basis",
// },
// {
// hidden: true,
// id: "4",
// name: "basis",
// required: true,
// defaultValue: "",
// domType: "select",
// classType: "STRING",
// classTypeName: "String",
// value: "",
// description: "",
// language: "",
// languageVersion: "",
// tags: [],
// source: "string",
// productId: "",
// tasks: [],
// validators: [
// {
// message: "请选择smi文件作为输入",
// regex: "^.[s][m][i]$",
// },
// ],
// choices: [],
// parameterGroup: "basis",
// },
// {
// hidden: true,
// id: "5",
// name: "senior",
// required: true,
// defaultValue: "",
// domType: "checkbox",
// classType: "STRING",
// classTypeName: "String",
// value: "",
// description: "",
// language: "",
// languageVersion: "",
// tags: [],
// source: "string",
// productId: "",
// tasks: [],
// validators: [
// {
// message: "请选择smi文件作为输入",
// regex: "^.[s][m][i]$",
// },
// ],
// choices: [
// {
// label: "123",
// value: "123",
// },
// {
// label: "456",
// value: "456",
// },
// {
// label: "789",
// value: "789",
// },
// ],
// parameterGroup: "senior",
// },
// {
// hidden: true,
// id: "6",
// name: "hardware",
// required: true,
// defaultValue: "",
// domType: "radio",
// classType: "STRING",
// classTypeName: "String",
// value: "",
// description: "",
// language: "",
// languageVersion: "",
// tags: [],
// source: "string",
// productId: "",
// tasks: [],
// validators: [
// {
// message: "请选择smi文件作为输入",
// regex: "^.[s][m][i]$",
// },
// ],
// choices: [
// {
// label: "123",
// value: "123",
// },
// {
// label: "456",
// value: "456",
// },
// {
// label: "789",
// value: "789",
// },
// ],
// parameterGroup: "hardware",
// },
// ],
// edges: [],
// isCheck: false,
// executionStatus: "Pending",
// },
// ];
// const taskId = "id";
const
ParameterSetting
=
(
props
:
IParameterSettingProps
)
=>
{
// const { templateConfigInfo, taskId } = props;
const
{
templateConfigInfo
,
setTemplateConfigInfo
,
taskId
}
=
props
;
// 算子大数组
const
[
templateConfigInfo
,
setTemplateConfigInfo
]
=
useState
<
ITask
[]
>
(
templateConfigInfoMock
as
ITask
[]
);
const
[
descHeight
,
setDescHeight
]
=
useState
(
0
);
const
[
isShowAllDese
,
setIsShowAllDese
]
=
useState
(
false
);
// 页面调试数据 暂不删除
// const [templateConfigInfo, setTemplateConfigInfo] = useState<ITask[]>(
// templateConfigInfoMock as ITask[]
// );
const
[
descHeight
,
setDescHeight
]
=
useState
(
0
);
// 算子描述的高度 用来完成描述展开收起功能
const
[
isShowAllDese
,
setIsShowAllDese
]
=
useState
(
false
);
// 是否展示全部描述
const
[
fileSelectOpen
,
setFileSelectOpen
]
=
useState
(
false
);
// 选择输出路径的弹窗显示控制
const
[
fileSelectType
,
setFileSelectType
]
=
useState
<
FileSelectType
>
(
"path"
);
const
[
parameterName
,
setParameterName
]
=
useState
(
""
);
// 当前算子中的parameters中正在编辑饿parameter(参数)
const
[
fileSelectObject
,
setFileSelectObject
]
=
useState
({
taskId
:
""
,
parameterName
:
""
,
});
const
div
=
document
.
getElementById
(
"descHeight"
);
const
div
=
document
.
getElementById
(
"descHeight"
);
// 算子描述的元素(不限高)用来完成描述展开收起功能
useEffect
(()
=>
{
if
(
div
)
{
setDescHeight
(
div
.
offsetHeight
);
}
},
[
div
]);
// 文件夹路线选择器弹窗
const
handleFileSelectOnClose
=
()
=>
{
setFileSelectOpen
(
false
);
};
// 选中的算子详情
const
taskInfo
:
ITask
|
null
=
useMemo
(()
=>
{
if
(
!
taskId
)
{
return
null
;
...
...
@@ -243,27 +275,125 @@ const ParameterSetting = (props: IParameterSettingProps) => {
}
},
[
templateConfigInfo
,
taskId
]);
/** 通过parameter.name删除与之相关联的线 */
const
handleHiddenDeleteEdge
=
useCallback
(
(
val
:
ITask
[],
parameterName
:
string
)
=>
{
return
(
val
?.
length
&&
val
?.
map
((
item
)
=>
{
if
(
item
.
id
===
taskId
)
{
const
newParameters
=
(
item
.
parameters
?.
length
&&
item
.
parameters
.
map
((
every
)
=>
{
if
(
every
.
name
===
parameterName
)
{
return
{
...
every
,
linked
:
false
,
};
}
else
{
return
every
;
}
}))
||
[];
return
{
...
item
,
parameters
:
newParameters
,
};
}
else
{
const
newEdges
=
(
item
?.
edges
?.
length
&&
item
?.
edges
?.
filter
((
every
)
=>
{
return
every
.
targetHandle
!==
parameterName
;
}))
||
[];
return
{
...
item
,
edges
:
newEdges
,
};
}
})
);
},
[
taskId
]
);
// 设置parameter.hidden字段
const
handleHiddenChange
=
useCallback
(
(
e
:
any
,
parameter
Id
:
string
)
=>
{
cons
t
result
:
ITask
[]
=
_
.
cloneDeep
(
templateConfigInfo
);
(
e
:
any
,
parameter
Name
:
string
)
=>
{
le
t
result
:
ITask
[]
=
_
.
cloneDeep
(
templateConfigInfo
);
const
taskIndex
=
result
.
findIndex
((
item
)
=>
{
return
item
.
id
===
taskId
;
});
if
(
taskIndex
!==
-
1
)
{
let
isCheck
=
true
;
result
[
taskIndex
].
parameters
.
forEach
((
parameter
)
=>
{
if
(
parameter
.
id
===
parameterId
)
{
console
.
log
(
e
.
target
.
checked
);
if
(
parameter
.
name
===
parameterName
)
{
parameter
.
hidden
=
!
e
.
target
.
checked
;
const
checkResult
=
getCustomTemplateParameterCheckResult
(
parameter
);
parameter
.
error
=
checkResult
.
error
;
parameter
.
helperText
=
checkResult
.
helperText
;
}
if
(
getCustomTemplateParameterCheckResult
(
parameter
).
error
===
true
)
{
isCheck
=
false
;
}
});
result
[
taskIndex
].
isCheck
=
isCheck
;
}
if
(
e
.
target
.
checked
)
{
result
=
handleHiddenDeleteEdge
(
result
,
parameterName
)
||
[];
}
setTemplateConfigInfo
(
result
);
},
[
templateConfigInfo
,
handleHiddenDeleteEdge
,
setTemplateConfigInfo
,
taskId
]
);
// 设置parameter.defaultValue字段
const
handleParameterChange
=
useCallback
(
(
e
:
any
,
parameterName
:
string
)
=>
{
const
result
:
ITask
[]
=
_
.
cloneDeep
(
templateConfigInfo
);
const
taskIndex
=
result
.
findIndex
((
item
)
=>
{
return
item
.
id
===
taskId
;
});
if
(
taskIndex
!==
-
1
)
{
let
isCheck
=
true
;
result
[
taskIndex
].
parameters
.
forEach
((
parameter
)
=>
{
console
.
log
(
parameter
);
if
(
parameter
.
name
===
parameterName
)
{
parameter
.
defaultValue
=
e
.
target
.
value
;
const
checkResult
=
getCustomTemplateParameterCheckResult
(
parameter
);
parameter
.
error
=
checkResult
.
error
;
parameter
.
helperText
=
checkResult
.
helperText
;
}
if
(
getCustomTemplateParameterCheckResult
(
parameter
).
error
===
true
)
{
isCheck
=
false
;
}
});
result
[
taskIndex
].
isCheck
=
isCheck
;
}
setTemplateConfigInfo
(
result
);
},
[
templateConfigInfo
,
setTemplateConfigInfo
]
[
templateConfigInfo
,
setTemplateConfigInfo
,
taskId
]
);
// 文件夹路线选择确认回调
const
onFileSelectConfirm
=
(
path
:
string
)
=>
{
setFileSelectOpen
(
false
);
handleParameterChange
(
{
target
:
{
value
:
`ProjectData
${
path
===
"/"
?
""
:
path
}
`
,
},
},
parameterName
);
};
const
renderInput
=
useCallback
((
parameter
:
IParameter
)
=>
{
// 渲染当个表单项
const
renderInput
=
useCallback
(
(
parameter
:
IParameter
)
=>
{
return
(
<
Tooltip
title=
{
parameter
.
description
}
placement=
"top"
>
<
div
>
...
...
@@ -273,7 +403,13 @@ const ParameterSetting = (props: IParameterSettingProps) => {
InputProps=
{
{
endAdornment
:
(
<
img
onClick=
{
()
=>
handleOpenFileSelect
(
taskId
,
parameter
.
name
)
}
onClick=
{
()
=>
{
if
(
parameter
.
parameterGroup
===
"out"
)
{
return
;
}
setFileSelectType
(
"file"
);
handleOpenFileSelect
(
parameter
.
name
);
}
}
src=
{
fileSelectIcon
}
alt=
""
className=
{
styles
.
fileSelectImg
}
...
...
@@ -292,7 +428,13 @@ const ParameterSetting = (props: IParameterSettingProps) => {
InputProps=
{
{
endAdornment
:
(
<
img
onClick=
{
()
=>
handleOpenFileSelect
(
taskId
,
parameter
.
name
)
}
onClick=
{
()
=>
{
if
(
parameter
.
parameterGroup
===
"out"
)
{
return
;
}
setFileSelectType
(
"path"
);
handleOpenFileSelect
(
parameter
.
name
);
}
}
src=
{
fileSelectIcon
}
alt=
""
className=
{
styles
.
fileSelectImg
}
...
...
@@ -311,7 +453,13 @@ const ParameterSetting = (props: IParameterSettingProps) => {
InputProps=
{
{
endAdornment
:
(
<
img
onClick=
{
()
=>
handleOpenFileSelect
(
taskId
,
parameter
.
name
)
}
onClick=
{
()
=>
{
if
(
parameter
.
parameterGroup
===
"out"
)
{
return
;
}
setFileSelectType
(
"dataset"
);
handleOpenFileSelect
(
parameter
.
name
);
}
}
src=
{
fileSelectIcon
}
alt=
""
className=
{
styles
.
fileSelectImg
}
...
...
@@ -328,7 +476,7 @@ const ParameterSetting = (props: IParameterSettingProps) => {
<
MyInput
value=
{
parameter
.
defaultValue
||
""
}
onChange=
{
(
e
:
any
)
=>
handleParameterChange
(
e
,
parameter
.
id
||
""
)
handleParameterChange
(
e
,
parameter
.
name
||
""
)
}
placeholder=
"请输入"
error=
{
parameter
.
error
||
false
}
...
...
@@ -340,7 +488,7 @@ const ParameterSetting = (props: IParameterSettingProps) => {
<
MySelect
value=
{
parameter
.
defaultValue
}
onChange=
{
(
e
:
any
)
=>
handleParameterChange
(
e
,
parameter
.
id
||
""
)
handleParameterChange
(
e
,
parameter
.
name
||
""
)
}
error=
{
parameter
.
error
||
false
}
helpertext=
{
parameter
.
helperText
}
...
...
@@ -352,7 +500,7 @@ const ParameterSetting = (props: IParameterSettingProps) => {
<
MySelect
value=
{
parameter
.
defaultValue
}
onChange=
{
(
e
:
any
)
=>
handleParameterChange
(
e
,
parameter
.
id
||
""
)
handleParameterChange
(
e
,
parameter
.
name
||
""
)
}
multiple=
{
true
}
error=
{
parameter
.
error
||
false
}
...
...
@@ -365,7 +513,7 @@ const ParameterSetting = (props: IParameterSettingProps) => {
<
MyRadio
value=
{
parameter
.
defaultValue
}
onChange=
{
(
e
:
any
)
=>
handleParameterChange
(
e
,
parameter
.
id
||
""
)
handleParameterChange
(
e
,
parameter
.
name
||
""
)
}
options=
{
optionsTransform
(
parameter
.
choices
,
"label"
)
}
error=
{
parameter
.
error
||
false
}
...
...
@@ -382,7 +530,7 @@ const ParameterSetting = (props: IParameterSettingProps) => {
value
:
e
,
},
},
parameter
.
id
||
""
parameter
.
name
||
""
)
}
options=
{
optionsTransform
(
parameter
.
choices
,
"label"
)
}
...
...
@@ -390,15 +538,12 @@ const ParameterSetting = (props: IParameterSettingProps) => {
helperText=
{
parameter
.
helperText
}
></
MyCheckBox
>
)
}
{
/* {parameter.description && (
<Tooltip title={parameter.description} placement="top">
<img className={styles.parameterDesc} src={questionMark} alt="" />
</Tooltip>
)} */
}
</
div
>
</
Tooltip
>
);
},
[]);
},
[
handleParameterChange
]
);
// 输入参数
const
inParameters
:
Array
<
IParameter
>
=
useMemo
(()
=>
{
...
...
@@ -455,6 +600,7 @@ const ParameterSetting = (props: IParameterSettingProps) => {
}
},
[
taskInfo
]);
// 某种类型的参数组渲染
const
randerParameters
=
useCallback
(
(
parameters
:
Array
<
IParameter
>
)
=>
{
return
(
...
...
@@ -463,7 +609,7 @@ const ParameterSetting = (props: IParameterSettingProps) => {
return
(
<
div
className=
{
styles
.
parameter
}
key=
{
parameter
.
id
||
""
+
parameterIndex
}
key=
{
`${parameter.name}${parameterIndex}`
}
>
<
div
className=
{
styles
.
parameterTop
}
>
<
div
className=
{
styles
.
parameterLeft
}
>
...
...
@@ -482,7 +628,7 @@ const ParameterSetting = (props: IParameterSettingProps) => {
<
MySwitch
value=
{
!
parameter
.
hidden
}
onChange=
{
(
e
:
any
)
=>
handleHiddenChange
(
e
,
parameter
.
id
||
""
)
handleHiddenChange
(
e
,
parameter
.
name
||
""
)
}
></
MySwitch
>
</
div
>
...
...
@@ -498,55 +644,12 @@ const ParameterSetting = (props: IParameterSettingProps) => {
[
renderInput
,
handleHiddenChange
]
);
const
handleOpenFileSelect
=
(
taskId
:
string
=
""
,
parameterName
:
string
=
""
)
=>
{
setFileSelectObject
({
taskId
,
parameterName
,
});
// 显示文件夹路径选择弹窗
const
handleOpenFileSelect
=
(
parameterName
:
string
=
""
)
=>
{
setParameterName
(
parameterName
);
setFileSelectOpen
(
true
);
};
const
handleParameterChange
=
useCallback
(
(
e
:
any
,
parameterId
:
string
)
=>
{
console
.
log
(
e
.
target
.
value
,
taskId
,
parameterId
);
const
result
:
ITask
[]
=
_
.
cloneDeep
(
templateConfigInfo
);
console
.
log
(
result
);
result
.
forEach
((
task
)
=>
{
if
(
task
.
id
===
taskId
)
{
let
isCheck
=
true
;
task
.
parameters
.
forEach
((
parameter
)
=>
{
if
(
parameter
.
id
===
parameterId
)
{
parameter
.
defaultValue
=
e
.
target
.
value
;
const
checkResult
=
getCustomTemplateParameterCheckResult
(
parameter
,
e
.
target
.
value
);
parameter
.
error
=
checkResult
.
error
;
parameter
.
helperText
=
checkResult
.
helperText
;
}
if
(
getCustomTemplateParameterCheckResult
(
parameter
,
parameter
.
defaultValue
).
error
===
true
)
{
isCheck
=
false
;
}
});
task
.
isCheck
=
isCheck
;
}
else
{
return
;
}
});
setTemplateConfigInfo
(
result
);
// setParameter(e.target.value, taskId, parameterName);
},
[
templateConfigInfo
,
setTemplateConfigInfo
]
);
// 参数组tabs
const
paramsTabList
=
useMemo
(()
=>
{
return
[
...
...
@@ -580,7 +683,7 @@ const ParameterSetting = (props: IParameterSettingProps) => {
}
else
if
(
hardwareParameters
.
length
!==
0
)
{
return
"hardware"
;
}
else
{
return
""
;
return
"
basis
"
;
}
},
[
basisParameters
,
seniorParameters
,
hardwareParameters
]);
...
...
@@ -631,7 +734,10 @@ const ParameterSetting = (props: IParameterSettingProps) => {
<
div
className=
{
styles
.
paramsList
}
>
{
inParameters
.
map
((
parameter
,
index
)
=>
{
return
(
<
div
className=
{
styles
.
inOutParameterBox
}
key=
{
index
}
>
<
div
className=
{
styles
.
inOutParameterBox
}
key=
{
`${parameter.name}${index}`
}
>
<
div
className=
{
styles
.
inOutParameterTop
}
>
<
div
className=
{
styles
.
inOutParameterleft
}
>
<
div
...
...
@@ -650,12 +756,17 @@ const ParameterSetting = (props: IParameterSettingProps) => {
<
MySwitch
value=
{
!
parameter
.
hidden
}
onChange=
{
(
e
:
any
)
=>
handleHiddenChange
(
e
,
parameter
.
id
||
""
)
handleHiddenChange
(
e
,
parameter
.
name
||
""
)
}
></
MySwitch
>
</
div
>
</
div
>
{
renderInput
(
parameter
)
}
{
parameter
.
error
&&
parameter
.
helperText
&&
(
<
div
className=
{
styles
.
inOutParameterHelperText
}
>
{
parameter
.
helperText
}
</
div
>
)
}
{
/* {renderInput(parameter)} */
}
</
div
>
);
})
}
...
...
@@ -666,9 +777,12 @@ const ParameterSetting = (props: IParameterSettingProps) => {
<
div
className=
{
styles
.
inOutBox
}
>
<
div
className=
{
styles
.
paramsTitle
}
>
输出
</
div
>
<
div
className=
{
styles
.
paramsList
}
>
{
in
Parameters
.
map
((
parameter
,
index
)
=>
{
{
out
Parameters
.
map
((
parameter
,
index
)
=>
{
return
(
<
div
className=
{
styles
.
inOutParameterBox
}
key=
{
index
}
>
<
div
className=
{
styles
.
inOutParameterBox
}
key=
{
`${parameter.name}${index}`
}
>
<
div
className=
{
styles
.
inOutParameterTop
}
>
<
div
className=
{
styles
.
inOutParameterleft
}
>
<
div
...
...
@@ -721,6 +835,14 @@ const ParameterSetting = (props: IParameterSettingProps) => {
<
span
className=
{
styles
.
noDataText
}
>
选中任意算子进行参数设置
</
span
>
</
div
>
)
}
{
fileSelectOpen
&&
(
<
FileSelect
onClose=
{
handleFileSelectOnClose
}
open=
{
fileSelectOpen
}
onConfirm=
{
onFileSelectConfirm
}
type=
{
fileSelectType
}
/>
)
}
</
div
>
);
};
...
...
src/views/WorkFlowEdit/components/SaveCustomTemplate/index.module.css
0 → 100644
View file @
d16c0cda
.saveBox
{
width
:
390px
;
}
src/views/WorkFlowEdit/components/SaveCustomTemplate/index.tsx
0 → 100644
View file @
d16c0cda
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-07-15 15:47:16
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-15 16:30:59
* @FilePath: /bkunyun/src/views/WorkFlowEdit/components/SaveCustomTemplate/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import
{
saveUserSpec
}
from
"@/api/workbench_api"
;
import
MyDialog
from
"@/components/mui/Dialog"
;
import
MyInput
from
"@/components/mui/MyInput"
;
import
{
checkIsNumberLetterChinese
}
from
"@/utils/util"
;
import
{
useState
}
from
"react"
;
import
useMyRequest
from
"@/hooks/useMyRequest"
;
import
{
useStores
}
from
"@/store"
;
import
styles
from
"./index.module.css"
;
import
{
useMessage
}
from
"@/components/MySnackbar"
;
import
{
toJS
}
from
"mobx"
;
import
{
ITask
}
from
"@/views/Project/ProjectSubmitWork/interface"
;
interface
IProps
{
saveFormDialog
:
boolean
;
setSaveFormDialog
:
(
val
:
boolean
)
=>
void
;
onBack
?:
()
=>
void
;
title
:
string
;
setTitle
:
(
val
:
string
)
=>
void
;
version
:
string
;
setVersion
:
(
val
:
string
)
=>
void
;
description
:
string
;
setDescription
:
(
val
:
string
)
=>
void
;
oldversion
:
string
;
creator
?:
string
;
templateConfigInfo
:
ITask
[];
id
?:
string
;
}
const
SaveCustomTemplate
=
(
props
:
IProps
)
=>
{
const
{
saveFormDialog
,
setSaveFormDialog
,
onBack
,
title
,
setTitle
,
version
,
setVersion
,
description
,
setDescription
,
oldversion
,
templateConfigInfo
,
creator
,
id
,
}
=
props
;
const
{
currentProjectStore
}
=
useStores
();
const
Message
=
useMessage
();
const
productId
=
toJS
(
currentProjectStore
.
currentProductInfo
.
id
);
const
[
titleHelper
,
setTitleHelper
]
=
useState
({
// 自定义模板名称错误提示
error
:
false
,
helperText
:
""
,
});
const
[
versionHelper
,
setVersionHelper
]
=
useState
({
// 自定义模板版本错误提示
error
:
false
,
helperText
:
""
,
});
// 自定义模板保存方法
const
{
run
:
saveUserSpecRun
}
=
useMyRequest
(
saveUserSpec
,
{
onSuccess
:
(
res
)
=>
{
Message
.
success
(
"保存成功!"
);
onBack
&&
onBack
();
},
});
// 关闭表单弹窗
const
handleCloseDialog
=
()
=>
{
setSaveFormDialog
(
false
);
};
// 自定义模板名称
const
handleTitleChange
=
(
e
:
any
)
=>
{
const
title
=
e
.
target
.
value
;
setTitle
(
title
);
checkTitle
(
title
);
// 格式不正确,必须在15字符以内,仅限大小写字母、数字、中文
};
// 自定义模板版本
const
handleVersionChange
=
(
e
:
any
)
=>
{
let
version
=
e
.
target
.
value
;
setVersion
(
version
);
checkVersion
(
version
);
};
// 自定义模板描述
const
handleDescriptionChange
=
(
e
:
any
)
=>
{
let
description
=
e
.
target
.
value
;
if
(
description
.
length
<
301
)
{
setDescription
(
description
);
}
};
// 校验模板名称
const
checkTitle
=
(
title
:
string
)
=>
{
if
(
!
title
)
{
setTitleHelper
({
error
:
true
,
helperText
:
"必须输入模板名称"
,
});
return
false
;
}
else
if
(
title
.
length
>
15
)
{
setTitleHelper
({
error
:
true
,
helperText
:
"格式不正确,必须在15字符以内,仅限大小写字母、数字、中文"
,
});
return
false
;
}
else
if
(
!
checkIsNumberLetterChinese
(
title
))
{
setTitleHelper
({
error
:
true
,
helperText
:
"格式不正确,必须在15字符以内,仅限大小写字母、数字、中文"
,
});
return
false
;
}
else
{
setTitleHelper
({
error
:
false
,
helperText
:
""
,
});
return
true
;
}
};
// 校验新版本号是否大于旧版本号
const
checkNewOldVersion
=
(
version
:
string
,
oldversion
:
string
):
boolean
=>
{
let
versionArr
:
any
[]
=
version
.
split
(
"."
);
let
oldversionArr
:
any
[]
=
oldversion
.
split
(
"."
);
versionArr
=
versionArr
.
map
((
item
)
=>
Number
(
item
));
oldversionArr
=
oldversionArr
.
map
((
item
)
=>
Number
(
item
));
if
(
versionArr
[
0
]
<
oldversionArr
[
0
])
{
setVersionHelper
({
error
:
true
,
helperText
:
"新版本号必须大于老版本号,且必须为X.Y.Z格式,XYZ必须为0~99的正整数"
,
});
return
false
;
}
else
if
(
versionArr
[
0
]
===
oldversionArr
[
0
])
{
if
(
versionArr
[
1
]
<
oldversionArr
[
1
])
{
setVersionHelper
({
error
:
true
,
helperText
:
"新版本号必须大于老版本号,且必须为X.Y.Z格式,XYZ必须为0~99的正整数"
,
});
return
false
;
}
else
if
(
versionArr
[
1
]
===
oldversionArr
[
1
])
{
if
(
versionArr
[
2
]
<=
oldversionArr
[
2
])
{
setVersionHelper
({
error
:
true
,
helperText
:
"新版本号必须大于老版本号,且必须为X.Y.Z格式,XYZ必须为0~99的正整数"
,
});
return
false
;
}
}
}
return
true
;
};
// 校验版本号格式
const
checkVersion
=
(
version
:
string
)
=>
{
if
(
/^
[
1-9
]\d?(\.(
0|
[
1-9
]\d?)){2}
$/
.
test
(
version
))
{
setVersionHelper
({
error
:
false
,
helperText
:
""
,
});
if
(
oldversion
)
{
if
(
checkNewOldVersion
(
version
,
oldversion
))
{
return
true
;
}
else
{
return
false
;
}
}
else
{
return
true
;
}
}
else
{
setVersionHelper
({
error
:
true
,
helperText
:
"格式不正确,必须为X.Y.Z格式,且XYZ必须为0~99的正整数"
,
});
return
false
;
}
};
// 表单弹窗确定,新建/编辑自定义模板保存
const
handleOncofirm
=
()
=>
{
if
(
checkTitle
(
title
)
&&
checkVersion
(
version
))
{
if
(
id
)
{
saveUserSpecRun
({
title
,
version
,
description
,
tasks
:
templateConfigInfo
,
productId
,
id
,
creator
,
});
}
else
{
saveUserSpecRun
({
title
,
version
,
description
,
tasks
:
templateConfigInfo
,
productId
,
});
}
}
};
return
(
<
MyDialog
open=
{
saveFormDialog
}
title=
"保存自定义模板"
onClose=
{
handleCloseDialog
}
onConfirm=
{
handleOncofirm
}
>
<
div
className=
{
styles
.
saveBox
}
>
<
MyInput
value=
{
title
}
label=
"模板名称"
onChange=
{
handleTitleChange
}
required
error=
{
titleHelper
.
error
}
helperText=
{
titleHelper
.
helperText
}
style=
{
{
margin
:
"20px 0"
}
}
disabled=
{
id
?
true
:
false
}
></
MyInput
>
<
MyInput
value=
{
version
}
label=
"版本号"
onChange=
{
handleVersionChange
}
error=
{
versionHelper
.
error
}
helperText=
{
versionHelper
.
helperText
}
style=
{
{
marginBottom
:
"20px"
}
}
></
MyInput
>
<
MyInput
value=
{
description
}
label=
"模板描述"
placeholder=
"模板描述"
onChange=
{
handleDescriptionChange
}
multiline
rows=
{
4
}
></
MyInput
>
</
div
>
</
MyDialog
>
);
};
export
default
SaveCustomTemplate
;
src/views/WorkFlowEdit/index.tsx
View file @
d16c0cda
...
...
@@ -2,13 +2,15 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-21 20:03:56
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-1
1 11:31:14
* @LastEditTime: 2022-07-1
5 16:35:59
* @FilePath: /bkunyun/src/views/Project/ProjectSubmitWork/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import
React
,
{
useCallback
,
useState
}
from
"react"
;
import
React
,
{
useCallback
,
use
Effect
,
use
State
}
from
"react"
;
import
ArrowBackIosNewIcon
from
"@mui/icons-material/ArrowBackIosNew"
;
import
IconButton
from
"@mui/material/IconButton"
;
import
_
from
"lodash"
;
import
{
observer
}
from
"mobx-react-lite"
;
import
MyPopconfirm
from
"@/components/mui/MyPopconfirm"
;
import
RadioGroupOfButtonStyle
from
"@/components/CommonComponents/RadioGroupOfButtonStyle"
;
...
...
@@ -16,7 +18,12 @@ import ButtonComponent from "@/components/mui/Button";
import
OperatorList
from
"./components/OperatorList"
;
import
Flow
from
"../Project/components/Flow"
;
import
ParameterSetting
from
"./components/ParameterSetting"
;
import
{
useMessage
}
from
"@/components/MySnackbar"
;
import
{
ITask
}
from
"../Project/ProjectSubmitWork/interface"
;
import
{
fetchTemplateConfigInfo
}
from
"@/api/project_api"
;
import
{
getCustomTemplateParameterCheckResult
}
from
"./util"
;
import
useMyRequest
from
"@/hooks/useMyRequest"
;
import
SaveCustomTemplate
from
"./components/SaveCustomTemplate"
;
import
styles
from
"./index.module.css"
;
...
...
@@ -33,32 +40,110 @@ const radioOptions = [
interface
IProps
{
onBack
?:
()
=>
void
;
id
?:
string
;
}
const
WorkFlowEdit
=
(
props
:
IProps
)
=>
{
const
{
onBack
}
=
props
;
const
[
templateConfigInfo
,
setTemplateConfigInfo
]
=
useState
<
ITask
[]
>
([]);
const
WorkFlowEdit
=
observer
((
props
:
IProps
)
=>
{
const
{
onBack
,
id
}
=
props
;
const
Message
=
useMessage
();
const
[
templateConfigInfo
,
setTemplateConfigInfo
]
=
useState
<
ITask
[]
>
([]);
// 算子大数组
const
[
leftContentType
,
setLeftContentType
]
=
useState
(
"list"
);
const
[
saveFormDialog
,
setSaveFormDialog
]
=
useState
(
false
);
// 保存弹窗显示与否控制
const
[
title
,
setTitle
]
=
useState
(
""
);
// 自定义模板名称
const
[
version
,
setVersion
]
=
useState
(
"1.0.0"
);
// 自定义模板版本
const
[
oldversion
,
setOldersion
]
=
useState
(
""
);
// 编辑是自定义模板的老版本
const
[
description
,
setDescription
]
=
useState
(
""
);
// 自定义模板描述
const
[
creator
,
setCreator
]
=
useState
(
""
);
// 自定义模板创建人
const
[
leftContentType
,
setLeftContentType
]
=
useState
(
"list"
);
// 页面左侧展示的是算子列表还是参数设置
const
[
popperTitle
,
setPopperTitle
]
=
useState
(
// 确认弹窗标题
"返回后,当前页面已填写内容将不保存,确认返回吗?"
);
// 返回后,当前页面已填写内容将不保存,确认返回吗?
// 编辑时获取模板详情的方法
const
{
run
:
fetchTemplateConfigInfoRun
}
=
useMyRequest
(
fetchTemplateConfigInfo
,
{
onSuccess
:
(
res
:
any
)
=>
{
if
(
res
.
data
)
{
setTemplateConfigInfo
(
res
.
data
.
tasks
);
setTitle
(
res
.
data
.
title
);
setOldersion
(
res
.
data
.
version
);
let
version
=
res
.
data
.
version
;
let
arr
=
version
.
split
(
"."
);
if
(
arr
.
length
===
3
)
{
if
(
Number
(
arr
[
2
])
<
99
)
{
arr
[
2
]
=
String
(
Number
(
arr
[
2
])
+
1
);
}
else
{
arr
[
2
]
=
"0"
;
if
(
Number
(
arr
[
1
])
<
99
)
{
arr
[
1
]
=
String
(
Number
(
arr
[
1
])
+
1
);
}
else
{
arr
[
1
]
=
"0"
;
arr
[
0
]
=
String
(
Number
(
arr
[
0
])
+
1
);
}
}
}
setVersion
(
arr
.
join
(
"."
));
setCreator
(
res
.
data
.
creator
);
setDescription
(
res
.
data
.
description
);
}
},
}
);
// id存在时获取模板详情
useEffect
(()
=>
{
if
(
id
)
{
fetchTemplateConfigInfoRun
({
id
});
}
},
[
id
,
fetchTemplateConfigInfoRun
]);
// 确认弹窗相对位置
const
[
anchorEl
,
setAnchorEl
]
=
useState
<
any
>
(
null
);
// 隐藏确认弹窗, 确认弹窗点击取消
const
handleCancel
=
()
=>
{
setAnchorEl
(
null
);
};
// 显示确认弹窗
const
handleShowPopper
=
(
e
:
any
,
title
:
string
)
=>
{
setPopperTitle
(
title
);
setAnchorEl
(
anchorEl
?
null
:
e
.
currentTarget
);
};
// 确认弹窗确认回调
const
handleConfirm
=
()
=>
{
if
(
popperTitle
===
"返回后,当前页面已填写内容将不保存,确认返回吗?"
)
{
onBack
&&
onBack
();
}
};
// 点击保存 先校验工作流 再显示自定义模板基础信息弹窗
const
handlePreserve
=
()
=>
{
// 校验
if
(
templateConfigInfo
.
length
===
0
)
{
Message
.
error
(
"工作流不能为空!"
);
return
;
}
let
templateConfigInfoClone
:
ITask
[]
=
_
.
cloneDeep
(
templateConfigInfo
);
let
check
=
true
;
templateConfigInfoClone
.
forEach
((
task
)
=>
{
task
.
parameters
.
forEach
((
parameter
)
=>
{
const
checkResult
=
getCustomTemplateParameterCheckResult
(
parameter
);
parameter
.
error
=
checkResult
.
error
;
parameter
.
helperText
=
checkResult
.
helperText
;
if
(
checkResult
.
error
)
{
check
=
false
;
}
});
});
setTemplateConfigInfo
(
templateConfigInfoClone
);
if
(
!
check
)
{
Message
.
error
(
"工作流校验未通过,请检查!"
);
}
else
{
console
.
log
(
"提交"
);
setSaveFormDialog
(
true
);
}
};
...
...
@@ -69,14 +154,11 @@ const WorkFlowEdit = (props: IProps) => {
const
handleNodeClick
=
useCallback
((
val
:
string
)
=>
{
setSelectTaskId
(
val
);
},
[]);
return
(
<
div
className=
{
styles
.
swBox
}
>
<
div
className=
{
styles
.
swHeader
}
>
<
div
className=
{
styles
.
swHeaderLeft
}
>
{
/* <MyPopconfirm
title="返回后,当前页面已填写内容将不保存,确认返回吗?"
onConfirm={onBack}
> */
}
<
IconButton
color=
"primary"
aria
-
label=
"upload picture"
...
...
@@ -97,20 +179,12 @@ const WorkFlowEdit = (props: IProps) => {
}
}
/>
</
IconButton
>
{
/* </MyPopconfirm> */
}
</
div
>
<
div
className=
{
styles
.
swHeaderRight
}
>
{
/* <MyPopconfirm
title="提交前请先确认参数填写无误,确认提交吗?"
onConfirm={() => console.log(2)}
> */
}
<
ButtonComponent
text=
"保存"
click=
{
(
e
:
any
)
=>
handleShowPopper
(
e
,
"提交前请先确认参数填写无误,确认提交吗?"
)
}
click=
{
()
=>
handlePreserve
()
}
></
ButtonComponent
>
{
/* </MyPopconfirm> */
}
</
div
>
</
div
>
<
div
className=
{
styles
.
swContent
}
>
...
...
@@ -139,7 +213,8 @@ const WorkFlowEdit = (props: IProps) => {
{
leftContentType
!==
"list"
&&
(
<
ParameterSetting
templateConfigInfo=
{
templateConfigInfo
}
taskId=
{
""
}
setTemplateConfigInfo=
{
setTemplateConfigInfo
}
taskId=
{
selectTaskId
||
""
}
/>
)
}
</
div
>
...
...
@@ -148,6 +223,7 @@ const WorkFlowEdit = (props: IProps) => {
tasks=
{
templateConfigInfo
}
setTasks=
{
setTemplateConfigInfo
}
type=
"edit"
onFlowNodeClick=
{
handleNodeClick
}
/>
</
div
>
</
div
>
...
...
@@ -157,8 +233,25 @@ const WorkFlowEdit = (props: IProps) => {
onCancel=
{
handleCancel
}
onConfirm=
{
handleConfirm
}
/>
{
saveFormDialog
&&
(
<
SaveCustomTemplate
title=
{
title
}
setTitle=
{
setTitle
}
description=
{
description
}
setDescription=
{
setDescription
}
version=
{
version
}
setVersion=
{
setVersion
}
creator=
{
creator
}
setSaveFormDialog=
{
setSaveFormDialog
}
saveFormDialog=
{
saveFormDialog
}
onBack=
{
onBack
}
templateConfigInfo=
{
templateConfigInfo
}
id=
{
id
}
oldversion=
{
oldversion
}
/>
)
}
</
div
>
);
};
}
)
;
export
default
WorkFlowEdit
;
src/views/WorkFlowEdit/util.ts
View file @
d16c0cda
import
{
IParameter
}
from
"../Project/ProjectSubmitWork/interface"
;
export
const
getCustomTemplateParameterCheckResult
=
(
parameter
:
IParameter
,
value
:
string
):
{
error
:
boolean
;
helperText
:
string
;
deleteLine
?:
boolean
;
// 该线是否要删除
}
=>
{
let
error
=
false
;
let
helperText
=
""
;
// 输出不做校验
if
(
parameter
.
parameterGroup
===
"out"
)
{
return
{
error
,
helperText
,
}
}
// 输入校验
// 1. 当该输入为必填项时:
// 1.1 若为“启用”状态,则表示该输入的值交由用户在使用时填写。故该输入的节点入口在右侧编辑区内不允许连线,若已有连线则自动将该线删除。
// 1.2 若为“关闭”状态,则表示该输入的值是上一步批算子的结果。故该输入的节点入口在右侧编辑区内必须有连线。(若编辑者没有为该节点入口添加连线,则错误提示“该输入为必填,需在右侧视图编辑区连接输入文件或重新改回“开启”状态”;若连上线了则无需错误提示。)
// 2. 当该输入为选填项时:
// 2.1 若为“启用”状态,则表示该输入的值交由用户在使用时填写。故该输入的节点入口在右侧编辑区内不允许连线,若已有连线则自动将该线删除。
// 2.2 若为“关闭”状态,则表示该输入的值是上一步批算子的结果,又因为其为选填项,所以这线可连可不连,不做限制。
if
(
parameter
.
parameterGroup
===
"in"
)
{
if
(
parameter
.
required
)
{
if
(
!
parameter
.
hidden
&&
parameter
.
linked
)
{
return
{
error
,
helperText
,
deleteLine
:
true
,
}
}
else
if
(
!
parameter
.
hidden
&&
!
parameter
.
linked
)
{
return
{
error
,
helperText
,
deleteLine
:
false
,
}
}
else
if
(
parameter
.
hidden
&&
parameter
.
linked
)
{
return
{
error
,
helperText
,
deleteLine
:
false
,
}
}
else
if
(
parameter
.
hidden
&&
!
parameter
.
linked
)
{
return
{
error
:
true
,
helperText
:
'该输入为必填,需在右侧视图编辑区连接输入文件或重新改回“开启”状态'
,
deleteLine
:
false
,
}
}
}
else
{
if
(
!
parameter
.
hidden
&&
parameter
.
linked
)
{
return
{
error
,
helperText
,
deleteLine
:
true
,
}
}
else
if
(
!
parameter
.
hidden
&&
!
parameter
.
linked
)
{
return
{
error
,
helperText
,
deleteLine
:
false
,
}
}
else
if
(
parameter
.
hidden
&&
parameter
.
linked
)
{
return
{
error
,
helperText
,
deleteLine
:
false
,
}
}
else
if
(
parameter
.
hidden
&&
!
parameter
.
linked
)
{
return
{
error
,
helperText
,
deleteLine
:
false
,
}
}
}
}
// 表单校验
if
(
parameter
.
required
)
{
// 提交任务时不展示
if
(
parameter
.
hidden
)
{
if
(
Array
.
isArray
(
v
alue
))
{
if
(
v
alue
.
length
===
0
)
{
if
(
Array
.
isArray
(
parameter
.
defaultV
alue
))
{
if
(
parameter
.
defaultV
alue
.
length
===
0
)
{
error
=
true
;
helperText
=
"该参数为必填,您必须为该参数赋予默认值"
;
}
}
else
if
(
value
===
""
||
value
===
null
||
v
alue
===
undefined
)
{
}
else
if
(
parameter
.
defaultValue
===
""
||
parameter
.
defaultValue
===
null
||
parameter
.
defaultV
alue
===
undefined
)
{
error
=
true
;
helperText
=
"该参数为必填,您必须为该参数赋予默认值"
;
}
}
}
if
(
error
)
{
return
{
error
,
helperText
,
};
}
// linked
// 有值才做validators旋律校验
if
(
parameter
.
defaultValue
)
{
if
(
Array
.
isArray
(
parameter
.
validators
))
{
if
(
parameter
.
validators
.
length
>
0
)
{
parameter
.
validators
.
forEach
((
validator
)
=>
{
const
reg
=
new
RegExp
(
validator
.
regex
);
if
(
!
reg
.
test
(
v
alue
))
{
if
(
!
reg
.
test
(
parameter
.
defaultV
alue
))
{
error
=
true
;
helperText
=
validator
.
message
;
}
});
}
}
}
return
{
error
,
helperText
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment