mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-18 02:30:51 +08:00
feat(AiProviders): improve layout and styling for OpenAI edit and models pages
This commit is contained in:
@@ -511,9 +511,9 @@ export function AiProvidersOpenAIEditPage() {
|
||||
>
|
||||
<Card>
|
||||
{invalidIndexParam || invalidIndex ? (
|
||||
<div className="hint">{t('common.invalid_provider_index')}</div>
|
||||
<div className={styles.sectionHint}>{t('common.invalid_provider_index')}</div>
|
||||
) : (
|
||||
<>
|
||||
<div className={styles.openaiEditForm}>
|
||||
<Input
|
||||
label={t('ai_providers.openai_add_modal_name_label')}
|
||||
value={form.name}
|
||||
@@ -579,7 +579,7 @@ export function AiProvidersOpenAIEditPage() {
|
||||
</div>
|
||||
|
||||
{/* 提示文本 */}
|
||||
<div className="hint">{t('ai_providers.openai_models_hint')}</div>
|
||||
<div className={styles.sectionHint}>{t('ai_providers.openai_models_hint')}</div>
|
||||
|
||||
{/* 模型列表 */}
|
||||
<ModelInputList
|
||||
@@ -649,14 +649,14 @@ export function AiProvidersOpenAIEditPage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={`form-group ${styles.keyEntriesSection}`}>
|
||||
<div className={styles.keyEntriesSection}>
|
||||
<div className={styles.keyEntriesHeader}>
|
||||
<label>{t('ai_providers.openai_add_modal_keys_label')}</label>
|
||||
<label className={styles.keyEntriesTitle}>{t('ai_providers.openai_add_modal_keys_label')}</label>
|
||||
<span className={styles.keyEntriesHint}>{t('ai_providers.openai_keys_hint')}</span>
|
||||
</div>
|
||||
{renderKeyEntries(form.apiKeyEntries)}
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
</SecondaryScreenShell>
|
||||
|
||||
@@ -153,70 +153,76 @@ export function AiProvidersOpenAIModelsPage() {
|
||||
loadingLabel={t('common.loading')}
|
||||
>
|
||||
<Card>
|
||||
<div className="hint" style={{ marginBottom: 8 }}>
|
||||
{t('ai_providers.openai_models_fetch_hint')}
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>{t('ai_providers.openai_models_fetch_url_label')}</label>
|
||||
<div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
|
||||
<input className="input" readOnly value={endpoint} />
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={() => void fetchOpenaiModelDiscovery({ allowFallback: true })}
|
||||
loading={fetching}
|
||||
disabled={disableControls || saving}
|
||||
>
|
||||
{t('ai_providers.openai_models_fetch_refresh')}
|
||||
</Button>
|
||||
<div className={styles.openaiModelsContent}>
|
||||
<div className={styles.sectionHint}>{t('ai_providers.openai_models_fetch_hint')}</div>
|
||||
<div className={styles.openaiModelsEndpointSection}>
|
||||
<label className={styles.openaiModelsEndpointLabel}>
|
||||
{t('ai_providers.openai_models_fetch_url_label')}
|
||||
</label>
|
||||
<div className={styles.openaiModelsEndpointControls}>
|
||||
<input
|
||||
className={`input ${styles.openaiModelsEndpointInput}`}
|
||||
readOnly
|
||||
value={endpoint}
|
||||
/>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={() => void fetchOpenaiModelDiscovery({ allowFallback: true })}
|
||||
loading={fetching}
|
||||
disabled={disableControls || saving}
|
||||
>
|
||||
{t('ai_providers.openai_models_fetch_refresh')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Input
|
||||
label={t('ai_providers.openai_models_search_label')}
|
||||
placeholder={t('ai_providers.openai_models_search_placeholder')}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
disabled={fetching}
|
||||
/>
|
||||
{error && <div className="error-box">{error}</div>}
|
||||
{fetching ? (
|
||||
<div className="hint">{t('ai_providers.openai_models_fetch_loading')}</div>
|
||||
) : models.length === 0 ? (
|
||||
<div className="hint">{t('ai_providers.openai_models_fetch_empty')}</div>
|
||||
) : filteredModels.length === 0 ? (
|
||||
<div className="hint">{t('ai_providers.openai_models_search_empty')}</div>
|
||||
) : (
|
||||
<div className={styles.modelDiscoveryList}>
|
||||
{filteredModels.map((model) => {
|
||||
const checked = selected.has(model.name);
|
||||
return (
|
||||
<label
|
||||
key={model.name}
|
||||
className={`${styles.modelDiscoveryRow} ${
|
||||
checked ? styles.modelDiscoveryRowSelected : ''
|
||||
}`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={checked}
|
||||
onChange={() => toggleSelection(model.name)}
|
||||
/>
|
||||
<div className={styles.modelDiscoveryMeta}>
|
||||
<div className={styles.modelDiscoveryName}>
|
||||
{model.name}
|
||||
{model.alias && (
|
||||
<span className={styles.modelDiscoveryAlias}>{model.alias}</span>
|
||||
<Input
|
||||
label={t('ai_providers.openai_models_search_label')}
|
||||
placeholder={t('ai_providers.openai_models_search_placeholder')}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
disabled={fetching}
|
||||
/>
|
||||
{error && <div className="error-box">{error}</div>}
|
||||
{fetching ? (
|
||||
<div className={styles.sectionHint}>{t('ai_providers.openai_models_fetch_loading')}</div>
|
||||
) : models.length === 0 ? (
|
||||
<div className={styles.sectionHint}>{t('ai_providers.openai_models_fetch_empty')}</div>
|
||||
) : filteredModels.length === 0 ? (
|
||||
<div className={styles.sectionHint}>{t('ai_providers.openai_models_search_empty')}</div>
|
||||
) : (
|
||||
<div className={styles.modelDiscoveryList}>
|
||||
{filteredModels.map((model) => {
|
||||
const checked = selected.has(model.name);
|
||||
return (
|
||||
<label
|
||||
key={model.name}
|
||||
className={`${styles.modelDiscoveryRow} ${
|
||||
checked ? styles.modelDiscoveryRowSelected : ''
|
||||
}`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={checked}
|
||||
onChange={() => toggleSelection(model.name)}
|
||||
/>
|
||||
<div className={styles.modelDiscoveryMeta}>
|
||||
<div className={styles.modelDiscoveryName}>
|
||||
{model.name}
|
||||
{model.alias && (
|
||||
<span className={styles.modelDiscoveryAlias}>{model.alias}</span>
|
||||
)}
|
||||
</div>
|
||||
{model.description && (
|
||||
<div className={styles.modelDiscoveryDesc}>{model.description}</div>
|
||||
)}
|
||||
</div>
|
||||
{model.description && (
|
||||
<div className={styles.modelDiscoveryDesc}>{model.description}</div>
|
||||
)}
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</label>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
</SecondaryScreenShell>
|
||||
);
|
||||
|
||||
@@ -322,7 +322,7 @@
|
||||
gap: 6px;
|
||||
max-height: 360px;
|
||||
overflow-y: auto;
|
||||
margin-top: 8px;
|
||||
margin-top: 0;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
@@ -561,11 +561,72 @@
|
||||
// Model Config Section - Unified Layout
|
||||
// ============================================
|
||||
|
||||
.modelConfigSection {
|
||||
margin-bottom: $spacing-md;
|
||||
.openaiEditForm {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-md;
|
||||
|
||||
:global(.form-group) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
:global(.status-badge) {
|
||||
margin-bottom: 0;
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.sectionHint {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.openaiModelsContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-md;
|
||||
|
||||
:global(.form-group) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.openaiModelsEndpointSection {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-xs;
|
||||
}
|
||||
|
||||
.openaiModelsEndpointLabel {
|
||||
display: block;
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.openaiModelsEndpointControls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $spacing-sm;
|
||||
|
||||
@include mobile {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
|
||||
.openaiModelsEndpointInput {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.modelConfigSection {
|
||||
margin-bottom: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-md;
|
||||
}
|
||||
|
||||
.modelConfigHeader {
|
||||
@@ -581,10 +642,11 @@
|
||||
}
|
||||
|
||||
.modelConfigTitle {
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.modelConfigToolbar {
|
||||
@@ -646,7 +708,7 @@
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: $spacing-md;
|
||||
margin-top: $spacing-sm;
|
||||
margin-top: 0;
|
||||
padding: $spacing-sm $spacing-md;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: $radius-md;
|
||||
@@ -661,7 +723,7 @@
|
||||
.modelTestMeta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
@@ -669,13 +731,13 @@
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.4;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.modelTestHint {
|
||||
font-size: 12px;
|
||||
color: var(--text-tertiary);
|
||||
line-height: 1.4;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.modelTestControls {
|
||||
@@ -697,22 +759,29 @@
|
||||
|
||||
.keyEntriesSection {
|
||||
margin-bottom: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-sm;
|
||||
}
|
||||
|
||||
.keyEntriesHeader {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
margin-bottom: $spacing-sm;
|
||||
gap: 6px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
margin: 0;
|
||||
}
|
||||
.keyEntriesTitle {
|
||||
display: block;
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.keyEntriesHint {
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
line-height: 1.5;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user