03 · SDD/V · View

View · UI 组件全集

所有前端组件签名 + 路由表 + i18n keys。Coder Agent (fe 类) 读这页能生成全部 Vue 代码。8 个 Vue 组件 + 1 个路由表 + 1 个 i18n key 表。

V-1 · DevLoopDashboard.vue

web/src/views/DevLoopDashboard.vue
// Composition API · setup script
const props = defineProps<{}>();   // 无 props,从 route param 取 pid

const route = useRoute();
const pid    = computed(() => route.params.pid as string);
const state  = ref<ProjectState | null>(null);
const sse    = useEventSource(`/api/devloop/projects/${pid.value}/stream`);
const modalOpen = ref(false);
const drawer  = ref<Unit | null>(null);

// 组件树:
// DashboardHeader → LoopStatusBar → UnitsDAG → LiveAgentStream + PrdDiffPanel
// 浮层:FeedbackModal · UnitDrawer
  • 挂载 5 秒内必须发起 GET /state 请求
  • SSE 断线自动重连(指数退避,最长 30s)
  • 页面卸载时关 SSE

V-2 · DashboardHeader.vue

web/src/components/devloop/DashboardHeader.vue
defineProps<{
  project: { id: string, name: string, status: string }
}>();
defineEmits<{
  feedback: []           // 点击 + NEW REQUIREMENT
}>();

// 渲染:
// - 黑底标题栏
// - 项目名(Fraunces 22px)
// - 右上紫色按钮

V-3 · LoopStatusBar.vue

web/src/components/devloop/LoopStatusBar.vue
defineProps<{
  l1: { passed: number, testing: number, pending: number, failed: number },
  l2: { lastRunAt?: string, status: 'idle'|'running'|'failed'|'shipped', rounds: number },
  l3: { rev: number, awaitingFeedback: boolean }
}>();
  • 三张卡片对应 emerald / amber / violet 三色,CSS 用 --L1/L2/L3 token
  • L2 running 时 amber 卡片有 pulse 动画
  • L3 awaitingFeedback=true 时显示 toast

V-4 · UnitsDAG.vue

web/src/components/devloop/UnitsDAG.vue
defineProps<{
  units: Unit[]
}>();
defineEmits<{
  select: [unit: Unit]
}>();

// 内部使用 SVG <rect> + <line>
// > 50 unit 时切 d3-force 自动布局
  • 节点配色由 unit.status 决定(见 ui-design-system 色板)
  • 节点点击 emit select 事件,父组件打开 UnitDrawer
  • 箭头方向 = depends_on (上游 → 下游)

V-5 · LiveAgentStream.vue

web/src/components/devloop/LiveAgentStream.vue
defineProps<{
  events: AgentStreamEvent[]   // 由父组件从 SSE 过滤 agent.stream 事件
}>();

// 渲染:
// - 黑底 #0E0E10 终端样式
// - 最近 500 行,老的丢
// - PASS / FAIL 着色(绿/橙)
// - 自动滚到底部,除非用户手动滚

V-6 · PrdDiffPanel.vue

web/src/components/devloop/PrdDiffPanel.vue
defineProps<{
  prdHtml: string,
  prevRev: number | null
}>();

// 内部用 diff-dom 客户端算 section 级 diff
// 新增 section 绿色 + 标记 / 删除红色删除线 / 修改黄色

V-7 · FeedbackModal.vue

web/src/components/devloop/FeedbackModal.vue
defineProps<{ open: boolean }>();
defineEmits<{
  submit: [text: string],
  close:  [],
}>();

// 单 textarea + 字数计数 + Ctrl+Enter 提交
// 提交后立即 emit close,父组件负责发请求
  • 空文本 → 提交按钮 disabled
  • > 4000 字 → 警告但不阻止
  • Esc 触发 close

V-8 · UnitDrawer.vue

web/src/components/devloop/UnitDrawer.vue
defineProps<{
  unit: Unit | null,
  runs: RunResult[]      // 最近 3 次 run
}>();
defineEmits<{ close: [] }>();

// 右侧抽屉,从 right 滑入
// 显示:spec.json 摘要 · contract.json · 最近 3 次 run 摘要 · 跳转完整日志按钮

V-9 · 路由表

web/src/router/index.js
// 在现有 routes 数组追加
{
  path:      '/devloop/:pid',
  name:      'DevLoop',
  component: () => import('@/views/DevLoopDashboard.vue'),
  meta:      { requiresAuth: true },
},
{
  path:      '/devloop',                  // 项目列表
  name:      'DevLoopList',
  component: () => import('@/views/DevLoopList.vue'),
}

DevLoopList.vue 在 P4 是可选的,先用 GET /api/devloop/projects 列出。

V-10 · i18n key 清单

web/src/i18n/{zh-CN,en-US,...}/devloop.json
// 每个 locale 一份扁平 JSON:Record<string, string>
{
  "devloop.loop.l1":           "...",
  "devloop.state.pending":     "...",
  "devloop.btn.newRequirement":"..."
  // ...完整 15 个 key 见下表
}
keyzh-CNen-US
devloop.loop.l1单元循环Unit Loop
devloop.loop.l2集成循环Integration Loop
devloop.loop.l3人类反馈Human Feedback
devloop.state.pending待处理Pending
devloop.state.coding编码中Coding
devloop.state.testing测试中Testing
devloop.state.failed失败Failed
devloop.state.passed已通过Passed
devloop.state.blocked阻塞Blocked
devloop.btn.newRequirement+ 新增需求+ New Requirement
devloop.btn.signOff验收Sign-off
devloop.btn.abandon放弃项目Abandon
devloop.toast.shipped项目已交付!Project shipped!
devloop.toast.needHelp需要人工介入Need human help
devloop.empty尚无项目No projects yet

中英文必填,其他 4 种语言可走 fallback。

V-11 · 设计 token(CSS 变量)

web/src/styles/devloop.css
:root {
  --L1: #0E8C5A; --L1-tint: #E2F2EA;
  --L2: #C77C2C; --L2-tint: #F7E8D2;
  --L3: #6E48C3; --L3-tint: #ECE4FB;
  --alert: #C7341A;
}
// 与 LemonBoss 全局 token 共存,前缀避免冲突

组件渲染依赖关系

DevLoopDashboard DashboardHeader LoopStatusBar UnitsDAG LiveAgentStream PrdDiffPanel FeedbackModal (浮层) UnitDrawer (浮层)