From ae224649f33bc3e8892e731b7921210ea509fa83 Mon Sep 17 00:00:00 2001 From: smail Date: Wed, 9 Sep 2026 01:46:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=96=E6=B6=88=E7=8B=AC=E7=AB=8B=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=AE=A1=E8=AE=A1=E5=B9=B6=E5=B0=86=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E5=86=99=E5=85=A5=E8=BF=90=E8=A1=8C=E6=97=A5?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/config/database_migration_test.go | 9 +- backend/config/manager_v2.go | 16 +-- backend/config/operation_log.go | 37 ++++++ backend/controllers/logs.go | 2 +- backend/listen/http_server/http_server.go | 25 +--- backend/res_init/init.go | 9 -- .../services/dbmigration/portable_executor.go | 10 +- backend/services/logstore/audit.go | 33 +----- backend/services/logstore/store.go | 3 + docs/日志改造任务.md | 10 ++ .../ConfigMaintenance/ConfigMaintenance.js | 3 +- .../ConfigMaintenance/ConfigMaintenance.vue | 34 +----- .../ConfigSettings/ConfigNavigation.js | 3 +- .../ConfigSettings/ConfigSettings.css | 47 +------- .../ConfigSettings/ConfigSettings.js | 71 +---------- .../components/LogSettings/LogSettings.js | 6 +- .../components/LogSettings/LogSettings.vue | 12 +- test/backend/config_runtime_log_test.go | 110 ++++++++++++++++++ test/backend/log_store_test.go | 42 +++++-- test/backend/logs_api_test.go | 2 +- test/backend/operation_log_test.go | 18 +++ test/frontend/config-navigation.test.mjs | 5 +- test/frontend/config-settings.test.mjs | 89 ++++++-------- test/frontend/logs.test.mjs | 7 ++ test/run.mjs | 1 + 25 files changed, 291 insertions(+), 313 deletions(-) create mode 100644 backend/config/operation_log.go create mode 100644 test/backend/config_runtime_log_test.go diff --git a/backend/config/database_migration_test.go b/backend/config/database_migration_test.go index 38e3e01..3b0ed8b 100644 --- a/backend/config/database_migration_test.go +++ b/backend/config/database_migration_test.go @@ -12,7 +12,8 @@ import ( func TestConfigManagerSwitchDatabaseCommitsSQLiteReference(t *testing.T) { root := t.TempDir() writeRuntimeFixture(t, root, validRuntimeConfig()) - manager, err := NewConfigManager(root, ConfigLoaderOptions{Validation: RuntimeValidationOptions{HasSuperAdmin: true, Production: true}}) + audit := &MemoryAuditWriter{} + manager, err := NewConfigManagerWithSecurity(root, ConfigLoaderOptions{Validation: RuntimeValidationOptions{HasSuperAdmin: true, Production: true}}, ConfigSecurity{Audit: audit}) if err != nil { t.Fatal(err) } @@ -29,7 +30,6 @@ func TestConfigManagerSwitchDatabaseCommitsSQLiteReference(t *testing.T) { if len(status.PendingRestart) != 1 || status.PendingRestart[0] != ServiceDatabase { t.Fatalf("pending restart services = %+v", status.PendingRestart) } - audit := manager.security.Audit.(*FileAuditWriter) events, err := audit.Query(context.Background(), ConfigAuditQuery{Operation: ConfigOperationMigration, Limit: 10}) if err != nil { t.Fatal(err) @@ -45,7 +45,8 @@ func TestConfigManagerSwitchAcrossTypesPersistsAndRedactsAudit(t *testing.T) { root := t.TempDir() writeRuntimeFixture(t, root, validRuntimeConfig()) options := ConfigLoaderOptions{Validation: RuntimeValidationOptions{HasSuperAdmin: true, Production: true}} - manager, err := NewConfigManager(root, options) + audit := &MemoryAuditWriter{} + manager, err := NewConfigManagerWithSecurity(root, options, ConfigSecurity{Audit: audit}) if err != nil { t.Fatal(err) } @@ -64,7 +65,7 @@ func TestConfigManagerSwitchAcrossTypesPersistsAndRedactsAudit(t *testing.T) { if got := reloaded.Snapshot(); got.Generation != 2 || got.Root.Database != target { t.Fatal("target configuration was not persisted") } - events, err := manager.security.Audit.(*FileAuditWriter).Query(context.Background(), ConfigAuditQuery{Operation: ConfigOperationMigration, Limit: 10}) + events, err := audit.Query(context.Background(), ConfigAuditQuery{Operation: ConfigOperationMigration, Limit: 10}) if err != nil || len(events) != 1 { t.Fatal("migration audit missing") } diff --git a/backend/config/manager_v2.go b/backend/config/manager_v2.go index ebcda20..e21a35d 100644 --- a/backend/config/manager_v2.go +++ b/backend/config/manager_v2.go @@ -135,15 +135,7 @@ type ConfigManager struct { } func NewConfigManager(root string, options ConfigLoaderOptions) (*ConfigManager, error) { - audit, err := NewFileAuditWriter(root) - if err != nil { - return nil, err - } - return newConfigManager(root, options, ConfigSecurity{ - Authorize: DefaultConfigAuthorization, - Confirm: DefaultConfigConfirmation, - Audit: audit, - }) + return NewConfigManagerWithSecurity(root, options, ConfigSecurity{}) } func NewConfigManagerWithSecurity(root string, options ConfigLoaderOptions, security ConfigSecurity) (*ConfigManager, error) { @@ -154,11 +146,7 @@ func NewConfigManagerWithSecurity(root string, options ConfigLoaderOptions, secu security.Confirm = DefaultConfigConfirmation } if security.Audit == nil { - audit, err := NewFileAuditWriter(root) - if err != nil { - return nil, err - } - security.Audit = audit + security.Audit = RuntimeConfigLogWriter{} } return newConfigManager(root, options, security) } diff --git a/backend/config/operation_log.go b/backend/config/operation_log.go new file mode 100644 index 0000000..4376fe5 --- /dev/null +++ b/backend/config/operation_log.go @@ -0,0 +1,37 @@ +package config + +import ( + "context" + + log "github.com/sirupsen/logrus" +) + +// RuntimeConfigLogWriter 复用运行日志记录配置结果,不生成独立审计文件或数据库记录。 +// 只保留定位操作需要的元数据,不输出配置值、凭据、用户名称或完整变更载荷。 +type RuntimeConfigLogWriter struct{} + +func (RuntimeConfigLogWriter) WriteConfigAudit(_ context.Context, event ConfigAuditEvent) error { + event, err := normalizeAuditEvent(event) + if err != nil { + return err + } + action := map[ConfigOperation]string{ + ConfigOperationUpdate: "保存配置", + ConfigOperationRollback: "回滚配置", + ConfigOperationMigration: "迁移配置", + }[event.Operation] + entry := log.WithFields(log.Fields{ + "operation": event.Operation, + "section": event.Section, + "actorId": event.ActorID, + "fromGeneration": event.FromGeneration, + "toGeneration": event.ToGeneration, + "result": event.Result, + }) + if event.Result == "failure" { + entry.Warn(action + "失败") + } else { + entry.Info(action + "成功") + } + return nil +} diff --git a/backend/controllers/logs.go b/backend/controllers/logs.go index ec79d76..da0a583 100644 --- a/backend/controllers/logs.go +++ b/backend/controllers/logs.go @@ -94,7 +94,7 @@ func GetLogs(ctx *appcontext.Context, w http.ResponseWriter, req *http.Request) response.NewSuccessResponse(page).FPrint(w) return } - if query.Kind != "config" && query.Kind != "operation" && query.Kind != "mail" { + if query.Kind != "operation" && query.Kind != "mail" { writeConfigError(w, config.ErrInvalidAuditQuery) return } diff --git a/backend/listen/http_server/http_server.go b/backend/listen/http_server/http_server.go index 7807a89..20b0ea0 100644 --- a/backend/listen/http_server/http_server.go +++ b/backend/listen/http_server/http_server.go @@ -223,31 +223,12 @@ func configSectionRoute(path, operation string) bool { } func configAuditRoute(ctx *context.Context, w http.ResponseWriter, r *http.Request) { controllers.EnsureConfigRequestID(w, r) - switch r.Method { - case http.MethodGet: - controllers.ConfigAuditQuery(ctx, w, r) - case http.MethodPost: - controllers.ExportConfigAudit(ctx, w, r) - default: - allowRouteMethod(w, r, http.MethodGet, http.MethodPost) - } + w.Header().Set("Cache-Control", "no-store") + http.Error(w, "独立配置审计已停用,请查看运行日志", http.StatusGone) } func configAuditSubRoute(ctx *context.Context, w http.ResponseWriter, r *http.Request) { - controllers.EnsureConfigRequestID(w, r) - path := strings.TrimSuffix(r.URL.Path, "/") - switch path { - case "/api/v1/audits/config/export": - if !allowRouteMethod(w, r, http.MethodPost) { - return - } - controllers.ExportConfigAuditFormal(ctx, w, r) - default: - if !allowRouteMethod(w, r, http.MethodGet) { - return - } - controllers.GetConfigAuditDetail(ctx, w, r) - } + configAuditRoute(ctx, w, r) } func databaseMigrationSubRoute(ctx *context.Context, w http.ResponseWriter, r *http.Request) { diff --git a/backend/res_init/init.go b/backend/res_init/init.go index 4eb99d9..2e005ac 100644 --- a/backend/res_init/init.go +++ b/backend/res_init/init.go @@ -76,15 +76,6 @@ func startConfigManager() error { return nil } security := config.ConfigSecurity{} - if store := logstore.Current(); store != nil { - audit := &logstore.AuditWriter{Store: store} - importCtx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - if err := audit.ImportLegacy(importCtx, config.ROOT_PATH); err != nil { - return fmt.Errorf("迁移旧配置审计失败,源文件已保留: %w", err) - } - security.Audit = audit - } manager, err := config.NewConfigManagerWithSecurity(config.ROOT_PATH, config.ConfigLoaderOptions{Validation: config.RuntimeValidationOptions{ HasSuperAdmin: true, Production: !config.DevelopmentMode, diff --git a/backend/services/dbmigration/portable_executor.go b/backend/services/dbmigration/portable_executor.go index 6745971..6435623 100644 --- a/backend/services/dbmigration/portable_executor.go +++ b/backend/services/dbmigration/portable_executor.go @@ -12,7 +12,6 @@ import ( "git.pcux.cn/xuans/Smail/config" "git.pcux.cn/xuans/Smail/db/migration" - "git.pcux.cn/xuans/Smail/services/logstore" ) // PortableExecutor 使用版本化目标结构复制业务数据,不拼接用户提供的 SQL。 @@ -221,13 +220,8 @@ func (e *PortableExecutor) Run(ctx context.Context, plan Plan, update func(Statu if err := update(StatusSwitching); err != nil { return err } - // 源库此时仍持有写锁,切换审计必须写入已复制且校验完成的目标库。 - logStore, err := logstore.New(target, dialect) - if err != nil { - return err - } - switchContext := config.WithMigrationAuditWriter(ctx, &logstore.AuditWriter{Store: logStore}) - err = e.switchConfig(switchContext, plan.expectedGeneration, plan.targetConfig, plan.actor) + // 配置切换结果只写运行日志,不再依赖源库或目标库保存独立审计。 + err = e.switchConfig(ctx, plan.expectedGeneration, plan.targetConfig, plan.actor) if err != nil && isKnownSwitchRejection(err) { return err } diff --git a/backend/services/logstore/audit.go b/backend/services/logstore/audit.go index 417413c..d1be454 100644 --- a/backend/services/logstore/audit.go +++ b/backend/services/logstore/audit.go @@ -5,28 +5,13 @@ import ( "encoding/json" "git.pcux.cn/xuans/Smail/config" - "git.pcux.cn/xuans/Smail/utils/logpolicy" ) type AuditWriter struct{ Store *Store } func (w *AuditWriter) WriteConfigAudit(ctx context.Context, event config.ConfigAuditEvent) error { - if w == nil || w.Store == nil { - return ErrUnavailable - } - normalized, err := config.NormalizeConfigAuditEvent(event) - if err != nil { - return err - } - payload, err := json.Marshal(normalized) - if err != nil { - return err - } - return w.Store.Write(ctx, Entry{ - ID: normalized.ID, CreatedAt: normalized.CreatedAt, Kind: "config", - ActorID: normalized.ActorID, Action: string(normalized.Operation), - Section: string(normalized.Section), Result: normalized.Result, Payload: payload, - }) + // 旧调用方也转到运行日志,避免再次接入数据库审计。 + return (config.RuntimeConfigLogWriter{}).WriteConfigAudit(ctx, event) } func (w *AuditWriter) Query(ctx context.Context, query config.ConfigAuditQuery) ([]config.ConfigAuditEvent, error) { @@ -70,15 +55,7 @@ func (w *AuditWriter) ExportCSV(ctx context.Context, query config.ConfigAuditQue return config.ExportConfigAuditCSV(items) } -func (w *AuditWriter) ImportLegacy(ctx context.Context, root string) error { - if w == nil || w.Store == nil { - return ErrUnavailable - } - legacy, err := config.NewFileAuditWriter(root) - if err != nil { - return err - } - return legacy.Visit(ctx, logpolicy.Cutoff(w.Store.now()), func(event config.ConfigAuditEvent) error { - return w.WriteConfigAudit(ctx, event) - }) +func (w *AuditWriter) ImportLegacy(_ context.Context, _ string) error { + // 独立配置审计已停用,历史文件留在原处,不再导入数据库或重复输出。 + return nil } diff --git a/backend/services/logstore/store.go b/backend/services/logstore/store.go index 7bd6240..0b5a558 100644 --- a/backend/services/logstore/store.go +++ b/backend/services/logstore/store.go @@ -92,6 +92,9 @@ func replacePlaceholders(statement string, index *int) string { // Write 只接受业务点构造的脱敏载荷,禁止直接传入 HTTP 请求或邮件正文。 func (s *Store) Write(ctx context.Context, entry Entry) error { + if entry.Kind == "config" { + return ErrInvalid + } if s == nil || s.db == nil { return ErrUnavailable } diff --git a/docs/日志改造任务.md b/docs/日志改造任务.md index fc47c06..3f7e53d 100644 --- a/docs/日志改造任务.md +++ b/docs/日志改造任务.md @@ -1,5 +1,15 @@ # 日志存储与可视化改造 +## 2026-09-09 取消独立配置审计 + +- [✓] 需求确认:取消配置审计分类、维护菜单及查询导出;配置修改仅在现有运行日志文件记录简短结果,操作记录与收发信存储方式不变。 +- [✓] 修改前检查点 `42a173f` 已提交并推送;不删除历史审计文件或清空数据库。 +- [✓] 默认配置管理器改用运行日志,停止数据库审计写入与历史审计导入;旧审计接口返回已停用,不再返回记录或下载文件。 +- [✓] 配置保存、回滚、迁移仍使用原有事务、备份、权限与二次验证;运行日志不写配置前后值、密钥、密码或用户名称。跨数据库迁移不再创建目标库审计写入器,保留复制校验和源库写锁。 +- [✓] 全量回归 `test-log/run-2026-09-08T17-37-37-092Z-35572`:前端 152 项、部署 4 项及后端全包通过。并发检测 `test-log/run-2026-09-08T17-42-33-063Z-34044`:配置、数据库日志、数据库迁移、HTTP 和运行日志包通过。 +- [~] 完整编译部署,浏览器 MCP 验证三个日志分类、配置维护菜单和停用接口。 +- [ ] 更新 `yunx-test` 并记录最终提交、运行版本与验证结果。 + ## 2026-09-09 倒序查询与写入前过滤 - [✓] 需求确认:四类日志统一倒序、每页十条、支持起止时间,默认最近二十四小时;翻页固定查询时段。 diff --git a/frontend/src/views/components/ConfigSettings/ConfigMaintenance/ConfigMaintenance.js b/frontend/src/views/components/ConfigSettings/ConfigMaintenance/ConfigMaintenance.js index c1bcb57..6183b51 100644 --- a/frontend/src/views/components/ConfigSettings/ConfigMaintenance/ConfigMaintenance.js +++ b/frontend/src/views/components/ConfigSettings/ConfigMaintenance/ConfigMaintenance.js @@ -9,7 +9,6 @@ export function useMaintenance(pageKey) { page.rollbackPreview.value = null page.rollbackConfirmed.value = false } - const auditPagination = usePagination(page.auditItems, 6) const backupPagination = usePagination(page.backups, 6) - return { ...page, selectBackup, auditPagination, backupPagination } + return { ...page, selectBackup, backupPagination } } diff --git a/frontend/src/views/components/ConfigSettings/ConfigMaintenance/ConfigMaintenance.vue b/frontend/src/views/components/ConfigSettings/ConfigMaintenance/ConfigMaintenance.vue index a61b4ba..285a2a7 100644 --- a/frontend/src/views/components/ConfigSettings/ConfigMaintenance/ConfigMaintenance.vue +++ b/frontend/src/views/components/ConfigSettings/ConfigMaintenance/ConfigMaintenance.vue @@ -149,36 +149,6 @@ -
-
-
-

展示最近 50 条,导出最多 500 条记录。

-
- 查询 - 导出 JSON - 导出 CSV -
-
- -
-
-
- {{ operationLabel(item.operation) }} - {{ sectionLabel(item.section) }} · {{ item.actorName || item.actorId || '系统' }} -
- {{ item.changes.length }} 个字段变更 -

- {{ change.field }}:{{ change.before }} → {{ change.after }} -

-
-
- -
-
- - -
-
@@ -201,10 +171,8 @@ const { canRestart, serviceLabel, restartPreview, previewRestart, requestRestart, canRollback, backupsLoading, backupsError, backups, rollbackGeneration, rollbackConfirmed, rollbackPreview, loadBackups, selectBackup, previewRollback, executeRollback, - canAudit, canExportAudit, auditLoading, auditError, auditItems, loadAudit, exportAudit, - formatTime, sectionLabel, operationLabel, auditPagination, backupPagination + formatTime, sectionLabel, backupPagination } = useMaintenance(props.pageKey) -const { currentPage: auditPage, pageCount: auditPageCount, pageItems: auditRows } = auditPagination const { currentPage: backupPage, pageCount: backupPageCount, pageItems: backupRows } = backupPagination defineExpose({ beforeLeave }) diff --git a/frontend/src/views/components/ConfigSettings/ConfigNavigation.js b/frontend/src/views/components/ConfigSettings/ConfigNavigation.js index 360ca47..b1d20ad 100644 --- a/frontend/src/views/components/ConfigSettings/ConfigNavigation.js +++ b/frontend/src/views/components/ConfigSettings/ConfigNavigation.js @@ -19,8 +19,7 @@ export function useNavigation() { const tools = [ { value: 'migration', label: '数据库迁移', capability: 'database.migrate' }, { value: 'restart', label: '服务重启', capability: 'service.restart' }, - { value: 'backups', label: '备份与回滚', capability: 'config.rollback' }, - { value: 'audit', label: '配置审计', capability: 'audit.read' } + { value: 'backups', label: '备份与回滚', capability: 'config.rollback' } ] const sectionOptions = computed(() => store.hasCapability('config.read') ? pages : []) const maintenanceOptions = computed(() => store.hasCapability('config.read') diff --git a/frontend/src/views/components/ConfigSettings/ConfigSettings.css b/frontend/src/views/components/ConfigSettings/ConfigSettings.css index f4f66f4..128a538 100644 --- a/frontend/src/views/components/ConfigSettings/ConfigSettings.css +++ b/frontend/src/views/components/ConfigSettings/ConfigSettings.css @@ -177,20 +177,15 @@ .confirmation-check :deep(.el-checkbox__input) { margin-top: 3px; } -.action-row, -.audit-actions { +.action-row { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px; } -.action-row > .el-button, -.audit-actions > .el-button { +.action-row > .el-button { margin-left: 0; } -.audit-actions { - margin-top: 0; -} .maintenance-heading { display: flex; align-items: baseline; @@ -315,37 +310,6 @@ margin: 0; padding-left: 18px; } -.audit-list { - display: grid; - gap: 10px; - margin-top: 18px; -} -.audit-item { - display: flex; - align-items: center; - justify-content: space-between; - gap: 16px; - padding: 8px 12px; - border-radius: var(--pm-radius-sm); - background: var(--pm-bg-primary); -} -.audit-item div { - display: grid; - gap: 4px; - min-width: 0; - overflow-wrap: anywhere; -} -.audit-item strong { - color: var(--pm-text-primary); -} -.audit-item span, -.audit-item time { - color: var(--pm-text-secondary); - font-size: 13px; -} -.audit-item time { - flex: none; -} @container config-main (max-width: 620px) { .secret-editor { grid-template-columns: minmax(0, 1fr); @@ -362,12 +326,7 @@ .maintenance-summary { flex-wrap: wrap; } - .audit-item { - align-items: stretch; - flex-direction: column; - } - .action-row .el-button, - .audit-actions .el-button { + .action-row .el-button { flex: 1; min-width: 110px; } diff --git a/frontend/src/views/components/ConfigSettings/ConfigSettings.js b/frontend/src/views/components/ConfigSettings/ConfigSettings.js index d6a73e8..99922c0 100644 --- a/frontend/src/views/components/ConfigSettings/ConfigSettings.js +++ b/frontend/src/views/components/ConfigSettings/ConfigSettings.js @@ -26,14 +26,6 @@ const serviceLabels = { } const sectionLabels = Object.fromEntries(sections.map(item => [item.value, item.label])) -const operationLabels = { - validate: '验证配置', - update: '保存配置', - apply: '应用配置', - rollback_preview: '预览回滚', - rollback_ticket: '签发回滚票据', - rollback: '执行回滚' -} export function usePage(pageKey = 'base') { const isConfigPage = sections.some(item => item.value === pageKey) @@ -45,9 +37,7 @@ export function usePage(pageKey = 'base') { const saveFlow = ref('') const busy = computed(() => !!working.value || !!saveFlow.value) const backupsLoading = ref(false) - const auditLoading = ref(false) const backupsError = ref('') - const auditError = ref('') const status = reactive({ setupState: '', tlsMode: '', @@ -116,7 +106,6 @@ export function usePage(pageKey = 'base') { const rollbackGeneration = ref(0) const rollbackConfirmed = ref(false) const rollbackPreview = ref(null) - const auditItems = ref([]) const databaseConfig = reactive({ type: '', name: '', localRef: '' }) const migrationTargetName = ref('') const migrationTarget = reactive({ type: 'sqlite', host: '127.0.0.1', port: 3306, username: '', password: '' }) @@ -161,8 +150,6 @@ export function usePage(pageKey = 'base') { const canWrite = computed(() => globalStatus.hasCapability('config.write_global')) const canRollback = computed(() => globalStatus.hasCapability('config.rollback')) - const canAudit = computed(() => globalStatus.hasCapability('audit.read')) - const canExportAudit = computed(() => globalStatus.hasCapability('audit.export')) const canMigrate = computed(() => globalStatus.hasCapability('database.migrate')) const canRestart = computed(() => globalStatus.hasCapability('service.restart')) const stateLabel = computed(() => ({ new: '未初始化', bootstrap: '初始化中', ready: '就绪', degraded: '降级' }[status.setupState] || status.setupState || '未知')) @@ -208,7 +195,6 @@ export function usePage(pageKey = 'base') { const formatTime = value => value ? new Date(value).toLocaleString('zh-CN', { hour12: false }) : '-' const serviceLabel = value => serviceLabels[value] || value const sectionLabel = value => sectionLabels[value] || value || '-' - const operationLabel = value => operationLabels[value] || value || '-' const migrationStatusLabels = { previewed: '已生成预览', created: '已创建', @@ -346,22 +332,6 @@ export function usePage(pageKey = 'base') { } } - const loadAudit = async () => { - if (!canAudit.value) return - auditLoading.value = true - auditError.value = '' - try { - const response = await http.get('/api/v1/audits/config?limit=50') - notifyResponseError(response, '配置审计读取失败') - auditItems.value = Array.isArray(response.data) ? response.data : [] - } catch (error) { - auditItems.value = [] - auditError.value = error.message || '配置审计读取失败' - } finally { - auditLoading.value = false - } - } - const previewDatabaseMigration = async () => { if (!canMigrate.value || working.value || sectionError.value || !migrationReady.value) return working.value = 'migration-preview' @@ -499,7 +469,6 @@ export function usePage(pageKey = 'base') { if (isConfigPage || (pageKey === 'migration' && canMigrate.value)) await loadSection() if (isConfigPage) await loadPending() if (pageKey === 'backups') await loadBackups() - if (pageKey === 'audit') await loadAudit() } catch (error) { availabilityError.value = error.message || '配置管理数据读取失败' } finally { @@ -723,38 +692,6 @@ export function usePage(pageKey = 'base') { } } - const exportAudit = async format => { - if (!canExportAudit.value || working.value) return - working.value = format === 'csv' ? 'export-csv' : 'export' - try { - const response = await requestWithRecentAuthentication(() => http.post( - '/api/v1/audits/config', { format, limit: 500 }, { responseType: 'blob' } - )) - if (!(response instanceof Blob)) { - throw new Error(response?.errorMsg || '审计导出响应格式不正确') - } - // Blob 请求也可能返回 JSON 业务错误,不能把错误响应当作审计文件下载。 - if (response.type.includes('json') || format === 'json') { - const payload = JSON.parse(await response.text()) - if (payload && !Array.isArray(payload) && Object.hasOwn(payload, 'errorNo') && payload.errorNo !== 0) { - throw new Error(payload.errorMsg || '审计导出失败') - } - } - const blob = response - const url = URL.createObjectURL(blob) - const anchor = document.createElement('a') - anchor.href = url - anchor.download = `smail-config-audit.${format}` - anchor.click() - URL.revokeObjectURL(url) - ElMessage.success('审计记录已导出') - } catch (error) { - if (!isRecentAuthenticationCancelled(error)) ElMessage.error(error.message || '审计导出失败') - } finally { - working.value = '' - } - } - const beforeLeave = async () => { if (busy.value) { ElMessage.warning('当前操作尚未完成,请稍后再切换页面') @@ -795,11 +732,11 @@ export function usePage(pageKey = 'base') { loading, availabilityError, working, status, stateLabel, stateTagType, sectionOptions: sections, selectedSection, currentSection, sectionLoading, editorText, formConfig, formErrors, updateField, updateSecret, sectionError, saveError, sensitiveHint, secretField, secretValue, - confirmed, savedGeneration, pendingCandidate, managePending, validationResult, canWrite, canRollback, canAudit, canExportAudit, + confirmed, savedGeneration, pendingCandidate, managePending, validationResult, canWrite, canRollback, backupsLoading, backupsError, backups, rollbackGeneration, rollbackConfirmed, rollbackPreview, - auditLoading, auditError, auditItems, loadAll, loadSection, validateConfig, saveConfig, applyConfig, saveAndApply, continuePending, - loadBackups, previewRollback, executeRollback, loadAudit, exportAudit, formatTime, - serviceLabel, sectionLabel, operationLabel, databaseConfig, databaseTypeLabel, canMigrate, + loadAll, loadSection, validateConfig, saveConfig, applyConfig, saveAndApply, continuePending, + loadBackups, previewRollback, executeRollback, formatTime, + serviceLabel, sectionLabel, databaseConfig, databaseTypeLabel, canMigrate, migrationTargetName, migrationPreview, migrationToken, migrationRecord, migrationStatusLabel, migrationStatusType, migrationTarget, migrationReady, migrationError, invalidateMigration, changeMigrationType, previewDatabaseMigration, loadMigrationStatus, executeDatabaseMigration, canRestart, restartPreview, diff --git a/frontend/src/views/components/LogSettings/LogSettings.js b/frontend/src/views/components/LogSettings/LogSettings.js index 31365e0..9485d83 100644 --- a/frontend/src/views/components/LogSettings/LogSettings.js +++ b/frontend/src/views/components/LogSettings/LogSettings.js @@ -3,7 +3,7 @@ import { http } from '@/utils/axios' import { parseRuntimeLine, summarizeRuntime, timeParts } from './RuntimeLog.js' export function useLogs() { - const category = ref('config') + const category = ref('operation') const loading = ref(false) const error = ref('') const items = ref([]) @@ -25,7 +25,6 @@ export function useLogs() { let appliedFilters = {} const categories = [ - { label: '配置审计', value: 'config' }, { label: '操作记录', value: 'operation' }, { label: '收发信记录', value: 'mail' }, { label: '运行日志', value: 'runtime' } @@ -36,7 +35,6 @@ export function useLogs() { const actionLabel = value => ({ update: '保存配置', rollback: '回滚配置', migration: '迁移配置' }[value] || value) const displayActor = item => item.payload?.actorName || (item.actorId && item.actorId !== '0' ? item.actorId : '系统') const details = computed(() => detail.value?.payload || {}) - const changes = computed(() => details.value.changes || []) const runtimeRows = computed(() => lines.value.map((line, index) => parseRuntimeLine(line, offset.value + index + 1))) const runtimeSummary = computed(() => summarizeRuntime(runtimeRows.value)) const visibleCount = computed(() => isRuntime.value ? lines.value.length : items.value.length) @@ -125,7 +123,7 @@ export function useLogs() { return { category, categories, loading, error, items, lines, offset, - hasMore, actorId, dateRange, detail, details, changes, isRuntime, + hasMore, actorId, dateRange, detail, details, isRuntime, runtimeDetail, runtimeRows, runtimeSummary, visibleCount, pageRange, currentCategory, resultType, runtimeRowClass, timeParts, formatTime, resultLabel, actionLabel, displayActor, search, recent, next, previous diff --git a/frontend/src/views/components/LogSettings/LogSettings.vue b/frontend/src/views/components/LogSettings/LogSettings.vue index 48fb33d..54f8a90 100644 --- a/frontend/src/views/components/LogSettings/LogSettings.vue +++ b/frontend/src/views/components/LogSettings/LogSettings.vue @@ -129,15 +129,7 @@