Commit f69316a2 authored by rocosen's avatar rocosen

Merge branch 'release' into feat-jobList

parents 710fd2a6 3d3954b0
...@@ -1437,17 +1437,48 @@ ...@@ -1437,17 +1437,48 @@
"integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ=="
}, },
"@emotion/react": { "@emotion/react": {
"version": "11.9.0", "version": "11.9.3",
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.9.0.tgz", "resolved": "https://registry.npmmirror.com/@emotion/react/-/react-11.9.3.tgz",
"integrity": "sha512-lBVSF5d0ceKtfKCDQJveNAtkC7ayxpVlgOohLgXqRwqWr9bOf4TZAFFyIcNngnV6xK6X4x2ZeXq7vliHkoVkxQ==", "integrity": "sha512-g9Q1GcTOlzOEjqwuLF/Zd9LC+4FljjPjDfxSM7KmEakm+hsHXk+bYZ2q+/hTJzr0OUNkujo72pXLQvXj6H+GJQ==",
"requires": { "requires": {
"@babel/runtime": "^7.13.10", "@babel/runtime": "^7.13.10",
"@emotion/babel-plugin": "^11.7.1", "@emotion/babel-plugin": "^11.7.1",
"@emotion/cache": "^11.7.1", "@emotion/cache": "^11.9.3",
"@emotion/serialize": "^1.0.3", "@emotion/serialize": "^1.0.4",
"@emotion/utils": "^1.1.0", "@emotion/utils": "^1.1.0",
"@emotion/weak-memoize": "^0.2.5", "@emotion/weak-memoize": "^0.2.5",
"hoist-non-react-statics": "^3.3.1" "hoist-non-react-statics": "^3.3.1"
},
"dependencies": {
"@emotion/cache": {
"version": "11.9.3",
"resolved": "https://registry.npmmirror.com/@emotion/cache/-/cache-11.9.3.tgz",
"integrity": "sha512-0dgkI/JKlCXa+lEXviaMtGBL0ynpx4osh7rjOXE71q9bIF8G+XhJgvi+wDu0B0IdCVx37BffiwXlN9I3UuzFvg==",
"requires": {
"@emotion/memoize": "^0.7.4",
"@emotion/sheet": "^1.1.1",
"@emotion/utils": "^1.0.0",
"@emotion/weak-memoize": "^0.2.5",
"stylis": "4.0.13"
}
},
"@emotion/serialize": {
"version": "1.0.4",
"resolved": "https://registry.npmmirror.com/@emotion/serialize/-/serialize-1.0.4.tgz",
"integrity": "sha512-1JHamSpH8PIfFwAMryO2bNka+y8+KA5yga5Ocf2d7ZEiJjb7xlLW7aknBGZqJLajuLOvJ+72vN+IBSwPlXD1Pg==",
"requires": {
"@emotion/hash": "^0.8.0",
"@emotion/memoize": "^0.7.4",
"@emotion/unitless": "^0.7.5",
"@emotion/utils": "^1.0.0",
"csstype": "^3.0.2"
}
},
"@emotion/sheet": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/@emotion/sheet/-/sheet-1.1.1.tgz",
"integrity": "sha512-J3YPccVRMiTZxYAY0IOq3kd+hUP8idY8Kz6B/Cyo+JuXq52Ek+zbPbSQUrVQp95aJ+lsAW7DPL1P2Z+U1jGkKA=="
}
} }
}, },
"@emotion/serialize": { "@emotion/serialize": {
...@@ -4126,6 +4157,11 @@ ...@@ -4126,6 +4157,11 @@
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz",
"integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==" "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA=="
}, },
"classcat": {
"version": "5.0.3",
"resolved": "https://registry.npmmirror.com/classcat/-/classcat-5.0.3.tgz",
"integrity": "sha512-6dK2ke4VEJZOFx2ZfdDAl5OhEL8lvkl6EHF92IfRePfHxQTqir5NlcNVUv+2idjDqCX2NDc8m8YSAI5NI975ZQ=="
},
"classnames": { "classnames": {
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmmirror.com/classnames/-/classnames-2.3.1.tgz", "resolved": "https://registry.npmmirror.com/classnames/-/classnames-2.3.1.tgz",
...@@ -4679,6 +4715,72 @@ ...@@ -4679,6 +4715,72 @@
"resolved": "https://registry.npmmirror.com/custom-error-instance/-/custom-error-instance-2.1.1.tgz", "resolved": "https://registry.npmmirror.com/custom-error-instance/-/custom-error-instance-2.1.1.tgz",
"integrity": "sha512-p6JFxJc3M4OTD2li2qaHkDCw9SfMw82Ldr6OC9Je1aXiGfhx2W8p3GaoeaGrPJTUN9NirTM/KTxHWMUdR1rsUg==" "integrity": "sha512-p6JFxJc3M4OTD2li2qaHkDCw9SfMw82Ldr6OC9Je1aXiGfhx2W8p3GaoeaGrPJTUN9NirTM/KTxHWMUdR1rsUg=="
}, },
"d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmmirror.com/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="
},
"d3-dispatch": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
"integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="
},
"d3-drag": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/d3-drag/-/d3-drag-3.0.0.tgz",
"integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
"requires": {
"d3-dispatch": "1 - 3",
"d3-selection": "3"
}
},
"d3-ease": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/d3-ease/-/d3-ease-3.0.1.tgz",
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="
},
"d3-interpolate": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
"requires": {
"d3-color": "1 - 3"
}
},
"d3-selection": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="
},
"d3-timer": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/d3-timer/-/d3-timer-3.0.1.tgz",
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="
},
"d3-transition": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/d3-transition/-/d3-transition-3.0.1.tgz",
"integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
"requires": {
"d3-color": "1 - 3",
"d3-dispatch": "1 - 3",
"d3-ease": "1 - 3",
"d3-interpolate": "1 - 3",
"d3-timer": "1 - 3"
}
},
"d3-zoom": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/d3-zoom/-/d3-zoom-3.0.0.tgz",
"integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
"requires": {
"d3-dispatch": "1 - 3",
"d3-drag": "2 - 3",
"d3-interpolate": "1 - 3",
"d3-selection": "2 - 3",
"d3-transition": "2 - 3"
}
},
"damerau-levenshtein": { "damerau-levenshtein": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
...@@ -10242,6 +10344,29 @@ ...@@ -10242,6 +10344,29 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg=="
}, },
"react-flow-renderer": {
"version": "10.3.7",
"resolved": "https://registry.npmmirror.com/react-flow-renderer/-/react-flow-renderer-10.3.7.tgz",
"integrity": "sha512-0WGyozT4SzMpim8MQRFBR8hqm11FGApXm+UD05BoAejhcUgohvmckBTRIQKxzGC2WQLR/6oXRzwzRYGQdrb4rw==",
"requires": {
"@babel/runtime": "^7.18.0",
"classcat": "^5.0.3",
"d3-drag": "^3.0.0",
"d3-selection": "^3.0.0",
"d3-zoom": "^3.0.0",
"zustand": "^3.7.2"
},
"dependencies": {
"@babel/runtime": {
"version": "7.18.3",
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.18.3.tgz",
"integrity": "sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
}
}
},
"react-is": { "react-is": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
...@@ -11478,6 +11603,16 @@ ...@@ -11478,6 +11603,16 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
}, },
"tss-react": {
"version": "3.7.0",
"resolved": "https://registry.npmmirror.com/tss-react/-/tss-react-3.7.0.tgz",
"integrity": "sha512-thvJWR+sr3ZGMcV/Ryo1F5RzjXd1gMTzYV/ckfUEBhu701uTYE3KyL9DNxv827uRFPFSLYG7bKefuc7kmYMB9Q==",
"requires": {
"@emotion/cache": "*",
"@emotion/serialize": "*",
"@emotion/utils": "*"
}
},
"tsutils": { "tsutils": {
"version": "3.21.0", "version": "3.21.0",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
...@@ -11838,7 +11973,7 @@ ...@@ -11838,7 +11973,7 @@
}, },
"webpack-dev-server": { "webpack-dev-server": {
"version": "4.9.0", "version": "4.9.0",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.0.tgz", "resolved": "https://registry.npmmirror.com/webpack-dev-server/-/webpack-dev-server-4.9.0.tgz",
"integrity": "sha512-+Nlb39iQSOSsFv0lWUuUTim3jDQO8nhK3E68f//J2r5rIcp4lULHXz2oZ0UVdEeWXEh5lSzYUlzarZhDAeAVQw==", "integrity": "sha512-+Nlb39iQSOSsFv0lWUuUTim3jDQO8nhK3E68f//J2r5rIcp4lULHXz2oZ0UVdEeWXEh5lSzYUlzarZhDAeAVQw==",
"requires": { "requires": {
"@types/bonjour": "^3.5.9", "@types/bonjour": "^3.5.9",
...@@ -12398,6 +12533,11 @@ ...@@ -12398,6 +12533,11 @@
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
},
"zustand": {
"version": "3.7.2",
"resolved": "https://registry.npmmirror.com/zustand/-/zustand-3.7.2.tgz",
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA=="
} }
} }
} }
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
"react-dev-utils": "^12.0.1", "react-dev-utils": "^12.0.1",
"react-dom": "^18.1.0", "react-dom": "^18.1.0",
"react-dropzone": "^14.2.1", "react-dropzone": "^14.2.1",
"react-flow-renderer": "^10.3.7",
"react-refresh": "^0.11.0", "react-refresh": "^0.11.0",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.3.0",
"resolve": "^1.20.0", "resolve": "^1.20.0",
......
...@@ -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: 吴永生#A02208 yongsheng.wu@wholion.com * @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-13 09:59:29 * @LastEditTime: 2022-07-07 18:19:20
* @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
*/ */
...@@ -29,17 +29,14 @@ const RESTAPI = { ...@@ -29,17 +29,14 @@ const RESTAPI = {
API_WORKBENCH_DELETE_TEMPLATE: `${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/product/workflowspec`, //项目管理员-添加工作流模板-模板列表 API_WORKBENCH_ADD_TEMPLATE_LIST: `${BACKEND_API_URI_PREFIX}/cpp/workbench/product/workflowspec`, //项目管理员-添加工作流模板-模板列表
API_WORKBENCH_ADD_TEMPLATE: `${BACKEND_API_URI_PREFIX}/cpp/workbench/project/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`, //点击任务列表查看任务详情
API_WORKBENCH_WORKFLOWJOB_LIST: `${BACKEND_API_URI_PREFIX}/cpp/workbench/project/workflowjob`, //查询工作流任务 API_WORKBENCH_WORKFLOWJOB_LIST: `${BACKEND_API_URI_PREFIX}/cpp/workbench/project/workflowjob`, //查询工作流任务
API_WORKBENCH_DEL_WORKFLOWJOB: `${BACKEND_API_URI_PREFIX}/cpp/workflow/job/`, //删除工作流任务 API_WORKBENCH_DEL_WORKFLOWJOB: `${BACKEND_API_URI_PREFIX}/cpp/workflow/job/`, //删除工作流任务
API_WORKBENCH_CANCEL_WORKFLOWJOB: `${BACKEND_API_URI_PREFIX}/cpp/workflow/cancel`, //取消工作流 API_WORKBENCH_CANCEL_WORKFLOWJOB: `${BACKEND_API_URI_PREFIX}/cpp/workflow/cancel`, //取消工作流
API_SUBMIT_WORKFLOW: `${BACKEND_API_URI_PREFIX}/cpp/workflow/submit`, //提交工作流
API_WORKBENCH_WORKFLOW_TASKINFO: `${BACKEND_API_URI_PREFIX}/cpp/workbench/workflowjob/task-info`, //查询任务某个算子详情
API_OPERATOR_LIST:`${BACKEND_API_URI_PREFIX}/cpp/workflow/actorspecs`, // 获取算子列表
}; };
export default RESTAPI; export default RESTAPI;
...@@ -176,7 +176,7 @@ export function useHttp(raw?: boolean) { ...@@ -176,7 +176,7 @@ export function useHttp(raw?: boolean) {
export default rawHttp; export default rawHttp;
export interface IResponse<T> { export interface IResponse<T> {
errorCode: number; errorCode?: number;
massage: string; massage?: string;
data: T; data: T;
} }
...@@ -21,7 +21,7 @@ type projectListParams = { ...@@ -21,7 +21,7 @@ type projectListParams = {
}; };
// 查询当前用户可以看到的项目列表 // 查询当前用户可以看到的项目列表
const product = (params: projectListParams) => { const getProjectList = (params: projectListParams) => {
return request({ return request({
url: Api.API_PROJECT_LIST, url: Api.API_PROJECT_LIST,
method: "get", method: "get",
...@@ -202,10 +202,51 @@ const getDataFileDelPackage = (params: getDataFileDelPackageParams) => { ...@@ -202,10 +202,51 @@ const getDataFileDelPackage = (params: getDataFileDelPackageParams) => {
}); });
}; };
// 点击使用模版,获取模版数据
const fetchTemplateConfigInfo = (params: { id: string }) => {
return request({
url: `${Api.API_FETCH_TEMPLATE_INFO}/${params.id}`,
method: "get",
});
};
// 点击工作列表,查看工作流详情
const fetchWorkFlowJob = (params: { id: string }) => {
return request({
url: `${Api.API_WORK_FLOW_JOB}/${params.id}`,
method: "get",
});
};
type submitWorkFlowParams = {
name: string;
projectId: string;
specId: string;
outputPath: string;
promotedParameters: any;
};
// 提交工作流
const submitWorkFlow = (params: submitWorkFlowParams) => {
return request({
url: Api.API_SUBMIT_WORKFLOW,
method: "post",
data: params,
});
};
// 查询任务某个算子详情
const getworkFlowTaskInfo = (params: { jobId: string; taskId: string }) => {
return request({
url: `${Api.API_WORKBENCH_WORKFLOW_TASKINFO}?jobId=${params.jobId}&taskId=${params.taskId}`,
method: "get",
});
};
export { export {
current, current,
menu, menu,
product, getProjectList,
hpczone, hpczone,
addProject, addProject,
getProject, getProject,
...@@ -218,4 +259,8 @@ export { ...@@ -218,4 +259,8 @@ export {
getDataFileMovePackage, getDataFileMovePackage,
getDataFileDel, getDataFileDel,
getDataFileDelPackage, getDataFileDelPackage,
fetchTemplateConfigInfo,
fetchWorkFlowJob,
submitWorkFlow,
getworkFlowTaskInfo,
}; };
export interface IGetOperatorList {
owner: string;
productId: string;
keyword?: string
}
\ No newline at end of file
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-07-05 14:00:37
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-07 18:24:16
* @FilePath: /bkunyun/src/api/workbench_api.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import request from "@/utils/axios/service"; import request from "@/utils/axios/service";
import Api from "./api_manager"; import Api from "./api_manager";
import { IGetOperatorList } from "./workbenchInterface";
function current() { function current() {
return request({ return request({
...@@ -119,6 +128,15 @@ const cancelWorkflowJob = (params: workflowJobCancelParams) => { ...@@ -119,6 +128,15 @@ const cancelWorkflowJob = (params: workflowJobCancelParams) => {
}); });
}; };
// 获取算子列表数据
const fetchOperatorList = (params: IGetOperatorList) => {
return request({
url: Api.API_OPERATOR_LIST,
method: "get",
params,
});
};
export { export {
current, current,
menu, menu,
...@@ -128,5 +146,6 @@ export { ...@@ -128,5 +146,6 @@ export {
addWorkbenchTemplate, addWorkbenchTemplate,
getWorkflowJobList, getWorkflowJobList,
deleteWorkflowJob, deleteWorkflowJob,
cancelWorkflowJob cancelWorkflowJob,
fetchOperatorList
}; };
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 6备份 5</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-25">
<rect id="矩形" x="0" y="0" width="20" height="20"></rect>
<g id="编组-32" transform="translate(0.533333, 3.452381)">
<path d="M8.36688938,0.416666667 L9.55313606,1.36249983 C9.81887602,1.6286558 10.1795465,1.77821568 10.5556538,1.77821568 L10.5556538,1.77821568 L14.8884238,1.77821568 L15.4717571,5.1407542 L8.77799689,5.3817735 L2.18238271,5.25717634 L2.18238271,1 L8.36688938,0.416666667 Z" id="路径-7" stroke="#8A9099" stroke-width="0.833333333" fill="#EBEDF0"></path>
<path d="M1.19361766,4.3897647 L17.7662846,4.3897647 C18.3185693,4.3897647 18.7662846,4.83747995 18.7662846,5.3897647 C18.7662846,5.43928252 18.7626065,5.48873196 18.7552809,5.53770491 L17.7437151,12.3001318 C17.6704625,12.7898332 17.2498687,13.1521916 16.7547187,13.1521916 L2.39674962,13.1521916 C1.91203684,13.1521916 1.49711429,12.804574 1.41221027,12.3273551 L0.209078316,5.56492826 C0.112338155,5.02118219 0.474708039,4.50196551 1.01845411,4.40522535 C1.07627469,4.39493825 1.1348891,4.3897647 1.19361766,4.3897647 Z" id="矩形" fill="#8A9099"></path>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>1.Base基础/Icon图标/全屏</title>
<defs>
<rect id="path-1" x="0" y="0" width="16" height="16"></rect>
<filter color-interpolation-filters="auto" id="filter-3">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0.337255 0 0 0 0 0.362353 0 0 0 0 0.400000 0 0 0 1.000000 0"></feColorMatrix>
</filter>
</defs>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="工作台(使用模版)" transform="translate(-1393.000000, -1979.000000)">
<g id="编组备份-2" transform="translate(1384.000000, 1970.000000)">
<g id="1.Base基础/Icon图标/全屏" transform="translate(8.000000, 8.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<g id="蒙版"></g>
<g filter="url(#filter-3)" id="编组">
<g mask="url(#mask-2)">
<g transform="translate(-1.000000, -1.000000)">
<g id="编组-63" transform="translate(12.706359, 5.236359) rotate(-315.000000) translate(-12.706359, -5.236359) translate(9.176029, 1.361359)">
<path d="M3.97654174,0.147051761 L4.06066017,0.219669914 L7.06066017,3.21966991 L6,4.28033009 L4.28,2.561 L4.28033009,7.75 L2.78033009,7.75 L2.78,2.561 L1.06066017,4.28033009 L6.61983662e-13,3.21966991 L3,0.219669914 C3.26626656,-0.0465966484 3.68293025,-0.0708026996 3.97654174,0.147051761 Z" id="形状结合" fill="#565C66" fill-rule="nonzero"></path>
</g>
<g id="编组-63备份" transform="translate(5.236359, 12.706359) scale(-1, -1) rotate(-315.000000) translate(-5.236359, -12.706359) translate(1.706029, 8.831359)">
<path d="M3.97654174,0.147051761 L4.06066017,0.219669914 L7.06066017,3.21966991 L6,4.28033009 L4.28,2.561 L4.28033009,7.75 L2.78033009,7.75 L2.78,2.561 L1.06066017,4.28033009 L2.55455517e-12,3.21966991 L3,0.219669914 C3.26626656,-0.0465966484 3.68293025,-0.0708026996 3.97654174,0.147051761 Z" id="形状结合" fill="#565C66" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?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>information-outline</title>
<g id="云平台视觉规范" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Feedback-反馈" transform="translate(-375.000000, -1027.000000)" fill="#1370FF" fill-rule="nonzero">
<g id="编组-17" transform="translate(355.000000, 1007.000000)">
<g id="information-outline" transform="translate(20.000000, 20.000000)">
<path d="M7.2,5.6 L8.8,5.6 L8.8,4 L7.2,4 M8,14.4 C4.472,14.4 1.6,11.528 1.6,8 C1.6,4.472 4.472,1.6 8,1.6 C11.528,1.6 14.4,4.472 14.4,8 C14.4,11.528 11.528,14.4 8,14.4 M8,-3.55271368e-16 C3.581722,-3.55271368e-16 -3.55271368e-16,3.581722 -3.55271368e-16,8 C-3.55271368e-16,10.1217319 0.842854723,12.1565632 2.34314575,13.6568542 C3.84343678,15.1571453 5.87826808,16 8,16 C10.1217319,16 12.1565632,15.1571453 13.6568542,13.6568542 C15.1571453,12.1565632 16,10.1217319 16,8 C16,5.87826808 15.1571453,3.84343678 13.6568542,2.34314575 C12.1565632,0.842854723 10.1217319,-3.55271368e-16 8,-3.55271368e-16 M7.2,12 L8.8,12 L8.8,7.2 L7.2,7.2 L7.2,12 Z" id="形状"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>1.Base基础/Icon图标/全屏</title>
<defs>
<rect id="path-1" x="0" y="0" width="16" height="16"></rect>
<filter color-interpolation-filters="auto" id="filter-3">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0.337255 0 0 0 0 0.362353 0 0 0 0 0.400000 0 0 0 1.000000 0"></feColorMatrix>
</filter>
</defs>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="全屏" transform="translate(-1393.000000, -873.000000)">
<g id="编组备份" transform="translate(1384.000000, 864.000000)">
<g id="1.Base基础/Icon图标/全屏" transform="translate(8.000000, 8.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<g id="蒙版"></g>
<g filter="url(#filter-3)" id="编组">
<g mask="url(#mask-2)">
<g transform="translate(-1.000000, -1.000000)">
<g id="编组-63" transform="translate(12.706359, 5.236359) rotate(-315.000000) translate(-12.706359, -5.236359) translate(9.176029, 1.361359)">
<path d="M3.97654174,0.147051761 L4.06066017,0.219669914 L7.06066017,3.21966991 L6,4.28033009 L4.28,2.561 L4.28033009,7.75 L2.78033009,7.75 L2.78,2.561 L1.06066017,4.28033009 L-5.89740035e-13,3.21966991 L3,0.219669914 C3.26626656,-0.0465966484 3.68293025,-0.0708026996 3.97654174,0.147051761 Z" id="形状结合" fill="#565C66" fill-rule="nonzero" transform="translate(3.530330, 3.875000) rotate(-180.000000) translate(-3.530330, -3.875000) "></path>
</g>
<g id="编组-63备份" transform="translate(5.236359, 12.706359) scale(-1, -1) rotate(-135.000000) translate(-5.236359, -12.706359) translate(1.706029, 8.831359)">
<path d="M3.97654174,0.147051761 L4.06066017,0.219669914 L7.06066017,3.21966991 L6,4.28033009 L4.28,2.561 L4.28033009,7.75 L2.78033009,7.75 L2.78,2.561 L1.06066017,4.28033009 L2.55455517e-12,3.21966991 L3,0.219669914 C3.26626656,-0.0465966484 3.68293025,-0.0708026996 3.97654174,0.147051761 Z" id="形状结合" fill="#565C66" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?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>编组 26备份 2</title>
<defs>
<filter color-interpolation-filters="auto" id="filter-1">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0.540000 0 0 0 0 0.564000 0 0 0 0 0.600000 0 0 0 1.000000 0"></feColorMatrix>
</filter>
<filter color-interpolation-filters="auto" id="filter-2">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0.540000 0 0 0 0 0.564000 0 0 0 0 0.600000 0 0 0 1.000000 0"></feColorMatrix>
</filter>
</defs>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g filter="url(#filter-1)" id="编组-26备份-2">
<g>
<g id="编组-24备份">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g filter="url(#filter-2)" id="提示图标">
<g>
<circle id="椭圆形" stroke="#979797" stroke-width="1.5" cx="8" cy="8" r="7.25"></circle>
</g>
</g>
</g>
<g id="编组" transform="translate(5.000000, 3.500000)" fill="#8A9099" fill-rule="nonzero">
<path d="M2.30709006,9 L3.69095124,9 L3.69095124,7.65034906 L2.30709006,7.65034906 L2.30709006,9 Z M4.42953435,4.770966 C3.73711269,5.22116893 3.41447366,5.76045459 3.41447364,6.3457184 L3.41447364,6.75042212 L2.30659899,6.75042212 L2.30659899,6.25567783 C2.26043754,5.44579147 2.67589055,4.7259457 3.41398257,4.18570217 C4.24390642,3.60139623 4.65935941,3.0161324 4.56703652,2.47588887 C4.47471362,1.66648145 4.01359027,1.21627851 3.13701391,1.17125823 C2.12195322,1.12623793 1.47618407,1.71150176 1.24586792,2.92609181 L0,2.61094976 C0.369291561,0.811574815 1.52234551,-0.0433318336 3.36782113,0.0016884633 C4.98248953,0.0917290571 5.81290444,0.856595112 5.99705913,2.34130693 C6.04371164,3.24123387 5.53593576,4.05112022 4.42904326,4.770966 L4.42953435,4.770966 Z" id="形状"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?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>编组 24</title>
<defs>
<filter color-interpolation-filters="auto" id="filter-1">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0.540000 0 0 0 0 0.564000 0 0 0 0 0.600000 0 0 0 1.000000 0"></feColorMatrix>
</filter>
<filter color-interpolation-filters="auto" id="filter-2">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0.540000 0 0 0 0 0.564000 0 0 0 0 0.600000 0 0 0 1.000000 0"></feColorMatrix>
</filter>
</defs>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g filter="url(#filter-1)" id="编组-24">
<g>
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g filter="url(#filter-2)" id="提示图标">
<g>
<line x1="8" y1="7.1" x2="8" y2="11.9" id="路径-7" stroke="#979797" stroke-width="1.6"></line>
<rect id="矩形" stroke="#979797" fill="#D8D8D8" x="7.75" y="4.6" width="1" height="1"></rect>
<circle id="椭圆形" stroke="#8A9099" stroke-width="1.5" cx="8" cy="8" r="7.25"></circle>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
.RadiosBox {
display: flex;
justify-content: space-between;
align-items: center;
border: 1px solid #e6e8eb;
border-radius: 4px;
background-color: #e6e8eb;
cursor: pointer;
height: 32px;
box-sizing: border-box;
padding: 2px;
}
.radio {
height: 28px;
box-sizing: border-box;
font-size: 14px;
color: #565c66;
border-radius: 4px;
line-height: 20px;
padding: 3px 18px;
background-color: #e6e8eb;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
white-space: nowrap;
}
.radioActive {
color: #1370ff;
background-color: #fff;
border: 1px solid #e6e8eb;
}
// 按钮样式的单选组
import classnames from "classnames";
import style from "./index.module.css";
type radioOption = {
value: string;
label: string;
};
type IRadioGroupOfButtonStyleProps = {
radioOptions: Array<radioOption>;
value: string;
handleRadio: any;
RadiosBoxStyle?: object;
radioStyle?: object;
};
const RadioGroupOfButtonStyle = (props: IRadioGroupOfButtonStyleProps) => {
const { radioOptions, value, handleRadio, RadiosBoxStyle, radioStyle } =
props;
return (
<div className={style.RadiosBox} style={RadiosBoxStyle}>
{radioOptions.map((options) => {
return (
<div
key={options.value}
className={classnames({
[style.radio]: true,
[style.radioActive]: value === options.value,
})}
onClick={() => handleRadio(options.value)}
style={radioStyle}
>
{options.label}
</div>
);
})}
</div>
);
};
export default RadioGroupOfButtonStyle;
.rootTitle {
border-radius: 4px 4px 0 0;
background-color: rgba(25, 118, 210, 0.08);
/* background-color: rgba(25, 118, 210, 0.5); */
line-height: 44px;
color: rgba(30, 38, 51, 1);
font-size: 14px;
font-weight: 600;
display: flex;
justify-content: flex-start;
align-items: center;
}
.rootTitleActive {
background-color: rgba(25, 118, 210, 0.2);
}
.bigFolderIcon {
margin: 0 9px;
}
.treeLabel {
display: flex;
justify-content: flex-start;
align-items: center;
}
.treeLabelText {
line-height: 44px;
overflow: hidden;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
white-space: nowrap;
width: 320px;
}
.labelFolderIcon {
margin-right: 9px;
}
import MyDialog from "../mui/Dialog";
import { useStores } from "@/store";
import { observer } from "mobx-react-lite";
import { toJS } from "mobx";
import { useEffect, useState } from "react";
import CloudEController from "@/api/fileserver/CloudEController";
import MyTreeView from "@/components/mui/MyTreeView";
import classNames from "classnames";
import bigFolderIcon from "@/assets/project/bigFolderIcon.svg";
import folderIcon from "@/assets/project/folderIcon.svg";
import dataSetIcon from "@/assets/project/dataSetIcon.svg";
import fileIcon from "@/assets/project/fileIcon.svg";
import useMyRequest from "@/hooks/useMyRequest";
import { getDataFind } from "@/api/project_api";
import style from "./index.module.css";
import _ from "lodash";
type FileSelectProps = {
open: boolean;
onConfirm: any;
onClose: any;
type?: "file" | "dataset" | "path";
};
const FileSelect = observer((props: FileSelectProps) => {
const { onConfirm, type = "path" } = props;
// const { onConfirm, type = "dataset" } = props;
const { currentProjectStore } = useStores();
const projectId = toJS(currentProjectStore.currentProjectInfo.id);
const fileToken = toJS(currentProjectStore.currentProjectInfo.filetoken);
const [treeData, setTreeData] = useState<Array<any>>([]);
const [rootActive, setRootActive] = useState(true);
const [newPath, setNewPath] = useState("/");
// 获取某路径下的数据集
const { run: getDataFindRun } = useMyRequest(getDataFind, {
onSuccess: (res: any) => {
const dataSetList = res.data.map((item: any) => {
return {
...item,
type: "dataset",
dir: `/${item.path}`,
subdirs: "",
};
});
let treeDataArr = _.cloneDeep(treeData);
if (newPath === "/") {
treeDataArr = _.uniqWith([...treeDataArr, ...dataSetList], _.isEqual);
setTreeData(treeDataArr);
} else {
let pathArr: Array<any> = newPath.split("/");
pathArr.shift();
let reduceResult = pathArr.reduce((result, path) => {
if (Array.isArray(result)) {
result.forEach((item: any, index: number) => {
if (item.name === path) {
result = result[index];
}
});
} else if (Array.isArray(result.subdirs)) {
result.subdirs.forEach((item: any, index: number) => {
if (item.name === path) {
result = result.subdirs[index];
}
});
} else {
result = result.subdirs;
}
return result;
}, treeDataArr);
if (Array.isArray(reduceResult.subdirs)) {
reduceResult.subdirs = _.uniqWith(
[...reduceResult.subdirs, ...dataSetList],
_.isEqual
);
} else {
reduceResult.subdirs = dataSetList;
}
treeDataArr = _.uniqWith(treeDataArr, _.isEqual);
setTreeData(treeDataArr);
}
},
});
useEffect(() => {
if (type === "dataset") {
getDataFindRun({
projectId: projectId as string,
path: newPath === "/" ? "/" : `${newPath}/`,
});
}
}, [newPath, getDataFindRun, projectId, type]);
useEffect(() => {
if (fileToken && projectId) {
CloudEController.JobOutFileDirtree(
"/",
fileToken,
projectId,
false
)?.then((res: any) => {
if (Array.isArray(res.data)) {
setTreeData(res.data);
} else {
setTreeData([]);
}
if (type === "dataset") {
getDataFindRun({
projectId: projectId as string,
path: "/",
// path: path === "/" ? "/" : `${path}/`,
});
}
});
}
}, [projectId, fileToken, type, getDataFindRun]);
// const renderLabel = (labelNmae: string) => {
const renderLabel = (node: any) => {
return (
<span className={style.treeLabel}>
{node.type === "directory" && (
<img className={style.labelFolderIcon} src={folderIcon} alt="" />
)}
{node.type === "dataset" && (
<img className={style.labelFolderIcon} src={dataSetIcon} alt="" />
)}
{node.type !== "directory" && node.type !== "dataset" && (
<img className={style.labelFolderIcon} src={fileIcon} alt="" />
)}
<span className={style.treeLabelText}>{node.name}</span>
</span>
);
};
const handleRoot = () => {
setNewPath("/");
setRootActive(true);
};
const onNodeSelect = (a: any, b: any) => {
setNewPath(b);
setRootActive(false);
};
// 给路径去掉第一个'/'然后结尾加上文件名 方便后面直接使用
const idFunc = (item: any) => {
return `${item.dir.substr(1)}${item.name}`;
};
const fileSelectOnConfirm = () => {
onConfirm(newPath);
};
return (
<MyDialog
open={props.open}
onClose={props.onClose}
onConfirm={fileSelectOnConfirm}
title={type}
>
<div
className={classNames({
[style.rootTitle]: true,
[style.rootTitleActive]: rootActive,
})}
onClick={handleRoot}
>
<img className={style.bigFolderIcon} src={bigFolderIcon} alt="" />
ProjectData
</div>
<MyTreeView
treeData={treeData}
renderLabel={renderLabel}
onNodeSelect={onNodeSelect}
idFunc={idFunc}
treeViewSx={{
width: 400,
overflow: "hidden",
}}
></MyTreeView>
</MyDialog>
);
});
export default FileSelect;
import { useStores } from "@/store/index"; import { useStores } from "@/store/index";
import { elements } from "@/router"; import { elements } from "@/router";
import { current } from "@/api/demo_api"; import { current } from "@/api/demo_api";
import { product } from "@/api/project_api";
import localStorageKey from "@/utils/localStorageKey"; import localStorageKey from "@/utils/localStorageKey";
import NotFound from "@/views/404"; import NotFound from "@/views/404";
import useMyRequest from "@/hooks/useMyRequest"; import useMyRequest from "@/hooks/useMyRequest";
import { useEffect } from "react"; import { useEffect } from "react";
import { menu } from "@/api/routes_api"; import { menu } from "@/api/routes_api";
import {
setFileServerEndPointLocalStorage,
getFiletokenAccordingToId,
} from "@/views/Project/project";
const useMyRouter = () => { const useMyRouter = () => {
const { permissionStore, menuStore, currentProjectStore } = useStores(); const { permissionStore, menuStore } = useStores();
const userInfo = useMyRequest(current); const userInfo = useMyRequest(current);
const menuInfo = useMyRequest(menu); const menuInfo = useMyRequest(menu);
const productInfo = useMyRequest(product);
useEffect(() => { useEffect(() => {
userInfo.run(); userInfo.run();
menuInfo.run(); menuInfo.run();
productInfo.run({
product: "CADD",
});
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
...@@ -47,24 +38,8 @@ const useMyRouter = () => { ...@@ -47,24 +38,8 @@ const useMyRouter = () => {
permissionStore.initAllRoutes(); permissionStore.initAllRoutes();
} }
if (productInfo.res) {
let list = productInfo.data?.data;
if (list.length === 0) {
currentProjectStore.setProjectList([]);
currentProjectStore.changeProject({});
} else {
currentProjectStore.setProjectList(list);
currentProjectStore.changeProject(list[0]);
setFileServerEndPointLocalStorage(list[0].zoneId);
getFiletokenAccordingToId(list[0].id).then((res) => {
list[0].filetoken = res;
currentProjectStore.changeProject(list[0]);
});
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [userInfo.data, menuInfo.data, productInfo.data]); }, [userInfo.data, menuInfo.data]);
return permissionStore.allRoutes; return permissionStore.allRoutes;
}; };
......
...@@ -42,7 +42,7 @@ const getTransitionComponent = (transition: "grow" | "fade") => { ...@@ -42,7 +42,7 @@ const getTransitionComponent = (transition: "grow" | "fade") => {
const MySnackbarProvider = ({ const MySnackbarProvider = ({
vertical = "top", vertical = "top",
horizontal = "center", horizontal = "center",
autoHideDuration = 2000, autoHideDuration = 5000,
snackerClasses, snackerClasses,
ClickAwayListenerProps, ClickAwayListenerProps,
ContentProps, ContentProps,
......
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-07-05 14:00:37
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-06 13:52:48
* @FilePath: /bkunyun/src/components/mui/MyCheckBox.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import * as React from "react";
import FormGroup, { FormGroupProps } from "@mui/material/FormGroup";
import FormControlLabel from "@mui/material/FormControlLabel";
import Checkbox from "@mui/material/Checkbox";
import FormControl from "@mui/material/FormControl";
import FormHelperText from '@mui/material/FormHelperText';
import _ from "lodash";
interface IMyCheckBoxProps extends FormGroupProps{
value: Array<any>;
options: Array<ICheckBoxOption>;
onChange: any; // 直接返回选中项的数组
variant?: "standard" | "outlined" | "filled";
error?: boolean;
helperText?: string;
};
type ICheckBoxOption = {
value: any;
label?: string;
disabled?: boolean;
};
export const optionsTransform = (
arr: Array<any>,
labelKey: string = "label",
valueKey: string = "value",
disabledKey: string = "disabled"
): Array<ICheckBoxOption> => {
return arr.map((item: any) => {
return {
value: item[valueKey],
label: item[labelKey],
disabled: item[disabledKey] || false,
};
});
};
export default function MyCheckBox(props: IMyCheckBoxProps) {
const { value, options, onChange, error = false, helperText, variant } = props;
const getCheckedStatus = (
checkBoxItemValue: any,
valueArr: Array<any>
): boolean => {
const result = valueArr.indexOf(checkBoxItemValue);
return result === -1 ? false : true;
};
const handleMyCheckBoxOnChange = (e: any) => {
const resultArr = _.cloneDeep(value);
const clickValue = e.target.name;
const clickValueIndex = value.indexOf(clickValue);
if (clickValueIndex === -1) {
resultArr.push(clickValue);
onChange && onChange(resultArr);
} else {
resultArr.splice(clickValueIndex, 1);
onChange && onChange(resultArr);
}
};
return (
<FormControl fullWidth variant={variant} error={error}>
<FormGroup {...props} row>
{options.map((option) => {
return (
<FormControlLabel
key={option.value}
control={
<Checkbox
checked={getCheckedStatus(option.value, value)}
value={option.value}
/>
}
label={option.label}
name={option.value}
onChange={handleMyCheckBoxOnChange}
/>
);
})}
</FormGroup>
{helperText && error && <FormHelperText>{helperText}</FormHelperText>}
</FormControl>
);
}
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-07-05 14:00:37
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-06 11:45:10
* @FilePath: /bkunyun/src/components/mui/MyInput.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import TextField, { TextFieldProps } from "@mui/material/TextField";
interface MyInputProps extends Omit<TextFieldProps, "value"> {
value: any;
inputSx?: any;
onChange?: any;
onFocus?: any;
label?: string;
variant?: "standard" | "filled" | "outlined";
id?: string;
size?: "small" | "medium";
placeholder?: string;
fullWidth?: boolean; // 宽度是否和容器一致
InputProps?: any; // input加前后icon可以用这个
error?: boolean;
helperText?: string;
};
const MyInput = (props: MyInputProps) => {
const {
inputSx = {},
value,
onChange,
onFocus,
label,
id,
variant,
size = "small",
placeholder = "请输入",
fullWidth = true,
InputProps,
error = false,
helperText,
} = props;
return (
<TextField
{...props}
error={error}
helperText={helperText}
sx={{ ...inputSx }}
id={id}
label={label}
variant={variant}
onChange={onChange}
onFocus={onFocus}
size={size}
placeholder={placeholder}
fullWidth={fullWidth}
InputProps={{
...InputProps,
}}
value={value}
/>
);
};
export default MyInput;
import * as React from "react";
import Menu from "@mui/material/Menu";
import MenuItem from "@mui/material/MenuItem";
import CheckIcon from "@mui/icons-material/Check";
import { ThemeProvider, createTheme } from "@mui/material/styles";
type IOption = {
label: string;
value: string;
};
type IMyMenuProps = {
children: React.ReactNode;
options: Array<IOption>;
value: string;
setValue?: any;
};
const theme = createTheme({
components: {
MuiMenu: {
styleOverrides: {
root: {
maxHeight: "260px",
overflowY: "scroll",
},
},
},
MuiMenuItem: {
styleOverrides: {
root: {
fontSize: "14px",
lineHeight: "36px",
display: "flex",
justifyContent: "space-between",
":hover": {
color: "rgba(19, 112, 255, 1)",
},
"&.Mui-selected": {
backgroundColor: "#fff",
color: "rgba(19, 112, 255, 1)",
},
},
},
},
MuiSvgIcon: {
styleOverrides: {
root: {
width: "16px",
height: "16px",
},
},
},
},
});
const MyMenu = (props: IMyMenuProps) => {
const { children, options, value, setValue } = props;
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = (value: string) => {
setAnchorEl(null);
setValue && setValue(value);
};
return (
<ThemeProvider theme={theme}>
<div>
<div onClick={handleClick}>{children}</div>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
"aria-labelledby": "basic-button",
}}
>
{options.map((option, index) => {
return (
<MenuItem
onClick={() => handleClose(option.value)}
selected={value === option.value}
key={index}
>
<span>{option.label}</span>
{value === option.value && <CheckIcon />}
</MenuItem>
);
})}
</Menu>
</div>
</ThemeProvider>
);
};
export default MyMenu;
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;
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-07-05 14:00:37
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-06 13:49:25
* @FilePath: /bkunyun/src/components/mui/MyRadio.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import * as React from "react";
import Radio from "@mui/material/Radio";
import RadioGroup, { RadioGroupProps } from "@mui/material/RadioGroup";
import FormControlLabel from "@mui/material/FormControlLabel";
import FormControl from "@mui/material/FormControl";
import FormHelperText from '@mui/material/FormHelperText';
interface IMyRadioProps extends RadioGroupProps {
value: any;
options: Array<ICheckBoxOption>;
onChange: any;
variant?: "standard" | "outlined" | "filled";
error?: boolean;
helperText?: string;
};
type ICheckBoxOption = {
value: any;
label?: string;
disabled?: boolean;
};
// 如果后端给的options不是 value-label的字段可以用下面的方法转换
export const optionsTransform = (
arr: Array<any>,
labelKey: string = "label",
valueKey: string = "value",
disabledKey: string = "disabled"
): Array<ICheckBoxOption> => {
return arr.map((item: any) => {
return {
value: item[valueKey],
label: item[labelKey],
disabled: item[disabledKey] || false,
};
});
};
export default function MyRadio(props: IMyRadioProps) {
const { value, options, onChange , error = false, helperText, variant} = props;
return (
<FormControl fullWidth variant={variant} error={error}>
<RadioGroup
{...props}
row
aria-labelledby="demo-row-radio-buttons-group-label"
name="row-radio-buttons-group"
value={value}
onChange={onChange}
>
{options.map((option) => {
return (
<FormControlLabel
key={option.value}
value={option.value}
control={<Radio />}
label={option.label}
/>
);
})}
</RadioGroup>
{helperText && error && <FormHelperText>{helperText}</FormHelperText>}
</FormControl>
);
}
...@@ -18,6 +18,22 @@ export interface IOption { ...@@ -18,6 +18,22 @@ export interface IOption {
value: string; value: string;
disabled?: boolean; disabled?: boolean;
} }
export const optionsTransform = (
arr: Array<any>,
labelKey: string = "label",
valueKey: string = "value",
disabledKey: string = "disabled"
): Array<IOption> => {
return arr.map((item: any) => {
return {
label: item[labelKey],
value: item[valueKey],
disabled: item[disabledKey],
};
});
};
interface IProps interface IProps
extends Omit<SelectProps, "value" | "options" | "onChange" | "title"> { extends Omit<SelectProps, "value" | "options" | "onChange" | "title"> {
value?: IOption; value?: IOption;
......
...@@ -15,7 +15,7 @@ type MyTreeViewProps = { ...@@ -15,7 +15,7 @@ type MyTreeViewProps = {
onNodeFocus?: (event: object, value: string) => void; // 点击某一项的回调 onNodeFocus?: (event: object, value: string) => void; // 点击某一项的回调
onNodeSelect?: (event: object, value: Array<any> | string) => void; // 点击某一项的回调 onNodeSelect?: (event: object, value: Array<any> | string) => void; // 点击某一项的回调
onNodeToggle?: (event: object, nodeIds: Array<any>) => void; // 点击某一项的回调 onNodeToggle?: (event: object, nodeIds: Array<any>) => void; // 点击某一项的回调
renderLabel?: (labelNmae: string) => React.ReactNode; renderLabel?: (node: any) => React.ReactNode;
treeViewSx?: any; treeViewSx?: any;
defaultExpanded?: Array<string>; defaultExpanded?: Array<string>;
idKey?: string; idKey?: string;
...@@ -48,7 +48,7 @@ const MyTreeView = (props: MyTreeViewProps) => { ...@@ -48,7 +48,7 @@ const MyTreeView = (props: MyTreeViewProps) => {
nodeId={String( nodeId={String(
idFunc ? idFunc(nodes) : nodes.id || `${nodes.name}${index}` idFunc ? idFunc(nodes) : nodes.id || `${nodes.name}${index}`
)} )}
label={renderLabel === undefined ? nodes.name : renderLabel(nodes.name)} label={renderLabel === undefined ? nodes.name : renderLabel(nodes)}
disabled={nodes?.disabled ? true : false} disabled={nodes?.disabled ? true : false}
> >
{Array.isArray(nodes.subdirs) {Array.isArray(nodes.subdirs)
......
...@@ -2,17 +2,17 @@ ...@@ -2,17 +2,17 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com * @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:18:13 * @Date: 2022-05-31 10:18:13
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com * @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-07 20:31:40 * @LastEditTime: 2022-07-04 20:18:17
* @FilePath: /bkunyun/src/views/Project/ProjectSetting/index.tsx * @FilePath: /bkunyun/src/views/Project/ProjectSetting/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 { memo } from "react"; import { memo } from "react";
import { isEqual } from "lodash"; import { isEqual } from "lodash";
import { useState, useMemo, useEffect } from "react"; import { useState } from "react";
import { Box } from "@mui/system"; import { Box } from "@mui/system";
import Tab from "@mui/material/Tab"; import Tab from "@mui/material/Tab";
import { TabContext, TabList, TabPanel } from "@mui/lab"; import { TabContext, TabList, TabPanel } from "@mui/lab";
import { Typography } from '@mui/material'; import { Typography } from "@mui/material";
interface ITabList { interface ITabList {
label: string; label: string;
...@@ -20,16 +20,19 @@ interface ITabList { ...@@ -20,16 +20,19 @@ interface ITabList {
component: JSX.Element; component: JSX.Element;
icon?: string; icon?: string;
iconed?: string; iconed?: string;
hide?: boolean hide?: boolean;
} }
interface IProps { interface IProps {
tabList: ITabList[]; tabList: ITabList[];
defaultValue?: string;
} }
const Tabs = (props: IProps) => { const Tabs = (props: IProps) => {
const { tabList } = props; const { tabList, defaultValue } = props;
const [value, setValue] = useState(tabList.filter(e => !e.hide)[0].value); const [value, setValue] = useState(
defaultValue || tabList.filter((e) => !e.hide)[0].value
);
const onChange = (val: string) => { const onChange = (val: string) => {
setValue(val); setValue(val);
...@@ -38,14 +41,21 @@ const Tabs = (props: IProps) => { ...@@ -38,14 +41,21 @@ const Tabs = (props: IProps) => {
const labelRender = (item: ITabList, key: number) => { const labelRender = (item: ITabList, key: number) => {
return ( return (
<Box style={{ display: "flex", alignItems: "center" }}> <Box style={{ display: "flex", alignItems: "center" }}>
{ {item.icon ? (
item.icon ? <img style={{ width: "14px", marginRight: "10px" }} src={value === item.value ? item.iconed : item.icon} alt="" /> <img
: "" style={{ width: "14px", marginRight: "10px" }}
} src={value === item.value ? item.iconed : item.icon}
<Typography sx={{ fontSize: "14px", fontWeight: '400' }} >{item.label}</Typography> alt=""
/>
) : (
""
)}
<Typography sx={{ fontSize: "14px", fontWeight: "400" }}>
{item.label}
</Typography>
</Box> </Box>
) );
} };
return ( return (
<TabContext value={value}> <TabContext value={value}>
...@@ -54,10 +64,10 @@ const Tabs = (props: IProps) => { ...@@ -54,10 +64,10 @@ const Tabs = (props: IProps) => {
onChange={(e: any, val: string) => { onChange={(e: any, val: string) => {
onChange(val); onChange(val);
}} }}
aria-label="lab API tabs example"
> >
{tabList?.map((item, key) => { {tabList
if (item.hide) return "" ?.filter((item) => !item.hide)
.map((item, key) => {
return ( return (
<Tab <Tab
key={key} key={key}
...@@ -69,7 +79,9 @@ const Tabs = (props: IProps) => { ...@@ -69,7 +79,9 @@ const Tabs = (props: IProps) => {
})} })}
</TabList> </TabList>
</Box> </Box>
{tabList?.map((item) => { {tabList
?.filter((item) => !item.hide)
.map((item) => {
return ( return (
<TabPanel <TabPanel
sx={{ padding: "20px 0 0 0" }} sx={{ padding: "20px 0 0 0" }}
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com * @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:17:23 * @Date: 2022-05-31 10:17:23
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com * @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-14 10:28:43 * @LastEditTime: 2022-07-07 22:03:00
* @FilePath: /bkunyun/src/react-app-env.d.ts * @FilePath: /bkunyun/src/react-app-env.d.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
*/ */
...@@ -80,7 +80,9 @@ declare module "*.module.sass" { ...@@ -80,7 +80,9 @@ declare module "*.module.sass" {
declare module "@mui/lab"; declare module "@mui/lab";
declare module "lodash"; declare module "lodash";
declare module 'lodash/cloneDeep'
declare module "@mui/material/Tab"; declare module "@mui/material/Tab";
declare module "tus-js-client"; declare module "tus-js-client";
declare module "uuid"; declare module "uuid";
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com * @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:18:13 * @Date: 2022-05-31 10:18:13
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com * @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-05-31 15:15:59 * @LastEditTime: 2022-06-24 14:32:32
* @FilePath: /bkunyun/src/router/index.ts * @FilePath: /bkunyun/src/router/index.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
import { AnyMap } from "immer/dist/internal"; import { AnyMap } from "immer/dist/internal";
...@@ -16,7 +16,8 @@ import Demo from "@/views/demo"; ...@@ -16,7 +16,8 @@ import Demo from "@/views/demo";
import ProjectSetting from "@/views/Project/ProjectSetting"; import ProjectSetting from "@/views/Project/ProjectSetting";
import ProjectData from "@/views/Project/ProjectData"; import ProjectData from "@/views/Project/ProjectData";
import ProjectWorkbench from "@/views/Project/ProjectWorkbench"; import ProjectWorkbench from "@/views/Project/ProjectWorkbench";
import ProjectSubmitWork from "@/views/Project/ProjectSubmitWork";
import ProjectJobDetail from "@/views/Project/ProjectJobDetail";
export type route = { export type route = {
id?: string; id?: string;
...@@ -51,7 +52,9 @@ export const elements: { ...@@ -51,7 +52,9 @@ export const elements: {
Demo: Demo, Demo: Demo,
ProjectSetting: ProjectSetting, ProjectSetting: ProjectSetting,
ProjectData: ProjectData, ProjectData: ProjectData,
ProjectWorkbench:ProjectWorkbench ProjectWorkbench: ProjectWorkbench,
ProjectSubmitWork: ProjectSubmitWork,
ProjectJobDetail: ProjectJobDetail
}; };
export const routes: Array<route | navigate> = [ export const routes: Array<route | navigate> = [
......
...@@ -11,22 +11,39 @@ type productInfo = { ...@@ -11,22 +11,39 @@ type productInfo = {
id?: string; id?: string;
name?: string; name?: string;
}; };
const sessionStorageCurrentProjectInfo = JSON.parse(
sessionStorage.getItem("currentProjectInfo") || "{}"
);
const sessionStorageCurrentProductInfo = JSON.parse(
sessionStorage.getItem("currentProductInfo") || "{}"
);
const sessionStorageProjectList = JSON.parse(
sessionStorage.getItem("projectList") || "[]"
);
class currentProject { class currentProject {
constructor() { constructor() {
makeAutoObservable(this); makeAutoObservable(this);
} }
// 选中的项目 // 选中的项目
currentProjectInfo: projectInfo = {}; currentProjectInfo: projectInfo = sessionStorageCurrentProjectInfo;
// 选中的产品下的项目列表 // 选中的产品下的项目列表
projectList: Array<projectInfo> = []; projectList: Array<projectInfo> = sessionStorageProjectList;
// 选中的产品 // 选中的产品
currentProductInfo: productInfo = {}; currentProductInfo: productInfo = sessionStorageCurrentProductInfo;
setProjectList = (list: Array<projectInfo>) => { setProjectList = (list: Array<projectInfo>) => {
this.projectList = list; this.projectList = list;
sessionStorage.setItem("projectList", JSON.stringify(list));
}; };
changeProject = (project: projectInfo) => { changeProject = (project: projectInfo) => {
this.currentProjectInfo = project; this.currentProjectInfo = project;
sessionStorage.setItem("currentProjectInfo", JSON.stringify(project));
};
changeProductInfo = (productInfo: productInfo) => {
this.currentProductInfo = productInfo;
sessionStorage.setItem("currentProductInfo", JSON.stringify(productInfo));
}; };
} }
......
...@@ -17,11 +17,13 @@ class Menus { ...@@ -17,11 +17,13 @@ class Menus {
productList: Array<{ productList: Array<{
name: string; name: string;
path: string; path: string;
id: string;
}> = []; }> = [];
utilityList: Array<{ utilityList: Array<{
name: string; name: string;
path: string; path: string;
id: string;
}> = []; }> = [];
initMenu = (list: projectList) => { initMenu = (list: projectList) => {
...@@ -32,11 +34,13 @@ class Menus { ...@@ -32,11 +34,13 @@ class Menus {
this.productList.push({ this.productList.push({
name: item.name, name: item.name,
path: item.routes[0].path, path: item.routes[0].path,
id: item.id,
}); });
} else if (item.type === "utility") { } else if (item.type === "utility") {
this.utilityList.push({ this.utilityList.push({
name: item.name, name: item.name,
path: item.routes[0].path, path: item.routes[0].path,
id: item.id,
}); });
} }
} }
......
...@@ -140,11 +140,10 @@ const FileItem = observer((props: IProps) => { ...@@ -140,11 +140,10 @@ const FileItem = observer((props: IProps) => {
<div className={styles.speedBox}> <div className={styles.speedBox}>
<span className={styles.span}>{`${storageUnitFromB( <span className={styles.span}>{`${storageUnitFromB(
itemInfo?.bytesUploaded || 0 itemInfo?.bytesUploaded || 0
)}/${storageUnitFromB(itemInfo?.bytesTotal || 0)}`}</span>{" "} )}/${storageUnitFromB(itemInfo?.bytesTotal || 0)}`}</span>
: {statusMsg !== '上传失败' ? <span className={styles.span}>{`${storageUnitFromB(
<span className={styles.span}>{`${storageUnitFromB(
speed speed
)}/s`}</span> )}/s`}</span> : null}
</div> </div>
)} )}
</div> </div>
......
import React, { useEffect } from "react"; import React, { useEffect, useState } from "react";
import { Outlet, useLocation, useNavigate } from "react-router-dom"; import { Outlet, useLocation, useNavigate } from "react-router-dom";
import cx from "classnames"; import cx from "classnames";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
...@@ -14,7 +14,12 @@ import Button from "@/components/mui/Button"; ...@@ -14,7 +14,12 @@ import Button from "@/components/mui/Button";
import logo from "@/assets/img/logo.svg"; import logo from "@/assets/img/logo.svg";
import MyPopover from "@/components/mui/MyPopover"; import MyPopover from "@/components/mui/MyPopover";
import TranSferList from "./components/TransferList"; import TranSferList from "./components/TransferList";
import { getProjectList } from "@/api/project_api";
import useMyRequest from "@/hooks/useMyRequest";
import {
setFileServerEndPointLocalStorage,
getFiletokenAccordingToId,
} from "@/views/Project/project";
import style from "./index.module.css"; import style from "./index.module.css";
const ConsoleLayout = observer(() => { const ConsoleLayout = observer(() => {
...@@ -28,6 +33,41 @@ const ConsoleLayout = observer(() => { ...@@ -28,6 +33,41 @@ const ConsoleLayout = observer(() => {
handleClose, handleClose,
} = useIndex(); } = useIndex();
const [currentProduct, setCurrentProduct] = useState<{
path: string;
name: string;
}>();
const { currentProjectStore } = useStores();
const { run: runGetProjectList } = useMyRequest(getProjectList, {
onSuccess: (res) => {
let list = res.data;
if (list.length === 0) {
currentProjectStore.setProjectList([]);
currentProjectStore.changeProject({});
navigate(currentProduct?.path as string);
} else {
currentProjectStore.setProjectList(list);
currentProjectStore.changeProject(list[0]);
setFileServerEndPointLocalStorage(list[0].zoneId);
getFiletokenAccordingToId(list[0].id).then((res) => {
list[0].filetoken = res;
currentProjectStore.changeProject(list[0]);
});
navigate(currentProduct?.path as string);
}
},
});
// 切换产品
const getProduct = (item: any) => {
currentProjectStore.changeProductInfo({ id: item.id, name: item.name });
setCurrentProduct(item);
runGetProjectList({
product: item.name,
});
};
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
const { permissionStore, menuStore } = useStores(); const { permissionStore, menuStore } = useStores();
...@@ -86,7 +126,7 @@ const ConsoleLayout = observer(() => { ...@@ -86,7 +126,7 @@ const ConsoleLayout = observer(() => {
root: style.menuItemRoot, root: style.menuItemRoot,
}} }}
onClick={() => { onClick={() => {
navigate(item.path); getProduct(item);
handleClose(); handleClose();
}} }}
> >
...@@ -106,13 +146,12 @@ const ConsoleLayout = observer(() => { ...@@ -106,13 +146,12 @@ const ConsoleLayout = observer(() => {
horizontal: "right", horizontal: "right",
}} }}
> >
<Box className={style.topRightItem}>
<img <img
className={style.topRightItem}
src={uploadIcon} src={uploadIcon}
alt="" alt=""
style={{ verticalAlign: "middle" }} style={{ verticalAlign: "middle" }}
/> />
</Box>
</MyPopover> </MyPopover>
<Box className={style.topRightItem}> <Box className={style.topRightItem}>
<Box <Box
......
...@@ -13,8 +13,7 @@ ...@@ -13,8 +13,7 @@
.content { .content {
flex: 1; flex: 1;
height: calc(100vh - 57px); height: calc(100vh - 57px);
overflow: hidden; overflow: scroll;
/* ??????????? */
} }
.list { .list {
/* background-color: red; */ /* background-color: red; */
......
...@@ -6,19 +6,28 @@ import style from "./index.module.css"; ...@@ -6,19 +6,28 @@ import style from "./index.module.css";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useStores } from "@/store/index"; import { useStores } from "@/store/index";
import classnames from "classnames"; import classnames from "classnames";
import { toJS } from "mobx";
const MenuLayout = observer(() => { const MenuLayout = observer(() => {
const { permissionStore } = useStores(); const { permissionStore, currentProjectStore } = useStores();
let pathname = new URL(window.location.href).pathname; let pathname = new URL(window.location.href).pathname;
const navigate = useNavigate(); const navigate = useNavigate();
const productInfo = toJS(currentProjectStore.currentProductInfo);
// 未选择产品时 直接跳转home页面
if (!productInfo.name) {
navigate("/home");
}
return ( return (
<Box className={style.container}> <Box className={style.container}>
<Box className={style.aside}> <Box className={style.aside}>
<CurrentProject /> <CurrentProject />
<List className={style.list}> <List className={style.list}>
{permissionStore.sidebarRouters.map((item, index) => { {permissionStore.sidebarRouters.map((item, index) => {
if (item.show) {
return ( return (
<li <li
key={"sidebar" + index} key={"sidebar" + index}
...@@ -31,6 +40,8 @@ const MenuLayout = observer(() => { ...@@ -31,6 +40,8 @@ const MenuLayout = observer(() => {
{item.name} {item.name}
</li> </li>
); );
}
return null;
})} })}
</List> </List>
</Box> </Box>
......
...@@ -34,7 +34,9 @@ const MoveFile = (props: any) => { ...@@ -34,7 +34,9 @@ const MoveFile = (props: any) => {
const [moveFileSubmitloading, setMoveFileSubmitloading] = useState(false); const [moveFileSubmitloading, setMoveFileSubmitloading] = useState(false);
const [treeData, setTreeData] = useState<any>([]); const [treeData, setTreeData] = useState<any>([]);
const [renderTreeData, setRenderTreeData] = useState<any>([]); const [renderTreeData, setRenderTreeData] = useState<any>([]);
let moveFileDialogRef: any = React.createRef(); const [moveFileDialogRef, setMoveFileDialogRef] = useState<any>(
React.createRef()
);
// 要移动的文件夹 之后用来隐藏文件夹树中同路径的文件夹 // 要移动的文件夹 之后用来隐藏文件夹树中同路径的文件夹
const [moveFolderPathArr, setMoveFolderPathArr] = useState<Array<string>>([]); const [moveFolderPathArr, setMoveFolderPathArr] = useState<Array<string>>([]);
...@@ -301,11 +303,11 @@ const MoveFile = (props: any) => { ...@@ -301,11 +303,11 @@ const MoveFile = (props: any) => {
}); });
}; };
const renderLabel = (labelNmae: string) => { const renderLabel = (node: any) => {
return ( return (
<span className={style.treeLabel}> <span className={style.treeLabel}>
<img className={style.labelFolderIcon} src={folderIcon} alt="" /> <img className={style.labelFolderIcon} src={folderIcon} alt="" />
<span className={style.treeLabelText}>{labelNmae}</span> <span className={style.treeLabelText}>{node.name}</span>
</span> </span>
); );
}; };
......
...@@ -453,7 +453,10 @@ const ProjectData = observer(() => { ...@@ -453,7 +453,10 @@ const ProjectData = observer(() => {
// 下载文件 // 下载文件
const hanleDownloadFile = (item: any) => { const hanleDownloadFile = (item: any) => {
const downloadPath = path === "/" ? "/" : `${path}/${item.name}`; console.log(item);
const downloadPath =
path === "/" ? `/${item.name}` : `${path}/${item.name}`;
console.log(downloadPath);
CloudEController.JobFileDownload( CloudEController.JobFileDownload(
downloadPath, downloadPath,
fileToken as string, fileToken as string,
......
.swBox {
position: fixed;
z-index: 1000;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: RGBA(247, 248, 250, 1);
overflow-y: scroll;
}
.swHeader {
z-index: 1001;
position: sticky;
top: 0;
height: 56px;
background-color: #fff;
box-shadow: 0px 3px 10px 0px rgba(0, 24, 57, 0.04);
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 24px;
}
.swHeaderLeft {
display: flex;
justify-content: flex-start;
align-items: center;
}
.swTemplateTitle {
margin: 0 19px 0 8px;
line-height: 22px;
font-size: 14px;
color: rgba(30, 38, 51, 1);
font-weight: 600;
}
.swContent {
display: flex;
height: calc(100vh - 56px);
}
.swFormBox {
background-color: #fff;
border-right: 1xp solid rgba(235, 237, 240, 1);
width: 360px;
overflow-y: scroll;
box-sizing: border-box;
padding: 24px;
}
.swFlowBox {
flex: 1;
height: calc(100vh - 56px);
}
.title {
color: rgba(30, 38, 51, 1);
font-size: 16px;
line-height: 24px;
font-weight: 600;
margin-bottom: 16px;
}
.taskResults {
padding: 24px;
background-color: rgba(247, 248, 250, 1);
margin-bottom: 24px;
}
.outputLi {
display: flex;
justify-content: space-between;
align-items: center;
margin: 6px 0;
}
.outputLiLeft {
display: flex;
align-items: center;
color: rgba(19, 112, 255, 1);
font-size: 14px;
}
.outputLiLeftImg {
margin-right: 15px;
}
.outputLiRight {
color: rgba(138, 144, 153, 1);
font-size: 12px;
}
.notResults {
background-color: rgba(247, 248, 250, 1);
padding: 54px 0;
text-align: center;
color: rgba(138, 144, 153, 1);
font-size: 14px;
line-height: 22px;
margin-bottom: 24px;
}
.taskInfoLi {
margin-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.taskInfoParams {
color: rgba(138, 144, 153, 1);
font-size: 14px;
line-height: 22px;
width: 72px;
margin-right: 44px;
}
.taskInfoValue {
color: rgba(30, 38, 51, 1);
font-size: 14px;
line-height: 22px;
display: flex;
position: relative;
align-items: center;
text-align: left;
word-break: break-all;
flex: 1;
justify-content: flex-end;
}
.taskInfoValueClick {
cursor: pointer;
color: rgba(19, 112, 255, 1);
}
.taskInfoDownload {
color: rgba(19, 112, 255, 1);
cursor: pointer;
}
.taskInfoValueShowAll {
white-space: normal;
}
.taskInfoValueIcon {
margin-right: 9px;
}
.tabs {
display: flex;
justify-content: flex-start;
border-bottom: 1px solid rgba(240, 242, 245, 1);
}
.tabLi {
cursor: pointer;
font-size: 14px;
line-height: 22px;
padding-bottom: 8px;
color: rgba(138, 144, 153, 1);
margin-right: 32px;
position: relative;
}
.tabLiAcitve {
color: rgba(19, 112, 255, 1);
border-bottom: 2px solid rgba(19, 112, 255, 1);
}
.overview {
padding-top: 19px;
}
.params {
padding-top: 19px;
}
.options {
position: absolute;
top: 33px;
max-height: 230px;
overflow-y: scroll;
padding: 8px 0px;
background: #ffffff;
box-shadow: 0px 3px 10px 0px rgba(0, 24, 57, 0.14);
border-radius: 4px;
z-index: 1002;
}
.option {
padding: 7px 16px;
font-size: 14px;
color: rgba(30, 38, 51, 1);
line-height: 22px;
cursor: pointer;
}
.option:hover {
color: rgba(19, 112, 255, 1);
}
.optionActive {
color: rgba(19, 112, 255, 1);
}
.fullScreenBox {
position: absolute;
background-color: #fff;
cursor: pointer;
z-index: 1000;
right: 24px;
bottom: 24px;
padding: 8px;
}
.fullScreenBox:hover {
opacity: 0.6;
}
This diff is collapsed.
...@@ -187,7 +187,7 @@ const BaseInfo = observer(() => { ...@@ -187,7 +187,7 @@ const BaseInfo = observer(() => {
// 修改项目 // 修改项目
const handleClickUpdate = () => { const handleClickUpdate = () => {
if (checkName(projectInfo.name, true)) { if (checkName(projectInfo.name, true)) {
updateProjectRun({ ...projectInfo, product: "CADD" }); updateProjectRun({ ...projectInfo, product: "cadd" });
} else { } else {
return; return;
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com * @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:18:13 * @Date: 2022-05-31 10:18:13
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com * @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-16 20:49:14 * @LastEditTime: 2022-07-07 18:08:33
* @FilePath: /bkunyun/src/views/Project/ProjectSetting/index.tsx * @FilePath: /bkunyun/src/views/Project/ProjectSetting/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
*/ */
...@@ -46,6 +46,8 @@ const ProjectMembers = observer(() => { ...@@ -46,6 +46,8 @@ const ProjectMembers = observer(() => {
const [addMemberDialog, setAddMemberDialog] = useState<boolean>(false); const [addMemberDialog, setAddMemberDialog] = useState<boolean>(false);
/** 表格数据 */ /** 表格数据 */
const [tableData, setTableData] = useState([]); const [tableData, setTableData] = useState([]);
/** 当前项目用户权限 */
const [projectRole, setProjectRole] = useState<string>("");
/** 项目名称 */ /** 项目名称 */
const [projectName, setProjectMember] = useState(""); const [projectName, setProjectMember] = useState("");
/** 过滤后数据 */ /** 过滤后数据 */
...@@ -56,6 +58,9 @@ const ProjectMembers = observer(() => { ...@@ -56,6 +58,9 @@ const ProjectMembers = observer(() => {
{ id: "username", label: "成员名称" }, { id: "username", label: "成员名称" },
{ id: "projectRoleDesc", label: "项目权限" }, { id: "projectRoleDesc", label: "项目权限" },
{ id: "phone", label: "联系方式" }, { id: "phone", label: "联系方式" },
...(projectRole !== "OWNER"
? []
: [
{ {
id: "operation", id: "operation",
label: "操作", label: "操作",
...@@ -83,9 +88,10 @@ const ProjectMembers = observer(() => { ...@@ -83,9 +88,10 @@ const ProjectMembers = observer(() => {
); );
}, },
}, },
]),
]; ];
return val; return val;
}, []); }, [projectRole]);
/** 获取表格数据 */ /** 获取表格数据 */
const getTableList = useCallback(() => { const getTableList = useCallback(() => {
...@@ -98,6 +104,8 @@ const ProjectMembers = observer(() => { ...@@ -98,6 +104,8 @@ const ProjectMembers = observer(() => {
.then((res) => { .then((res) => {
const { data = {} } = res; const { data = {} } = res;
setTableData(data?.members || []); setTableData(data?.members || []);
console.log(data?.projectRole, data?.projectRole);
setProjectRole(data?.projectRole || "");
}); });
}, [currentProjectStore?.currentProjectInfo, http]); }, [currentProjectStore?.currentProjectInfo, http]);
......
.formBox {
position: relative;
}
.templateDescBox {
margin-bottom: 40px;
}
.templateDescTitle {
font-size: 16px;
line-height: 24px;
color: rgba(30, 38, 51, 1);
font-weight: 600;
margin-bottom: 12px;
}
.templateDesc {
font-size: 12px;
line-height: 20px;
color: #565c66;
}
.backgroundTitle {
background-color: rgba(245, 246, 247, 1);
height: 48px;
display: flex;
justify-content: flex-start;
align-items: center;
padding: 12px 16px;
box-sizing: border-box;
position: relative;
}
.backgroundTitleTextIcon {
visibility: hidden;
}
.backgroundTitleTextIconShow {
visibility: visible;
}
.backgroundTitleText {
font-size: 16px;
font-weight: 600;
line-height: 24px;
color: rgba(30, 38, 51, 1);
margin-left: 12px;
}
.taskDescIcon {
margin-left: 8px;
}
.flowDescIcon {
margin-left: 8px;
}
.formItems {
padding: 20px 44px 40px 44px;
}
.formItem {
margin-bottom: 20px;
}
.fileSelectImg {
cursor: pointer;
}
.formItemLable {
margin-bottom: 12px;
font-size: 14px;
color: rgba(30, 38, 51, 1);
line-height: 22px;
font-weight: 600;
}
.required::after {
content: "*";
color: red;
margin-left: 3px;
}
.taskConfigBox {
padding: 24px 44px 40px 44px;
}
.flowTitle {
line-height: 16px;
margin: 3px 0 27px;
color: rgba(30, 38, 51, 1);
font-size: 14px;
font-weight: 600;
border-left: 3px solid rgba(19, 112, 255, 1);
padding-left: 3px;
display: flex;
align-items: center;
}
.parameter {
margin-bottom: 20px;
position: relative;
}
.parameterTitle {
color: rgba(30, 38, 51, 1);
font-size: 14px;
font-weight: 600;
line-height: 22px;
margin-bottom: 12px;
}
.parameterContent {
position: relative;
}
.parameterDesc {
position: absolute;
top: 12px;
right: -22px;
}
.parameterDataType {
color: rgba(138, 144, 153, 1);
margin-left: 16px;
}
This diff is collapsed.
/*
* @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
* @FilePath: /bkunyun/src/views/Project/ProjectSubmitWork/WorkFlow/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import Flow from "../../components/Flow";
import { ITemplateConfig } from "../interface";
interface IProps {
templateConfigInfo?: ITemplateConfig;
setSelectedNodeId?: (val:string) => void;
selectedNodeId?: string;
}
const WorkFlow = (props: IProps) => {
const { templateConfigInfo,setSelectedNodeId, selectedNodeId } = props;
return <Flow tasks={templateConfigInfo?.tasks} setSelectedNodeId={setSelectedNodeId} selectedNodeId={selectedNodeId}/>;
};
export default WorkFlow;
import React from "react";
// import { MarkerType } from "react-flow-renderer";
export const nodes = [
{
id: "1",
type: "input",
data: {
label: (
<>
Welcome to <strong>React Flow!</strong>
</>
),
},
position: { x: 250, y: 0 },
},
{
id: "2",
data: {
label: (
<>
This is a <strong>default node</strong>
</>
),
},
position: { x: 100, y: 100 },
},
{
id: "3",
data: {
label: (
<>
This one has a <strong>custom style</strong>
</>
),
},
position: { x: 400, y: 100 },
style: {
background: "#D6D5E6",
color: "#333",
border: "1px solid #222138",
width: 180,
},
},
{
id: "4",
position: { x: 250, y: 200 },
data: {
label: "Another default node",
},
},
{
id: "5",
data: {
label: "Node id: 5",
},
position: { x: 250, y: 325 },
},
{
id: "6",
type: "output",
data: {
label: (
<>
An <strong>output node</strong>
</>
),
},
position: { x: 100, y: 480 },
},
{
id: "7",
type: "output",
data: { label: "Another output node" },
position: { x: 400, y: 450 },
},
];
export const edges = [
{ id: "e1-2", source: "1", target: "2", label: "this is an edge label" },
{ id: "e1-3", source: "1", target: "3" },
{
id: "e3-4",
source: "3",
target: "4",
animated: true,
label: "animated edge",
},
{
id: "e4-5",
source: "4",
target: "5",
label: "edge with arrow head",
},
{
id: "e5-6",
source: "5",
target: "6",
type: "smoothstep",
label: "smooth step edge",
},
{
id: "e5-7",
source: "5",
target: "7",
type: "step",
style: { stroke: "#f6ab6c" },
label: "a step edge",
animated: true,
labelStyle: { fill: "#f6ab6c", fontWeight: 700 },
},
];
import * as React from "react";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import FormHelperText from "@mui/material/FormHelperText";
import Select, { SelectProps } from "@mui/material/Select";
export interface IOption {
label: string;
value: string;
disabled?: boolean;
}
export const optionsTransform = (
arr: Array<any>,
labelKey: string = "label",
valueKey: string = "value",
disabledKey: string = "disabled"
): Array<IOption> => {
return arr.map((item: any) => {
return {
label: item[labelKey],
value: item[valueKey],
disabled: item[disabledKey],
};
});
};
interface IProps
extends Omit<SelectProps, "value" | "options" | "onChange" | "title"> {
value?: any;
options: IOption[];
onChange?: any;
/** 类型变种 */
variant?: "standard" | "outlined" | "filled";
/** title */
title?: string;
/** 是否显示title */
isTitle?: boolean;
size?: "small" | "medium";
multiple?: boolean; // 多选
error?: boolean;
helpertext?: string;
}
export default function MySelect(props: IProps) {
const {
value,
options,
onChange,
title,
isTitle = false,
variant,
size = "small",
multiple = false,
error = false,
helpertext,
} = props;
return (
<FormControl fullWidth variant={variant} error={error}>
{isTitle ? (
<InputLabel id="demo-simple-select-label">
{title || "请选择"}
</InputLabel>
) : null}
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
label={title || ""}
size={size}
{...props}
value={value}
onChange={onChange}
multiple={multiple}
>
{options.length
? options?.map((item: IOption) => {
return (
<MenuItem
key={item.value}
value={item.value}
disabled={item?.disabled}
>
{item.label}
</MenuItem>
);
})
: null}
</Select>
{helpertext && error && <FormHelperText>{helpertext}</FormHelperText>}
</FormControl>
);
}
.swBox {
position: fixed;
z-index: 1000;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: RGBA(247, 248, 250, 1);
overflow-y: scroll;
}
.swHeader {
z-index: 1001;
position: sticky;
top: 0;
height: 56px;
background-color: #fff;
box-shadow: 0px 3px 10px 0px rgba(0, 24, 57, 0.04);
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 24px;
}
.swHeaderLeft {
display: flex;
justify-content: flex-start;
align-items: center;
}
.swTemplateTitle {
margin: 0 19px 0 8px;
line-height: 22px;
font-size: 14px;
color: rgba(30, 38, 51, 1);
font-weight: 600;
padding-right: 20px;
border-right: 1px solid rgba(235, 237, 240, 1);
}
.swHeaderLable {
color: rgba(138, 144, 153, 1);
font-size: 12px;
}
.swHeaderValue {
color: rgba(30, 38, 51, 1);
font-size: 12px;
margin-right: 24px;
}
.swContent {
display: flex;
height: calc(100vh - 56px);
}
.swFormBox {
background-color: #fff;
border-right: 1xp solid rgba(235, 237, 240, 1);
width: 608px;
overflow-y: scroll;
box-sizing: border-box;
padding: 36px;
}
.swFlowBox {
flex: 1;
height: calc(100vh - 56px);
}
.fullScreenBox {
position: absolute;
background-color: #fff;
cursor: pointer;
z-index: 1000;
right: 24px;
bottom: 24px;
padding: 8px;
}
.fullScreenBox:hover {
opacity: 0.6;
}
\ No newline at end of file
/*
* @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
* @FilePath: /bkunyun/src/views/Project/ProjectSubmitWork/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { toJS } from "mobx";
import React, { useEffect, useState } from "react";
import ArrowBackIosNewIcon from "@mui/icons-material/ArrowBackIosNew";
import IconButton from "@mui/material/IconButton";
import _ from "lodash";
import { useLocation, useNavigate } from "react-router-dom";
import moment from "moment";
import ConfigForm from "./ConfigForm";
import WorkFlow from "./WorkFlow";
import ButtonComponent from "@/components/mui/Button";
import { ITemplateConfig } from "./interface";
import useMyRequest from "@/hooks/useMyRequest";
import { fetchTemplateConfigInfo, submitWorkFlow } from "@/api/project_api";
import { getCheckResult } from "./util";
import { IResponse } from "@/api/http";
import fullScreen from "@/assets/project/fullScreen.svg";
import partialScreen from "@/assets/project/partialScreen.svg";
import { useMessage } from "@/components/MySnackbar";
import { useStores } from "@/store";
import MyPopconfirm from "@/components/mui/MyPopconfirm";
import styles from "./index.module.css";
const ProjectSubmitWork = () => {
const Message = useMessage();
const { currentProjectStore } = useStores();
const projectId = toJS(currentProjectStore.currentProjectInfo.id);
const [templateConfigInfo, setTemplateConfigInfo] =
useState<ITemplateConfig>();
const location: any = useLocation();
const navigate = useNavigate();
let configFormRef: any = React.createRef();
/** 是否全屏 */
const [fullScreenShow, setFullScreenShow] = useState<boolean>(false);
const [selectedNodeId, setSelectedNodeId] = useState<string>("");
// 前往工作台
const goToWorkbench = (toWorkbenchList = false) => {
navigate("/product/cadd/projectWorkbench", {
state: { type: toWorkbenchList ? "workbenchList" : "" },
});
};
// 返回
const handleGoBack = () => {
goToWorkbench();
};
if (!location?.state?.id) {
goToWorkbench();
}
/** 获取模版数据 */
const { run } = useMyRequest(fetchTemplateConfigInfo, {
onSuccess: (res: IResponse<ITemplateConfig>) => {
// setTemplateConfigInfo(templateConfigJson as ITemplateConfig);
res.data.tasks.forEach((task) => {
// 设置默认值
task.parameters.forEach((parameter) => {
let value: any = undefined;
if (parameter.defaultValue) {
if (
parameter.domType.toLowerCase() === "multipleselect" ||
parameter.domType.toLowerCase() === "checkbox"
) {
value = parameter.defaultValue.split(",");
} else {
value = parameter.defaultValue;
}
} else if (
parameter.domType.toLowerCase() === "multipleselect" ||
parameter.domType.toLowerCase() === "checkbox"
) {
value = [];
} else {
value = "";
}
parameter.value = value;
});
// 设置右边流程图某个节点是否通过(绿点)
let isCheck = true;
task.parameters
.filter((parameter) => parameter.hidden === false)
.forEach((parameter) => {
if (getCheckResult(parameter, parameter.value).error === true) {
isCheck = false;
}
});
task.isCheck = isCheck;
});
setTemplateConfigInfo(res.data);
configFormRef.current.setInitName(res.data.title);
},
onError: () => {
// setTemplateConfigInfo(templateConfigJson as ITemplateConfig);
},
});
const { run: submitWorkFlowRun } = useMyRequest(submitWorkFlow, {
onSuccess: (res) => {
Message.success("提交成功");
goToWorkbench(true);
},
});
useEffect(() => {
run({
id: location?.state?.id,
});
}, [location?.state?.id, run]);
const setParameter = (value: any, taskId: string, parameterName: string) => {
const result: ITemplateConfig = _.cloneDeep(templateConfigInfo);
result.tasks.forEach((task) => {
if (task.id === taskId) {
let isCheck = true;
task.parameters
.filter((parameter) => parameter.hidden === false)
.forEach((parameter) => {
if (parameter.name === parameterName) {
parameter.value = value;
const checkResult = getCheckResult(parameter, value);
parameter.error = checkResult.error;
parameter.helperText = checkResult.helperText;
}
if (getCheckResult(parameter, parameter.value).error === true) {
isCheck = false;
}
});
task.isCheck = isCheck;
} else {
return;
}
});
setTemplateConfigInfo(result);
};
const handleSubmitForm = () => {
let check = true;
const { name, outputPath, nameAndOutputPathCheck } =
configFormRef.current.getNameAndPath();
if (!nameAndOutputPathCheck) {
check = false;
}
const result: ITemplateConfig = _.cloneDeep(templateConfigInfo);
result.tasks.forEach((tack) => {
tack.parameters
.filter((parameter) => parameter.hidden === false)
.forEach((parameter) => {
const checkResult = getCheckResult(parameter, parameter.value);
parameter.error = checkResult.error;
parameter.helperText = checkResult.helperText;
if (checkResult.error) {
check = false;
}
});
});
setTemplateConfigInfo(result);
if (check) {
let promotedParameters: any = {};
result.tasks.forEach((tack) => {
tack.parameters
.filter((parameter) => parameter.hidden === false)
.forEach((parameter) => {
let value: string = "";
if (Array.isArray(parameter.value)) {
value = parameter.value.join(",");
} else {
value = parameter.value;
}
if (
parameter.domType.toLowerCase() === "path" ||
parameter.domType.toLowerCase() === "dataset" ||
parameter.domType.toLowerCase() === "file"
) {
if (value === "ProjectData") {
value = "/home/cloudam";
} else {
value = `/home/cloudam${value.slice(11)}`;
}
}
promotedParameters[parameter.name] = {
[parameter.classTypeName]: value,
};
});
});
submitWorkFlowRun({
name,
outputPath:
outputPath === "ProjectData"
? "/home/cloudam"
: `/home/cloudam${outputPath.slice(11)}`,
projectId: projectId as string,
specId: templateConfigInfo?.id as string,
promotedParameters,
});
} else {
Message.error("请完善左侧表单再提交");
}
};
return (
<div className={styles.swBox}>
{fullScreenShow ? null : (
<div className={styles.swHeader}>
<div className={styles.swHeaderLeft}>
<MyPopconfirm
title="返回后,当前页面已填写内容将不保存,确认返回吗?"
onConfirm={handleGoBack}
>
<IconButton
color="primary"
// onClick={() => handleGoBack()}
aria-label="upload picture"
component="span"
size="small"
>
<ArrowBackIosNewIcon
sx={{
color: "rgba(194, 198, 204, 1)",
width: "12px",
height: "12px",
}}
/>
</IconButton>
</MyPopconfirm>
<div className={styles.swTemplateTitle}>
{templateConfigInfo?.title}
</div>
<div className={styles.swTemplateVersionBox}>
<span className={styles.swHeaderLable}>版本:</span>
<span className={styles.swHeaderValue}>
{templateConfigInfo?.version}
</span>
</div>
<div className={styles.swTemplateUpdateTimeBox}>
<span className={styles.swHeaderLable}>更新时间:</span>
<span className={styles.swHeaderValue}>
{templateConfigInfo?.updateTime
? moment(templateConfigInfo?.updateTime).format(
"YYYY-MM-DD HH:mm:ss"
)
: "-"}
</span>
</div>
<div className={styles.swHeaderGoback}></div>
</div>
<div className={styles.swHeaderRight}>
<MyPopconfirm
title="提交前请先确认参数填写无误,确认提交吗?"
onConfirm={handleSubmitForm}
>
<ButtonComponent
text="提交任务"
// click={handleSubmitForm}
></ButtonComponent>
</MyPopconfirm>
</div>
</div>
)}
<div className={styles.swContent}>
{fullScreenShow ? null : (
<div className={styles.swFormBox}>
<ConfigForm
onRef={configFormRef}
templateConfigInfo={templateConfigInfo}
setParameter={setParameter}
setSelectedNodeId={setSelectedNodeId}
/>
</div>
)}
<div
className={styles.swFlowBox}
style={fullScreenShow ? { height: "100vh" } : undefined}
>
<WorkFlow
templateConfigInfo={templateConfigInfo}
setSelectedNodeId={setSelectedNodeId}
selectedNodeId={selectedNodeId}
/>
</div>
</div>
<img
className={styles.fullScreenBox}
src={fullScreenShow ? partialScreen : fullScreen}
onClick={() => setFullScreenShow(!fullScreenShow)}
alt="全屏"
/>
</div>
);
};
export default ProjectSubmitWork;
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-21 20:03:56
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-07 17:39:49
* @FilePath: /bkunyun/src/views/Project/ProjectSubmitWork/interface.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
type IType = "BATCH" | "FLOW";
export interface IParameter {
hidden: boolean;
id?: string;
name: string;
required: boolean;
defaultValue: any;
domType: IDomType;
classType: string;
classTypeName: string;
value: any;
description: string;
language: string;
languageVersion: string;
tags: Array<string>;
source: string;
productId: string;
tasks: ITask[];
validators: Array<IValidator>;
choices: Array<IChoice>;
error?: boolean;
helperText?: string;
parameterGroup?: string;
}
export type IExecutionStatus = "Pending" | "Running" | "Done" | "Failed";
export interface ITask {
id: string;
title: string;
description: string;
version?: string;
position: {
x: number;
y: number;
};
tags?: string[];
type: IType | string;
parentNode?: string;
parameters: Array<IParameter>;
edges: Array<IEdge>;
isCheck?: boolean;
executionStatus?: IExecutionStatus;
}
export interface ITemplateConfig {
title: string;
version: string;
updateTime?: string;
description: string;
language: string;
languageVersion: string;
tags: Array<string>;
source: string;
productId: string;
tasks: ITask[];
id: string;
}
export type IDomType =
| "path"
| "dataset"
| "file"
| "input"
| "file"
| "select"
| "multipleselect"
| "radio"
| "checkbox";
// 待定
export type IValidator = {
regex: string;
message: string;
};
export interface IChoice {
key: string;
value: boolean | string | number;
}
export interface IEdge {
id: string;
source: string;
sourceHandle: string;
target: string;
targetHandle: string;
label: string;
}
// 提交任务时的动态表单的数据结构
export type IRenderTasks = Array<IRenderTask>;
export type IRenderTask = {
id: string;
title: string;
description: string;
position: {
x: number;
y: number;
};
type: IType | string;
parameters: Array<IParameter>;
edges: Array<IEdge>;
flows: ITask[];
isCheck: boolean; // 里面的子项表单校验是否全部通过
};
export interface ITaskInfo extends ITemplateConfig {
name: string;
outputPath: string;
state: IState;
specTitle: string;
specVersion: string;
jobCost: string;
creator: string;
createTime: string;
costTime: string;
logPath: string;
outputs?: any;
}
type IState = "SUCCEEDED" | "RUNNING" | "ABORTED" | "FAILED";
This diff is collapsed.
import { IParameter } from "./interface";
export const getCheckResult = (
parameter: IParameter,
value: string
): {
error: boolean;
helperText: string;
} => {
let error = false;
let helperText = "";
// 表单校验
if (parameter.required) {
if (Array.isArray(value)) {
if (value.length === 0) {
error = true;
helperText = "该选项是必填项";
}
} else if (value === "" || value === null || value === undefined) {
error = true;
helperText = "该选项是必填项";
}
}
if (parameter.validators.length > 0) {
parameter.validators.forEach((validator) => {
const reg = new RegExp(validator.regex);
if (!reg.test(value)) {
error = true;
helperText = validator.message;
}
});
}
return {
error,
helperText,
};
};
/* /*
* @Author: rocosen * @Author: rocosen
* @Date: 2022-06-12 10:05:13 * @Date: 2022-06-12 10:05:13
* @LastEditors: rocosen * @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-07 20:23:02 * @LastEditTime: 2022-07-04 20:23:26
* @FilePath: /bkunyun/src/views/Project/ProjectSetting/index.tsx * @FilePath: /bkunyun/src/views/Project/ProjectSetting/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 { memo, useState, useMemo, useEffect } from "react"; import { memo, useMemo } from "react";
import { Box } from "@mui/system"; import { Box } from "@mui/system";
import { useStores } from "@/store/index";
import NoProject from "@/components/NoProject";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useLocation } from "react-router-dom";
import projectImg from "@/assets/project/projectIconSmall.svg"; import projectImg from "@/assets/project/projectIconSmall.svg";
import WorkbenchTemplate from "./workbenchTemplate"; import WorkbenchTemplate from "./workbenchTemplate";
import WorkbenchList from "./workbenchList"; import WorkbenchList from "./workbenchList";
import Tabs from "@/components/mui/Tabs"; import Tabs from "@/components/mui/Tabs";
import usePass from "@/hooks/usePass"; import usePass from "@/hooks/usePass";
import Template from "@/assets/project/workbenchTemplate.svg";
import Template from "@/assets/project/workbenchTemplate.svg" import Template_select from "@/assets/project/workbenchTemplate_select.svg";
import Template_select from "@/assets/project/workbenchTemplate_select.svg" import List from "@/assets/project/workbenchList.svg";
import List from "@/assets/project/workbenchList.svg" import List_select from "@/assets/project/workbenchList_select.svg";
import List_select from "@/assets/project/workbenchList_select.svg"
//ui
import ButtonDemo from "@/views/mui_demo/button"
import InputDemo from "@/views/mui_demo/input"
const ProjectWorkbench = observer(() => { const ProjectWorkbench = observer(() => {
const { currentProjectStore } = useStores();
const isPass = usePass(); const isPass = usePass();
const location: any = useLocation();
useEffect(() => {
console.log(isPass("PROJECT_WORKBENCH_FLOES_USE", 'USER'), "11111111111");
console.log(isPass("PROJECT_WORKBENCH_FLOES"), 'wwwwwwwwwww')
}, [])
const tabList = useMemo(() => { const tabList = useMemo(() => {
return [ return [
...@@ -46,7 +33,7 @@ const ProjectWorkbench = observer(() => { ...@@ -46,7 +33,7 @@ const ProjectWorkbench = observer(() => {
component: <WorkbenchTemplate />, component: <WorkbenchTemplate />,
hide: !isPass("PROJECT_WORKBENCH_FLOES"), hide: !isPass("PROJECT_WORKBENCH_FLOES"),
icon: Template, icon: Template,
iconed: Template_select iconed: Template_select,
}, },
{ {
label: "任务列表", label: "任务列表",
...@@ -54,36 +41,36 @@ const ProjectWorkbench = observer(() => { ...@@ -54,36 +41,36 @@ const ProjectWorkbench = observer(() => {
component: <WorkbenchList />, component: <WorkbenchList />,
hide: !isPass("PROJECT_WORKBENCH_JOBS"), hide: !isPass("PROJECT_WORKBENCH_JOBS"),
icon: List, icon: List,
iconed: List_select iconed: List_select,
},
{
label: "按钮组件",
value: "MUI_BUTTON",
component: <ButtonDemo />,
icon: List,
iconed: List_select
},
{
label: "输入框组件",
value: "MUI_INPUT",
component: <InputDemo />,
icon: List,
iconed: List_select
}, },
// {
// label: "按钮组件",
// value: "MUI_BUTTON",
// component: <ButtonDemo />,
// icon: List,
// iconed: List_select,
// },
// {
// label: "输入框组件",
// value: "MUI_INPUT",
// component: <InputDemo />,
// icon: List,
// iconed: List_select,
// },
]; ];
}, []); }, [isPass]);
return ( return (
<div style={{ padding: 24 }}> <div style={{ padding: 24 }}>
<div style={{ display: "flex", alignItems: "center" }}> <div style={{ display: "flex", alignItems: "center" }}>
<img src={projectImg} alt="项目logo" /> <img src={projectImg} alt="项目logo" />
<span style={{ marginLeft: 12 }}> <span style={{ marginLeft: 12 }}>工作台</span>
工作台
</span>
</div> </div>
<Box sx={{ width: "100%", typography: "body1" }}> <Box sx={{ width: "100%", typography: "body1" }}>
<Tabs tabList={tabList} /> <Tabs
tabList={tabList}
defaultValue={location?.state?.type || "workbenchTemplate"}
/>
</Box> </Box>
</div> </div>
); );
......
...@@ -2,24 +2,25 @@ ...@@ -2,24 +2,25 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com * @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:18:13 * @Date: 2022-05-31 10:18:13
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com * @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-07 21:39:30 * @LastEditTime: 2022-06-28 11:30:27
* @FilePath: /bkunyun/src/views/Project/ProjectSetting/index.tsx * @FilePath: /bkunyun/src/views/Project/ProjectSetting/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 { memo, useEffect, useState } from "react"; import { memo, useCallback, useEffect, useState } from "react";
import _ from "lodash"; import _ from "lodash";
import { useStores } from "@/store"; import { useNavigate } from "react-router-dom";
import styles from "./index.module.css";
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import OutlinedInput from "@mui/material/OutlinedInput"; import OutlinedInput from "@mui/material/OutlinedInput";
import SearchIcon from "@mui/icons-material/Search"; import SearchIcon from "@mui/icons-material/Search";
import useMyRequest from "@/hooks/useMyRequest";
import LinearProgress, { linearProgressClasses } from '@mui/material/LinearProgress'; import LinearProgress, { linearProgressClasses } from '@mui/material/LinearProgress';
import { TablePagination } from '@mui/material'; import { TablePagination } from '@mui/material';
import ActionsComponent from "../../../../components/Material.Ui/Table/ActionsComponent"
import TextField from '@mui/material/TextField'; import TextField from '@mui/material/TextField';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import SimpleDialog from "./components/simpleDialog" import SimpleDialog from "./components/simpleDialog"
import { useStores } from "@/store";
import useMyRequest from "@/hooks/useMyRequest";
import ActionsComponent from "../../../../components/Material.Ui/Table/ActionsComponent"
import runTime from '../../../../assets/project/runTime.svg' import runTime from '../../../../assets/project/runTime.svg'
import jobCost from '../../../../assets/project/jobCost.svg' import jobCost from '../../../../assets/project/jobCost.svg'
import jobSue from '../../../../assets/project/jobSue.svg' import jobSue from '../../../../assets/project/jobSue.svg'
...@@ -39,6 +40,9 @@ import { toJS } from "mobx"; ...@@ -39,6 +40,9 @@ import { toJS } from "mobx";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import usePass from "@/hooks/usePass"; import usePass from "@/hooks/usePass";
import styles from "./index.module.css";
const currencies = [ const currencies = [
{ {
value: 'ALL', value: 'ALL',
...@@ -93,6 +97,7 @@ const ProjectMembers = observer(() => { ...@@ -93,6 +97,7 @@ const ProjectMembers = observer(() => {
}, 60000); }, 60000);
}, },
}); });
const navigate = useNavigate()
// 删除作业 // 删除作业
const { run: delWorkflowJob } = useMyRequest(deleteWorkflowJob, { const { run: delWorkflowJob } = useMyRequest(deleteWorkflowJob, {
...@@ -238,6 +243,16 @@ const ProjectMembers = observer(() => { ...@@ -238,6 +243,16 @@ const ProjectMembers = observer(() => {
} }
} }
/** 点击每一行 */
const rowClick = useCallback(
(id: string) => {
navigate(`/product/cadd/projectJobDetail`, {
state: { taskId: id },
});
},
[navigate],
);
return ( return (
<Box className={styles.headerBox}> <Box className={styles.headerBox}>
...@@ -312,7 +327,7 @@ const ProjectMembers = observer(() => { ...@@ -312,7 +327,7 @@ const ProjectMembers = observer(() => {
{ {
jobList.length > 0 && jobList.map((item: any, key) => { jobList.length > 0 && jobList.map((item: any, key) => {
return ( return (
<Box className={styles.tabBox}> <Box className={styles.tabBox} onClick={()=>rowClick(item.id)}>
<Box className={styles.tabBoxInfo}> <Box className={styles.tabBoxInfo}>
<div className={styles.tabBoxTitle}>{item.name}</div> <div className={styles.tabBoxTitle}>{item.name}</div>
<Box className={styles.tabBoxDescInfo}> <Box className={styles.tabBoxDescInfo}>
......
.addTemplateBox {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.78);
z-index: 100;
display: flex;
flex-direction: column;
}
.closeBox {
display: flex;
justify-content: flex-end;
height: 40px;
align-items: center;
/* background-color: ; */
}
.content {
flex: 1;
background-color: #fff;
border-radius: 16px 0 0 0;
padding: 24px 32px;
box-sizing: border-box;
overflow: scroll;
}
.templateList {
/* height: 2000px; */
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.templateLi {
height: 146px;
box-sizing: border-box;
padding: 16px 20px;
cursor: pointer;
border: 1px solid rgba(235, 237, 240, 1);
border-radius: 4px;
min-width: 20%;
flex: 1;
margin-right: 16px;
margin-bottom: 16px;
}
.templateLiCustom {
height: 194px;
}
.templateLiHidden {
visibility: hidden;
}
.addCustomTemplate {
height: 194px;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.addCustomTemplateText {
margin-top: 12px;
line-height: 22px;
font-size: 14px;
color: rgba(138, 144, 153, 1);
}
.templateLi:hover {
box-shadow: 6px 8px 22px 0px rgba(0, 24, 57, 0.08);
}
.templateLi:nth-child(4n) {
margin-right: 0;
}
.templateLiTop {
display: flex;
justify-content: space-between;
align-items: center;
}
.templateTitle {
font-size: 14px;
font-weight: 600;
color: #1e2633;
margin-bottom: 4px;
overflow: hidden;
text-overflow: ellipsis;
line-height: 22px;
}
.templateLiInfo {
margin-bottom: 8px;
}
.templateLiInfoText {
line-height: 20px;
font-size: 12px;
color: rgba(19, 112, 255, 1);
}
.templateLiDesc {
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
display: -webkit-box;
height: 54px;
font-size: 12px;
color: rgba(138, 144, 153, 1);
}
.templateLiEditBox {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
import { memo, useEffect, useState, useMemo } from "react";
import style from "./index.module.css";
import classNames from "classnames";
import CloseOutlinedIcon from "@mui/icons-material/CloseOutlined";
import { Box, Typography } from "@mui/material";
import RadioGroupOfButtonStyle from "@/components/CommonComponents/RadioGroupOfButtonStyle";
import SearchIcon from "@mui/icons-material/Search";
import Button from "@/components/mui/Button";
import OutlinedInput from "@mui/material/OutlinedInput";
import Checkbox from "@mui/material/Checkbox";
import useMyRequest from "@/hooks/useMyRequest";
import AddIcon from "@mui/icons-material/Add";
import { useStores } from "@/store";
import WorkFlowEdit from "@/views/WorkFlowEdit";
import _ from "lodash";
import { observer } from "mobx-react-lite";
import noData from "../../../../../../assets/project/noTemplate.svg";
import { ICustomTemplate } from "../../interface";
import { getAddWorkbenchTemplate } from "@/api/workbench_api";
import { toJS } from "mobx";
type IAddTemplateProps = {
setShowAddTemplate: any;
};
const radioOptions = [
{
value: "public",
label: "公共",
},
{
value: "custom",
label: "自定义",
},
];
const AddTemplate = observer((props: IAddTemplateProps) => {
const { currentProjectStore } = useStores();
const projectId = toJS(currentProjectStore.currentProjectInfo.id);
const productId = toJS(currentProjectStore.currentProductInfo.id);
const { setShowAddTemplate } = props;
const handleSearch = (value: string) => {
console.log(value);
};
/** 可增加模板列表 */
const [addTemplateList, setAddTemplateList] = useState([]);
/** 已选择增加的模板列表 */
const [selectTemplateData, setSelectTemplateData] = useState<string[]>([]);
const [templateType, setTemplateType] = useState("public");
const handleRadio = (value: string) => {
setTemplateType(value);
};
const handleAddTemplate = () => {
console.log("handleAddTemplate");
};
// 添加工作流模板-获取模板列表
const { run: getAddTemplateList } = useMyRequest(getAddWorkbenchTemplate, {
onSuccess: (result: any) => {
console.log(result);
setAddTemplateList(result.data);
// setOpenAddTemplate(true);
},
});
/** 是否显示自定义模版编辑并带有参数 */
const [customTemplateInfo, setCustomTemplateInfo] = useState<ICustomTemplate>(
{
show: false,
}
);
// 显示新增、编辑自定义模板弹窗
const handleAddCustomTemplate = () => {
setCustomTemplateInfo({
show: true,
});
};
useEffect(() => {
getAddTemplateList({
projectId: projectId as string,
productId: productId as string,
});
}, [getAddTemplateList, projectId, productId]);
const hiddenBoxArr = useMemo(() => {
const length =
templateType === "public"
? addTemplateList.length
: addTemplateList.length + 1;
const hiddenBoxNumber = 4 - (length % 4);
const arr = new Array(hiddenBoxNumber).fill("");
return arr;
}, [addTemplateList, templateType]);
return (
<div className={style.addTemplateBox}>
<div className={style.closeBox}>
<CloseOutlinedIcon
sx={{ color: "#ffffff", marginRight: "10px", cursor: "pointer" }}
onClick={() => {
setShowAddTemplate(false);
}}
/>
</div>
<div className={style.content}>
<Typography
sx={{ fontSize: "18px", fontWeight: "600", color: "#1E2633" }}
>
添加工作流模版
</Typography>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginBottom: "20px",
}}
>
<OutlinedInput
onChange={(e: any) => {
_.debounce(() => {
// searchTemplateNameCallback(e.target.value);
handleSearch(e.target.value);
}, 200)();
}}
placeholder="输入关键词搜索"
size="small"
sx={{ width: 340, height: 32, marginTop: "20px" }}
endAdornment={<SearchIcon style={{ color: "#8A9099" }} />}
/>
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
alignItems: "center",
}}
>
<RadioGroupOfButtonStyle
value={templateType}
radioOptions={radioOptions}
handleRadio={handleRadio}
></RadioGroupOfButtonStyle>
<Button
// click={addTemplateCallback}
click={handleAddTemplate}
size={"small"}
style={{
marginLeft: "12px",
}}
text={
"添加模版" +
(selectTemplateData.length === 0
? ""
: `(${selectTemplateData.length})`)
}
/>
</Box>
</Box>
{templateType === "public" && addTemplateList.length === 0 && (
<Box
sx={{
display: "flex",
alignItems: "center",
flexDirection: "column",
minHeight: "calc(100vh - 376px)",
justifyContent: "center",
}}
>
<img alt="" src={noData} />
<Typography
sx={{ fontSize: "12px", fontWeight: "400", color: "#8A9099" }}
>
暂无相关模版
</Typography>
</Box>
)}
<div className={style.templateList}>
{templateType !== "public" && (
<div
className={classNames({
[style.templateLi]: true,
[style.addCustomTemplate]: true,
})}
onClick={handleAddCustomTemplate}
>
<AddIcon />
<span className={style.addCustomTemplateText}>
创建自定义模板
</span>
</div>
)}
{addTemplateList.map((item: any, index) => {
return (
<div
className={classNames({
[style.templateLi]: true,
[style.templateLiCustom]: templateType !== "public",
})}
key={index}
>
<div className={style.templateLiTop}>
<span className={style.templateTitle}>{item.title}</span>
<Checkbox
size="small"
sx={{ padding: "0px" }}
checked={selectTemplateData.includes(item.id)}
/>
</div>
<div className={style.templateLiInfo}>
<span
className={style.templateLiInfoText}
style={{ marginRight: "24px" }}
>
版本:{item.version}
</span>
<span className={style.templateLiInfoText}>
更新时间:{item.updateTime}
</span>
</div>
<div className={style.templateLiDesc}>{item.description}</div>
{templateType !== "public" && (
<div className={style.templateLiEditBox}>
<Button
click={handleAddTemplate}
size={"small"}
style={{
height: "32px",
}}
color="inherit"
text="编辑模板"
/>
</div>
)}
</div>
);
})}
{hiddenBoxArr.length !== 4 &&
hiddenBoxArr.map((item, index) => {
return (
<div
key={`-${index}`}
className={classNames({
[style.templateLi]: true,
[style.templateLiHidden]: true,
})}
/>
);
})}
</div>
</div>
{customTemplateInfo?.show ? (
<WorkFlowEdit
onBack={() =>
setCustomTemplateInfo({
id: "",
show: false,
})
}
/>
) : null}
</div>
);
});
export default AddTemplate;
import { memo, useCallback, useEffect, useMemo, useState } from "react"; import { memo, useCallback, useEffect, useMemo, useState } from "react";
import styles from "../index.module.css"; import styles from "../index.module.css";
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import Button from "@/components/mui/Button"; import Button from "@/components/mui/Button";
import Dialog from "@/components/mui/Dialog"; import Dialog from "@/components/mui/Dialog";
import OutlinedInput from "@mui/material/OutlinedInput"; import OutlinedInput from "@mui/material/OutlinedInput";
import RadioGroupOfButtonStyle from "@/components/CommonComponents/RadioGroupOfButtonStyle";
import SearchIcon from "@mui/icons-material/Search"; import SearchIcon from "@mui/icons-material/Search";
import Checkbox from '@mui/material/Checkbox'; import Checkbox from "@mui/material/Checkbox";
import CloseOutlinedIcon from '@mui/icons-material/CloseOutlined'; import CloseOutlinedIcon from "@mui/icons-material/CloseOutlined";
import noData from '../../../../../assets/project/noTemplate.svg' import noData from "../../../../../assets/project/noTemplate.svg";
import _ from "lodash"; import _ from "lodash";
const AddTemplate = (props: any) => { const AddTemplate = (props: any) => {
const { openAddTemplate, closeAddTemplateBlock, addTemplateList, templateSelectCallback, selectTemplateData, addTemplateCallback, searchTemplateNameCallback } = props; const {
openAddTemplate,
closeAddTemplateBlock,
addTemplateList,
templateSelectCallback,
selectTemplateData,
addTemplateCallback,
searchTemplateNameCallback,
} = props;
const [templateType, setTemplateType] = useState("public");
const radioOptions = [
{
value: "public",
label: "公共",
},
{
value: "custom",
label: "自定义",
},
];
const handleRadio = (value: string) => {
setTemplateType(value);
};
return ( return (
<Box className={styles.addTemplateMask} sx={{ display: openAddTemplate ? 'flex' : 'none' }} > <Box
<Box sx={{ height: '50px', display: 'flex', alignItems: 'center' }} > className={styles.addTemplateMask}
<CloseOutlinedIcon sx={{ color: "#ffffff", marginRight: "10px", cursor: "pointer" }} onClick={() => { sx={{ display: openAddTemplate ? "flex" : "none" }}
closeAddTemplateBlock() >
}} /> <Box sx={{ height: "50px", display: "flex", alignItems: "center" }}>
<CloseOutlinedIcon
sx={{ color: "#ffffff", marginRight: "10px", cursor: "pointer" }}
onClick={() => {
closeAddTemplateBlock();
}}
/>
</Box> </Box>
<Box className={styles.addTemplateBlock}> <Box className={styles.addTemplateBlock}>
<Box sx={{ padding: "24px 32px" }}> <Box sx={{ padding: "24px 32px" }}>
<Typography sx={{ fontSize: '18px', fontWeight: '600', color: "#1E2633" }}>添加工作流模版</Typography> <Typography
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: "20px" }}> sx={{ fontSize: "18px", fontWeight: "600", color: "#1E2633" }}
>
添加工作流模版
</Typography>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginBottom: "20px",
}}
>
<OutlinedInput <OutlinedInput
onChange={(e: any) => { onChange={(e: any) => {
_.debounce(() => { _.debounce(() => {
searchTemplateNameCallback(e.target.value) searchTemplateNameCallback(e.target.value);
}, 200)(); }, 200)();
}} }}
placeholder="输入关键词搜索" placeholder="输入关键词搜索"
...@@ -36,45 +77,128 @@ const AddTemplate = (props: any) => { ...@@ -36,45 +77,128 @@ const AddTemplate = (props: any) => {
sx={{ width: 340, height: 32, marginTop: "20px" }} sx={{ width: 340, height: 32, marginTop: "20px" }}
endAdornment={<SearchIcon style={{ color: "#8A9099" }} />} endAdornment={<SearchIcon style={{ color: "#8A9099" }} />}
/> />
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
alignItems: "center",
}}
>
<RadioGroupOfButtonStyle
value={templateType}
radioOptions={radioOptions}
handleRadio={handleRadio}
></RadioGroupOfButtonStyle>
<Button <Button
click={addTemplateCallback} click={addTemplateCallback}
size={"small"} size={"small"}
text={'添加模版' + (selectTemplateData.length === 0 ? "" : `(${selectTemplateData.length})`)} style={{
marginLeft: "12px",
}}
text={
"添加模版" +
(selectTemplateData.length === 0
? ""
: `(${selectTemplateData.length})`)
}
/> />
</Box> </Box>
</Box>
{ {addTemplateList.length === 0 && (
addTemplateList.length === 0 && <Box sx={{ <Box
display: 'flex', alignItems: 'center', flexDirection: 'column', minHeight: 'calc(100vh - 376px)', sx={{
justifyContent: 'center' display: "flex",
}}> alignItems: "center",
flexDirection: "column",
minHeight: "calc(100vh - 376px)",
justifyContent: "center",
}}
>
<img alt="" src={noData} /> <img alt="" src={noData} />
<Typography sx={{ fontSize: '12px', fontWeight: '400', color: '#8A9099' }}>暂未相关模版</Typography> <Typography
sx={{ fontSize: "12px", fontWeight: "400", color: "#8A9099" }}
>
暂未相关模版
</Typography>
</Box> </Box>
} )}
<Box sx={{ display: "flex", flexWrap: 'wrap', overflowX: 'hidden', overflowY: 'overlay', marginLeft: '-8px' }} > <Box
{ sx={{
addTemplateList.map((item: any, key: any) => { display: "flex",
flexWrap: "wrap",
overflowX: "hidden",
overflowY: "overlay",
marginLeft: "-8px",
}}
>
{addTemplateList.map((item: any, key: any) => {
return ( return (
<Box className={styles.addTemplateBox} onClick={() => { <Box
templateSelectCallback(item.id) className={styles.addTemplateBox}
onClick={() => {
templateSelectCallback(item.id);
}}
sx={{
border: selectTemplateData.includes(item.id)
? "1px solid #1370FF"
: "1px solid #EBEDF0;",
}}
key={item.id}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Typography
sx={{
fontSize: "14px",
fontWeight: "600",
color: "#1E2633",
marginBottom: "4px",
overflow: "hidden",
textOverflow: "ellipsis",
}} }}
sx={{ border: selectTemplateData.includes(item.id) ? '1px solid #1370FF' : "1px solid #EBEDF0;" }}
> >
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', }}> {item.title}
<Typography sx={{ fontSize: '14px', fontWeight: '600', color: '#1E2633', marginBottom: "4px", overflow: 'hidden', textOverflow: 'ellipsis' }}>{item.title}</Typography> </Typography>
<Checkbox size="small" sx={{ padding: "0px" }} checked={selectTemplateData.includes(item.id)} /> <Checkbox
size="small"
sx={{ padding: "0px" }}
checked={selectTemplateData.includes(item.id)}
/>
</Box> </Box>
<Box sx={{ display: 'flex', marginBottom: "8px" }}> <Box sx={{ display: "flex", marginBottom: "8px" }}>
<Typography sx={{ fontSize: '12px', fontWeight: '400', color: '#1370FF', marginRight: "24px" }}>版本:{item.version}</Typography> <Typography
<Typography sx={{ fontSize: '12px', fontWeight: '400', color: '#1370FF' }}>更新时间:{item.updateTime}</Typography> sx={{
fontSize: "12px",
fontWeight: "400",
color: "#1370FF",
marginRight: "24px",
}}
>
版本:{item.version}
</Typography>
<Typography
sx={{
fontSize: "12px",
fontWeight: "400",
color: "#1370FF",
}}
>
更新时间:{item.updateTime}
</Typography>
</Box> </Box>
<Typography className={styles.templateDescText} >{item.description}</Typography> <Typography className={styles.templateDescText}>
{item.description}
</Typography>
</Box> </Box>
) );
}) })}
}
</Box> </Box>
</Box> </Box>
</Box> </Box>
......
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-17 14:48:57
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-24 16:41:40
* @FilePath: /bkunyun/src/views/Project/ProjectWorkbench/workbenchTemplate/components/templateBox.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { memo, useCallback, useEffect, useMemo, useState } from "react"; import { memo, useCallback, useEffect, useMemo, useState } from "react";
import styles from "../index.module.css"; import styles from "../index.module.css";
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import Button from "@/components/mui/Button"; import Button from "@/components/mui/Button";
import usePass from "@/hooks/usePass"; import usePass from "@/hooks/usePass";
import { useNavigate } from "react-router-dom";
const TemplateBox = (props: any) => { const TemplateBox = (props: any) => {
const info = props.data const info = props.data;
const isPass = usePass(); const isPass = usePass();
const navigate = useNavigate();
const addTemplateBlock = useCallback(
(id: string) => {
navigate(`/product/cadd/projectSubmitWork`, {
state: { id },
});
},
[navigate]
);
return ( return (
<Box className={styles.templateBlock} > <Box className={styles.templateBlock}>
<Box> <Box>
<Typography sx={{ fontSize: '14px', fontWeight: '600', color: '#1E2633', marginBottom: "4px", overflow: 'hidden', textOverflow: 'ellipsis' }}>{info.title}</Typography> <Typography
<Box sx={{ display: 'flex', marginBottom: "8px" }} > sx={{
<Typography sx={{ fontSize: '12px', fontWeight: '400', color: '#1370FF', marginRight: "24px" }}>版本:{info.version}</Typography> fontSize: "14px",
<Typography sx={{ fontSize: '12px', fontWeight: '400', color: '#1370FF' }}>更新时间:{info.updateTime}</Typography> fontWeight: "600",
color: "#1E2633",
marginBottom: "4px",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
{info.title}
</Typography>
<Box sx={{ display: "flex", marginBottom: "8px" }}>
<Typography
sx={{
fontSize: "12px",
fontWeight: "400",
color: "#1370FF",
marginRight: "24px",
}}
>
版本:{info.version}
</Typography>
<Typography
sx={{ fontSize: "12px", fontWeight: "400", color: "#1370FF" }}
>
更新时间:{info.updateTime}
</Typography>
</Box>
<Typography className={styles.templateDescText}>
{info.description}
</Typography>
</Box> </Box>
<Typography className={styles.templateDescText} >{info.description}</Typography> <Box
sx={{
display: "flex",
justifyContent: "end",
}}
>
{isPass("PROJECT_WORKBENCH_FLOES_USE", "MANAGER") && (
<Button
size={"small"}
text={"删除模版"}
click={() => {
props.startDialog(info.id);
}}
style={{ backgroundColor: "#F0F2F5", color: "#565C66" }}
/>
)}
{isPass("PROJECT_WORKBENCH_FLOES_USE", "USER") && (
<Button
size={"small"}
text={"使用模版"}
click={() => addTemplateBlock(info.id)}
style={{ marginLeft: "12px" }}
/>
)}
</Box> </Box>
<Box sx={{
display: 'flex', justifyContent: 'end'
}} >
{
isPass("PROJECT_WORKBENCH_FLOES_USE", 'MANAGER') &&
<Button size={"small"} text={'删除模版'} click={() => { props.startDialog(info.id) }} style={{ backgroundColor: "#F0F2F5", color: "#565C66" }} />
}
{
isPass("PROJECT_WORKBENCH_FLOES_USE", 'USER') &&
<Button size={"small"} text={'使用模版'} click={() => { }} style={{ marginLeft: "12px" }} />
}
</Box> </Box>
</Box >
); );
}; };
......
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-07-06 14:44:13
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-06 14:47:28
* @FilePath: /bkunyun/src/views/Project/ProjectWorkbench/workbenchTemplate/interface.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
export interface ICustomTemplate{
show?: boolean;
id?: string;
}
\ No newline at end of file
...@@ -84,17 +84,16 @@ const AddProject = (props: any) => { ...@@ -84,17 +84,16 @@ const AddProject = (props: any) => {
const handleClickOpen = () => { const handleClickOpen = () => {
DialogRef.current.handleClickOpen(); DialogRef.current.handleClickOpen();
initData() initData();
}; };
const initData = () => { const initData = () => {
setName('') setName("");
setDesc('') setDesc("");
if (zoneIdOptions.length > 0) { if (zoneIdOptions.length > 0) {
setZoneId(zoneIdOptions[0].id) setZoneId(zoneIdOptions[0].id);
} }
} };
const checkName = (name: string) => { const checkName = (name: string) => {
if (name) { if (name) {
...@@ -155,7 +154,7 @@ const AddProject = (props: any) => { ...@@ -155,7 +154,7 @@ const AddProject = (props: any) => {
name, name,
desc, desc,
zoneId, zoneId,
product: "CADD", product: "cadd",
}); });
} else { } else {
return; return;
......
...@@ -45,7 +45,6 @@ const CurrentProject = observer(() => { ...@@ -45,7 +45,6 @@ const CurrentProject = observer(() => {
const openAddProject = () => { const openAddProject = () => {
addProjectRef.current.handleClickOpen(); addProjectRef.current.handleClickOpen();
// setAddProjectOpen(true);
setProjectListOpen(false); setProjectListOpen(false);
}; };
...@@ -59,9 +58,12 @@ const CurrentProject = observer(() => { ...@@ -59,9 +58,12 @@ const CurrentProject = observer(() => {
<img src={logo} alt="" className={style.logo} /> <img src={logo} alt="" className={style.logo} />
<div className={style.info}> <div className={style.info}>
<div className={style.productName}> <div className={style.productName}>
{currentProjectStore.currentProductInfo.name || "CADD"} {currentProjectStore.currentProductInfo.name}
</div> </div>
<div className={style.projectName} title={currentProjectStore.currentProjectInfo.name}> <div
className={style.projectName}
title={currentProjectStore.currentProjectInfo.name}
>
{currentProjectStore.currentProjectInfo.name || "暂无项目"} {currentProjectStore.currentProjectInfo.name || "暂无项目"}
</div> </div>
</div> </div>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
import { product, hpczone, getDataFileToken } from "@/api/project_api"; /*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-17 14:48:57
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-04 19:38:48
* @FilePath: /bkunyun/src/views/Project/project.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import {
getProjectList as getProjectListApi,
hpczone,
getDataFileToken,
} from "@/api/project_api";
export const getProjectList = async () => { export const getProjectList = async () => {
const res = await product({ product: "CADD" }); const res = await getProjectListApi({ product: "cadd" });
return res.data; return res.data;
}; };
...@@ -12,7 +24,7 @@ export const setFileServerEndPointLocalStorage = async (zoneId: string) => { ...@@ -12,7 +24,7 @@ export const setFileServerEndPointLocalStorage = async (zoneId: string) => {
if (Array.isArray(res)) { if (Array.isArray(res)) {
res.forEach((item: any) => { res.forEach((item: any) => {
if (item.id === zoneId) { if (item.id === zoneId) {
fileServerEndPoint = item.storageConfig.fileServerEndPoint; fileServerEndPoint = item.storageConfig?.fileServerEndPoint;
} }
}); });
localStorage.setItem("fileServerEndPoint", fileServerEndPoint); localStorage.setItem("fileServerEndPoint", fileServerEndPoint);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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