style(web): status 徽章默认态静默——active 不挂徽章,终态行淡化(bump 0.38.6)
「进行中」徽章与运行圆点语义撞车,且列表主体都是 active,重复徽章是零信息 噪音。改为:active 不渲染徽章(列表 + chat-meta 同规则),completed/abandoned 保留徽章且整行淡化(st-* class,hover 恢复),脉冲圆点成为唯一动效信号。 删不再渲染的 .badge.active CSS。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
7e6159af48
commit
2937b75143
|
|
@ -21,6 +21,9 @@
|
||||||
|
|
||||||
## 已完成关键能力
|
## 已完成关键能力
|
||||||
|
|
||||||
|
### 2026-07-03 / web status 徽章改"默认态静默"——active 不挂徽章,终态行淡化(bump 0.38.6)
|
||||||
|
运行圆点落地后暴露 status 徽章两问题:「进行中」(生命周期 active)与「运行中」(run_status)语义撞车;列表主体都是 active,每行重复挂蓝徽章是零信息噪音、还占 meta 行首槽。设计原则定为**默认态静默、例外态着色、瞬时态用动效**:active 不再渲染徽章(列表行 + 中栏 chat-meta 同规则,chat-meta 终态徽章保留兼解释"输入框为什么消失");completed/abandoned 徽章保留且整行淡化(`st-*` class,opacity .68,hover 恢复——st- 前缀防撞选中态 .task-row.active);绿脉冲点成为唯一动效信号,与生命周期解耦。筛选下拉「进行中」文案不动(筛选语境无歧义)。顺手删掉不再被渲染的 `.badge.active` CSS。改 `web/static/js/chat.js` + `web/static/dev.html`。
|
||||||
|
|
||||||
### 2026-07-03 / web 运行态标识精简为纯脉冲圆点(bump 0.38.5)
|
### 2026-07-03 / web 运行态标识精简为纯脉冲圆点(bump 0.38.5)
|
||||||
用户反馈「运行中」等文字让列表 meta 行太拥挤。标识收成一个 7px 带色脉冲圆点(绿=运行中/橙=停止中/红=出错),文案全部移进 hover title(error 仍带 run_error 详情);圆点在 baseline 对齐的 meta 行里补 `align-self:center`。改 `web/static/js/chat.js` + `web/static/dev.html`。
|
用户反馈「运行中」等文字让列表 meta 行太拥挤。标识收成一个 7px 带色脉冲圆点(绿=运行中/橙=停止中/红=出错),文案全部移进 hover title(error 仍带 run_error 详情);圆点在 baseline 对齐的 meta 行里补 `align-self:center`。改 `web/static/js/chat.js` + `web/static/dev.html`。
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
|
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
|
||||||
# 改版本只动这一行。
|
# 改版本只动这一行。
|
||||||
__version__ = "0.38.5"
|
__version__ = "0.38.6"
|
||||||
|
|
|
||||||
|
|
@ -570,9 +570,12 @@
|
||||||
.run-ind .run-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
|
.run-ind .run-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
|
||||||
.run-ind.running .run-dot, .run-ind.cancelling .run-dot { animation: run-pulse 1.2s ease-in-out infinite; }
|
.run-ind.running .run-dot, .run-ind.cancelling .run-dot { animation: run-pulse 1.2s ease-in-out infinite; }
|
||||||
@keyframes run-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
|
@keyframes run-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
|
||||||
|
/* 生命周期徽章只渲终态(active 静默,见 renderTaskList/renderChatMeta);终态行整体淡化,
|
||||||
|
开放任务自然浮起,hover 恢复全亮便于读 meta */
|
||||||
.badge.completed { background: var(--c-green-bg); color: var(--c-green); }
|
.badge.completed { background: var(--c-green-bg); color: var(--c-green); }
|
||||||
.badge.abandoned { background: var(--accent-soft); color: var(--accent); }
|
.badge.abandoned { background: var(--accent-soft); color: var(--accent); }
|
||||||
.badge.active { background: #eef; color: #336; }
|
.task-row.st-completed, .task-row.st-abandoned { opacity: .68; }
|
||||||
|
.task-row.st-completed:hover, .task-row.st-abandoned:hover { opacity: 1; }
|
||||||
/* 微信渠道专属:品牌绿徽章(白字 + 内嵌微信图标),与蓝灰状态徽章拉开区分 */
|
/* 微信渠道专属:品牌绿徽章(白字 + 内嵌微信图标),与蓝灰状态徽章拉开区分 */
|
||||||
.badge.wx { background: #07C160; color: #fff; display: inline-flex; align-items: center;
|
.badge.wx { background: #07C160; color: #fff; display: inline-flex; align-items: center;
|
||||||
gap: 3px; vertical-align: 1px; }
|
gap: 3px; vertical-align: 1px; }
|
||||||
|
|
|
||||||
|
|
@ -182,24 +182,28 @@ function renderTaskList(tasks, append = false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (append && !tasks.length) return; // 末页空 batch,不动 DOM
|
if (append && !tasks.length) return; // 末页空 batch,不动 DOM
|
||||||
const statusLabels = { active: "进行中", completed: "已完成", abandoned: "已废弃" };
|
// 默认态静默:active 不挂徽章(列表主体都是 active,重复徽章是纯噪音),
|
||||||
|
// 终态(completed/abandoned)才着色 + 整行淡化(st-* class),瞬时态交给运行圆点
|
||||||
|
const statusLabels = { completed: "已完成", abandoned: "已废弃" };
|
||||||
const html = tasks.map((t) => {
|
const html = tasks.map((t) => {
|
||||||
const active = state.taskId === t.task_id ? " active" : "";
|
const active = state.taskId === t.task_id ? " active" : "";
|
||||||
// 主行 = 任务名(必填字段);副行 = 工作目录 + description(都按需显示)
|
// 主行 = 任务名(必填字段);副行 = 工作目录 + description(都按需显示)
|
||||||
const taskName = t.name || "(未命名)";
|
const taskName = t.name || "(未命名)";
|
||||||
const wdName = t.working_dir ? t.working_dir.split("/").filter(Boolean).pop() : "";
|
const wdName = t.working_dir ? t.working_dir.split("/").filter(Boolean).pop() : "";
|
||||||
const desc = t.description || "";
|
const desc = t.description || "";
|
||||||
const statusLabel = statusLabels[t.status] || t.status;
|
const statusLabel = statusLabels[t.status] || "";
|
||||||
|
// st- 前缀防撞 .task-row.active(选中态)——status 值 "active" 不能直接当 class 用
|
||||||
|
const stCls = statusLabel ? ` st-${t.status}` : "";
|
||||||
const rowTitle = `${taskName}\n${t.task_id}`; // hover 出全名 + 完整 id(替代 meta 里被去掉的 id8)
|
const rowTitle = `${taskName}\n${t.task_id}`; // hover 出全名 + 完整 id(替代 meta 里被去掉的 id8)
|
||||||
// 渠道镜像 task(微信 / 企业微信)不进此列表 —— 后端 /v1/tasks 已排除,改由左栏卡片承载(loadChannelCards)
|
// 渠道镜像 task(微信 / 企业微信)不进此列表 —— 后端 /v1/tasks 已排除,改由左栏卡片承载(loadChannelCards)
|
||||||
return `
|
return `
|
||||||
<div class="task-row${active}" data-tid="${t.task_id}" title="${escapeHtml(rowTitle)}" style="display:flex;align-items:flex-start;gap:6px;">
|
<div class="task-row${active}${stCls}" data-tid="${t.task_id}" title="${escapeHtml(rowTitle)}" style="display:flex;align-items:flex-start;gap:6px;">
|
||||||
<div style="flex:1;min-width:0;">
|
<div style="flex:1;min-width:0;">
|
||||||
<div class="desc">${escapeHtml(taskName)}</div>
|
<div class="desc">${escapeHtml(taskName)}</div>
|
||||||
${wdName ? `<div class="meta muted" title="${escapeHtml(t.working_dir || "")}" style="display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">📁 ${escapeHtml(wdName)}</div>` : ""}
|
${wdName ? `<div class="meta muted" title="${escapeHtml(t.working_dir || "")}" style="display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">📁 ${escapeHtml(wdName)}</div>` : ""}
|
||||||
${desc ? `<div class="meta muted" title="${escapeHtml(desc)}" style="display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${escapeHtml(desc)}</div>` : ""}
|
${desc ? `<div class="meta muted" title="${escapeHtml(desc)}" style="display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${escapeHtml(desc)}</div>` : ""}
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
<span class="badge ${t.status}">${statusLabel}</span>
|
${statusLabel ? `<span class="badge ${t.status}">${statusLabel}</span>` : ""}
|
||||||
${runIndicatorHtml(t)}
|
${runIndicatorHtml(t)}
|
||||||
${t.skill ? `<span class="muted" title="${escapeHtml(t.skill)}">${escapeHtml(t.skill)}</span>` : ""}
|
${t.skill ? `<span class="muted" title="${escapeHtml(t.skill)}">${escapeHtml(t.skill)}</span>` : ""}
|
||||||
<span class="num right-group">${t.n_messages || 0} 条</span>
|
<span class="num right-group">${t.n_messages || 0} 条</span>
|
||||||
|
|
@ -468,7 +472,8 @@ function renderChatMeta() {
|
||||||
if (!t) { $("chat-meta").innerHTML = `<span class="muted">(未选中任务)</span>`; return; }
|
if (!t) { $("chat-meta").innerHTML = `<span class="muted">(未选中任务)</span>`; return; }
|
||||||
const wdName = t.working_dir ? t.working_dir.split("/").filter(Boolean).pop() : "";
|
const wdName = t.working_dir ? t.working_dir.split("/").filter(Boolean).pop() : "";
|
||||||
const taskName = t.name || "(未命名)";
|
const taskName = t.name || "(未命名)";
|
||||||
const statusLabel = { active: "进行中", completed: "已完成", abandoned: "已废弃" }[t.status] || t.status;
|
// 同列表规则:active 静默,终态才挂徽章(它同时解释"输入框为什么消失了")
|
||||||
|
const statusLabel = { completed: "已完成", abandoned: "已废弃" }[t.status] || "";
|
||||||
// wdName 与 taskName 相同时(留空 fallback,多数场景)不重复显示 📁;
|
// wdName 与 taskName 相同时(留空 fallback,多数场景)不重复显示 📁;
|
||||||
// 不同时(用户显式指定共享目录 / 改了 name)才挂 📁,提示"项目归属"
|
// 不同时(用户显式指定共享目录 / 改了 name)才挂 📁,提示"项目归属"
|
||||||
const wdBadge = (wdName && wdName !== taskName)
|
const wdBadge = (wdName && wdName !== taskName)
|
||||||
|
|
@ -476,7 +481,7 @@ function renderChatMeta() {
|
||||||
: "";
|
: "";
|
||||||
$("chat-meta").innerHTML = `
|
$("chat-meta").innerHTML = `
|
||||||
<span style="font-weight:600;" title="${escapeHtml(taskName)}">${escapeHtml(taskName)}</span>
|
<span style="font-weight:600;" title="${escapeHtml(taskName)}">${escapeHtml(taskName)}</span>
|
||||||
<span class="badge ${t.status}">${statusLabel}</span>
|
${statusLabel ? `<span class="badge ${t.status}">${statusLabel}</span>` : ""}
|
||||||
${wdBadge}
|
${wdBadge}
|
||||||
${t.skill ? `<span class="muted">${escapeHtml(t.skill)}</span>` : ""}
|
${t.skill ? `<span class="muted">${escapeHtml(t.skill)}</span>` : ""}
|
||||||
<span class="tid">${t.task_id.slice(0, 8)}</span>
|
<span class="tid">${t.task_id.slice(0, 8)}</span>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue