/* * @Author: ZhaoYing * @Date: 2026-02-03 16:49:20 * @Last Modified by: ZhaoYing * @Last Modified time: 2026-02-03 16:54:54 */ /** * Sub-Model Modal * Modal for selecting models and API keys to add to group model * Uses cascader for hierarchical selection */ import { forwardRef, useImperativeHandle, useState, useEffect } from 'react'; import { Form, Cascader, App, type CascaderProps } from 'antd'; import { useTranslation } from 'react-i18next'; import type { SubModelModalForm, SubModelModalRef, SubModelModalProps } from './types'; import RbModal from '@/components/RbModal' import CustomSelect from '@/components/CustomSelect' import { modelProviderUrl, getModelNewList } from '@/api/models' import type { ProviderModelItem } from '../../types' const { SHOW_CHILD } = Cascader; /** * Cascader option interface */ interface Option { value: string | number; label: string; children?: Option[]; [key: string]: any; } /** * Sub-model modal component */ const SubModelModal = forwardRef(({ refresh, type, groupedByProvider }, ref) => { const { t } = useTranslation(); const { message } = App.useApp() const [visible, setVisible] = useState(false); const [form] = Form.useForm(); const [selecteds, setSelecteds] = useState([]) const [modelList, setModelList] = useState([]) const provider = Form.useWatch(['provider'], form) useEffect(() => { if (provider && groupedByProvider) { const lastModels = groupedByProvider[provider] || [] const list = lastModels.map(vo => [{ name: vo.model_name, id: vo.model_config_ids[0], value: vo.model_config_ids[0], provider }, { value: vo.id }]) setSelecteds(list) form.setFieldValue('api_key_ids', lastModels.map(vo => [vo.model_config_ids[0], vo.id])) } }, [groupedByProvider, provider]) /** Close modal and reset state */ const handleClose = () => { form.resetFields(); setVisible(false); setSelecteds([]) setModelList([]) }; /** Open modal */ const handleOpen = () => { form.resetFields() setVisible(true); }; /** Save selected models and API keys */ const handleSave = () => { form .validateFields() .then(() => { refresh?.(selecteds.map(vo => ({ ...vo[0], model_name: vo[0].name, model_config_ids: [vo[0].id], id: vo[1].value, api_key: vo[1].label }))) handleClose() }) } /** Handle cascader selection change */ const handleChange = (value: (string | number)[][], selectedOptions: Option[][]) => { const filterList = selectedOptions.filter(vo => vo.length === 1).map(item => item[0]) const lastFilterLit = value.filter(vo => vo.length !== 1) if (filterList.length) { message.warning(`【${filterList.map(vo => vo.label)}】${t('modelNew.selectOneTip')}`) form.setFieldValue('api_key_ids', lastFilterLit) } setSelecteds(selectedOptions) } /** Handle provider change and load models */ const handleChangeProvider = (provider: string, api_key_ids?: any[]) => { form.setFieldValue('api_key_ids', undefined) if (provider) { getModelNewList({ provider: provider, is_composite: false, is_active: true, type }) .then(res => { const response = res as ProviderModelItem[] const list = response[0]?.models || [] setModelList(list.map(vo => { const children = vo.api_keys.map(item => ({ label: item.api_key, value: item.id, })) return { ...vo, label: vo.name, value: vo.id, children: children } })) if (api_key_ids?.length) { form.setFieldsValue({ api_key_ids: api_key_ids }) } }) } else { setModelList([]) } } /** Custom display renderer for cascader */ const displayRender: CascaderProps