7da5124067
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
Pinia Stores Documentation
This directory contains all Pinia stores for the Sub2API frontend application.
Stores Overview
1. Auth Store (auth.ts)
Manages user authentication state, login/logout, and token persistence.
State:
user: User | null- Current authenticated usertoken: string | null- JWT authentication token
Computed:
isAuthenticated: boolean- Whether user is currently authenticated
Actions:
login(credentials)- Authenticate user with username/passwordregister(userData)- Register new user accountlogout()- Clear authentication and logoutcheckAuth()- Restore session from localStoragerefreshUser()- Fetch latest user data from server
2. App Store (app.ts)
Manages global UI state including sidebar, loading indicators, and toast notifications.
State:
sidebarCollapsed: boolean- Sidebar collapsed stateloading: boolean- Global loading statetoasts: Toast[]- Active toast notifications
Computed:
hasActiveToasts: boolean- Whether any toasts are active
Actions:
toggleSidebar()- Toggle sidebar statesetSidebarCollapsed(collapsed)- Set sidebar state explicitlysetLoading(isLoading)- Set loading stateshowToast(type, message, duration?)- Show toast notificationshowSuccess(message, duration?)- Show success toastshowError(message, duration?)- Show error toastshowInfo(message, duration?)- Show info toastshowWarning(message, duration?)- Show warning toasthideToast(id)- Hide specific toastclearAllToasts()- Clear all toastswithLoading(operation)- Execute async operation with loading statewithLoadingAndError(operation, errorMessage?)- Execute with loading and error handlingreset()- Reset store to defaults
Usage Examples
Auth Store
import { useAuthStore } from '@/stores'
// In component setup
const authStore = useAuthStore()
// Initialize on app startup
authStore.checkAuth()
// Login
try {
await authStore.login({ username: 'user', password: 'pass' })
console.log('Logged in:', authStore.user)
} catch (error) {
console.error('Login failed:', error)
}
// Check authentication
if (authStore.isAuthenticated) {
console.log('User is logged in:', authStore.user?.username)
}
// Logout
authStore.logout()
App Store
import { useAppStore } from '@/stores'
// In component setup
const appStore = useAppStore()
// Sidebar control
appStore.toggleSidebar()
appStore.setSidebarCollapsed(true)
// Loading state
appStore.setLoading(true)
// ... do work
appStore.setLoading(false)
// Or use helper
await appStore.withLoading(async () => {
const data = await fetchData()
return data
})
// Toast notifications
appStore.showSuccess('Operation completed!')
appStore.showError('Something went wrong!', 5000)
appStore.showInfo('FYI: This is informational')
appStore.showWarning('Be careful!')
// Custom toast
const toastId = appStore.showToast('info', 'Custom message', undefined) // No auto-dismiss
// Later...
appStore.hideToast(toastId)
Combined Usage in Vue Component
<script setup lang="ts">
import { useAuthStore, useAppStore } from '@/stores'
import { onMounted } from 'vue'
const authStore = useAuthStore()
const appStore = useAppStore()
onMounted(() => {
// Check for existing session
authStore.checkAuth()
})
async function handleLogin(username: string, password: string) {
try {
await appStore.withLoading(async () => {
await authStore.login({ username, password })
})
appStore.showSuccess('Welcome back!')
} catch (error) {
appStore.showError('Login failed. Please check your credentials.')
}
}
async function handleLogout() {
authStore.logout()
appStore.showInfo('You have been logged out.')
}
</script>
<template>
<div>
<button @click="appStore.toggleSidebar">Toggle Sidebar</button>
<div v-if="appStore.loading">Loading...</div>
<div v-if="authStore.isAuthenticated">
Welcome, {{ authStore.user?.username }}!
<button @click="handleLogout">Logout</button>
</div>
<div v-else>
<button @click="handleLogin('user', 'pass')">Login</button>
</div>
</div>
</template>
Persistence
- Auth Store: Token and user data are automatically persisted to
localStorage- Keys:
auth_token,auth_user - Restored on
checkAuth()call
- Keys:
- App Store: No persistence (UI state resets on page reload)
TypeScript Support
All stores are fully typed with TypeScript. Import types from @/types:
import type { User, Toast, ToastType } from '@/types'
Testing
Stores can be reset to initial state:
// Auth store
authStore.logout() // Clears all auth state
// App store
appStore.reset() // Resets to defaults