'use client' import { useState, useEffect } from 'react' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Textarea } from '@/components/ui/textarea' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Checkbox } from '@/components/ui/checkbox' import { Trash2, Plus } from 'lucide-react' import { authenticatedFetch } from '@/lib/auth' interface DataSourceConfigFormProps { type: 'lankong' | 'manual' | 'api_get' | 'api_post' | 'endpoint' | 's3' config: string onChange: (config: string) => void } interface LankongConfig { api_token: string album_ids: string[] base_url?: string } interface APIConfig { url: string method?: string headers: { [key: string]: string } body?: string url_field: string } interface SavedToken { id: string name: string token: string } interface EndpointConfig { endpoint_ids: number[] } interface S3Config { endpoint: string bucket_name: string region: string access_key_id: string secret_access_key: string list_objects_version: string use_path_style: boolean remove_bucket: boolean custom_domain: string folder_path: string include_subfolders: boolean file_extensions: string[] } export default function DataSourceConfigForm({ type, config, onChange }: DataSourceConfigFormProps) { const [lankongConfig, setLankongConfig] = useState({ api_token: '', album_ids: [''], base_url: '' }) const [apiConfig, setAPIConfig] = useState({ url: '', method: type === 'api_post' ? 'POST' : 'GET', headers: {}, body: '', url_field: 'url' }) const [endpointConfig, setEndpointConfig] = useState({ endpoint_ids: [] }) const [s3Config, setS3Config] = useState({ endpoint: '', bucket_name: '', region: '', access_key_id: '', secret_access_key: '', list_objects_version: 'v2', use_path_style: false, remove_bucket: false, custom_domain: '', folder_path: '', include_subfolders: true, file_extensions: [] }) const [availableEndpoints, setAvailableEndpoints] = useState>([]) const [headerPairs, setHeaderPairs] = useState>([{key: '', value: ''}]) const [extensionInputs, setExtensionInputs] = useState(['']) const [savedTokens, setSavedTokens] = useState([]) const [newTokenName, setNewTokenName] = useState('') // 从localStorage加载保存的token useEffect(() => { const saved = localStorage.getItem('lankong_tokens') if (saved) { try { setSavedTokens(JSON.parse(saved)) } catch (error) { console.error('Failed to parse saved tokens:', error) } } }, []) // 获取可用端点列表 useEffect(() => { if (type === 'endpoint') { loadAvailableEndpoints() } }, [type]) const loadAvailableEndpoints = async () => { try { const response = await authenticatedFetch('/api/admin/endpoints') if (response.ok) { const data = await response.json() setAvailableEndpoints(data.data || []) } } catch (error) { console.error('Failed to load endpoints:', error) } } // 解析现有配置 useEffect(() => { if (!config) return try { const parsed = JSON.parse(config) if (type === 'lankong') { setLankongConfig({ api_token: parsed.api_token || '', album_ids: parsed.album_ids || [''], base_url: parsed.base_url || '' }) } else if (type === 'api_get' || type === 'api_post') { setAPIConfig({ url: parsed.url || '', method: parsed.method || (type === 'api_post' ? 'POST' : 'GET'), headers: parsed.headers || {}, body: parsed.body || '', url_field: parsed.url_field || 'url' }) // 转换headers为键值对数组 const pairs = Object.entries(parsed.headers || {}).map(([key, value]) => ({key, value: value as string})) if (pairs.length === 0) pairs.push({key: '', value: ''}) setHeaderPairs(pairs) } else if (type === 'endpoint') { setEndpointConfig({ endpoint_ids: parsed.endpoint_ids || [] }) } else if (type === 's3') { setS3Config({ endpoint: parsed.endpoint || '', bucket_name: parsed.bucket_name || '', region: parsed.region || '', access_key_id: parsed.access_key_id || '', secret_access_key: parsed.secret_access_key || '', list_objects_version: parsed.list_objects_version || 'v2', use_path_style: parsed.use_path_style || false, remove_bucket: parsed.remove_bucket || false, custom_domain: parsed.custom_domain || '', folder_path: parsed.folder_path || '', include_subfolders: parsed.include_subfolders !== false, file_extensions: parsed.file_extensions || [] }) // 设置文件扩展名输入框 const extensions = parsed.file_extensions || [''] if (extensions.length === 0) extensions.push('') setExtensionInputs(extensions) } } catch (error) { console.error('Failed to parse config:', error) } }, [config, type]) // 保存token到localStorage const saveToken = () => { if (!newTokenName.trim() || !lankongConfig.api_token.trim()) { alert('请输入token名称和token值') return } const newToken: SavedToken = { id: Date.now().toString(), name: newTokenName.trim(), token: lankongConfig.api_token } const updated = [...savedTokens, newToken] setSavedTokens(updated) localStorage.setItem('lankong_tokens', JSON.stringify(updated)) setNewTokenName('') alert('Token保存成功') } // 删除保存的token const deleteToken = (tokenId: string) => { if (!confirm('确定要删除这个token吗?')) return const updated = savedTokens.filter(t => t.id !== tokenId) setSavedTokens(updated) localStorage.setItem('lankong_tokens', JSON.stringify(updated)) } // 更新兰空图床配置 const updateConfig = (newConfig: LankongConfig | APIConfig) => { onChange(JSON.stringify(newConfig)) } // 添加相册ID const addAlbumId = () => { const newConfig = { ...lankongConfig, album_ids: [...lankongConfig.album_ids, ''] } setLankongConfig(newConfig) updateConfig(newConfig) } // 删除相册ID const removeAlbumId = (index: number) => { const newConfig = { ...lankongConfig, album_ids: lankongConfig.album_ids.filter((_, i) => i !== index) } setLankongConfig(newConfig) updateConfig(newConfig) } // 更新相册ID const updateAlbumId = (index: number, value: string) => { const newConfig = { ...lankongConfig, album_ids: lankongConfig.album_ids.map((id, i) => i === index ? value : id) } setLankongConfig(newConfig) updateConfig(newConfig) } // 添加请求头 const addHeader = () => { setHeaderPairs([...headerPairs, {key: '', value: ''}]) } // 删除请求头 const removeHeader = (index: number) => { const newPairs = headerPairs.filter((_, i) => i !== index) setHeaderPairs(newPairs) updateAPIHeaders(newPairs) } // 更新请求头 const updateHeader = (index: number, field: 'key' | 'value', value: string) => { const newPairs = headerPairs.map((pair, i) => i === index ? { ...pair, [field]: value } : pair ) setHeaderPairs(newPairs) updateAPIHeaders(newPairs) } // 更新API配置的headers const updateAPIHeaders = (pairs: Array<{key: string, value: string}>) => { const headers: { [key: string]: string } = {} pairs.forEach(pair => { if (pair.key.trim() && pair.value.trim()) { headers[pair.key.trim()] = pair.value.trim() } }) const newConfig = { ...apiConfig, headers } setAPIConfig(newConfig) updateConfig(newConfig) } // 更新API配置 const updateAPIConfig = (field: keyof APIConfig, value: string) => { // 对URL字段进行trim处理,去除前后空格 const trimmedValue = field === 'url' ? value.trim() : value const newConfig = { ...apiConfig, [field]: trimmedValue } setAPIConfig(newConfig) updateConfig(newConfig) } // 更新端点配置 const updateEndpointConfig = (endpointIds: number[]) => { const newConfig = { endpoint_ids: endpointIds } setEndpointConfig(newConfig) onChange(JSON.stringify(newConfig)) } // 切换端点选择 const toggleEndpoint = (endpointId: number) => { const currentIds = endpointConfig.endpoint_ids const newIds = currentIds.includes(endpointId) ? currentIds.filter(id => id !== endpointId) : [...currentIds, endpointId] updateEndpointConfig(newIds) } // 更新S3配置 const updateS3Config = (field: keyof S3Config, value: string | boolean | string[]) => { const newConfig = { ...s3Config, [field]: value } setS3Config(newConfig) onChange(JSON.stringify(newConfig)) } // 添加文件扩展名 const addExtension = () => { const newExtensions = [...extensionInputs, ''] setExtensionInputs(newExtensions) } // 删除文件扩展名 const removeExtension = (index: number) => { const newExtensions = extensionInputs.filter((_, i) => i !== index) setExtensionInputs(newExtensions) updateS3Config('file_extensions', newExtensions.filter(ext => ext.trim() !== '')) } // 更新文件扩展名 const updateExtension = (index: number, value: string) => { const newExtensions = extensionInputs.map((ext, i) => i === index ? value : ext) setExtensionInputs(newExtensions) updateS3Config('file_extensions', newExtensions.filter(ext => ext.trim() !== '')) } if (type === 'manual') { return (