diff --git a/react-ui/config/config.ts b/react-ui/config/config.ts
index 7907e31e..3b681f86 100644
--- a/react-ui/config/config.ts
+++ b/react-ui/config/config.ts
@@ -78,7 +78,7 @@ export default defineConfig({
*/
title: '智能软件开发平台',
layout: {
- locale: true,
+ locale: false,
...defaultSettings,
},
// keepalive: [/./],
@@ -97,10 +97,8 @@ export default defineConfig({
* @doc https://umijs.org/docs/max/i18n
*/
locale: {
- // default zh-CN
default: 'zh-CN',
antd: true,
- // default true, when it is true, will use `navigator.language` overwrite default
baseNavigator: true,
},
/**
diff --git a/react-ui/config/routes.ts b/react-ui/config/routes.ts
index a44c0cbb..619012f6 100644
--- a/react-ui/config/routes.ts
+++ b/react-ui/config/routes.ts
@@ -13,7 +13,7 @@
export default [
{
path: '/',
- redirect: '/account/center',
+ redirect: '/workspace',
},
{
path: '*',
@@ -88,13 +88,6 @@ export default [
},
],
},
- {
- name: 'experiment',
- path: '/experiment',
- routes: [
-
- ],
- },
{
name: 'developmentEnvironment',
path: '/developmentEnvironment',
@@ -169,7 +162,7 @@ export default [
},
],
},
-
+
{
name: 'workspace',
path: '/workspace',
@@ -177,7 +170,8 @@ export default [
{
name: '工作空间',
path: '',
- component: './missingPage.jsx',
+ key: 'workspace',
+ component: './Workspace/index',
},
],
},
@@ -188,11 +182,11 @@ export default [
{
name: '模型部署',
path: '',
+ key: 'modelDseployment',
component: './missingPage.jsx',
},
],
},
-
{
name: 'appsDeployment',
path: '/appsDeployment',
@@ -200,6 +194,7 @@ export default [
{
name: '应用开发',
path: '',
+ key: 'appsDeployment',
component: './missingPage.jsx',
},
],
@@ -211,6 +206,7 @@ export default [
{
name: '监控运维',
path: '',
+ key: 'see',
component: './missingPage.jsx',
},
],
@@ -242,4 +238,16 @@ export default [
},
],
},
+ {
+ name: 'docs',
+ path: '/docs',
+ routes: [
+ {
+ name: '使用指南',
+ path: '',
+ key: 'docs',
+ component: './Docs/index',
+ },
+ ],
+ },
];
diff --git a/react-ui/package.json b/react-ui/package.json
index a3ad6812..1534f112 100644
--- a/react-ui/package.json
+++ b/react-ui/package.json
@@ -60,6 +60,7 @@
"@umijs/route-utils": "^4.0.1",
"antd": "^5.4.4",
"classnames": "^2.3.2",
+ "echarts": "^5.5.0",
"fabric": "^5.3.0",
"highlight.js": "^11.7.0",
"lodash": "^4.17.21",
@@ -70,6 +71,7 @@
"rc-menu": "^9.8.4",
"rc-util": "^5.30.0",
"react": "^18.2.0",
+ "react-activation": "^0.12.4",
"react-cropper": "^2.3.3",
"react-dev-inspector": "^1.8.1",
"react-dom": "^18.2.0",
diff --git a/react-ui/public/assets/材料科研软件平台使用文档.pdf b/react-ui/public/assets/材料科研软件平台使用文档.pdf
new file mode 100644
index 00000000..8371f0b9
Binary files /dev/null and b/react-ui/public/assets/材料科研软件平台使用文档.pdf differ
diff --git a/react-ui/src/app.tsx b/react-ui/src/app.tsx
index d9a54a20..a4642589 100644
--- a/react-ui/src/app.tsx
+++ b/react-ui/src/app.tsx
@@ -35,13 +35,12 @@ export async function getInitialState(): Promise<{
const response = await getUserInfo({
skipErrorHandler: true,
});
- response.user.avatar =
- response.user.avatar ||
- 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png';
return {
...response.user,
+ avatar: response.user.avatar || require('@/assets/img/avatar-default.png'),
permissions: response.permissions,
roles: response.roles,
+ roleNames: response.user.roles,
} as API.CurrentUser;
} catch (error) {
console.log(error);
@@ -128,7 +127,7 @@ export const layout: RuntimeConfig['layout'] = ({ initialState }) => {
// ,
// ]
// : [],
- menuHeaderRender: undefined,
+ menuHeaderRender: false,
// 自定义 403 页面
// unAccessible:
unAccessible
,
// 增加一个 loading 的状态
@@ -138,10 +137,40 @@ export const layout: RuntimeConfig['layout'] = ({ initialState }) => {
},
menuProps: {
onClick: () => {
+ // 点击菜单项,删除所有的页面 state 缓存
removeAllPageCacheState();
},
+ // onSelect: (e) => {
+ // console.log(e);
+ // },
},
...initialState?.settings,
+ token: {
+ sider: {
+ colorTextMenu: themes['textColor'],
+ colorTextMenuSelected: themes['primaryColor'],
+ colorTextMenuActive: themes['primaryColor'],
+ colorBgMenuItemSelected: 'rgba(197, 232, 255, 0.8)',
+ colorMenuBackground: themes['siderBGColor'],
+ },
+ },
+ // menuItemRender: (itemProps, defaultDom, props) => {
+ // console.log('menuItemProps', itemProps);
+ // console.log('defaultDom', defaultDom);
+ // console.log('props', props);
+
+ // const { pathname } = window.location;
+ // const isSelected = pathname === itemProps.path;
+
+ // // 根据菜单项的状态动态显示不同的 icon
+ // const icon = isSelected ? 'icon-developmentEnvironment-icon' : 'icon-kaifahuanjing';
+ // return (
+ //
+ //
+ // {itemProps.name}
+ //
+ // );
+ // },
};
};
diff --git a/react-ui/src/assets/img/avatar-default.png b/react-ui/src/assets/img/avatar-default.png
new file mode 100644
index 00000000..b2022f38
Binary files /dev/null and b/react-ui/src/assets/img/avatar-default.png differ
diff --git a/react-ui/src/assets/img/blue-triangle.png b/react-ui/src/assets/img/blue-triangle.png
new file mode 100644
index 00000000..b82879d9
Binary files /dev/null and b/react-ui/src/assets/img/blue-triangle.png differ
diff --git a/react-ui/src/assets/img/functional-material.png b/react-ui/src/assets/img/functional-material.png
new file mode 100644
index 00000000..9eb39a70
Binary files /dev/null and b/react-ui/src/assets/img/functional-material.png differ
diff --git a/react-ui/src/assets/img/molecular-material.png b/react-ui/src/assets/img/molecular-material.png
new file mode 100644
index 00000000..5cd79357
Binary files /dev/null and b/react-ui/src/assets/img/molecular-material.png differ
diff --git a/react-ui/src/assets/img/user-avatar/1.png b/react-ui/src/assets/img/user-avatar/1.png
new file mode 100644
index 00000000..bb55cbb8
Binary files /dev/null and b/react-ui/src/assets/img/user-avatar/1.png differ
diff --git a/react-ui/src/assets/img/user-avatar/2.png b/react-ui/src/assets/img/user-avatar/2.png
new file mode 100644
index 00000000..941690cc
Binary files /dev/null and b/react-ui/src/assets/img/user-avatar/2.png differ
diff --git a/react-ui/src/assets/img/user-avatar/3.png b/react-ui/src/assets/img/user-avatar/3.png
new file mode 100644
index 00000000..36b9a8fd
Binary files /dev/null and b/react-ui/src/assets/img/user-avatar/3.png differ
diff --git a/react-ui/src/assets/img/user-avatar/4.png b/react-ui/src/assets/img/user-avatar/4.png
new file mode 100644
index 00000000..5f59cd8f
Binary files /dev/null and b/react-ui/src/assets/img/user-avatar/4.png differ
diff --git a/react-ui/src/assets/img/user-avatar/5.png b/react-ui/src/assets/img/user-avatar/5.png
new file mode 100644
index 00000000..7f815419
Binary files /dev/null and b/react-ui/src/assets/img/user-avatar/5.png differ
diff --git a/react-ui/src/assets/img/user-avatar/6.png b/react-ui/src/assets/img/user-avatar/6.png
new file mode 100644
index 00000000..df2b149b
Binary files /dev/null and b/react-ui/src/assets/img/user-avatar/6.png differ
diff --git a/react-ui/src/assets/img/user-avatar/7.png b/react-ui/src/assets/img/user-avatar/7.png
new file mode 100644
index 00000000..3526a286
Binary files /dev/null and b/react-ui/src/assets/img/user-avatar/7.png differ
diff --git a/react-ui/src/assets/img/user-avatar/8.png b/react-ui/src/assets/img/user-avatar/8.png
new file mode 100644
index 00000000..e672d96d
Binary files /dev/null and b/react-ui/src/assets/img/user-avatar/8.png differ
diff --git a/react-ui/src/assets/img/workspace-experiment.png b/react-ui/src/assets/img/workspace-experiment.png
new file mode 100644
index 00000000..bcd69981
Binary files /dev/null and b/react-ui/src/assets/img/workspace-experiment.png differ
diff --git a/react-ui/src/assets/img/workspace-intro-icon.png b/react-ui/src/assets/img/workspace-intro-icon.png
new file mode 100644
index 00000000..d6d75417
Binary files /dev/null and b/react-ui/src/assets/img/workspace-intro-icon.png differ
diff --git a/react-ui/src/assets/img/workspace-intro.png b/react-ui/src/assets/img/workspace-intro.png
new file mode 100644
index 00000000..a8bc72ac
Binary files /dev/null and b/react-ui/src/assets/img/workspace-intro.png differ
diff --git a/react-ui/src/assets/img/workspace-pipeline.png b/react-ui/src/assets/img/workspace-pipeline.png
new file mode 100644
index 00000000..fbbc3ed7
Binary files /dev/null and b/react-ui/src/assets/img/workspace-pipeline.png differ
diff --git a/react-ui/src/assets/img/workspace-quick-start.png b/react-ui/src/assets/img/workspace-quick-start.png
new file mode 100644
index 00000000..b4e9f43c
Binary files /dev/null and b/react-ui/src/assets/img/workspace-quick-start.png differ
diff --git a/react-ui/src/assets/img/workspace-user.png b/react-ui/src/assets/img/workspace-user.png
new file mode 100644
index 00000000..f64de254
Binary files /dev/null and b/react-ui/src/assets/img/workspace-user.png differ
diff --git a/react-ui/src/components/CommonTableCell/index.tsx b/react-ui/src/components/CommonTableCell/index.tsx
index 6493899e..65a1dff2 100644
--- a/react-ui/src/components/CommonTableCell/index.tsx
+++ b/react-ui/src/components/CommonTableCell/index.tsx
@@ -1,3 +1,9 @@
+/*
+ * @Author: 赵伟
+ * @Date: 2024-04-28 14:18:11
+ * @Description: 自定义 Table 单元格,没有数据时展示 --
+ */
+
function CommonTableCell(text?: string | null) {
return {text ?? '--'};
}
diff --git a/react-ui/src/components/DateTableCell/index.tsx b/react-ui/src/components/DateTableCell/index.tsx
index 1b7d785c..0b4efe93 100644
--- a/react-ui/src/components/DateTableCell/index.tsx
+++ b/react-ui/src/components/DateTableCell/index.tsx
@@ -1,3 +1,9 @@
+/*
+ * @Author: 赵伟
+ * @Date: 2024-04-28 14:18:11
+ * @Description: 自定义 Table 日期类单元格
+ */
+
import dayjs from 'dayjs';
function DateTableCell(text?: string | null) {
@@ -5,7 +11,7 @@ function DateTableCell(text?: string | null) {
return --;
}
if (!dayjs(text).isValid()) {
- return 日期无效;
+ return 无效的日期;
}
return {dayjs(text).format('YYYY-MM-DD HH:mm:ss')};
}
diff --git a/react-ui/src/components/KFRadio/index.tsx b/react-ui/src/components/KFRadio/index.tsx
index 9f18f6e8..4bb4ccce 100644
--- a/react-ui/src/components/KFRadio/index.tsx
+++ b/react-ui/src/components/KFRadio/index.tsx
@@ -1,7 +1,7 @@
/*
* @Author: 赵伟
* @Date: 2024-04-17 16:59:42
- * @Description: 自定义Radio
+ * @Description: 自定义 Radio
*/
import classNames from 'classnames';
diff --git a/react-ui/src/components/ModalTitle/index.tsx b/react-ui/src/components/ModalTitle/index.tsx
index 485e22a7..ae0da9b6 100644
--- a/react-ui/src/components/ModalTitle/index.tsx
+++ b/react-ui/src/components/ModalTitle/index.tsx
@@ -1,3 +1,9 @@
+/*
+ * @Author: 赵伟
+ * @Date: 2024-04-28 14:18:11
+ * @Description: 自定义 Modal Title
+ */
+
import classNames from 'classnames';
import React from 'react';
import styles from './index.less';
diff --git a/react-ui/src/global.less b/react-ui/src/global.less
index dca04156..39531f05 100644
--- a/react-ui/src/global.less
+++ b/react-ui/src/global.less
@@ -1,6 +1,7 @@
html,
body,
#root {
+ min-width: 1440px;
height: 100%;
margin: 0;
padding: 0;
@@ -20,9 +21,6 @@ body,
.ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed {
left: unset;
}
-.ant-layout-sider-children {
- margin-top: 60px !important;
-}
canvas {
display: block;
}
@@ -33,58 +31,29 @@ body {
-moz-osx-font-smoothing: grayscale;
}
.ant-pro-layout .ant-pro-layout-content {
- padding: 10px;
+ padding: 0 10px 10px;
+ background-color: transparent;
}
.ant-pro-layout .ant-pro-layout-bg-list {
- background: #f9fafb;
+ background: @background-color;
}
-.ant-menu-light .ant-menu-item-selected {
- background: rgba(197, 232, 255, 0.8) !important;
-}
-.ant-menu-light .ant-menu-item-selected .ant-pro-base-menu-inline-item-text {
- // color: #1664ff;
-}
-.ant-pro-layout .ant-pro-sider .ant-layout-sider-children {
- background: #f2f5f7;
-}
.ant-pro-base-menu-inline-item-title .ant-pro-base-menu-inline-item-text {
- // color: #1d1d20;
font-size: 16px;
}
-// .ant-menu-light .ant-menu-item-selected{
-// color:#1664ff;
-// }
+
.ant-pro-layout .ant-pro-sider-menu {
padding-top: 40px;
}
-.ant-table-wrapper .ant-table-container table > thead > tr:first-child > *:first-child,
-.ant-table-wrapper .ant-table-tbody>tr>td:first-child {
- padding: 0 30px;
-}
-
-
.ant-pro-global-header-logo-mix {
- width: 257px;
- height: 75px;
- margin-left: -16px;
- padding-left: 28px;
- background: #f2f5f7;
- border-bottom: 1px solid rgba(233, 237, 240, 1);
- border-top-right-radius: 20px;
+ padding-left: 12px;
}
.ant-pro-layout .ant-pro-sider .ant-layout-sider-children {
border-right: unset;
- border-bottom-right-radius: 20px;
}
.ant-pro-base-menu-inline {
- // height: 87vh;
- background: #f2f5f7;
border-radius: 0px 20px 20px 0px;
}
-.ant-pro-layout .ant-pro-layout-content {
- background-color: transparent;
-}
.ant-drawer .ant-drawer-body {
padding: 0;
}
@@ -102,15 +71,12 @@ body {
padding: 20px 16px;
background-color: #fff;
}
-// .ant-table-wrapper .ant-table {
-// height: 81vh;
-// // overflow-y: auto;
-// }
.ant-pro-global-header-logo img {
height: 21px;
}
.ant-pro-layout .ant-layout-sider.ant-pro-sider {
- height: 94vh;
+ height: 100vh;
+ padding-top: 56px;
}
.ant-pro-layout .ant-pro-layout-container {
height: 100vh;
@@ -131,7 +97,7 @@ body {
width: 110px;
height: 40px;
margin-right: 10px;
- // color: #1d1d20;
+ // color: @text-color;
font-size: 18px;
background: rgba(22, 100, 255, 0.06);
border-color: transparent;
@@ -161,9 +127,6 @@ body {
.ant-modal .ant-select-single .ant-select-selector .ant-select-selection-placeholder {
line-height: 46px;
}
-.ant-menu-light.ant-menu-inline .ant-menu-item {
- color: #575757;
-}
.ant-modal .ant-modal-close-x {
width: 26px;
height: 26px;
diff --git a/react-ui/src/hooks/index.ts b/react-ui/src/hooks/index.ts
index 24a80d81..1d56a24d 100644
--- a/react-ui/src/hooks/index.ts
+++ b/react-ui/src/hooks/index.ts
@@ -41,7 +41,7 @@ export function useVisible(initialValue: boolean) {
setVisible(false);
}, []);
- return [visible, open, close];
+ return [visible, open, close] as const;
}
type Callback = (state: T) => void;
@@ -92,7 +92,7 @@ export function useDomSize(
setWidth(domRef.current.offsetWidth);
}
};
- const debounceFunc = debounce(setDomHeight, 200);
+ const debounceFunc = debounce(setDomHeight, 100);
setDomHeight();
window.addEventListener('resize', debounceFunc);
diff --git a/react-ui/src/iconfont/iconfont.js b/react-ui/src/iconfont/iconfont.js
index a7ee3e08..77f8486f 100644
--- a/react-ui/src/iconfont/iconfont.js
+++ b/react-ui/src/iconfont/iconfont.js
@@ -1 +1 @@
-window._iconfont_svg_string_4511447='',function(t){var a=(a=document.getElementsByTagName("script"))[a.length-1],h=a.getAttribute("data-injectcss"),a=a.getAttribute("data-disable-injectsvg");if(!a){var v,i,o,l,z,m=function(a,h){h.parentNode.insertBefore(a,h)};if(h&&!t.__iconfont__svg__cssinject__){t.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}v=function(){var a,h=document.createElement("div");h.innerHTML=t._iconfont_svg_string_4511447,(h=h.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",h=h,(a=document.body).firstChild?m(h,a.firstChild):a.appendChild(h))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(v,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),v()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(o=v,l=t.document,z=!1,d(),l.onreadystatechange=function(){"complete"==l.readyState&&(l.onreadystatechange=null,n())})}function n(){z||(z=!0,o())}function d(){try{l.documentElement.doScroll("left")}catch(a){return void setTimeout(d,50)}n()}}(window);
\ No newline at end of file
+window._iconfont_svg_string_4511447='',function(t){var a=(a=document.getElementsByTagName("script"))[a.length-1],h=a.getAttribute("data-injectcss"),a=a.getAttribute("data-disable-injectsvg");if(!a){var l,i,v,o,z,m=function(a,h){h.parentNode.insertBefore(a,h)};if(h&&!t.__iconfont__svg__cssinject__){t.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}l=function(){var a,h=document.createElement("div");h.innerHTML=t._iconfont_svg_string_4511447,(h=h.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",h=h,(a=document.body).firstChild?m(h,a.firstChild):a.appendChild(h))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(l,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),l()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(v=l,o=t.document,z=!1,p(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,n())})}function n(){z||(z=!0,v())}function p(){try{o.documentElement.doScroll("left")}catch(a){return void setTimeout(p,50)}n()}}(window);
\ No newline at end of file
diff --git a/react-ui/src/overrides.less b/react-ui/src/overrides.less
index c65420fb..b933bad0 100644
--- a/react-ui/src/overrides.less
+++ b/react-ui/src/overrides.less
@@ -52,3 +52,7 @@
.ant-table-wrapper .ant-table-thead > tr > td {
background-color: #fff;
}
+
+.ant-pro-page-container {
+ overflow-y: auto;
+}
diff --git a/react-ui/src/pages/Dataset/personalData.jsx b/react-ui/src/pages/Dataset/personalData.jsx
index 0dd09739..d03dac4a 100644
--- a/react-ui/src/pages/Dataset/personalData.jsx
+++ b/react-ui/src/pages/Dataset/personalData.jsx
@@ -117,14 +117,14 @@ const PublicData = (React.FC = () => {
};
const chooseDatasetType = (val, item) => {
console.log(val, item);
- if (item.path == queryFlow.data_type) {
+ if (item.id == queryFlow.data_type) {
setActiveType('');
setQueryFlow({ ...queryFlow, data_type: null });
getDatasetlist({ ...queryFlow, data_type: null });
} else {
- setActiveType(item.path);
- setQueryFlow({ ...queryFlow, data_type: item.path });
- getDatasetlist({ ...queryFlow, data_type: item.path });
+ setActiveType(item.id);
+ setQueryFlow({ ...queryFlow, data_type: item.id });
+ getDatasetlist({ ...queryFlow, data_type: item.id });
}
// setQueryFlow({...queryFlow,data_type:item.path},()=>{
// getDatasetlist()
@@ -132,14 +132,14 @@ const PublicData = (React.FC = () => {
};
const chooseDatasetTag = (val, item) => {
console.log(val, item);
- if (item.path == queryFlow.data_tag) {
+ if (item.id == queryFlow.data_tag) {
setActiveTag('');
setQueryFlow({ ...queryFlow, data_tag: null });
getDatasetlist({ ...queryFlow, data_tag: null });
} else {
- setActiveTag(item.path);
- setQueryFlow({ ...queryFlow, data_tag: item.path });
- getDatasetlist({ ...queryFlow, data_tag: item.path });
+ setActiveTag(item.id);
+ setQueryFlow({ ...queryFlow, data_tag: item.id });
+ getDatasetlist({ ...queryFlow, data_tag: item.id });
}
// setQueryFlow({...queryFlow,data_type:item.path},()=>{
// getDatasetlist()
@@ -196,7 +196,7 @@ const PublicData = (React.FC = () => {
{
chooseDatasetType(e, item);
@@ -230,7 +230,7 @@ const PublicData = (React.FC = () => {
{
chooseDatasetTag(e, item);
diff --git a/react-ui/src/pages/Dataset/publicData.jsx b/react-ui/src/pages/Dataset/publicData.jsx
index 19ae0323..1a33b8e5 100644
--- a/react-ui/src/pages/Dataset/publicData.jsx
+++ b/react-ui/src/pages/Dataset/publicData.jsx
@@ -76,14 +76,14 @@ const PublicData = () => {
};
const chooseDatasetType = (val, item) => {
console.log(val, item);
- if (item.path == queryFlow.data_type) {
+ if (item.id == queryFlow.data_type) {
setActiveType('');
setQueryFlow({ ...queryFlow, data_type: null });
getDatasetlist({ ...queryFlow, data_type: null });
} else {
- setActiveType(item.path);
- setQueryFlow({ ...queryFlow, data_type: item.path });
- getDatasetlist({ ...queryFlow, data_type: item.path });
+ setActiveType(item.id);
+ setQueryFlow({ ...queryFlow, data_type: item.id });
+ getDatasetlist({ ...queryFlow, data_type: item.id });
}
// setQueryFlow({...queryFlow,data_type:item.path},()=>{
// getDatasetlist()
@@ -91,14 +91,14 @@ const PublicData = () => {
};
const chooseDatasetTag = (val, item) => {
console.log(val, item);
- if (item.path == queryFlow.data_tag) {
+ if (item.id == queryFlow.data_tag) {
setActiveTag('');
setQueryFlow({ ...queryFlow, data_tag: null });
getDatasetlist({ ...queryFlow, data_tag: null });
} else {
- setActiveTag(item.path);
- setQueryFlow({ ...queryFlow, data_tag: item.path });
- getDatasetlist({ ...queryFlow, data_tag: item.path });
+ setActiveTag(item.id);
+ setQueryFlow({ ...queryFlow, data_tag: item.id });
+ getDatasetlist({ ...queryFlow, data_tag: item.id });
}
// setQueryFlow({...queryFlow,data_type:item.path},()=>{
// getDatasetlist()
@@ -146,7 +146,7 @@ const PublicData = () => {
{
chooseDatasetType(e, item);
@@ -180,7 +180,7 @@ const PublicData = () => {
{
chooseDatasetTag(e, item);
diff --git a/react-ui/src/pages/Docs/index.less b/react-ui/src/pages/Docs/index.less
new file mode 100644
index 00000000..e69de29b
diff --git a/react-ui/src/pages/Docs/index.tsx b/react-ui/src/pages/Docs/index.tsx
new file mode 100644
index 00000000..fcf4ed12
--- /dev/null
+++ b/react-ui/src/pages/Docs/index.tsx
@@ -0,0 +1,9 @@
+const Docs = () => {
+ return (
+
+ );
+};
+export default Docs;
diff --git a/react-ui/src/pages/Experiment/index.less b/react-ui/src/pages/Experiment/index.less
index 94264bdf..50ec2305 100644
--- a/react-ui/src/pages/Experiment/index.less
+++ b/react-ui/src/pages/Experiment/index.less
@@ -24,7 +24,7 @@
align-items: center;
width: 100%;
padding: 0 0 0 33px;
- color: #1d1d20;
+ color: @text-color;
font-size: 15px;
& > div {
@@ -76,16 +76,18 @@
.statusBox:hover .statusIcon {
visibility: visible;
}
-.experimentBox{
+.experimentBox {
height: calc(100% - 20px);
- .experimentTable{
+ .experimentTable {
height: calc(100% - 60px);
- :global{
- .ant-table-wrapper .ant-table{
+ :global {
+ .ant-table-wrapper .ant-table {
// overflow-y: auto;
height: calc(100% - 48px);
}
+ .ant-table-row-expand-icon-cell {
+ padding: 0 30px;
+ }
}
}
-
-}
\ No newline at end of file
+}
diff --git a/react-ui/src/pages/Experiment/status.ts b/react-ui/src/pages/Experiment/status.ts
index 2a075951..9f568795 100644
--- a/react-ui/src/pages/Experiment/status.ts
+++ b/react-ui/src/pages/Experiment/status.ts
@@ -16,7 +16,7 @@ export enum ExperimentStatus {
}
type ExperimentStatusKeys = keyof typeof ExperimentStatus;
-type ExperimentStatusValues = (typeof ExperimentStatus)[ExperimentStatusKeys];
+export type ExperimentStatusValues = (typeof ExperimentStatus)[ExperimentStatusKeys];
export const experimentStatusInfo: Record
= {
Running: {
diff --git a/react-ui/src/pages/Model/personalData.jsx b/react-ui/src/pages/Model/personalData.jsx
index 34ff8f2a..58bd5645 100644
--- a/react-ui/src/pages/Model/personalData.jsx
+++ b/react-ui/src/pages/Model/personalData.jsx
@@ -121,14 +121,14 @@ const PublicData = () => {
const chooseModelType = (val, item) => {
console.log(val, item);
- if (item.path == queryFlow.model_type) {
+ if (item.id == queryFlow.model_type) {
setActiveType('');
setQueryFlow({ ...queryFlow, model_type: null });
getModelLists({ ...queryFlow, model_type: null });
} else {
- setActiveType(item.path);
- setQueryFlow({ ...queryFlow, model_type: item.path });
- getModelLists({ ...queryFlow, model_type: item.path });
+ setActiveType(item.id);
+ setQueryFlow({ ...queryFlow, model_type: item.id });
+ getModelLists({ ...queryFlow, model_type: item.id });
}
// setQueryFlow({...queryFlow,data_type:item.path},()=>{
@@ -136,14 +136,14 @@ const PublicData = () => {
// })
};
const chooseModelTag = (val, item) => {
- if (item.path == queryFlow.model_tag) {
+ if (item.id == queryFlow.model_tag) {
setActiveTag('');
setQueryFlow({ ...queryFlow, model_tag: null });
getModelLists({ ...queryFlow, model_tag: null });
} else {
- setActiveTag(item.path);
- setQueryFlow({ ...queryFlow, model_tag: item.path });
- getModelLists({ ...queryFlow, model_tag: item.path });
+ setActiveTag(item.id);
+ setQueryFlow({ ...queryFlow, model_tag: item.id });
+ getModelLists({ ...queryFlow, model_tag: item.id });
}
// setQueryFlow({...queryFlow,data_type:item.path},()=>{
// getDatasetlist()
@@ -190,7 +190,7 @@ const PublicData = () => {
{
chooseModelType(e, item);
@@ -231,7 +231,7 @@ const PublicData = () => {
{
chooseModelTag(e, item);
diff --git a/react-ui/src/pages/Model/publicData.jsx b/react-ui/src/pages/Model/publicData.jsx
index 36261368..d22775dd 100644
--- a/react-ui/src/pages/Model/publicData.jsx
+++ b/react-ui/src/pages/Model/publicData.jsx
@@ -77,14 +77,14 @@ const PublicData = () => {
};
const chooseModelType = (val, item) => {
console.log(val, item);
- if (item.path == queryFlow.model_type) {
+ if (item.id == queryFlow.model_type) {
setActiveType('');
setQueryFlow({ ...queryFlow, model_type: null });
getModelLists({ ...queryFlow, model_type: null });
} else {
- setActiveType(item.path);
- setQueryFlow({ ...queryFlow, model_type: item.path });
- getModelLists({ ...queryFlow, model_type: item.path });
+ setActiveType(item.id);
+ setQueryFlow({ ...queryFlow, model_type: item.id });
+ getModelLists({ ...queryFlow, model_type: item.id });
}
// setQueryFlow({...queryFlow,data_type:item.path},()=>{
@@ -92,14 +92,14 @@ const PublicData = () => {
// })
};
const chooseModelTag = (val, item) => {
- if (item.path == queryFlow.model_tag) {
+ if (item.id == queryFlow.model_tag) {
setActiveTag('');
setQueryFlow({ ...queryFlow, model_tag: null });
getModelLists({ ...queryFlow, model_tag: null });
} else {
- setActiveTag(item.path);
- setQueryFlow({ ...queryFlow, model_tag: item.path });
- getModelLists({ ...queryFlow, model_tag: item.path });
+ setActiveTag(item.id);
+ setQueryFlow({ ...queryFlow, model_tag: item.id });
+ getModelLists({ ...queryFlow, model_tag: item.id });
}
// setQueryFlow({...queryFlow,data_type:item.path},()=>{
// getDatasetlist()
@@ -147,7 +147,7 @@ const PublicData = () => {
{
chooseModelType(e, item);
@@ -181,7 +181,7 @@ const PublicData = () => {
{
chooseModelTag(e, item);
diff --git a/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.less b/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.less
index fddea2b7..bfff8100 100644
--- a/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.less
+++ b/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.less
@@ -22,7 +22,7 @@
height: 398px;
margin-right: 15px;
padding: 15px;
- background-color: @background-color-primay;
+ background-color: @background-color-primary;
border: 1px solid @border-color;
border-radius: 8px;
@@ -31,7 +31,7 @@
padding-left: 0;
background-color: transparent;
border-width: 0;
- border-bottom: 1px solid @border-color-second;
+ border-bottom: 1px solid @border-color-secondary;
border-radius: 0;
}
}
@@ -40,7 +40,7 @@
width: calc(100% - 488px - 15px);
height: 398px;
padding: 15px;
- background-color: @background-color-primay;
+ background-color: @background-color-primary;
border: 1px solid @border-color;
border-radius: 8px;
@@ -49,7 +49,7 @@
padding: 3px 0 6px;
color: @text-color;
font-size: @font-size;
- border-bottom: 1px solid @border-color-second;
+ border-bottom: 1px solid @border-color-secondary;
}
&__files {
height: calc(100% - 75px);
diff --git a/react-ui/src/pages/Workspace/components/AssetsManagement/index.less b/react-ui/src/pages/Workspace/components/AssetsManagement/index.less
new file mode 100644
index 00000000..122d3bf4
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/AssetsManagement/index.less
@@ -0,0 +1,54 @@
+.assets-management {
+ flex: 1;
+ width: 100%;
+ padding: 20px 20px 0;
+ background-color: white;
+ border-radius: 4px;
+
+ :global {
+ .ant-select-filled {
+ background-color: rgba(138, 138, 138, 0.12);
+ border-radius: 2px;
+
+ .ant-select-selection-item {
+ color: @text-color-secondary !important;
+ font-size: 13px;
+ }
+ }
+ }
+
+ &__title {
+ color: @text-color;
+ font-weight: 500;
+ font-size: @font-size-title;
+ }
+
+ &__increase {
+ display: inline-block;
+ margin-top: 12px;
+ margin-bottom: 30px;
+ padding: 2px 7px;
+ color: @primary-color-secondary;
+ font-size: 13px;
+ background-color: rgba(187, 210, 255, 0.29);
+ border-radius: 2px;
+ }
+
+ &__summary {
+ display: flex;
+ flex-direction: column;
+ width: 33.33%;
+
+ &__title {
+ margin-bottom: 12px;
+ color: @text-color-secondary;
+ font-size: @font-size;
+ }
+
+ &__value {
+ color: @text-color;
+ font-weight: 500;
+ font-size: 22px;
+ }
+ }
+}
diff --git a/react-ui/src/pages/Workspace/components/AssetsManagement/index.tsx b/react-ui/src/pages/Workspace/components/AssetsManagement/index.tsx
new file mode 100644
index 00000000..dc1af6c9
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/AssetsManagement/index.tsx
@@ -0,0 +1,81 @@
+import { CommonTabKeys } from '@/enums';
+import { getWorkspaceAssetCountReq } from '@/services/workspace';
+import { to } from '@/utils/promise';
+import { Flex, Select } from 'antd';
+import { useEffect, useState } from 'react';
+import styles from './index.less';
+function AssetsManagement() {
+ const [type, setType] = useState(CommonTabKeys.Public);
+ const [assetCounts, setAssetCounts] = useState<{ title: string; value: number }[]>([]);
+ useEffect(() => {
+ getWorkspacAssetCount();
+ }, [type]);
+ // 获取工作空间资产数量
+ const getWorkspacAssetCount = async () => {
+ const params = {
+ isPublic: type === CommonTabKeys.Public,
+ };
+ const [res] = await to(getWorkspaceAssetCountReq(params));
+ if (res && res.data) {
+ const { component, dataset, image, model, workflow } = res.data;
+ const items = [
+ {
+ title: '数据集',
+ value: dataset,
+ },
+ {
+ title: '模型',
+ value: model,
+ },
+ {
+ title: '镜像',
+ value: image,
+ },
+ {
+ title: '组件',
+ value: component,
+ },
+ {
+ title: '代码配置',
+ value: 0,
+ },
+ {
+ title: '流水线模版',
+ value: workflow,
+ },
+ ];
+ setAssetCounts(items);
+ }
+ };
+
+ return (
+
+
+ AI资产
+
+
+
+
今日新增数量:5
+
+ {assetCounts.map((item, index) => (
+
+
{item.title}
+
{item.value}
+
+ ))}
+
+
+ );
+}
+
+export default AssetsManagement;
diff --git a/react-ui/src/pages/Workspace/components/ExperimentChart/index.less b/react-ui/src/pages/Workspace/components/ExperimentChart/index.less
new file mode 100644
index 00000000..3891b3f4
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/ExperimentChart/index.less
@@ -0,0 +1,7 @@
+.experiment-chart {
+ width: 295px;
+ min-width: 295px;
+ height: 140px;
+ background-color: @workspace-background;
+ border-radius: 4px;
+}
diff --git a/react-ui/src/pages/Workspace/components/ExperimentChart/index.tsx b/react-ui/src/pages/Workspace/components/ExperimentChart/index.tsx
new file mode 100644
index 00000000..f4d30fe1
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/ExperimentChart/index.tsx
@@ -0,0 +1,214 @@
+import themes from '@/styles/theme.less';
+import * as echarts from 'echarts';
+import React, { useEffect, useRef } from 'react';
+import styles from './index.less';
+
+const color1 = new echarts.graphic.LinearGradient(
+ 0,
+ 0,
+ 0,
+ 1,
+ [
+ { offset: 0, color: '#c73131' },
+ { offset: 1, color: '#ff7e96' },
+ ],
+ false,
+);
+
+const color2 = new echarts.graphic.LinearGradient(
+ 0,
+ 0,
+ 0,
+ 1,
+ [
+ { offset: 0, color: '#6ac21d' },
+ { offset: 1, color: '#96e850' },
+ ],
+ false,
+);
+const color3 = new echarts.graphic.LinearGradient(
+ 0,
+ 0,
+ 0,
+ 1,
+ [
+ { offset: 0, color: '#8c8c8c' },
+ { offset: 1, color: '#c8c6c6' },
+ ],
+ false,
+);
+const color4 = new echarts.graphic.LinearGradient(
+ 0,
+ 0,
+ 0,
+ 1,
+ [
+ { offset: 0, color: '#ecb934' },
+ { offset: 1, color: '#f0864d' },
+ ],
+ false,
+);
+
+const color5 = new echarts.graphic.LinearGradient(
+ 0,
+ 0,
+ 0,
+ 1,
+ [
+ { offset: 0, color: '#7ea9fe' },
+ { offset: 1, color: '#1664ff' },
+ ],
+ false,
+);
+
+const color6 = new echarts.graphic.LinearGradient(
+ 0,
+ 0,
+ 0,
+ 1,
+ [
+ { offset: 0, color: 'rgba(255, 255, 255, 0.62)' },
+ { offset: 1, color: '#ebf2ff ' },
+ ],
+ false,
+);
+
+export type ExperimentStatistics = {
+ Failed: number;
+ Pending: number;
+ Running: number;
+ Succeeded: number;
+ Terminated: number;
+};
+
+type ExperimentChartProps = {
+ style?: React.CSSProperties;
+ chartData: ExperimentStatistics;
+};
+
+function ExperimentChart({ chartData, style }: ExperimentChartProps) {
+ const chartRef = useRef
(null);
+ const total =
+ chartData.Failed +
+ chartData.Pending +
+ chartData.Running +
+ chartData.Succeeded +
+ chartData.Terminated;
+ const options: echarts.EChartsOption = {
+ title: {
+ show: true,
+ left: '29%',
+ top: 'center',
+ textAlign: 'center',
+ text: [`{a|${total}}`, '{b|实验状态}'].join('\n'),
+ textStyle: {
+ rich: {
+ a: {
+ color: themes['textColor'],
+ fontSize: 20,
+ fontWeight: 700,
+ lineHeight: 28,
+ },
+ b: {
+ color: themes['textColorSecondary'],
+ fontSize: 10,
+ fontWeight: 'normal',
+ },
+ },
+ },
+ },
+ tooltip: {
+ trigger: 'item',
+ },
+ legend: {
+ top: 'center',
+ right: '5%',
+ orient: 'vertical',
+ icon: 'circle',
+ itemWidth: 6,
+ itemGap: 20,
+ height: 100,
+ },
+ color: [color1, color2, color3, color4, color5],
+ series: [
+ {
+ type: 'pie',
+ radius: ['70%', '80%'],
+ center: ['30%', '50%'],
+ avoidLabelOverlap: false,
+ padAngle: 3,
+ itemStyle: {
+ borderRadius: 3,
+ },
+ label: {
+ show: false,
+ },
+ emphasis: {
+ label: {
+ show: false,
+ },
+ },
+ labelLine: {
+ show: false,
+ },
+ data: [
+ { value: chartData.Failed, name: '失败' },
+ { value: chartData.Succeeded, name: '成功' },
+ { value: chartData.Terminated, name: '中止' },
+ { value: chartData.Pending, name: '等待' },
+ { value: chartData.Running, name: '运行中' },
+ ],
+ },
+ {
+ type: 'pie',
+ radius: '60%',
+ center: ['30%', '50%'],
+ avoidLabelOverlap: false,
+ label: {
+ show: false,
+ },
+ tooltip: {
+ show: false,
+ },
+ emphasis: {
+ label: {
+ show: false,
+ },
+ disabled: true,
+ },
+ animation: false,
+ labelLine: {
+ show: false,
+ },
+ data: [
+ {
+ value: 100,
+ itemStyle: { color: color6, borderColor: 'rgba(22, 100, 255, 0.08)', borderWidth: 1 },
+ },
+ ],
+ },
+ ],
+ };
+
+ useEffect(() => {
+ // 创建一个echarts实例,返回echarts实例
+ const chart = echarts.init(chartRef.current);
+
+ // 设置图表实例的配置项和数据
+ chart.setOption(options);
+
+ // 组件卸载
+ return () => {
+ // myChart.dispose() 销毁实例
+ chart.dispose();
+ };
+ }, []);
+
+ return (
+
+ );
+}
+
+export default ExperimentChart;
diff --git a/react-ui/src/pages/Workspace/components/ExperimentTable/index.less b/react-ui/src/pages/Workspace/components/ExperimentTable/index.less
new file mode 100644
index 00000000..85c5e42d
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/ExperimentTable/index.less
@@ -0,0 +1,58 @@
+.experiment-table {
+ flex: 1;
+ min-width: 500px;
+ height: 140px;
+ padding: 12px 24px;
+ background-color: @workspace-background;
+ border-radius: 4px;
+
+ &__header {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-bottom: 4px;
+ color: @text-color;
+ font-size: @font-size;
+ line-height: 20px;
+ }
+
+ &__content {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 6px 0;
+ color: .addAlpha(@text-color, 0.75) [];
+ font-size: 14px;
+ line-height: 20px;
+ border-bottom: 1px solid rgba(234, 234, 234, 0.8);
+
+ &:last-child {
+ border-bottom: 0;
+ }
+ }
+
+ &__status {
+ width: 20%;
+ }
+
+ &__duration {
+ width: 25%;
+ }
+
+ &__date {
+ width: 35%;
+ }
+
+ &__operation {
+ width: 20%;
+
+ :global {
+ .ant-btn-link {
+ height: 20px;
+ padding: 0;
+ line-height: 20px;
+ border: 0;
+ }
+ }
+ }
+}
diff --git a/react-ui/src/pages/Workspace/components/ExperimentTable/index.tsx b/react-ui/src/pages/Workspace/components/ExperimentTable/index.tsx
new file mode 100644
index 00000000..7a179a39
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/ExperimentTable/index.tsx
@@ -0,0 +1,59 @@
+import KFIcon from '@/components/KFIcon';
+import { ExperimentStatusValues, experimentStatusInfo } from '@/pages/Experiment/status';
+import { ExperimentInstance } from '@/types';
+import { elapsedTime, formatDate } from '@/utils/date';
+import { useNavigate } from '@umijs/max';
+import { Button } from 'antd';
+import styles from './index.less';
+type ExperimentTableProps = {
+ tableData: ExperimentInstance[];
+ style?: React.CSSProperties;
+};
+
+function ExperimentTable({ tableData = [], style }: ExperimentTableProps) {
+ const navgite = useNavigate();
+ const gotoExperiment = (record: ExperimentInstance) => {
+ navgite(`/pipeline/experimentPytorchtext/${record.workflow_id}/${record.id}`);
+ };
+
+ return (
+
+
+
状态
+
运行时长
+
开始时间
+
操作
+
+ {tableData?.map((item) => (
+
+
+

+
+
+ {elapsedTime(
+ new Date(item.create_time),
+ item.finish_time ? new Date(item.finish_time) : new Date(),
+ )}
+
+
{formatDate(item.create_time)}
+
+ }
+ onClick={() => gotoExperiment(item)}
+ >
+ 详情
+
+
+
+ ))}
+
+ );
+}
+
+export default ExperimentTable;
diff --git a/react-ui/src/pages/Workspace/components/QuickStart/WorkArrow.tsx b/react-ui/src/pages/Workspace/components/QuickStart/WorkArrow.tsx
new file mode 100644
index 00000000..76ca1ca7
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/QuickStart/WorkArrow.tsx
@@ -0,0 +1,60 @@
+import styles from './index.less';
+
+type WorkArrowProps = {
+ width?: number;
+ height?: number;
+ x: number;
+ y: number;
+ arrowLeft: number;
+ arrorwTop: number;
+ borderLeft?: number;
+ borderTop?: number;
+ borderRight?: number;
+ borderBottom?: number;
+ arrrowAngle?: number;
+};
+
+function WorkArrow({
+ width = 1,
+ height = 1,
+ x,
+ y,
+ arrowLeft,
+ arrorwTop,
+ borderLeft = 0,
+ borderTop = 0,
+ borderRight = 0,
+ borderBottom = 0,
+ arrrowAngle = 0,
+}: WorkArrowProps) {
+ return (
+
+
})
+
+ );
+}
+
+export default WorkArrow;
diff --git a/react-ui/src/pages/Workspace/components/QuickStart/WorkFlow.tsx b/react-ui/src/pages/Workspace/components/QuickStart/WorkFlow.tsx
new file mode 100644
index 00000000..9401bbe3
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/QuickStart/WorkFlow.tsx
@@ -0,0 +1,31 @@
+import { Button } from 'antd';
+import styles from './index.less';
+
+type WorkFlowProps = {
+ content: string;
+ buttonText: string;
+ tips?: string;
+ onClick?: () => void;
+ buttonTop?: number;
+ x: number;
+ y: number;
+};
+
+function WorkFlow({ content, buttonText, tips, buttonTop = 20, x, y, onClick }: WorkFlowProps) {
+ return (
+
+ {tips &&
{tips}
}
+
{content}
+
+
+ );
+}
+
+export default WorkFlow;
diff --git a/react-ui/src/pages/Workspace/components/QuickStart/index.less b/react-ui/src/pages/Workspace/components/QuickStart/index.less
new file mode 100644
index 00000000..f5eb76f4
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/QuickStart/index.less
@@ -0,0 +1,96 @@
+.quick-start {
+ width: calc(100% - 326px);
+ padding: 20px 30px;
+ background-color: white;
+ border-radius: 4px;
+
+ &__title {
+ margin-bottom: 20px;
+ color: @text-color;
+ font-weight: 500;
+ font-size: @font-size-title;
+ }
+
+ &__content {
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 610px;
+ background-image: url(@/assets/img/workspace-quick-start.png);
+ background-repeat: no-repeat;
+ background-position: top left;
+ background-size: 100% 100%;
+
+ &__canvas {
+ position: relative;
+ width: 1223px;
+ height: 610px;
+ transform-origin: center left;
+
+ &__model {
+ position: absolute;
+ top: 358px;
+ left: 920px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ color: @primary-color;
+ font-size: @font-size;
+ }
+
+ &__task {
+ position: absolute;
+ top: 110px;
+ left: 603px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 131px;
+ height: 41px;
+ color: @primary-color;
+ font-size: @font-size;
+ background-color: rgba(22, 100, 255, 0.05);
+ border: 1px dashed @primary-color;
+ border-radius: 4px;
+ box-shadow: 0px 0px 6px rgba(22, 100, 255, 0.07);
+ }
+ }
+ }
+}
+
+.work-flow {
+ position: absolute;
+ width: 192px;
+ padding: 15px;
+ background-color: white;
+ border: 1px solid;
+ border-color: rgba(22, 100, 255, 0.08);
+ border-radius: 0px 8px 0px 0px;
+ box-shadow: 0px 0px 10px rgba(22, 100, 255, 0.06);
+
+ &__content {
+ color: @text-color-secondary;
+ font-size: @font-size;
+ }
+
+ &__tips {
+ position: absolute;
+ top: -16px;
+ left: 0;
+ padding: 4px 10px;
+ color: white;
+ font-size: @font-size;
+ background-color: #333333;
+ }
+}
+
+.work-arrow {
+ position: absolute;
+ border: 0 dashed @primary-color;
+
+ &__img {
+ position: absolute;
+ }
+}
diff --git a/react-ui/src/pages/Workspace/components/QuickStart/index.tsx b/react-ui/src/pages/Workspace/components/QuickStart/index.tsx
new file mode 100644
index 00000000..d1995244
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/QuickStart/index.tsx
@@ -0,0 +1,149 @@
+import KFIcon from '@/components/KFIcon';
+import { useNavigate } from '@umijs/max';
+import { debounce } from 'lodash';
+import { useEffect, useState } from 'react';
+import WorkArrow from './WorkArrow';
+import WorkFlow from './WorkFlow';
+import styles from './index.less';
+
+function QuickStart() {
+ const navgite = useNavigate();
+ const [scale, setScale] = useState(1);
+
+ useEffect(() => {
+ const changeScale = () => {
+ const width = document.body.offsetWidth - 256 - 80 - 60 - 326 - 15 - 8;
+ const ratio = width >= 1223 ? 1 : width / 1223;
+ setScale(ratio);
+ };
+
+ const debounceFunc = debounce(changeScale, 16);
+ window.addEventListener('resize', debounceFunc);
+
+ return () => {
+ window.removeEventListener('resize', debounceFunc);
+ };
+ }, []);
+
+ return (
+
+
快速开始
+
+
+
navgite('/datasetPreparation/datasetAnnotation')}
+ />
+ navgite('/developmentEnvironment')}
+ />
+ navgite('/pipeline/pipelineText')}
+ />
+ navgite('/pipeline/experimentText')}
+ />
+ navgite('/modelDseployment')}
+ />
+
+
+ 模型管理
+
+
+
+ 任务自动调度
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default QuickStart;
diff --git a/react-ui/src/pages/Workspace/components/TotalStatistics/index.less b/react-ui/src/pages/Workspace/components/TotalStatistics/index.less
new file mode 100644
index 00000000..aec9945b
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/TotalStatistics/index.less
@@ -0,0 +1,41 @@
+.total-statistics {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 400px;
+ height: 140px;
+ background-color: @workspace-background;
+ border-radius: 4px;
+
+ &__icon {
+ width: 85px;
+ height: 80px;
+ margin-right: 40px;
+ }
+
+ &__title {
+ position: relative;
+ margin-bottom: 6px;
+ color: @text-color-secondary;
+ font-size: @font-size-content;
+ }
+
+ &__title-shadow {
+ position: absolute;
+ bottom: 6px;
+ left: 0;
+ width: 79px;
+ height: 6px;
+ background-color: linear-gradient(
+ 87.07deg,
+ rgba(22, 100, 255, 0.6) 0%,
+ rgba(22, 100, 255, 0) 100%
+ );
+ }
+
+ &__count {
+ color: @text-color;
+ font-weight: 700;
+ font-size: 25px;
+ }
+}
diff --git a/react-ui/src/pages/Workspace/components/TotalStatistics/index.tsx b/react-ui/src/pages/Workspace/components/TotalStatistics/index.tsx
new file mode 100644
index 00000000..c1eba291
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/TotalStatistics/index.tsx
@@ -0,0 +1,25 @@
+import styles from './index.less';
+
+type TotalStatisticsProps = {
+ icon: string;
+ title: string;
+ count?: string | number;
+ style?: React.CSSProperties;
+};
+
+function TotalStatistics({ icon = '', title = '', count = 0, style }: TotalStatisticsProps) {
+ return (
+
+

+
+
+ );
+}
+
+export default TotalStatistics;
diff --git a/react-ui/src/pages/Workspace/components/UserSpace/index.less b/react-ui/src/pages/Workspace/components/UserSpace/index.less
new file mode 100644
index 00000000..b95fdf6d
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/UserSpace/index.less
@@ -0,0 +1,65 @@
+.user-space {
+ margin-bottom: 16px;
+ padding-bottom: 20px;
+ background-color: white;
+ border-radius: 4px;
+ &__title {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 107px;
+ color: @text-color;
+ font-size: @font-size-title;
+ background-image: url(@/assets/img/workspace-user.png);
+ background-repeat: no-repeat;
+ background-position: top left;
+ background-size: 100% 100%;
+ }
+
+ &__avatar {
+ position: relative;
+ top: -28px;
+ width: 56px;
+ height: 56px;
+ }
+
+ &__name {
+ margin-top: -20px;
+ margin-bottom: 8px;
+ color: @text-color;
+ font-size: @font-size-content;
+ }
+
+ &__role {
+ display: inline-block;
+ padding: 1px 7px;
+ color: @primary-color-secondary;
+ font-size: 13px;
+ background-color: rgba(187, 210, 255, 0.29);
+ border-radius: 2px;
+ }
+
+ &__participant {
+ &__title {
+ color: @text-color-secondary;
+ font-size: @font-size-content;
+ }
+
+ &__count {
+ width: 24px;
+ height: 24px;
+ color: #8a8a8a;
+ font-size: 12px;
+ line-height: 24px;
+ text-align: center;
+ background-color: rgba(153, 153, 153, 0.13);
+ border-radius: 50%;
+ }
+
+ &__user {
+ width: 36px;
+ height: 36px;
+ }
+ }
+}
diff --git a/react-ui/src/pages/Workspace/components/UserSpace/index.tsx b/react-ui/src/pages/Workspace/components/UserSpace/index.tsx
new file mode 100644
index 00000000..503ea9fc
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/UserSpace/index.tsx
@@ -0,0 +1,47 @@
+import { useModel } from '@umijs/max';
+import { Divider, Flex, Space } from 'antd';
+import styles from './index.less';
+
+type UserSpaceProps = {
+ users: any[];
+};
+
+function UserSpace({ users = [] }: UserSpaceProps) {
+ const { initialState } = useModel('@@initialState');
+ const { currentUser } = initialState || {};
+
+ return (
+
+
工作空间管理
+
+

+
{currentUser?.nickName}
+
{currentUser?.roleNames?.[0]?.roleName}
+
+
+
+ 参与者
+ 8
+
+
+ {users?.map((item, index) => {
+ return (
+
+ );
+ })}
+
+
+
+
+ );
+}
+
+export default UserSpace;
diff --git a/react-ui/src/pages/Workspace/components/WorkspaceIntro/index.less b/react-ui/src/pages/Workspace/components/WorkspaceIntro/index.less
new file mode 100644
index 00000000..0b9a0ddf
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/WorkspaceIntro/index.less
@@ -0,0 +1,43 @@
+.workspace-intro {
+ display: flex;
+ align-items: center;
+ margin-bottom: 16px;
+ padding: 0 30px;
+ background-image: url(@/assets/img/workspace-intro.png);
+ background-repeat: no-repeat;
+ background-position: top right;
+ background-size: 100% 100%;
+ border-radius: 4px;
+
+ &__left {
+ padding: 30px 0 34px;
+ }
+
+ &__right {
+ display: flex;
+ flex: 1;
+ align-items: center;
+ justify-content: center;
+ }
+
+ &__title {
+ margin-bottom: 20px;
+ color: @text-color;
+ font-weight: 500;
+ font-size: 20px;
+ }
+
+ &__content {
+ max-width: 980px;
+ margin-bottom: 20px;
+ color: @text-color-secondary;
+ font-size: @font-size-title;
+ line-height: 1.8;
+ letter-spacing: 1px;
+ }
+
+ &__icon {
+ width: 363px;
+ height: 216px;
+ }
+}
diff --git a/react-ui/src/pages/Workspace/components/WorkspaceIntro/index.tsx b/react-ui/src/pages/Workspace/components/WorkspaceIntro/index.tsx
new file mode 100644
index 00000000..49c03711
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/WorkspaceIntro/index.tsx
@@ -0,0 +1,43 @@
+import { Button } from 'antd';
+import styles from './index.less';
+
+function WorkspaceIntro() {
+ return (
+
+
+
自主实验平台
+
+ 材料领域的自主实验系统是一种用于材料研究和开发的技术平台,它旨在提供实验数据收集、分析和可视化等功能,
+ 以支持材料工程师、科学家和研究人员在材料设计、性能评估和工艺优化方面的工作
+
+
+
+ }
+ >
+ 功能材料自主实验系统
+
+
+ }
+ >
+ 分子材料自主实验系统
+
+
+
+
+
})
+
+
+ );
+}
+
+export default WorkspaceIntro;
diff --git a/react-ui/src/pages/Workspace/index.less b/react-ui/src/pages/Workspace/index.less
new file mode 100644
index 00000000..1a454f38
--- /dev/null
+++ b/react-ui/src/pages/Workspace/index.less
@@ -0,0 +1,45 @@
+.workspace {
+ height: 100%;
+ padding: 20px 30px 10px;
+ overflow-y: auto;
+ background-color: linear-gradient(#ecf2fe, #f9fafb);
+
+ &__overview {
+ margin-bottom: 16px;
+ padding: 20px 30px;
+ background-color: white;
+ border-radius: 4px;
+
+ &__title {
+ margin-bottom: 20px;
+ color: @text-color;
+ font-weight: 500;
+ font-size: @font-size-title;
+ }
+
+ &__content {
+ display: flex;
+ gap: 15px;
+ align-items: center;
+
+ @media screen and (max-width: 1800px) {
+ flex-wrap: wrap;
+ }
+ }
+ }
+
+ &__quick-start {
+ display: flex;
+ gap: 15px;
+ align-items: flex-start;
+ width: 100%;
+ }
+
+ &__user {
+ display: flex;
+ flex-direction: column;
+ width: 326px;
+ min-width: 326px;
+ height: 700px;
+ }
+}
diff --git a/react-ui/src/pages/Workspace/index.tsx b/react-ui/src/pages/Workspace/index.tsx
new file mode 100644
index 00000000..55acd264
--- /dev/null
+++ b/react-ui/src/pages/Workspace/index.tsx
@@ -0,0 +1,71 @@
+import { getWorkspaceOverviewReq } from '@/services/workspace';
+import { ExperimentInstance } from '@/types';
+import { to } from '@/utils/promise';
+import { useEffect, useState } from 'react';
+import AssetsManagement from './components/AssetsManagement';
+import ExperimentChart, { type ExperimentStatistics } from './components/ExperimentChart';
+import ExperitableTable from './components/ExperimentTable';
+import QuickStart from './components/QuickStart';
+import TotalStatistics from './components/TotalStatistics';
+import UserSpace from './components/UserSpace';
+import WorkspaceIntro from './components/WorkspaceIntro';
+import styles from './index.less';
+
+type OverviewData = {
+ workflowCount: number;
+ runningExperimentInsCount: number;
+ experimentInsStatus: ExperimentStatistics;
+ latestExperimentInsList: ExperimentInstance[];
+};
+
+function Workspace() {
+ const [overviewData, setOverviewData] = useState();
+ const users: number[] = new Array(8).fill(0);
+ useEffect(() => {
+ getWorkspaceOverview();
+ }, []);
+
+ // 获取工作空间概况
+ const getWorkspaceOverview = async () => {
+ const [res] = await to(getWorkspaceOverviewReq());
+ if (res && res.data) {
+ setOverviewData(res.data);
+ }
+ };
+
+ return (
+
+
+
+
运行概览
+
+
+
+
+ {overviewData?.experimentInsStatus && (
+
+ )}
+
+
+
+
+ );
+}
+
+export default Workspace;
diff --git a/react-ui/src/requestConfig.ts b/react-ui/src/requestConfig.ts
index 501e78c5..2a9d6413 100644
--- a/react-ui/src/requestConfig.ts
+++ b/react-ui/src/requestConfig.ts
@@ -46,7 +46,8 @@ export const requestConfig: RequestConfig = {
],
responseInterceptors: [
(response: any) => {
- const { status, data } = response;
+ const { status, data } = response || {};
+ console.log('response2', response);
if (status >= 200 && status < 300) {
if (data && (data instanceof Blob || data.code === 200)) {
return response;
diff --git a/react-ui/src/services/ant-design-pro/typings.d.ts b/react-ui/src/services/ant-design-pro/typings.d.ts
index 0da99b38..e94832c6 100644
--- a/react-ui/src/services/ant-design-pro/typings.d.ts
+++ b/react-ui/src/services/ant-design-pro/typings.d.ts
@@ -14,6 +14,9 @@ declare namespace API {
};
address?: string;
phone?: string;
+ roleNames?: {
+ roleName?: string;
+ }[];
};
type ErrorResponse = {
diff --git a/react-ui/src/services/mirror/index.ts b/react-ui/src/services/mirror/index.ts
index 331408a2..5820f631 100644
--- a/react-ui/src/services/mirror/index.ts
+++ b/react-ui/src/services/mirror/index.ts
@@ -1,7 +1,7 @@
/*
* @Author: 赵伟
* @Date: 2024-04-16 14:29:44
- * @Description:
+ * @Description: 镜像管理接口
*/
import { request } from '@umijs/max';
diff --git a/react-ui/src/services/workspace/index.ts b/react-ui/src/services/workspace/index.ts
new file mode 100644
index 00000000..c6cd9696
--- /dev/null
+++ b/react-ui/src/services/workspace/index.ts
@@ -0,0 +1,21 @@
+/*
+ * @Author: 赵伟
+ * @Date: 2024-04-16 14:29:44
+ * @Description: 工作空间接口
+ */
+import { request } from '@umijs/max';
+
+// 获取工作空间概况
+export function getWorkspaceOverviewReq() {
+ return request(`/api/mmp/workspace/overview`, {
+ method: 'GET',
+ });
+}
+
+// 获取工作空间概况
+export function getWorkspaceAssetCountReq(params: any) {
+ return request(`/api/mmp/workspace/assetCount`, {
+ method: 'GET',
+ params,
+ });
+}
diff --git a/react-ui/src/styles/theme.less b/react-ui/src/styles/theme.less
index 0f93891e..c6514915 100644
--- a/react-ui/src/styles/theme.less
+++ b/react-ui/src/styles/theme.less
@@ -6,6 +6,7 @@
// 颜色
@primary-color: #1664ff; // 主色调
+@primary-color-secondary: #4e89ff;
@primary-color-hover: #69b1ff;
@background-color: #f9fafb; // 页面背景颜色
@text-color: #1d1d20;
@@ -15,17 +16,35 @@
@warning-color: #f98e1b;
@border-color: rgba(22, 100, 255, 0.3);
-@border-color-second: rgba(22, 100, 255, 0.1);
-@background-color-primay: rgba(22, 100, 255, 0.03);
+@border-color-secondary: rgba(22, 100, 255, 0.1);
+@background-color-primary: rgba(22, 100, 255, 0.03);
@background-color-gray: rgba(4, 3, 3, 0.06);
@heading-color: rgba(0, 0, 0, 0.85);
@input-icon-hover-color: rgba(0, 0, 0, 0.85);
@border-color-base: #d9d9d9;
@link-hover-color: #69b1ff;
+@sider-background-color: #f2f5f7;
+
+@workspace-background: linear-gradient(
+ 179.03deg,
+ rgba(138, 138, 138, 0.06) 0%,
+ rgba(22, 100, 255, 0.02) 100%
+);
// 字体大小
@font-size: 15px;
+@font-size-title: 18px;
+@font-size-content: 16px;
+
+// 函数
+.addAlpha(@color, @alpha) {
+ @red: red(@color);
+ @green: green(@color);
+ @blue: blue(@color);
+
+ @result: rgba(@red, @green, @blue, @alpha);
+}
// 导出变量
:export {
@@ -34,5 +53,7 @@
errorColor: @error-color;
warningColor: @warning-color;
textColor: @text-color;
+ textColorSecondary: @text-color-secondary;
fontSize: @font-size;
+ siderBGColor: @sider-background-color;
}
diff --git a/react-ui/src/types.ts b/react-ui/src/types.ts
index 8e49075e..a0f53f2d 100644
--- a/react-ui/src/types.ts
+++ b/react-ui/src/types.ts
@@ -12,3 +12,19 @@ export type PipelineGlobalParam = {
param_value: number | string | boolean;
is_sensitive: number;
};
+
+// 实验实例
+export type ExperimentInstance = {
+ id: number;
+ experiment_id: number;
+ workflow_id: number;
+ create_time: string;
+ finish_time: string;
+ update_time: string;
+ status: string;
+ argo_ins_name: string;
+ argo_ins_ns: string;
+ nodes_result: string;
+ nodes_status: string;
+ global_param: PipelineGlobalParam[];
+};
diff --git a/react-ui/src/utils/date.ts b/react-ui/src/utils/date.ts
index be36af05..eaab9f3f 100644
--- a/react-ui/src/utils/date.ts
+++ b/react-ui/src/utils/date.ts
@@ -36,3 +36,15 @@ export const isValidDate = (date: Date): boolean => {
}
return false;
};
+
+// 格式化日期
+export const formatDate = (text: Date | string, format = 'YYYY-MM-DD HH:mm:ss'): string => {
+ if (text === undefined || text === null || text === '') {
+ return '--';
+ }
+ if (!dayjs(text).isValid()) {
+ return '--';
+ }
+
+ return dayjs(text).format(format);
+};
diff --git a/react-ui/src/utils/ui.tsx b/react-ui/src/utils/ui.tsx
index ddf83f6f..4088d703 100644
--- a/react-ui/src/utils/ui.tsx
+++ b/react-ui/src/utils/ui.tsx
@@ -51,7 +51,7 @@ export const gotoLoginPage = (toHome: boolean = true) => {
const { pathname, search } = window.location;
const urlParams = new URLSearchParams();
urlParams.append('redirect', pathname + search);
- const newSearch = toHome ? '' : urlParams.toString();
+ const newSearch = toHome && pathname && pathname !== PageEnum.LOGIN ? '' : urlParams.toString();
if (window.location.pathname !== PageEnum.LOGIN) {
history.replace({
pathname: PageEnum.LOGIN,