feat: 完成模型和数据集选择
This commit is contained in:
parent
57d859a8dc
commit
ff761eaa28
|
@ -135,6 +135,17 @@ export default [
|
|||
path: '/dataset/datasetIntro/:id',
|
||||
component: './Dataset/datasetIntro',
|
||||
},
|
||||
{
|
||||
name: '镜像',
|
||||
path: 'mirror',
|
||||
routes: [
|
||||
{
|
||||
name: '镜像列表',
|
||||
path: '',
|
||||
component: './Mirror/list',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '模型管理',
|
||||
path: '/dataset/modelIndex',
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
|
@ -5,22 +5,31 @@
|
|||
*/
|
||||
|
||||
import ModalTitle from '@/components/ModalTitle';
|
||||
import { Modal, type ModalProps } from 'antd';
|
||||
import { ConfigProvider, Modal, theme, type ModalProps } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { useAntdConfig } from 'umi';
|
||||
import './index.less';
|
||||
|
||||
const { useToken } = theme;
|
||||
|
||||
export interface KFModalProps extends ModalProps {
|
||||
image: string;
|
||||
}
|
||||
function KFModal({ title, image, children, className = '', ...rest }: KFModalProps) {
|
||||
const { token } = useToken();
|
||||
console.log('token', token);
|
||||
const antdConfig = useAntdConfig();
|
||||
console.log('antdConfig', antdConfig);
|
||||
return (
|
||||
<Modal
|
||||
className={classNames(['kf-modal', className])}
|
||||
{...rest}
|
||||
title={<ModalTitle title={title} image={image}></ModalTitle>}
|
||||
>
|
||||
{children}
|
||||
</Modal>
|
||||
<ConfigProvider {...antdConfig}>
|
||||
<Modal
|
||||
className={classNames(['kf-modal', className])}
|
||||
{...rest}
|
||||
title={<ModalTitle title={title} image={image}></ModalTitle>}
|
||||
>
|
||||
{children}
|
||||
</Modal>
|
||||
</ConfigProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* @Author: 赵伟
|
||||
* @Date: 2024-04-16 14:55:40
|
||||
* @Description:
|
||||
*/
|
||||
// import { useEffect, useState } from 'react';
|
||||
// import styles from './index.less';
|
||||
// import { Tabs } from "antd"
|
||||
|
||||
// function KFTabs() {
|
||||
// const [iframeUrl, setIframeUrl] = useState('');
|
||||
// useEffect(() => {
|
||||
|
||||
// }, []);
|
||||
|
||||
// return (
|
||||
// <div className={styles.container}>
|
||||
// <div className={Styles.datasetAllBox}>
|
||||
// <Tabs defaultActiveKey="1">
|
||||
// <TabPane tab="数据广场" key="1">
|
||||
// <PublicData />
|
||||
// </TabPane>
|
||||
// <TabPane tab="个人数据" key="2">
|
||||
// <PersonalData />
|
||||
// </TabPane>
|
||||
// </Tabs>
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
|
||||
// export default KFTabs;
|
|
@ -194,6 +194,6 @@ ol {
|
|||
}
|
||||
}
|
||||
|
||||
.local-svg {
|
||||
.umi-local-svg {
|
||||
vertical-align: -1px;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="15.429" height="15.429" viewBox="0 0 15.429 15.429">
|
||||
<path id="搜索" d="M98.21,97.392a7.248,7.248,0,1,0-3.422,2.26.579.579,0,1,0-.338-1.107,6.218,6.218,0,1,1,2.6-1.6.669.669,0,0,0,.007.939l2.712,2.712a.579.579,0,0,0,.818-.818Z" transform="translate(-85.333 -85.333)" fill="rgba(22,100,255,0.4)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 358 B |
|
@ -62,7 +62,7 @@ export const getParamRules = (paramType: number, required: boolean = false): For
|
|||
};
|
||||
|
||||
// 根据参数设置 label
|
||||
const getParamType = (param: PipelineGlobalParam): string => {
|
||||
export const getParamType = (param: PipelineGlobalParam): string => {
|
||||
const paramTypes: Readonly<Record<number, string>> = {
|
||||
1: '字符串',
|
||||
2: '整型',
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
.params_container {
|
||||
max-height: 230px;
|
||||
padding: 15px 15px 0;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #e6e6e6;
|
||||
border-radius: 8px;
|
||||
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
/*
|
||||
* @Author: 赵伟
|
||||
* @Date: 2024-04-09 15:59:14
|
||||
* @Description: 查看实验使用的参数
|
||||
*/
|
||||
import parameterImg from '@/assets/img/modal-parameter.png';
|
||||
import KFModal from '@/components/KFModal';
|
||||
import { type PipelineGlobalParam } from '@/types';
|
||||
import { getParamType } from './addExperimentModal';
|
||||
import styles from './paramsModal.less';
|
||||
|
||||
type ParamsModalProps = {
|
||||
|
@ -22,7 +28,7 @@ function ParamsModal({ open, onCancel, globalParam = [] }: ParamsModalProps) {
|
|||
<div className={styles.params_container}>
|
||||
{globalParam.map((item) => (
|
||||
<div key={item.param_name} className={styles.params_container_line}>
|
||||
<span className={styles.params_container_line_label}>{item.param_name}</span>
|
||||
<span className={styles.params_container_line_label}>{getParamType(item)}</span>
|
||||
<span className={styles.params_container_line_value}>{item.param_value}</span>
|
||||
</div>
|
||||
))}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
.mirror-list {
|
||||
height: 100%;
|
||||
background-color: #f9fafb;
|
||||
&__tabs-container {
|
||||
height: 59px;
|
||||
background-image: url('../../assets/img/mirror-tabs-bg.png');
|
||||
}
|
||||
|
||||
&__content {
|
||||
height: calc(100% - 69px);
|
||||
margin-top: 10px;
|
||||
padding: 20px 30px 0;
|
||||
background-color: white;
|
||||
border-radius: 10px;
|
||||
|
||||
&__filter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
&__table {
|
||||
height: calc(100% - 44px);
|
||||
margin-top: 12px;
|
||||
:global {
|
||||
.ant-table-wrapper {
|
||||
height: 100%;
|
||||
.ant-spin-nested-loading {
|
||||
height: 100%;
|
||||
}
|
||||
.ant-spin-container {
|
||||
height: 100%;
|
||||
}
|
||||
.ant-table {
|
||||
height: calc(100% - 74px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* @Author: 赵伟
|
||||
* @Date: 2024-04-16 13:58:08
|
||||
* @Description: 镜像列表
|
||||
*/
|
||||
import { getMirrorListReq } from '@/services/mirror';
|
||||
import { to } from '@/utils/promise';
|
||||
import { Button, Input, Table } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import styles from './list.less';
|
||||
|
||||
const tabItems = [
|
||||
{
|
||||
key: 'Public',
|
||||
label: '公共镜像',
|
||||
},
|
||||
{
|
||||
key: 'Private',
|
||||
label: '个人镜像',
|
||||
},
|
||||
];
|
||||
|
||||
function MirrorList() {
|
||||
const [activeTab, setActiveTab] = useState('Public');
|
||||
const [tableData, setTableData] = useState([]);
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
const [tableHeight, setTableHeight] = useState(0);
|
||||
const [pagination, setPagination] = useState({
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
useEffect(() => {
|
||||
getMirrorList('');
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const setTableScollHeight = () => {
|
||||
if (contentRef.current) {
|
||||
setTableHeight(contentRef.current.offsetHeight - 74 - 55);
|
||||
}
|
||||
};
|
||||
setTableScollHeight();
|
||||
window.addEventListener('resize', setTableScollHeight);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', setTableScollHeight);
|
||||
};
|
||||
}, [contentRef]);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '镜像名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: '10%',
|
||||
},
|
||||
{
|
||||
title: '版本数据',
|
||||
dataIndex: 'version_count',
|
||||
key: 'version_count',
|
||||
width: '10%',
|
||||
},
|
||||
{
|
||||
title: '镜像描述',
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
width: '50%',
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'create_time',
|
||||
key: 'create_time',
|
||||
width: '20%',
|
||||
render: (text: string) => <span>{dayjs(text).format('YYYY-MM-DD HH:mm:ss')}</span>,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
width: '100px',
|
||||
key: 'operation',
|
||||
render: (_: any, record: any) => [
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
key="download"
|
||||
// onClick={(e) => downloadAlone(e, record)}
|
||||
>
|
||||
查看详情
|
||||
</Button>,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const getMirrorList = async (name: string) => {
|
||||
const params = {
|
||||
page: pagination.current - 1,
|
||||
size: pagination.pageSize,
|
||||
name,
|
||||
image_type: 1,
|
||||
};
|
||||
const [res] = await to(getMirrorListReq(params));
|
||||
if (res && res.data) {
|
||||
const { content = [], totalElements = 0 } = res.data;
|
||||
console.log(res);
|
||||
setTableData(content);
|
||||
setPagination((prev) => ({
|
||||
...prev,
|
||||
total: totalElements,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
const onSearch = (value: string) => {
|
||||
getMirrorList(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles['mirror-list']}>
|
||||
<div className={styles['mirror-list__tabs-container']}>
|
||||
{/* <Tabs
|
||||
activeKey={activeTab}
|
||||
items={tabItems}
|
||||
onChange={setActiveTab}
|
||||
className={styles['model-tabs']}
|
||||
/> */}
|
||||
</div>
|
||||
<div className={styles['mirror-list__content']}>
|
||||
<div className={styles['mirror-list__content__filter']}>
|
||||
<Input.Search
|
||||
placeholder="按数据集名称筛选"
|
||||
allowClear
|
||||
onSearch={onSearch}
|
||||
style={{ width: 300 }}
|
||||
/>
|
||||
<Button type="default">刷新</Button>
|
||||
</div>
|
||||
<div className={styles['mirror-list__content__table']} ref={contentRef}>
|
||||
<Table
|
||||
dataSource={tableData}
|
||||
columns={columns}
|
||||
scroll={{ y: tableHeight }}
|
||||
pagination={pagination}
|
||||
rowKey="id"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MirrorList;
|
|
@ -1,13 +1,18 @@
|
|||
@import '@/styles/theme.less';
|
||||
|
||||
.model-tabs {
|
||||
margin-left: 8px;
|
||||
:global {
|
||||
.ant-tabs-tab {
|
||||
padding-top: 0 !important;
|
||||
padding-top: 0;
|
||||
}
|
||||
.ant-tabs-nav::before,
|
||||
div > .ant-tabs-nav::before {
|
||||
border: none !important;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ant-tabs-nav {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +21,12 @@
|
|||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
:global {
|
||||
.ant-input-affix-wrapper .ant-input-prefix {
|
||||
margin-inline-end: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
&__left {
|
||||
width: 488px;
|
||||
height: 398px;
|
||||
|
@ -27,20 +38,11 @@
|
|||
|
||||
&__search {
|
||||
margin-bottom: 14px;
|
||||
padding-left: 0;
|
||||
background-color: transparent;
|
||||
border-width: 0;
|
||||
border-bottom: 1px solid @border-color-second;
|
||||
border-radius: 0;
|
||||
|
||||
// &:hover {
|
||||
// background-color: transparent;
|
||||
// }
|
||||
// &:active {
|
||||
// background-color: transparent;
|
||||
// }
|
||||
// &:focus {
|
||||
// background-color: transparent;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,9 +16,10 @@ import {
|
|||
getModelVersionsById,
|
||||
} from '@/services/dataset/index.js';
|
||||
import { to } from '@/utils/promise';
|
||||
import { Icon } from '@umijs/max';
|
||||
import type { GetRef, ModalProps, TabsProps, TreeDataNode, TreeProps } from 'antd';
|
||||
import { Input, Tabs, Tree } from 'antd';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import styles from './index.less';
|
||||
|
||||
export enum ResourceSelectorType {
|
||||
|
@ -30,7 +31,7 @@ type ResourceSelectorTypeKeys = keyof typeof ResourceSelectorType;
|
|||
type ResourceSelectorTypeValues = (typeof ResourceSelectorType)[ResourceSelectorTypeKeys];
|
||||
|
||||
type GetModelFilesReqParam = {
|
||||
model_id: number;
|
||||
models_id: number;
|
||||
version: string;
|
||||
};
|
||||
|
||||
|
@ -52,6 +53,11 @@ export type SelectorTypeInfo = {
|
|||
tabItems: TabsProps['items'];
|
||||
};
|
||||
|
||||
enum TabItemKeys {
|
||||
Private = 'Private', // 我的
|
||||
Public = 'Public', // 公开
|
||||
}
|
||||
|
||||
export const selectorTypeData: Record<ResourceSelectorTypeValues, SelectorTypeInfo> = {
|
||||
Model: {
|
||||
getList: getModelList,
|
||||
|
@ -63,11 +69,11 @@ export const selectorTypeData: Record<ResourceSelectorTypeValues, SelectorTypeIn
|
|||
fileReqParamKey: 'models_id',
|
||||
tabItems: [
|
||||
{
|
||||
key: '0',
|
||||
key: TabItemKeys.Private,
|
||||
label: '我的模型',
|
||||
},
|
||||
{
|
||||
key: '1',
|
||||
key: TabItemKeys.Public,
|
||||
label: '公开模型',
|
||||
},
|
||||
],
|
||||
|
@ -82,11 +88,11 @@ export const selectorTypeData: Record<ResourceSelectorTypeValues, SelectorTypeIn
|
|||
fileReqParamKey: 'dataset_id',
|
||||
tabItems: [
|
||||
{
|
||||
key: '0',
|
||||
key: TabItemKeys.Private,
|
||||
label: '我的数据集',
|
||||
},
|
||||
{
|
||||
key: '1',
|
||||
key: TabItemKeys.Public,
|
||||
label: '公开数据集',
|
||||
},
|
||||
],
|
||||
|
@ -94,31 +100,33 @@ export const selectorTypeData: Record<ResourceSelectorTypeValues, SelectorTypeIn
|
|||
};
|
||||
|
||||
type ResourceSelectorResponse = {
|
||||
id: number;
|
||||
name: string;
|
||||
path: string;
|
||||
version: string;
|
||||
activeTab: string;
|
||||
id: number; // 数据集或者模型 id
|
||||
name: string; // 数据集或者模型 name
|
||||
version: string; // 数据集或者模型版本
|
||||
path: string; // 数据集或者模型版本路径
|
||||
activeTab: TabItemKeys; // 是我的还是公开的
|
||||
};
|
||||
|
||||
interface ResourceSelectorModalProps extends Omit<ModalProps, 'onOk'> {
|
||||
type: ResourceSelectorType; // 模型 | 数据集
|
||||
defaultExpandedKeys: React.Key[];
|
||||
defaultCheckedKeys: React.Key[];
|
||||
defaultActiveTab: string;
|
||||
defaultActiveTab: TabItemKeys;
|
||||
onOk?: (params: ResourceSelectorResponse | null) => void;
|
||||
}
|
||||
|
||||
type ResourceGroup = {
|
||||
id: number;
|
||||
name: string;
|
||||
id: number; // 数据集或者模型 id
|
||||
name: string; // 数据集或者模型 id
|
||||
};
|
||||
|
||||
type ResourceFile = {
|
||||
id: number;
|
||||
file_name: string;
|
||||
id: number; // 文件 id
|
||||
file_name: string; // 文件 name
|
||||
};
|
||||
|
||||
type TreeRef = GetRef<typeof Tree<TreeDataNode>>;
|
||||
|
||||
// list 转成 treeData
|
||||
const convertToTreeData = (list: ResourceGroup[]): TreeDataNode[] => {
|
||||
return list.map((v) => ({
|
||||
|
@ -129,6 +137,7 @@ const convertToTreeData = (list: ResourceGroup[]): TreeDataNode[] => {
|
|||
}));
|
||||
};
|
||||
|
||||
// 更新树形结构的 children
|
||||
const updateChildren = (parentId: number, children: TreeDataNode[]) => {
|
||||
return (node: TreeDataNode) => {
|
||||
if (node.key === parentId) {
|
||||
|
@ -141,22 +150,30 @@ const updateChildren = (parentId: number, children: TreeDataNode[]) => {
|
|||
};
|
||||
};
|
||||
|
||||
type TreeRef = GetRef<typeof Tree<TreeDataNode>>;
|
||||
// 得到数据集或者模型 id 和下属版本号
|
||||
const getIdAndVersion = (versionKey: string) => {
|
||||
const index = versionKey.indexOf('-');
|
||||
const id = Number(versionKey.slice(0, index));
|
||||
const version = versionKey.slice(index + 1);
|
||||
return {
|
||||
id,
|
||||
version,
|
||||
};
|
||||
};
|
||||
|
||||
function ResourceSelectorModal({
|
||||
type,
|
||||
defaultExpandedKeys = [],
|
||||
defaultCheckedKeys = [],
|
||||
defaultActiveTab = '0',
|
||||
defaultActiveTab = TabItemKeys.Private,
|
||||
onOk,
|
||||
...rest
|
||||
}: ResourceSelectorModalProps) {
|
||||
const [activeTab, setActiveTab] = useState(defaultActiveTab);
|
||||
const [activeTab, setActiveTab] = useState<string>(defaultActiveTab);
|
||||
const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
|
||||
const [checkedKeys, setCheckedKeys] = useState<React.Key[]>([]);
|
||||
const [loadedKeys, setLoadedKeys] = useState<React.Key[]>([]);
|
||||
const [originTreeData, setOriginTreeData] = useState<TreeDataNode[]>([]);
|
||||
const [treeData, setTreeData] = useState<TreeDataNode[]>([]);
|
||||
const [files, setFiles] = useState<ResourceFile[]>([]);
|
||||
const [versionPath, setVersionPath] = useState('');
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
@ -174,19 +191,21 @@ function ResourceSelectorModal({
|
|||
getTreeData();
|
||||
}, [activeTab, type]);
|
||||
|
||||
useEffect(() => {
|
||||
const treeData = originTreeData.filter((v) =>
|
||||
(v.title as string).toLowerCase()?.includes(searchText.toLowerCase()),
|
||||
);
|
||||
setTreeData(treeData);
|
||||
}, [originTreeData, searchText]);
|
||||
const treeData = useMemo(
|
||||
() =>
|
||||
originTreeData.filter((v) =>
|
||||
(v.title as string).toLowerCase()?.includes(searchText.toLowerCase()),
|
||||
),
|
||||
[originTreeData, searchText],
|
||||
);
|
||||
|
||||
// 获取数据集或模型列表
|
||||
const getTreeData = async () => {
|
||||
const available_range = activeTab === TabItemKeys.Private ? '0' : '1';
|
||||
const params = {
|
||||
page: 0,
|
||||
size: 200,
|
||||
available_range: activeTab,
|
||||
available_range: available_range,
|
||||
};
|
||||
const getListReq = selectorTypeData[type].getList;
|
||||
const [res] = await to(getListReq(params));
|
||||
|
@ -255,7 +274,7 @@ function ResourceSelectorModal({
|
|||
|
||||
// 扩展
|
||||
const onExpand: TreeProps['onExpand'] = (expandedKeysValue) => {
|
||||
const lastKeys = (expandedKeysValue as React.Key[]).slice(-1);
|
||||
const lastKeys = expandedKeysValue.slice(-1);
|
||||
setExpandedKeys(lastKeys);
|
||||
};
|
||||
|
||||
|
@ -265,9 +284,7 @@ function ResourceSelectorModal({
|
|||
setCheckedKeys(lastKeys);
|
||||
if (lastKeys.length) {
|
||||
const last = lastKeys[0] as string;
|
||||
const index = last.indexOf('-');
|
||||
const id = Number(last.slice(0, index));
|
||||
const version = last.slice(index + 1);
|
||||
const { id, version } = getIdAndVersion(last);
|
||||
getFiles(id, version);
|
||||
} else {
|
||||
setFiles([]);
|
||||
|
@ -295,9 +312,7 @@ function ResourceSelectorModal({
|
|||
const restoreLastCheck = (parentId: number) => {
|
||||
if (!fisrtLoadVersions && defaultCheckedKeys.length > 0) {
|
||||
const last = defaultCheckedKeys[0] as string;
|
||||
const index = last.indexOf('-');
|
||||
const id = Number(last.slice(0, index));
|
||||
const version = last.slice(index + 1);
|
||||
const { id, version } = getIdAndVersion(last);
|
||||
// 判断正在打开的 id 和 defaultCheckedKeys 的 id 是否一致
|
||||
if (id === parentId) {
|
||||
setTimeout(() => {
|
||||
|
@ -319,16 +334,14 @@ function ResourceSelectorModal({
|
|||
const handleOk = () => {
|
||||
if (checkedKeys.length > 0) {
|
||||
const last = checkedKeys[0] as string;
|
||||
const index = last.indexOf('-');
|
||||
const id = Number(last.slice(0, index));
|
||||
const version = last.slice(index + 1);
|
||||
const { id, version } = getIdAndVersion(last);
|
||||
const name = (treeData.find((v) => Number(v.key) === id)?.title ?? '') as string;
|
||||
const res = {
|
||||
id,
|
||||
name,
|
||||
path: versionPath,
|
||||
version,
|
||||
activeTab,
|
||||
activeTab: activeTab as TabItemKeys,
|
||||
};
|
||||
onOk?.(res);
|
||||
} else {
|
||||
|
@ -344,7 +357,7 @@ function ResourceSelectorModal({
|
|||
|
||||
return (
|
||||
<KFModal {...rest} title={title} image={titleImg} onOk={handleOk} width={920} destroyOnClose>
|
||||
<div className={styles}>
|
||||
<div>
|
||||
<Tabs
|
||||
activeKey={activeTab}
|
||||
items={tabItems}
|
||||
|
@ -360,6 +373,7 @@ function ResourceSelectorModal({
|
|||
variant="borderless"
|
||||
value={searchText}
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
prefix={<Icon icon="local:magnifying-glass" style={{ height: '15px' }} />}
|
||||
/>
|
||||
<Tree
|
||||
ref={treeRef}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { pick } from '@/utils/index';
|
||||
import { openAntdModal } from '@/utils/modal';
|
||||
import { Icon } from '@umijs/max';
|
||||
import { Button, Drawer, Form, Input } from 'antd';
|
||||
|
@ -9,17 +10,14 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
|||
const [form] = Form.useForm();
|
||||
const [stagingItem, setStagingItem] = useState({});
|
||||
const [open, setOpen] = useState(false);
|
||||
// const [modelSelectorOpen, openModelSelector, closeModelSelector] = useVisible(false);
|
||||
// const [selectorType, setSelectorType] = useState(SelectorType.Model);
|
||||
// const [formItemName, setFormItemName] = useState('');
|
||||
const [selectedModel, setSelectedModel] = useState(undefined);
|
||||
const [selectedDataset, setSelectedDataset] = useState(undefined);
|
||||
|
||||
const afterOpenChange = () => {
|
||||
if (!open) {
|
||||
console.log(111, open);
|
||||
|
||||
console.log(stagingItem, form.getFieldsValue());
|
||||
// 禁止校验 guard-for-in
|
||||
/* eslint-disable */
|
||||
for (let i in form.getFieldsValue()) {
|
||||
for (let j in stagingItem.in_parameters) {
|
||||
if (i == j) {
|
||||
|
@ -38,6 +36,7 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
/* eslint-enable */
|
||||
// setStagingItem({...stagingItem,})
|
||||
console.log(stagingItem.control_strategy);
|
||||
onParentChange({
|
||||
|
@ -86,14 +85,12 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
|||
},
|
||||
}));
|
||||
|
||||
// 选择数据集、模型
|
||||
const selectResource = (name, item) => {
|
||||
// setFormItemName(name);
|
||||
// setSelectorType(item.item_type === 'dataset' ? SelectorType.Dataset : SelectorType.Model);
|
||||
// openModelSelector();
|
||||
const type =
|
||||
item.item_type === 'dataset' ? ResourceSelectorType.Dataset : ResourceSelectorType.Model;
|
||||
const resource = type === ResourceSelectorType.Dataset ? selectedDataset : selectedModel;
|
||||
const { destroy } = openAntdModal(
|
||||
const { close } = openAntdModal(
|
||||
ResourceSelectorModal,
|
||||
{
|
||||
type,
|
||||
|
@ -102,7 +99,8 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
|||
defaultActiveTab: resource?.activeTab,
|
||||
onOk: (res) => {
|
||||
if (res) {
|
||||
const value = JSON.stringify(res);
|
||||
const jsonObj = pick(res, ['id', 'version', 'path']);
|
||||
const value = JSON.stringify(jsonObj);
|
||||
form.setFieldValue(name, value);
|
||||
if (type === ResourceSelectorType.Dataset) {
|
||||
setSelectedDataset(res);
|
||||
|
@ -117,35 +115,32 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
|||
}
|
||||
form.setFieldValue(name, '');
|
||||
}
|
||||
destroy();
|
||||
close();
|
||||
},
|
||||
},
|
||||
true,
|
||||
);
|
||||
};
|
||||
|
||||
const handleModelSelect = (obj) => {
|
||||
if (obj) {
|
||||
const value = JSON.stringify(obj);
|
||||
setSelectedModel(obj);
|
||||
form.setFieldValue(formItemName, value);
|
||||
} else {
|
||||
form.setFieldValue(formItemName, '');
|
||||
}
|
||||
closeModelSelector();
|
||||
};
|
||||
|
||||
// 获取选择数据集、模型后面按钮 icon
|
||||
const getSelectBtnIcon = (item) => {
|
||||
const type = item.item_type;
|
||||
if (type === 'dataset') {
|
||||
return <Icon icon="local:dataset-select-button" className="local-svg" />;
|
||||
return <Icon icon="local:dataset-select-button" className="umi-local-svg" />;
|
||||
} else if (type === 'model') {
|
||||
return <Icon icon="local:model-select-button" className="local-svg" />;
|
||||
return <Icon icon="local:model-select-button" className="umi-local-svg" />;
|
||||
} else {
|
||||
return <Icon icon="local:mirror-select-button" className="local-svg" />;
|
||||
return <Icon icon="local:mirror-select-button" className="umi-local-svg" />;
|
||||
}
|
||||
};
|
||||
|
||||
// 控制策略
|
||||
const controlStrategy = stagingItem.control_strategy;
|
||||
// 输入参数
|
||||
const inParameters = stagingItem.in_parameters;
|
||||
// 输出参数
|
||||
const outParameters = stagingItem.out_parameters;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Drawer
|
||||
|
@ -254,11 +249,9 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
|||
<Form.Item label="环境变量" name="env_variables">
|
||||
<TextArea />
|
||||
</Form.Item>
|
||||
{stagingItem.control_strategy &&
|
||||
Object.keys(stagingItem.control_strategy) &&
|
||||
Object.keys(stagingItem.control_strategy).length > 0
|
||||
? Object.keys(stagingItem.control_strategy).map((item) => (
|
||||
<Form.Item key={item} label={stagingItem.control_strategy[item].label} name={item}>
|
||||
{controlStrategy && Object.keys(controlStrategy).length > 0
|
||||
? Object.keys(controlStrategy).map((item) => (
|
||||
<Form.Item key={item} label={controlStrategy[item].label} name={item}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
))
|
||||
|
@ -271,32 +264,33 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
|||
/>
|
||||
输入参数
|
||||
</div>
|
||||
{stagingItem.in_parameters &&
|
||||
Object.keys(stagingItem.in_parameters) &&
|
||||
Object.keys(stagingItem.in_parameters).length > 0
|
||||
? Object.keys(stagingItem.in_parameters).map((item) => (
|
||||
{inParameters && Object.keys(inParameters).length > 0
|
||||
? Object.keys(inParameters).map((item) => (
|
||||
<Form.Item
|
||||
key={item}
|
||||
label={stagingItem.in_parameters[item].label + '(' + item + ')'}
|
||||
label={inParameters[item].label + '(' + item + ')'}
|
||||
required={inParameters[item].require ? true : false}
|
||||
>
|
||||
<div className={Styles['ref-row']}>
|
||||
<Form.Item
|
||||
name={item}
|
||||
noStyle
|
||||
rules={[{ required: stagingItem.in_parameters[item].require ? true : false }]}
|
||||
rules={[{ required: inParameters[item].require ? true : false }]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item noStyle>
|
||||
<Button
|
||||
type="link"
|
||||
icon={getSelectBtnIcon(stagingItem.in_parameters[item])}
|
||||
onClick={() => selectResource(item, stagingItem.in_parameters[item])}
|
||||
className={Styles['select-button']}
|
||||
>
|
||||
{stagingItem.in_parameters[item].label}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
{inParameters[item].type === 'ref' && (
|
||||
<Form.Item noStyle>
|
||||
<Button
|
||||
type="link"
|
||||
icon={getSelectBtnIcon(inParameters[item])}
|
||||
onClick={() => selectResource(item, inParameters[item])}
|
||||
className={Styles['select-button']}
|
||||
>
|
||||
{inParameters[item].label}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
)}
|
||||
</div>
|
||||
</Form.Item>
|
||||
))
|
||||
|
@ -309,14 +303,12 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
|||
/>
|
||||
输出参数
|
||||
</div>
|
||||
{stagingItem.out_parameters &&
|
||||
Object.keys(stagingItem.out_parameters) &&
|
||||
Object.keys(stagingItem.out_parameters).length > 0
|
||||
? Object.keys(stagingItem.out_parameters).map((item) => (
|
||||
{outParameters && Object.keys(outParameters).length > 0
|
||||
? Object.keys(outParameters).map((item) => (
|
||||
<Form.Item
|
||||
key={item}
|
||||
label={stagingItem.out_parameters[item].label + '(' + item + ')'}
|
||||
rules={[{ required: stagingItem.out_parameters[item].require ? true : false }]}
|
||||
label={outParameters[item].label + '(' + item + ')'}
|
||||
rules={[{ required: outParameters[item].require ? true : false }]}
|
||||
name={item}
|
||||
>
|
||||
<Input />
|
||||
|
@ -324,18 +316,6 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
|||
))
|
||||
: ''}
|
||||
</Form>
|
||||
{/* {modelSelectorOpen && (
|
||||
<ResourceSelectorModal
|
||||
open={modelSelectorOpen}
|
||||
onCancel={closeModelSelector}
|
||||
defaultExpandedKeys={selectedModel ? [selectedModel.id] : []}
|
||||
defaultCheckedKeys={
|
||||
selectedModel ? [`${selectedModel.id}-${selectedModel.version}`] : []
|
||||
}
|
||||
type={selectorType}
|
||||
onOk={handleModelSelect}
|
||||
/>
|
||||
)} */}
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* @Author: 赵伟
|
||||
* @Date: 2024-04-16 14:29:44
|
||||
* @Description:
|
||||
*/
|
||||
import { request } from '@umijs/max';
|
||||
|
||||
// 分页查询镜像列表
|
||||
export function getMirrorListReq(params: any) {
|
||||
return request(`/api/mmp/image/`, {
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
// // 分页查询镜像列表
|
||||
// export function getMirrorList(params: any) {
|
||||
// return request(`/image/`, {
|
||||
// method: 'GET',
|
||||
// params,
|
||||
// });
|
||||
// }
|
|
@ -1,12 +0,0 @@
|
|||
export function s8() {
|
||||
return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
|
||||
}
|
||||
|
||||
export function getNameByCode(list, code) {
|
||||
let name = '';
|
||||
list.forEach((item) => {
|
||||
if (item.dictValue === code) name = item.dictLabel;
|
||||
});
|
||||
return name;
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* @Author: 赵伟
|
||||
* @Date: 2024-03-25 13:52:54
|
||||
* @Description:
|
||||
*/
|
||||
export function s8() {
|
||||
return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
|
||||
}
|
||||
|
||||
export function getNameByCode(list: any[], code: any) {
|
||||
let name = '';
|
||||
list.forEach((item) => {
|
||||
if (item.dictValue === code) name = item.dictLabel;
|
||||
});
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks specified properties from an object and returns a new object with only those properties.
|
||||
*
|
||||
* @param obj - The object to pick properties from.
|
||||
* @param properties - An array of property names to pick from the object.
|
||||
* @return A new object with only the picked properties.
|
||||
*/
|
||||
export function pick<T extends object, K extends keyof T>(obj: T, properties: K[]): Pick<T, K> {
|
||||
const picked: Partial<T> = {};
|
||||
for (const key of properties) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
picked[key] = obj[key];
|
||||
}
|
||||
}
|
||||
return picked as Pick<T, K>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Omit properties from an object and return a new object without those properties.
|
||||
*
|
||||
* @param obj - The object to omit properties from.
|
||||
* @param properties - An array of property names to omit from the object.
|
||||
* @return A new object without the omitted properties.
|
||||
*/
|
||||
export function omit<T extends object, K extends keyof T>(obj: T, properties: K[]): Omit<T, K> {
|
||||
const omitted: Partial<T> = { ...obj };
|
||||
for (const key of properties) {
|
||||
if (Object.prototype.hasOwnProperty.call(omitted, key)) {
|
||||
delete omitted[key];
|
||||
}
|
||||
}
|
||||
return omitted as Omit<T, K>;
|
||||
}
|
|
@ -56,7 +56,7 @@ export const openAntdModal = <T extends ModalProps>(
|
|||
render({ ...modalProps, open: true });
|
||||
|
||||
return {
|
||||
destroy: close,
|
||||
close,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue