Commit fd18b243 authored by wuyongsheng's avatar wuyongsheng

feat: 构建算子添加联调

parent 34f6e947
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com * @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-13 09:56:57 * @Date: 2022-06-13 09:56:57
* @LastEditors: 吴永生 15770852798@163.com * @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-20 14:56:21 * @LastEditTime: 2022-10-24 13:41:26
* @FilePath: /bkunyun/src/api/api_manager.ts * @FilePath: /bkunyun/src/api/api_manager.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/ */
...@@ -56,6 +56,7 @@ const RESTAPI = { ...@@ -56,6 +56,7 @@ const RESTAPI = {
API_ACTORENV_DELETE:`${BACKEND_API_URI_PREFIX}/cpp/actorenv/delete`, // 删除用户算子环境 API_ACTORENV_DELETE:`${BACKEND_API_URI_PREFIX}/cpp/actorenv/delete`, // 删除用户算子环境
API_ACTORENV_DETAIL:`${BACKEND_API_URI_PREFIX}/cpp/actorenv/detail`, // 查询应用环境的详情信息 API_ACTORENV_DETAIL:`${BACKEND_API_URI_PREFIX}/cpp/actorenv/detail`, // 查询应用环境的详情信息
API_ACTOR_ENV_OPTIONS:`${BACKEND_API_URI_PREFIX}/cpp/actorenv/usableenv`, // 查询用户应用环境下拉 API_ACTOR_ENV_OPTIONS:`${BACKEND_API_URI_PREFIX}/cpp/actorenv/usableenv`, // 查询用户应用环境下拉
API_SAVE_OPERATOR:`${BACKEND_API_URI_PREFIX}/cpp/workflow/custom/actor`, // 保存自定义批流算子
API_WORKFLOWSPEC_LIST:`${BACKEND_API_URI_PREFIX}/cpp/workbench/product/workflowspec/list`, // 模板列表 所有的 API_WORKFLOWSPEC_LIST:`${BACKEND_API_URI_PREFIX}/cpp/workbench/product/workflowspec/list`, // 模板列表 所有的
}; };
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴永生 15770852798@163.com * @Author: 吴永生 15770852798@163.com
* @Date: 2022-10-19 17:09:23 * @Date: 2022-10-19 17:09:23
* @LastEditors: 吴永生 15770852798@163.com * @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-20 15:01:36 * @LastEditTime: 2022-10-24 13:41:53
* @FilePath: /bkunyun/src/api/resourceCenter.ts * @FilePath: /bkunyun/src/api/resourceCenter.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/ */
...@@ -113,6 +113,17 @@ const getWorkflowspecList = (params: {productId?: string, title?: string}) => { ...@@ -113,6 +113,17 @@ const getWorkflowspecList = (params: {productId?: string, title?: string}) => {
}; };
// API_WORKFLOWSPEC_LIST // API_WORKFLOWSPEC_LIST
// 新增应用环境
const saveOperator = (params: any) => {
return request({
url: Api.API_SAVE_OPERATOR,
method: "post",
data: params,
});
};
export { export {
getPublicEnv, getPublicEnv,
getPublicProject, getPublicProject,
...@@ -122,5 +133,6 @@ export { ...@@ -122,5 +133,6 @@ export {
getOperatorList, getOperatorList,
getActorenvDetail, getActorenvDetail,
getActorEnvOptions, getActorEnvOptions,
getWorkflowspecList getWorkflowspecList,
saveOperator
}; };
import CodeMirror from "@uiw/react-codemirror"; /*
* @Author: 吴永生 15770852798@163.com
* @Date: 2022-10-20 19:45:32
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-21 10:19:46
* @FilePath: /bkunyun/src/components/CommonComponents/Code/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import CodeMirror, { ReactCodeMirrorProps } from "@uiw/react-codemirror";
// import { javascript } from "@codemirror/lang-javascript";
type ICodeType = { interface ICodeType extends ReactCodeMirrorProps {
value: string; value: string;
onChange: any; onChange: any;
height?: string; height?: string;
width?: string; width?: string;
maxWidth?: string; maxWidth?: string;
theme?: "light" | "dark"; theme?: "light" | "dark";
}; }
const Code = (props: ICodeType) => { const Code = (props: ICodeType) => {
const { value, onChange, height, theme = "dark", width, maxWidth } = props; const { value, onChange, height, theme = "dark", width, maxWidth } = props;
return ( return (
<CodeMirror <CodeMirror
{...props}
height={height || "100%"} height={height || "100%"}
width={width || "100%"} width={width || "100%"}
maxWidth={maxWidth || "100%"} maxWidth={maxWidth || "100%"}
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
} }
.form { .form {
width: 368px; width: 368px;
min-width: 368px;
box-sizing: border-box; box-sizing: border-box;
padding: 16px 24px; padding: 16px 24px;
border: 1px solid #ebedf0; border: 1px solid #ebedf0;
...@@ -48,6 +49,7 @@ ...@@ -48,6 +49,7 @@
} }
.newForm { .newForm {
width: 368px; width: 368px;
min-width: 368px;
box-sizing: border-box; box-sizing: border-box;
padding: 16px 32px 0px 0; padding: 16px 32px 0px 0;
border-right: 1px solid #ebedf0; border-right: 1px solid #ebedf0;
......
...@@ -2,13 +2,15 @@ ...@@ -2,13 +2,15 @@
* @Author: 吴永生 15770852798@163.com * @Author: 吴永生 15770852798@163.com
* @Date: 2022-10-18 16:12:55 * @Date: 2022-10-18 16:12:55
* @LastEditors: 吴永生 15770852798@163.com * @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-20 19:44:43 * @LastEditTime: 2022-10-24 13:40:27
* @FilePath: /bkunyun/src/views/ResourceCenter/UserResources/WorkflowOperator/components/AddOperator/index.tsx * @FilePath: /bkunyun/src/views/ResourceCenter/UserResources/WorkflowOperator/components/AddOperator/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/ */
import { useEffect, useState, useCallback, useMemo } from "react"; import { useEffect, useState, useCallback, useMemo } from "react";
import classNames from "classnames"; import classNames from "classnames";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { Base64 } from "js-base64";
import _ from "lodash";
import MyInput from "@/components/mui/MyInput"; import MyInput from "@/components/mui/MyInput";
import MySelect from "@/components/mui/MySelect"; import MySelect from "@/components/mui/MySelect";
...@@ -22,13 +24,12 @@ import OperatorList from "@/views/CustomOperator/components/OperatorList"; ...@@ -22,13 +24,12 @@ import OperatorList from "@/views/CustomOperator/components/OperatorList";
import FormItemBox from "@/components/mui/FormItemBox"; import FormItemBox from "@/components/mui/FormItemBox";
import { useStores } from "@/store"; import { useStores } from "@/store";
import useMyRequest from "@/hooks/useMyRequest"; import useMyRequest from "@/hooks/useMyRequest";
import { getActorEnvOptions } from "@/api/resourceCenter"; import { getActorEnvOptions, saveOperator } from "@/api/resourceCenter";
import { IOperatorAddFormData } from "../../interface"; import { IOperatorAddFormData } from "../../interface";
import { checkFormData, checkParamsConfig, initCode } from "./utils";
import style from "./index.module.css"; import style from "./index.module.css";
import { checkFormData, checkParamsConfig } from "./utils"; import { useMessage } from "@/components/MySnackbar";
import { Base64 } from "js-base64";
interface IAddOperator { interface IAddOperator {
pageType: string; pageType: string;
setPageType: (val: string) => void; setPageType: (val: string) => void;
...@@ -38,6 +39,7 @@ type IBuildType = "ENVIRONMENT" | "OPERATOR"; ...@@ -38,6 +39,7 @@ type IBuildType = "ENVIRONMENT" | "OPERATOR";
const AddOperator = observer((props: IAddOperator) => { const AddOperator = observer((props: IAddOperator) => {
const { setPageType } = props; const { setPageType } = props;
const Message = useMessage();
/** 创建类型 BATCH - 批算子; FLOW - 流算子*/ /** 创建类型 BATCH - 批算子; FLOW - 流算子*/
const [taskType, setTaskType] = useState<"BATCH" | "FLOW">("BATCH"); const [taskType, setTaskType] = useState<"BATCH" | "FLOW">("BATCH");
...@@ -53,7 +55,7 @@ const AddOperator = observer((props: IAddOperator) => { ...@@ -53,7 +55,7 @@ const AddOperator = observer((props: IAddOperator) => {
/** 应用环境下拉 */ /** 应用环境下拉 */
const [actorEnvOptions, setActorEnvOptions] = useState([]); const [actorEnvOptions, setActorEnvOptions] = useState([]);
/** 参数配置 */ /** 参数配置 */
const [code, setCode] = useState(""); const [code, setCode] = useState(JSON.stringify(initCode, null, "\t"));
/** 运行脚本 */ /** 运行脚本 */
const [command, setCommand] = useState<string>(""); const [command, setCommand] = useState<string>("");
...@@ -77,6 +79,48 @@ const AddOperator = observer((props: IAddOperator) => { ...@@ -77,6 +79,48 @@ const AddOperator = observer((props: IAddOperator) => {
[formData] [formData]
); );
const paramsConfigBlur = () => {
if (code === "") return;
let result;
try {
result = JSON.stringify(JSON.parse(code), null, "\t");
if (typeof result === "string") {
setCode(result);
const checkErrorArr = checkParamsConfig(result);
if (checkErrorArr.length) {
Message.error("参数配置不正确!");
setFormErrors({
...formErrors,
...{ parameters: "参数配置不正确!" },
});
const codeDom = document.getElementById("paramsConfig");
const all = codeDom?.getElementsByClassName("cm-line");
const allArr = Array.prototype.slice.call(all);
for (let x = 0; x < allArr?.length; x++) {
const a = `${allArr[x]?.innerHTML}`
.replace(/"/g, "")
.replace(/,/g, "")
.replace(/\t/g, "");
if (checkErrorArr.includes(a)) {
setTimeout(() => {
allArr[x].style =
"text-decoration: wavy underline; text-decoration-color: #ff4e4e;";
}, 500);
}
}
} else {
const newFormErrors = _.cloneDeep(formErrors);
delete newFormErrors.parameters;
setFormErrors(newFormErrors);
}
}
} catch (error) {
Message.error("JSON格式不正确!");
console.log("JSON格式不正确!");
}
};
/** 获取应用环境下拉 */ /** 获取应用环境下拉 */
const { run: fetchActorEnvOptions } = useMyRequest(getActorEnvOptions, { const { run: fetchActorEnvOptions } = useMyRequest(getActorEnvOptions, {
onSuccess: (res: any) => { onSuccess: (res: any) => {
...@@ -100,16 +144,28 @@ const AddOperator = observer((props: IAddOperator) => { ...@@ -100,16 +144,28 @@ const AddOperator = observer((props: IAddOperator) => {
}; };
const handleSubmit = useCallback(() => { const handleSubmit = useCallback(() => {
const paramsError = checkParamsConfig(code);
const resultErrors = checkFormData(formData, taskType); const resultErrors = checkFormData(formData, taskType);
setFormErrors(resultErrors); formErrors?.parameters
if (!Object.getOwnPropertyNames(resultErrors)?.length) return; ? setFormErrors({ ...resultErrors, parameters: formErrors.parameters })
: setFormErrors({ ...resultErrors });
if (Object.getOwnPropertyNames(resultErrors)?.length) return;
let newParameters = [];
try {
newParameters = JSON.parse(code);
} catch (err) {
console.log(err);
}
const params = { const params = {
...formData, ...formData,
command: Base64.encode(command), command: Base64.encode(command),
parameters: newParameters,
type: taskType,
}; };
console.log(params, 33); saveOperator(params).then((res) => {
}, [command, formData, taskType, code]); console.log(res, "333");
});
}, [code, command, formData, formErrors, taskType]);
return ( return (
<div className={style.addOperatorBox}> <div className={style.addOperatorBox}>
...@@ -140,7 +196,7 @@ const AddOperator = observer((props: IAddOperator) => { ...@@ -140,7 +196,7 @@ const AddOperator = observer((props: IAddOperator) => {
<div <div
className={classNames({ className={classNames({
[style.form]: batchBuildType === "ENVIRONMENT", [style.form]: batchBuildType === "ENVIRONMENT",
[style.newForm]: batchBuildType != "ENVIRONMENT", [style.newForm]: batchBuildType !== "ENVIRONMENT",
})} })}
> >
<FormItemBox <FormItemBox
...@@ -243,11 +299,16 @@ const AddOperator = observer((props: IAddOperator) => { ...@@ -243,11 +299,16 @@ const AddOperator = observer((props: IAddOperator) => {
<div className={style.codeTitle}>参数配置</div> <div className={style.codeTitle}>参数配置</div>
<div className={style.code}> <div className={style.code}>
<Code <Code
id="paramsConfig"
value={code} value={code}
onChange={(e: string) => { // placeholder="dd"
onChange={(e: string, viewUpdate: any) => {
setCode(e); setCode(e);
}} }}
onBlur={paramsConfigBlur}
height="535px" height="535px"
width="600"
style={{ flex: 1 }}
/> />
</div> </div>
</div> </div>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴永生 15770852798@163.com * @Author: 吴永生 15770852798@163.com
* @Date: 2022-10-20 17:36:14 * @Date: 2022-10-20 17:36:14
* @LastEditors: 吴永生 15770852798@163.com * @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-20 19:44:52 * @LastEditTime: 2022-10-24 11:00:49
* @FilePath: /bkunyun/src/views/ResourceCenter/UserResources/WorkflowOperator/components/AddOperator/utils.ts * @FilePath: /bkunyun/src/views/ResourceCenter/UserResources/WorkflowOperator/components/AddOperator/utils.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/ */
...@@ -39,15 +39,61 @@ export const checkFormData = (formData: IOperatorAddFormData, taskType: 'BATCH' ...@@ -39,15 +39,61 @@ export const checkFormData = (formData: IOperatorAddFormData, taskType: 'BATCH'
/** 参数配置校验 */ /** 参数配置校验 */
export const checkParamsConfig = (val: string) => { export const checkParamsConfig = (val: string) => {
let result: string = '' let result: any = []
const arr = val.split('\n' || ',') try{
const value = JSON.parse(val)
if(!val){ value?.length && value.forEach((item: any)=>{
result = '请输入参数配置' const nameReg = new RegExp("^[A-Za-z][A-Za-z0-9_]{1,14}$");
const titleReg = new RegExp("^[A-Za-z0-9\u4e00-\u9fa5]{1,15}$");
if( !nameReg.test(item?.name) ){
result.push(`name: ${item?.name}`)
} }
if(!true){ if( !titleReg.test(item?.title) ){
result = '参数配置格式不正确' result.push(`title: ${item?.title}`)
}
if( item?.description > 300 ){
result.push(`description: ${item?.description}`)
}
if( !['STRING','FILE','DATASET','INT','FLOAT','DOUBLE','BOOLEAN','ARRAY_STRING','ARRAY_FILE','ARRAY_DATASET','ARRAY_INT','ARRAY_FLOAT','ARRAY_DOUBLE','ARRAY_BOOLEAN'].includes(item?.classType )){
result.push(`classType: ${item?.classType}`)
}
if(!['true','false'].includes(String(item?.required)) ) {
result.push(`required: ${item?.required}`)
}
if( !['PATH','DATASET','FILE','INPUT','SELECT','MULTIPLESELECT','RADIO','CHECKBOX'].includes(item?.domType )){
result.push(`domType: ${item?.domType}`)
}
})
} catch(error){
console.log(error)
} }
return result return result
} }
export const initCode = [{
"name" : "timeout",
"classType" : "INT",
"required" : false,
"defaultValue" : 10000,
"description" : "",
"hidden" : true,
"title" : "",
"order" : 0,
"domType" : "INPUT",
"choices" : [
{
"label" : "是",
"value" : "true"
},
{
"label": "否",
"value": "false"
}
],
"validators" : [
{
"regex" : "^.*\\.(pdb|PDB|pdbqt|PDBQT)$",
"message" : "请输入PDB或PDBQT文件"
}
]
}]
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴永生 15770852798@163.com * @Author: 吴永生 15770852798@163.com
* @Date: 2022-10-19 20:50:18 * @Date: 2022-10-19 20:50:18
* @LastEditors: 吴永生 15770852798@163.com * @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-20 19:05:27 * @LastEditTime: 2022-10-24 11:29:18
* @FilePath: /bkunyun/src/views/ResourceCenter/UserResources/WorkflowOperator/interface.ts * @FilePath: /bkunyun/src/views/ResourceCenter/UserResources/WorkflowOperator/interface.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/ */
...@@ -28,4 +28,5 @@ export interface IOperatorAddFormData { ...@@ -28,4 +28,5 @@ export interface IOperatorAddFormData {
productId?: string; productId?: string;
description?: string; description?: string;
envId?: string; envId?: string;
parameters?: any
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment