diff --git a/react-ui/src/components/FormInfo/index.tsx b/react-ui/src/components/FormInfo/index.tsx index c1e23cbe..d33d615a 100644 --- a/react-ui/src/components/FormInfo/index.tsx +++ b/react-ui/src/components/FormInfo/index.tsx @@ -1,5 +1,5 @@ import { formatEnum } from '@/utils/format'; -import { Typography } from 'antd'; +import { Typography, type SelectProps } from 'antd'; import classNames from 'classnames'; import './index.less'; @@ -13,7 +13,9 @@ type FormInfoProps = { /** 是否是下拉框 */ select?: boolean; /** 下拉框数据 */ - options?: { label: string; value: any }[]; + options?: SelectProps['options']; + /** 自定义节点 label、value 的字段 */ + fieldNames?: SelectProps['fieldNames']; /** 自定义类名 */ className?: string; /** 自定义样式 */ @@ -26,17 +28,29 @@ type FormInfoProps = { function FormInfo({ value, valuePropName, - className, - select, + textArea = false, + select = false, options, + fieldNames, + className, style, - textArea = false, }: FormInfoProps) { let showValue = value; if (value && typeof value === 'object' && valuePropName) { showValue = value[valuePropName]; } else if (select === true && options) { - showValue = formatEnum(options)(value); + let _options: SelectProps['options'] = options; + if (fieldNames) { + _options = options.map((v) => { + return { + ...v, + label: fieldNames.label && v[fieldNames.label], + value: fieldNames.value && v[fieldNames.value], + options: fieldNames.options && v[fieldNames.options], + }; + }); + } + showValue = formatEnum(_options)(value); } return ( diff --git a/react-ui/src/components/ParameterSelect/index.tsx b/react-ui/src/components/ParameterSelect/index.tsx index a6a911e5..9b6389d8 100644 --- a/react-ui/src/components/ParameterSelect/index.tsx +++ b/react-ui/src/components/ParameterSelect/index.tsx @@ -7,43 +7,50 @@ import { to } from '@/utils/promise'; import { Select, type SelectProps } from 'antd'; import { useEffect, useState } from 'react'; +import FormInfo from '../FormInfo'; import { paramSelectConfig } from './config'; -/** 值类型 */ -export type ParameterSelectValue = { - /** 类型,参数名是和后台保持一致的 */ - item_type: 'dataset' | 'model' | 'service' | 'resource'; - /** 值 */ - value?: any; - /** 占位符 */ - placeholder?: string; - /** 其它属性 */ +type ParameterSelectObject = { + value: any; [key: string]: any; }; interface ParameterSelectProps extends SelectProps { + /** 类型 */ + dataType: 'dataset' | 'model' | 'service' | 'resource'; + /** 是否只是展示信息 */ + isInfo?: boolean; /** 值 */ - value?: ParameterSelectValue; + value?: string | ParameterSelectObject; /** 修改后回调 */ - onChange?: (value: ParameterSelectValue) => void; + onChange?: (value: string | ParameterSelectObject) => void; } /** 参数选择器,支持资源规格、数据集、模型、服务 */ -function ParameterSelect({ value, onChange, ...rest }: ParameterSelectProps) { +function ParameterSelect({ + dataType, + isInfo = false, + value, + onChange, + ...rest +}: ParameterSelectProps) { const [options, setOptions] = useState([]); - const valueNotNullable = value ?? ({} as ParameterSelectValue); - const { item_type } = valueNotNullable; - const propsConfig = paramSelectConfig[item_type]; + const propsConfig = paramSelectConfig[dataType]; + const valueText = typeof value === 'object' && value !== null ? value.value : value; useEffect(() => { getSelectOptions(); }, []); - const hangleChange = (e: string) => { - onChange?.({ - ...valueNotNullable, - value: e, - }); + const handleChange = (text: string) => { + if (typeof value === 'object' && value !== null) { + onChange?.({ + ...value, + value: text, + }); + } else { + onChange?.(text); + } }; // 获取下拉数据 @@ -58,16 +65,26 @@ function ParameterSelect({ value, onChange, ...rest }: ParameterSelectProps) { } }; + if (isInfo) { + return ( + + ); + } + return ( - + {controlStrategyList.map((item) => ( @@ -146,7 +146,9 @@ function ExperimentParameter({ nodeData }: ExperimentParameterProps) { rules={[{ required: item.value.require ? true : false }]} > {item.value.type === 'select' ? ( - + ['dataset', 'model', 'service', 'resource'].includes(item.value.item_type) ? ( + + ) : null ) : ( )} diff --git a/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx b/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx index de041c72..6314ea76 100644 --- a/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx +++ b/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx @@ -502,7 +502,7 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete label={getLabel(item, 'control_strategy')} rules={getFormRules(item)} > - + ))} {/* 输入参数 */} @@ -523,9 +523,18 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete
{item.value.type === 'select' ? ( - + ['dataset', 'model', 'service', 'resource'].includes(item.value.item_type) ? ( + + ) : null ) : ( - + )} {item.value.type === 'ref' && ( @@ -563,7 +572,7 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete label={getLabel(item, 'out_parameters')} rules={getFormRules(item)} > - + ))} diff --git a/react-ui/src/stories/FormInfo.stories.tsx b/react-ui/src/stories/FormInfo.stories.tsx index a214abae..abdf7b5e 100644 --- a/react-ui/src/stories/FormInfo.stories.tsx +++ b/react-ui/src/stories/FormInfo.stories.tsx @@ -38,7 +38,7 @@ export const InForm: Story = {
+ + + diff --git a/react-ui/src/stories/ParameterSelect.stories.tsx b/react-ui/src/stories/ParameterSelect.stories.tsx index 6aed4e31..924ab423 100644 --- a/react-ui/src/stories/ParameterSelect.stories.tsx +++ b/react-ui/src/stories/ParameterSelect.stories.tsx @@ -2,7 +2,7 @@ import ParameterSelect, { ParameterSelectValue } from '@/components/ParameterSel import { useArgs } from '@storybook/preview-api'; import type { Meta, StoryObj } from '@storybook/react'; import { fn } from '@storybook/test'; -import { Col, Form, Row } from 'antd'; +import { Button, Col, Form, Row } from 'antd'; import { http, HttpResponse } from 'msw'; import { computeResourceData, datasetListData, modelListData, serviceListData } from './mockData'; @@ -46,12 +46,32 @@ type Story = StoryObj; // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args export const Primary: Story = { args: { - value: { - item_type: 'dataset', - placeholder: '请选择数据集', - }, + placeholder: '请选择', + dataType: 'dataset', + style: { width: 400 }, + size: 'large', + }, + render: function Render(args) { + const [{ value }, updateArgs] = useArgs(); + function handleChange(value?: ParameterSelectValue) { + updateArgs({ value: value }); + args.onChange?.(value); + } + + return ; + }, +}; + +/** 值可以是一个对象,典型的是流水线节点对象 **PipelineNodeModelParameter** */ +export const Object: Story = { + args: { + placeholder: '请选择', + dataType: 'dataset', style: { width: 400 }, size: 'large', + value: { + value: undefined, + }, }, render: function Render(args) { const [{ value }, updateArgs] = useArgs(); @@ -65,6 +85,9 @@ export const Primary: Story = { }; export const InForm: Story = { + args: { + dataType: 'dataset', + }, render: ({ onChange }) => { return ( { + console.log('onFinish', values); + }} autoComplete="off" initialValues={{ dataset: { + type: 'select', item_type: 'dataset', placeholder: '请选择数据集', + label: '数据集', }, model: { + type: 'select', item_type: 'model', placeholder: '请选择模型', + label: '模型', }, service: { + type: 'select', item_type: 'service', placeholder: '请选择服务', + label: '服务', }, resource: { + type: 'select', item_type: 'resource', placeholder: '请选择计算资源', + label: '计算资源', }, + test: '1234', }} > - + - + - + - + + + + ); }, diff --git a/react-ui/src/utils/format.ts b/react-ui/src/utils/format.ts index 40d46fdc..7d37fbf5 100644 --- a/react-ui/src/utils/format.ts +++ b/react-ui/src/utils/format.ts @@ -122,14 +122,14 @@ export const formatBoolean = (value: boolean): string => { return value ? '是' : '否'; }; -type FormatEnumFunc = (value: string | number) => string; +type FormatEnumFunc = (value: string | number) => React.ReactNode; // 格式化枚举 export const formatEnum = ( - options: { value: string | number; label: string }[], + options: { value?: string | number | null; label?: React.ReactNode }[], ): FormatEnumFunc => { return (value: string | number) => { const option = options.find((item) => item.value === value); - return option ? option.label : '--'; + return option && option.label ? option.label : '--'; }; };