Files
aurak/web/components/VisionModelSelector.tsx
Developer 0a9588abb7 feat: implement QuestionBank CRUD with pagination and template query
- Add pagination support to findAll (page, limit query params)
- Add findByTemplateId method to service
- Add GET /by-template/:templateId endpoint to controller
- Service already includes CRUD for QuestionBank and QuestionBankItem
2026-04-23 17:19:11 +08:00

94 lines
2.9 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { Eye } from 'lucide-react';
import { settingsService } from '../services/settingsService';
import { useLanguage } from '../contexts/LanguageContext';
interface VisionModel {
id: string;
name: string;
modelId: string;
}
interface VisionModelSelectorProps {
isAdmin?: boolean;
}
const VisionModelSelector: React.FC<VisionModelSelectorProps> = ({ isAdmin = false }) => {
const { t } = useLanguage();
const [visionModels, setVisionModels] = useState<VisionModel[]>([]);
const [selectedModelId, setSelectedModelId] = useState<string>('');
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string>('');
useEffect(() => {
loadData();
}, []);
const loadData = async () => {
try {
setLoading(true);
setError('');
const [models, current] = await Promise.all([
settingsService.getVisionModels(),
settingsService.getVisionModel()
]);
console.log('Vision models loaded:', models);
console.log('Current vision model:', current);
setVisionModels(models || []);
setSelectedModelId(current?.visionModelId || '');
} catch (error) {
console.error(t('loadVisionModelFailed'), error);
setError(t('loadFailed'));
} finally {
setLoading(false);
}
};
const handleChange = async (modelId: string) => {
try {
setSelectedModelId(modelId);
await settingsService.updateVisionModel(modelId);
} catch (error) {
console.error(t('saveVisionModelFailed'), error);
}
};
return (
<div className="bg-white p-4 rounded-xl border border-slate-200 shadow-sm">
<div className="flex items-center gap-2 mb-4 text-slate-800 font-semibold border-b border-slate-100 pb-2">
<Eye className="w-4 h-4 text-purple-600" />
{t('visionModelSettings')}
</div>
<div>
<label className="block text-xs font-medium text-slate-500 mb-1.5">
{t('defaultVisionModel')}
</label>
{error ? (
<div className="text-red-500 text-sm p-2 bg-red-50 rounded">
{error}
</div>
) : (
<select
value={selectedModelId}
onChange={(e) => handleChange(e.target.value)}
disabled={loading || !isAdmin}
className="w-full text-sm bg-slate-50 border border-slate-200 rounded-lg px-3 py-2 text-slate-700 focus:outline-none focus:border-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
>
<option value="">--- {t('selectVisionModel')} ---</option>
{visionModels.map(model => (
<option key={model.id} value={model.id}>
{model.name} ({model.modelId})
</option>
))}
</select>
)}
<p className="text-[10px] text-slate-400 mt-1">
{t('visionModelHelp')}
</p>
</div>
</div>
);
};
export default VisionModelSelector;