diff --git a/react-ui/src/assets/img/dataset-config-icon.png b/react-ui/src/assets/img/dataset-config-icon.png
new file mode 100644
index 00000000..1afc4f72
Binary files /dev/null and b/react-ui/src/assets/img/dataset-config-icon.png differ
diff --git a/react-ui/src/components/BasicInfo/components.tsx b/react-ui/src/components/BasicInfo/components.tsx
new file mode 100644
index 00000000..b8932a25
--- /dev/null
+++ b/react-ui/src/components/BasicInfo/components.tsx
@@ -0,0 +1,113 @@
+/*
+ * @Author: 赵伟
+ * @Date: 2024-11-29 09:27:19
+ * @Description: 用于 BasicInfo 和 BasicTableInfo 组件的子组件
+ */
+
+import { Link } from '@umijs/max';
+import { Typography } from 'antd';
+import React from 'react';
+import { type BasicInfoData, type BasicInfoLink } from './types';
+
+type BasicInfoItemProps = {
+ data: BasicInfoData;
+ labelWidth: number;
+ classPrefix: string;
+};
+
+export function BasicInfoItem({ data, labelWidth, classPrefix }: BasicInfoItemProps) {
+ const { label, value, format, ellipsis } = data;
+ const formatValue = format ? format(value) : value;
+ const myClassName = `${classPrefix}__item`;
+ let valueComponent = undefined;
+ if (Array.isArray(formatValue)) {
+ valueComponent = (
+
+ {formatValue.map((item: BasicInfoLink) => (
+
+ ))}
+
+ );
+ } else if (React.isValidElement(formatValue)) {
+ // 这个判断必须在下面的判断之前
+ valueComponent = (
+
+ );
+ } else if (typeof formatValue === 'object' && formatValue) {
+ valueComponent = (
+
+ );
+ } else {
+ valueComponent = (
+
+ );
+ }
+ return (
+
+
+ {label}
+
+ {valueComponent}
+
+ );
+}
+
+type BasicInfoItemValueProps = {
+ ellipsis?: boolean;
+ classPrefix: string;
+ value: string | React.ReactNode;
+ link?: string;
+ url?: string;
+};
+
+export function BasicInfoItemValue({
+ value,
+ link,
+ url,
+ ellipsis,
+ classPrefix,
+}: BasicInfoItemValueProps) {
+ const myClassName = `${classPrefix}__item__value`;
+ let component = undefined;
+ if (url && value) {
+ component = (
+
+ {value}
+
+ );
+ } else if (link && value) {
+ component = (
+
+ {value}
+
+ );
+ } else if (React.isValidElement(value)) {
+ return value;
+ } else {
+ component = {value ?? '--'};
+ }
+
+ return (
+
+
+ {component}
+
+
+ );
+}
diff --git a/react-ui/src/components/BasicInfo/format.ts b/react-ui/src/components/BasicInfo/format.ts
new file mode 100644
index 00000000..0dae2422
--- /dev/null
+++ b/react-ui/src/components/BasicInfo/format.ts
@@ -0,0 +1,48 @@
+/*
+ * @Author: 赵伟
+ * @Date: 2024-11-29 09:27:19
+ * @Description: 用于 BasicInfo 和 BasicTableInfo 组件的常用转化格式
+ */
+
+// 格式化日期
+export { formatDate } from '@/utils/date';
+
+/**
+ * 格式化字符串数组
+ * @param value - 字符串数组
+ * @returns 逗号分隔的字符串
+ */
+export const formatList = (value: string[] | null | undefined): string => {
+ if (
+ value === undefined ||
+ value === null ||
+ Array.isArray(value) === false ||
+ value.length === 0
+ ) {
+ return '--';
+ }
+ return value.join(',');
+};
+
+/**
+ * 格式化布尔值
+ * @param value - 布尔值
+ * @returns "是" 或 "否"
+ */
+export const formatBoolean = (value: boolean): string => {
+ return value ? '是' : '否';
+};
+
+type FormatEnum = (value: string | number) => string;
+
+/**
+ * 格式化枚举
+ * @param options - 枚举选项
+ * @returns 格式化枚举函数
+ */
+export const formatEnum = (options: { value: string | number; label: string }[]): FormatEnum => {
+ return (value: string | number) => {
+ const option = options.find((item) => item.value === value);
+ return option ? option.label : '--';
+ };
+};
diff --git a/react-ui/src/components/BasicInfo/index.tsx b/react-ui/src/components/BasicInfo/index.tsx
index 1fa18783..1336d0b6 100644
--- a/react-ui/src/components/BasicInfo/index.tsx
+++ b/react-ui/src/components/BasicInfo/index.tsx
@@ -1,21 +1,10 @@
-import { Link } from '@umijs/max';
-import { Typography } from 'antd';
import classNames from 'classnames';
import React from 'react';
+import { BasicInfoItem } from './components';
import './index.less';
-
-export type BasicInfoLink = {
- value: string;
- link?: string;
- url?: string;
-};
-
-export type BasicInfoData = {
- label: string;
- value?: any;
- ellipsis?: boolean;
- format?: (_value?: any) => string | BasicInfoLink | BasicInfoLink[] | undefined;
-};
+import type { BasicInfoData, BasicInfoLink } from './types';
+export * from './format';
+export type { BasicInfoData, BasicInfoLink };
type BasicInfoProps = {
datas: BasicInfoData[];
@@ -24,20 +13,6 @@ type BasicInfoProps = {
labelWidth: number;
};
-type BasicInfoItemProps = {
- data: BasicInfoData;
- labelWidth: number;
- classPrefix: string;
-};
-
-type BasicInfoItemValueProps = {
- ellipsis?: boolean;
- classPrefix: string;
- value: string | React.ReactNode;
- link?: string;
- url?: string;
-};
-
export default function BasicInfo({ datas, className, style, labelWidth }: BasicInfoProps) {
return (
@@ -52,92 +27,3 @@ export default function BasicInfo({ datas, className, style, labelWidth }: Basic
);
}
-
-export function BasicInfoItem({ data, labelWidth, classPrefix }: BasicInfoItemProps) {
- const { label, value, format, ellipsis } = data;
- const formatValue = format ? format(value) : value;
- const myClassName = `${classPrefix}__item`;
- let valueComponent = undefined;
- if (Array.isArray(formatValue)) {
- valueComponent = (
-
- {formatValue.map((item: BasicInfoLink) => (
-
- ))}
-
- );
- } else if (React.isValidElement(formatValue)) {
- // 这个判断必须在下面的判断之前
- valueComponent = (
-
- );
- } else if (typeof formatValue === 'object' && formatValue) {
- valueComponent = (
-
- );
- } else {
- valueComponent = (
-
- );
- }
- return (
-
-
- {label}
-
- {valueComponent}
-
- );
-}
-
-export function BasicInfoItemValue({
- value,
- link,
- url,
- ellipsis,
- classPrefix,
-}: BasicInfoItemValueProps) {
- const myClassName = `${classPrefix}__item__value`;
- let component = undefined;
- if (url && value) {
- component = (
-
- {value}
-
- );
- } else if (link && value) {
- component = (
-
- {value}
-
- );
- } else if (React.isValidElement(value)) {
- return value;
- } else {
- component = {value ?? '--'};
- }
-
- return (
-
-
- {component}
-
-
- );
-}
diff --git a/react-ui/src/components/BasicInfo/types.ts b/react-ui/src/components/BasicInfo/types.ts
new file mode 100644
index 00000000..a7c10ba0
--- /dev/null
+++ b/react-ui/src/components/BasicInfo/types.ts
@@ -0,0 +1,14 @@
+// 基础信息
+export type BasicInfoData = {
+ label: string;
+ value?: any;
+ ellipsis?: boolean;
+ format?: (_value?: any) => string | BasicInfoLink | BasicInfoLink[] | undefined;
+};
+
+// 值为链接的类型
+export type BasicInfoLink = {
+ value: string;
+ link?: string;
+ url?: string;
+};
diff --git a/react-ui/src/components/BasicTableInfo/index.tsx b/react-ui/src/components/BasicTableInfo/index.tsx
index df167ae2..104bc2bb 100644
--- a/react-ui/src/components/BasicTableInfo/index.tsx
+++ b/react-ui/src/components/BasicTableInfo/index.tsx
@@ -1,6 +1,8 @@
import classNames from 'classnames';
-import { BasicInfoItem, type BasicInfoData, type BasicInfoLink } from '../BasicInfo';
+import { BasicInfoItem } from '../BasicInfo/components';
+import { type BasicInfoData, type BasicInfoLink } from '../BasicInfo/types';
import './index.less';
+export * from '../BasicInfo/format';
export type { BasicInfoData, BasicInfoLink };
type BasicTableInfoProps = {
diff --git a/react-ui/src/enums/index.ts b/react-ui/src/enums/index.ts
index 05e14b34..26359678 100644
--- a/react-ui/src/enums/index.ts
+++ b/react-ui/src/enums/index.ts
@@ -92,19 +92,29 @@ export enum AutoMLTaskType {
Regression = 'regression',
}
+export const autoMLTaskTypeOptions = [
+ { label: '分类', value: AutoMLTaskType.Classification },
+ { label: '回归', value: AutoMLTaskType.Regression },
+];
+
// 自动化任务集成策略
export enum AutoMLEnsembleClass {
Default = 'default',
SingleBest = 'SingleBest',
}
+export const autoMLEnsembleClassOptions = [
+ { label: '集成模型', value: AutoMLEnsembleClass.Default },
+ { label: '单一最佳模型', value: AutoMLEnsembleClass.SingleBest },
+];
+
// 自动化任务重采样策略
export enum AutoMLResamplingStrategy {
Holdout = 'holdout',
CrossValid = 'crossValid',
}
-export const resamplingStrategyOptions = [
+export const autoMLResamplingStrategyOptions = [
{ label: 'holdout', value: AutoMLResamplingStrategy.Holdout },
{ label: 'crossValid', value: AutoMLResamplingStrategy.CrossValid },
];
diff --git a/react-ui/src/pages/AutoML/Create/index.less b/react-ui/src/pages/AutoML/Create/index.less
index 7c88312e..f8d15d2e 100644
--- a/react-ui/src/pages/AutoML/Create/index.less
+++ b/react-ui/src/pages/AutoML/Create/index.less
@@ -1,4 +1,4 @@
-.create-service-version {
+.create-automl {
height: 100%;
&__content {
diff --git a/react-ui/src/pages/AutoML/Create/index.tsx b/react-ui/src/pages/AutoML/Create/index.tsx
index 26e1866c..4d4d70d3 100644
--- a/react-ui/src/pages/AutoML/Create/index.tsx
+++ b/react-ui/src/pages/AutoML/Create/index.tsx
@@ -5,9 +5,9 @@
*/
import PageTitle from '@/components/PageTitle';
-import { AutoMLTaskType } from '@/enums';
-import { addAutoMLReq, getDatasetInfoReq, updateAutoMLReq } from '@/services/autoML';
-import { parseJsonText, trimCharacter } from '@/utils';
+import { AutoMLEnsembleClass, AutoMLTaskType } from '@/enums';
+import { addAutoMLReq, getAutoMLInfoReq, updateAutoMLReq } from '@/services/autoML';
+import { convertEmptyStringToUndefined, parseJsonText, trimCharacter } from '@/utils';
import { safeInvoke } from '@/utils/functional';
import { to } from '@/utils/promise';
import SessionStorage from '@/utils/sessionStorage';
@@ -49,7 +49,7 @@ function CreateAutoML() {
// 获取服务详情
const getAutoMLInfo = async (id: number, isCopy = false) => {
- const [res] = await to(getDatasetInfoReq({ id }));
+ const [res] = await to(getAutoMLInfoReq({ id }));
if (res && res.data) {
const autoMLInfo: AutoMLData = res.data;
const {
@@ -96,7 +96,7 @@ function CreateAutoML() {
}
};
- // 创建版本
+ // 创建、更新、复制实验
const createExperiment = async (formData: FormData) => {
const include_classifier = formData['include_classifier']?.join(',');
const include_feature_preprocessor = formData['include_feature_preprocessor']?.join(',');
@@ -113,12 +113,12 @@ function CreateAutoML() {
// 根据后台要求,修改表单数据
const object = {
...omit(formData),
- include_classifier,
- include_feature_preprocessor,
- include_regressor,
- exclude_classifier,
- exclude_feature_preprocessor,
- exclude_regressor,
+ include_classifier: convertEmptyStringToUndefined(include_classifier),
+ include_feature_preprocessor: convertEmptyStringToUndefined(include_feature_preprocessor),
+ include_regressor: convertEmptyStringToUndefined(include_regressor),
+ exclude_classifier: convertEmptyStringToUndefined(exclude_classifier),
+ exclude_feature_preprocessor: convertEmptyStringToUndefined(exclude_feature_preprocessor),
+ exclude_regressor: convertEmptyStringToUndefined(exclude_regressor),
metrics: metrics ? JSON.stringify(metrics) : undefined,
target_columns,
};
@@ -148,7 +148,6 @@ function CreateAutoML() {
navigate(-1);
};
- const disabled = id !== null || id !== undefined;
let buttonText = '新建';
let title = '新增实验';
if (id) {
@@ -157,26 +156,28 @@ function CreateAutoML() {
}
return (
-