feat: Implement core backend API server, S2A integration, auto-add service, and a new monitoring page.

This commit is contained in:
2026-01-30 19:26:33 +08:00
parent 364b393bc6
commit d73ca4c6ff
4 changed files with 36 additions and 20 deletions

View File

@@ -78,9 +78,8 @@ func main() {
}
fmt.Println()
// 启动自动补号服务
// 启动自动补号检查器(需在前端开启开关才会实际补号)
api.StartAutoAddService()
fmt.Printf("%s[服务]%s 自动补号服务已启动\n", colorGreen, colorReset)
// 启动服务器
startServer(cfg)

View File

@@ -19,7 +19,7 @@ var (
lastAutoAddTime time.Time
)
// StartAutoAddService 启动自动补号服务
// StartAutoAddService 启动自动补号服务(后台检查器)
func StartAutoAddService() {
autoAddMu.Lock()
if autoAddRunning {
@@ -30,7 +30,8 @@ func StartAutoAddService() {
autoAddStopChan = make(chan struct{})
autoAddMu.Unlock()
logger.Info("自动补号服务已启动", "", "auto-add")
// 注意:这只是启动后台检查器,实际补号需要前端开启开关
logger.Info("自动补号检查器已启动(需在前端开启开关)", "", "auto-add")
go func() {
ticker := time.NewTicker(60 * time.Second) // 每分钟检查一次
@@ -39,7 +40,7 @@ func StartAutoAddService() {
for {
select {
case <-autoAddStopChan:
logger.Info("自动补号服务已停止", "", "auto-add")
logger.Info("自动补号检查器已停止", "", "auto-add")
return
case <-ticker.C:
checkAndAutoAdd()

View File

@@ -45,20 +45,34 @@ export function useS2AApi() {
// 兼容不同的响应格式
// 格式1: { data: [...], total: N }
// 格式2: { list: [...], total: N }
// 格式3: 直接是数组 [...]
// 格式2: { items: [...], total: N } ← S2A 实际使用这个
// 格式3: { list: [...], total: N }
// 格式4: 直接是数组 [...]
let accounts: S2AAccount[] = []
let total = 0
const res = response as unknown as {
data?: S2AAccount[]
items?: S2AAccount[]
list?: S2AAccount[]
total?: number
page?: number
page_size?: number
}
if (Array.isArray(response)) {
accounts = response as unknown as S2AAccount[]
total = accounts.length
} else if (response.data && Array.isArray(response.data)) {
accounts = response.data
total = response.total || accounts.length
} else if ((response as unknown as { list: S2AAccount[] }).list) {
accounts = (response as unknown as { list: S2AAccount[] }).list
total = response.total || accounts.length
} else if (res.items && Array.isArray(res.items)) {
// S2A API 使用 items 字段
accounts = res.items
total = res.total || accounts.length
} else if (res.data && Array.isArray(res.data)) {
accounts = res.data
total = res.total || accounts.length
} else if (res.list && Array.isArray(res.list)) {
accounts = res.list
total = res.total || accounts.length
}
console.log('Parsed accounts:', accounts.length, 'total:', total)
@@ -66,9 +80,9 @@ export function useS2AApi() {
return {
data: accounts,
total: total,
page: response.page || 1,
page_size: response.page_size || 20,
total_pages: Math.ceil(total / (response.page_size || 20)),
page: res.page || 1,
page_size: res.page_size || 20,
total_pages: Math.ceil(total / (res.page_size || 20)),
}
} catch (err) {
const message = err instanceof Error ? err.message : '获取账号列表失败'

View File

@@ -419,10 +419,12 @@ export default function Monitor() {
</div>
</div>
{deficit > 0 && (
<p className="mt-2 text-xs text-orange-500 flex items-center gap-1">
<div className="mt-2 space-y-1">
<p className="text-xs text-orange-500 flex items-center gap-1">
<AlertTriangle className="h-3 w-3" />
{Math.ceil(deficit / 4)} Team
</p>
</div>
)}
</CardContent>
</Card>