From a5483cf37f584d142586a3e68a31b9838ea45776 Mon Sep 17 00:00:00 2001 From: WangDL Date: Fri, 22 May 2026 22:37:28 +0800 Subject: [PATCH] feat: M0-03 config management admin page --- src/App.tsx | 4 ++ src/config/menu.tsx | 1 + src/layouts/AdminLayout.tsx | 1 + src/pages/Config.tsx | 89 +++++++++++++++++++++++++++++++++++++ src/services/config-api.ts | 12 +++++ 5 files changed, 107 insertions(+) create mode 100644 src/pages/Config.tsx create mode 100644 src/services/config-api.ts diff --git a/src/App.tsx b/src/App.tsx index 341b4d8..8030d7c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -100,6 +100,10 @@ function App() { }> } /> + }>} + /> }>} diff --git a/src/config/menu.tsx b/src/config/menu.tsx index 9c69e07..1903989 100644 --- a/src/config/menu.tsx +++ b/src/config/menu.tsx @@ -30,6 +30,7 @@ export const adminMenuItems: AdminMenuItem[] = [ { path: '/billing', name: 'API 用量', icon: , requiredRole: 'SUPER_ADMIN' }, { path: '/git', name: '代码仓库', icon: }, { path: '/ops', name: '系统运维', icon: , requiredRole: 'SUPER_ADMIN', children: [ + { path: '/config', name: '配置管理' }, { path: '/servers', name: '服务器' }, { path: '/events', name: '事件队列' }, ]}, diff --git a/src/layouts/AdminLayout.tsx b/src/layouts/AdminLayout.tsx index ab0c3b5..045b247 100644 --- a/src/layouts/AdminLayout.tsx +++ b/src/layouts/AdminLayout.tsx @@ -24,6 +24,7 @@ const breadcrumbMap: Record = { '/billing': 'API 用量', '/git': '代码仓库', '/servers': '服务器运维', + '/config': '配置管理', '/events': '事件队列', '/audit': '审计日志', } diff --git a/src/pages/Config.tsx b/src/pages/Config.tsx new file mode 100644 index 0000000..2e5f0ec --- /dev/null +++ b/src/pages/Config.tsx @@ -0,0 +1,89 @@ +import { useState } from 'react' +import { useQuery, useQueryClient } from '@tanstack/react-query' +import { Table, Switch, Button, Typography, App, Modal, Input, Tabs, Space } from 'antd' +import { ReloadOutlined, PlusOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons' +import { getConfig, setConfig, updateConfig, deleteConfig, toggleFlag, getChangeLog } from '@/services/config-api' +import dayjs from 'dayjs' + +const { Title, Text } = Typography + +function ConfigPage() { + const { modal, message } = App.useApp() + const qc = useQueryClient() + const [addOpen, setAddOpen] = useState(false) + const [editKey, setEditKey] = useState('') + const [newKey, setNewKey] = useState('') + const [newValue, setNewValue] = useState('') + + const { data } = useQuery({ queryKey: ['config'], queryFn: getConfig, staleTime: 30_000 }) + const { data: changelog } = useQuery({ queryKey: ['config', 'changelog'], queryFn: getChangeLog, staleTime: 10_000 }) + + const handleSave = async () => { + if (editKey) { await updateConfig(editKey, newValue); message.success('已更新') } + else { await setConfig(newKey, newValue); message.success('已添加') } + setAddOpen(false); setEditKey(''); setNewKey(''); setNewValue('') + qc.invalidateQueries({ queryKey: ['config'] }) + } + + const handleDelete = (key: string) => modal.confirm({ + title: '删除配置', content: `确定删除 ${key}?`, okType: 'danger', + onOk: async () => { await deleteConfig(key); qc.invalidateQueries({ queryKey: ['config'] }) }, + }) + + const configColumns = [ + { title: 'Key', dataIndex: 'key', width: 180, ellipsis: true }, + { title: 'Value', dataIndex: 'value', width: 300, ellipsis: true, render: (v: string) => {v} }, + { title: '环境', dataIndex: 'environment', width: 80 }, + { title: '更新', dataIndex: 'updatedAt', width: 140, render: (d: string) => dayjs(d).format('MM-DD HH:mm') }, + { title: '操作', width: 100, render: (_: any, r: any) => ( + +