feat: opt system notify init data
This commit is contained in:
@@ -48,7 +48,8 @@ const (
|
|||||||
KeySecret = "secret"
|
KeySecret = "secret"
|
||||||
|
|
||||||
// System Settings Key 常量
|
// System Settings Key 常量
|
||||||
KeyInitialized = "initialized"
|
KeyInitialized = "initialized"
|
||||||
|
KeyLogRetention = "log_retention"
|
||||||
|
|
||||||
// Scheduler Settings Key 常量
|
// Scheduler Settings Key 常量
|
||||||
KeyWorkerCount = "worker_count"
|
KeyWorkerCount = "worker_count"
|
||||||
@@ -158,3 +159,6 @@ var DefaultSettings = map[string]map[string]string{
|
|||||||
KeyRateInterval: "200",
|
KeyRateInterval: "200",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultLogRetention 默认日志清理配置
|
||||||
|
var DefaultLogRetention = `{"system_notice":{"days":30,"max_count":500},"push_log":{"days":15,"max_count":5000}}`
|
||||||
|
|||||||
@@ -106,6 +106,25 @@ func (sc *SettingsController) GetSiteSettings(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取日志清理配置
|
||||||
|
logRetentionJson := sc.settingsService.Get(constant.SectionSystem, constant.KeyLogRetention)
|
||||||
|
if logRetentionJson != "" {
|
||||||
|
var configs map[string]struct {
|
||||||
|
Days int `json:"days"`
|
||||||
|
MaxCount int `json:"max_count"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal([]byte(logRetentionJson), &configs); err == nil {
|
||||||
|
if cfg, ok := configs[constant.LogCategorySystemNotice]; ok {
|
||||||
|
settings["system_notice_days"] = fmt.Sprintf("%d", cfg.Days)
|
||||||
|
settings["system_notice_max_count"] = fmt.Sprintf("%d", cfg.MaxCount)
|
||||||
|
}
|
||||||
|
if cfg, ok := configs[constant.LogCategoryPushLog]; ok {
|
||||||
|
settings["push_log_days"] = fmt.Sprintf("%d", cfg.Days)
|
||||||
|
settings["push_log_max_count"] = fmt.Sprintf("%d", cfg.MaxCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
utils.Success(c, settings)
|
utils.Success(c, settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,14 +143,18 @@ func (sc *SettingsController) GetPublicSiteSettings(c *gin.Context) {
|
|||||||
// UpdateSiteSettings 更新站点设置
|
// UpdateSiteSettings 更新站点设置
|
||||||
func (sc *SettingsController) UpdateSiteSettings(c *gin.Context) {
|
func (sc *SettingsController) UpdateSiteSettings(c *gin.Context) {
|
||||||
var req struct {
|
var req struct {
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Subtitle string `json:"subtitle"`
|
Subtitle string `json:"subtitle"`
|
||||||
Icon string `json:"icon"`
|
Icon string `json:"icon"`
|
||||||
PageSize string `json:"page_size"`
|
PageSize string `json:"page_size"`
|
||||||
CookieDays string `json:"cookie_days"`
|
CookieDays string `json:"cookie_days"`
|
||||||
OpenapiEnabled bool `json:"openapi_enabled"`
|
OpenapiEnabled bool `json:"openapi_enabled"`
|
||||||
OpenapiToken string `json:"openapi_token"`
|
OpenapiToken string `json:"openapi_token"`
|
||||||
OpenapiTokenExpire string `json:"openapi_token_expire"`
|
OpenapiTokenExpire string `json:"openapi_token_expire"`
|
||||||
|
SystemNoticeDays int `json:"system_notice_days"`
|
||||||
|
SystemNoticeMaxCount int `json:"system_notice_max_count"`
|
||||||
|
PushLogDays int `json:"push_log_days"`
|
||||||
|
PushLogMaxCount int `json:"push_log_max_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
@@ -165,6 +188,21 @@ func (sc *SettingsController) UpdateSiteSettings(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 保存日志清理配置
|
||||||
|
logRetentionConfig := map[string]interface{}{
|
||||||
|
constant.LogCategorySystemNotice: map[string]int{
|
||||||
|
"days": req.SystemNoticeDays,
|
||||||
|
"max_count": req.SystemNoticeMaxCount,
|
||||||
|
},
|
||||||
|
constant.LogCategoryPushLog: map[string]int{
|
||||||
|
"days": req.PushLogDays,
|
||||||
|
"max_count": req.PushLogMaxCount,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if logRetentionJson, err := json.Marshal(logRetentionConfig); err == nil {
|
||||||
|
sc.settingsService.Set(constant.SectionSystem, constant.KeyLogRetention, string(logRetentionJson))
|
||||||
|
}
|
||||||
|
|
||||||
utils.SuccessMsg(c, "保存成功")
|
utils.SuccessMsg(c, "保存成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,21 @@ func (s *SettingsService) InitSettings() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化日志清理配置
|
||||||
|
var logRetentionCount int64
|
||||||
|
database.DB.Model(&models.Setting{}).Where("section = ? AND `key` = ?", constant.SectionSystem, constant.KeyLogRetention).Count(&logRetentionCount)
|
||||||
|
if logRetentionCount == 0 {
|
||||||
|
if err := database.DB.Create(&models.Setting{
|
||||||
|
ID: utils.GenerateID(),
|
||||||
|
Section: constant.SectionSystem,
|
||||||
|
Key: constant.KeyLogRetention,
|
||||||
|
Value: models.BigText(constant.DefaultLogRetention),
|
||||||
|
}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化或获取 JWT Secret 密码
|
// 初始化或获取 JWT Secret 密码
|
||||||
var secCount int64
|
var secCount int64
|
||||||
database.DB.Model(&models.Setting{}).Where("section = ? AND `key` = ?", constant.SectionSecurity, constant.KeySecret).Count(&secCount)
|
database.DB.Model(&models.Setting{}).Where("section = ? AND `key` = ?", constant.SectionSecurity, constant.KeySecret).Count(&secCount)
|
||||||
|
|||||||
@@ -450,6 +450,10 @@ export interface SiteSettings {
|
|||||||
openapi_enabled?: boolean
|
openapi_enabled?: boolean
|
||||||
openapi_token?: string
|
openapi_token?: string
|
||||||
openapi_token_expire?: string
|
openapi_token_expire?: string
|
||||||
|
system_notice_days?: string
|
||||||
|
system_notice_max_count?: string
|
||||||
|
push_log_days?: string
|
||||||
|
push_log_max_count?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SchedulerSettings {
|
export interface SchedulerSettings {
|
||||||
|
|||||||
@@ -200,13 +200,13 @@ function onDialogClose(open: boolean) {
|
|||||||
@click="showDetail(log)">
|
@click="showDetail(log)">
|
||||||
<span class="w-12 sm:w-16 shrink-0 text-muted-foreground text-xs sm:text-sm">#{{ getLogIndex(index) }}</span>
|
<span class="w-12 sm:w-16 shrink-0 text-muted-foreground text-xs sm:text-sm">#{{ getLogIndex(index) }}</span>
|
||||||
<span class="w-40 sm:w-56 shrink-0 font-medium text-xs sm:text-sm truncate" :title="log.title">{{ log.title }}</span>
|
<span class="w-40 sm:w-56 shrink-0 font-medium text-xs sm:text-sm truncate" :title="log.title">{{ log.title }}</span>
|
||||||
<span class="hidden sm:flex sm:flex-1 font-medium text-xs sm:text-sm text-muted-foreground truncate" :title="log.content">
|
<span class="hidden sm:flex sm:flex-1 text-xs sm:text-sm text-muted-foreground truncate" :title="log.content">
|
||||||
{{ log.content || '-' }}
|
{{ log.content || '-' }}
|
||||||
</span>
|
</span>
|
||||||
<span class="w-10 sm:w-16 shrink-0 flex justify-center">
|
<span class="w-10 sm:w-16 shrink-0 flex justify-center">
|
||||||
<span :class="['h-2 w-2 rounded-full', log.status === LOG_STATUS.SUCCESS ? 'bg-green-500 shadow-[0_0_8px_rgba(34,197,94,0.4)]' : 'bg-red-500 shadow-[0_0_8px_rgba(239,68,68,0.4)]']"></span>
|
<span :class="['h-2 w-2 rounded-full', log.status === LOG_STATUS.SUCCESS ? 'bg-green-500' : 'bg-red-500']"></span>
|
||||||
</span>
|
</span>
|
||||||
<span class="shrink-0 w-24 sm:w-40 sm:text-right text-[10px] sm:text-xs text-muted-foreground font-mono">
|
<span class="shrink-0 w-24 sm:w-40 sm:text-right text-xs text-muted-foreground">
|
||||||
{{ formatDate(log.created_at) }}
|
{{ formatDate(log.created_at) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -32,7 +32,11 @@ const form = ref<SiteSettings>({
|
|||||||
cookie_days: '7',
|
cookie_days: '7',
|
||||||
openapi_enabled: false,
|
openapi_enabled: false,
|
||||||
openapi_token: '',
|
openapi_token: '',
|
||||||
openapi_token_expire: ''
|
openapi_token_expire: '',
|
||||||
|
system_notice_days: '30',
|
||||||
|
system_notice_max_count: '500',
|
||||||
|
push_log_days: '15',
|
||||||
|
push_log_max_count: '5000'
|
||||||
})
|
})
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const showOpenapiConfirmDialog = ref(false)
|
const showOpenapiConfirmDialog = ref(false)
|
||||||
@@ -62,7 +66,11 @@ async function saveSettings() {
|
|||||||
await api.settings.updateSite({
|
await api.settings.updateSite({
|
||||||
...form.value,
|
...form.value,
|
||||||
page_size: String(form.value.page_size),
|
page_size: String(form.value.page_size),
|
||||||
cookie_days: String(form.value.cookie_days)
|
cookie_days: String(form.value.cookie_days),
|
||||||
|
system_notice_days: String(form.value.system_notice_days || '30'),
|
||||||
|
system_notice_max_count: String(form.value.system_notice_max_count || '500'),
|
||||||
|
push_log_days: String(form.value.push_log_days || '15'),
|
||||||
|
push_log_max_count: String(form.value.push_log_max_count || '5000')
|
||||||
})
|
})
|
||||||
await refreshSettings()
|
await refreshSettings()
|
||||||
toast.success('保存成功')
|
toast.success('保存成功')
|
||||||
@@ -137,6 +145,43 @@ onMounted(loadSettings)
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pt-6 border-t mt-6">
|
||||||
|
<h3 class="text-lg font-medium text-foreground mb-4">日志清理策略</h3>
|
||||||
|
<p class="text-sm text-muted-foreground mb-4">自动清理超过指定天数或数量的日志记录,保持系统性能。</p>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-4 items-center gap-2 sm:gap-4">
|
||||||
|
<Label class="sm:text-right text-muted-foreground">系统通知</Label>
|
||||||
|
<div class="sm:col-span-3 flex flex-wrap items-center gap-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<Input v-model="form.system_notice_days" type="number" class="w-20" min="0" />
|
||||||
|
<span class="text-sm text-muted-foreground">天后清理</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="text-sm text-muted-foreground">或保留最新</span>
|
||||||
|
<Input v-model="form.system_notice_max_count" type="number" class="w-24" min="0" />
|
||||||
|
<span class="text-sm text-muted-foreground">条</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-4 items-center gap-2 sm:gap-4">
|
||||||
|
<Label class="sm:text-right text-muted-foreground">推送日志</Label>
|
||||||
|
<div class="sm:col-span-3 flex flex-wrap items-center gap-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<Input v-model="form.push_log_days" type="number" class="w-20" min="0" />
|
||||||
|
<span class="text-sm text-muted-foreground">天后清理</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="text-sm text-muted-foreground">或保留最新</span>
|
||||||
|
<Input v-model="form.push_log_max_count" type="number" class="w-24" min="0" />
|
||||||
|
<span class="text-sm text-muted-foreground">条</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="pt-6 border-t mt-6">
|
<div class="pt-6 border-t mt-6">
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="flex items-center justify-between mb-4">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
|
|||||||
Reference in New Issue
Block a user