From 1c4a81b3f39b824a4abb2aa474d7fb6d9e98fcd4 Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Sat, 13 Jun 2026 15:08:53 +0800 Subject: [PATCH] =?UTF-8?q?feat(web):=20SVG=20=E5=9B=BE=E6=A0=87=E9=9B=86?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2=20Unicode=20=E2=80=94=E2=80=94=20tsk=5F3uhHO?= =?UTF-8?q?GU0qzj0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用 design/assets/icons/ 的 15 个双色 SVG 图标替换现网纯 Unicode 图标: • 拷贝 design/assets/icons/*.svg → web/assets/icons/(15 个) • app.js 顶部新增 ICONS 对象 + icon() 内联 helper • index.html:徽章组(gate/ready/running/deps)、配置按钮(config)、 同步按钮(sync)、搜索输入框(search + filter-search-wrap 包装)、 清除筛选按钮(close)、「新建」/「新建任务」按钮(add) 各区块头加语义图标:project/task/gate/running/flow • app.js 模板字符串:⛓→deps、✕→close(任务行取消/预览关闭/归档关闭)、 依赖等待标签、ap-reason→reason SVG、分支显示→git、事件项 ev-type→event • style.css:新增 svg.icon 基础尺寸规则、filter-search-wrap 布局、 各语义上下文 --icon-accent 注入(暗/浅主题均用 CSS 变量自动适配)、 .ap-reason::before 移除 content:'↳' 改用 SVG • 品牌字符保留不动:▍▮→·— 及状态 CSS 圆点 Co-Authored-By: Claude Sonnet 4.6 --- web/app.js | 45 ++++++++++++++++++++++++++---------- web/assets/icons/add.svg | 1 + web/assets/icons/close.svg | 1 + web/assets/icons/config.svg | 1 + web/assets/icons/deps.svg | 1 + web/assets/icons/event.svg | 1 + web/assets/icons/flow.svg | 1 + web/assets/icons/gate.svg | 1 + web/assets/icons/git.svg | 1 + web/assets/icons/project.svg | 1 + web/assets/icons/ready.svg | 1 + web/assets/icons/reason.svg | 1 + web/assets/icons/running.svg | 1 + web/assets/icons/search.svg | 1 + web/assets/icons/sync.svg | 1 + web/assets/icons/task.svg | 1 + web/index.html | 33 ++++++++++++++------------ web/style.css | 37 ++++++++++++++++++++++++++--- 18 files changed, 100 insertions(+), 30 deletions(-) create mode 100644 web/assets/icons/add.svg create mode 100644 web/assets/icons/close.svg create mode 100644 web/assets/icons/config.svg create mode 100644 web/assets/icons/deps.svg create mode 100644 web/assets/icons/event.svg create mode 100644 web/assets/icons/flow.svg create mode 100644 web/assets/icons/gate.svg create mode 100644 web/assets/icons/git.svg create mode 100644 web/assets/icons/project.svg create mode 100644 web/assets/icons/ready.svg create mode 100644 web/assets/icons/reason.svg create mode 100644 web/assets/icons/running.svg create mode 100644 web/assets/icons/search.svg create mode 100644 web/assets/icons/sync.svg create mode 100644 web/assets/icons/task.svg diff --git a/web/app.js b/web/app.js index 35dc559..a46f289 100644 --- a/web/app.js +++ b/web/app.js @@ -3,6 +3,27 @@ ════════════════════════════════════════════════════════════ */ 'use strict'; +// ── SVG 图标集(v1.1 双色调,24×24,2px 圆头;currentColor=基础描边,--icon-accent=信号色) ── +const ICONS = { + task: ``, + project: ``, + gate: ``, + ready: ``, + running: ``, + sync: ``, + config: ``, + search: ``, + git: ``, + deps: ``, + reason: ``, + event: ``, + flow: ``, + add: ``, + close: ``, +}; +/** 返回指定图标的内联 SVG HTML(name 不存在时返回空串) */ +function icon(name) { return ICONS[name] || ''; } + // ── 模型常量(与 src/model/status.ts / complexity.ts 对齐) ── const STATUS_LABEL = { init: '新建', analyzing: '分析拆解中', plan_review: '待确认拆解', @@ -461,7 +482,7 @@ function gateDocs(t) { blocks.push(reviewReportBlocks(r)); // CODE REVIEW + 安全审计 两节(各带 verdict 徽章),置于 DIFF 摘要上方 blocks.push(`
RESULT · 执行结果
- ${r.branch ? `
分支
${esc(r.branch)}
` : ''} + ${r.branch ? `
${icon('git')} 分支
${esc(r.branch)}
` : ''} ${r.worktree ? `
worktree
${esc(r.worktree)}
` : ''} ${r.prUrl ? `
PR
${esc(r.prUrl)}
` : ''}
`); @@ -699,7 +720,7 @@ function renderArchiveModal(t, runs, events) { const resultBlock = r ? `${reviewReportBlocks(r)}
执行结果
- ${r.branch ? kv('分支', esc(r.branch)) : ''} + ${r.branch ? kv(`${icon('git')} 分支`, esc(r.branch)) : ''} ${r.worktree ? kv('worktree', esc(r.worktree)) : ''} ${r.prUrl ? kv('合并', esc(r.prUrl)) : ''} ${r.commits && r.commits.length ? kv('commits', r.commits.map(esc).join('
')) : ''} @@ -709,7 +730,7 @@ function renderArchiveModal(t, runs, events) { const approvalRows = t.approvals && t.approvals.length ? `
审批记录
${t.approvals.map((a) => kv( `${GATE_LABEL[a.gate] || esc(a.gate)} · ${a.action === 'accept' ? '接受' : '驳回'}`, - `审批人 ${esc(a.actor)} · ${fmtFull(a.at)}${a.reason ? `
意见:${esc(a.reason)}` : ''}`, + `审批人 ${esc(a.actor)} · ${fmtFull(a.at)}${a.reason ? `
${icon('reason')} 意见:${esc(a.reason)}` : ''}`, )).join('')}
` : ''; const timeline = events.length ? `
状态流转时间线
@@ -739,7 +760,7 @@ function renderArchiveModal(t, runs, events) { ${cplxBadge(t.complexity)} ${statusChip(t.status)} - +
${attrs}${docs}${runRows}${resultBlock}${approvalRows}${timeline} @@ -804,7 +825,7 @@ function renderPreview() { ${cplxBadge(t.complexity)} ${statusChip(t.status)} - +
${gateDocs(t)}
@@ -1008,12 +1029,12 @@ function renderTree() { if (t.status !== 'blocked' || !(t.deps || []).length) return ''; const unmet = t.deps.filter((d) => byId.get(d)?.status !== 'done'); if (!unmet.length) return ''; - return `⛓ 等依赖 ${unmet.length}`; + return `${icon('deps')} 等依赖 ${unmet.length}`; })()} P${t.priority} ${cplxBadge(t.complexity, t.id)} ${statusChip(t.status)} - ${!ARCHIVED.has(t.status) ? `` : ''} + ${!ARCHIVED.has(t.status) ? `` : ''}
${expanded ? renderDetail(t) : ''} @@ -1054,7 +1075,7 @@ function renderDetail(t) {
${reviewReportBlocks(r)}
RESULT · 执行结果
-
分支
${esc(r.branch || '—')}
+
${icon('git')} 分支
${esc(r.branch || '—')}
worktree
${esc(r.worktree || '—')}
${r.prUrl ? `
合并
${esc(r.prUrl)}
` : ''} ${r.commits && r.commits.length ? `
commits
${r.commits.map(esc).join('
')}
` : ''} @@ -1072,7 +1093,7 @@ function renderDetail(t) { ${a.action === 'accept' ? '✓ 通过' : '✗ 驳回'} ${GATE_LABEL[a.gate] || esc(a.gate)} · ${esc(a.actor)} ${fmtTime(a.at)} - ${a.reason ? `${esc(a.reason)}` : ''} + ${a.reason ? `${icon('reason')}${esc(a.reason)}` : ''}
`).join('')} `); } @@ -1086,7 +1107,7 @@ function renderDetail(t) { const dt = S.tasks.find((x) => x.id === d); const ok = dt && dt.status === 'done'; return `
- ${ok ? '✓' : '⛓'} + ${ok ? '✓' : icon('deps')} ${dt ? statusChip(dt.status) : ''} ${esc(dt ? dt.title : d)} ${esc(d.slice(-6))} @@ -1114,7 +1135,7 @@ function renderDetail(t) {
`; } - return ``; + return ``; })() : ''; const deleteSection = (() => { if (S.confirmDelete === t.id) { @@ -1214,7 +1235,7 @@ function renderEvents() { ul.innerHTML = S.events.slice(0, 80).map((e) => `
  • - ${EVENT_LABEL[e.type] || esc(e.type)} + ${icon('event')}${EVENT_LABEL[e.type] || esc(e.type)} ${fmtTime(e.at)}
    ${eventDetail(e)}
    diff --git a/web/assets/icons/add.svg b/web/assets/icons/add.svg new file mode 100644 index 0000000..3d96d3f --- /dev/null +++ b/web/assets/icons/add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/assets/icons/close.svg b/web/assets/icons/close.svg new file mode 100644 index 0000000..9bce1ff --- /dev/null +++ b/web/assets/icons/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/assets/icons/config.svg b/web/assets/icons/config.svg new file mode 100644 index 0000000..30052e3 --- /dev/null +++ b/web/assets/icons/config.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/assets/icons/deps.svg b/web/assets/icons/deps.svg new file mode 100644 index 0000000..c8a2cf2 --- /dev/null +++ b/web/assets/icons/deps.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/assets/icons/event.svg b/web/assets/icons/event.svg new file mode 100644 index 0000000..5efd235 --- /dev/null +++ b/web/assets/icons/event.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/assets/icons/flow.svg b/web/assets/icons/flow.svg new file mode 100644 index 0000000..c1e2502 --- /dev/null +++ b/web/assets/icons/flow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/assets/icons/gate.svg b/web/assets/icons/gate.svg new file mode 100644 index 0000000..c44e9d5 --- /dev/null +++ b/web/assets/icons/gate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/assets/icons/git.svg b/web/assets/icons/git.svg new file mode 100644 index 0000000..e5d0c12 --- /dev/null +++ b/web/assets/icons/git.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/assets/icons/project.svg b/web/assets/icons/project.svg new file mode 100644 index 0000000..a768d24 --- /dev/null +++ b/web/assets/icons/project.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/assets/icons/ready.svg b/web/assets/icons/ready.svg new file mode 100644 index 0000000..de52463 --- /dev/null +++ b/web/assets/icons/ready.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/assets/icons/reason.svg b/web/assets/icons/reason.svg new file mode 100644 index 0000000..36064bb --- /dev/null +++ b/web/assets/icons/reason.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/assets/icons/running.svg b/web/assets/icons/running.svg new file mode 100644 index 0000000..ee82d11 --- /dev/null +++ b/web/assets/icons/running.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/assets/icons/search.svg b/web/assets/icons/search.svg new file mode 100644 index 0000000..a181aa6 --- /dev/null +++ b/web/assets/icons/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/assets/icons/sync.svg b/web/assets/icons/sync.svg new file mode 100644 index 0000000..21da67a --- /dev/null +++ b/web/assets/icons/sync.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/assets/icons/task.svg b/web/assets/icons/task.svg new file mode 100644 index 0000000..de7baf9 --- /dev/null +++ b/web/assets/icons/task.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/index.html b/web/index.html index 076ce34..064b1b9 100644 --- a/web/index.html +++ b/web/index.html @@ -20,8 +20,8 @@
    - 项目 - + 项目 +
      @@ -41,23 +41,23 @@
      @@ -92,25 +92,25 @@
      - +
      -
      Agent 执行
      +
      Agent 执行
      - 任务树 - + 任务树 +