diff --git a/web/src/components/graph-console/DispatchTaskButton.vue b/web/src/components/graph-console/DispatchTaskButton.vue
new file mode 100644
index 0000000..fc0077c
--- /dev/null
+++ b/web/src/components/graph-console/DispatchTaskButton.vue
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
diff --git a/web/src/views/GraphConsole.vue b/web/src/views/GraphConsole.vue
index 79cd77b..a68be0d 100644
--- a/web/src/views/GraphConsole.vue
+++ b/web/src/views/GraphConsole.vue
@@ -37,6 +37,19 @@
+
+
+
+
+
+
+
defNodes.value.length > 0);
+/** run 在跑时端点会按 v1 并发约束 409,所以下达入口这时候直接不出现(W14) */
+const ACTIVE_RUN = new Set(['ready', 'running', 'paused', 'blocked']);
+const rootRunActive = computed(() => !!rootRun.value && ACTIVE_RUN.has(rootRun.value.run_status));
const currentRunId = computed(() => (stack.value.length ? stack.value[stack.value.length - 1].runId : null));
const budget = computed(() => rootState.value.budget || null);
const spent = computed(() => budget.value?.spent || {});
@@ -227,6 +244,14 @@ async function onReplanned() {
await Promise.all([loadOrgDef(), loadRuns()]);
}
+/** 下达成功 → 立刻把新 run 拉进来,用户不用手动刷新(W14) */
+async function onDispatched() {
+ orgNode.value = null;
+ selectedNode.value = null;
+ stack.value = [];
+ await loadRuns();
+}
+
function onRootState(s) {
rootState.value = s;
// root run 的 childRuns 就是各 org node 这次跑的 work run。allRuns 只在挂载时拉过一次,
@@ -316,7 +341,13 @@ function fmt(n) { return n == null ? '∞' : Number(n).toLocaleString(); }
.history { display:flex; align-items:center; gap:8px; margin-bottom:8px; font-size:12px; color:#666; }
.history select { font-size:11px; padding:3px 6px; border:1px solid #ddd; border-radius:4px; background:#fff; max-width:100%; }
-.left-actions { display:flex; justify-content:flex-end; margin-bottom:8px; }
+.left-actions {
+ display:flex; gap:6px; flex-wrap:wrap; align-items:flex-start;
+ justify-content:flex-end; margin-bottom:8px; padding:8px 12px 0;
+}
+
+/* 有图未跑:下达任务是这时候唯一该做的事,给它主操作的位置与留白 */
+.dispatch-lead { padding: 10px 12px; border-bottom: 1px solid var(--border-primary); }
/* 左栏空态:控制台在无图公司上唯一能做的事,所以按钮是主操作而不是脚注 */
.org-empty { text-align:center; color:#888; padding:34px 10px; }