服务端媒体源导入/保存/客户端输出链路修复:支持 snake/camel、subcategories/sources,默认客户端可见,保存后发布兼容 media-types.json。
build-winui / winui (push) Has been cancelled

新增数据库同步 Job API、持久化状态、实时输出、最新任务恢复,以及系统日志聚合接口。
管理端优化:日志中心、运维实时状态框、同步输出自动滚动、仪表盘“输出”列、真实延迟空态、本地 favicon/avatar。
新增 server/unified-management/assets/favicon.ico 和 developer-avatar.png,并接好 /favicon.ico、/admin/favicon.ico、/setup/favicon.ico、/assets/*。
WinUI 随机放映室卡片优先显示子接口原始 Description。
Inno 安装器输出框改为选区末尾 + SendMessage 滚动到底部。
This commit is contained in:
QWQLwToo
2026-06-29 22:28:58 +08:00
parent f00124c1c0
commit 7745e7a2d4
36 changed files with 1482 additions and 153 deletions
+21 -1
View File
@@ -69,6 +69,7 @@ func Open(cfg *config.Config) (*Store, error) {
SchemaVersion: CurrentSchemaVersion,
SQLiteReady: true,
LastRecoveredAt: Now(),
LastHealthStatus: "not_configured",
},
}
if err := store.migrate(local, localDialect); err != nil {
@@ -86,6 +87,7 @@ func Open(cfg *config.Config) (*Store, error) {
store.markFailover(err)
}
}
store.restoreDatabaseSyncStatus()
go store.maintain()
return store, nil
}
@@ -171,14 +173,17 @@ func (s *Store) ReconfigureDatabase(cfg *config.Config) error {
s.status.RemoteReady = remote != nil
s.status.LastError = ""
s.status.FailoverActive = false
s.status.LastHealthCheckedAt = Now()
if remote != nil {
s.db = remote
s.dialect = remoteDialect
s.status.ActiveProvider = "mysql"
s.status.LastHealthStatus = "ok"
} else {
s.db = local
s.dialect = localDialect
s.status.ActiveProvider = "sqlite"
s.status.LastHealthStatus = "not_configured"
}
s.status.LastRecoveredAt = Now()
s.mu.Unlock()
@@ -188,6 +193,7 @@ func (s *Store) ReconfigureDatabase(cfg *config.Config) error {
if oldLocal != nil && oldLocal != local {
_ = oldLocal.Close()
}
s.restoreDatabaseSyncStatus()
return nil
}
@@ -237,7 +243,11 @@ func (s *Store) insertID(query string, args ...any) (int64, error) {
}
func (s *Store) maintain() {
ticker := time.NewTicker(time.Duration(s.cfg.Database.HealthIntervalSec) * time.Second)
interval := s.cfg.Database.HealthIntervalSec
if interval <= 0 {
interval = 60
}
ticker := time.NewTicker(time.Duration(interval) * time.Second)
defer ticker.Stop()
for {
select {
@@ -276,12 +286,18 @@ func (s *Store) openRemote() error {
s.status.FailoverActive = false
s.status.LastError = ""
s.status.LastRecoveredAt = Now()
s.status.LastHealthCheckedAt = Now()
s.status.LastHealthStatus = "ok"
s.mu.Unlock()
return nil
}
func (s *Store) checkRemote() {
if !strings.EqualFold(s.cfg.Database.Provider, "mysql") {
s.mu.Lock()
s.status.LastHealthCheckedAt = Now()
s.status.LastHealthStatus = "not_configured"
s.mu.Unlock()
return
}
s.mu.RLock()
@@ -311,6 +327,8 @@ func (s *Store) checkRemote() {
s.status.FailoverActive = false
s.status.LastError = ""
s.status.LastRecoveredAt = Now()
s.status.LastHealthCheckedAt = Now()
s.status.LastHealthStatus = "ok"
s.mu.Unlock()
}
@@ -329,4 +347,6 @@ func (s *Store) markFailover(err error) {
s.status.FailoverActive = !strings.EqualFold(s.cfg.Database.Provider, "sqlite")
s.status.LastError = err.Error()
s.status.LastFailoverAt = Now()
s.status.LastHealthCheckedAt = Now()
s.status.LastHealthStatus = "error"
}