diff --git a/admin-v2/src/layouts/AdminLayout.tsx b/admin-v2/src/layouts/AdminLayout.tsx
index 097a524..56da9c8 100644
--- a/admin-v2/src/layouts/AdminLayout.tsx
+++ b/admin-v2/src/layouts/AdminLayout.tsx
@@ -20,6 +20,7 @@ import {
CrownOutlined,
SafetyOutlined,
FieldTimeOutlined,
+ SyncOutlined,
} from '@ant-design/icons'
import { Avatar, Dropdown, Tooltip, Drawer } from 'antd'
import { useAuthStore } from '@/stores/authStore'
@@ -51,6 +52,7 @@ const navItems: NavItem[] = [
{ path: '/knowledge', name: '知识库', icon: , permission: 'knowledge:read', group: '资源管理' },
{ path: '/billing', name: '计费管理', icon: , permission: 'billing:read', group: '核心' },
{ path: '/logs', name: '操作日志', icon: , permission: 'admin:full', group: '运维' },
+ { path: '/config-sync', name: '同步日志', icon: , permission: 'config:read', group: '运维' },
{ path: '/config', name: '系统配置', icon: , permission: 'config:read', group: '系统' },
{ path: '/prompts', name: '提示词管理', icon: , permission: 'prompt:read', group: '系统' },
]
@@ -219,6 +221,7 @@ const breadcrumbMap: Record = {
'/config': '系统配置',
'/prompts': '提示词管理',
'/logs': '操作日志',
+ '/config-sync': '同步日志',
}
// ============================================================
diff --git a/admin-v2/src/pages/ConfigSync.tsx b/admin-v2/src/pages/ConfigSync.tsx
new file mode 100644
index 0000000..16d2eb8
--- /dev/null
+++ b/admin-v2/src/pages/ConfigSync.tsx
@@ -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 = {
+ push: '推送',
+ merge: '合并',
+ pull: '拉取',
+ diff: '差异',
+}
+
+const actionColors: Record = {
+ 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[] = [
+ {
+ title: '操作',
+ dataIndex: 'action',
+ width: 100,
+ render: (_, r) => (
+
+ {actionLabels[r.action] || r.action}
+
+ ),
+ },
+ {
+ title: '客户端指纹',
+ dataIndex: 'client_fingerprint',
+ width: 160,
+ render: (_, r) => {r.client_fingerprint.substring(0, 16)}...,
+ },
+ {
+ 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 (
+
+
+
配置同步日志
+
+
+
+ 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,
+ }}
+ />
+
+ )
+}
diff --git a/admin-v2/src/router/index.tsx b/admin-v2/src/router/index.tsx
index cc7bee9..9b9d10d 100644
--- a/admin-v2/src/router/index.tsx
+++ b/admin-v2/src/router/index.tsx
@@ -35,6 +35,7 @@ export const router = createBrowserRouter([
{ path: 'config', lazy: () => import('@/pages/Config').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: 'config-sync', lazy: () => import('@/pages/ConfigSync').then((m) => ({ Component: m.default })) },
],
},
])
diff --git a/admin-v2/src/services/config-sync.ts b/admin-v2/src/services/config-sync.ts
new file mode 100644
index 0000000..9738771
--- /dev/null
+++ b/admin-v2/src/services/config-sync.ts
@@ -0,0 +1,7 @@
+import request, { withSignal } from './request'
+import type { ConfigSyncLog, PaginatedResponse } from '@/types'
+
+export const configSyncService = {
+ list: (params?: Record, signal?: AbortSignal) =>
+ request.get>('/config/sync-logs', withSignal({ params }, signal)).then((r) => r.data),
+}
diff --git a/admin-v2/src/types/index.ts b/admin-v2/src/types/index.ts
index 6f6b1ac..f8dd89d 100644
--- a/admin-v2/src/types/index.ts
+++ b/admin-v2/src/types/index.ts
@@ -324,3 +324,16 @@ export interface CreateTemplateRequest {
description?: 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
+}
diff --git a/crates/zclaw-saas/src/migration/handlers.rs b/crates/zclaw-saas/src/migration/handlers.rs
index 7173cf0..3eda459 100644
--- a/crates/zclaw-saas/src/migration/handlers.rs
+++ b/crates/zclaw-saas/src/migration/handlers.rs
@@ -137,7 +137,7 @@ pub async fn config_diff(
}
/// 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(
State(state): State,
Extension(ctx): Extension,
diff --git a/docs/features/AUDIT_TRACKER.md b/docs/features/AUDIT_TRACKER.md
index bb9c6dc..b0251cb 100644
--- a/docs/features/AUDIT_TRACKER.md
+++ b/docs/features/AUDIT_TRACKER.md
@@ -43,8 +43,8 @@
| 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** | 文件已于先前清理中删除 |
| DEAD-04 | director.rs 907 行孤立代码 | **FALSE_POSITIVE** | 与 V11-P3-05 相同,multi-agent feature gate 已正确隔离 |
-| ADMIN-01 | config_sync_logs 无 Admin 页面 | OPEN | - | - | 添加页面 |
-| ADMIN-02 | operation_logs 无 Admin 页面 | OPEN | - | - | 添加页面 |
+| ADMIN-01 | config_sync_logs 无 Admin 页面 | **FIXED** | admin-v2 ConfigSync.tsx + config-sync service + route + nav |
+| ADMIN-02 | operation_logs 无 Admin 页面 | **FALSE_POSITIVE** | admin-v2 已有 Logs.tsx + logs service 完整实现 |
## P4: 低优先级
@@ -274,6 +274,8 @@
| 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 | 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)