diff --git a/react-ui/package.json b/react-ui/package.json index 1534f112..ac2bc997 100644 --- a/react-ui/package.json +++ b/react-ui/package.json @@ -57,6 +57,7 @@ "@ant-design/pro-components": "^2.4.4", "@ant-design/use-emotion-css": "1.0.4", "@antv/g6": "^4.8.24", + "@antv/hierarchy": "^0.6.12", "@umijs/route-utils": "^4.0.1", "antd": "^5.4.4", "classnames": "^2.3.2", diff --git a/react-ui/src/app.tsx b/react-ui/src/app.tsx index 7d928861..3b468859 100644 --- a/react-ui/src/app.tsx +++ b/react-ui/src/app.tsx @@ -21,6 +21,7 @@ import './styles/menu.less'; export { requestConfig as request } from './requestConfig'; // const isDev = process.env.NODE_ENV === 'development'; import { menuItemRender } from '@/utils/menuRender'; +import { gotoLoginPage } from './utils/ui'; /** * @see https://umijs.org/zh-CN/plugins/plugin-initial-state * */ @@ -45,7 +46,7 @@ export async function getInitialState(): Promise<{ } as API.CurrentUser; } catch (error) { console.log(error); - history.push(PageEnum.LOGIN); + gotoLoginPage(); } return undefined; }; @@ -97,7 +98,7 @@ export const layout: RuntimeConfig['layout'] = ({ initialState }) => { const { location } = history; // 如果没有登录,重定向到 login if (!initialState?.currentUser && location.pathname !== PageEnum.LOGIN) { - history.push(PageEnum.LOGIN); + gotoLoginPage(); } }, layoutBgImgList: [ diff --git a/react-ui/src/components/KFModal/index.tsx b/react-ui/src/components/KFModal/index.tsx index 8fea54bc..c073ab27 100644 --- a/react-ui/src/components/KFModal/index.tsx +++ b/react-ui/src/components/KFModal/index.tsx @@ -12,12 +12,21 @@ import './index.less'; export interface KFModalProps extends ModalProps { image?: string; } -function KFModal({ title, image, children, className = '', centered, ...rest }: KFModalProps) { +function KFModal({ + title, + image, + children, + className = '', + centered, + maskClosable, + ...rest +}: KFModalProps) { return ( } > {children} diff --git a/react-ui/src/components/ParameterInput/index.tsx b/react-ui/src/components/ParameterInput/index.tsx index 27ba2856..4b838b2d 100644 --- a/react-ui/src/components/ParameterInput/index.tsx +++ b/react-ui/src/components/ParameterInput/index.tsx @@ -29,7 +29,6 @@ function ParameterInput({ onClick, canInput = true, textArea = false, - placeholder, allowClear, className, style, @@ -37,8 +36,6 @@ function ParameterInput({ disabled = false, ...rest }: ParameterInputProps) { - // console.log('ParameterInput', value); - const valueObj = typeof value === 'string' ? { value: value, fromSelect: false, showValue: value } : value; if (valueObj && !valueObj.showValue) { @@ -46,6 +43,7 @@ function ParameterInput({ } const isSelect = valueObj?.fromSelect; const InputComponent = textArea ? Input.TextArea : Input; + const placeholder = valueObj?.placeholder; return ( <> @@ -68,9 +66,12 @@ function ParameterInput({ e.stopPropagation(); onChange?.({ ...valueObj, - fromSelect: false, value: undefined, showValue: undefined, + fromSelect: false, + activeTab: undefined, + expandedKeys: undefined, + checkedKeys: undefined, }); }} /> diff --git a/react-ui/src/components/ParameterSelect/config.tsx b/react-ui/src/components/ParameterSelect/config.tsx new file mode 100644 index 00000000..84c99914 --- /dev/null +++ b/react-ui/src/components/ParameterSelect/config.tsx @@ -0,0 +1,72 @@ +import { getDatasetList, getModelList } from '@/services/dataset/index.js'; +import { getComputingResourceReq } from '@/services/pipeline'; +import { ComputingResource } from '@/types'; +import { type SelectProps } from 'antd'; + +// 过滤资源规格 +const filterResourceStandard: SelectProps['filterOption'] = ( + input: string, + option?: ComputingResource, +) => { + return ( + option?.computing_resource?.toLocaleLowerCase()?.includes(input.toLocaleLowerCase()) ?? false + ); +}; + +// id 从 number 转换为 string +const convertId = (item: any) => ({ ...item, id: String(item.id) }); + +export type SelectPropsConfig = { + getOptions: () => Promise; + fieldNames?: SelectProps['fieldNames']; + optionFilterProp?: SelectProps['optionFilterProp']; + filterOption?: SelectProps['filterOption']; +}; + +export const paramSelectConfig: Record = { + dataset: { + getOptions: async () => { + const res = await getDatasetList({ + page: 0, + size: 1000, + available_range: 0, + }); + return res?.data?.content?.map(convertId) ?? []; + }, + fieldNames: { + label: 'name', + value: 'id', + }, + optionFilterProp: 'name', + }, + model: { + getOptions: async () => { + const res = await getModelList({ + page: 0, + size: 1000, + available_range: 0, + }); + return res?.data?.content?.map(convertId) ?? []; + }, + fieldNames: { + label: 'name', + value: 'id', + }, + optionFilterProp: 'name', + }, + resource: { + getOptions: async () => { + const res = await getComputingResourceReq({ + page: 0, + size: 1000, + resource_type: '', + }); + return res?.data?.content ?? []; + }, + fieldNames: { + label: 'description', + value: 'standard', + }, + filterOption: filterResourceStandard as SelectProps['filterOption'], + }, +}; diff --git a/react-ui/src/components/ParameterSelect/index.tsx b/react-ui/src/components/ParameterSelect/index.tsx new file mode 100644 index 00000000..5b181a01 --- /dev/null +++ b/react-ui/src/components/ParameterSelect/index.tsx @@ -0,0 +1,58 @@ +import { PipelineNodeModelParameter } from '@/types'; +import { to } from '@/utils/promise'; +import { Select } from 'antd'; +import { useEffect, useState } from 'react'; +import { paramSelectConfig } from './config'; + +type ParameterSelectProps = { + value?: PipelineNodeModelParameter; + onChange?: (value: PipelineNodeModelParameter) => void; + disabled?: boolean; +}; + +function ParameterSelect({ value, onChange, disabled = false }: ParameterSelectProps) { + const [options, setOptions] = useState([]); + const valueNonNullable = value ?? ({} as PipelineNodeModelParameter); + const { item_type } = valueNonNullable; + const propsConfig = paramSelectConfig[item_type]; + + useEffect(() => { + getSelectOptions(); + }, []); + + const hangleChange = (e: string) => { + onChange?.({ + ...valueNonNullable, + value: e, + }); + }; + + // 获取下拉数据 + const getSelectOptions = async () => { + if (!propsConfig) { + return; + } + const getOptions = propsConfig.getOptions; + const [res] = await to(getOptions()); + if (res) { + setOptions(res); + } + }; + + return ( + + + + + {!isPublic && ( + + )} + + + +
+ {fileList.length > 0 && fileList[0].description + ? '版本描述:' + fileList[0].description + : null} +
+ + + ); +} + +export default ResourceVersion; diff --git a/react-ui/src/pages/Dataset/components/Resourcetem/index.tsx b/react-ui/src/pages/Dataset/components/Resourcetem/index.tsx index b8ad9750..3b517184 100644 --- a/react-ui/src/pages/Dataset/components/Resourcetem/index.tsx +++ b/react-ui/src/pages/Dataset/components/Resourcetem/index.tsx @@ -3,7 +3,7 @@ import creatByImg from '@/assets/img/creatBy.png'; import KFIcon from '@/components/KFIcon'; import { formatDate } from '@/utils/date'; import { Button, Flex, Typography } from 'antd'; -import { ResourceData } from '../../types'; +import { ResourceData } from '../../config'; import styles from './index.less'; type ResourceItemProps = { diff --git a/react-ui/src/pages/Dataset/types.tsx b/react-ui/src/pages/Dataset/config.tsx similarity index 67% rename from react-ui/src/pages/Dataset/types.tsx rename to react-ui/src/pages/Dataset/config.tsx index 5f3c5f1e..be31f697 100644 --- a/react-ui/src/pages/Dataset/types.tsx +++ b/react-ui/src/pages/Dataset/config.tsx @@ -4,10 +4,14 @@ import { addDatasetVersionDetail, addModelsVersionDetail, deleteDataset, + deleteDatasetVersion, deleteModel, + deleteModelVersion, + getDatasetById, getDatasetList, getDatasetVersionIdList, getDatasetVersionsById, + getModelById, getModelList, getModelVersionIdList, getModelVersionsById, @@ -24,6 +28,9 @@ type ResourceTypeInfo = { getVersions: (params: any) => Promise; getFiles: (params: any) => Promise; deleteRecord: (params: any) => Promise; + addVersion: (params: any) => Promise; + deleteVersion: (params: any) => Promise; + getInfo: (params: any) => Promise; name: string; typeParamKey: string; tagParamKey: string; @@ -33,13 +40,16 @@ type ResourceTypeInfo = { tagTitle: string; typeValue: number; // 从 getAssetIcon 接口获取特定值的数据为 type 分类 (category_id === typeValue) tagValue: number; // 从 getAssetIcon 接口获取特定值的数据为 tag 分类(category_id === tagValue) - iconPathPrefix: string; // 图标路径前缀 + prefix: string; // 前缀 deleteModalTitle: string; // 删除弹框的title addBtnTitle: string; // 新增按钮的title - addVersionReq: (params: any) => Promise; - idParamKey: string; + idParamKey: 'models_id' | 'dataset_id'; uploadAction: string; uploadAccept?: string; + downloadAllAction: string; + downloadSingleAction: string; + infoTypePropertyName: string; + infoTagPropertyName: string; }; export const resourceConfig: Record = { @@ -48,6 +58,9 @@ export const resourceConfig: Record = { getVersions: getDatasetVersionsById, getFiles: getDatasetVersionIdList, deleteRecord: deleteDataset, + addVersion: addDatasetVersionDetail, + deleteVersion: deleteDatasetVersion, + getInfo: getDatasetById, name: '数据集', typeParamKey: 'data_type', tagParamKey: 'data_tag', @@ -68,19 +81,25 @@ export const resourceConfig: Record = { tagTitle: '研究方向/应用领域', typeValue: 1, tagValue: 2, - iconPathPrefix: 'dataset', + prefix: 'dataset', deleteModalTitle: '确定删除该条数据集实例吗?', addBtnTitle: '新建数据集', - addVersionReq: addDatasetVersionDetail, idParamKey: 'dataset_id', uploadAction: '/api/mmp/dataset/upload', uploadAccept: '.zip,.tgz', + downloadAllAction: '/api/mmp/dataset/downloadAllFilesl', + downloadSingleAction: '/api/mmp/dataset/download', + infoTypePropertyName: 'dataset_type_name', + infoTagPropertyName: 'dataset_tag_name', }, [ResourceType.Model]: { getList: getModelList, getVersions: getModelVersionsById, getFiles: getModelVersionIdList, deleteRecord: deleteModel, + addVersion: addModelsVersionDetail, + deleteVersion: deleteModelVersion, + getInfo: getModelById, name: '模型', typeParamKey: 'model_type', tagParamKey: 'model_tag', @@ -101,13 +120,16 @@ export const resourceConfig: Record = { tagTitle: '模型能力', typeValue: 3, tagValue: 4, - iconPathPrefix: 'model', + prefix: 'model', deleteModalTitle: '确定删除该条模型实例吗?', addBtnTitle: '新建模型', - addVersionReq: addModelsVersionDetail, idParamKey: 'models_id', uploadAction: '/api/mmp/models/upload', uploadAccept: undefined, + downloadAllAction: '/api/mmp/models/downloadAllFiles', + downloadSingleAction: '/api/mmp/models/download_model', + infoTypePropertyName: 'model_type_name', + infoTagPropertyName: 'model_tag_name', }, }; @@ -119,11 +141,36 @@ export type CategoryData = { path: string; }; -// 数据类型 +// 资源数据 export type ResourceData = { id: number; name: string; description: string; create_by: string; update_time: string; + available_range: number; + model_type_name?: string; + model_tag_name?: string; + dataset_type_name?: string; + dataset_tag_name?: string; +}; + +// 版本数据 +export type ResourceVersionData = { + label: string; + value: string; +}; + +// 版本文件数据 +export type ResourceFileData = { + id: number; + file_name: string; + file_size: string; + description: string; + create_by: string; + create_time: string; + update_by: string; + update_time: string; + url: string; + version: string; }; diff --git a/react-ui/src/pages/Dataset/index.jsx b/react-ui/src/pages/Dataset/index.tsx similarity index 81% rename from react-ui/src/pages/Dataset/index.jsx rename to react-ui/src/pages/Dataset/index.tsx index 33d2844d..29963749 100644 --- a/react-ui/src/pages/Dataset/index.jsx +++ b/react-ui/src/pages/Dataset/index.tsx @@ -1,5 +1,5 @@ import ResourcePage from './components/ResourcePage'; -import { ResourceType } from './types'; +import { ResourceType } from './config'; const DatasetPage = () => { return ; diff --git a/react-ui/src/pages/Dataset/intro.jsx b/react-ui/src/pages/Dataset/intro.jsx deleted file mode 100644 index 6d556c08..00000000 --- a/react-ui/src/pages/Dataset/intro.jsx +++ /dev/null @@ -1,263 +0,0 @@ -import KFIcon from '@/components/KFIcon'; -import { ResourceType } from '@/pages/Dataset/types'; -import { - deleteDatasetVersion, - getDatasetById, - getDatasetVersionIdList, - getDatasetVersionsById, -} from '@/services/dataset/index.js'; -import { formatDate } from '@/utils/date'; -import { downLoadZip } from '@/utils/downloadfile'; -import { openAntdModal } from '@/utils/modal'; -import { modalConfirm } from '@/utils/ui'; -import { useParams, useSearchParams } from '@umijs/max'; -import { App, Button, Input, Select, Table, Tabs } from 'antd'; -import { useEffect, useRef, useState } from 'react'; -import AddVersionModal from './components/AddVersionModal'; -import Styles from './intro.less'; -const { Search } = Input; -const { TabPane } = Tabs; - -const Dataset = () => { - const { message } = App.useApp(); - const [formList, setFormList] = useState([]); - const [datasetDetailObj, setDatasetDetailObj] = useState({}); - const [version, setVersion] = useState(null); - const [versionList, setVersionList] = useState([]); - const locationParams = useParams(); //新版本获取路由参数接口 - const [searchParams] = useSearchParams(); - const [wordList, setWordList] = useState([]); - const [activeTabKey, setActiveTabKey] = useState('1'); - const isPublic = searchParams.get('isPublic') === 'true'; - - const getDatasetByDetail = () => { - getDatasetById(locationParams.id).then((ret) => { - console.log(ret); - setDatasetDetailObj(ret.data); - }); - }; - // 获取数据集版本 - const getDatasetVersionList = () => { - getDatasetVersionsById(locationParams.id).then((ret) => { - console.log(ret); - if (ret.data && ret.data.length > 0) { - setVersionList( - ret.data.map((item) => { - return { - label: item, - value: item, - }; - }), - ); - setVersion(ret.data[0]); - getDatasetVersions({ version: ret.data[0], dataset_id: locationParams.id }); - } else { - setVersion(null); - setWordList([]); - } - }); - }; - useEffect(() => { - getDatasetByDetail(); - getDatasetVersionList(); - return () => {}; - }, []); - const showModal = () => { - const { close } = openAntdModal(AddVersionModal, { - resourceType: ResourceType.Dataset, - resourceId: locationParams.id, - initialName: datasetDetailObj.name, - onOk: () => { - getDatasetVersionList(); - close(); - }, - }); - }; - - const deleteDataset = () => { - modalConfirm({ - title: '删除后,该数据集版本将不可恢复', - content: '是否确认删除?', - onOk: () => { - deleteDatasetVersion({ dataset_id: locationParams.id, version }).then((ret) => { - getDatasetVersionList(); - message.success('删除成功'); - }); - }, - }); - }; - // 获取版本下的文件列表 - const getDatasetVersions = (params) => { - getDatasetVersionIdList(params).then((res) => { - setWordList(res?.data?.content ?? []); - }); - }; - - const handleExport = async () => { - const hide = message.loading('正在下载'); - hide(); - downLoadZip(`/api/mmp/dataset/downloadAllFiles`, { dataset_id: locationParams.id, version }); - }; - - const downloadAlone = (e, record) => { - console.log(record); - const hide = message.loading('正在下载'); - hide(); - downLoadZip(`/api/mmp/dataset/download/${record.id}`); - }; - - const handleChange = (value) => { - console.log(value); - if (value) { - getDatasetVersions({ version: value, dataset_id: locationParams.id }); - setVersion(value); - } else { - setVersion(null); - } - }; - - const columns = [ - { - title: '序号', - dataIndex: 'index', - key: 'index', - width: 80, - render(text, record, index) { - return {(pageOption.current.page - 1) * 10 + index + 1}; - }, - // render: (text, record, index) => `${((curPage-1)*10)+(index+1)}`, - }, - { - title: '文件名称', - dataIndex: 'file_name', - key: 'file_name', - render: (text, record) => downloadAlone(e, record)}>{text}, - }, - { - title: '版本号', - dataIndex: 'version', - key: 'version', - }, - { - title: '文件大小', - dataIndex: 'file_size', - key: 'file_size', - }, - { - title: '更新时间', - dataIndex: 'update_time', - key: 'update_time', - render: (text) => {formatDate(text)}, - }, - { - title: '操作', - dataIndex: 'option', - width: '100px', - key: 'option', - render: (_, record) => [ - , - ], - }, - ]; - const pageOption = useRef({ page: 1, size: 10 }); - - // 当前页面切换 - const paginationChange = async (current, size) => { - console.log('page', current, size); - pageOption.current = { - page: current, - size: size, - }; - // getList() - }; - return ( -
-
- {datasetDetailObj.name} -
-
数据集 id:{datasetDetailObj.id}
-
{datasetDetailObj.dataset_type_name || '...'}
-
{datasetDetailObj.dataset_tag_name || '...'}
-
-
-
- setActiveTabKey(key)}> - -
简介
-
{datasetDetailObj.description}
-
- -
-
数据集文件列表
-
-
- 版本号: -
- - - - - - ); -}; -export default Dataset; diff --git a/react-ui/src/pages/Dataset/intro.less b/react-ui/src/pages/Dataset/intro.less deleted file mode 100644 index b36af2cf..00000000 --- a/react-ui/src/pages/Dataset/intro.less +++ /dev/null @@ -1,82 +0,0 @@ -.datasetIntroTopBox { - display: flex; - flex-direction: column; - justify-content: space-between; - width: 100%; - height: 110px; - margin-bottom: 10px; - padding: 25px 30px; - background-image: url(/assets/images/dataset-back.png); - background-repeat: no-repeat; - background-position: top center; - background-size: 100% 100%; - - .smallTagBox { - display: flex; - align-items: center; - color: #1664ff; - font-size: 14px; - .tagItem { - margin-right: 20px; - padding: 4px 10px; - background: rgba(22, 100, 255, 0.1); - border-radius: 4px; - } - } -} -.dataListBox { - padding: 20px 30px; - color: #1d1d20; - font-size: 16px; - font-family: alibaba; - background: #ffffff; - border-radius: 10px; - box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09); - .dataButtonList { - display: flex; - align-items: center; - justify-content: space-between; - height: 32px; - margin: 24px 0 30px 0; - color: #575757; - font-size: 16px; - } -} -.datasetIntroCneterBox { - height: 77vh; - padding: 20px 30px; - background: #ffffff; - border-radius: 10px; - box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09); -} -.datasetIntroTitle { - margin: 37px 0 10px 0; - color: #1d1d20; - font-size: 15px; -} -.datasetIntroText { - margin-bottom: 30px; - color: #575757; - font-size: 14px; -} -.datasetBox { - background: #f9fafb; - - :global { - .ant-tabs-top > .ant-tabs-nav { - margin: 0; - } - .ant-pagination { - text-align: right; - } - } -} - -.plusButton { - margin: 0 18px 0 20px; -} - -.tipContent { - margin-top: 5px; - color: #c73131; -} diff --git a/react-ui/src/pages/Dataset/intro.tsx b/react-ui/src/pages/Dataset/intro.tsx new file mode 100644 index 00000000..6a9e14ec --- /dev/null +++ b/react-ui/src/pages/Dataset/intro.tsx @@ -0,0 +1,8 @@ +import ResourceIntro from '@/pages/Dataset/components/ResourceIntro'; +import { ResourceType } from '@/pages/Dataset/config'; + +function DatasetIntro() { + return ; +} + +export default DatasetIntro; diff --git a/react-ui/src/pages/DatasetPreparation/DatasetAnnotation/index.tsx b/react-ui/src/pages/DatasetPreparation/DatasetAnnotation/index.tsx index 385be971..a1f017e6 100644 --- a/react-ui/src/pages/DatasetPreparation/DatasetAnnotation/index.tsx +++ b/react-ui/src/pages/DatasetPreparation/DatasetAnnotation/index.tsx @@ -16,7 +16,7 @@ function DatasetAnnotation() { }; return (
- + {iframeUrl && }
); } diff --git a/react-ui/src/pages/Experiment/components/ExperimentParameter/index.tsx b/react-ui/src/pages/Experiment/components/ExperimentParameter/index.tsx index 9e8018c2..62be954f 100644 --- a/react-ui/src/pages/Experiment/components/ExperimentParameter/index.tsx +++ b/react-ui/src/pages/Experiment/components/ExperimentParameter/index.tsx @@ -1,3 +1,5 @@ +import ParameterInput from '@/components/ParameterInput'; +import ParameterSelect from '@/components/ParameterSelect'; import SubAreaTitle from '@/components/SubAreaTitle'; import { useComputingResource } from '@/hooks/resource'; import { PipelineNodeModelSerialize } from '@/types'; @@ -122,15 +124,8 @@ function ExperimentParameter({ form, nodeData }: ExperimentParameterProps) {