fix(config): 统一历史记录与配置的数据库时间来源

- saveHistory 接收调用方传入的数据库时间,不再使用 time.Now()
- 更新、删除、回滚先取 dao.Now(),避免取时间失败时产生无效历史
- 历史表 created_at 升级为 datetime(3),新增迁移脚本
This commit is contained in:
2026-09-18 21:14:53 +08:00
parent 1f8cae5a8b
commit 28c727501f
4 changed files with 29 additions and 21 deletions
+22 -19
View File
@@ -278,19 +278,20 @@ func (h *ConfigHandler) Update(c *gin.Context) {
return
}
// save history
h.saveHistory(&config, userInfo.Name, "update")
originalContents := config.Contents
config.Contents = req.Contents
config.Version = req.Version
config.UpdatedBy = userInfo.Name
now, err := dao.Now()
if err != nil {
logger.SugaredLogger.Errorf("[ConfigHandler.Update] get database time error: %v", err)
c.JSON(http.StatusInternalServerError, model.WrapperResponse{Code: 500, Msg: "保存失败"})
return
}
// save history
h.saveHistory(&config, userInfo.Name, "update", now)
originalContents := config.Contents
config.Contents = req.Contents
config.Version = req.Version
config.UpdatedBy = userInfo.Name
config.UpdatedAt = &now
dao.Engine.ID(config.Id).Cols("contents", "version", "updated_by", "updated_at").Update(&config)
@@ -316,17 +317,18 @@ func (h *ConfigHandler) Delete(c *gin.Context) {
return
}
// 记录删除前的配置内容
h.saveHistory(&config, userInfo.Name, "delete")
config.Enabled = false
config.UpdatedBy = userInfo.Name
now, err := dao.Now()
if err != nil {
logger.SugaredLogger.Errorf("[ConfigHandler.Delete] get database time error: %v", err)
c.JSON(http.StatusInternalServerError, model.WrapperResponse{Code: 500, Msg: "删除失败"})
return
}
// 记录删除前的配置内容
h.saveHistory(&config, userInfo.Name, "delete", now)
config.Enabled = false
config.UpdatedBy = userInfo.Name
config.UpdatedAt = &now
dao.Engine.ID(config.Id).Cols("enabled", "updated_by", "updated_at").Update(&config)
@@ -431,17 +433,18 @@ func (h *ConfigHandler) Rollback(c *gin.Context) {
return
}
// 记录回滚前的配置内容
h.saveHistory(&config, userInfo.Name, "rollback")
config.Contents = history.Contents
config.UpdatedBy = userInfo.Name
now, err := dao.Now()
if err != nil {
logger.SugaredLogger.Errorf("[ConfigHandler.Rollback] get database time error: %v", err)
c.JSON(http.StatusInternalServerError, model.WrapperResponse{Code: 500, Msg: "回滚失败"})
return
}
// 记录回滚前的配置内容
h.saveHistory(&config, userInfo.Name, "rollback", now)
config.Contents = history.Contents
config.UpdatedBy = userInfo.Name
config.UpdatedAt = &now
dao.Engine.ID(config.Id).Cols("contents", "updated_by", "updated_at").Update(&config)
}
@@ -460,7 +463,7 @@ func (h *ConfigHandler) buildAppNames(config *model.AppConfig) string {
return ""
}
func (h *ConfigHandler) saveHistory(config *model.AppConfig, operator, operate string) {
func (h *ConfigHandler) saveHistory(config *model.AppConfig, operator, operate string, createdAt time.Time) {
history := model.AppConfigHistory{
OriginId: config.Id,
AppId: config.AppId,
@@ -471,7 +474,7 @@ func (h *ConfigHandler) saveHistory(config *model.AppConfig, operator, operate s
Type: config.Type,
Operate: operate,
Contents: config.Contents,
CreatedAt: func() *time.Time { t := time.Now(); return &t }(),
CreatedAt: &createdAt,
CreatedBy: operator,
}
dao.Engine.Insert(&history)
+1 -1
View File
@@ -39,7 +39,7 @@ type AppConfigHistory struct {
Operate string `xorm:"varchar(16)" json:"operate"` // update, delete, rollback
Contents string `xorm:"text" json:"contents"`
ActiveContents string `xorm:"-" json:"activeContents,omitempty"`
CreatedAt *time.Time `xorm:"datetime" json:"createdAt"`
CreatedAt *time.Time `xorm:"datetime(3)" json:"createdAt"`
CreatedBy string `xorm:"varchar(32)" json:"createdBy"`
}
+1 -1
View File
@@ -152,7 +152,7 @@ CREATE TABLE `app_config_history` (
`type` smallint DEFAULT NULL,
`operate` varchar(16) DEFAULT NULL,
`contents` text,
`created_at` datetime DEFAULT NULL,
`created_at` datetime(3) DEFAULT NULL,
`created_by` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=39 DEFAULT CHARSET=utf8mb3;
@@ -0,0 +1,5 @@
-- 将配置历史时间字段升级为毫秒精度,与 app_config 保持一致。
-- 新库由 xorm Sync2 按模型定义建表,已有环境执行本脚本升级。
ALTER TABLE `app_config_history`
MODIFY COLUMN `created_at` DATETIME(3) NULL DEFAULT NULL;