/* ---- 删边(× 按钮;公司派生边无 × 不可删) ---- */ function edgeDeleteClick(e) { const del = e.target.closest('.edge-del'); if (!del || !G.editing) return; const g = del.closest('g.edge-g'); if (!g) return; const eid = g.dataset.eid, pair = g.dataset.pair.split('>'); if (eid.indexOf('p_') === 0) { G.pendingAdds = G.pendingAdds.filter(a => !(a.parent === pair[0] && a.child === pair[1])); toast('已撤销本次新增连线(未保存)'); renderGraph(); renderGraphState(); return; } if (!G.edges.find(x => x.id === eid)) return; G.pendingDeletes.push(eid); G.cycleHighlight = null; addLog('关系', '删除连线(未保存):' + cname(pair[0]) + ' → ' + cname(pair[1]) + '(手动边)'); renderGraph(); renderGraphState(); } /* ---- 图谱卡片电话点击明文 + 埋点(脱敏拍板:列表与图谱卡片均默认脱敏) ---- */ function cardPhoneClick(e) { const ph = e.target.closest('.gphone'); if (!ph) return; const card = ph.closest('.gcard'); if (!card || !card.dataset.id) return; revealOne(card.dataset.id).then(renderGraph); } /* ---- 悬停气泡(人脉关系/内线/礼品——节点 DTO 未含,诚实显 --) ---- */ function hideBubble() { $('bubble').style.display = 'none'; } function cardBubbleOver(e) { const card = e.target.closest('.gcard'); if (!card || card.classList.contains('company') || !card.dataset.id) { hideBubble(); return; } const c = byId(card.dataset.id); if (!c) return; const b = $('bubble'); b.innerHTML = '