Преглед на файлове

添加建立配置文件默认值

qdy преди 2 месеца
родител
ревизия
78b80b79b4
променени са 6 файла, в които са добавени 637 реда и са изтрити 125 реда
  1. 263
    0
      models/Config_template_builder.go
  2. 47
    24
      models/config_template.go
  3. 0
    25
      models/service_profile.go
  4. 0
    54
      models/startup_config.go
  5. 0
    22
      models/template_type.go
  6. 327
    0
      service/create_config_template.go

+ 263
- 0
models/Config_template_builder.go Целия файл

@@ -0,0 +1,263 @@
1
+package models
2
+
3
+import (
4
+	"encoding/json"
5
+	"time"
6
+)
7
+
8
+// ConfigTemplateBuilder 配置模板建造者
9
+type ConfigTemplateBuilder struct {
10
+	templates []*ConfigTemplate
11
+	current   *ConfigTemplate
12
+}
13
+
14
+// NewConfigTemplateBuilder 创建配置模板建造者
15
+func NewConfigTemplateBuilder() *ConfigTemplateBuilder {
16
+	return &ConfigTemplateBuilder{
17
+		templates: make([]*ConfigTemplate, 0),
18
+	}
19
+}
20
+
21
+// StartTemplate 开始创建新模板
22
+func (b *ConfigTemplateBuilder) StartTemplate(name, rootKey, description string) *ConfigTemplateBuilder {
23
+	b.current = &ConfigTemplate{
24
+		TemplateName: name,
25
+		YamlRootKey:  rootKey,
26
+		Description:  description,
27
+		IsDefault:    true,
28
+		SortOrder:    len(b.templates) + 1,
29
+		Creator:      "system",
30
+		CreatedAt:    time.Now(),
31
+		UpdatedAt:    time.Now(),
32
+		Details:      make([]ConfigTemplateDetail, 0),
33
+	}
34
+	return b
35
+}
36
+
37
+// AddInt 添加整型配置项
38
+func (b *ConfigTemplateBuilder) AddInt(key, description string) *DetailBuilder {
39
+	return b.addDetail(key, description, "number", "int")
40
+}
41
+
42
+// AddString 添加字符串配置项
43
+func (b *ConfigTemplateBuilder) AddString(key, description string) *DetailBuilder {
44
+	return b.addDetail(key, description, "string", "string")
45
+}
46
+
47
+// AddBoolean 添加布尔型配置项
48
+func (b *ConfigTemplateBuilder) AddBoolean(key, description string) *DetailBuilder {
49
+	return b.addDetail(key, description, "boolean", "boolean")
50
+}
51
+
52
+// AddEnum 添加枚举型配置项
53
+func (b *ConfigTemplateBuilder) AddEnum(key, description string, enumValues []string) *DetailBuilder {
54
+	db := b.addDetail(key, description, "string", "string")
55
+	db.detail.ValidationRules = func() string {
56
+		rules := ValidationRules{
57
+			EnumValues: enumValues,
58
+		}
59
+		b, _ := json.Marshal(rules)
60
+		return string(b)
61
+	}()
62
+	return db
63
+}
64
+
65
+// FinishTemplate 完成当前模板创建
66
+func (b *ConfigTemplateBuilder) FinishTemplate() *ConfigTemplateBuilder {
67
+	if b.current != nil {
68
+		b.templates = append(b.templates, b.current)
69
+		b.current = nil
70
+	}
71
+	return b
72
+}
73
+
74
+// GetTemplates 获取所有模板
75
+func (b *ConfigTemplateBuilder) GetTemplates() []*ConfigTemplate {
76
+	return b.templates
77
+}
78
+
79
+// // BuildSampleTemplates 构建示例模板
80
+// func (b *ConfigTemplateBuilder) BuildSampleTemplates() *ConfigTemplateBuilder {
81
+// 	// Service模板
82
+// 	b.StartTemplate("Service配置", "service", "服务基础配置").
83
+// 		AddInt("port", "服务监听端口").Default("8080").Min(1024).Max(65535).Required().FinishDetail().
84
+// 		AddString("service_name", "服务名称").Default("svc-configure").Pattern("^[a-zA-Z][a-zA-Z0-9_-]*$").Required().FinishDetail().
85
+// 		AddString("instance_name", "实例名称").Default("svc-configure-01").Required().FinishDetail().
86
+// 		AddInt("read_timeout", "读取超时时间(秒)").Default("30").Min(1).Max(300).Required().FinishDetail().
87
+// 		AddInt("write_timeout", "写入超时时间(秒)").Default("30").Min(1).Max(300).Required().FinishDetail().
88
+// 		AddInt("idle_timeout", "空闲超时时间(秒)").Default("60").Min(10).Max(600).Required().FinishDetail().
89
+// 		FinishTemplate()
90
+
91
+// 	// Log模板
92
+// 	b.StartTemplate("日志配置", "log", "日志相关配置").
93
+// 		AddEnum("level", "日志级别", []string{"debug", "info", "warn", "error", "fatal"}).Default("debug").Required().FinishDetail().
94
+// 		AddString("output", "日志输出目标").Default("console,file").FinishDetail().
95
+// 		AddBoolean("json_format", "是否以JSON格式输出日志").Default("true").FinishDetail().
96
+// 		FinishTemplate()
97
+
98
+// 	// Doris模板
99
+// 	b.StartTemplate("Doris配置", "doris", "Doris数据库连接配置").
100
+// 		AddString("fe_host", "Doris FE节点主机地址").Default("161.189.89.196").Pattern(`^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`).Required().FinishDetail().
101
+// 		AddInt("fe_port", "Doris FE端口号").Default("8040").Min(1).Max(65535).Required().FinishDetail().
102
+// 		AddString("fe_username", "Doris FE用户名").Default("root").Required().FinishDetail().
103
+// 		AddString("fe_password", "Doris FE密码").Default("mos8555").Sensitive().Required().MinLength(6).MaxLength(100).FinishDetail().
104
+// 		AddInt("stream_load_timeout", "Stream Load超时时间(秒)").Default("300").Min(10).Max(3600).FinishDetail().
105
+// 		AddInt("batch_size", "批量大小").Default("1000").Min(1).Max(10000).FinishDetail().
106
+// 		FinishTemplate()
107
+
108
+// 	return b
109
+// }
110
+
111
+// 私有方法
112
+func (b *ConfigTemplateBuilder) addDetail(key, description, valueType, dataType string) *DetailBuilder {
113
+	if b.current == nil {
114
+		b.StartTemplate("未命名模板", "untitled", "未描述模板")
115
+	}
116
+
117
+	detail := ConfigTemplateDetail{
118
+		ConfigKey:   key,
119
+		Description: description,
120
+		ValueType:   valueType,
121
+		DataType:    dataType,
122
+		IsRequired:  false,
123
+		IsSensitive: false,
124
+		IsReadonly:  false,
125
+		SortOrder:   len(b.current.Details) + 1,
126
+		Creator:     "system",
127
+		CreatedAt:   time.Now(),
128
+		UpdatedAt:   time.Now(),
129
+	}
130
+
131
+	return &DetailBuilder{
132
+		builder: b,
133
+		detail:  detail,
134
+	}
135
+}
136
+
137
+// DetailBuilder 配置详情建造者
138
+type DetailBuilder struct {
139
+	builder *ConfigTemplateBuilder
140
+	detail  ConfigTemplateDetail
141
+}
142
+
143
+// Default 设置默认值
144
+func (db *DetailBuilder) Default(value string) *DetailBuilder {
145
+	db.detail.DefaultValue = value
146
+	db.detail.ConfigValue = value
147
+	return db
148
+}
149
+
150
+// Required 设置为必填项
151
+func (db *DetailBuilder) Required() *DetailBuilder {
152
+	db.detail.IsRequired = true
153
+	return db
154
+}
155
+
156
+// Sensitive 设置为敏感信息
157
+func (db *DetailBuilder) Sensitive() *DetailBuilder {
158
+	db.detail.IsSensitive = true
159
+	return db
160
+}
161
+
162
+// Readonly 设置为只读
163
+func (db *DetailBuilder) Readonly() *DetailBuilder {
164
+	db.detail.IsReadonly = true
165
+	return db
166
+}
167
+
168
+// Min 设置最小值
169
+func (db *DetailBuilder) Min(min float64) *DetailBuilder {
170
+	db.addValidation(func(r *ValidationRules) {
171
+		r.Min = &min
172
+	})
173
+	return db
174
+}
175
+
176
+// Max 设置最大值
177
+func (db *DetailBuilder) Max(max float64) *DetailBuilder {
178
+	db.addValidation(func(r *ValidationRules) {
179
+		r.Max = &max
180
+	})
181
+	return db
182
+}
183
+
184
+// MinLength 设置最小长度
185
+func (db *DetailBuilder) MinLength(length int) *DetailBuilder {
186
+	db.addValidation(func(r *ValidationRules) {
187
+		r.MinLength = &length
188
+	})
189
+	return db
190
+}
191
+
192
+// MaxLength 设置最大长度
193
+func (db *DetailBuilder) MaxLength(length int) *DetailBuilder {
194
+	db.addValidation(func(r *ValidationRules) {
195
+		r.MaxLength = &length
196
+	})
197
+	return db
198
+}
199
+
200
+// Pattern 设置正则表达式
201
+func (db *DetailBuilder) Pattern(pattern string) *DetailBuilder {
202
+	db.addValidation(func(r *ValidationRules) {
203
+		r.Pattern = pattern
204
+	})
205
+	return db
206
+}
207
+
208
+// Message 设置验证错误消息
209
+func (db *DetailBuilder) Message(msg string) *DetailBuilder {
210
+	db.addValidation(func(r *ValidationRules) {
211
+		r.Message = msg
212
+	})
213
+	return db
214
+}
215
+
216
+// FinishDetail 完成当前详情项
217
+func (db *DetailBuilder) FinishDetail() *ConfigTemplateBuilder {
218
+	db.builder.current.Details = append(db.builder.current.Details, db.detail)
219
+	return db.builder
220
+}
221
+
222
+// 私有方法
223
+func (db *DetailBuilder) addValidation(fn func(*ValidationRules)) {
224
+	var rules ValidationRules
225
+	if db.detail.ValidationRules != "" {
226
+		json.Unmarshal([]byte(db.detail.ValidationRules), &rules)
227
+	}
228
+	fn(&rules)
229
+	b, _ := json.Marshal(rules)
230
+	db.detail.ValidationRules = string(b)
231
+}
232
+
233
+// 使用示例
234
+func CreateSampleConfigTemplates() []*ConfigTemplate {
235
+	builder := NewConfigTemplateBuilder()
236
+	//builder.BuildSampleTemplates()
237
+	return builder.GetTemplates()
238
+}
239
+
240
+// 更简洁的使用示例
241
+func CreateConfigTemplates() []*ConfigTemplate {
242
+	builder := NewConfigTemplateBuilder()
243
+
244
+	// Service模板 - 更简洁的写法
245
+	builder.StartTemplate("Service配置", "service", "服务基础配置")
246
+	builder.AddInt("port", "服务监听端口").Default("8080").Min(1024).Max(65535).Required().FinishDetail()
247
+	builder.AddString("service_name", "服务名称").Default("svc-configure").Required().FinishDetail()
248
+	builder.FinishTemplate()
249
+
250
+	// Log模板
251
+	builder.StartTemplate("日志配置", "log", "日志相关配置")
252
+	builder.AddEnum("level", "日志级别", []string{"debug", "info", "warn", "error", "fatal"}).Default("debug").Required().FinishDetail()
253
+	builder.AddString("output", "日志输出").Default("console,file").FinishDetail()
254
+	builder.FinishTemplate()
255
+
256
+	// Doris模板
257
+	builder.StartTemplate("Doris配置", "doris", "Doris连接配置")
258
+	builder.AddString("fe_host", "FE主机").Default("localhost").Required().FinishDetail()
259
+	builder.AddString("fe_password", "密码").Sensitive().Required().FinishDetail()
260
+	builder.FinishTemplate()
261
+
262
+	return builder.GetTemplates()
263
+}

