import { Component, OnInit, inject, signal, output } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import { finalize } from 'rxjs';
interface ModelSettings {
base_url: string;
model: string;
api_key_configured: boolean;
timeout_seconds: number;
max_retries: number;
env_path: string;
message?: string;
}
@Component({
selector: 'app-model-settings',
standalone: true,
imports: [FormsModule],
template: `
`,
styles: [`
.model-settings { display: grid; gap: 10px; color: #1e293b; }
p, small { margin: 0; line-height: 1.6; color: #64748b; }
label { font-weight: 600; } label span { font-weight: 400; font-size: 12px; }
input { box-sizing: border-box; width: 100%; padding: 12px; border-radius: 10px; border: 1px solid #64748b66;
background: #f8fafc; color: inherit; font: inherit; }
input:focus { outline: 2px solid #38bdf8; }
.number-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 8px; }
.number-fields input { margin-top: 8px; }
.actions { display: flex; gap: 12px; margin-top: 8px; }
button { padding: 11px 20px; border-radius: 10px; border: 1px solid #38bdf877; background: #0284c7; color: white; cursor: pointer; font: inherit; }
button:disabled { opacity: .5; cursor: default; } .success { color: #047857; } .error { color: #be123c; }
small { overflow-wrap: anywhere; } @media(max-width: 480px) { .number-fields { grid-template-columns: 1fr; } }
`]
})
export class ModelSettingsComponent implements OnInit {
private http = inject(HttpClient);
saved = output();
baseUrl = ''; model = ''; apiKey = ''; timeout = 120; retries = 0;
busy = signal<'save' | 'test' | null>(null);
loading = signal(true); keyConfigured = signal(false); envPath = signal('');
message = signal(''); error = signal('');
ngOnInit(): void {
this.http.get('/api/system/model-settings').pipe(finalize(() => this.loading.set(false))).subscribe({
next: config => this.apply(config),
error: () => this.error.set('配置加载失败,请刷新页面重试。')
});
}
valid(): boolean {
return !!this.baseUrl.trim() && !!this.model.trim() && (!!this.apiKey.trim() || this.keyConfigured())
&& this.timeout > 0 && this.timeout <= 3600 && Number.isInteger(this.retries) && this.retries >= 0 && this.retries <= 10;
}
private payload() {
return { base_url: this.baseUrl.trim(), model: this.model.trim(), api_key: this.apiKey.trim() || undefined,
timeout_seconds: this.timeout, max_retries: this.retries };
}
private apply(config: ModelSettings): void {
this.baseUrl = config.base_url; this.model = config.model; this.timeout = config.timeout_seconds;
this.retries = config.max_retries; this.keyConfigured.set(config.api_key_configured); this.envPath.set(config.env_path);
}
save(): void {
if (this.busy() || !this.valid()) return;
this.busy.set('save'); this.message.set(''); this.error.set('');
this.http.post('/api/system/model-settings', this.payload()).pipe(finalize(() => this.busy.set(null))).subscribe({
next: config => { this.apply(config); this.apiKey = ''; this.message.set(config.message || '配置已保存。'); this.saved.emit(); },
error: err => this.error.set(typeof err.error?.detail === 'string' ? err.error.detail : '保存失败,请检查配置内容。')
});
}
test(): void {
if (this.busy() || !this.valid()) return;
this.busy.set('test'); this.message.set(''); this.error.set('');
this.http.post<{ message: string }>('/api/system/model-settings/test', this.payload()).pipe(finalize(() => this.busy.set(null))).subscribe({
next: result => this.message.set(result.message),
error: err => this.error.set(typeof err.error?.detail === 'string' ? err.error.detail : '连接测试失败,请检查配置。')
});
}
}