feat: Implement core backend API server, S2A integration, auto-add service, and a new monitoring page.
This commit is contained in:
@@ -78,9 +78,8 @@ func main() {
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
// 启动自动补号服务
|
||||
// 启动自动补号检查器(需在前端开启开关才会实际补号)
|
||||
api.StartAutoAddService()
|
||||
fmt.Printf("%s[服务]%s 自动补号服务已启动\n", colorGreen, colorReset)
|
||||
|
||||
// 启动服务器
|
||||
startServer(cfg)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 : '获取账号列表失败'
|
||||
|
||||
@@ -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">
|
||||
<AlertTriangle className="h-3 w-3" />
|
||||
低于目标
|
||||
</p>
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user