This commit is contained in:
LTbinglingfeng
2026-01-31 02:03:17 +08:00
parent e4c5f80b02
commit 3d33958d9e
6 changed files with 67 additions and 22 deletions

1
src/assets/icons/glm.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 91 KiB

View File

@@ -22,6 +22,7 @@ export function AmpcodeSection({
onEdit, onEdit,
}: AmpcodeSectionProps) { }: AmpcodeSectionProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const showLoadingPlaceholder = loading && !config;
return ( return (
<> <>
@@ -42,7 +43,7 @@ export function AmpcodeSection({
</Button> </Button>
} }
> >
{loading ? ( {showLoadingPlaceholder ? (
<div className="hint">{t('common.loading')}</div> <div className="hint">{t('common.loading')}</div>
) : ( ) : (
<> <>

View File

@@ -34,7 +34,7 @@ export function ProviderList<T>({
}: ProviderListProps<T>) { }: ProviderListProps<T>) {
const { t } = useTranslation(); const { t } = useTranslation();
if (loading) { if (loading && items.length === 0) {
return <div className="hint">{t('common.loading')}</div>; return <div className="hint">{t('common.loading')}</div>;
} }

View File

@@ -90,6 +90,18 @@
gap: $spacing-sm; gap: $spacing-sm;
} }
.groupTitle {
display: flex;
align-items: center;
gap: $spacing-sm;
}
.groupIcon {
width: 18px;
height: 18px;
flex-shrink: 0;
}
.modelTag { .modelTag {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;

View File

@@ -3,15 +3,32 @@ import { useTranslation } from 'react-i18next';
import { Card } from '@/components/ui/Card'; import { Card } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button'; import { Button } from '@/components/ui/Button';
import { IconGithub, IconBookOpen, IconExternalLink, IconCode } from '@/components/ui/icons'; import { IconGithub, IconBookOpen, IconExternalLink, IconCode } from '@/components/ui/icons';
import { useAuthStore, useConfigStore, useNotificationStore, useModelsStore } from '@/stores'; import { useAuthStore, useConfigStore, useNotificationStore, useModelsStore, useThemeStore } from '@/stores';
import { apiKeysApi } from '@/services/api/apiKeys'; import { apiKeysApi } from '@/services/api/apiKeys';
import { classifyModels } from '@/utils/models'; import { classifyModels } from '@/utils/models';
import { STORAGE_KEY_AUTH } from '@/utils/constants'; import { STORAGE_KEY_AUTH } from '@/utils/constants';
import iconGemini from '@/assets/icons/gemini.svg';
import iconClaude from '@/assets/icons/claude.svg';
import iconOpenaiLight from '@/assets/icons/openai-light.svg';
import iconOpenaiDark from '@/assets/icons/openai-dark.svg';
import iconQwen from '@/assets/icons/qwen.svg';
import iconKimi from '@/assets/icons/kimi.svg';
import iconGlm from '@/assets/icons/glm.svg';
import styles from './SystemPage.module.scss'; import styles from './SystemPage.module.scss';
const MODEL_CATEGORY_ICONS: Record<string, string | { light: string; dark: string }> = {
gpt: { light: iconOpenaiLight, dark: iconOpenaiDark },
claude: iconClaude,
gemini: iconGemini,
qwen: iconQwen,
kimi: iconKimi,
glm: iconGlm,
};
export function SystemPage() { export function SystemPage() {
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
const { showNotification, showConfirmation } = useNotificationStore(); const { showNotification, showConfirmation } = useNotificationStore();
const resolvedTheme = useThemeStore((state) => state.resolvedTheme);
const auth = useAuthStore(); const auth = useAuthStore();
const config = useConfigStore((state) => state.config); const config = useConfigStore((state) => state.config);
const fetchConfig = useConfigStore((state) => state.fetchConfig); const fetchConfig = useConfigStore((state) => state.fetchConfig);
@@ -31,6 +48,13 @@ export function SystemPage() {
); );
const groupedModels = useMemo(() => classifyModels(models, { otherLabel }), [models, otherLabel]); const groupedModels = useMemo(() => classifyModels(models, { otherLabel }), [models, otherLabel]);
const getIconForCategory = (categoryId: string): string | null => {
const iconEntry = MODEL_CATEGORY_ICONS[categoryId];
if (!iconEntry) return null;
if (typeof iconEntry === 'string') return iconEntry;
return resolvedTheme === 'dark' ? iconEntry.dark : iconEntry.light;
};
const normalizeApiKeyList = (input: any): string[] => { const normalizeApiKeyList = (input: any): string[] => {
if (!Array.isArray(input)) return []; if (!Array.isArray(input)) return [];
const seen = new Set<string>(); const seen = new Set<string>();
@@ -242,10 +266,15 @@ export function SystemPage() {
<div className="hint">{t('system_info.models_empty')}</div> <div className="hint">{t('system_info.models_empty')}</div>
) : ( ) : (
<div className="item-list"> <div className="item-list">
{groupedModels.map((group) => ( {groupedModels.map((group) => {
const iconSrc = getIconForCategory(group.id);
return (
<div key={group.id} className="item-row"> <div key={group.id} className="item-row">
<div className="item-meta"> <div className="item-meta">
<div className="item-title">{group.label}</div> <div className={styles.groupTitle}>
{iconSrc && <img src={iconSrc} alt="" className={styles.groupIcon} />}
<span className="item-title">{group.label}</span>
</div>
<div className="item-subtitle">{t('system_info.models_count', { count: group.items.length })}</div> <div className="item-subtitle">{t('system_info.models_count', { count: group.items.length })}</div>
</div> </div>
<div className={styles.modelTags}> <div className={styles.modelTags}>
@@ -261,7 +290,8 @@ export function SystemPage() {
))} ))}
</div> </div>
</div> </div>
))} );
})}
</div> </div>
)} )}
</Card> </Card>