+ 47
- 24
models/config_template.go Целия файл

@@ -1,40 +1,63 @@
1 1
 package models
2 2
 
3 3
 import (
4
-	"database/sql"
5
-	"encoding/json"
6
-	"strings"
7 4
 	"time"
8 5
 )
9 6
 
10
-// ConfigTemplate 配置模板
7
+// ConfigTemplate 配置模板
11 8
 type ConfigTemplate struct {
12
-	ID          int64           `json:"id" db:"id"`                               // 技术主键
13
-	Name        string          `json:"name" db:"name"`                           // 模板名称
14
-	TypeCode    string          `json:"type_code" db:"type_code"`                 // 类型编码,关联template_type.code
15
-	Content     json.RawMessage `json:"content" db:"content"`                     // 模板内容JSON
16
-	ServiceType sql.NullString  `json:"service_type,omitempty" db:"service_type"` // 适用服务类型
17
-	IsDefault   bool            `json:"is_default" db:"is_default"`               // 是否默认模板
18
-	SortOrder   int             `json:"sort_order" db:"sort_order"`               // 排序号
19
-	Creator     string          `json:"creator" db:"creator"`                     // 创建人
20
-	CreatedAt   time.Time       `json:"created_at" db:"created_at"`               // 创建时间
9
+	ConfigTemplateID int64     `gorm:"column:config_template_id;primaryKey;autoIncrement" json:"config_template_id"`
10
+	TemplateName     string    `gorm:"column:template_name;type:varchar(100);not null;uniqueIndex;comment:模板名称" json:"template_name"`
11
+	YamlRootKey      string    `gorm:"column:yaml_root_key;type:varchar(100);comment:YAML根键名" json:"yaml_root_key"`
12
+	IsDefault        bool      `gorm:"column:is_default;type:boolean;default:false;comment:是否为默认模板" json:"is_default"`
13
+	SortOrder        int       `gorm:"column:sort_order;type:integer;default:0;comment:排序序号" json:"sort_order"`
14
+	Description      string    `gorm:"column:description;type:text;comment:模板描述" json:"description"`
15
+	Creator          string    `gorm:"column:creator;type:varchar(100);not null;comment:创建者" json:"creator"`
16
+	CreatedAt        time.Time `gorm:"column:created_at;type:timestamp;default:CURRENT_TIMESTAMP" json:"created_at"`
17
+	UpdatedAt        time.Time `gorm:"column:updated_at;type:timestamp;default:CURRENT_TIMESTAMP;autoUpdateTime" json:"updated_at"`
18
+
19
+	// 关联关系
20
+	Details []ConfigTemplateDetail `gorm:"foreignKey:ConfigTemplateID;references:ConfigTemplateID" json:"details,omitempty"`
21 21
 }
