| @@ -78,7 +78,7 @@ export default defineConfig({ | |||||
| */ | */ | ||||
| title: '智能软件开发平台', | title: '智能软件开发平台', | ||||
| layout: { | layout: { | ||||
| locale: true, | |||||
| locale: false, | |||||
| ...defaultSettings, | ...defaultSettings, | ||||
| }, | }, | ||||
| // keepalive: [/./], | // keepalive: [/./], | ||||
| @@ -97,10 +97,8 @@ export default defineConfig({ | |||||
| * @doc https://umijs.org/docs/max/i18n | * @doc https://umijs.org/docs/max/i18n | ||||
| */ | */ | ||||
| locale: { | locale: { | ||||
| // default zh-CN | |||||
| default: 'zh-CN', | default: 'zh-CN', | ||||
| antd: true, | antd: true, | ||||
| // default true, when it is true, will use `navigator.language` overwrite default | |||||
| baseNavigator: true, | baseNavigator: true, | ||||
| }, | }, | ||||
| /** | /** | ||||
| @@ -110,6 +108,7 @@ export default defineConfig({ | |||||
| */ | */ | ||||
| antd: { | antd: { | ||||
| configProvider: {}, | configProvider: {}, | ||||
| appConfig: {}, | |||||
| }, | }, | ||||
| /** | /** | ||||
| * @name 网络请求配置 | * @name 网络请求配置 | ||||
| @@ -13,7 +13,7 @@ | |||||
| export default [ | export default [ | ||||
| { | { | ||||
| path: '/', | path: '/', | ||||
| redirect: '/account/center', | |||||
| redirect: '/workspace', | |||||
| }, | }, | ||||
| { | { | ||||
| path: '*', | path: '*', | ||||
| @@ -88,13 +88,6 @@ export default [ | |||||
| }, | }, | ||||
| ], | ], | ||||
| }, | }, | ||||
| { | |||||
| name: 'experiment', | |||||
| path: '/experiment', | |||||
| routes: [ | |||||
| ], | |||||
| }, | |||||
| { | { | ||||
| name: 'developmentEnvironment', | name: 'developmentEnvironment', | ||||
| path: '/developmentEnvironment', | path: '/developmentEnvironment', | ||||
| @@ -127,14 +120,36 @@ export default [ | |||||
| path: '/dataset', | path: '/dataset', | ||||
| routes: [ | routes: [ | ||||
| { | { | ||||
| name: '数据集管理', | |||||
| path: '/dataset/datasetIndex', | |||||
| component: './Dataset/index', | |||||
| name: '数据集', | |||||
| path: 'dataset', | |||||
| routes: [ | |||||
| { | |||||
| name: '数据集列表', | |||||
| path: '', | |||||
| component: './Dataset/index', | |||||
| }, | |||||
| { | |||||
| name: '数据集简介', | |||||
| path: ':id', | |||||
| component: './Dataset/datasetIntro', | |||||
| }, | |||||
| ], | |||||
| }, | }, | ||||
| { | { | ||||
| name: '数据集简介', | |||||
| path: '/dataset/datasetIntro/:id', | |||||
| component: './Dataset/datasetIntro', | |||||
| name: '模型', | |||||
| path: 'model', | |||||
| routes: [ | |||||
| { | |||||
| name: '模型列表', | |||||
| path: '', | |||||
| component: './Model/index', | |||||
| }, | |||||
| { | |||||
| name: '模型简介', | |||||
| path: ':id', | |||||
| component: './Model/modelIntro', | |||||
| }, | |||||
| ], | |||||
| }, | }, | ||||
| { | { | ||||
| name: '镜像', | name: '镜像', | ||||
| @@ -157,19 +172,9 @@ export default [ | |||||
| }, | }, | ||||
| ], | ], | ||||
| }, | }, | ||||
| { | |||||
| name: '模型管理', | |||||
| path: '/dataset/modelIndex', | |||||
| component: './Model/index', | |||||
| }, | |||||
| { | |||||
| name: '模型简介', | |||||
| path: '/dataset/modelIntro/:id', | |||||
| component: './Model/modelIntro', | |||||
| }, | |||||
| ], | ], | ||||
| }, | }, | ||||
| { | { | ||||
| name: 'workspace', | name: 'workspace', | ||||
| path: '/workspace', | path: '/workspace', | ||||
| @@ -177,7 +182,8 @@ export default [ | |||||
| { | { | ||||
| name: '工作空间', | name: '工作空间', | ||||
| path: '', | path: '', | ||||
| component: './missingPage.jsx', | |||||
| key: 'workspace', | |||||
| component: './Workspace/index', | |||||
| }, | }, | ||||
| ], | ], | ||||
| }, | }, | ||||
| @@ -188,11 +194,11 @@ export default [ | |||||
| { | { | ||||
| name: '模型部署', | name: '模型部署', | ||||
| path: '', | path: '', | ||||
| key: 'modelDseployment', | |||||
| component: './missingPage.jsx', | component: './missingPage.jsx', | ||||
| }, | }, | ||||
| ], | ], | ||||
| }, | }, | ||||
| { | { | ||||
| name: 'appsDeployment', | name: 'appsDeployment', | ||||
| path: '/appsDeployment', | path: '/appsDeployment', | ||||
| @@ -200,6 +206,7 @@ export default [ | |||||
| { | { | ||||
| name: '应用开发', | name: '应用开发', | ||||
| path: '', | path: '', | ||||
| key: 'appsDeployment', | |||||
| component: './missingPage.jsx', | component: './missingPage.jsx', | ||||
| }, | }, | ||||
| ], | ], | ||||
| @@ -211,6 +218,7 @@ export default [ | |||||
| { | { | ||||
| name: '监控运维', | name: '监控运维', | ||||
| path: '', | path: '', | ||||
| key: 'see', | |||||
| component: './missingPage.jsx', | component: './missingPage.jsx', | ||||
| }, | }, | ||||
| ], | ], | ||||
| @@ -242,4 +250,16 @@ export default [ | |||||
| }, | }, | ||||
| ], | ], | ||||
| }, | }, | ||||
| { | |||||
| name: 'docs', | |||||
| path: '/docs', | |||||
| routes: [ | |||||
| { | |||||
| name: '使用指南', | |||||
| path: '', | |||||
| key: 'docs', | |||||
| component: './Docs/index', | |||||
| }, | |||||
| ], | |||||
| }, | |||||
| ]; | ]; | ||||
| @@ -60,6 +60,7 @@ | |||||
| "@umijs/route-utils": "^4.0.1", | "@umijs/route-utils": "^4.0.1", | ||||
| "antd": "^5.4.4", | "antd": "^5.4.4", | ||||
| "classnames": "^2.3.2", | "classnames": "^2.3.2", | ||||
| "echarts": "^5.5.0", | |||||
| "fabric": "^5.3.0", | "fabric": "^5.3.0", | ||||
| "highlight.js": "^11.7.0", | "highlight.js": "^11.7.0", | ||||
| "lodash": "^4.17.21", | "lodash": "^4.17.21", | ||||
| @@ -70,6 +71,7 @@ | |||||
| "rc-menu": "^9.8.4", | "rc-menu": "^9.8.4", | ||||
| "rc-util": "^5.30.0", | "rc-util": "^5.30.0", | ||||
| "react": "^18.2.0", | "react": "^18.2.0", | ||||
| "react-activation": "^0.12.4", | |||||
| "react-cropper": "^2.3.3", | "react-cropper": "^2.3.3", | ||||
| "react-dev-inspector": "^1.8.1", | "react-dev-inspector": "^1.8.1", | ||||
| "react-dom": "^18.2.0", | "react-dom": "^18.2.0", | ||||
| @@ -1,8 +1,7 @@ | |||||
| import RightContent from '@/components/RightContent'; | import RightContent from '@/components/RightContent'; | ||||
| import themes from '@/styles/theme.less'; | import themes from '@/styles/theme.less'; | ||||
| import type { Settings as LayoutSettings } from '@ant-design/pro-components'; | import type { Settings as LayoutSettings } from '@ant-design/pro-components'; | ||||
| import type { RunTimeLayoutConfig } from '@umijs/max'; | |||||
| import { history } from '@umijs/max'; | |||||
| import { RuntimeConfig, history } from '@umijs/max'; | |||||
| import { RuntimeAntdConfig } from 'umi'; | import { RuntimeAntdConfig } from 'umi'; | ||||
| import defaultSettings from '../config/defaultSettings'; | import defaultSettings from '../config/defaultSettings'; | ||||
| import '../public/fonts/font.css'; | import '../public/fonts/font.css'; | ||||
| @@ -10,6 +9,7 @@ import { getAccessToken } from './access'; | |||||
| import './dayjsConfig'; | import './dayjsConfig'; | ||||
| import { PageEnum } from './enums/pagesEnums'; | import { PageEnum } from './enums/pagesEnums'; | ||||
| import './global.less'; | import './global.less'; | ||||
| import { removeAllPageCacheState } from './hooks/pageCacheState'; | |||||
| import { | import { | ||||
| getRemoteMenu, | getRemoteMenu, | ||||
| getRoutersInfo, | getRoutersInfo, | ||||
| @@ -29,20 +29,18 @@ export async function getInitialState(): Promise<{ | |||||
| loading?: boolean; | loading?: boolean; | ||||
| fetchUserInfo?: () => Promise<API.CurrentUser | undefined>; | fetchUserInfo?: () => Promise<API.CurrentUser | undefined>; | ||||
| }> { | }> { | ||||
| console.log('getInitialState'); | |||||
| // console.log('getInitialState'); | |||||
| const fetchUserInfo = async () => { | const fetchUserInfo = async () => { | ||||
| try { | try { | ||||
| const response = await getUserInfo({ | const response = await getUserInfo({ | ||||
| skipErrorHandler: true, | skipErrorHandler: true, | ||||
| }); | }); | ||||
| response.user.avatar = | |||||
| response.user.avatar || | |||||
| 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png'; | |||||
| return { | return { | ||||
| ...response.user, | ...response.user, | ||||
| avatar: response.user.avatar || require('@/assets/img/avatar-default.png'), | |||||
| permissions: response.permissions, | permissions: response.permissions, | ||||
| roles: response.roles, | roles: response.roles, | ||||
| roleNames: response.user.roles, | |||||
| } as API.CurrentUser; | } as API.CurrentUser; | ||||
| } catch (error) { | } catch (error) { | ||||
| console.log(error); | console.log(error); | ||||
| @@ -67,7 +65,7 @@ export async function getInitialState(): Promise<{ | |||||
| } | } | ||||
| // ProLayout 支持的api https://procomponents.ant.design/components/layout | // ProLayout 支持的api https://procomponents.ant.design/components/layout | ||||
| export const layout: RunTimeLayoutConfig = ({ initialState }) => { | |||||
| export const layout: RuntimeConfig['layout'] = ({ initialState }) => { | |||||
| return { | return { | ||||
| rightContentRender: () => <RightContent />, | rightContentRender: () => <RightContent />, | ||||
| waterMarkProps: { | waterMarkProps: { | ||||
| @@ -129,7 +127,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => { | |||||
| // </Link>, | // </Link>, | ||||
| // ] | // ] | ||||
| // : [], | // : [], | ||||
| menuHeaderRender: undefined, | |||||
| menuHeaderRender: false, | |||||
| // 自定义 403 页面 | // 自定义 403 页面 | ||||
| // unAccessible: <div>unAccessible</div>, | // unAccessible: <div>unAccessible</div>, | ||||
| // 增加一个 loading 的状态 | // 增加一个 loading 的状态 | ||||
| @@ -137,30 +135,66 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => { | |||||
| // if (initialState?.loading) return <PageLoading />; | // if (initialState?.loading) return <PageLoading />; | ||||
| return <>{children}</>; | return <>{children}</>; | ||||
| }, | }, | ||||
| menuProps: { | |||||
| onClick: () => { | |||||
| // 点击菜单项,删除所有的页面 state 缓存 | |||||
| removeAllPageCacheState(); | |||||
| }, | |||||
| // onSelect: (e) => { | |||||
| // console.log(e); | |||||
| // }, | |||||
| }, | |||||
| ...initialState?.settings, | ...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 ( | |||||
| // <Link to={itemProps.path || ''} target={itemProps.target}> | |||||
| // <KFIcon type={icon} /> | |||||
| // {itemProps.name} | |||||
| // </Link> | |||||
| // ); | |||||
| // }, | |||||
| }; | }; | ||||
| }; | }; | ||||
| export async function onRouteChange({ clientRoutes, location }: any) { | |||||
| export const onRouteChange: RuntimeConfig['onRouteChange'] = async (e) => { | |||||
| const { location } = e; | |||||
| const menus = getRemoteMenu(); | const menus = getRemoteMenu(); | ||||
| // console.log('onRouteChange', clientRoutes, location, menus); | |||||
| console.log('onRouteChange', e); | |||||
| if (menus === null && location.pathname !== PageEnum.LOGIN) { | if (menus === null && location.pathname !== PageEnum.LOGIN) { | ||||
| console.log('refresh'); | console.log('refresh'); | ||||
| history.go(0); | history.go(0); | ||||
| } | } | ||||
| } | |||||
| }; | |||||
| export function patchRoutes({ routes, routeComponents }: any) { | |||||
| //console.log('patchRoutes', routes, routeComponents); | |||||
| } | |||||
| export const patchRoutes: RuntimeConfig['patchRoutes'] = (e) => { | |||||
| console.log('patchRoutes', e); | |||||
| }; | |||||
| export async function patchClientRoutes({ routes }: any) { | |||||
| // console.log('patchClientRoutes', routes); | |||||
| patchRouteWithRemoteMenus(routes); | |||||
| } | |||||
| export const patchClientRoutes: RuntimeConfig['patchClientRoutes'] = (e) => { | |||||
| console.log('patchClientRoutes', e); | |||||
| patchRouteWithRemoteMenus(e.routes); | |||||
| }; | |||||
| export function render(oldRender: () => void) { | export function render(oldRender: () => void) { | ||||
| // console.log('render get routers', oldRender); | |||||
| console.log('render'); | |||||
| const token = getAccessToken(); | const token = getAccessToken(); | ||||
| if (!token || token?.length === 0) { | if (!token || token?.length === 0) { | ||||
| oldRender(); | oldRender(); | ||||
| @@ -1,3 +1,9 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-04-28 14:18:11 | |||||
| * @Description: 自定义 Table 单元格,没有数据时展示 -- | |||||
| */ | |||||
| function CommonTableCell(text?: string | null) { | function CommonTableCell(text?: string | null) { | ||||
| return <span>{text ?? '--'}</span>; | return <span>{text ?? '--'}</span>; | ||||
| } | } | ||||
| @@ -1,3 +1,9 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-04-28 14:18:11 | |||||
| * @Description: 自定义 Table 日期类单元格 | |||||
| */ | |||||
| import dayjs from 'dayjs'; | import dayjs from 'dayjs'; | ||||
| function DateTableCell(text?: string | null) { | function DateTableCell(text?: string | null) { | ||||
| @@ -5,7 +11,7 @@ function DateTableCell(text?: string | null) { | |||||
| return <span>--</span>; | return <span>--</span>; | ||||
| } | } | ||||
| if (!dayjs(text).isValid()) { | if (!dayjs(text).isValid()) { | ||||
| return <span>日期无效</span>; | |||||
| return <span>无效的日期</span>; | |||||
| } | } | ||||
| return <span>{dayjs(text).format('YYYY-MM-DD HH:mm:ss')}</span>; | return <span>{dayjs(text).format('YYYY-MM-DD HH:mm:ss')}</span>; | ||||
| } | } | ||||
| @@ -1,6 +1,7 @@ | |||||
| import KFModal from '@/components/KFModal'; | |||||
| import * as AntdIcons from '@ant-design/icons'; | import * as AntdIcons from '@ant-design/icons'; | ||||
| import { useIntl } from '@umijs/max'; | import { useIntl } from '@umijs/max'; | ||||
| import { Modal, Popover, Progress, Result, Spin, Tooltip, Upload } from 'antd'; | |||||
| import { Popover, Progress, Result, Spin, Tooltip, Upload } from 'antd'; | |||||
| import React, { useCallback, useEffect, useState } from 'react'; | import React, { useCallback, useEffect, useState } from 'react'; | ||||
| import './style.less'; | import './style.less'; | ||||
| @@ -134,7 +135,7 @@ const PicSearcher: React.FC = () => { | |||||
| > | > | ||||
| <AntdIcons.CameraOutlined className="icon-pic-btn" onClick={toggleModal} /> | <AntdIcons.CameraOutlined className="icon-pic-btn" onClick={toggleModal} /> | ||||
| </Popover> | </Popover> | ||||
| <Modal | |||||
| <KFModal | |||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'app.docs.components.icon.pic-searcher.title', | id: 'app.docs.components.icon.pic-searcher.title', | ||||
| defaultMessage: '信息', | defaultMessage: '信息', | ||||
| @@ -228,7 +229,7 @@ const PicSearcher: React.FC = () => { | |||||
| )} | )} | ||||
| </div> | </div> | ||||
| </Spin> | </Spin> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| </div> | </div> | ||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -17,15 +17,16 @@ interface KFIconProps extends IconFontProps { | |||||
| font?: number; | font?: number; | ||||
| color?: string; | color?: string; | ||||
| style?: React.CSSProperties; | style?: React.CSSProperties; | ||||
| className?: string; | |||||
| } | } | ||||
| function KFIcon({ type, font = 15, color = '', style = {} }: KFIconProps) { | |||||
| function KFIcon({ type, font = 15, color = '', style = {}, className }: KFIconProps) { | |||||
| const iconStyle = { | const iconStyle = { | ||||
| ...style, | ...style, | ||||
| fontSize: font, | fontSize: font, | ||||
| color, | color, | ||||
| }; | }; | ||||
| return <Icon type={type} style={iconStyle} />; | |||||
| return <Icon type={type} className={className} style={iconStyle} />; | |||||
| } | } | ||||
| export default KFIcon; | export default KFIcon; | ||||
| @@ -1,30 +1,29 @@ | |||||
| .kf-modal { | .kf-modal { | ||||
| .ant-modal-content { | .ant-modal-content { | ||||
| padding: 20px 67px; | |||||
| padding: 40px 67px; | |||||
| background-image: url(/assets/images/modal-back.png); | background-image: url(/assets/images/modal-back.png); | ||||
| background-repeat:no-repeat; | |||||
| background-size:100%; | |||||
| background-position: top center; | |||||
| // background: linear-gradient(180deg, #cfdfff 0%, #d4e2ff 9.77%, #ffffff 40%, #ffffff 100%); | |||||
| border-radius: 21px; | |||||
| background-repeat: no-repeat; | |||||
| background-position: top center; | |||||
| background-size: 100%; | |||||
| border-radius: 20px; | |||||
| } | } | ||||
| .ant-modal-header { | .ant-modal-header { | ||||
| margin: 20px 0 30px; | |||||
| margin-bottom: 30px; | |||||
| background-color: transparent; | background-color: transparent; | ||||
| } | } | ||||
| .ant-modal-footer { | .ant-modal-footer { | ||||
| display: flex; | display: flex; | ||||
| justify-content: center; | justify-content: center; | ||||
| margin: 40px 0 20px 0; | |||||
| margin-top: 40px; | |||||
| .ant-btn { | .ant-btn { | ||||
| height: 40px; | height: 40px; | ||||
| padding: 0 30px; | padding: 0 30px; | ||||
| font-size: 16px; | |||||
| font-size: @font-size-content; | |||||
| border-radius: 10px; | border-radius: 10px; | ||||
| } | } | ||||
| .ant-btn-default { | .ant-btn-default { | ||||
| color: #1d1d20; | |||||
| color: @text-color; | |||||
| background: rgba(22, 100, 255, 0.06); | background: rgba(22, 100, 255, 0.06); | ||||
| border-color: transparent; | border-color: transparent; | ||||
| } | } | ||||
| @@ -32,10 +31,4 @@ background-position: top center; | |||||
| margin-left: 20px; | margin-left: 20px; | ||||
| } | } | ||||
| } | } | ||||
| .ant-modal-close { | |||||
| top: 27px; | |||||
| right: 27px; | |||||
| width: 26px; | |||||
| height: 26px; | |||||
| } | |||||
| } | } | ||||
| @@ -5,31 +5,22 @@ | |||||
| */ | */ | ||||
| import ModalTitle from '@/components/ModalTitle'; | import ModalTitle from '@/components/ModalTitle'; | ||||
| import { ConfigProvider, Modal, theme, type ModalProps } from 'antd'; | |||||
| import { Modal, type ModalProps } from 'antd'; | |||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import { useAntdConfig } from 'umi'; | |||||
| import './index.less'; | import './index.less'; | ||||
| const { useToken } = theme; | |||||
| export interface KFModalProps extends ModalProps { | export interface KFModalProps extends ModalProps { | ||||
| image: string; | |||||
| image?: string; | |||||
| } | } | ||||
| function KFModal({ title, image, children, className = '', ...rest }: KFModalProps) { | function KFModal({ title, image, children, className = '', ...rest }: KFModalProps) { | ||||
| const { token } = useToken(); | |||||
| console.log('token', token); | |||||
| const antdConfig = useAntdConfig(); | |||||
| console.log('antdConfig', antdConfig); | |||||
| return ( | return ( | ||||
| <ConfigProvider {...antdConfig}> | |||||
| <Modal | |||||
| className={classNames(['kf-modal', className])} | |||||
| {...rest} | |||||
| title={<ModalTitle title={title} image={image}></ModalTitle>} | |||||
| > | |||||
| {children} | |||||
| </Modal> | |||||
| </ConfigProvider> | |||||
| <Modal | |||||
| className={classNames(['kf-modal', className])} | |||||
| {...rest} | |||||
| title={<ModalTitle title={title} image={image}></ModalTitle>} | |||||
| > | |||||
| {children} | |||||
| </Modal> | |||||
| ); | ); | ||||
| } | } | ||||
| @@ -1,7 +1,7 @@ | |||||
| /* | /* | ||||
| * @Author: 赵伟 | * @Author: 赵伟 | ||||
| * @Date: 2024-04-17 16:59:42 | * @Date: 2024-04-17 16:59:42 | ||||
| * @Description: 自定义Radio | |||||
| * @Description: 自定义 Radio | |||||
| */ | */ | ||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| @@ -16,12 +16,14 @@ export type KFRadioItem = { | |||||
| type KFRadioProps = { | type KFRadioProps = { | ||||
| items: KFRadioItem[]; | items: KFRadioItem[]; | ||||
| value?: string; | value?: string; | ||||
| style?: React.CSSProperties; | |||||
| className?: string; | |||||
| onChange?: (value: string) => void; | onChange?: (value: string) => void; | ||||
| }; | }; | ||||
| function KFRadio({ items, value, onChange }: KFRadioProps) { | |||||
| function KFRadio({ items, value, style, className, onChange }: KFRadioProps) { | |||||
| return ( | return ( | ||||
| <span className={'kf-radio'}> | |||||
| <span className={classNames('kf-radio', className)} style={style}> | |||||
| {items.map((item) => { | {items.map((item) => { | ||||
| return ( | return ( | ||||
| <span | <span | ||||
| @@ -1,2 +0,0 @@ | |||||
| .tabs-container { | |||||
| } | |||||
| @@ -1,16 +0,0 @@ | |||||
| // import { Tabs } from 'antd'; | |||||
| // import { useEffect, useState } from 'react'; | |||||
| // import styles from './index.less'; | |||||
| // function KFTabs() { | |||||
| // const [iframeUrl, setIframeUrl] = useState(''); | |||||
| // useEffect(() => {}, []); | |||||
| // return ( | |||||
| // <div className={styles}> | |||||
| // <Tabs></Tabs> | |||||
| // </div> | |||||
| // ); | |||||
| // } | |||||
| // export default KFTabs; | |||||
| @@ -1,11 +1,11 @@ | |||||
| .modal_title { | |||||
| .modal-title { | |||||
| display: flex; | display: flex; | ||||
| align-items: center; | align-items: center; | ||||
| color: @primary-color; | color: @primary-color; | ||||
| font-weight: 400; | font-weight: 400; | ||||
| font-size: 20px; | font-size: 20px; | ||||
| &_image { | |||||
| &__image { | |||||
| width: 22px; | width: 22px; | ||||
| margin-right: 10px; | margin-right: 10px; | ||||
| } | } | ||||
| @@ -1,15 +1,24 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-04-28 14:18:11 | |||||
| * @Description: 自定义 Modal Title | |||||
| */ | |||||
| import classNames from 'classnames'; | |||||
| import React from 'react'; | import React from 'react'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| type ModalTitleProps = { | type ModalTitleProps = { | ||||
| title: React.ReactNode; | title: React.ReactNode; | ||||
| image?: string; | image?: string; | ||||
| style?: React.CSSProperties; | |||||
| className?: string; | |||||
| }; | }; | ||||
| function ModalTitle({ title, image }: ModalTitleProps) { | |||||
| function ModalTitle({ title, image, style, className }: ModalTitleProps) { | |||||
| return ( | return ( | ||||
| <div className={styles.modal_title}> | |||||
| <img className={styles.modal_title_image} src={image} alt="" /> | |||||
| <div className={classNames(styles['modal-title'], className)} style={style}> | |||||
| {image && <img className={styles['modal-title__image']} src={image} alt="" />} | |||||
| {title} | {title} | ||||
| </div> | </div> | ||||
| ); | ); | ||||
| @@ -2,7 +2,7 @@ import { clearSessionToken } from '@/access'; | |||||
| import { setRemoteMenu } from '@/services/session'; | import { setRemoteMenu } from '@/services/session'; | ||||
| import { logout } from '@/services/system/auth'; | import { logout } from '@/services/system/auth'; | ||||
| import { gotoLoginPage } from '@/utils/ui'; | import { gotoLoginPage } from '@/utils/ui'; | ||||
| import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons'; | |||||
| import { LogoutOutlined, UserOutlined } from '@ant-design/icons'; | |||||
| import { setAlpha } from '@ant-design/pro-components'; | import { setAlpha } from '@ant-design/pro-components'; | ||||
| import { useEmotionCss } from '@ant-design/use-emotion-css'; | import { useEmotionCss } from '@ant-design/use-emotion-css'; | ||||
| import { history, useModel } from '@umijs/max'; | import { history, useModel } from '@umijs/max'; | ||||
| @@ -127,11 +127,11 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => { | |||||
| icon: <UserOutlined />, | icon: <UserOutlined />, | ||||
| label: '个人中心', | label: '个人中心', | ||||
| }, | }, | ||||
| { | |||||
| key: 'settings', | |||||
| icon: <SettingOutlined />, | |||||
| label: '个人设置', | |||||
| }, | |||||
| // { | |||||
| // key: 'settings', | |||||
| // icon: <SettingOutlined />, | |||||
| // label: '个人设置', | |||||
| // }, | |||||
| { | { | ||||
| type: 'divider' as const, | type: 'divider' as const, | ||||
| }, | }, | ||||
| @@ -48,7 +48,7 @@ const GlobalHeaderRight: React.FC = () => { | |||||
| > | > | ||||
| <QuestionCircleOutlined /> | <QuestionCircleOutlined /> | ||||
| </span> */} | </span> */} | ||||
| <Avatar menu={false} /> | |||||
| <Avatar menu={true} /> | |||||
| {/* <SelectLang className={actionClassName} /> */} | {/* <SelectLang className={actionClassName} /> */} | ||||
| </div> | </div> | ||||
| ); | ); | ||||
| @@ -4,17 +4,19 @@ | |||||
| * @Description: 分区标题 | * @Description: 分区标题 | ||||
| */ | */ | ||||
| import classNames from 'classnames'; | |||||
| import './index.less'; | import './index.less'; | ||||
| type SubAreaTitleProps = { | type SubAreaTitleProps = { | ||||
| title: string; | title: string; | ||||
| image: string; | image: string; | ||||
| style?: React.CSSProperties; | style?: React.CSSProperties; | ||||
| className?: string; | |||||
| }; | }; | ||||
| function SubAreaTitle({ title, image, style }: SubAreaTitleProps) { | |||||
| function SubAreaTitle({ title, image, style, className }: SubAreaTitleProps) { | |||||
| return ( | return ( | ||||
| <div className={'kf-subarea-title'} style={style}> | |||||
| <div className={classNames('kf-subarea-title', className)} style={style}> | |||||
| <img src={image} width={14} /> | <img src={image} width={14} /> | ||||
| <span style={{ marginLeft: '8px' }}>{title}</span> | <span style={{ marginLeft: '8px' }}>{title}</span> | ||||
| </div> | </div> | ||||
| @@ -1,6 +1,7 @@ | |||||
| html, | html, | ||||
| body, | body, | ||||
| #root { | #root { | ||||
| min-width: 1440px; | |||||
| height: 100%; | height: 100%; | ||||
| margin: 0; | margin: 0; | ||||
| padding: 0; | padding: 0; | ||||
| @@ -20,9 +21,6 @@ body, | |||||
| .ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed { | .ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed { | ||||
| left: unset; | left: unset; | ||||
| } | } | ||||
| .ant-layout-sider-children { | |||||
| margin-top: 60px !important; | |||||
| } | |||||
| canvas { | canvas { | ||||
| display: block; | display: block; | ||||
| } | } | ||||
| @@ -33,58 +31,29 @@ body { | |||||
| -moz-osx-font-smoothing: grayscale; | -moz-osx-font-smoothing: grayscale; | ||||
| } | } | ||||
| .ant-pro-layout .ant-pro-layout-content { | .ant-pro-layout .ant-pro-layout-content { | ||||
| padding: 10px; | |||||
| padding: 0 10px 10px; | |||||
| background-color: transparent; | |||||
| } | } | ||||
| .ant-pro-layout .ant-pro-layout-bg-list { | .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 { | .ant-pro-base-menu-inline-item-title .ant-pro-base-menu-inline-item-text { | ||||
| // color: #1d1d20; | |||||
| font-size: 16px; | font-size: 16px; | ||||
| } | } | ||||
| // .ant-menu-light .ant-menu-item-selected{ | |||||
| // color:#1664ff; | |||||
| // } | |||||
| .ant-pro-layout .ant-pro-sider-menu { | .ant-pro-layout .ant-pro-sider-menu { | ||||
| padding-top: 40px; | 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 { | .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 { | .ant-pro-layout .ant-pro-sider .ant-layout-sider-children { | ||||
| border-right: unset; | border-right: unset; | ||||
| border-bottom-right-radius: 20px; | |||||
| } | } | ||||
| .ant-pro-base-menu-inline { | .ant-pro-base-menu-inline { | ||||
| // height: 87vh; | |||||
| background: #f2f5f7; | |||||
| border-radius: 0px 20px 20px 0px; | border-radius: 0px 20px 20px 0px; | ||||
| } | } | ||||
| .ant-pro-layout .ant-pro-layout-content { | |||||
| background-color: transparent; | |||||
| } | |||||
| .ant-drawer .ant-drawer-body { | .ant-drawer .ant-drawer-body { | ||||
| padding: 0; | padding: 0; | ||||
| } | } | ||||
| @@ -102,99 +71,17 @@ body { | |||||
| padding: 20px 16px; | padding: 20px 16px; | ||||
| background-color: #fff; | background-color: #fff; | ||||
| } | } | ||||
| // .ant-table-wrapper .ant-table { | |||||
| // height: 81vh; | |||||
| // // overflow-y: auto; | |||||
| // } | |||||
| .ant-pro-global-header-logo img { | .ant-pro-global-header-logo img { | ||||
| height: 21px; | height: 21px; | ||||
| } | } | ||||
| .ant-pro-layout .ant-layout-sider.ant-pro-sider { | .ant-pro-layout .ant-layout-sider.ant-pro-sider { | ||||
| height: 94vh; | |||||
| height: 100vh; | |||||
| padding-top: 56px; | |||||
| } | } | ||||
| .ant-pro-layout .ant-pro-layout-container { | .ant-pro-layout .ant-pro-layout-container { | ||||
| height: 100vh; | height: 100vh; | ||||
| overflow-y: hidden; | overflow-y: hidden; | ||||
| } | } | ||||
| .ant-modal-confirm .ant-modal-confirm-paragraph { | |||||
| margin: 54px 0 auto; | |||||
| text-align: center; | |||||
| } | |||||
| .ant-modal-confirm-confirm .ant-modal-confirm-body > .anticon { | |||||
| display: none; | |||||
| } | |||||
| .ant-modal-confirm .ant-modal-confirm-btns { | |||||
| margin-top: 30px; | |||||
| text-align: center; | |||||
| } | |||||
| .ant-modal-confirm-btns .ant-btn-default { | |||||
| width: 110px; | |||||
| height: 40px; | |||||
| margin-right: 10px; | |||||
| // color: #1d1d20; | |||||
| font-size: 18px; | |||||
| background: rgba(22, 100, 255, 0.06); | |||||
| border-color: transparent; | |||||
| border-radius: 10px; | |||||
| } | |||||
| .ant-modal-confirm-btns .ant-btn-default:hover { | |||||
| background: rgba(22, 100, 255, 0.06); | |||||
| border-color: transparent; | |||||
| } | |||||
| .ant-modal-confirm-btns .ant-btn-primary { | |||||
| width: 110px; | |||||
| height: 40px; | |||||
| font-size: 18px; | |||||
| border-radius: 10px; | |||||
| border-radius: 10px; | |||||
| } | |||||
| .ant-modal .ant-input-affix-wrapper { | |||||
| height: 46px; | |||||
| padding: 1px 11px; | |||||
| } | |||||
| .ant-input-textarea-affix-wrapper.ant-input-affix-wrapper{ | |||||
| padding: 0; | |||||
| } | |||||
| .ant-modal .ant-select-single { | |||||
| height: 46px; | |||||
| } | |||||
| .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; | |||||
| color: #272536; | |||||
| border: 2px solid #272536; | |||||
| border-radius: 50%; | |||||
| } | |||||
| .ant-modal-content { | |||||
| margin-top: 50px; | |||||
| margin-left: -130px; | |||||
| } | |||||
| .ant-modal .ant-modal-content { | |||||
| padding: 0; | |||||
| } | |||||
| .ant-modal-confirm-body-wrapper { | |||||
| height: 303px; | |||||
| background-image: url(/assets/images/modal-back.png); | |||||
| background-repeat: no-repeat; | |||||
| background-position: top center; | |||||
| background-size: 100%; | |||||
| border-radius: 0; | |||||
| } | |||||
| .ant-modal .ant-modal-content { | |||||
| border-radius: 20px; | |||||
| } | |||||
| .ant-modal .ant-modal-close:hover { | |||||
| background-color: transparent; | |||||
| } | |||||
| .ant-modal .ant-modal-footer > .ant-btn + .ant-btn { | |||||
| margin-left: 20px; | |||||
| } | |||||
| .ant-pagination .ant-pagination-item.ant-pagination-item-active { | .ant-pagination .ant-pagination-item.ant-pagination-item-active { | ||||
| background: @primary-color; | background: @primary-color; | ||||
| border-width: 0; | border-width: 0; | ||||
| @@ -212,22 +99,18 @@ body { | |||||
| border: 1px solid #e6e6e6; | border: 1px solid #e6e6e6; | ||||
| } | } | ||||
| // ::-webkit-scrollbar-button { | |||||
| // background: #97a1bd; | |||||
| // } | |||||
| ::-webkit-scrollbar { | ::-webkit-scrollbar { | ||||
| width: 9px; | |||||
| border-radius: 2px; | |||||
| width: 8px; | |||||
| background: transparent; | |||||
| } | } | ||||
| ::-webkit-scrollbar-thumb { | ::-webkit-scrollbar-thumb { | ||||
| // background-color: #9aa3bc!important; | |||||
| width: 7px; | |||||
| background: rgba(77, 87, 123, 0.5) !important; | |||||
| width: 8px; | |||||
| background: rgba(0, 0, 0, 0.5); | |||||
| border-radius: 99px; | |||||
| } | } | ||||
| ::-webkit-scrollbar-track { | ::-webkit-scrollbar-track { | ||||
| // background-color: #eaf1ff!important; | |||||
| width: 9px; | |||||
| background: rgba(22, 100, 255, 0.06) !important; | |||||
| width: 8px; | |||||
| background: transparent; | |||||
| } | } | ||||
| ul, | ul, | ||||
| ol { | ol { | ||||
| @@ -41,7 +41,7 @@ export function useVisible(initialValue: boolean) { | |||||
| setVisible(false); | setVisible(false); | ||||
| }, []); | }, []); | ||||
| return [visible, open, close]; | |||||
| return [visible, open, close] as const; | |||||
| } | } | ||||
| type Callback<T> = (state: T) => void; | type Callback<T> = (state: T) => void; | ||||
| @@ -92,7 +92,7 @@ export function useDomSize<T extends HTMLElement>( | |||||
| setWidth(domRef.current.offsetWidth); | setWidth(domRef.current.offsetWidth); | ||||
| } | } | ||||
| }; | }; | ||||
| const debounceFunc = debounce(setDomHeight, 200); | |||||
| const debounceFunc = debounce(setDomHeight, 100); | |||||
| setDomHeight(); | setDomHeight(); | ||||
| window.addEventListener('resize', debounceFunc); | window.addEventListener('resize', debounceFunc); | ||||
| @@ -0,0 +1,58 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-04-28 11:49:48 | |||||
| * @Description: 页面状态缓存,pop 回到这个页面的时候,重新构建之前的状态 | |||||
| */ | |||||
| import { useCallback, useState } from 'react'; | |||||
| const pageKeys: string[] = []; | |||||
| // let stateCaches: Record<string, any> = {}; | |||||
| // 获取页面缓存 | |||||
| const getCacheState = (key: string) => { | |||||
| const jsonStr = sessionStorage.getItem(key); | |||||
| if (jsonStr) { | |||||
| removeCacheState(key); | |||||
| try { | |||||
| return JSON.parse(jsonStr); | |||||
| } catch (error) { | |||||
| return undefined; | |||||
| } | |||||
| } | |||||
| return undefined; | |||||
| }; | |||||
| // 移除页面 state 缓存 | |||||
| const removeCacheState = (key: string) => { | |||||
| sessionStorage.removeItem(key); | |||||
| const index = pageKeys.indexOf(key); | |||||
| if (index !== -1) { | |||||
| pageKeys.splice(index, 1); | |||||
| } | |||||
| }; | |||||
| // 移除所有页面 state 缓存 | |||||
| export const removeAllPageCacheState = () => { | |||||
| pageKeys.forEach((key) => { | |||||
| sessionStorage.removeItem(key); | |||||
| }); | |||||
| }; | |||||
| export const useCacheState = () => { | |||||
| const { pathname } = window.location; | |||||
| const key = 'pagecache:' + pathname; | |||||
| const setCacheState = useCallback( | |||||
| (state?: any) => { | |||||
| if (state) { | |||||
| pageKeys.push(key); | |||||
| sessionStorage.setItem(key, JSON.stringify(state)); | |||||
| } | |||||
| }, | |||||
| [key], | |||||
| ); | |||||
| const [cacheState] = useState(() => getCacheState(key)); | |||||
| return [cacheState, setCacheState] as const; | |||||
| }; | |||||
| @@ -52,3 +52,88 @@ | |||||
| .ant-table-wrapper .ant-table-thead > tr > td { | .ant-table-wrapper .ant-table-thead > tr > td { | ||||
| background-color: #fff; | background-color: #fff; | ||||
| } | } | ||||
| .ant-pro-page-container { | |||||
| overflow-y: auto; | |||||
| } | |||||
| // Input | |||||
| .ant-input-textarea-affix-wrapper.ant-input-affix-wrapper { | |||||
| padding: 0; | |||||
| } | |||||
| // Modal | |||||
| .ant-modal { | |||||
| .ant-modal-close { | |||||
| top: 27px; | |||||
| right: 27px; | |||||
| width: 26px; | |||||
| height: 26px; | |||||
| color: @text-color-secondary; | |||||
| border: 2px solid @text-color-secondary; | |||||
| border-radius: 50%; | |||||
| &:hover, | |||||
| &:active { | |||||
| color: #272536; | |||||
| background-color: transparent; | |||||
| border: 2px solid #272536; | |||||
| } | |||||
| } | |||||
| .ant-input-affix-wrapper { | |||||
| height: 46px; | |||||
| padding: 1px 11px; | |||||
| } | |||||
| .ant-select-single { | |||||
| height: 46px; | |||||
| } | |||||
| .ant-select-single .ant-select-selector .ant-select-selection-placeholder { | |||||
| line-height: 46px; | |||||
| } | |||||
| } | |||||
| // Confirm Modal | |||||
| .ant-modal-confirm { | |||||
| .ant-modal-content { | |||||
| padding: 40px 67px; | |||||
| background-image: url(/assets/images/modal-back.png); | |||||
| background-repeat: no-repeat; | |||||
| background-position: top center; | |||||
| background-size: 100%; | |||||
| border-radius: 20px; | |||||
| } | |||||
| .ant-modal-confirm-body { | |||||
| .anticon { | |||||
| display: none; | |||||
| } | |||||
| } | |||||
| .ant-modal-confirm-paragraph { | |||||
| max-width: 100%; | |||||
| margin-top: 27px; | |||||
| text-align: center; | |||||
| } | |||||
| .ant-modal-confirm-btns { | |||||
| margin-top: 40px; | |||||
| text-align: center; | |||||
| .ant-btn { | |||||
| height: 40px; | |||||
| padding: 0 30px; | |||||
| font-size: @font-size-content; | |||||
| border-radius: 10px; | |||||
| } | |||||
| .ant-btn-default { | |||||
| color: @text-color; | |||||
| background: rgba(22, 100, 255, 0.06); | |||||
| border-color: transparent; | |||||
| } | |||||
| .ant-btn + .ant-btn { | |||||
| margin-left: 20px; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -46,7 +46,7 @@ const Dataset = () => { | |||||
| const onFinish = (values) => {}; | const onFinish = (values) => {}; | ||||
| const routeToIntro = (e, record) => { | const routeToIntro = (e, record) => { | ||||
| e.stopPropagation(); | e.stopPropagation(); | ||||
| navgite({ pathname: '/dataset/datasetIntro' }); | |||||
| navgite({ pathname: '/dataset/dataset' }); | |||||
| }; | }; | ||||
| const onFinishFailed = (errorInfo) => { | const onFinishFailed = (errorInfo) => { | ||||
| console.log('Failed:', errorInfo); | console.log('Failed:', errorInfo); | ||||
| @@ -117,14 +117,14 @@ const PublicData = (React.FC = () => { | |||||
| }; | }; | ||||
| const chooseDatasetType = (val, item) => { | const chooseDatasetType = (val, item) => { | ||||
| console.log(val, item); | console.log(val, item); | ||||
| if (item.path == queryFlow.data_type) { | |||||
| if (item.id == queryFlow.data_type) { | |||||
| setActiveType(''); | setActiveType(''); | ||||
| setQueryFlow({ ...queryFlow, data_type: null }); | setQueryFlow({ ...queryFlow, data_type: null }); | ||||
| getDatasetlist({ ...queryFlow, data_type: null }); | getDatasetlist({ ...queryFlow, data_type: null }); | ||||
| } else { | } 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},()=>{ | // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | ||||
| // getDatasetlist() | // getDatasetlist() | ||||
| @@ -132,14 +132,14 @@ const PublicData = (React.FC = () => { | |||||
| }; | }; | ||||
| const chooseDatasetTag = (val, item) => { | const chooseDatasetTag = (val, item) => { | ||||
| console.log(val, item); | console.log(val, item); | ||||
| if (item.path == queryFlow.data_tag) { | |||||
| if (item.id == queryFlow.data_tag) { | |||||
| setActiveTag(''); | setActiveTag(''); | ||||
| setQueryFlow({ ...queryFlow, data_tag: null }); | setQueryFlow({ ...queryFlow, data_tag: null }); | ||||
| getDatasetlist({ ...queryFlow, data_tag: null }); | getDatasetlist({ ...queryFlow, data_tag: null }); | ||||
| } else { | } 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},()=>{ | // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | ||||
| // getDatasetlist() | // getDatasetlist() | ||||
| @@ -155,7 +155,7 @@ const PublicData = (React.FC = () => { | |||||
| const routeToIntro = (e, record) => { | const routeToIntro = (e, record) => { | ||||
| e.stopPropagation(); | e.stopPropagation(); | ||||
| console.log(record); | console.log(record); | ||||
| navgite({ pathname: `/dataset/datasetIntro/${record.id}` }); | |||||
| navgite({ pathname: `/dataset/dataset/${record.id}` }); | |||||
| }; | }; | ||||
| const onFinishFailed = (errorInfo) => { | const onFinishFailed = (errorInfo) => { | ||||
| console.log('Failed:', errorInfo); | console.log('Failed:', errorInfo); | ||||
| @@ -196,7 +196,7 @@ const PublicData = (React.FC = () => { | |||||
| <div | <div | ||||
| className={[ | className={[ | ||||
| Styles.messageBox, | Styles.messageBox, | ||||
| item.path === activeType ? Styles.active : null, | |||||
| item.id === activeType ? Styles.active : null, | |||||
| ].join(' ')} | ].join(' ')} | ||||
| onClick={(e) => { | onClick={(e) => { | ||||
| chooseDatasetType(e, item); | chooseDatasetType(e, item); | ||||
| @@ -230,7 +230,7 @@ const PublicData = (React.FC = () => { | |||||
| <div | <div | ||||
| className={[ | className={[ | ||||
| Styles.messageBox, | Styles.messageBox, | ||||
| item.path === activeTag ? Styles.active : null, | |||||
| item.id === activeTag ? Styles.active : null, | |||||
| ].join(' ')} | ].join(' ')} | ||||
| onClick={(e) => { | onClick={(e) => { | ||||
| chooseDatasetTag(e, item); | chooseDatasetTag(e, item); | ||||
| @@ -76,14 +76,14 @@ const PublicData = () => { | |||||
| }; | }; | ||||
| const chooseDatasetType = (val, item) => { | const chooseDatasetType = (val, item) => { | ||||
| console.log(val, item); | console.log(val, item); | ||||
| if (item.path == queryFlow.data_type) { | |||||
| if (item.id == queryFlow.data_type) { | |||||
| setActiveType(''); | setActiveType(''); | ||||
| setQueryFlow({ ...queryFlow, data_type: null }); | setQueryFlow({ ...queryFlow, data_type: null }); | ||||
| getDatasetlist({ ...queryFlow, data_type: null }); | getDatasetlist({ ...queryFlow, data_type: null }); | ||||
| } else { | } 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},()=>{ | // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | ||||
| // getDatasetlist() | // getDatasetlist() | ||||
| @@ -91,14 +91,14 @@ const PublicData = () => { | |||||
| }; | }; | ||||
| const chooseDatasetTag = (val, item) => { | const chooseDatasetTag = (val, item) => { | ||||
| console.log(val, item); | console.log(val, item); | ||||
| if (item.path == queryFlow.data_tag) { | |||||
| if (item.id == queryFlow.data_tag) { | |||||
| setActiveTag(''); | setActiveTag(''); | ||||
| setQueryFlow({ ...queryFlow, data_tag: null }); | setQueryFlow({ ...queryFlow, data_tag: null }); | ||||
| getDatasetlist({ ...queryFlow, data_tag: null }); | getDatasetlist({ ...queryFlow, data_tag: null }); | ||||
| } else { | } 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},()=>{ | // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | ||||
| // getDatasetlist() | // getDatasetlist() | ||||
| @@ -108,7 +108,7 @@ const PublicData = () => { | |||||
| const routeToIntro = (e, record) => { | const routeToIntro = (e, record) => { | ||||
| e.stopPropagation(); | e.stopPropagation(); | ||||
| console.log(record); | console.log(record); | ||||
| navgite({ pathname: `/dataset/datasetIntro/${record.id}` }); | |||||
| navgite({ pathname: `/dataset/dataset/${record.id}` }); | |||||
| }; | }; | ||||
| const onFinishFailed = (errorInfo) => { | const onFinishFailed = (errorInfo) => { | ||||
| console.log('Failed:', errorInfo); | console.log('Failed:', errorInfo); | ||||
| @@ -146,7 +146,7 @@ const PublicData = () => { | |||||
| <div | <div | ||||
| className={[ | className={[ | ||||
| Styles.messageBox, | Styles.messageBox, | ||||
| item.path === activeType ? Styles.active : null, | |||||
| item.id === activeType ? Styles.active : null, | |||||
| ].join(' ')} | ].join(' ')} | ||||
| onClick={(e) => { | onClick={(e) => { | ||||
| chooseDatasetType(e, item); | chooseDatasetType(e, item); | ||||
| @@ -180,7 +180,7 @@ const PublicData = () => { | |||||
| <div | <div | ||||
| className={[ | className={[ | ||||
| Styles.messageBox, | Styles.messageBox, | ||||
| item.path === activeTag ? Styles.active : null, | |||||
| item.id === activeTag ? Styles.active : null, | |||||
| ].join(' ')} | ].join(' ')} | ||||
| onClick={(e) => { | onClick={(e) => { | ||||
| chooseDatasetTag(e, item); | chooseDatasetTag(e, item); | ||||
| @@ -0,0 +1,9 @@ | |||||
| const Docs = () => { | |||||
| return ( | |||||
| <iframe | |||||
| style={{ width: '100%', height: '100%', border: 0 }} | |||||
| src={'/assets/材料科研软件平台使用文档.pdf'} | |||||
| ></iframe> | |||||
| ); | |||||
| }; | |||||
| export default Docs; | |||||
| @@ -24,7 +24,7 @@ | |||||
| align-items: center; | align-items: center; | ||||
| width: 100%; | width: 100%; | ||||
| padding: 0 0 0 33px; | padding: 0 0 0 33px; | ||||
| color: #1d1d20; | |||||
| color: @text-color; | |||||
| font-size: 15px; | font-size: 15px; | ||||
| & > div { | & > div { | ||||
| @@ -76,16 +76,18 @@ | |||||
| .statusBox:hover .statusIcon { | .statusBox:hover .statusIcon { | ||||
| visibility: visible; | visibility: visible; | ||||
| } | } | ||||
| .experimentBox{ | |||||
| .experimentBox { | |||||
| height: calc(100% - 20px); | height: calc(100% - 20px); | ||||
| .experimentTable{ | |||||
| .experimentTable { | |||||
| height: calc(100% - 60px); | height: calc(100% - 60px); | ||||
| :global{ | |||||
| .ant-table-wrapper .ant-table{ | |||||
| :global { | |||||
| .ant-table-wrapper .ant-table { | |||||
| // overflow-y: auto; | // overflow-y: auto; | ||||
| height: calc(100% - 48px); | height: calc(100% - 48px); | ||||
| } | } | ||||
| .ant-table-row-expand-icon-cell { | |||||
| padding: 0 30px; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | |||||
| } | |||||
| @@ -16,7 +16,7 @@ export enum ExperimentStatus { | |||||
| } | } | ||||
| type ExperimentStatusKeys = keyof typeof ExperimentStatus; | type ExperimentStatusKeys = keyof typeof ExperimentStatus; | ||||
| type ExperimentStatusValues = (typeof ExperimentStatus)[ExperimentStatusKeys]; | |||||
| export type ExperimentStatusValues = (typeof ExperimentStatus)[ExperimentStatusKeys]; | |||||
| export const experimentStatusInfo: Record<ExperimentStatusValues, StatusInfo | undefined> = { | export const experimentStatusInfo: Record<ExperimentStatusValues, StatusInfo | undefined> = { | ||||
| Running: { | Running: { | ||||
| @@ -11,7 +11,7 @@ import SubAreaTitle from '@/components/SubAreaTitle'; | |||||
| import { CommonTabKeys } from '@/enums'; | import { CommonTabKeys } from '@/enums'; | ||||
| import { createMirrorReq } from '@/services/mirror'; | import { createMirrorReq } from '@/services/mirror'; | ||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import { mirrorNameKey } from '@/utils/sessionKeys'; | |||||
| import { getSessionItemThenRemove, mirrorNameKey } from '@/utils/sessionStorage'; | |||||
| import { getFileListFromEvent } from '@/utils/ui'; | import { getFileListFromEvent } from '@/utils/ui'; | ||||
| import { useNavigate } from '@umijs/max'; | import { useNavigate } from '@umijs/max'; | ||||
| import { Button, Col, Form, Input, Row, Upload, UploadFile, message, type UploadProps } from 'antd'; | import { Button, Col, Form, Input, Row, Upload, UploadFile, message, type UploadProps } from 'antd'; | ||||
| @@ -56,14 +56,11 @@ function MirrorCreate() { | |||||
| }; | }; | ||||
| useEffect(() => { | useEffect(() => { | ||||
| const name = sessionStorage.getItem(mirrorNameKey); | |||||
| const name = getSessionItemThenRemove(mirrorNameKey); | |||||
| if (name) { | if (name) { | ||||
| form.setFieldValue('name', name); | form.setFieldValue('name', name); | ||||
| setNameDisabled(true); | setNameDisabled(true); | ||||
| } | } | ||||
| return () => { | |||||
| sessionStorage.removeItem(mirrorNameKey); | |||||
| }; | |||||
| }, []); | }, []); | ||||
| // 创建公网、本地镜像 | // 创建公网、本地镜像 | ||||
| @@ -9,6 +9,7 @@ import KFIcon from '@/components/KFIcon'; | |||||
| import PageTitle from '@/components/PageTitle'; | import PageTitle from '@/components/PageTitle'; | ||||
| import SubAreaTitle from '@/components/SubAreaTitle'; | import SubAreaTitle from '@/components/SubAreaTitle'; | ||||
| import { useDomSize } from '@/hooks'; | import { useDomSize } from '@/hooks'; | ||||
| import { useCacheState } from '@/hooks/pageCacheState'; | |||||
| import { | import { | ||||
| deleteMirrorVersionReq, | deleteMirrorVersionReq, | ||||
| getMirrorInfoReq, | getMirrorInfoReq, | ||||
| @@ -16,17 +17,17 @@ import { | |||||
| } from '@/services/mirror'; | } from '@/services/mirror'; | ||||
| import themes from '@/styles/theme.less'; | import themes from '@/styles/theme.less'; | ||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import { mirrorNameKey } from '@/utils/sessionKeys'; | |||||
| import { mirrorNameKey, setSessionStorageItem } from '@/utils/sessionStorage'; | |||||
| import { modalConfirm } from '@/utils/ui'; | import { modalConfirm } from '@/utils/ui'; | ||||
| import { useNavigate, useParams, useSearchParams } from '@umijs/max'; | import { useNavigate, useParams, useSearchParams } from '@umijs/max'; | ||||
| import { | import { | ||||
| App, | |||||
| Button, | Button, | ||||
| Col, | Col, | ||||
| ConfigProvider, | ConfigProvider, | ||||
| Flex, | Flex, | ||||
| Row, | Row, | ||||
| Table, | Table, | ||||
| message, | |||||
| type TablePaginationConfig, | type TablePaginationConfig, | ||||
| type TableProps, | type TableProps, | ||||
| } from 'antd'; | } from 'antd'; | ||||
| @@ -56,17 +57,19 @@ function MirrorInfo() { | |||||
| const navigate = useNavigate(); | const navigate = useNavigate(); | ||||
| const urlParams = useParams(); | const urlParams = useParams(); | ||||
| const [searchParams] = useSearchParams(); | const [searchParams] = useSearchParams(); | ||||
| const [cacheState, setCacheState] = useCacheState(); | |||||
| const [mirrorInfo, setMirrorInfo] = useState<MirrorInfoData>({}); | const [mirrorInfo, setMirrorInfo] = useState<MirrorInfoData>({}); | ||||
| const [tableData, setTableData] = useState<MirrorVersionData[]>([]); | const [tableData, setTableData] = useState<MirrorVersionData[]>([]); | ||||
| const [topRef, { height: topHeight }] = useDomSize<HTMLDivElement>(0, 0, [mirrorInfo]); | const [topRef, { height: topHeight }] = useDomSize<HTMLDivElement>(0, 0, [mirrorInfo]); | ||||
| const [total, setTotal] = useState(0); | const [total, setTotal] = useState(0); | ||||
| const [pagination, setPagination] = useState<TablePaginationConfig>({ | |||||
| showSizeChanger: true, | |||||
| showQuickJumper: true, | |||||
| current: 1, | |||||
| pageSize: 10, | |||||
| }); | |||||
| const [pagination, setPagination] = useState<TablePaginationConfig>( | |||||
| cacheState?.pagination ?? { | |||||
| current: 1, | |||||
| pageSize: 10, | |||||
| }, | |||||
| ); | |||||
| const isPublic = searchParams.get('isPublic') === 'true'; | const isPublic = searchParams.get('isPublic') === 'true'; | ||||
| const { message } = App.useApp(); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| getMirrorInfo(); | getMirrorInfo(); | ||||
| }, []); | }, []); | ||||
| @@ -115,7 +118,7 @@ function MirrorInfo() { | |||||
| // 如果是一页的唯一数据,删除时,请求第一页的数据 | // 如果是一页的唯一数据,删除时,请求第一页的数据 | ||||
| // 否则直接刷新这一页的数据 | // 否则直接刷新这一页的数据 | ||||
| // 避免回到第一页 | // 避免回到第一页 | ||||
| if (tableData.length > 1) { | |||||
| if (tableData.length === 1) { | |||||
| setPagination((prev) => ({ | setPagination((prev) => ({ | ||||
| ...prev, | ...prev, | ||||
| current: 1, | current: 1, | ||||
| @@ -146,7 +149,10 @@ function MirrorInfo() { | |||||
| const createMirrorVersion = () => { | const createMirrorVersion = () => { | ||||
| navigate(`/dataset/mirror/create`); | navigate(`/dataset/mirror/create`); | ||||
| sessionStorage.setItem(mirrorNameKey, mirrorInfo.name || ''); | |||||
| setSessionStorageItem(mirrorNameKey, mirrorInfo.name || ''); | |||||
| setCacheState({ | |||||
| pagination, | |||||
| }); | |||||
| }; | }; | ||||
| const columns: TableProps<MirrorVersionData>['columns'] = [ | const columns: TableProps<MirrorVersionData>['columns'] = [ | ||||
| @@ -256,13 +262,14 @@ function MirrorInfo() { | |||||
| </Col> | </Col> | ||||
| </Row> | </Row> | ||||
| </div> | </div> | ||||
| <Flex justify="space-between" align="center" style={{ marginTop: '40px' }}> | |||||
| <Flex justify="flex-start" align="center" style={{ marginTop: '40px' }}> | |||||
| <SubAreaTitle | <SubAreaTitle | ||||
| title="镜像版本" | title="镜像版本" | ||||
| image={require('@/assets/img/mirror-version.png')} | image={require('@/assets/img/mirror-version.png')} | ||||
| ></SubAreaTitle> | ></SubAreaTitle> | ||||
| {!isPublic && ( | {!isPublic && ( | ||||
| <Button | <Button | ||||
| style={{ marginRight: 0, marginLeft: 'auto' }} | |||||
| type="default" | type="default" | ||||
| onClick={createMirrorVersion} | onClick={createMirrorVersion} | ||||
| icon={<KFIcon type="icon-xinjian2" />} | icon={<KFIcon type="icon-xinjian2" />} | ||||
| @@ -270,6 +277,14 @@ function MirrorInfo() { | |||||
| 新增镜像版本 | 新增镜像版本 | ||||
| </Button> | </Button> | ||||
| )} | )} | ||||
| <Button | |||||
| style={{ marginLeft: '20px' }} | |||||
| type="default" | |||||
| onClick={getMirrorVersionList} | |||||
| icon={<KFIcon type="icon-shuaxin" />} | |||||
| > | |||||
| 刷新 | |||||
| </Button> | |||||
| </Flex> | </Flex> | ||||
| </div> | </div> | ||||
| <div | <div | ||||
| @@ -280,7 +295,7 @@ function MirrorInfo() { | |||||
| dataSource={tableData} | dataSource={tableData} | ||||
| columns={columns} | columns={columns} | ||||
| scroll={{ y: 'calc(100% - 55px)' }} | scroll={{ y: 'calc(100% - 55px)' }} | ||||
| pagination={{ ...pagination, total }} | |||||
| pagination={{ ...pagination, total, showSizeChanger: true, showQuickJumper: true }} | |||||
| onChange={handleTableChange} | onChange={handleTableChange} | ||||
| rowKey="id" | rowKey="id" | ||||
| /> | /> | ||||
| @@ -7,11 +7,12 @@ import CommonTableCell from '@/components/CommonTableCell'; | |||||
| import DateTableCell from '@/components/DateTableCell'; | import DateTableCell from '@/components/DateTableCell'; | ||||
| import KFIcon from '@/components/KFIcon'; | import KFIcon from '@/components/KFIcon'; | ||||
| import { CommonTabKeys } from '@/enums'; | import { CommonTabKeys } from '@/enums'; | ||||
| import { useCacheState } from '@/hooks/pageCacheState'; | |||||
| import { deleteMirrorReq, getMirrorListReq } from '@/services/mirror'; | import { deleteMirrorReq, getMirrorListReq } from '@/services/mirror'; | ||||
| import themes from '@/styles/theme.less'; | import themes from '@/styles/theme.less'; | ||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import { modalConfirm } from '@/utils/ui'; | import { modalConfirm } from '@/utils/ui'; | ||||
| import { useNavigate, useSearchParams } from '@umijs/max'; | |||||
| import { useNavigate } from '@umijs/max'; | |||||
| import { | import { | ||||
| Button, | Button, | ||||
| ConfigProvider, | ConfigProvider, | ||||
| @@ -50,20 +51,17 @@ export type MirrorData = { | |||||
| function MirrorList() { | function MirrorList() { | ||||
| const navigate = useNavigate(); | const navigate = useNavigate(); | ||||
| const [searchParams, setSearchParams] = useSearchParams(); | |||||
| const isPrivate = searchParams.get('isPublic') === 'false'; | |||||
| const [activeTab, setActiveTab] = useState<string>( | |||||
| isPrivate ? CommonTabKeys.Private : CommonTabKeys.Public, | |||||
| ); | |||||
| const [searchText, setSearchText] = useState(''); | |||||
| const [cacheState, setCacheState] = useCacheState(); | |||||
| const [activeTab, setActiveTab] = useState<string>(cacheState?.activeTab ?? CommonTabKeys.Public); | |||||
| const [searchText, setSearchText] = useState(cacheState?.searchText); | |||||
| const [tableData, setTableData] = useState<MirrorData[]>([]); | const [tableData, setTableData] = useState<MirrorData[]>([]); | ||||
| const [total, setTotal] = useState(0); | const [total, setTotal] = useState(0); | ||||
| const [pagination, setPagination] = useState<TablePaginationConfig>({ | |||||
| showSizeChanger: true, | |||||
| showQuickJumper: true, | |||||
| current: 1, | |||||
| pageSize: 10, | |||||
| }); | |||||
| const [pagination, setPagination] = useState<TablePaginationConfig>( | |||||
| cacheState?.pagination ?? { | |||||
| current: 1, | |||||
| pageSize: 10, | |||||
| }, | |||||
| ); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| getMirrorList(); | getMirrorList(); | ||||
| @@ -73,17 +71,12 @@ function MirrorList() { | |||||
| const hanleTabChange: TabsProps['onChange'] = (value) => { | const hanleTabChange: TabsProps['onChange'] = (value) => { | ||||
| setSearchText(''); | setSearchText(''); | ||||
| setPagination({ | setPagination({ | ||||
| showSizeChanger: true, | |||||
| showQuickJumper: true, | |||||
| current: 1, | current: 1, | ||||
| pageSize: 10, | pageSize: 10, | ||||
| }); | }); | ||||
| setTotal(0); | setTotal(0); | ||||
| setTableData([]); | setTableData([]); | ||||
| setActiveTab(value); | setActiveTab(value); | ||||
| setSearchParams([['isPublic', value === CommonTabKeys.Public ? 'true' : 'false']], { | |||||
| replace: true, | |||||
| }); | |||||
| }; | }; | ||||
| // 获取镜像列表 | // 获取镜像列表 | ||||
| const getMirrorList = async (params?: Record<string, any>) => { | const getMirrorList = async (params?: Record<string, any>) => { | ||||
| @@ -131,11 +124,11 @@ function MirrorList() { | |||||
| // 查看详情 | // 查看详情 | ||||
| const toDetail = (record: MirrorData) => { | const toDetail = (record: MirrorData) => { | ||||
| console.log('record', record); | |||||
| navigate(`/dataset/mirror/${record.id}?isPublic=${activeTab === CommonTabKeys.Public}`, { | |||||
| state: { | |||||
| isPublic: activeTab === CommonTabKeys.Public, | |||||
| }, | |||||
| navigate(`/dataset/mirror/${record.id}?isPublic=${activeTab === CommonTabKeys.Public}`); | |||||
| setCacheState({ | |||||
| activeTab, | |||||
| pagination, | |||||
| searchText, | |||||
| }); | }); | ||||
| }; | }; | ||||
| @@ -153,6 +146,11 @@ function MirrorList() { | |||||
| // 创建镜像 | // 创建镜像 | ||||
| const createMirror = () => { | const createMirror = () => { | ||||
| navigate(`/dataset/mirror/create`); | navigate(`/dataset/mirror/create`); | ||||
| setCacheState({ | |||||
| activeTab, | |||||
| pagination, | |||||
| searchText, | |||||
| }); | |||||
| }; | }; | ||||
| // 分页切换 | // 分页切换 | ||||
| @@ -276,7 +274,12 @@ function MirrorList() { | |||||
| dataSource={tableData} | dataSource={tableData} | ||||
| columns={columns} | columns={columns} | ||||
| scroll={{ y: 'calc(100% - 55px)' }} | scroll={{ y: 'calc(100% - 55px)' }} | ||||
| pagination={{ ...pagination, total: total }} | |||||
| pagination={{ | |||||
| ...pagination, | |||||
| total: total, | |||||
| showSizeChanger: true, | |||||
| showQuickJumper: true, | |||||
| }} | |||||
| onChange={handleTableChange} | onChange={handleTableChange} | ||||
| rowKey="id" | rowKey="id" | ||||
| /> | /> | ||||
| @@ -46,7 +46,7 @@ const Dataset = () => { | |||||
| const onFinish = (values) => {}; | const onFinish = (values) => {}; | ||||
| const routeToIntro = (e, record) => { | const routeToIntro = (e, record) => { | ||||
| e.stopPropagation(); | e.stopPropagation(); | ||||
| navgite({ pathname: '/dataset/datasetIntro' }); | |||||
| navgite({ pathname: '/dataset/dataset' }); | |||||
| }; | }; | ||||
| const onFinishFailed = (errorInfo) => { | const onFinishFailed = (errorInfo) => { | ||||
| console.log('Failed:', errorInfo); | console.log('Failed:', errorInfo); | ||||
| @@ -121,14 +121,14 @@ const PublicData = () => { | |||||
| const chooseModelType = (val, item) => { | const chooseModelType = (val, item) => { | ||||
| console.log(val, item); | console.log(val, item); | ||||
| if (item.path == queryFlow.model_type) { | |||||
| if (item.id == queryFlow.model_type) { | |||||
| setActiveType(''); | setActiveType(''); | ||||
| setQueryFlow({ ...queryFlow, model_type: null }); | setQueryFlow({ ...queryFlow, model_type: null }); | ||||
| getModelLists({ ...queryFlow, model_type: null }); | getModelLists({ ...queryFlow, model_type: null }); | ||||
| } else { | } 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},()=>{ | // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | ||||
| @@ -136,14 +136,14 @@ const PublicData = () => { | |||||
| // }) | // }) | ||||
| }; | }; | ||||
| const chooseModelTag = (val, item) => { | const chooseModelTag = (val, item) => { | ||||
| if (item.path == queryFlow.model_tag) { | |||||
| if (item.id == queryFlow.model_tag) { | |||||
| setActiveTag(''); | setActiveTag(''); | ||||
| setQueryFlow({ ...queryFlow, model_tag: null }); | setQueryFlow({ ...queryFlow, model_tag: null }); | ||||
| getModelLists({ ...queryFlow, model_tag: null }); | getModelLists({ ...queryFlow, model_tag: null }); | ||||
| } else { | } 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},()=>{ | // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | ||||
| // getDatasetlist() | // getDatasetlist() | ||||
| @@ -152,7 +152,7 @@ const PublicData = () => { | |||||
| const routeToIntro = (e, record) => { | const routeToIntro = (e, record) => { | ||||
| e.stopPropagation(); | e.stopPropagation(); | ||||
| console.log(record); | console.log(record); | ||||
| navgite({ pathname: `/dataset/modelIntro/${record.id}` }); | |||||
| navgite({ pathname: `/dataset/model/${record.id}` }); | |||||
| }; | }; | ||||
| const onFinishFailed = (errorInfo) => { | const onFinishFailed = (errorInfo) => { | ||||
| console.log('Failed:', errorInfo); | console.log('Failed:', errorInfo); | ||||
| @@ -190,7 +190,7 @@ const PublicData = () => { | |||||
| <div | <div | ||||
| className={[ | className={[ | ||||
| Styles.messageBox, | Styles.messageBox, | ||||
| item.path === activeType ? Styles.active : null, | |||||
| item.id === activeType ? Styles.active : null, | |||||
| ].join(' ')} | ].join(' ')} | ||||
| onClick={(e) => { | onClick={(e) => { | ||||
| chooseModelType(e, item); | chooseModelType(e, item); | ||||
| @@ -231,7 +231,7 @@ const PublicData = () => { | |||||
| <div | <div | ||||
| className={[ | className={[ | ||||
| Styles.messageBox, | Styles.messageBox, | ||||
| item.path === activeTag ? Styles.active : null, | |||||
| item.id === activeTag ? Styles.active : null, | |||||
| ].join(' ')} | ].join(' ')} | ||||
| onClick={(e) => { | onClick={(e) => { | ||||
| chooseModelTag(e, item); | chooseModelTag(e, item); | ||||
| @@ -77,14 +77,14 @@ const PublicData = () => { | |||||
| }; | }; | ||||
| const chooseModelType = (val, item) => { | const chooseModelType = (val, item) => { | ||||
| console.log(val, item); | console.log(val, item); | ||||
| if (item.path == queryFlow.model_type) { | |||||
| if (item.id == queryFlow.model_type) { | |||||
| setActiveType(''); | setActiveType(''); | ||||
| setQueryFlow({ ...queryFlow, model_type: null }); | setQueryFlow({ ...queryFlow, model_type: null }); | ||||
| getModelLists({ ...queryFlow, model_type: null }); | getModelLists({ ...queryFlow, model_type: null }); | ||||
| } else { | } 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},()=>{ | // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | ||||
| @@ -92,14 +92,14 @@ const PublicData = () => { | |||||
| // }) | // }) | ||||
| }; | }; | ||||
| const chooseModelTag = (val, item) => { | const chooseModelTag = (val, item) => { | ||||
| if (item.path == queryFlow.model_tag) { | |||||
| if (item.id == queryFlow.model_tag) { | |||||
| setActiveTag(''); | setActiveTag(''); | ||||
| setQueryFlow({ ...queryFlow, model_tag: null }); | setQueryFlow({ ...queryFlow, model_tag: null }); | ||||
| getModelLists({ ...queryFlow, model_tag: null }); | getModelLists({ ...queryFlow, model_tag: null }); | ||||
| } else { | } 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},()=>{ | // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | ||||
| // getDatasetlist() | // getDatasetlist() | ||||
| @@ -109,7 +109,7 @@ const PublicData = () => { | |||||
| const routeToIntro = (e, record) => { | const routeToIntro = (e, record) => { | ||||
| e.stopPropagation(); | e.stopPropagation(); | ||||
| console.log(record); | console.log(record); | ||||
| navgite({ pathname: `/dataset/modelIntro/${record.id}` }); | |||||
| navgite({ pathname: `/dataset/model/${record.id}` }); | |||||
| }; | }; | ||||
| const onFinishFailed = (errorInfo) => { | const onFinishFailed = (errorInfo) => { | ||||
| console.log('Failed:', errorInfo); | console.log('Failed:', errorInfo); | ||||
| @@ -147,7 +147,7 @@ const PublicData = () => { | |||||
| <div | <div | ||||
| className={[ | className={[ | ||||
| Styles.messageBox, | Styles.messageBox, | ||||
| item.path === activeType ? Styles.active : null, | |||||
| item.id === activeType ? Styles.active : null, | |||||
| ].join(' ')} | ].join(' ')} | ||||
| onClick={(e) => { | onClick={(e) => { | ||||
| chooseModelType(e, item); | chooseModelType(e, item); | ||||
| @@ -181,7 +181,7 @@ const PublicData = () => { | |||||
| <div | <div | ||||
| className={[ | className={[ | ||||
| Styles.messageBox, | Styles.messageBox, | ||||
| item.path === activeTag ? Styles.active : null, | |||||
| item.id === activeTag ? Styles.active : null, | |||||
| ].join(' ')} | ].join(' ')} | ||||
| onClick={(e) => { | onClick={(e) => { | ||||
| chooseModelTag(e, item); | chooseModelTag(e, item); | ||||
| @@ -1,9 +1,9 @@ | |||||
| import { DictValueEnumObj } from '@/components/DictTag'; | import { DictValueEnumObj } from '@/components/DictTag'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| import { getValueEnumLabel } from '@/utils/options'; | import { getValueEnumLabel } from '@/utils/options'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Button, Descriptions, Modal } from 'antd'; | |||||
| import { Button, Descriptions } from 'antd'; | |||||
| import React, { useEffect } from 'react'; | import React, { useEffect } from 'react'; | ||||
| /* * | /* * | ||||
| * | * | ||||
| * @author whiteshader@163.com | * @author whiteshader@163.com | ||||
| @@ -39,7 +39,7 @@ const OperlogForm: React.FC<OperlogFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={800} | width={800} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'monitor.job.detail', | id: 'monitor.job.detail', | ||||
| @@ -124,7 +124,7 @@ const OperlogForm: React.FC<OperlogFormProps> = (props) => { | |||||
| {values.invokeTarget} | {values.invokeTarget} | ||||
| </Descriptions.Item> | </Descriptions.Item> | ||||
| </Descriptions> | </Descriptions> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -11,7 +11,7 @@ import { | |||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Form, Modal } from 'antd'; | import { Form, Modal } from 'antd'; | ||||
| import React, { useEffect } from 'react'; | import React, { useEffect } from 'react'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| /** | /** | ||||
| * 定时任务调度 Edit Form | * 定时任务调度 Edit Form | ||||
| * | * | ||||
| @@ -66,7 +66,7 @@ const JobForm: React.FC<JobFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'monitor.job.title', | id: 'monitor.job.title', | ||||
| @@ -238,7 +238,7 @@ const JobForm: React.FC<JobFormProps> = (props) => { | |||||
| ]} | ]} | ||||
| /> | /> | ||||
| </ProForm> | </ProForm> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,16 +1,10 @@ | |||||
| import { DictValueEnumObj } from '@/components/DictTag'; | import { DictValueEnumObj } from '@/components/DictTag'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| import { getValueEnumLabel } from '@/utils/options'; | import { getValueEnumLabel } from '@/utils/options'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Descriptions, Modal } from 'antd'; | |||||
| import { Descriptions } from 'antd'; | |||||
| import React, { useEffect } from 'react'; | import React, { useEffect } from 'react'; | ||||
| /* * | |||||
| * | |||||
| * @author whiteshader@163.com | |||||
| * @datetime 2021/09/16 | |||||
| * | |||||
| * */ | |||||
| export type JobLogFormValueType = Record<string, unknown> & Partial<API.Monitor.JobLog>; | export type JobLogFormValueType = Record<string, unknown> & Partial<API.Monitor.JobLog>; | ||||
| export type JobLogFormProps = { | export type JobLogFormProps = { | ||||
| @@ -33,7 +27,7 @@ const JobLogDetailForm: React.FC<JobLogFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'monitor.job.log.title', | id: 'monitor.job.log.title', | ||||
| @@ -95,7 +89,7 @@ const JobLogDetailForm: React.FC<JobLogFormProps> = (props) => { | |||||
| {getValueEnumLabel(statusOptions, values.status, '未知')} | {getValueEnumLabel(statusOptions, values.status, '未知')} | ||||
| </Descriptions.Item> | </Descriptions.Item> | ||||
| </Descriptions> | </Descriptions> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -22,7 +22,7 @@ | |||||
| height: 398px; | height: 398px; | ||||
| margin-right: 15px; | margin-right: 15px; | ||||
| padding: 15px; | padding: 15px; | ||||
| background-color: @background-color-primay; | |||||
| background-color: @background-color-primary; | |||||
| border: 1px solid @border-color; | border: 1px solid @border-color; | ||||
| border-radius: 8px; | border-radius: 8px; | ||||
| @@ -31,7 +31,7 @@ | |||||
| padding-left: 0; | padding-left: 0; | ||||
| background-color: transparent; | background-color: transparent; | ||||
| border-width: 0; | border-width: 0; | ||||
| border-bottom: 1px solid @border-color-second; | |||||
| border-bottom: 1px solid @border-color-secondary; | |||||
| border-radius: 0; | border-radius: 0; | ||||
| } | } | ||||
| } | } | ||||
| @@ -40,7 +40,7 @@ | |||||
| width: calc(100% - 488px - 15px); | width: calc(100% - 488px - 15px); | ||||
| height: 398px; | height: 398px; | ||||
| padding: 15px; | padding: 15px; | ||||
| background-color: @background-color-primay; | |||||
| background-color: @background-color-primary; | |||||
| border: 1px solid @border-color; | border: 1px solid @border-color; | ||||
| border-radius: 8px; | border-radius: 8px; | ||||
| @@ -49,7 +49,7 @@ | |||||
| padding: 3px 0 6px; | padding: 3px 0 6px; | ||||
| color: @text-color; | color: @text-color; | ||||
| font-size: @font-size; | font-size: @font-size; | ||||
| border-bottom: 1px solid @border-color-second; | |||||
| border-bottom: 1px solid @border-color-secondary; | |||||
| } | } | ||||
| &__files { | &__files { | ||||
| height: calc(100% - 75px); | height: calc(100% - 75px); | ||||
| @@ -1,4 +1,5 @@ | |||||
| import { DictValueEnumObj } from '@/components/DictTag'; | import { DictValueEnumObj } from '@/components/DictTag'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| import { | import { | ||||
| ProForm, | ProForm, | ||||
| ProFormDigit, | ProFormDigit, | ||||
| @@ -7,9 +8,8 @@ import { | |||||
| ProFormTextArea, | ProFormTextArea, | ||||
| } from '@ant-design/pro-components'; | } from '@ant-design/pro-components'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Form, Modal } from 'antd'; | |||||
| import { Form } from 'antd'; | |||||
| import React, { useEffect } from 'react'; | import React, { useEffect } from 'react'; | ||||
| export type ConfigFormData = Record<string, unknown> & Partial<API.System.Config>; | export type ConfigFormData = Record<string, unknown> & Partial<API.System.Config>; | ||||
| export type ConfigFormProps = { | export type ConfigFormProps = { | ||||
| @@ -53,7 +53,7 @@ const ConfigForm: React.FC<ConfigFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.config.title', | id: 'system.config.title', | ||||
| @@ -166,7 +166,7 @@ const ConfigForm: React.FC<ConfigFormProps> = (props) => { | |||||
| ]} | ]} | ||||
| /> | /> | ||||
| </ProForm> | </ProForm> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,4 +1,5 @@ | |||||
| import { DictValueEnumObj } from '@/components/DictTag'; | import { DictValueEnumObj } from '@/components/DictTag'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| import { | import { | ||||
| ProForm, | ProForm, | ||||
| ProFormDigit, | ProFormDigit, | ||||
| @@ -7,10 +8,9 @@ import { | |||||
| ProFormTreeSelect, | ProFormTreeSelect, | ||||
| } from '@ant-design/pro-components'; | } from '@ant-design/pro-components'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Form, Modal } from 'antd'; | |||||
| import { Form } from 'antd'; | |||||
| import { DataNode } from 'antd/es/tree'; | import { DataNode } from 'antd/es/tree'; | ||||
| import React, { useEffect } from 'react'; | import React, { useEffect } from 'react'; | ||||
| export type DeptFormData = Record<string, unknown> & Partial<API.System.Dept>; | export type DeptFormData = Record<string, unknown> & Partial<API.System.Dept>; | ||||
| export type DeptFormProps = { | export type DeptFormProps = { | ||||
| @@ -59,7 +59,7 @@ const DeptForm: React.FC<DeptFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.dept.title', | id: 'system.dept.title', | ||||
| @@ -204,7 +204,7 @@ const DeptForm: React.FC<DeptFormProps> = (props) => { | |||||
| ]} | ]} | ||||
| /> | /> | ||||
| </ProForm> | </ProForm> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,4 +1,5 @@ | |||||
| import { DictValueEnumObj } from '@/components/DictTag'; | import { DictValueEnumObj } from '@/components/DictTag'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| import { | import { | ||||
| ProForm, | ProForm, | ||||
| ProFormDigit, | ProFormDigit, | ||||
| @@ -7,9 +8,8 @@ import { | |||||
| ProFormTextArea, | ProFormTextArea, | ||||
| } from '@ant-design/pro-components'; | } from '@ant-design/pro-components'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Form, Modal } from 'antd'; | |||||
| import { Form } from 'antd'; | |||||
| import React, { useEffect } from 'react'; | import React, { useEffect } from 'react'; | ||||
| export type DictTypeFormData = Record<string, unknown> & Partial<API.System.DictType>; | export type DictTypeFormData = Record<string, unknown> & Partial<API.System.DictType>; | ||||
| export type DictTypeFormProps = { | export type DictTypeFormProps = { | ||||
| @@ -52,7 +52,7 @@ const DictTypeForm: React.FC<DictTypeFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.dict.title', | id: 'system.dict.title', | ||||
| @@ -146,7 +146,7 @@ const DictTypeForm: React.FC<DictTypeFormProps> = (props) => { | |||||
| ]} | ]} | ||||
| /> | /> | ||||
| </ProForm> | </ProForm> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,4 +1,5 @@ | |||||
| import { DictValueEnumObj } from '@/components/DictTag'; | import { DictValueEnumObj } from '@/components/DictTag'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| import { | import { | ||||
| ProForm, | ProForm, | ||||
| ProFormDigit, | ProFormDigit, | ||||
| @@ -8,9 +9,8 @@ import { | |||||
| ProFormTextArea, | ProFormTextArea, | ||||
| } from '@ant-design/pro-components'; | } from '@ant-design/pro-components'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Form, Modal } from 'antd'; | |||||
| import { Form } from 'antd'; | |||||
| import React, { useEffect } from 'react'; | import React, { useEffect } from 'react'; | ||||
| export type DataFormData = Record<string, unknown> & Partial<API.System.DictData>; | export type DataFormData = Record<string, unknown> & Partial<API.System.DictData>; | ||||
| export type DataFormProps = { | export type DataFormProps = { | ||||
| @@ -58,7 +58,7 @@ const DictDataForm: React.FC<DataFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.dict.data.title', | id: 'system.dict.data.title', | ||||
| @@ -246,7 +246,7 @@ const DictDataForm: React.FC<DataFormProps> = (props) => { | |||||
| ]} | ]} | ||||
| /> | /> | ||||
| </ProForm> | </ProForm> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,4 +1,5 @@ | |||||
| import { DictValueEnumObj } from '@/components/DictTag'; | import { DictValueEnumObj } from '@/components/DictTag'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| import { | import { | ||||
| ProForm, | ProForm, | ||||
| ProFormDigit, | ProFormDigit, | ||||
| @@ -7,9 +8,8 @@ import { | |||||
| ProFormTimePicker, | ProFormTimePicker, | ||||
| } from '@ant-design/pro-components'; | } from '@ant-design/pro-components'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Form, Modal } from 'antd'; | |||||
| import { Form } from 'antd'; | |||||
| import React, { useEffect } from 'react'; | import React, { useEffect } from 'react'; | ||||
| export type LogininforFormData = Record<string, unknown> & Partial<API.Monitor.Logininfor>; | export type LogininforFormData = Record<string, unknown> & Partial<API.Monitor.Logininfor>; | ||||
| export type LogininforFormProps = { | export type LogininforFormProps = { | ||||
| @@ -53,7 +53,7 @@ const LogininforForm: React.FC<LogininforFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.logininfor.title', | id: 'system.logininfor.title', | ||||
| @@ -209,7 +209,7 @@ const LogininforForm: React.FC<LogininforFormProps> = (props) => { | |||||
| ]} | ]} | ||||
| /> | /> | ||||
| </ProForm> | </ProForm> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,5 +1,6 @@ | |||||
| import { DictValueEnumObj } from '@/components/DictTag'; | import { DictValueEnumObj } from '@/components/DictTag'; | ||||
| import IconSelector from '@/components/IconSelector'; | import IconSelector from '@/components/IconSelector'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| import { createIcon } from '@/utils/IconUtil'; | import { createIcon } from '@/utils/IconUtil'; | ||||
| import { | import { | ||||
| ProForm, | ProForm, | ||||
| @@ -10,7 +11,7 @@ import { | |||||
| ProFormTreeSelect, | ProFormTreeSelect, | ||||
| } from '@ant-design/pro-components'; | } from '@ant-design/pro-components'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Form, Modal } from 'antd'; | |||||
| import { Form } from 'antd'; | |||||
| import { DataNode } from 'antd/es/tree'; | import { DataNode } from 'antd/es/tree'; | ||||
| import React, { useEffect, useState } from 'react'; | import React, { useEffect, useState } from 'react'; | ||||
| @@ -73,7 +74,7 @@ const MenuForm: React.FC<MenuFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.menu.title', | id: 'system.menu.title', | ||||
| @@ -367,7 +368,7 @@ const MenuForm: React.FC<MenuFormProps> = (props) => { | |||||
| }} | }} | ||||
| /> | /> | ||||
| </ProForm> | </ProForm> | ||||
| <Modal | |||||
| <KFModal | |||||
| width={800} | width={800} | ||||
| open={iconSelectorOpen} | open={iconSelectorOpen} | ||||
| onCancel={() => { | onCancel={() => { | ||||
| @@ -382,8 +383,8 @@ const MenuForm: React.FC<MenuFormProps> = (props) => { | |||||
| setIconSelectorOpen(false); | setIconSelectorOpen(false); | ||||
| }} | }} | ||||
| /> | /> | ||||
| </Modal> | |||||
| </Modal> | |||||
| </KFModal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,4 +1,5 @@ | |||||
| import { DictValueEnumObj } from '@/components/DictTag'; | import { DictValueEnumObj } from '@/components/DictTag'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| import { | import { | ||||
| ProForm, | ProForm, | ||||
| ProFormDigit, | ProFormDigit, | ||||
| @@ -8,9 +9,8 @@ import { | |||||
| ProFormTextArea, | ProFormTextArea, | ||||
| } from '@ant-design/pro-components'; | } from '@ant-design/pro-components'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Form, Modal } from 'antd'; | |||||
| import { Form } from 'antd'; | |||||
| import React, { useEffect } from 'react'; | import React, { useEffect } from 'react'; | ||||
| export type NoticeFormData = Record<string, unknown> & Partial<API.System.Notice>; | export type NoticeFormData = Record<string, unknown> & Partial<API.System.Notice>; | ||||
| export type NoticeFormProps = { | export type NoticeFormProps = { | ||||
| @@ -55,7 +55,7 @@ const NoticeForm: React.FC<NoticeFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.notice.title', | id: 'system.notice.title', | ||||
| @@ -168,7 +168,7 @@ const NoticeForm: React.FC<NoticeFormProps> = (props) => { | |||||
| ]} | ]} | ||||
| /> | /> | ||||
| </ProForm> | </ProForm> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,9 +1,9 @@ | |||||
| import { DictValueEnumObj } from '@/components/DictTag'; | import { DictValueEnumObj } from '@/components/DictTag'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| import { getValueEnumLabel } from '@/utils/options'; | import { getValueEnumLabel } from '@/utils/options'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Descriptions, Modal } from 'antd'; | |||||
| import { Descriptions } from 'antd'; | |||||
| import React from 'react'; | import React from 'react'; | ||||
| export type OperlogFormData = Record<string, unknown> & Partial<API.Monitor.Operlog>; | export type OperlogFormData = Record<string, unknown> & Partial<API.Monitor.Operlog>; | ||||
| export type OperlogFormProps = { | export type OperlogFormProps = { | ||||
| @@ -28,7 +28,7 @@ const OperlogDetailForm: React.FC<OperlogFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'monitor.operlog.title', | id: 'monitor.operlog.title', | ||||
| @@ -107,7 +107,7 @@ const OperlogDetailForm: React.FC<OperlogFormProps> = (props) => { | |||||
| {values.operTime?.toString()} | {values.operTime?.toString()} | ||||
| </Descriptions.Item> | </Descriptions.Item> | ||||
| </Descriptions> | </Descriptions> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,4 +1,5 @@ | |||||
| import { DictValueEnumObj } from '@/components/DictTag'; | import { DictValueEnumObj } from '@/components/DictTag'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| import { | import { | ||||
| ProForm, | ProForm, | ||||
| ProFormDigit, | ProFormDigit, | ||||
| @@ -7,9 +8,8 @@ import { | |||||
| ProFormTextArea, | ProFormTextArea, | ||||
| } from '@ant-design/pro-components'; | } from '@ant-design/pro-components'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Form, Modal } from 'antd'; | |||||
| import { Form } from 'antd'; | |||||
| import React, { useEffect } from 'react'; | import React, { useEffect } from 'react'; | ||||
| export type PostFormData = Record<string, unknown> & Partial<API.System.Post>; | export type PostFormData = Record<string, unknown> & Partial<API.System.Post>; | ||||
| export type PostFormProps = { | export type PostFormProps = { | ||||
| @@ -53,7 +53,7 @@ const PostForm: React.FC<PostFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.post.title', | id: 'system.post.title', | ||||
| @@ -160,7 +160,7 @@ const PostForm: React.FC<PostFormProps> = (props) => { | |||||
| ]} | ]} | ||||
| /> | /> | ||||
| </ProForm> | </ProForm> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,10 +1,10 @@ | |||||
| import KFModal from '@/components/KFModal'; | |||||
| import { Key, ProForm, ProFormDigit, ProFormSelect, ProFormText } from '@ant-design/pro-components'; | import { Key, ProForm, ProFormDigit, ProFormSelect, ProFormText } from '@ant-design/pro-components'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Checkbox, Col, Form, Modal, Row, Tree } from 'antd'; | |||||
| import { Checkbox, Col, Form, Row, Tree } from 'antd'; | |||||
| import { CheckboxValueType } from 'antd/es/checkbox/Group'; | import { CheckboxValueType } from 'antd/es/checkbox/Group'; | ||||
| import { DataNode } from 'antd/es/tree'; | import { DataNode } from 'antd/es/tree'; | ||||
| import React, { useEffect, useState } from 'react'; | import React, { useEffect, useState } from 'react'; | ||||
| /* * | /* * | ||||
| * | * | ||||
| * @author whiteshader@163.com | * @author whiteshader@163.com | ||||
| @@ -90,7 +90,7 @@ const DataScopeForm: React.FC<DataScopeFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.user.auth.role', | id: 'system.user.auth.role', | ||||
| @@ -234,7 +234,7 @@ const DataScopeForm: React.FC<DataScopeFormProps> = (props) => { | |||||
| </Row> | </Row> | ||||
| </ProForm.Item> | </ProForm.Item> | ||||
| </ProForm> | </ProForm> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,4 +1,5 @@ | |||||
| import DictTag from '@/components/DictTag'; | import DictTag from '@/components/DictTag'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| import { getDictValueEnum } from '@/services/system/dict'; | import { getDictValueEnum } from '@/services/system/dict'; | ||||
| import { | import { | ||||
| ActionType, | ActionType, | ||||
| @@ -8,9 +9,7 @@ import { | |||||
| RequestData, | RequestData, | ||||
| } from '@ant-design/pro-components'; | } from '@ant-design/pro-components'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Modal } from 'antd'; | |||||
| import React, { useEffect, useRef, useState } from 'react'; | import React, { useEffect, useRef, useState } from 'react'; | ||||
| /* * | /* * | ||||
| * | * | ||||
| * @author whiteshader@163.com | * @author whiteshader@163.com | ||||
| @@ -90,7 +89,7 @@ const UserSelectorModal: React.FC<DataScopeFormProps> = (props) => { | |||||
| ]; | ]; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={800} | width={800} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.role.auth.user', | id: 'system.role.auth.user', | ||||
| @@ -122,7 +121,7 @@ const UserSelectorModal: React.FC<DataScopeFormProps> = (props) => { | |||||
| }, | }, | ||||
| }} | }} | ||||
| /> | /> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,4 +1,5 @@ | |||||
| import { DictValueEnumObj } from '@/components/DictTag'; | import { DictValueEnumObj } from '@/components/DictTag'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| import { | import { | ||||
| ProForm, | ProForm, | ||||
| ProFormDigit, | ProFormDigit, | ||||
| @@ -7,10 +8,9 @@ import { | |||||
| ProFormTextArea, | ProFormTextArea, | ||||
| } from '@ant-design/pro-components'; | } from '@ant-design/pro-components'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Form, Modal } from 'antd'; | |||||
| import { Form } from 'antd'; | |||||
| import Tree, { DataNode } from 'antd/es/tree'; | import Tree, { DataNode } from 'antd/es/tree'; | ||||
| import React, { useEffect, useState } from 'react'; | import React, { useEffect, useState } from 'react'; | ||||
| export type RoleFormData = Record<string, unknown> & Partial<API.System.Role>; | export type RoleFormData = Record<string, unknown> & Partial<API.System.Role>; | ||||
| export type RoleFormProps = { | export type RoleFormProps = { | ||||
| @@ -61,7 +61,7 @@ const RoleForm: React.FC<RoleFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.role.title', | id: 'system.role.title', | ||||
| @@ -198,7 +198,7 @@ const RoleForm: React.FC<RoleFormProps> = (props) => { | |||||
| ]} | ]} | ||||
| /> | /> | ||||
| </ProForm> | </ProForm> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,15 +1,8 @@ | |||||
| import KFModal from '@/components/KFModal'; | |||||
| import { ProForm, ProFormSelect } from '@ant-design/pro-components'; | import { ProForm, ProFormSelect } from '@ant-design/pro-components'; | ||||
| import { useIntl } from '@umijs/max'; | import { useIntl } from '@umijs/max'; | ||||
| import { Form, Modal } from 'antd'; | |||||
| import { Form } from 'antd'; | |||||
| import React, { useEffect } from 'react'; | import React, { useEffect } from 'react'; | ||||
| /* * | |||||
| * | |||||
| * @author whiteshader@163.com | |||||
| * @datetime 2023/02/06 | |||||
| * | |||||
| * */ | |||||
| export type FormValueType = any & Partial<API.System.Dept>; | export type FormValueType = any & Partial<API.System.Dept>; | ||||
| export type AuthRoleFormProps = { | export type AuthRoleFormProps = { | ||||
| @@ -40,7 +33,7 @@ const AuthRoleForm: React.FC<AuthRoleFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.user.auth.role', | id: 'system.user.auth.role', | ||||
| @@ -74,7 +67,7 @@ const AuthRoleForm: React.FC<AuthRoleFormProps> = (props) => { | |||||
| rules={[{ required: true, message: '请选择角色!' }]} | rules={[{ required: true, message: '请选择角色!' }]} | ||||
| /> | /> | ||||
| </ProForm> | </ProForm> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,15 +1,9 @@ | |||||
| import KFModal from '@/components/KFModal'; | |||||
| import { ProForm, ProFormText } from '@ant-design/pro-components'; | import { ProForm, ProFormText } from '@ant-design/pro-components'; | ||||
| import { useIntl } from '@umijs/max'; | import { useIntl } from '@umijs/max'; | ||||
| import { Form, Modal } from 'antd'; | |||||
| import { Form } from 'antd'; | |||||
| import React from 'react'; | import React from 'react'; | ||||
| /* * | |||||
| * | |||||
| * @author whiteshader@163.com | |||||
| * @datetime 2023/02/06 | |||||
| * | |||||
| * */ | |||||
| export type FormValueType = any & Partial<API.System.User>; | export type FormValueType = any & Partial<API.System.User>; | ||||
| export type UpdateFormProps = { | export type UpdateFormProps = { | ||||
| @@ -44,7 +38,7 @@ const UpdateForm: React.FC<UpdateFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.user.reset.password', | id: 'system.user.reset.password', | ||||
| @@ -88,7 +82,7 @@ const UpdateForm: React.FC<UpdateFormProps> = (props) => { | |||||
| ]} | ]} | ||||
| /> | /> | ||||
| </ProForm> | </ProForm> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,4 +1,5 @@ | |||||
| import { DictValueEnumObj } from '@/components/DictTag'; | import { DictValueEnumObj } from '@/components/DictTag'; | ||||
| import KFModal from '@/components/KFModal'; | |||||
| import { | import { | ||||
| ProForm, | ProForm, | ||||
| ProFormRadio, | ProFormRadio, | ||||
| @@ -8,17 +9,10 @@ import { | |||||
| ProFormTreeSelect, | ProFormTreeSelect, | ||||
| } from '@ant-design/pro-components'; | } from '@ant-design/pro-components'; | ||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | import { FormattedMessage, useIntl } from '@umijs/max'; | ||||
| import { Form, Modal } from 'antd'; | |||||
| import { Form } from 'antd'; | |||||
| import { DataNode } from 'antd/es/tree'; | import { DataNode } from 'antd/es/tree'; | ||||
| import React, { useEffect } from 'react'; | import React, { useEffect } from 'react'; | ||||
| /* * | |||||
| * | |||||
| * @author whiteshader@163.com | |||||
| * @datetime 2023/02/06 | |||||
| * | |||||
| * */ | |||||
| export type UserFormData = Record<string, unknown> & Partial<API.System.User>; | export type UserFormData = Record<string, unknown> & Partial<API.System.User>; | ||||
| export type UserFormProps = { | export type UserFormProps = { | ||||
| @@ -74,7 +68,7 @@ const UserForm: React.FC<UserFormProps> = (props) => { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={640} | width={640} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.user.title', | id: 'system.user.title', | ||||
| @@ -260,7 +254,7 @@ const UserForm: React.FC<UserFormProps> = (props) => { | |||||
| ]} | ]} | ||||
| /> | /> | ||||
| </ProForm> | </ProForm> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,10 +1,10 @@ | |||||
| import KFModal from '@/components/KFModal'; | |||||
| import { useIntl } from '@umijs/max'; | import { useIntl } from '@umijs/max'; | ||||
| import type { TabsProps } from 'antd'; | import type { TabsProps } from 'antd'; | ||||
| import { Modal, Tabs } from 'antd'; | |||||
| import { Tabs } from 'antd'; | |||||
| import 'highlight.js/styles/base16/material.css'; | import 'highlight.js/styles/base16/material.css'; | ||||
| import React, { useEffect } from 'react'; | import React, { useEffect } from 'react'; | ||||
| import Highlight from 'react-highlight'; | import Highlight from 'react-highlight'; | ||||
| interface PreviewTableProps { | interface PreviewTableProps { | ||||
| open: boolean; | open: boolean; | ||||
| data?: any; | data?: any; | ||||
| @@ -26,7 +26,7 @@ const PreviewTableCode: React.FC<PreviewTableProps> = (props) => { | |||||
| useEffect(() => {}, []); | useEffect(() => {}, []); | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={900} | width={900} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'gen.preview', | id: 'gen.preview', | ||||
| @@ -43,7 +43,7 @@ const PreviewTableCode: React.FC<PreviewTableProps> = (props) => { | |||||
| }} | }} | ||||
| > | > | ||||
| <Tabs defaultActiveKey="1" items={panes}></Tabs> | <Tabs defaultActiveKey="1" items={panes}></Tabs> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,3 +1,4 @@ | |||||
| import KFModal from '@/components/KFModal'; | |||||
| import { uploadAvatar } from '@/services/system/user'; | import { uploadAvatar } from '@/services/system/user'; | ||||
| import { | import { | ||||
| MinusOutlined, | MinusOutlined, | ||||
| @@ -7,7 +8,7 @@ import { | |||||
| UploadOutlined, | UploadOutlined, | ||||
| } from '@ant-design/icons'; | } from '@ant-design/icons'; | ||||
| import { useIntl } from '@umijs/max'; | import { useIntl } from '@umijs/max'; | ||||
| import { Button, Col, Modal, Row, Space, Upload, message } from 'antd'; | |||||
| import { Button, Col, Row, Space, Upload, message } from 'antd'; | |||||
| import React, { useEffect, useRef, useState } from 'react'; | import React, { useEffect, useRef, useState } from 'react'; | ||||
| import { Cropper } from 'react-cropper'; | import { Cropper } from 'react-cropper'; | ||||
| import './cropper.css'; | import './cropper.css'; | ||||
| @@ -88,7 +89,7 @@ const AvatarCropperForm: React.FC<AvatarCropperProps> = (props) => { | |||||
| }; | }; | ||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Modal | |||||
| <KFModal | |||||
| width={800} | width={800} | ||||
| title={intl.formatMessage({ | title={intl.formatMessage({ | ||||
| id: 'system.user.modify_avatar', | id: 'system.user.modify_avatar', | ||||
| @@ -137,7 +138,7 @@ const AvatarCropperForm: React.FC<AvatarCropperProps> = (props) => { | |||||
| </Space> | </Space> | ||||
| </Col> | </Col> | ||||
| </Row> | </Row> | ||||
| </Modal> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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 ( | |||||
| <div className={styles['assets-management']}> | |||||
| <Flex justify="space-between"> | |||||
| <div className={styles['assets-management__title']}>AI资产</div> | |||||
| <Select | |||||
| size="small" | |||||
| value={type} | |||||
| style={{ width: 70 }} | |||||
| onChange={setType} | |||||
| variant="filled" | |||||
| options={[ | |||||
| { value: CommonTabKeys.Public, label: '公开' }, | |||||
| { value: CommonTabKeys.Private, label: '个人' }, | |||||
| ]} | |||||
| /> | |||||
| </Flex> | |||||
| <div className={styles['assets-management__increase']}>今日新增数量:5</div> | |||||
| <Flex justify="space-between" gap="22px 0" wrap="wrap"> | |||||
| {assetCounts.map((item, index) => ( | |||||
| <div className={styles['assets-management__summary']} key={index}> | |||||
| <div className={styles['assets-management__summary__title']}>{item.title}</div> | |||||
| <div className={styles['assets-management__summary__value']}>{item.value}</div> | |||||
| </div> | |||||
| ))} | |||||
| </Flex> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default AssetsManagement; | |||||
| @@ -0,0 +1,7 @@ | |||||
| .experiment-chart { | |||||
| width: 295px; | |||||
| min-width: 295px; | |||||
| height: 140px; | |||||
| background-color: @workspace-background; | |||||
| border-radius: 4px; | |||||
| } | |||||
| @@ -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<HTMLDivElement>(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 ( | |||||
| <div className={styles['experiment-chart']} style={style}> | |||||
| <div style={{ width: '100%', height: '100%' }} ref={chartRef}></div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default ExperimentChart; | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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 ( | |||||
| <div className={styles['experiment-table']} style={style}> | |||||
| <div className={styles['experiment-table__header']}> | |||||
| <div className={styles['experiment-table__status']}>状态</div> | |||||
| <div className={styles['experiment-table__duration']}>运行时长</div> | |||||
| <div className={styles['experiment-table__date']}>开始时间</div> | |||||
| <div className={styles['experiment-table__operation']}>操作</div> | |||||
| </div> | |||||
| {tableData?.map((item) => ( | |||||
| <div className={styles['experiment-table__content']} key={item.id}> | |||||
| <div className={styles['experiment-table__status']} style={{ paddingLeft: '6.5px' }}> | |||||
| <img | |||||
| src={experimentStatusInfo[item.status as ExperimentStatusValues]?.icon} | |||||
| width={17} | |||||
| height={17} | |||||
| /> | |||||
| </div> | |||||
| <div className={styles['experiment-table__duration']}> | |||||
| {elapsedTime( | |||||
| new Date(item.create_time), | |||||
| item.finish_time ? new Date(item.finish_time) : new Date(), | |||||
| )} | |||||
| </div> | |||||
| <div className={styles['experiment-table__date']}>{formatDate(item.create_time)}</div> | |||||
| <div className={styles['experiment-table__operation']}> | |||||
| <Button | |||||
| size="small" | |||||
| type="link" | |||||
| icon={<KFIcon type="icon-xiangqing2" font={14} />} | |||||
| onClick={() => gotoExperiment(item)} | |||||
| > | |||||
| 详情 | |||||
| </Button> | |||||
| </div> | |||||
| </div> | |||||
| ))} | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default ExperimentTable; | |||||
| @@ -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 ( | |||||
| <div | |||||
| className={styles['work-arrow']} | |||||
| style={{ | |||||
| left: `${x}px`, | |||||
| top: `${y}px`, | |||||
| width: `${width}px`, | |||||
| height: `${height}px`, | |||||
| borderLeftWidth: `${borderLeft}px`, | |||||
| borderTopWidth: `${borderTop}px`, | |||||
| borderRightWidth: `${borderRight}px`, | |||||
| borderBottomWidth: `${borderBottom}px`, | |||||
| }} | |||||
| > | |||||
| <img | |||||
| className={styles['work-arrow__img']} | |||||
| src={require('@/assets/img/blue-triangle.png')} | |||||
| alt="" | |||||
| width={10} | |||||
| height={9} | |||||
| style={{ | |||||
| left: `${arrowLeft}px`, | |||||
| top: `${arrorwTop}px`, | |||||
| transform: `rotate(${arrrowAngle}deg)`, | |||||
| }} | |||||
| /> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default WorkArrow; | |||||
| @@ -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 ( | |||||
| <div className={styles['work-flow']} style={{ left: `${x}px`, top: `${y}px` }}> | |||||
| {tips && <div className={styles['work-flow__tips']}>{tips}</div>} | |||||
| <div className={styles['work-flow__content']}>{content}</div> | |||||
| <Button | |||||
| className={styles['work-flow__button']} | |||||
| type="primary" | |||||
| style={{ marginTop: `${buttonTop}px` }} | |||||
| onClick={onClick} | |||||
| > | |||||
| {buttonText} | |||||
| </Button> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default WorkFlow; | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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 ( | |||||
| <div className={styles['quick-start']}> | |||||
| <div className={styles['quick-start__title']}>快速开始</div> | |||||
| <div className={styles['quick-start__content']}> | |||||
| <div | |||||
| className={styles['quick-start__content__canvas']} | |||||
| style={{ transform: `scale(${scale})` }} | |||||
| > | |||||
| <WorkFlow | |||||
| content="为开发者提供数据智能标注与数据回流服务" | |||||
| buttonText="数据准备" | |||||
| buttonTop={40} | |||||
| x={20} | |||||
| y={309} | |||||
| onClick={() => navgite('/datasetPreparation/datasetAnnotation')} | |||||
| /> | |||||
| <WorkFlow | |||||
| content="为开发者提供定制化编辑器,开发者可根据自己需求选择配置,保存编译器中的调试环境为镜像供训练使用" | |||||
| buttonText="开发环境" | |||||
| buttonTop={20} | |||||
| x={248} | |||||
| y={301} | |||||
| onClick={() => navgite('/developmentEnvironment')} | |||||
| /> | |||||
| <WorkFlow | |||||
| content="为开发者提供定制化编辑器,开发者可根据自己需求选择配置,保存编译器中的调试环境为镜像供训练使用" | |||||
| tips="可视化建模Designer" | |||||
| buttonText="流水线" | |||||
| buttonTop={20} | |||||
| x={476} | |||||
| y={276} | |||||
| onClick={() => navgite('/pipeline/pipelineText')} | |||||
| /> | |||||
| <WorkFlow | |||||
| content="开发者可以在这里运行流水线模板,产生实验实例,对比实验训练过程与产生的实验训练数据" | |||||
| buttonText="实验" | |||||
| buttonTop={40} | |||||
| x={699} | |||||
| y={295} | |||||
| onClick={() => navgite('/pipeline/experimentText')} | |||||
| /> | |||||
| <WorkFlow | |||||
| content="支持异构硬件(CPU/GPU)的模型加载,高吞吐,低延迟;支持大规模复杂模型的一键部署,实时弹性扩缩容;提供完整的运维监控体系。" | |||||
| tips="模型在线服务" | |||||
| buttonText="模型在线部署" | |||||
| buttonTop={20} | |||||
| x={1010} | |||||
| y={263} | |||||
| onClick={() => navgite('/modelDseployment')} | |||||
| /> | |||||
| <div className={styles['quick-start__content__canvas__model']}> | |||||
| <KFIcon type="icon-moxingguanli" font={38} /> | |||||
| <span>模型管理</span> | |||||
| </div> | |||||
| <div className={styles['quick-start__content__canvas__task']}> | |||||
| <KFIcon type="icon-tiaoduguanli" font={13} style={{ marginRight: '5px' }} /> | |||||
| <span>任务自动调度</span> | |||||
| </div> | |||||
| <WorkArrow | |||||
| x={213} | |||||
| y={378} | |||||
| width={22} | |||||
| height={1} | |||||
| arrowLeft={22} | |||||
| arrorwTop={-4} | |||||
| borderBottom={1} | |||||
| /> | |||||
| <WorkArrow | |||||
| x={441} | |||||
| y={378} | |||||
| width={22} | |||||
| height={1} | |||||
| arrowLeft={22} | |||||
| arrorwTop={-4} | |||||
| borderBottom={1} | |||||
| /> | |||||
| <WorkArrow | |||||
| x={893} | |||||
| y={378} | |||||
| width={22} | |||||
| height={1} | |||||
| arrowLeft={22} | |||||
| arrorwTop={-4} | |||||
| borderBottom={1} | |||||
| /> | |||||
| <WorkArrow | |||||
| x={974} | |||||
| y={378} | |||||
| width={22} | |||||
| height={1} | |||||
| arrowLeft={22} | |||||
| arrorwTop={-4} | |||||
| borderBottom={1} | |||||
| /> | |||||
| <WorkArrow | |||||
| x={532} | |||||
| y={139} | |||||
| width={54} | |||||
| height={125} | |||||
| arrowLeft={54} | |||||
| arrorwTop={-4} | |||||
| borderLeft={1} | |||||
| borderTop={1} | |||||
| /> | |||||
| <WorkArrow | |||||
| x={740} | |||||
| y={127} | |||||
| width={49} | |||||
| height={156} | |||||
| arrowLeft={44} | |||||
| arrorwTop={156} | |||||
| arrrowAngle={90} | |||||
| borderRight={1} | |||||
| borderTop={1} | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default QuickStart; | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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 ( | |||||
| <div className={styles['total-statistics']} style={style}> | |||||
| <img className={styles['total-statistics__icon']} src={icon} /> | |||||
| <div> | |||||
| <div className={styles['total-statistics__title']}> | |||||
| <span>{title}</span> | |||||
| <div className={styles['total-statistics__title-shadow']}></div> | |||||
| </div> | |||||
| <div className={styles['total-statistics__count']}>{count ?? '--'}</div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default TotalStatistics; | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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 ( | |||||
| <div className={styles['user-space']}> | |||||
| <div className={styles['user-space__title']}>工作空间管理</div> | |||||
| <div style={{ padding: '0 20px' }}> | |||||
| <img className={styles['user-space__avatar']} src={currentUser?.avatar} alt="" /> | |||||
| <div className={styles['user-space__name']}>{currentUser?.nickName}</div> | |||||
| <div className={styles['user-space__role']}>{currentUser?.roleNames?.[0]?.roleName}</div> | |||||
| <Divider | |||||
| dashed | |||||
| style={{ borderColor: 'rgba(22, 100, 255, 0.19)', margin: '20px 0' }} | |||||
| ></Divider> | |||||
| <div className={styles['user-space__participant']}> | |||||
| <Space align="center" size={10} style={{ marginBottom: '20px' }}> | |||||
| <div className={styles['user-space__participant__title']}>参与者</div> | |||||
| <div className={styles['user-space__participant__count']}>8</div> | |||||
| </Space> | |||||
| <Flex align="center" gap={12} wrap="wrap"> | |||||
| {users?.map((item, index) => { | |||||
| return ( | |||||
| <img | |||||
| className={styles['user-space__participant__user']} | |||||
| key={index} | |||||
| src={require(`@/assets/img/user-avatar/${index + 1}.png`)} | |||||
| alt="" | |||||
| /> | |||||
| ); | |||||
| })} | |||||
| </Flex> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default UserSpace; | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,43 @@ | |||||
| import { Button } from 'antd'; | |||||
| import styles from './index.less'; | |||||
| function WorkspaceIntro() { | |||||
| return ( | |||||
| <div className={styles['workspace-intro']}> | |||||
| <div className={styles['workspace-intro__left']}> | |||||
| <div className={styles['workspace-intro__title']}>自主实验平台</div> | |||||
| <div className={styles['workspace-intro__content']}> | |||||
| 材料领域的自主实验系统是一种用于材料研究和开发的技术平台,它旨在提供实验数据收集、分析和可视化等功能, | |||||
| 以支持材料工程师、科学家和研究人员在材料设计、性能评估和工艺优化方面的工作 | |||||
| </div> | |||||
| <div className={styles['workspace-intro__buttons']}> | |||||
| <Button | |||||
| type="primary" | |||||
| style={{ marginRight: '20px' }} | |||||
| icon={ | |||||
| <img src={require('@/assets/img/functional-material.png')} width={19} height={19} /> | |||||
| } | |||||
| > | |||||
| 功能材料自主实验系统 | |||||
| </Button> | |||||
| <Button | |||||
| type="default" | |||||
| icon={ | |||||
| <img src={require('@/assets/img/molecular-material.png')} width={19} height={19} /> | |||||
| } | |||||
| > | |||||
| 分子材料自主实验系统 | |||||
| </Button> | |||||
| </div> | |||||
| </div> | |||||
| <div className={styles['workspace-intro__right']}> | |||||
| <img | |||||
| className={styles['workspace-intro__icon']} | |||||
| src={require('@/assets/img/workspace-intro-icon.png')} | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default WorkspaceIntro; | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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<OverviewData>(); | |||||
| 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 ( | |||||
| <div className={styles.workspace}> | |||||
| <WorkspaceIntro></WorkspaceIntro> | |||||
| <div className={styles['workspace__overview']}> | |||||
| <div className={styles['workspace__overview__title']}>运行概览</div> | |||||
| <div className={styles['workspace__overview__content']}> | |||||
| <TotalStatistics | |||||
| icon={require('@/assets/img/workspace-pipeline.png')} | |||||
| title="流水线总数" | |||||
| count={overviewData?.workflowCount} | |||||
| /> | |||||
| <TotalStatistics | |||||
| icon={require('@/assets/img/workspace-experiment.png')} | |||||
| title="正在运行实例总数" | |||||
| count={overviewData?.runningExperimentInsCount} | |||||
| /> | |||||
| <ExperitableTable | |||||
| tableData={overviewData?.latestExperimentInsList || []} | |||||
| ></ExperitableTable> | |||||
| {overviewData?.experimentInsStatus && ( | |||||
| <ExperimentChart chartData={overviewData?.experimentInsStatus}></ExperimentChart> | |||||
| )} | |||||
| </div> | |||||
| </div> | |||||
| <div className={styles['workspace__quick-start']}> | |||||
| <QuickStart></QuickStart> | |||||
| <div className={styles['workspace__user']}> | |||||
| <UserSpace users={users}></UserSpace> | |||||
| <AssetsManagement></AssetsManagement> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default Workspace; | |||||
| @@ -46,7 +46,8 @@ export const requestConfig: RequestConfig = { | |||||
| ], | ], | ||||
| responseInterceptors: [ | responseInterceptors: [ | ||||
| (response: any) => { | (response: any) => { | ||||
| const { status, data } = response; | |||||
| const { status, data } = response || {}; | |||||
| console.log('response2', response); | |||||
| if (status >= 200 && status < 300) { | if (status >= 200 && status < 300) { | ||||
| if (data && (data instanceof Blob || data.code === 200)) { | if (data && (data instanceof Blob || data.code === 200)) { | ||||
| return response; | return response; | ||||
| @@ -14,6 +14,9 @@ declare namespace API { | |||||
| }; | }; | ||||
| address?: string; | address?: string; | ||||
| phone?: string; | phone?: string; | ||||
| roleNames?: { | |||||
| roleName?: string; | |||||
| }[]; | |||||
| }; | }; | ||||
| type ErrorResponse = { | type ErrorResponse = { | ||||
| @@ -1,7 +1,7 @@ | |||||
| /* | /* | ||||
| * @Author: 赵伟 | * @Author: 赵伟 | ||||
| * @Date: 2024-04-16 14:29:44 | * @Date: 2024-04-16 14:29:44 | ||||
| * @Description: | |||||
| * @Description: 镜像管理接口 | |||||
| */ | */ | ||||
| import { request } from '@umijs/max'; | import { request } from '@umijs/max'; | ||||
| @@ -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, | |||||
| }); | |||||
| } | |||||
| @@ -6,6 +6,7 @@ | |||||
| // 颜色 | // 颜色 | ||||
| @primary-color: #1664ff; // 主色调 | @primary-color: #1664ff; // 主色调 | ||||
| @primary-color-secondary: #4e89ff; | |||||
| @primary-color-hover: #69b1ff; | @primary-color-hover: #69b1ff; | ||||
| @background-color: #f9fafb; // 页面背景颜色 | @background-color: #f9fafb; // 页面背景颜色 | ||||
| @text-color: #1d1d20; | @text-color: #1d1d20; | ||||
| @@ -15,17 +16,35 @@ | |||||
| @warning-color: #f98e1b; | @warning-color: #f98e1b; | ||||
| @border-color: rgba(22, 100, 255, 0.3); | @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); | @background-color-gray: rgba(4, 3, 3, 0.06); | ||||
| @heading-color: rgba(0, 0, 0, 0.85); | @heading-color: rgba(0, 0, 0, 0.85); | ||||
| @input-icon-hover-color: rgba(0, 0, 0, 0.85); | @input-icon-hover-color: rgba(0, 0, 0, 0.85); | ||||
| @border-color-base: #d9d9d9; | @border-color-base: #d9d9d9; | ||||
| @link-hover-color: #69b1ff; | @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: 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 { | :export { | ||||
| @@ -34,5 +53,7 @@ | |||||
| errorColor: @error-color; | errorColor: @error-color; | ||||
| warningColor: @warning-color; | warningColor: @warning-color; | ||||
| textColor: @text-color; | textColor: @text-color; | ||||
| textColorSecondary: @text-color-secondary; | |||||
| fontSize: @font-size; | fontSize: @font-size; | ||||
| siderBGColor: @sider-background-color; | |||||
| } | } | ||||
| @@ -12,3 +12,19 @@ export type PipelineGlobalParam = { | |||||
| param_value: number | string | boolean; | param_value: number | string | boolean; | ||||
| is_sensitive: number; | 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[]; | |||||
| }; | |||||