|
@@ -2068,6 +2068,12 @@
|
|
|
transform: translateY(-8px);
|
|
transform: translateY(-8px);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ .qr-row { display:flex; align-items:flex-start; gap:10px; padding:5px 0; border-bottom:1px solid #f4f4f4; }
|
|
|
|
|
+ .qr-lab { min-width:64px; color:#999; font-size:12.5px; padding-top:6px; flex-shrink:0; }
|
|
|
|
|
+ .qr-chips { display:flex; flex-wrap:wrap; gap:7px; flex:1; }
|
|
|
|
|
+ .chip { padding:4px 13px; border-radius:18px; font-size:12.5px; cursor:pointer; border:1.5px solid #e2e2e2; background:#fff; color:#666; }
|
|
|
|
|
+ .chip:hover { border-color:#bbb; color:#333; }
|
|
|
|
|
+ .chip.on { background:#1a1a1a; border-color:#1a1a1a; color:#fff; }
|
|
|
</style>
|
|
</style>
|
|
|
</head>
|
|
</head>
|
|
|
<body>
|
|
<body>
|
|
@@ -3652,6 +3658,70 @@
|
|
|
matrix: null, // /api/query_matrix
|
|
matrix: null, // /api/query_matrix
|
|
|
scores: null, // 最近一次评分结果 cells
|
|
scores: null, // 最近一次评分结果 cells
|
|
|
};
|
|
};
|
|
|
|
|
+ function qrChip(label, active, on) {
|
|
|
|
|
+ const b = document.createElement("button");
|
|
|
|
|
+ b.className = "chip" + (active ? " on" : "");
|
|
|
|
|
+ b.textContent = label;
|
|
|
|
|
+ b.onclick = on;
|
|
|
|
|
+ return b;
|
|
|
|
|
+ }
|
|
|
|
|
+ function renderQrDims() {
|
|
|
|
|
+ const root = $("#qr-dims");
|
|
|
|
|
+ root.innerHTML = "";
|
|
|
|
|
+ // 扁平维度
|
|
|
|
|
+ QR_FLAT.forEach((d) => {
|
|
|
|
|
+ const row = document.createElement("div");
|
|
|
|
|
+ row.className = "qr-row";
|
|
|
|
|
+ row.innerHTML = `<span class="qr-lab">· ${d.label}</span>`;
|
|
|
|
|
+ const wrap = document.createElement("span");
|
|
|
|
|
+ wrap.className = "qr-chips";
|
|
|
|
|
+ wrap.appendChild(qrChip("无", qrState.flat[d.id] == null, () => { qrState.flat[d.id] = null; renderQrDims(); }));
|
|
|
|
|
+ d.items.forEach((it) =>
|
|
|
|
|
+ wrap.appendChild(qrChip(it, qrState.flat[d.id] === it, () => { qrState.flat[d.id] = it; renderQrDims(); })));
|
|
|
|
|
+ row.appendChild(wrap);
|
|
|
|
|
+ root.appendChild(row);
|
|
|
|
|
+ });
|
|
|
|
|
+ // 实质/形式 下钻:每一层一行,展示当前层可选项;选中后再展开下一层
|
|
|
|
|
+ QR_TREE.forEach((d) => {
|
|
|
|
|
+ const data = qrState.treeData[d.id];
|
|
|
|
|
+ const path = qrState.treePath[d.id];
|
|
|
|
|
+ // 沿 path 定位到当前层的 children 列表(逐层)
|
|
|
|
|
+ let level = data ? data.tree : [];
|
|
|
|
|
+ const rows = [];
|
|
|
|
|
+ for (let depth = 0; ; depth++) {
|
|
|
|
|
+ const labtxt = depth === 0 ? `· ${d.label}` : "";
|
|
|
|
|
+ const row = document.createElement("div");
|
|
|
|
|
+ row.className = "qr-row";
|
|
|
|
|
+ row.innerHTML = `<span class="qr-lab">${labtxt}</span>`;
|
|
|
|
|
+ const wrap = document.createElement("span");
|
|
|
|
|
+ wrap.className = "qr-chips";
|
|
|
|
|
+ wrap.appendChild(qrChip("无", path.length === depth, () => { qrState.treePath[d.id] = path.slice(0, depth); renderQrDims(); }));
|
|
|
|
|
+ (level || []).forEach((node) =>
|
|
|
|
|
+ wrap.appendChild(qrChip(node.name, path[depth] === node.name,
|
|
|
|
|
+ () => { qrState.treePath[d.id] = [...path.slice(0, depth), node.name]; renderQrDims(); })));
|
|
|
|
|
+ row.appendChild(wrap);
|
|
|
|
|
+ rows.push(row);
|
|
|
|
|
+ // 进入已选中节点的下一层
|
|
|
|
|
+ const sel = (level || []).find((n) => n.name === path[depth]);
|
|
|
|
|
+ if (!sel || !(sel.children && sel.children.length)) break;
|
|
|
|
|
+ level = sel.children;
|
|
|
|
|
+ }
|
|
|
|
|
+ rows.forEach((r) => root.appendChild(r));
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ async function qrOpen() {
|
|
|
|
|
+ renderQrDims();
|
|
|
|
|
+ // 并行拉矩阵 + 两棵分类树(接口挂则该维度降级:提示不可选)
|
|
|
|
|
+ try { qrState.matrix = qrState.matrix || await api("/api/query_matrix"); }
|
|
|
|
|
+ catch (e) { return toast("内容树矩阵加载失败", "error"); }
|
|
|
|
|
+ for (const d of QR_TREE) {
|
|
|
|
|
+ if (qrState.treeData[d.id]) continue;
|
|
|
|
|
+ try { qrState.treeData[d.id] = await api("/api/category_tree?source_type=" + encodeURIComponent(d.source)); }
|
|
|
|
|
+ catch (e) { toast(`${d.label} 接口不可达,该维度暂不可选`, "warn"); }
|
|
|
|
|
+ }
|
|
|
|
|
+ renderQrDims();
|
|
|
|
|
+ renderQrTable();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/* ════ 新建搜索 ════ */
|
|
/* ════ 新建搜索 ════ */
|
|
|
/* 渠道下拉多选(选项同 search_eval:小红书/知乎/公众号/抖音/视频号/YouTube) */
|
|
/* 渠道下拉多选(选项同 search_eval:小红书/知乎/公众号/抖音/视频号/YouTube) */
|