373167b705
对照已实现系统功能补 admin 缺失模块(feat/site): - 全平台任务/运行观测:GET /admin/tasks(跨租户查 sundynix_task,join 租户名/提交人邮箱/评测, 按状态/租户筛 + 状态计数;含 HITL 待审批=筛 waiting)+ TasksPage(状态卡+筛+表)。 - 空间(Space)管理:GET /admin/spaces(跨租户列 Space + 成员数子查询 + kind/归档态)+ SpacesPage。 - 基建观测:infra 加 MinIO(126 对象存储);postgres/redis/minio 从启动标志升级为实时 ping (blob.Ping/Postgres.Ping/Redis.Ping),能反映中途掉线。StatusPage 加 minio 标签、6 个依赖。 - 模型健康/熔断:确认 DashboardPage 已有「运行时链路态」渲染 m.health,无需重做。 验证:admin tsc + vitest 41 过、gateway build/vet/test 过;两新页浏览器实测渲染+优雅错误处理; 两新端点起临时 gateway 打真 PG 实测——tasks(counts+3路join)、spaces(成员数子查询)均返真数据。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
76 lines
2.5 KiB
Go
76 lines
2.5 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
)
|
|
|
|
// 全平台任务观测(管理端「运行观测」页)。系统级口径:跨租户看所有任务,
|
|
// 故走 WithoutTenant 旁路租户插件 + raw Table 查询(同 RecentRuns 手动控制过滤)。
|
|
|
|
// AdminTaskRow 是管理端任务流一行:任务 + 租户名 + 提交人邮箱 + 评测分级(LEFT JOIN)。
|
|
type AdminTaskRow struct {
|
|
TaskID string `json:"task_id"`
|
|
TenantID string `json:"tenant_id"`
|
|
TenantName string `json:"tenant_name"`
|
|
Owner string `json:"owner"`
|
|
OwnerEmail string `json:"owner_email"`
|
|
Status string `json:"status"`
|
|
Detail string `json:"detail"`
|
|
Topic string `json:"topic"`
|
|
At time.Time `json:"at"`
|
|
EvalLevel string `json:"eval_level"`
|
|
EvalOverall float64 `json:"eval_overall"`
|
|
}
|
|
|
|
// AllTasks 全平台任务流(管理端观测;可按状态/租户过滤)。倒序,翻页。
|
|
// status 空=全部;tenantID 空=全租户。
|
|
func (p *Postgres) AllTasks(ctx context.Context, status, tenantID string, limit int) []AdminTaskRow {
|
|
if p.db == nil {
|
|
return nil
|
|
}
|
|
if limit <= 0 || limit > 200 {
|
|
limit = 50
|
|
}
|
|
ctx = WithoutTenant(ctx) // 系统级:看所有租户的任务
|
|
q := p.db.WithContext(ctx).Table("sundynix_task as t").
|
|
Select("t.task_id, t.tenant_id, t.owner, t.status, t.detail, t.created_at as at, " +
|
|
"coalesce(tn.name,'') as tenant_name, coalesce(u.email,'') as owner_email, " +
|
|
"coalesce(e.level,'') as eval_level, coalesce(e.overall,0) as eval_overall, " +
|
|
"coalesce(t.graph->>'topic','') as topic").
|
|
Joins("left join sundynix_tenant tn on tn.id = t.tenant_id").
|
|
Joins("left join sundynix_user u on u.id = t.owner").
|
|
Joins("left join sundynix_eval e on e.task_id = t.task_id").
|
|
Where("t.deleted_at is null")
|
|
if status != "" {
|
|
q = q.Where("t.status = ?", status)
|
|
}
|
|
if tenantID != "" {
|
|
q = q.Where("t.tenant_id = ?", tenantID)
|
|
}
|
|
var out []AdminTaskRow
|
|
q.Order("t.created_at desc").Limit(limit).Scan(&out)
|
|
return out
|
|
}
|
|
|
|
// TaskStatusCounts 全平台任务按状态计数(观测页的筛选标签 + 分布)。
|
|
func (p *Postgres) TaskStatusCounts(ctx context.Context) map[string]int64 {
|
|
out := map[string]int64{}
|
|
if p.db == nil {
|
|
return out
|
|
}
|
|
ctx = WithoutTenant(ctx)
|
|
var rows []struct {
|
|
Status string
|
|
N int64
|
|
}
|
|
p.db.WithContext(ctx).Table("sundynix_task").
|
|
Select("status, count(*) as n").
|
|
Where("deleted_at is null").
|
|
Group("status").Scan(&rows)
|
|
for _, r := range rows {
|
|
out[r.Status] = r.N
|
|
}
|
|
return out
|
|
}
|