feat(board): 卡片标机制标签 loop/图(用户:怎区分那个项目是 loop 机制 那个是图机制)

This commit is contained in:
admin committed 2026-10-19 22:40:02 +08:00
1 parent efbe128670
commit d662a38944
2 files changed
+36 -2

No files matched your search

@@ -282,6 +282,9 @@
.gchip.gst-gating { border-color: #b48bff; background: rgba(180,139,255,.16); } .gchip.gst-gating { border-color: #b48bff; background: rgba(180,139,255,.16); }
.gchip.gst-skipped, .gchip.gst-cancelled { opacity: .45; } .gchip.gst-skipped, .gchip.gst-cancelled { opacity: .45; }
.gempty { opacity: .55; font-size: 12px; padding: 6px 0; } .gempty { opacity: .55; font-size: 12px; padding: 6px 0; }
/* 机制标签(卡片上):loop=现有项目机制,图=图模式有图 */
.badge.mech-loop { background: rgba(255,255,255,.10); border: 1px solid rgba(255,255,255,.30); }
.badge.mech-graph { background: rgba(180,139,255,.18); border: 1px solid #b48bff; color: #e8dcff; }
</style> </style>
<main> <main>
@@ -497,7 +500,18 @@ function _cardHtml(t){
? '<div class="wsrow"><span class="wsname">'+esc(t._ws)+'</span>'+ ? '<div class="wsrow"><span class="wsname">'+esc(t._ws)+'</span>'+
(t._self ? '<span class="wsself">本工作区</span>' : '')+'</div>' (t._self ? '<span class="wsself">本工作区</span>' : '')+'</div>'
: ''; : '';
var badges = '<span class="badge">'+esc(t.life||"")+'</span>'; var badges = '';
// 🔴 机制标签先出(用户 2026-10-19:「怎区分那个项目是 loop 机制 那个是 图机制」):
// loop = 现有项目机制那套(目标+排队+检查会话推进);图 = `.workbuddy/graph/` 里有图。
// 两套并存就两个都挂 —— 图模式本来就是并列机制,⛔ 不逼它二选一。
(t._mech || []).forEach(function(m){
var cls = (m === '图') ? 'mech-graph' : 'mech-loop';
var tip = (m === '图')
? ('图模式:.workbuddy/graph 下有 ' + (t._gcount || 0) + ' 张图')
: 'loop 机制:目标登记 + 协作队列 + 检查会话推进';
badges += '<span class="badge ' + cls + '" title="' + esc(tip) + '">' + esc(m) + '</span>';
});
badges += '<span class="badge">'+esc(t.life||"")+'</span>';
if(t.current) badges += '<span class="badge cur">当前</span>'; if(t.current) badges += '<span class="badge cur">当前</span>';
// 🔴 2026-10-18:目标「状态未收口」明说(后端判据:非已完成 且 无判据/判据全未过) // 🔴 2026-10-18:目标「状态未收口」明说(后端判据:非已完成 且 无判据/判据全未过)
if(t.warn) badges += '<span class="badge miss" title="'+esc(t.warn)+'">'+esc(t.warn)+'</span>'; if(t.warn) badges += '<span class="badge miss" title="'+esc(t.warn)+'">'+esc(t.warn)+'</span>';
@@ -537,6 +551,9 @@ function _collectCards(){
x._goal = p.name; // 目标短名(⛔ 不上卡片标签,仅供详情/排查) x._goal = p.name; // 目标短名(⛔ 不上卡片标签,仅供详情/排查)
x._self = !!p.self; // 🔴 本工作区 ⇒ 卡片换色突出 x._self = !!p.self; // 🔴 本工作区 ⇒ 卡片换色突出
x._life = p.life || ""; x._life = p.life || "";
// 🔴 机制标签(loop/图):跟着**工作区**走,不跟目标走 —— 同一区里所有卡片一样
x._mech = (p.mech && p.mech.labels) || [];
x._gcount = (p.mech && p.mech.graph_count) || 0;
out.push(x); out.push(x);
}); });
}); });
@@ -842,7 +859,8 @@ function paintGraphs(){
return; return;
} }
var h = ['<div class="ghead">图模式<span class="gsub">' var h = ['<div class="ghead">图模式<span class="gsub">'
+ rows.length + ' 张图 · 胶囊上的粗体是节点类型,颜色是状态</span></div>']; + rows.length + ' 张图 · 胶囊上的粗体是节点类型,颜色是状态'
+ ' · 卡片上的 <b>loop</b> = 目标队列推进、<b>图</b> = 本区有图</span></div>'];
rows.forEach(function(r){ rows.forEach(function(r){
var g = r.g, p = r.p; var g = r.g, p = r.p;
h.push('<div class="gcard"><div class="gttl">' + esc(g.title) h.push('<div class="gcard"><div class="gttl">' + esc(g.title)
@@ -432,6 +432,20 @@ def graph_view(ws: Path) -> dict:
return {"graphs": graphs, "count": len(graphs), "dir": str(base).replace("\\", "/")} return {"graphs": graphs, "count": len(graphs), "dir": str(base).replace("\\", "/")}
def mech_view(ws: Path, goal: dict, tasks: dict, st: dict) -> dict:
"""这个工作区在跑哪套机制(用户 2026-10-19:「怎区分那个项目是 loop 机制 那个是 图机制」)。
· `loop` = 现有项目机制那套(有目标登记/台账/协作状态 ⇒ 目标是靠「队列+检查会话」推进的)
· `图` = 图模式那套(`.workbuddy/graph/<gid>/` 下有图)
两套并存 ⇒ 两个标签都给(图模式本来就是并列的,⛔ 不强行二选一)。
"""
gv = graph_view(ws)
loop = bool(str(goal.get("title") or "").strip() or tasks or st)
labels = (["loop"] if loop else []) + (["图"] if gv["count"] else [])
return {"loop": loop, "graph": gv["count"], "labels": labels,
"graph_count": gv["count"]}
def build_project(ws: Path) -> dict: def build_project(ws: Path) -> dict:
"""把**一个工作区**读成「项目」(纯读,⛔ 不写任何东西)。""" """把**一个工作区**读成「项目」(纯读,⛔ 不写任何东西)。"""
inbox = ws / "tmp" / "supervise-inbox" inbox = ws / "tmp" / "supervise-inbox"
@@ -624,6 +638,8 @@ def build_project(ws: Path) -> dict:
"life_unknown": life_unknown, "life_unknown": life_unknown,
# 🔴 图模式快照(只读):`<ws>/.workbuddy/graph/*/graph.json` ⇒ 前端「图模式」块 # 🔴 图模式快照(只读):`<ws>/.workbuddy/graph/*/graph.json` ⇒ 前端「图模式」块
"graph": graph_view(ws), "graph": graph_view(ws),
# 🔴 机制标签:loop(目标+队列)/图(图模式)
"mech": mech_view(ws, goal, tasks, st),
"acc": {"n": len(eff), "pass": acc_pass, "items": acc_items}, "acc": {"n": len(eff), "pass": acc_pass, "items": acc_items},
"region": str(_region_dir(ws, goal)).replace("\\", "/"), "region": str(_region_dir(ws, goal)).replace("\\", "/"),
"port": cfg.get("singleton_port"), "port": cfg.get("singleton_port"),