refactor(desktop,gateway): 用户端去重 —— 一个功能一个入口,一份数据一个查法

用户反馈「UI 太乱」。数出来的:report/kb/memory 各 4 个入口、studio 5 个;
运行历史两套渲染。乱的机制是同一件事写了两遍,改一处另一处必然掉队。

**一份数据一个查法**
- 工作台「最近任务」和运行页「运行历史」是同一批数据,却各查各的:
  前者走 store.RecentTasks(),后者走 RecentRuns()。于是我给运行历史加的
  topic 字段工作台完全没跟上,还在 mono 显示 report_<hex>;而且 RecentTasks
  没有租户过滤,口径也不一致。现在统一走 RecentRuns,RecentTasks 删掉
  (它只有那一个调用点)。前端 recent_runs 也改用 RunSummary 同一个类型。

**一个功能一个入口**
- 工作台删掉「入库知识/生成报告/管理记忆」按钮排 —— 跳的目标和上面四张
  能力卡片完全重合,同一页给两个入口。
- 「最近任务」现在点击直达运行页对应那条(App 加 goto(view, taskId) →
  RunsView focusTaskId),而不是只把页面切过去让用户自己再找一遍。

**报告归 RUN,只做启动器**
- 报告是「执行」不是「构建」,从 BUILD 组移到 RUN。
- 报告页砍掉「执行轨迹」「报告正文」两个面板 —— 和运行页完全重复,而且
  那套是组件本地 state,切页面就没。现在它只有主题输入框。
- 报告改走 App 的全局运行态(新增 onRunReport,与 onRun 同构、复用 attachRun):
  提交 → 跳「运行 · 观测」→ 实时看轨迹/正文/导出。App 里 onRun 早就写着
  「发起即跳运行页,观测统一收敛在此页」——这条方针一直在,只有报告没遵守。

**顺带清死代码**
- 市场(规划中)从导航下架,ViewKey 里的 "market" 和 Boxes 图标一并删。
- PLACEHOLDERS 整块死代码:它列的 home/kb/report/runs 全都早已真实实现,
  market 是唯一还可能用到的、下架后那个 Placeholder 分支永远走不到
  (tsc 报 "Spread types" 就是因为 PLACEHOLDERS[view] 已成 never)。
  连同 views/Placeholder.tsx 一起删。

live 验证(真账号,桌面端实机):报告页输入主题 → 提交 → 自动跳运行页 →
顶部「当前运行 · live」→ 轨迹实时跑 → 报告正文流式出 + 导出按钮在位 →
report_7a0110a10b534f90 落库带 topic「归口测试」,POST /api/v1/reports → 202。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-07-16 14:08:16 +08:00
parent fd99ba6226
commit 759483bf92
9 changed files with 110 additions and 212 deletions
@@ -453,13 +453,10 @@ func (h *Handler) StatsOverview(c *gin.Context) {
})
}
// 近期运行 feed。
recent := make([]gin.H, 0, 8)
for _, t := range h.db.RecentTasks(ctx, uid, 8) {
recent = append(recent, gin.H{
"task_id": t.TaskID, "status": t.Status, "detail": t.Detail, "at": t.CreatedAt,
})
}
// 近期运行 feed —— 与「运行」页的运行历史共用 RecentRuns,同一份数据不能有两个查法
// 此前这里走 RecentTasks(),于是运行历史加了 topic 字段、工作台完全没跟上,
// 还在显示 report_<hex>;而且 RecentTasks 没有租户过滤,口径也不一致。
recent := h.db.RecentRuns(ctx, uid, 8)
// 服务健康(与 Health 同口径:本地可判 + milvus/neo4j 经 mcp-go)。
services := gin.H{"gateway": true, "nats": true, "db": h.db.Enabled(), "redis": h.cache.Enabled(), "milvus": false, "neo4j": false}
+3 -14
View File
@@ -275,19 +275,8 @@ func (p *Postgres) StatsOverview(ctx context.Context, owner string) *Overview {
return o
}
// RecentTasks 返回最近 n 条任务(工作台「近期运行」feed)。
// RecentTasks 返回某用户最近 n 条任务(个人工作台「近期运行」feed)。
// owner 过滤"我的运行";tenant 由插件自动叠加(双保险:跨用户/跨租户都隔离)。
func (p *Postgres) RecentTasks(ctx context.Context, owner string, n int) []Task {
if p.db == nil {
return nil
}
var out []Task
p.db.WithContext(ctx).Where("owner = ?", owner).Order("created_at desc").Limit(n).Find(&out)
return out
}
// RunRow 是「运行历史」一行:任务 + 其评测(LEFT JOIN,未评则 level 空)。
// 工作台「最近任务」与「运行」页共用它 —— 同一份数据只能有一个查法。
type RunRow struct {
TaskID string `json:"task_id"`
Status string `json:"status"`
@@ -308,8 +297,8 @@ func (p *Postgres) RecentRuns(ctx context.Context, owner string, n int) []RunRow
}
var out []RunRow
q := p.db.WithContext(ctx).Table("sundynix_task as t").
Select("t.task_id, t.status, t.detail, t.created_at as at, " +
"coalesce(e.level,'') as eval_level, coalesce(e.overall,0) as eval_overall, " +
Select("t.task_id, t.status, t.detail, t.created_at as at, "+
"coalesce(e.level,'') as eval_level, coalesce(e.overall,0) as eval_overall, "+
"coalesce(t.graph->>'topic','') as topic").
Joins("left join sundynix_eval e on e.task_id = t.task_id").
Where("t.deleted_at is null AND t.owner = ?", owner)