/** * System Settings Management Page */ import { useState, useEffect } from 'react'; import { Modal, Form, Input, InputNumber, Switch, Select, Button, Card, Descriptions, Badge, Space, Popconfirm, Alert, Divider } from 'antd'; import { ReloadOutlined, ClearOutlined, WarningOutlined } from '@ant-design/icons'; import type { ColumnsType } from 'antd/es/table'; import { DataTable } from '../../components/admin/DataTable'; import { request } from '../../utils/request'; import { useToast } from '../../contexts/ToastContext'; interface SystemSetting { id: number; key: string; value: any; raw_value: string; value_type: 'string' | 'int' | 'float' | 'bool' | 'json'; category: string; label: string; description?: string; is_public: boolean; created_at?: string; updated_at?: string; } const CATEGORY_MAP: Record = { visualization: '可视化', cache: '缓存', ui: '界面', api: 'API', general: '常规', }; export function SystemSettings() { const [loading, setLoading] = useState(false); const [data, setData] = useState([]); const [filteredData, setFilteredData] = useState([]); const [isModalOpen, setIsModalOpen] = useState(false); const [editingRecord, setEditingRecord] = useState(null); const [form] = Form.useForm(); const [clearingCache, setClearingCache] = useState(false); const toast = useToast(); useEffect(() => { loadData(); }, []); const loadData = async () => { setLoading(true); try { const { data: result } = await request.get('/system/settings'); setData(result.settings || []); setFilteredData(result.settings || []); } catch (error) { toast.error('加载数据失败'); } finally { setLoading(false); } }; // Search handler const handleSearch = (keyword: string) => { const lowerKeyword = keyword.toLowerCase(); const filtered = data.filter( (item) => item.key.toLowerCase().includes(lowerKeyword) || item.label?.toLowerCase().includes(lowerKeyword) || item.category?.toLowerCase().includes(lowerKeyword) ); setFilteredData(filtered); }; // Add handler const handleAdd = () => { setEditingRecord(null); form.resetFields(); form.setFieldsValue({ value_type: 'string', category: 'general', is_public: false }); setIsModalOpen(true); }; // Edit handler const handleEdit = (record: SystemSetting) => { setEditingRecord(record); form.setFieldsValue({ key: record.key, value: record.value, value_type: record.value_type, category: record.category, label: record.label, description: record.description, is_public: record.is_public, }); setIsModalOpen(true); }; // Delete handler const handleDelete = async (record: SystemSetting) => { try { await request.delete(`/system/settings/${record.key}`); toast.success('删除成功'); loadData(); } catch (error) { toast.error('删除失败'); } }; // Form submit const handleModalOk = async () => { try { const values = await form.validateFields(); if (editingRecord) { // Update await request.put(`/system/settings/${editingRecord.key}`, values); toast.success('更新成功'); } else { // Create await request.post('/system/settings', values); toast.success('创建成功'); } setIsModalOpen(false); loadData(); } catch (error) { console.error(error); } }; // Clear all caches const handleClearCache = async () => { setClearingCache(true); try { const { data } = await request.post('/system/cache/clear'); toast.success( <>
{data.message}
位置缓存: {data.redis_cache.positions_keys} 个键 | NASA缓存: {data.redis_cache.nasa_keys} 个键
, 5 ); loadData(); } catch (error) { toast.error('清除缓存失败'); } finally { setClearingCache(false); } }; const columns: ColumnsType = [ { title: '参数键', dataIndex: 'key', key: 'key', width: 220, fixed: 'left', render: (key: string, record) => (
{key}
{record.is_public && ( )}
), }, { title: '名称', dataIndex: 'label', key: 'label', width: 180, }, { title: '当前值', dataIndex: 'value', key: 'value', width: 150, render: (value: any, record) => { if (record.value_type === 'bool') { return ; } return {String(value)}; }, }, { title: '类型', dataIndex: 'value_type', key: 'value_type', width: 90, filters: [ { text: '字符串', value: 'string' }, { text: '整数', value: 'int' }, { text: '浮点数', value: 'float' }, { text: '布尔值', value: 'bool' }, { text: 'JSON', value: 'json' }, ], onFilter: (value, record) => record.value_type === value, render: (type: string) => { const typeMap: Record = { string: '字符串', int: '整数', float: '浮点数', bool: '布尔值', json: 'JSON', }; return typeMap[type] || type; }, }, { title: '分类', dataIndex: 'category', key: 'category', width: 100, filters: Object.keys(CATEGORY_MAP).map((key) => ({ text: CATEGORY_MAP[key], value: key, })), onFilter: (value, record) => record.category === value, render: (category: string) => CATEGORY_MAP[category] || category, }, { title: '描述', dataIndex: 'description', key: 'description', ellipsis: true, }, ]; return ( <> {/* Cache Management Card */} 缓存管理 } style={{ marginBottom: 16 }} styles={{ body: { padding: 16 } }} >
  • * 位置数据缓存(当前位置和历史位置)
  • * NASA API 响应缓存
  • * 所有其他临时缓存数据
} type="warning" showIcon style={{ marginBottom: 16 }} />
{/* Settings Table */} setIsModalOpen(false)} width={700} >
prevValues.value_type !== currentValues.value_type } > {({ getFieldValue }) => { const valueType = getFieldValue('value_type'); if (valueType === 'bool') { return ( ); } else if (valueType === 'int' || valueType === 'float') { return ( ); } else { return ( ); } }}
); }