feat(channel-monitor): add feature switch settings + fix extra_models save

Settings:
- New "功能开关" tab between 通用设置 and 安全与认证
- ChannelMonitorEnabled toggle: runner skips scheduling when false,
  user-facing list returns empty
- ChannelMonitorDefaultIntervalSeconds (15-3600): pre-fills interval
  when creating a new monitor; each monitor can still override

Bug fix:
- ModelTagInput now commits pending input on blur, not just Enter/Tab.
  Previously clicking "save" with an un-Enter'd extra model would drop
  the value (DB stored extra_models=[] even when user typed entries).

Backend:
- domain_constants: SettingKeyChannelMonitor{Enabled,DefaultIntervalSeconds}
- SettingService.GetChannelMonitorRuntime: lightweight getter used by
  runner tick + user handler per-request (fail-open on DB error)
- Runner tickDueChecks: bails early when feature disabled
- ChannelMonitorUserHandler: checks feature flag before serving
- Comment on runner doc: scheduler state is implicit (every tick re-reads
  ListEnabled from DB), so CRUD ops on monitors self-maintain the schedule

Bump VERSION to 0.1.114.25
This commit is contained in:
erio
2026-04-21 00:21:29 +08:00
parent a1425b457d
commit 7da5124067
18 changed files with 283 additions and 14 deletions

View File

@@ -143,6 +143,13 @@ const emit = defineEmits<{
const { t } = useI18n()
const appStore = useAppStore()
// System-configured default interval for new monitors. Falls back to the static
// constant when public settings haven't loaded yet or store the legacy 0 value.
const systemDefaultInterval = computed<number>(() => {
const configured = appStore.cachedPublicSettings?.channel_monitor_default_interval_seconds
return configured && configured > 0 ? configured : DEFAULT_INTERVAL_SECONDS
})
// editing is true when we have an existing monitor
const editing = computed<ChannelMonitor | null>(() => props.monitor)
@@ -173,7 +180,7 @@ const form = reactive<MonitorForm>({
primary_model: '',
extra_models: [],
group_name: '',
interval_seconds: DEFAULT_INTERVAL_SECONDS,
interval_seconds: systemDefaultInterval.value,
enabled: true,
})
@@ -191,7 +198,7 @@ function resetForm() {
form.primary_model = ''
form.extra_models = []
form.group_name = ''
form.interval_seconds = DEFAULT_INTERVAL_SECONDS
form.interval_seconds = systemDefaultInterval.value
form.enabled = true
}
@@ -203,7 +210,7 @@ function loadFromMonitor(m: ChannelMonitor) {
form.primary_model = m.primary_model
form.extra_models = [...(m.extra_models || [])]
form.group_name = m.group_name || ''
form.interval_seconds = m.interval_seconds || DEFAULT_INTERVAL_SECONDS
form.interval_seconds = m.interval_seconds || systemDefaultInterval.value
form.enabled = m.enabled
}