feat(admin): add ConfigSync page + close ADMIN-01/02 (AUDIT_TRACKER)
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
- ADMIN-01 FIXED: ConfigSync.tsx page with ProTable + pagination - config-sync service calling GET /config/sync-logs - route + nav item + breadcrumb - backend @reserved → @connected - ADMIN-02 FALSE_POSITIVE: Logs.tsx + logs service already exist
This commit is contained in:
@@ -20,6 +20,7 @@ import {
|
|||||||
CrownOutlined,
|
CrownOutlined,
|
||||||
SafetyOutlined,
|
SafetyOutlined,
|
||||||
FieldTimeOutlined,
|
FieldTimeOutlined,
|
||||||
|
SyncOutlined,
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import { Avatar, Dropdown, Tooltip, Drawer } from 'antd'
|
import { Avatar, Dropdown, Tooltip, Drawer } from 'antd'
|
||||||
import { useAuthStore } from '@/stores/authStore'
|
import { useAuthStore } from '@/stores/authStore'
|
||||||
@@ -51,6 +52,7 @@ const navItems: NavItem[] = [
|
|||||||
{ path: '/knowledge', name: '知识库', icon: <BookOutlined />, permission: 'knowledge:read', group: '资源管理' },
|
{ path: '/knowledge', name: '知识库', icon: <BookOutlined />, permission: 'knowledge:read', group: '资源管理' },
|
||||||
{ path: '/billing', name: '计费管理', icon: <CrownOutlined />, permission: 'billing:read', group: '核心' },
|
{ path: '/billing', name: '计费管理', icon: <CrownOutlined />, permission: 'billing:read', group: '核心' },
|
||||||
{ path: '/logs', name: '操作日志', icon: <FileTextOutlined />, permission: 'admin:full', group: '运维' },
|
{ path: '/logs', name: '操作日志', icon: <FileTextOutlined />, permission: 'admin:full', group: '运维' },
|
||||||
|
{ path: '/config-sync', name: '同步日志', icon: <SyncOutlined />, permission: 'config:read', group: '运维' },
|
||||||
{ path: '/config', name: '系统配置', icon: <SettingOutlined />, permission: 'config:read', group: '系统' },
|
{ path: '/config', name: '系统配置', icon: <SettingOutlined />, permission: 'config:read', group: '系统' },
|
||||||
{ path: '/prompts', name: '提示词管理', icon: <MessageOutlined />, permission: 'prompt:read', group: '系统' },
|
{ path: '/prompts', name: '提示词管理', icon: <MessageOutlined />, permission: 'prompt:read', group: '系统' },
|
||||||
]
|
]
|
||||||
@@ -219,6 +221,7 @@ const breadcrumbMap: Record<string, string> = {
|
|||||||
'/config': '系统配置',
|
'/config': '系统配置',
|
||||||
'/prompts': '提示词管理',
|
'/prompts': '提示词管理',
|
||||||
'/logs': '操作日志',
|
'/logs': '操作日志',
|
||||||
|
'/config-sync': '同步日志',
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|||||||
111
admin-v2/src/pages/ConfigSync.tsx
Normal file
111
admin-v2/src/pages/ConfigSync.tsx
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
// ============================================================
|
||||||
|
// 配置同步日志
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { useQuery } from '@tanstack/react-query'
|
||||||
|
import { Tag, Typography } from 'antd'
|
||||||
|
import type { ProColumns } from '@ant-design/pro-components'
|
||||||
|
import { ProTable } from '@ant-design/pro-components'
|
||||||
|
import { configSyncService } from '@/services/config-sync'
|
||||||
|
import type { ConfigSyncLog } from '@/types'
|
||||||
|
|
||||||
|
const { Title } = Typography
|
||||||
|
|
||||||
|
const actionLabels: Record<string, string> = {
|
||||||
|
push: '推送',
|
||||||
|
merge: '合并',
|
||||||
|
pull: '拉取',
|
||||||
|
diff: '差异',
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionColors: Record<string, string> = {
|
||||||
|
push: 'blue',
|
||||||
|
merge: 'green',
|
||||||
|
pull: 'cyan',
|
||||||
|
diff: 'orange',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ConfigSync() {
|
||||||
|
const [page, setPage] = useState(1)
|
||||||
|
|
||||||
|
const { data, isLoading } = useQuery({
|
||||||
|
queryKey: ['config-sync', page],
|
||||||
|
queryFn: ({ signal }) => configSyncService.list({ page, page_size: 20 }, signal),
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns: ProColumns<ConfigSyncLog>[] = [
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
dataIndex: 'action',
|
||||||
|
width: 100,
|
||||||
|
render: (_, r) => (
|
||||||
|
<Tag color={actionColors[r.action] || 'default'}>
|
||||||
|
{actionLabels[r.action] || r.action}
|
||||||
|
</Tag>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '客户端指纹',
|
||||||
|
dataIndex: 'client_fingerprint',
|
||||||
|
width: 160,
|
||||||
|
render: (_, r) => <code>{r.client_fingerprint.substring(0, 16)}...</code>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '配置键',
|
||||||
|
dataIndex: 'config_keys',
|
||||||
|
width: 200,
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '客户端值',
|
||||||
|
dataIndex: 'client_values',
|
||||||
|
width: 150,
|
||||||
|
ellipsis: true,
|
||||||
|
render: (_, r) => r.client_values || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '服务端值',
|
||||||
|
dataIndex: 'saas_values',
|
||||||
|
width: 150,
|
||||||
|
ellipsis: true,
|
||||||
|
render: (_, r) => r.saas_values || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '解决方式',
|
||||||
|
dataIndex: 'resolution',
|
||||||
|
width: 120,
|
||||||
|
render: (_, r) => r.resolution || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '时间',
|
||||||
|
dataIndex: 'created_at',
|
||||||
|
width: 180,
|
||||||
|
render: (_, r) => new Date(r.created_at).toLocaleString('zh-CN'),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div style={{ marginBottom: 24 }}>
|
||||||
|
<Title level={4} style={{ margin: 0 }}>配置同步日志</Title>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ProTable<ConfigSyncLog>
|
||||||
|
columns={columns}
|
||||||
|
dataSource={data?.items ?? []}
|
||||||
|
loading={isLoading}
|
||||||
|
rowKey="id"
|
||||||
|
search={false}
|
||||||
|
toolBarRender={false}
|
||||||
|
pagination={{
|
||||||
|
total: data?.total ?? 0,
|
||||||
|
pageSize: 20,
|
||||||
|
current: page,
|
||||||
|
onChange: setPage,
|
||||||
|
showSizeChanger: false,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -35,6 +35,7 @@ export const router = createBrowserRouter([
|
|||||||
{ path: 'config', lazy: () => import('@/pages/Config').then((m) => ({ Component: m.default })) },
|
{ path: 'config', lazy: () => import('@/pages/Config').then((m) => ({ Component: m.default })) },
|
||||||
{ path: 'prompts', lazy: () => import('@/pages/Prompts').then((m) => ({ Component: m.default })) },
|
{ path: 'prompts', lazy: () => import('@/pages/Prompts').then((m) => ({ Component: m.default })) },
|
||||||
{ path: 'logs', lazy: () => import('@/pages/Logs').then((m) => ({ Component: m.default })) },
|
{ path: 'logs', lazy: () => import('@/pages/Logs').then((m) => ({ Component: m.default })) },
|
||||||
|
{ path: 'config-sync', lazy: () => import('@/pages/ConfigSync').then((m) => ({ Component: m.default })) },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|||||||
7
admin-v2/src/services/config-sync.ts
Normal file
7
admin-v2/src/services/config-sync.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import request, { withSignal } from './request'
|
||||||
|
import type { ConfigSyncLog, PaginatedResponse } from '@/types'
|
||||||
|
|
||||||
|
export const configSyncService = {
|
||||||
|
list: (params?: Record<string, unknown>, signal?: AbortSignal) =>
|
||||||
|
request.get<PaginatedResponse<ConfigSyncLog>>('/config/sync-logs', withSignal({ params }, signal)).then((r) => r.data),
|
||||||
|
}
|
||||||
@@ -324,3 +324,16 @@ export interface CreateTemplateRequest {
|
|||||||
description?: string
|
description?: string
|
||||||
permissions?: string[]
|
permissions?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 配置同步日志 */
|
||||||
|
export interface ConfigSyncLog {
|
||||||
|
id: number
|
||||||
|
account_id: string
|
||||||
|
client_fingerprint: string
|
||||||
|
action: string
|
||||||
|
config_keys: string
|
||||||
|
client_values: string | null
|
||||||
|
saas_values: string | null
|
||||||
|
resolution: string | null
|
||||||
|
created_at: string
|
||||||
|
}
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ pub async fn config_diff(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// GET /api/v1/config/sync-logs?page=1&page_size=20
|
/// GET /api/v1/config/sync-logs?page=1&page_size=20
|
||||||
// @reserved - no frontend caller
|
/// @connected - admin-v2 ConfigSync page
|
||||||
pub async fn list_sync_logs(
|
pub async fn list_sync_logs(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Extension(ctx): Extension<AuthContext>,
|
Extension(ctx): Extension<AuthContext>,
|
||||||
|
|||||||
@@ -43,8 +43,8 @@
|
|||||||
| SEC-V9-02 | relay 输入验证可加强 | **FALSE_POSITIVE** | relay/handlers.rs 已有完整验证(body size/model/role/content/temperature/max_tokens/queue/permission) |
|
| SEC-V9-02 | relay 输入验证可加强 | **FALSE_POSITIVE** | relay/handlers.rs 已有完整验证(body size/model/role/content/temperature/max_tokens/queue/permission) |
|
||||||
| AUDIT-01 | 前端 audit-logger 无消费者 | **FALSE_POSITIVE** | 文件已于先前清理中删除 |
|
| AUDIT-01 | 前端 audit-logger 无消费者 | **FALSE_POSITIVE** | 文件已于先前清理中删除 |
|
||||||
| DEAD-04 | director.rs 907 行孤立代码 | **FALSE_POSITIVE** | 与 V11-P3-05 相同,multi-agent feature gate 已正确隔离 |
|
| DEAD-04 | director.rs 907 行孤立代码 | **FALSE_POSITIVE** | 与 V11-P3-05 相同,multi-agent feature gate 已正确隔离 |
|
||||||
| ADMIN-01 | config_sync_logs 无 Admin 页面 | OPEN | - | - | 添加页面 |
|
| ADMIN-01 | config_sync_logs 无 Admin 页面 | **FIXED** | admin-v2 ConfigSync.tsx + config-sync service + route + nav |
|
||||||
| ADMIN-02 | operation_logs 无 Admin 页面 | OPEN | - | - | 添加页面 |
|
| ADMIN-02 | operation_logs 无 Admin 页面 | **FALSE_POSITIVE** | admin-v2 已有 Logs.tsx + logs service 完整实现 |
|
||||||
|
|
||||||
## P4: 低优先级
|
## P4: 低优先级
|
||||||
|
|
||||||
@@ -274,6 +274,8 @@
|
|||||||
| 2026-04-05 | V11-P2-05 | 部分关闭 → FIXED | 完整审计: 160 @connected + 16 @reserved + 1 未注册 = 177 总命令 |
|
| 2026-04-05 | V11-P2-05 | 部分关闭 → FIXED | 完整审计: 160 @connected + 16 @reserved + 1 未注册 = 177 总命令 |
|
||||||
| 2026-04-05 | TYPE-01 | OPEN → FIXED | ConnectionState 统一(含 handshaking); saas-types PromptTemplate/PromptVariable union literal; CreateRoleRequest optional; PropertyPanel as any→类型安全; chatStore window cast |
|
| 2026-04-05 | TYPE-01 | OPEN → FIXED | ConnectionState 统一(含 handshaking); saas-types PromptTemplate/PromptVariable union literal; CreateRoleRequest optional; PropertyPanel as any→类型安全; chatStore window cast |
|
||||||
| 2026-04-05 | AUD3-DB-01 | OPEN → FIXED | 16 个 down migration SQL + db::run_down_migrations() + migrate_down task (timestamp=20260402) |
|
| 2026-04-05 | AUD3-DB-01 | OPEN → FIXED | 16 个 down migration SQL + db::run_down_migrations() + migrate_down task (timestamp=20260402) |
|
||||||
|
| 2026-04-05 | ADMIN-01 | OPEN → FIXED | admin-v2 ConfigSync.tsx 页面 + config-sync service + route + nav + 后端 @reserved→@connected |
|
||||||
|
| 2026-04-05 | ADMIN-02 | OPEN → FALSE_POSITIVE | admin-v2 已有 Logs.tsx + logs service + route 完整实现 |
|
||||||
|
|
||||||
## V12 模块化端到端审计修复 (2026-04-04)
|
## V12 模块化端到端审计修复 (2026-04-04)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user