22 22
 
23
-// TableName 返回表名
23
+// TableName 设置表名
24 24
 func (ConfigTemplate) TableName() string {
25 25
 	return "config_template"
26 26
 }
27 27
 
28
-// TemplateKey 返回业务键:type_code.name
29
-func (c *ConfigTemplate) TemplateKey() string {
30
-	return c.TypeCode + "." + c.Name
28
+// ConfigTemplateDetail 配置模板详情
29
+type ConfigTemplateDetail struct {
30
+	ConfigTemplateDetailID int64     `gorm:"column:config_template_detail_id;primaryKey;autoIncrement" json:"config_template_detail_id"`
31
+	ConfigTemplateID       int64     `gorm:"column:config_template_id;not null;index" json:"config_template_id"`
32
+	ConfigKey              string    `gorm:"column:config_key;type:varchar(100);not null;index" json:"config_key"`
33
+	ConfigValue            string    `gorm:"column:config_value;type:text" json:"config_value"`
34
+	ValueType              string    `gorm:"column:value_type;type:varchar(20);not null;default:'string';comment:值类型:string,number,boolean,json,array" json:"value_type"`
35
+	DataType               string    `gorm:"column:data_type;type:varchar(50);comment:数据类型:int,float,string,boolean,date,datetime" json:"data_type"`
36
+	IsRequired             bool      `gorm:"column:is_required;type:boolean;default:false" json:"is_required"`
37
+	DefaultValue           string    `gorm:"column:default_value;type:text" json:"default_value"`
38
+	ValidationRules        string    `gorm:"column:validation_rules;type:jsonb;comment:验证规则JSON" json:"validation_rules"`
39
+	Description            string    `gorm:"column:description;type:text" json:"description"`
40
+	SortOrder              int       `gorm:"column:sort_order;type:integer;default:0" json:"sort_order"`
41
+	IsSensitive            bool      `gorm:"column:is_sensitive;type:boolean;default:false;comment:是否为敏感信息,敏感信息会加密存储" json:"is_sensitive"`
42
+	IsReadonly             bool      `gorm:"column:is_readonly;type:boolean;default:false" json:"is_readonly"`
43
+	Creator                string    `gorm:"column:creator;type:varchar(100);not null" json:"creator"`
44
+	CreatedAt              time.Time `gorm:"column:created_at;type:timestamp;default:CURRENT_TIMESTAMP" json:"created_at"`
45
+	UpdatedAt              time.Time `gorm:"column:updated_at;type:timestamp;default:CURRENT_TIMESTAMP;autoUpdateTime" json:"updated_at"`
46
+}
47
+
48
+// TableName 设置表名
49
+func (ConfigTemplateDetail) TableName() string {
50
+	return "config_template_detail"
31 51
 }
32 52
 
33
-// ParseTemplateKey 解析业务键
34
-func ParseTemplateKey(key string) (typeCode, name string, ok bool) {
35
-	parts := strings.SplitN(key, ".", 2)
36
-	if len(parts) != 2 {
37
-		return "", "", false
38
-	}
39
-	return parts[0], parts[1], true
53
+// ValidationRulesStruct 验证规则结构体
54
+type ValidationRules struct {
55
+	Min        *float64 `json:"min,omitempty"`         // 最小值
56
+	Max        *float64 `json:"max,omitempty"`         // 最大值
57
+	MinLength  *int     `json:"min_length,omitempty"`  // 最小长度
58
+	MaxLength  *int     `json:"max_length,omitempty"`  // 最大长度
59
+	Pattern    string   `json:"pattern,omitempty"`     // 正则表达式
60
+	Required   *bool    `json:"required,omitempty"`    // 是否必填
61
+	EnumValues []string `json:"enum_values,omitempty"` // 枚举值
62
+	Message    string   `json:"message,omitempty"`     // 验证失败提示信息
40 63
 }

+ 0
- 25
models/service_profile.go Целия файл

@@ -1,25 +0,0 @@
1
-package models
2
-
3
-import (
4
-	"database/sql"
5
-	"time"
6
-)
7
-
8
-// ServiceProfile 微服务档案表
9
-type ServiceProfile struct {
10
-	ServiceCode string         `json:"service_code" db:"service_code"` // 主键,服务编码
11
-	ServiceName string         `json:"service_name" db:"service_name"` // 服务名称
12
-	ServiceType string         `json:"service_type" db:"service_type"` // 服务类型:api/auth/order等
13
-	Version     string         `json:"version" db:"version"`           // 当前版本
14
-	Language    string         `json:"language" db:"language"`         // 开发语言
15
-	Owner       string         `json:"owner" db:"owner"`               // 负责人
16
-	OwnerPhone  sql.NullString `json:"owner_phone,omitempty" db:"owner_phone"`
17
-	Status      string         `json:"status" db:"status"`         // 状态:active/inactive
18
-	Creator     string         `json:"creator" db:"creator"`       // 创建人
19
-	CreatedAt   time.Time      `json:"created_at" db:"created_at"` // 创建时间
20
-}
21
-
22
-// TableName 返回表名
23
-func (ServiceProfile) TableName() string {
24
-	return "service_profile"
25
-}

+ 0
- 54
models/startup_config.go Целия файл

@@ -1,54 +0,0 @@
1
-package models
2
-
3
-import (
4
-	"database/sql"
5
-	"encoding/json"
6
-	"fmt"
7
-	"strconv"
8
-	"strings"
9
-	"time"
10
-)
11
-
12
-// StartupConfig 启动配置表
13
-type StartupConfig struct {
14
-	ID          int64           `json:"id" db:"id"`                           // 技术主键
15
-	ServiceName string          `json:"service_name" db:"service_name"`       // 服务名称
16
-	Environment string          `json:"environment" db:"environment"`         // 环境:dev/test/prod
17
-	Version     int             `json:"version" db:"version"`                 // 配置版本
18
-	ConfigJSON  json.RawMessage `json:"config_json" db:"config_json"`         // 配置内容JSON
19
-	IsActive    bool            `json:"is_active" db:"is_active"`             // 是否生效
20
-	Creator     string          `json:"creator" db:"creator"`                 // 创建人
21
-	CreatedAt   time.Time       `json:"created_at" db:"created_at"`           // 创建时间
22
-	UpdatedAt   sql.NullTime    `json:"updated_at,omitempty" db:"updated_at"` // 更新时间
23
-}
24
-
25
-// TableName 返回表名
26
-func (StartupConfig) TableName() string {
27
-	return "startup_config"
28
-}
29
-
30
-// ConfigKey 返回业务键:service_name.environment.vversion
31
-func (c *StartupConfig) ConfigKey() string {
32
-	return fmt.Sprintf("%s.%s.v%d", c.ServiceName, c.Environment, c.Version)
33
-}
34
-
35
-// ParseConfigKey 解析业务键
36
-func ParseConfigKey(key string) (service, env string, version int, ok bool) {
37
-	parts := strings.Split(key, ".")
38
-	if len(parts) != 3 {
39
-		return "", "", 0, false
40
-	}
41
-
42
-	// 检查版本格式
43
-	if !strings.HasPrefix(parts[2], "v") {
44
-		return "", "", 0, false
45
-	}
46
-
47
-	verStr := strings.TrimPrefix(parts[2], "v")
48
-	version, err := strconv.Atoi(verStr)
49
-	if err != nil {
50
-		return "", "", 0, false
51
-	}
52
-
53
-	return parts[0], parts[1], version, true
54
-}

+ 0
- 22
models/template_type.go Целия файл

@@ -1,22 +0,0 @@
1
-package models
2
-
3
-import (
4
-	"database/sql"
5
-	"time"
6
-)
7
-
8
-// TemplateType 模板类型表
9
-type TemplateType struct {
10
-	Code        string         `json:"code" db:"code"` // 主键,如:db, redis, auth
11
-	Name        string         `json:"name" db:"name"` // 类型名称
12
-	Description sql.NullString `json:"description,omitempty" db:"description"`
13
-	SortOrder   int            `json:"sort_order" db:"sort_order"` // 排序号
14
-	IsSystem    bool           `json:"is_system" db:"is_system"`   // 是否系统类型
15
-	Creator     string         `json:"creator" db:"creator"`       // 创建人
16
-	CreatedAt   time.Time      `json:"created_at" db:"created_at"` // 创建时间
17
-}
18
-
19
-// TableName 返回表名
20
-func (TemplateType) TableName() string {
21
-	return "template_type"
22
-}

+ 327
- 0
service/create_config_template.go Целия файл

@@ -0,0 +1,327 @@
1
+package service
2
+
3
+import (
4
+	"fmt"
5
+	"time"
6
+
7
+	"git.x2erp.com/qdy/go-svc-configure/models"
8
+	"github.com/jmoiron/sqlx"
9
+)
10
+
11
+// InitConfigTemplates 初始化默认配置信息
12
+func InitConfigTemplates(db *sqlx.DB) error {
13
+
14
+	builder := models.NewConfigTemplateBuilder()
15
+
16
+	templates := builder.
17
+		// Service模板
18
+		StartTemplate("Service配置", "service", "服务基础配置").
19
+		AddInt("port", "服务监听端口").Default("8080").Min(1024).Max(65535).Required().FinishDetail().
20
+		AddString("service_name", "服务名称").Default("svc-configure").Pattern("^[a-zA-Z][a-zA-Z0-9_-]*$").Required().FinishDetail().
21
+		AddString("instance_name", "实例名称").Default("svc-configure-01").Required().FinishDetail().
22
+		AddInt("read_timeout", "读取超时时间(秒)").Default("30").Min(1).Max(300).Required().FinishDetail().
23
+		AddInt("write_timeout", "写入超时时间(秒)").Default("30").Min(1).Max(300).Required().FinishDetail().
24
+		AddInt("idle_timeout", "空闲超时时间(秒)").Default("60").Min(10).Max(600).Required().FinishDetail().
25
+		FinishTemplate().
26
+
27
+		// Log模板
28
+		StartTemplate("日志增强配置", "log", "增强版日志配置").
29
+		AddEnum("level", "日志级别", []string{"debug", "info", "warn", "error", "fatal"}).Default("debug").Required().FinishDetail().
30
+		AddString("output", "日志输出目标").Default("console,es").FinishDetail().
31
+		//AddBoolean("json_format", "JSON格式输出").Default("true").FinishDetail().
32
+		AddString("file_path", "日志文件路径").Default("./logs/app-%s.log").FinishDetail().
33
+		AddInt("max_size", "最大文件大小(MB)").Default("100").FinishDetail().
34
+		AddInt("max_backups", "最大备份文件数").Default("30").FinishDetail().
35
+		AddInt("max_age", "最大保存天数").Default("7").FinishDetail().
36
+		AddBoolean("compress", "压缩备份文件").Default("true").FinishDetail().
37
+		AddString("es_path", "ES地址").Default("http://x3cloudb.x2erp.com:9200").FinishDetail().
38
+		AddString("es_username", "ES用户名").Default("").FinishDetail().
39
+		AddString("es_password", "ES密码").Default("").Sensitive().FinishDetail().
40
+		FinishTemplate().
41
+
42
+		// Doris模板
43
+		StartTemplate("Doris配置", "doris", "Doris数据库连接配置").
44
+		AddString("fe_host", "Doris FE节点主机地址").Default("161.189.89.196").Pattern(`^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`).Required().FinishDetail().
45
+		AddInt("fe_port", "Doris FE端口号").Default("8040").Min(1).Max(65535).Required().FinishDetail().
46
+		AddString("fe_username", "Doris FE用户名").Default("root").Required().FinishDetail().
47
+		AddString("fe_password", "Doris FE密码").Default("").Sensitive().Required().MinLength(6).MaxLength(100).FinishDetail().
48
+		AddInt("stream_load_timeout", "Stream Load超时时间(秒)").Default("300").Min(10).Max(3600).FinishDetail().
49
+		AddInt("batch_size", "批量大小").Default("1000").Min(1).Max(10000).FinishDetail().
50
+		FinishTemplate().
51
+
52
+		// micro 注册发现配置
53
+		StartTemplate("Micro服务配置", "micro", "Micro服务基础配置").
54
+		AddString("service_name", "服务名称").Default("svc-worker").Required().FinishDetail().
55
+		AddString("service_address", "服务地址").Default(":7070").Required().FinishDetail().
56
+		AddString("registry_address", "注册中心地址").Default("localhost:8500").Required().FinishDetail().
57
+		AddString("registry_type", "注册中心类型").Default("consul").Required().FinishDetail().
58
+		AddInt("registry_timeout", "注册中心超时时间").Default("10").Required().FinishDetail().
59
+		FinishTemplate().
60
+
61
+		// rabbitmq
62
+		StartTemplate("RabbitMQ配置", "rabbitmq", "RabbitMQ消息队列配置").
63
+		AddString("host", "主机地址").Default("localhost").Required().FinishDetail().
64
+		AddInt("port", "端口").Default("5672").Required().FinishDetail().
65
+		AddString("username", "用户名").Default("guest").Required().FinishDetail().
66
+		AddString("password", "密码").Default("guest").Sensitive().Required().FinishDetail().
67
+		AddString("vhost", "虚拟主机").Default("/").FinishDetail().
68
+		AddBoolean("use_tls", "启用TLS").Default("false").FinishDetail().
69
+		AddString("ca_cert", "CA证书").Default("").FinishDetail().
70
+		AddString("cert_file", "证书文件").Default("").FinishDetail().
71
+		AddString("key_file", "密钥文件").Default("").FinishDetail().
72
+		AddInt("max_open_channels", "最大通道数").Default("10").FinishDetail().
73
+		AddInt("reconnect_delay", "重连延迟(ms)").Default("5000").FinishDetail().
74
+		AddInt("max_reconnect_attempts", "最大重试次数").Default("10").FinishDetail().
75
+		AddInt("heartbeat", "心跳间隔(s)").Default("30").FinishDetail().
76
+		AddInt("channel_size", "通道大小").Default("100").FinishDetail().
77
+		AddString("default_exchange", "默认交换机").Default("amq.direct").FinishDetail().
78
+		AddString("default_queue", "默认队列").Default("").FinishDetail().
79
+		AddBoolean("auto_ack", "自动确认").Default("false").FinishDetail().
80
+		AddBoolean("mandatory", "强制路由").Default("false").FinishDetail().
81
+		AddBoolean("immediate", "立即发送").Default("false").FinishDetail().
82
+		AddInt("prefetch_count", "预取数量").Default("1").FinishDetail().
83
+		AddInt("prefetch_size", "预取大小").Default("0").FinishDetail().
84
+		AddBoolean("global", "全局设置").Default("false").FinishDetail().
85
+		AddBoolean("publisher_confirms", "发布确认").Default("false").FinishDetail().
86
+		AddInt("confirm_timeout", "确认超时(s)").Default("5").FinishDetail().
87
+		FinishTemplate().
88
+		GetTemplates()
89
+
90
+	return CreateOrUpdateConfigTemplates(db, templates)
91
+}
92
+
93
+// CreateOrUpdateConfigTemplates 创建或更新配置模板(支持部分更新)
94
+func CreateOrUpdateConfigTemplates(db *sqlx.DB, templates []*models.ConfigTemplate) error {
95
+	if db == nil {
96
+		return fmt.Errorf("database connection is nil")
97
+	}
98
+
99
+	// 开始事务
100
+	tx, err := db.Beginx()
101
+	if err != nil {
102
+		return fmt.Errorf("begin transaction failed: %v", err)
103
+	}
104
+	defer func() {
105
+		if err != nil {
106
+			tx.Rollback()
107
+		}
108
+	}()
109
+
110
+	now := time.Now()
111
+
112
+	for _, template := range templates {
113
+		// 设置时间
114
+		if template.CreatedAt.IsZero() {
115
+			template.CreatedAt = now
116
+		}
117
+		template.UpdatedAt = now
118
+
119
+		// 1. 插入或更新模板主表
120
+		templateID, err := upsertTemplate(tx, template, now)
121
+		if err != nil {
122
+			return err
123
+		}
124
+
125
+		// 2. 处理模板详情(部分更新)
126
+		if len(template.Details) > 0 {
127
+			err = upsertTemplateDetails(tx, templateID, template.Details, now)
128
+			if err != nil {
129
+				return err
130
+			}
131
+		}
132
+	}
133
+
134
+	return tx.Commit()
135
+}
136
+
137
+// upsertTemplate 插入或更新模板主表
138
+func upsertTemplate(tx *sqlx.Tx, template *models.ConfigTemplate, now time.Time) (int64, error) {
139
+	sqlStr := `
140
+		INSERT INTO config_template (
141
+			template_name, 
142
+			yaml_root_key, 
143
+			is_default, 
144
+			sort_order, 
145
+			description, 
146
+			creator, 
147
+			created_at, 
148
+			updated_at
149
+		) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
150
+		ON CONFLICT (template_name) DO UPDATE SET
151
+			yaml_root_key = EXCLUDED.yaml_root_key,
152
+			is_default = EXCLUDED.is_default,
153
+			sort_order = EXCLUDED.sort_order,
154
+			description = EXCLUDED.description,
155
+			creator = EXCLUDED.creator,
156
+			updated_at = $8
157
+		RETURNING config_template_id`
158
+
159
+	var templateID int64
160
+	err := tx.QueryRow(sqlStr,
161
+		template.TemplateName,
162
+		template.YamlRootKey,
163
+		template.IsDefault,
164
+		template.SortOrder,
165
+		template.Description,
166
+		template.Creator,
167
+		template.CreatedAt,
168
+		now, // 使用事务中的时间
169
+	).Scan(&templateID)
170
+
171
+	if err != nil {
172
+		return 0, fmt.Errorf("upsert template failed: %v", err)
173
+	}
174
+
175
+	return templateID, nil
176
+}
177
+
178
+// upsertTemplateDetails 插入或更新模板详情(基于config_key唯一性)
179
+func upsertTemplateDetails(tx *sqlx.Tx, templateID int64, details []models.ConfigTemplateDetail, now time.Time) error {
180
+	for _, detail := range details {
181
+		// 设置时间和模板ID
182
+		if detail.CreatedAt.IsZero() {
183
+			detail.CreatedAt = now
184
+		}
185
+		detail.UpdatedAt = now
186
+		detail.ConfigTemplateID = templateID
187
+
188
+		sqlStr := `
189
+			INSERT INTO config_template_detail (
190
+				config_template_id,
191
+				config_key,
192
+				config_value,
193
+				value_type,
194
+				data_type,
195
+				is_required,
196
+				default_value,
197
+				validation_rules,
198
+				description,
199
+				sort_order,
200
+				is_sensitive,
201
+				is_readonly,
202
+				creator,
203
+				created_at,
204
+				updated_at
205
+			) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
206
+			ON CONFLICT (config_template_id, config_key) DO UPDATE SET
207
+				config_value = EXCLUDED.config_value,
208
+				value_type = EXCLUDED.value_type,
209
+				data_type = EXCLUDED.data_type,
210
+				is_required = EXCLUDED.is_required,
211
+				default_value = EXCLUDED.default_value,
212
+				validation_rules = EXCLUDED.validation_rules,
213
+				description = EXCLUDED.description,
214
+				sort_order = EXCLUDED.sort_order,
215
+				is_sensitive = EXCLUDED.is_sensitive,
216
+				is_readonly = EXCLUDED.is_readonly,
217
+				creator = EXCLUDED.creator,
218
+				updated_at = $15`
219
+
220
+		_, err := tx.Exec(sqlStr,
221
+			detail.ConfigTemplateID,
222
+			detail.ConfigKey,
223
+			detail.ConfigValue,
224
+			detail.ValueType,
225
+			detail.DataType,
226
+			detail.IsRequired,
227
+			detail.DefaultValue,
228
+			detail.ValidationRules,
229
+			detail.Description,
230
+			detail.SortOrder,
231
+			detail.IsSensitive,
232
+			detail.IsReadonly,
233
+			detail.Creator,
234
+			detail.CreatedAt,
235
+			now,
236
+		)
237
+
238
+		if err != nil {
239
+			return fmt.Errorf("upsert template detail failed (key: %s): %v", detail.ConfigKey, err)
240
+		}
241
+	}
242
+
243
+	return nil
244
+}
245
+
246
+// 批量版本(如果需要更高性能)
247
+func batchUpsertTemplateDetails(tx *sqlx.Tx, templateID int64, details []models.ConfigTemplateDetail, now time.Time) error {
248
+	if len(details) == 0 {
249
+		return nil
250
+	}
251
+
252
+	// 使用临时表进行批量操作
253
+	_, err := tx.Exec(`
254
+		CREATE TEMP TABLE temp_config_details (
255
+			config_key VARCHAR(100),
256
+			config_value TEXT,
257
+			value_type VARCHAR(20),
258
+			data_type VARCHAR(50),
259
+			is_required BOOLEAN,
260
+			default_value TEXT,
261
+			validation_rules JSONB,
262
+			description TEXT,
263
+			sort_order INTEGER,
264
+			is_sensitive BOOLEAN,
265
+			is_readonly BOOLEAN,
266
+			creator VARCHAR(100)
267
+		) ON COMMIT DROP`)
268
+	if err != nil {
269
+		return fmt.Errorf("create temp table failed: %v", err)
270
+	}
271
+
272
+	// 批量插入到临时表
273
+	stmt, err := tx.Prepare(`
274
+		INSERT INTO temp_config_details VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`)
275
+	if err != nil {
276
+		return err
277
+	}
278
+	defer stmt.Close()
279
+
280
+	for _, detail := range details {
281
+		_, err = stmt.Exec(
282
+			detail.ConfigKey,
283
+			detail.ConfigValue,
284
+			detail.ValueType,
285
+			detail.DataType,
286
+			detail.IsRequired,
287
+			detail.DefaultValue,
288
+			detail.ValidationRules,
289
+			detail.Description,
290
+			detail.SortOrder,
291
+			detail.IsSensitive,
292
+			detail.IsReadonly,
293
+			detail.Creator,
294
+		)
295
+		if err != nil {
296
+			return err
297
+		}
298
+	}
299
+
300
+	// 使用临时表进行批量UPSERT
301
+	_, err = tx.Exec(`
302
+		INSERT INTO config_template_detail (
303
+			config_template_id, config_key, config_value, value_type, data_type,
304
+			is_required, default_value, validation_rules, description, sort_order,
305
+			is_sensitive, is_readonly, creator, created_at, updated_at
306
+		)
307
+		SELECT $1, config_key, config_value, value_type, data_type,
308
+			is_required, default_value, validation_rules, description, sort_order,
309
+			is_sensitive, is_readonly, creator, $2, $3
310
+		FROM temp_config_details
311
+		ON CONFLICT (config_template_id, config_key) DO UPDATE SET
312
+			config_value = EXCLUDED.config_value,
313
+			value_type = EXCLUDED.value_type,
314
+			data_type = EXCLUDED.data_type,
315
+			is_required = EXCLUDED.is_required,
316
+			default_value = EXCLUDED.default_value,
317
+			validation_rules = EXCLUDED.validation_rules,
318
+			description = EXCLUDED.description,
319
+			sort_order = EXCLUDED.sort_order,
320
+			is_sensitive = EXCLUDED.is_sensitive,
321
+			is_readonly = EXCLUDED.is_readonly,
322
+			creator = EXCLUDED.creator,
323
+			updated_at = EXCLUDED.updated_at`,
324
+		templateID, now, now)
325
+
326
+	return err
327
+}

Loading…
Отказ
Запис