/* query.js —— 筛选与搜索(纯函数,可单独测试)。 * 维度的取值放在 hash 里,多选维度用逗号连接;结果 = 各维度条件的交集。 */ (function () { "use strict"; const T = window.KF_TAXONOMY; function parseList(v) { return v ? String(v).split(",").map((s) => s.trim()).filter(Boolean) : []; } /* 构造"生效中的筛选条件" */ function criteria(q) { return { priority: parseList(q.priority), stage: parseList(q.stage), category: parseList(q.category), evidence: parseList(q.evidence), layer: parseList(q.layer), member: parseList(q.member), q: (q.q || "").trim().toLowerCase(), sort: q.sort || "", ins: q.ins || "", focus: q.focus || "" }; } function isEmpty(c) { return !c.priority.length && !c.stage.length && !c.category.length && !c.evidence.length && !c.layer.length && !c.member.length && !c.q; } /* 多个维度各自"任一命中"即通过,维度之间取交集 */ function test(row, c) { if (c.priority.length && !c.priority.includes(row.priority)) return false; if (c.stage.length && !(row.stageObj && c.stage.includes(row.stageObj.code))) return false; if (c.category.length && !c.category.includes(row.category)) return false; if (c.evidence.length && !c.evidence.includes(row.evidenceKey || row.evidenceLevel)) return false; if (c.layer.length && !c.layer.includes(row.layer)) return false; if (c.member.length && !c.member.includes(row.ownerName)) return false; if (c.q) { const hay = [row.title, row.ownerName, row.category, row.projectTitle, row.summary, row.body] .filter(Boolean).join(" ").toLowerCase(); if (!hay.includes(c.q)) return false; } return true; } /* 逐维度计数:用于在筛选条上显示"如果只点这一项会有几条",且该计数会受其他维度约束 */ function facetCounts(rows, c, dim, keyFn) { const rest = { ...c, [dim]: [] }; const m = new Map(); for (const r of rows) { if (!test(r, rest)) continue; const k = keyFn(r); if (k == null) continue; m.set(k, (m.get(k) || 0) + 1); } return m; } /* 组内去重成员数(归纳交叉人数用同一口径) */ function distinctOwners(rows) { return new Set(rows.map((r) => r.ownerKey || r.ownerName).filter(Boolean)).size; } window.KF_QUERY = { parseList, criteria, isEmpty, test, facetCounts, distinctOwners }; })();