Commit 74d0c2b4 authored by chenshouchao's avatar chenshouchao

Merge branch 'feat-20221012-environment' into 'staging'

cn-Feat 20221012 environment

See merge request !155
parents e4258ebe ff63dd42
......@@ -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 20:26:42
* @FilePath: /bkunyun/src/api/resourceCenter.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -15,7 +15,8 @@ type addActorenvBuildenvParams = {
baseEnvId: string,
type: "BATCH" | "FLOW",
filePaths: Array<string>,
bashScript: string,
bashScript?: string,
script?: string,
computeType: string,
publicProjectId: string,
}
......@@ -59,6 +60,7 @@ const getActorenvList = (params: {
page: number,
size: number,
title?: string,
order?: string,
}) => {
return request({
url: Api.API_ACTORENV_LIST,
......@@ -114,9 +116,9 @@ const getWorkflowspecList = (params: {productId?: string, title?: string}) => {
// API_WORKFLOWSPEC_LIST
// 新增应用环境
const saveOperator = (params: any) => {
const saveOperator = (params: any, isEdit: boolean) => {
return request({
url: Api.API_SAVE_OPERATOR,
url: `${Api.API_SAVE_OPERATOR}?isEdit=${isEdit}`,
method: "post",
data: params,
});
......@@ -133,6 +135,16 @@ const deleteWorkflowspec = (params: {
});
};
// 查询算子的详情信息
const getOperatorDetail = (id: string) => {
return request({
url:`${Api.API_OPERATOR_DETAILS}/${id}`,
method: "get",
});
};
// 获取工作流模板详情
const getWorkflowspecDetail = (id: string) => {
return request({
......@@ -154,5 +166,6 @@ export {
getWorkflowspecList,
saveOperator,
deleteWorkflowspec,
getWorkflowspecDetail
getWorkflowspecDetail,
getOperatorDetail
};
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 89备份</title>
<g id="新" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="个人资源-工作流算子" transform="translate(-982.000000, -323.000000)">
<g id="编组-6备份" transform="translate(641.000000, 298.000000)">
<g id="编组-89备份" transform="translate(349.000000, 33.000000) rotate(-270.000000) translate(-349.000000, -33.000000) translate(341.000000, 25.000000)">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g id="编组-88" transform="translate(2.250000, 6.750000)" fill="#8A9099">
<circle id="椭圆形" cx="1.25" cy="1.25" r="1.25"></circle>
<circle id="椭圆形备份-15" cx="5.75" cy="1.25" r="1.25"></circle>
<circle id="椭圆形备份-16" cx="10.25" cy="1.25" r="1.25"></circle>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
......@@ -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 21:16:13
* @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) => {
/>
);
};
// const handleEqual = (prvProps: ICodeType, nextProps: ICodeType) => {
// if (isEqual(prvProps, nextProps)) {
// return true;
// }
// return true;
// };
export default Code;
......@@ -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 21:27:26
* @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";
......@@ -56,7 +56,7 @@ export const elements: {
Demo: Demo,
UserResources: UserResources,
SeeEnv: SeeEnv,
OperatorDetails: OperatorDetails,
SeeFloe: OperatorDetails,
ProjectSetting: ProjectSetting,
ProjectData: ProjectData,
ProjectWorkbench: ProjectWorkbench,
......
......@@ -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);
......
......@@ -203,7 +203,7 @@ const SaveOperator = (props: IProps) => {
style={{
position: "absolute",
fontSize: "14px",
bottom: "7px",
top: "96px",
right: "12px",
color: description.length >= 300 ? "#d32f2f" : "#C2C6CC",
}}
......
......@@ -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();
};
......
......@@ -358,7 +358,7 @@ const BaseInfo = observer(() => {
style={{
fontSize: "14px",
position: "absolute",
bottom: "7px",
top: "96px",
right: "12px",
color: projectInfo.desc.length >= 100 ? "#d32f2f" : "#C2C6CC",
}}
......
......@@ -224,7 +224,7 @@ const AddProject = observer((props: IAddProjectProps) => {
style={{
position: "absolute",
fontSize: "14px",
bottom: "7px",
top: "96px",
right: "12px",
color: desc.length >= 300 ? "#d32f2f" : "#C2C6CC",
}}
......
......@@ -31,7 +31,6 @@
.content {
display: flex;
border-radius: 4px;
margin-bottom: 24px;
height: 580px;
}
.form {
......@@ -51,6 +50,22 @@
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.codeBox2 {
flex: 1;
display: flex;
flex-direction: column;
border-radius: 4px;
margin-top: 20px;
}
.codeBox2 .codeTitle {
border-top-right-radius: 4px;
border-top-left-radius: 4px;
}
.codeBox2 .code {
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
overflow: hidden;
}
.codeTitle {
background-color: rgba(230, 233, 237, 1);
padding: 11px 20px;
......@@ -143,3 +158,6 @@
line-height: 20px;
margin-top: 12px;
}
.button {
margin-top: 24px;
}
......@@ -48,6 +48,7 @@ const AddEnvironment = (props: IAddEnvironmentProps) => {
const [envList, setEnvList] = useState<Array<any>>([]); // 基础环境列表 和taskType环境类型有关
const [progress, setProgress] = useState("0%"); // 上传压缩包进度
const [code, setCode] = useState(""); // 脚本内容
const [flowCode, setFlowCode] = useState(""); // 脚本内容
const [codeWidth, setCodeWidth] = useState(0);
const [upload, setUpload] = useState<any>(() => {}); // 上传压缩包实例 用于暂停(取消上传)upload.abort(true);
const [nameHelper, setNameHelper] = useState({
......@@ -270,25 +271,49 @@ const AddEnvironment = (props: IAddEnvironmentProps) => {
};
const handleSubmit = () => {
if (
!checkName(name) &&
!checkDesc(desc) &&
!checkFile(filePaths) &&
baseEnvId &&
code
) {
addActorenvBuildenvFn({
title: name,
desc,
baseEnvId,
type: taskType,
filePaths,
bashScript: Base64.encode(code),
publicProjectId,
computeType,
});
if (taskType === "BATCH") {
if (
!checkName(name) &&
!checkDesc(desc) &&
!checkFile(filePaths) &&
baseEnvId &&
code
) {
addActorenvBuildenvFn({
title: name,
desc,
baseEnvId,
type: taskType,
filePaths,
bashScript: Base64.encode(code),
publicProjectId,
computeType,
});
} else {
Message.error("请完善环境信息");
}
} else {
Message.error("请完善环境信息");
if (
!checkName(name) &&
!checkDesc(desc) &&
!checkFile(filePaths) &&
baseEnvId &&
flowCode
) {
addActorenvBuildenvFn({
title: name,
desc,
baseEnvId,
type: taskType,
filePaths,
bashScript: Base64.encode(code),
script: Base64.encode(flowCode),
publicProjectId,
computeType,
});
} else {
Message.error("请完善环境信息");
}
}
};
......@@ -358,7 +383,7 @@ const AddEnvironment = (props: IAddEnvironmentProps) => {
style={{
position: "absolute",
fontSize: "14px",
bottom: "7px",
top: "96px",
right: "12px",
color: desc.length >= 300 ? "#d32f2f" : "#C2C6CC",
}}
......@@ -462,7 +487,10 @@ const AddEnvironment = (props: IAddEnvironmentProps) => {
</div>
<div className={style.codeBox}>
<div className={style.codeTitle}>
{taskType === "BATCH" ? "Shell脚本" : "Python脚本"}
Shell脚本
{taskType === "BATCH" && (
<span className={style.required}>*</span>
)}
</div>
<div className={style.code} id="addEnvironmentCode">
<Code
......@@ -474,6 +502,22 @@ const AddEnvironment = (props: IAddEnvironmentProps) => {
</div>
</div>
</div>
{taskType === "FLOW" && (
<div className={style.codeBox2}>
<div className={style.codeTitle}>
Python脚本
<span className={style.required}>*</span>
</div>
<div className={style.code} id="addEnvironmentCode">
<Code
value={flowCode}
onChange={(e: string) => setFlowCode(e)}
height="535px"
width={`${codeWidth + 368}px`}
/>
</div>
</div>
)}
<div className={style.button}>
<MyButton
text="开始构建"
......
......@@ -144,7 +144,11 @@ const SeeEnv = () => {
className={style.goBackIcon}
src={goback}
alt=""
onClick={() => navigate("/utility/resourceCenter/userResources")}
onClick={() =>
navigate("/utility/resourceCenter/userResources", {
state: { defaultTab: "USERRESOURCES_ENVIRONMENT" },
})
}
/>
<div className={style.title}>{info.title}</div>
<div className={style.type}>
......
......@@ -5,7 +5,7 @@ import style from "./index.module.css";
import SearchInput from "@/components/BusinessComponents/SearchInput";
import MySelect from "@/components/mui/MySelect";
import MyButton from "@/components/mui/MyButton";
import MyTable from "@/components/mui/MyTableNew";
import MyTable, { sortState } from "@/components/mui/MyTableNew";
import useMyRequest from "@/hooks/useMyRequest";
import { getActorenvList } from "@/api/resourceCenter";
import Add from "@mui/icons-material/Add";
......@@ -28,6 +28,10 @@ const UserResourcesEnvironment = () => {
const [id, setId] = useState("");
const [deleteOpen, setDeleteOpen] = useState(false);
const [totalElements, setTotalElements] = useState(0);
const [sortState, setSortState] = useState<sortState>({
field: "createdTime",
order: "DESC",
});
const headCells: Array<any> = [
{
id: "title",
......@@ -42,6 +46,7 @@ const UserResourcesEnvironment = () => {
id: "createdTime",
label: "创建时间",
width: 180,
sort: true,
},
{
id: "status",
......@@ -73,9 +78,10 @@ const UserResourcesEnvironment = () => {
size,
title,
type: type === "ALL" ? "" : type,
order: sortState.order || "DESC",
});
}
}, [getList, page, size, title, type, addOpen, deleteOpen]);
}, [getList, page, size, title, type, addOpen, deleteOpen, sortState]);
const renderType = (item: any) => {
if (item.type === "BATCH") {
......@@ -256,6 +262,8 @@ const UserResourcesEnvironment = () => {
paginationType="complex"
totalElements={totalElements}
loading={loading}
sortState={sortState}
setSortState={setSortState}
></MyTable>
</div>
{addOpen && <AddEnvironment setAddopen={setAddopen}></AddEnvironment>}
......
......@@ -16,6 +16,7 @@ import WorkFlowEdit from "@/views/WorkFlowEdit";
import { useMessage } from "@/components/MySnackbar";
import TemplateDetail from "./TemplateDetail";
import style from "./index.module.css";
import NoData from "@/components/BusinessComponents/NoData";
const UserResourcesTemplate = observer(() => {
const [title, setTitle] = useState("");
......@@ -162,6 +163,7 @@ const UserResourcesTemplate = observer(() => {
</div>
</div>
<div className={style.tableBox}>
{list.length === 0 && <NoData text="暂无相关模板"></NoData>}
<CardTable
data={list}
renderItem={renderItem}
......
......@@ -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-20 17:36:14
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-24 15:52:56
* @LastEditTime: 2022-10-26 13:56:10
* @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
*/
......@@ -12,11 +12,36 @@ import { IOperatorAddFormData } from "../../interface";
type IBuildType = "ENVIRONMENT" | "OPERATOR";
export const checkFormData = (formData: IOperatorAddFormData, taskType: IBuildType)=>{
// 校验新版本号是否大于旧版本号
const checkNewOldVersion = (version: string, oldVersion: string): string => {
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]) {
return "新版本号必须大于老版本号且大于等于1.0.0"
} else if (versionArr[0] === oldVersionArr[0]) {
if (versionArr[1] < oldVersionArr[1]) {
return "新版本号必须大于老版本号且大于等于1.0.0"
} else if (versionArr[1] === oldVersionArr[1]) {
if (versionArr[2] <= oldVersionArr[2]) {
return "新版本号必须大于老版本号且大于等于1.0.0"
}
}
}
return '';
}
export const checkFormData = (formData: IOperatorAddFormData, taskType: IBuildType, oldVersion: string)=>{
const reg = new RegExp("^[A-Za-z0-9\u4e00-\u9fa5]{1,15}$");
const result:IOperatorAddFormData = {}
const versionErr = checkNewOldVersion(formData?.version || '', oldVersion )
if(!formData?.title){
result.title = '请输入算子名称'
}
......@@ -26,6 +51,10 @@ export const checkFormData = (formData: IOperatorAddFormData, taskType: IBuildTy
if(!/^[1-9]\d?(\.(0|[1-9]\d?)){2}$/.test(formData?.version || '')){
result.version = '格式不正确,必须为X.Y.Z格式,且XYZ必须为0~99的正整数'
}
if(versionErr) {
result.version = versionErr
}
if(!formData?.version){
result.version = '请输入算子版本'
}
......@@ -39,6 +68,26 @@ export const checkFormData = (formData: IOperatorAddFormData, taskType: IBuildTy
return result
}
/** 编辑算子版本默认加0.0.1 */
export const editDefaultVersion = (version: string)=>{
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);
}
}
}
return arr.join(".")
}
/** 参数配置校验 */
export const checkParamsConfig = (val: string) => {
let result: any = []
......@@ -56,7 +105,7 @@ export const checkParamsConfig = (val: string) => {
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 )){
if( !['STRING','FILE','DATASET','INT','FLOAT','DOUBLE','BOOLEAN','ARRAY_STRING','ARRAY_FILE','ARRAY_DATASET','ARRAY_INT','ARRAY_FLOAT','ARRAY_DOUBLE','ARRAY_BOOLEAN','TEXT','JSON'].includes(item?.classType )){
result.push(`classType: ${item?.classType}`)
}
if(!['true','false'].includes(String(item?.required)) ) {
......
......@@ -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 21:32:49
* @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;
......@@ -45,9 +46,9 @@ const OperatorCard = observer((props: IProps) => {
}
};
const handleToSeeOperator = (item: any) => {
const handleToSeeOperator = () => {
navigate("/utility/resourceCenter/userResources/seeFloe", {
state: { id: item.id },
state: { id },
});
};
......@@ -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,9 +2,38 @@
padding: 0 24px;
}
.titleBox {
.baseInfoBox {
font-size: 16px;
color: #1e2633;
line-height: 24px;
padding: 20px 0;
}
.titleBox {
padding: 14px 24px;
display: flex;
justify-content: flex-start;
align-items: center;
border-bottom: 1px solid rgba(235, 237, 240, 1);
}
.goBackIcon {
width: 22px;
height: 22px;
cursor: pointer;
}
.title {
margin-left: 2px;
font-size: 18px;
line-height: 26px;
color: rgba(30, 38, 51, 1);
font-weight: 550;
margin-right: 16px;
}
.type {
background-color: rgba(235, 237, 240, 1);
font-size: 12px;
line-height: 20px;
padding: 1px 9px;
color: #565c66;
border-radius: 2px;
}
......@@ -2,17 +2,25 @@
* @Author: 吴永生 15770852798@163.com
* @Date: 2022-10-17 14:35:11
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-19 10:30:55
* @LastEditTime: 2022-10-26 09:27:56
* @FilePath: /bkunyun/src/views/ResourceCenter/UserResources/WorkflowOperator/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import styles from "./index.module.css";
import { observer } from "mobx-react-lite";
import { useEffect, useMemo, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import BasicInfo from "../../../../components/BasinInfo";
import { useMemo, useState } from "react";
import RadioGroupOfButtonStyle from "@/components/CommonComponents/RadioGroupOfButtonStyle";
import useMyRequest from "@/hooks/useMyRequest";
import { getOperatorDetail } from "@/api/resourceCenter";
import { useStores } from "@/store";
import goback from "@/assets/project/goback.svg";
const OperatorDetails = () => {
import styles from "./index.module.css";
const OperatorDetails = observer(() => {
const contentTypeList = useMemo(() => {
return [
{ value: "flowChart", label: "流程图" },
......@@ -21,31 +29,85 @@ const OperatorDetails = () => {
];
}, []);
/** 产品store */
const { productListStore } = useStores();
const navigate = useNavigate();
/** 详情类型 */
const [contentType, setContentType] = useState<string>("flowChart");
/** 详情数据 */
const [detailInfo, setDetailInfo] = useState<any>({});
/** 获取算子详情 */
const { run: fetchOperatorDetail } = useMyRequest(getOperatorDetail, {
onSuccess: (res: any) => {
if (res.message === "success") {
/** 设置详情信息 */
setDetailInfo(res.data);
}
},
});
const location = useLocation();
const locationInfo: any = location?.state;
const {
title = "",
version = "",
productId = "",
createdTime = "",
creator = "",
description = "",
type,
} = detailInfo;
/** 切换类型 */
const handleRadio = (val: string) => {
setContentType(val);
};
const productText = useMemo(() => {
const result = productListStore.productList?.filter((item) => {
return item.value === productId;
});
return result?.length ? result[0].label : "";
}, [productListStore.productList, productId]);
useEffect(() => {
fetchOperatorDetail(locationInfo.id);
}, [fetchOperatorDetail, locationInfo.id]);
return (
<div className={styles.detailsBox}>
<h2 className={styles.titleBox}>基础信息</h2>
<div className={styles.titleBox}>
<img
className={styles.goBackIcon}
src={goback}
alt=""
onClick={() =>
navigate("/utility/resourceCenter/userResources", {
state: { defaultTab: "USERRESOURCES_FLOE" },
})
}
/>
<div className={styles.title}>{title}</div>
<div className={styles.type}>
{type === "BATCH" ? "批算子" : "流算子"}
</div>
</div>
<h2 className={styles.baseInfoBox}>基础信息</h2>
<div style={{ border: "1px solid #EBEDF0" }}>
<BasicInfo
infoList={[
{ label: "33333331", value: "1" },
{ label: "所属产品", value: productText },
{
label: "1",
value: "42543253245325325432452345235432452323542352354235235321",
label: "创建时间",
value: createdTime,
},
{ label: "1", value: "1" },
{ label: "1", value: "1" },
{ label: "1", value: "1" },
{ label: "创建人", value: creator },
{ label: "算子版本", value: version },
{ label: "应用环境", value: "1" },
]}
/>
<BasicInfo infoList={[{ label: "2", value: "2" }]} />
<BasicInfo infoList={[{ label: "描述", value: description }]} />
</div>
<div style={{ padding: "26px 0 16px 0" }}>
<RadioGroupOfButtonStyle
......@@ -58,6 +120,6 @@ const OperatorDetails = () => {
<div>11</div>
</div>
);
};
});
export default OperatorDetails;
......@@ -2,7 +2,7 @@
* @Author: 吴永生 15770852798@163.com
* @Date: 2022-10-17 14:35:11
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-10-24 20:40:16
* @LastEditTime: 2022-10-26 14:05:04
* @FilePath: /bkunyun/src/views/ResourceCenter/UserResources/WorkflowOperator/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -12,6 +12,7 @@ import { observer } from "mobx-react";
import _ from "lodash";
import Add from "@mui/icons-material/Add";
import noFile from "@/assets/project/noFile.svg";
import SearchInput from "@/components/BusinessComponents/SearchInput";
import MySelect from "@/components/mui/MySelect";
import MyButton from "@/components/mui/MyButton";
......@@ -23,6 +24,7 @@ import useMyRequest from "@/hooks/useMyRequest";
import { IOperatorInfo } from "./interface";
import styles from "./index.module.css";
import MyCircularProgress from "@/components/mui/MyCircularProgress";
const WorkflowOperator = observer(() => {
const [pageType, setPageType] = useState<string>("");
......@@ -39,7 +41,7 @@ const WorkflowOperator = observer(() => {
const [list, setList] = useState<IOperatorInfo[]>();
const { run: getList } = useMyRequest(getOperatorList, {
const { run: getList, loading } = useMyRequest(getOperatorList, {
// refreshDeps: [],
onSuccess: (res) => {
console.log(res);
......@@ -71,78 +73,109 @@ const WorkflowOperator = observer(() => {
return (
<>
<div className={styles.indexBox}>
<div className={styles.headerBox}>
<div>
<SearchInput
sx={{ width: 340, marginRight: "16px" }}
placeholder="输入关键词搜索"
value={searchParams.keyword}
onKeyUp={handleKeyWordChangeKeyUp}
onChange={(e) => {
setSearchParams({ ...searchParams, keyword: e.target.value });
}}
/>
<MySelect
title="所属产品"
isTitle={true}
options={
[
<MyCircularProgress loading={loading}>
<div className={styles.indexBox}>
<div className={styles.headerBox}>
<div>
<SearchInput
sx={{ width: 340, marginRight: "16px" }}
placeholder="输入关键词搜索"
value={searchParams.keyword}
onKeyUp={handleKeyWordChangeKeyUp}
onChange={(e) => {
setSearchParams({ ...searchParams, keyword: e.target.value });
}}
/>
<MySelect
title="所属产品"
isTitle={true}
options={
[
{ label: "全部", value: "all" },
...productListStore?.productList,
] || []
}
value={searchParams.productId}
onChange={(e) => {
setSearchParams({ ...searchParams, productId: e });
}}
className={styles.searchSelectBox}
sx={{ width: "150px", height: "32px" }}
/>
<MySelect
title="环境类型"
isTitle={true}
value={searchParams.type}
onChange={(e) => {
setSearchParams({ ...searchParams, type: e });
}}
options={[
{ label: "全部", value: "all" },
...productListStore?.productList,
] || []
}
value={searchParams.productId}
onChange={(e) => {
setSearchParams({ ...searchParams, productId: e });
}}
className={styles.searchSelectBox}
sx={{ width: "150px", height: "32px" }}
/>
<MySelect
title="环境类型"
isTitle={true}
value={searchParams.type}
onChange={(e) => {
setSearchParams({ ...searchParams, type: e });
{
label: "批式",
value: "BATCH",
},
{
label: "流式",
value: "FLOW",
},
]}
sx={{ width: "150px", height: "32px" }}
/>
</div>
<MyButton
text="构建算子"
startIcon={<Add />}
onClick={() => {
setPageType("add");
setDetailsId("");
}}
options={[
{ label: "全部", value: "all" },
{
label: "批式",
value: "BATCH",
},
{
label: "流式",
value: "FLOW",
},
]}
sx={{ width: "150px", height: "32px" }}
/>
></MyButton>
</div>
<MyButton
text="构建算子"
startIcon={<Add />}
onClick={() => {
setPageType("add");
setDetailsId("");
}}
></MyButton>
</div>
<div className={styles.contentBox}>
{list?.map((item) => {
return (
<OperatorCard
setDetailsId={setDetailsId}
operatorInfo={item}
setPageType={setPageType}
{list?.length ? (
<div className={styles.contentBox}>
{list?.map((item) => {
return (
<OperatorCard
setDetailsId={setDetailsId}
operatorInfo={item}
setPageType={setPageType}
/>
);
})}
</div>
) : (
<div style={{ position: "relative" }}>
<img
src={noFile}
alt=""
style={{
position: "absolute",
top: "100px",
left: "50%",
transform: "translate(-50%, 0)",
}}
/>
);
})}
<span
style={{
position: "absolute",
top: "165px",
left: "50%",
transform: "translate(-50%, 0)",
fontSize: "14px",
lineHeight: "22px",
color: "#8a9099",
}}
>
暂无工作流算子
</span>
</div>
)}
</div>
</div>
</MyCircularProgress>
{pageType && (
<AddOperator
getList={newGetList}
detailsId={detailsId}
setPageType={setPageType}
pageType={pageType}
......
......@@ -2,12 +2,14 @@ import style from "./index.module.css";
import usePass from "@/hooks/usePass";
import UserResourcesTemplate from "./UserResourcesTemplate";
import UserResourcesEnvironment from "./UserResourcesEnvironment";
import { useLocation } from "react-router-dom";
import { useMemo } from "react";
import Tabs from "@/components/mui/MyTabs";
import WorkflowOperator from "./WorkflowOperator";
import OperatorDetails from "./WorkflowOperator/components/OperatorDetails";
const UserResources = () => {
const isPass = usePass();
const location: any = useLocation();
const tabList = useMemo(() => {
return [
{
......@@ -36,7 +38,7 @@ const UserResources = () => {
<Tabs
title="个人资源"
tabList={tabList}
defaultValue={"USERRESOURCES_TEMPLATE"}
defaultValue={location?.state?.defaultTab || "USERRESOURCES_TEMPLATE"}
tabPanelSx={{ padding: "0" }}
/>
{/* <OperatorDetails /> */}
......
......@@ -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>
);
......
......@@ -253,7 +253,7 @@ const SaveCustomTemplate = (props: IProps) => {
style={{
position: "absolute",
fontSize: "14px",
bottom: "7px",
top: "96px",
right: "12px",
color: description.length >= 300 ? "#d32f2f" : "#C2C6CC",
}}
......
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