Commit e0e8414c authored by wuyongsheng's avatar wuyongsheng

feat: 编辑算子联调

parent a0fa234c
......@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-13 09:56:57
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-24 13:41:26
* @LastEditTime: 2022-10-25 18:23:37
* @FilePath: /bkunyun/src/api/api_manager.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -60,6 +60,7 @@ const RESTAPI = {
API_WORKFLOWSPEC_LIST:`${BACKEND_API_URI_PREFIX}/cpp/workbench/product/workflowspec/list`, // 模板列表 所有的
API_WORKFLOWSPEC_DELETE:`${BACKEND_API_URI_PREFIX}/cpp/workbench/workflowspec/delete`, // 删除模板
API_WORKFLOWSPEC_DETAIL:`${BACKEND_API_URI_PREFIX}/cpp/workbench/workflowspec`, // 删除模板
API_OPERATOR_DETAILS:`${BACKEND_API_URI_PREFIX}/cpp/workflow/actorspec/detail`, // 获取算子详情
};
export default RESTAPI;
......@@ -2,7 +2,7 @@
* @Author: 吴永生 15770852798@163.com
* @Date: 2022-10-19 17:09:23
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-24 13:41:53
* @LastEditTime: 2022-10-25 18:23:55
* @FilePath: /bkunyun/src/api/resourceCenter.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -134,6 +134,16 @@ const deleteWorkflowspec = (params: {
});
};
// 查询算子的详情信息
const getOperatorDetail = (id: string) => {
return request({
url:`${Api.API_OPERATOR_DETAILS}/${id}`,
method: "get",
});
};
// 获取工作流模板详情
const getWorkflowspecDetail = (id: string) => {
return request({
......@@ -155,5 +165,6 @@ export {
getWorkflowspecList,
saveOperator,
deleteWorkflowspec,
getWorkflowspecDetail
getWorkflowspecDetail,
getOperatorDetail
};
......@@ -2,15 +2,17 @@
* @Author: 吴永生 15770852798@163.com
* @Date: 2022-10-20 19:45:32
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-21 10:19:46
* @LastEditTime: 2022-10-25 17:14:16
* @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 { memo } from "react";
import { isEqual } from "lodash";
// import { javascript } from "@codemirror/lang-javascript";
interface ICodeType extends ReactCodeMirrorProps {
value: string;
value?: string;
onChange: any;
height?: string;
width?: string;
......@@ -19,6 +21,7 @@ interface ICodeType extends ReactCodeMirrorProps {
}
const Code = (props: ICodeType) => {
console.log("----");
const { value, onChange, height, theme = "dark", width, maxWidth } = props;
return (
<CodeMirror
......@@ -32,4 +35,12 @@ const Code = (props: ICodeType) => {
/>
);
};
export default Code;
const handleEqual = (prvProps: ICodeType, nextProps: ICodeType) => {
if (isEqual(prvProps, nextProps)) {
return true;
}
return true;
};
export default memo(Code, handleEqual);
......@@ -76,14 +76,14 @@ export default function MyBorderlessSelect(props: IProps) {
background: "rgba(247, 248, 250, 1)",
cursor: "not-allowed",
"& .MuiOutlinedInput-notchedOutline": {
borderWidth: '0px'
borderWidth: "0px",
},
},
},
input: {
fontSize: "14px",
"&.Mui-focused":{
color:"#1370FF",
"&.Mui-focused": {
color: "#1370FF",
},
"&.Mui-disabled": {
background: "rgba(247, 248, 250, 1)",
......@@ -127,7 +127,7 @@ export default function MyBorderlessSelect(props: IProps) {
root: {
"&.Mui-focused .MuiOutlinedInput-notchedOutline": {
borderWidth: "0px",
color: '#1370FF'
color: "#1370FF",
},
"& .MuiOutlinedInput-notchedOutline": {
borderColor: "#DDE1E6",
......@@ -213,29 +213,29 @@ export default function MyBorderlessSelect(props: IProps) {
>
{options.length
? options?.map((item: IOption, index) => {
return (
<MenuItem
value={item.value}
disabled={item?.disabled}
key={index}
>
{item.label}
{value === item.value && (
<img
style={{
width: "16px",
height: "16px",
position: "absolute",
top: "10px",
right: "12px",
}}
src={selectActive}
alt=""
/>
)}
</MenuItem>
);
})
return (
<MenuItem
value={item.value}
disabled={item?.disabled}
key={index}
>
{item.label}
{value === item.value && (
<img
style={{
width: "16px",
height: "16px",
position: "absolute",
top: "10px",
right: "12px",
}}
src={selectActive}
alt=""
/>
)}
</MenuItem>
);
})
: null}
</Select>
{helpertext && error && <FormHelperText>{helpertext}</FormHelperText>}
......
......@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:18:13
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-24 20:23:02
* @LastEditTime: 2022-10-25 09:44:27
* @FilePath: /bkunyun/src/router/index.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
import { AnyMap } from "immer/dist/internal";
......@@ -55,7 +55,7 @@ export const elements: {
} = {
Demo: Demo,
UserResources: UserResources,
SeeEnv: SeeEnv,
SeeFloe: SeeEnv,
OperatorDetails: OperatorDetails,
ProjectSetting: ProjectSetting,
ProjectData: ProjectData,
......
......@@ -30,11 +30,11 @@ const OperatorList = (props: IProps) => {
return 1;
} else {
const countArr = operatorList.map((operatorLi) => {
const _index = operatorLi.id.indexOf("_");
const _index = operatorLi.id?.indexOf("_");
if (_index === -1) {
return 1;
} else {
return Number(operatorLi.id.slice(_index + 1));
return Number(operatorLi.id?.slice(_index + 1));
}
});
const maxCount = Math.max(...countArr);
......
......@@ -8,7 +8,7 @@ import { ITask } from "../Project/ProjectSubmitWork/interface";
* @Author: 吴永生 15770852798@163.com
* @Date: 2022-10-24 18:08:47
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-24 18:31:12
* @LastEditTime: 2022-10-25 18:16:34
* @FilePath: /bkunyun/src/views/CustomOperator/useCheckOperator.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -18,7 +18,7 @@ const useCheckOperator = (
nullText?: string
) => {
const Message = useMessage();
const [checkStatus, setCheckStatus] = useState<boolean>(false);
let checkStatus = false;
// 判断 每个起始算子(可以有多个起始点)的输入必须为文件的路径输入或数据集的路径输入。
const checkIn = (targetArr: string[]) => {
......@@ -105,6 +105,7 @@ const useCheckOperator = (
const handleCheck = () => {
if (operatorList.length === 0) {
Message.error(nullText || "内容不能为空!");
checkStatus = false;
return;
}
let sourceArr: string[] = [];
......@@ -116,20 +117,23 @@ const useCheckOperator = (
});
});
if (!checkHasOneLine([...sourceArr], [...targetArr])) {
checkStatus = false;
Message.error("部分算子没有流程线,请检查流程!");
return;
}
if (!checkIn([...targetArr])) {
checkStatus = false;
Message.error("每个流程第一步需读取文件/数据集,请检查流程!");
return;
}
if (!checkOut([...sourceArr])) {
checkStatus = false;
Message.error(
"每个流程最后一步必须将数据写入为文件/数据集,请检查流程!"
);
return;
}
setCheckStatus(true);
checkStatus = true;
successCallBack();
};
......
......@@ -94,3 +94,12 @@
.descBox {
padding-left: 32px;
}
.codeErrorBox {
padding-left: 20px;
height: 32px;
line-height: 32px;
width: calc(100% - 20px);
color: #ff4e4e;
background-color: #ffe8e8;
}
......@@ -2,7 +2,7 @@
* @Author: 吴永生 15770852798@163.com
* @Date: 2022-10-18 16:12:55
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-24 20:39:26
* @LastEditTime: 2022-10-25 18:04:16
* @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
*/
......@@ -25,7 +25,11 @@ import OperatorList from "@/views/CustomOperator/components/OperatorList";
import FormItemBox from "@/components/mui/FormItemBox";
import { useStores } from "@/store";
import useMyRequest from "@/hooks/useMyRequest";
import { getActorEnvOptions, saveOperator } from "@/api/resourceCenter";
import {
getActorEnvOptions,
getOperatorDetail,
saveOperator,
} from "@/api/resourceCenter";
import { IOperatorAddFormData } from "../../interface";
import { checkFormData, checkParamsConfig, initCode, text } from "./utils";
import batchOperator from "@/assets/resourceCenter/batchOperator.svg";
......@@ -66,15 +70,22 @@ const AddOperator = observer((props: IAddOperator) => {
const [actorEnvOptions, setActorEnvOptions] = useState([]);
/** 参数配置 */
const [code, setCode] = useState(JSON.stringify(initCode, null, "\t"));
/** 参数配置 错误提示 */
const [parametersError, setParametersError] = useState<string>("");
/** 运行脚本 */
const [command, setCommand] = useState<string>("");
/** 表单数据 */
const [formData, setFormData] = useState<IOperatorAddFormData>({});
const [formData, setFormData] = useState<IOperatorAddFormData>({
productId: defaultProduct,
});
/** 表单数据修改 */
const [formErrors, setFormErrors] = useState<IOperatorAddFormData>({});
/** 是否打开帮助手册 */
const [tipsOpen, setTipsOpen] = useState<boolean>(false);
/** 详情数据 */
const [detailInfo, setDetailInfo] = useState<any>();
const { handleCheck, checkStatus } = useCheckOperator(
operatorList,
......@@ -89,6 +100,8 @@ const AddOperator = observer((props: IAddOperator) => {
];
}, []);
/** 获取详情数据 */
/** 表单数据 */
const changeFormData = useCallback(
(val: IOperatorAddFormData) => {
......@@ -97,22 +110,67 @@ const AddOperator = observer((props: IAddOperator) => {
[formData]
);
/** 获取算子详情 */
const { run: fetchOperatorDetail } = useMyRequest(getOperatorDetail, {
onSuccess: (res: any) => {
if (res.message === "success") {
const {
title = "",
type = "BATCH",
version = "",
productId = "",
description = "",
envId = "",
} = res.data;
/** 设置表单数据 */
setFormData({
title,
type,
version,
productId,
description,
envId,
});
/** 有envId 就是基于应用环境创建的 */
if (type === "BATCH") {
setBatchBuildType(envId ? "ENVIRONMENT" : "OPERATOR");
}
/** 有envId 就是基于应用环境创建的 */
setTaskType(type || "BATCH");
/** 设置参数配置 */
if (type === "BATCH" && !envId) {
setOperatorList(res?.data?.parameters || []);
} else {
setCode(JSON.stringify(res?.data?.parameters, null, "\t"));
}
/** 设置详情信息 */
setDetailInfo(res.data);
}
},
});
useEffect(() => {
if (!detailsId) return;
fetchOperatorDetail(detailsId);
}, [detailsId, fetchOperatorDetail]);
const paramsConfigBlur = useCallback(() => {
console.log(2);
if (code === "") return;
let result;
let result, resultError;
console.log(batchBuildType, "batchBuildType");
if (batchBuildType === "OPERATOR") return;
if (code === "") {
resultError = " 请输入参数配置!";
}
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: "参数配置不正确!" },
// });
setParametersError("参数配置不正确!");
resultError = "参数配置不正确!";
const codeDom = document.getElementById("paramsConfig");
const all = codeDom?.getElementsByClassName("cm-line");
const allArr = Array.prototype.slice.call(all);
......@@ -128,17 +186,16 @@ const AddOperator = observer((props: IAddOperator) => {
}, 200);
}
}
} else {
const newFormErrors = _.cloneDeep(formErrors);
delete newFormErrors.parameters;
setFormErrors(newFormErrors);
}
}
} catch (error) {
Message.error("JSON格式不正确!");
setParametersError("JSON格式不正确!");
resultError = "JSON格式不正确!";
console.log("JSON格式不正确!");
}
}, [Message, code, formErrors]);
return resultError;
}, [batchBuildType, code]);
/** 获取应用环境下拉 */
const { run: fetchActorEnvOptions } = useMyRequest(getActorEnvOptions, {
......@@ -164,16 +221,19 @@ const AddOperator = observer((props: IAddOperator) => {
const handleSubmit = useCallback(() => {
const resultErrors = checkFormData(formData, batchBuildType);
// paramsConfigBlur();
formErrors?.parameters
? setFormErrors({ ...resultErrors, parameters: formErrors.parameters })
: setFormErrors({ ...resultErrors });
const paramsResultError = paramsConfigBlur();
setFormErrors(resultErrors);
if (taskType === "BATCH" && batchBuildType === "OPERATOR") {
handleCheck();
}
if (Object.getOwnPropertyNames(resultErrors)?.length || !checkStatus)
if (
Object.getOwnPropertyNames(resultErrors)?.length ||
checkStatus ||
paramsResultError
)
return;
console.log(code, "111");
let newParameters = [];
try {
newParameters = JSON.parse(code);
......@@ -181,8 +241,6 @@ const AddOperator = observer((props: IAddOperator) => {
console.log(err);
}
console.log(operatorList, "operatorList");
const params = {
...formData,
...(batchBuildType === "ENVIRONMENT" && taskType === "BATCH"
......@@ -200,6 +258,7 @@ const AddOperator = observer((props: IAddOperator) => {
delete params.envId;
}
console.log(params, "params");
saveOperator(params).then((res: any) => {
if (res?.message === "success") {
Message.success("构建成功");
......@@ -214,9 +273,9 @@ const AddOperator = observer((props: IAddOperator) => {
code,
command,
formData,
formErrors.parameters,
handleCheck,
operatorList,
paramsConfigBlur,
taskType,
]);
......@@ -224,6 +283,7 @@ const AddOperator = observer((props: IAddOperator) => {
<div className={style.addOperatorBox}>
<div className={style.left}>
<SwitchBatchFolw
type={pageType !== "add" ? "edit" : undefined}
bottomImg={flowOperator}
topImg={batchOperator}
active={taskType}
......@@ -238,7 +298,7 @@ const AddOperator = observer((props: IAddOperator) => {
<div className={style.title}>
{taskType === "BATCH" ? "批式算子信息" : "流式算子信息"}
</div>
{taskType === "BATCH" ? (
{taskType === "BATCH" && pageType !== "edit" ? (
<div
style={{
paddingBottom: batchBuildType === "ENVIRONMENT" ? "20px" : "2px",
......@@ -311,7 +371,6 @@ const AddOperator = observer((props: IAddOperator) => {
<MySelect
fullWidth
options={productListStore?.productList || []}
defaultValue={defaultProduct}
value={formData?.productId}
onChange={(e) => {
changeFormData({ productId: e });
......@@ -353,6 +412,20 @@ const AddOperator = observer((props: IAddOperator) => {
changeFormData({ description: e.target.value });
}}
/>
<span
style={{
position: "absolute",
fontSize: "14px",
bottom: "7px",
right: "12px",
color:
Number(formData?.description?.length) >= 300
? "#d32f2f"
: "#C2C6CC",
}}
>
{formData?.description?.length}/300
</span>
</FormItemBox>
) : null}
</div>
......@@ -378,14 +451,17 @@ const AddOperator = observer((props: IAddOperator) => {
id="paramsConfig"
value={code}
// placeholder="dd"
onChange={(e: string, viewUpdate: any) => {
onChange={(e: string) => {
setCode(e);
}}
onBlur={paramsConfigBlur}
height="535px"
height={parametersError ? "480px" : "512px"}
width="600"
style={{ flex: 1 }}
/>
{parametersError ? (
<p className={style.codeErrorBox}>{parametersError}</p>
) : null}
</div>
</div>
) : (
......@@ -433,7 +509,7 @@ const AddOperator = observer((props: IAddOperator) => {
operatorList={operatorList}
setOperatorList={setOperatorList}
setInputActive={setInputActive}
productId={formData.productId || defaultProduct || ""}
productId={formData.productId || ""}
/>
<BatchOperatorFlow
tasks={operatorList}
......
......@@ -51,8 +51,9 @@
display: inline-block;
width: 24px;
height: 24px;
text-align: center;
line-height: 24px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
......
......@@ -2,7 +2,7 @@
* @Author: 吴永生 15770852798@163.com
* @Date: 2022-10-17 14:35:11
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-24 20:38:16
* @LastEditTime: 2022-10-25 15:12:47
* @FilePath: /bkunyun/src/views/ResourceCenter/UserResources/WorkflowOperator/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -14,6 +14,7 @@ import { useStores } from "@/store";
import { useMemo } from "react";
import MyMenu from "@/components/mui/MyMenu";
import { useNavigate } from "react-router-dom";
import expandOperationSvg from "@/assets/project/expandOperationSvg.svg";
interface IProps {
operatorInfo: IOperatorInfo;
......@@ -70,7 +71,13 @@ const OperatorCard = observer((props: IProps) => {
zIndex: 1601,
}}
>
<span className={styles.operationBox}>大大</span>
<span className={styles.operationBox}>
<img
style={{ width: 16, height: 16 }}
src={expandOperationSvg}
alt=""
/>
</span>
</MyMenu>
</div>
<div className={styles.itemContentBox}>
......
......@@ -2,7 +2,7 @@
* @Author: 吴永生 15770852798@163.com
* @Date: 2022-10-18 09:32:40
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-24 14:57:06
* @LastEditTime: 2022-10-25 14:48:51
* @FilePath: /bkunyun/src/views/ResourceCenter/components/SwitchBatchFolw/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -17,12 +17,13 @@ type ISwitchBatchFolwProps = {
topImg?: string;
bottomImg?: string;
active: "BATCH" | "FLOW";
type?: "edit";
setActive: any;
goBack: any;
};
const SwitchBatchFolw = (props: ISwitchBatchFolwProps) => {
const { active, setActive, goBack, topImg, bottomImg } = props;
const { active, setActive, goBack, topImg, bottomImg, type } = props;
return (
<div className={style.switchBatchFolw}>
<div className={style.goBackBox}>
......@@ -35,40 +36,45 @@ const SwitchBatchFolw = (props: ISwitchBatchFolwProps) => {
<span className={style.goBackText}>返回</span>
</div>
<div className={style.switchBox}>
<div
className={classNames({
[style.switchItem]: true,
[style.activeSwitchItem]: active === "BATCH",
})}
>
<img
onClick={() => setActive("BATCH")}
{/* type为edit 只显示一个 */}
{type === "edit" && active !== "BATCH" ? null : (
<div
className={classNames({
[style.itemImg]: true,
[style.activeImg]: active === "BATCH",
[style.switchItem]: true,
[style.activeSwitchItem]: active === "BATCH",
})}
src={topImg || batchImg}
alt=""
/>
{active === "BATCH" && <div className={style.arrow}></div>}
</div>
<div
className={classNames({
[style.switchItem]: true,
[style.activeSwitchItem]: active === "FLOW",
})}
>
<img
onClick={() => setActive("FLOW")}
>
<img
onClick={() => setActive("BATCH")}
className={classNames({
[style.itemImg]: true,
[style.activeImg]: active === "BATCH",
})}
src={topImg || batchImg}
alt=""
/>
{active === "BATCH" && <div className={style.arrow}></div>}
</div>
)}
{type === "edit" && active !== "FLOW" ? null : (
<div
className={classNames({
[style.itemImg]: true,
[style.activeImg]: active === "FLOW",
[style.switchItem]: true,
[style.activeSwitchItem]: active === "FLOW",
})}
src={bottomImg || flowImg}
alt=""
/>
{active === "FLOW" && <div className={style.arrow}></div>}
</div>
>
<img
onClick={() => setActive("FLOW")}
className={classNames({
[style.itemImg]: true,
[style.activeImg]: active === "FLOW",
})}
src={bottomImg || flowImg}
alt=""
/>
{active === "FLOW" && <div className={style.arrow}></div>}
</div>
)}
</div>
</div>
);
......
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