From dcdd8b403188346b6ec5e182129fb616bd77a93f Mon Sep 17 00:00:00 2001 From: 1600822305 <1600822305@qq.com> Date: Thu, 10 Apr 2025 13:36:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=90=9C=E7=B4=A2=E5=88=87=E6=8D=A2=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/Popups/SelectModelPopup.tsx | 124 +++++++++++++++--- 1 file changed, 103 insertions(+), 21 deletions(-) diff --git a/src/renderer/src/components/Popups/SelectModelPopup.tsx b/src/renderer/src/components/Popups/SelectModelPopup.tsx index e9d3adcd10..5b2e0a7886 100644 --- a/src/renderer/src/components/Popups/SelectModelPopup.tsx +++ b/src/renderer/src/components/Popups/SelectModelPopup.tsx @@ -4,7 +4,7 @@ import { getModelLogo, isEmbeddingModel, isRerankModel } from '@renderer/config/ import db from '@renderer/databases' import { useProviders } from '@renderer/hooks/useProvider' import { getModelUniqId } from '@renderer/services/ModelService' -import { Model } from '@renderer/types' +import { Model, Provider } from '@renderer/types' import { Avatar, Divider, Empty, Input, InputRef, Menu, MenuProps, Modal } from 'antd' import { first, sortBy } from 'lodash' import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react' @@ -35,6 +35,7 @@ const PopupContainer: React.FC = ({ model, resolve }) => { const scrollContainerRef = useRef(null) const [keyboardSelectedId, setKeyboardSelectedId] = useState('') const menuItemRefs = useRef>({}) + const [selectedProvider, setSelectedProvider] = useState('all') const setMenuItemRef = useCallback( (key: string) => (el: HTMLElement | null) => { @@ -360,13 +361,48 @@ const PopupContainer: React.FC = ({ model, resolve }) => { const selectedKeys = keyboardSelectedId ? [keyboardSelectedId] : model ? [getModelUniqId(model)] : [] + // 创建左侧提供商列表 + const providerItems = [ + { key: 'all', label: t('models.all') || '全部' }, + ...(pinnedModels.length > 0 ? [{ key: 'pinned', label: t('models.pinned') || '已固定' }] : []), + ...providers.map(p => ({ + key: p.id, + label: p.isSystem ? t(`provider.${p.id}`) || p.name : p.name, + icon: {first(p.name)} + })) + ]; + + // 根据选中的提供商筛选模型 + const getFilteredModelsByProvider = useCallback(() => { + if (searchText.trim()) { + // 搜索模式下显示所有匹配的模型 + return processedItems; + } + + if (selectedProvider === 'all') { + // 显示所有模型 + return processedItems; + } else if (selectedProvider === 'pinned') { + // 只显示固定的模型 + const pinnedGroup = processedItems.find(item => item && 'key' in item && item.key === 'pinned'); + return pinnedGroup ? [pinnedGroup] : []; + } else { + // 显示选中提供商的模型 + const providerGroup = processedItems.find(item => item && 'key' in item && item.key === selectedProvider); + return providerGroup ? [providerGroup] : []; + } + }, [selectedProvider, processedItems, searchText]); + + // 获取要显示的模型列表 + const displayedItems = getFilteredModelsByProvider(); + return ( = ({ model, resolve }) => { /> - - - {processedItems.length > 0 ? ( - { - setKeyboardSelectedId(key as string) - }} + + + + setSelectedProvider(key as string)} /> - ) : ( - - - - )} - - + + + + + + {displayedItems.length > 0 ? ( + { + setKeyboardSelectedId(key as string) + }} + /> + ) : ( + + + + )} + + + + ) } @@ -431,11 +480,44 @@ const Container = styled.div` margin-top: 10px; ` +const SplitContainer = styled.div` + display: flex; + flex-direction: row; + height: 50vh; +` + +const LeftPanel = styled.div` + width: 200px; + border-right: 1px solid var(--color-border); + overflow-y: auto; +` + +const RightPanel = styled.div` + flex: 1; + overflow-y: auto; +` + +const ProviderMenu = styled(Menu)` + background-color: transparent; + border-inline-end: none !important; + + .ant-menu-item { + height: 40px; + line-height: 40px; + margin: 0; + border-radius: 0; + + &.ant-menu-item-selected { + background-color: var(--color-background-mute) !important; + color: var(--color-text-primary) !important; + } + } +` + const StyledMenu = styled(Menu)` background-color: transparent; padding: 5px; margin-top: -10px; - max-height: calc(60vh - 50px); .ant-menu-item-group-title { position: sticky;