fix(web): 任务树/父任务下拉对异常 depth/id 加固,避免整页崩溃

renderParentOptions 的 '· '.repeat(depth-1) 在 depth=0 时抛 RangeError(Invalid count value)、
renderNode 的 t.id.slice(-6) 在 id 缺失时抛 TypeError——任一都会让看板整页崩。
改为 repeat(Math.max(0,(depth||1)-1)) 与 String(t.id||'').slice。
(node:vm + 最小 DOM harness 复现并验证)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-13 09:40:55 +08:00
parent ac0d5b7b77
commit 3fc19e47c4
+2 -2
View File
@@ -856,7 +856,7 @@ function renderTree() {
<div class="task-node depth-${t.depth}">
<div class="task-row ${isGate ? 'is-gate' : ''} ${expanded ? 'expanded' : ''} ${isCtx ? 'filter-ctx' : ''}" data-action="toggle-detail" data-id="${esc(t.id)}">
${caret}
<span class="t-title">${esc(t.title)}<span class="t-id">${esc(t.id.slice(-6))}</span></span>
<span class="t-title">${esc(t.title)}<span class="t-id">${esc(String(t.id || '').slice(-6))}</span></span>
<span class="spacer"></span>
${(() => {
// blocked(系统按依赖自动落位)→ 显示在等哪几条
@@ -1000,7 +1000,7 @@ function renderParentOptions() {
const sel = document.querySelector('#newTaskPanel select[name=parentId]');
const cur = sel.value;
sel.innerHTML = `<option value="">(顶层)</option>` +
S.tasks.map((t) => `<option value="${esc(t.id)}">${esc('· '.repeat(t.depth - 1) + t.title)}</option>`).join('');
S.tasks.map((t) => `<option value="${esc(t.id)}">${esc('· '.repeat(Math.max(0, (t.depth || 1) - 1)) + t.title)}</option>`).join('');
sel.value = cur;
}