You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
76 lines
3.6 KiB
76 lines
3.6 KiB
|
1 day ago
|
/* 定级/撤级统一入口(修订⑦+⑧):有上级边禁调级;有下级边可调但须高于最高下级(公司边不计入);取消等级仍须无任何边 */
|
||
|
|
function tryLevelDrop(id, target) {
|
||
|
|
const c = byId(id);
|
||
|
|
if (!c) return;
|
||
|
|
const newLv = target.kind === 'unrec' ? null : target.lv;
|
||
|
|
if (newLv === c.level) return;
|
||
|
|
const eff = effectiveEdges();
|
||
|
|
const parentEdge = eff.find(e => e.child === id);
|
||
|
|
const childEdges = eff.filter(e => e.parent === id && e.child !== COMPANY_ID);
|
||
|
|
if (parentEdge) {
|
||
|
|
toast('「' + c.name + '」有上级连线(' + cname(parentEdge.parent) + '),请先取消上级连线后再调整等级', 'err');
|
||
|
|
layoutGraph(); renderEdgesOnly(); return;
|
||
|
|
}
|
||
|
|
if (newLv == null) {
|
||
|
|
if (childEdges.length) {
|
||
|
|
toast('「' + c.name + '」存在连线,请先取消所有连线后再取消等级', 'err');
|
||
|
|
layoutGraph(); renderEdgesOnly(); return;
|
||
|
|
}
|
||
|
|
} else if (childEdges.length) {
|
||
|
|
const maxChild = Math.max.apply(null, childEdges.map(e => byId(e.child).level));
|
||
|
|
const childNames = childEdges.filter(e => byId(e.child).level === maxChild).map(e => cname(e.child)).join('、');
|
||
|
|
if (newLv <= maxChild) {
|
||
|
|
toast('「' + c.name + '」最高下级为等级 ' + maxChild + '(' + childNames + '),新等级须高于它', 'err');
|
||
|
|
layoutGraph(); renderEdgesOnly(); return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
const from = c.level == null ? '未设置' : c.level;
|
||
|
|
c.level = newLv;
|
||
|
|
delete G.cardPos[id];
|
||
|
|
sanitizeManualEdges();
|
||
|
|
layoutGraph();
|
||
|
|
if (newLv == null) {
|
||
|
|
addLog('数据', '「' + c.name + '」等级已取消(拖回未设置栏,原等级:' + from + ')');
|
||
|
|
toast('已取消「' + c.name + '」的等级,移入未设置栏');
|
||
|
|
} else {
|
||
|
|
addLog('数据', '为「' + c.name + '」设定等级 ' + newLv + '(拖入等级格子,原等级:' + from + ')');
|
||
|
|
toast('已为「' + c.name + '」设定等级 ' + newLv);
|
||
|
|
}
|
||
|
|
renderGraph(); renderGraphState();
|
||
|
|
}
|
||
|
|
/* 强制按等级归行:等级 10 在公司上方,等级 9..1 在公司下方(9 邻近公司),未定级固定右侧栏 */
|
||
|
|
function layoutGraph() {
|
||
|
|
canvasInner.style.width = '2400px'; canvasInner.style.height = '1400px';
|
||
|
|
renderLevelRows();
|
||
|
|
const top = [], byLv = {}, unrec = [];
|
||
|
|
G.contacts.forEach(c => {
|
||
|
|
if (c.level == null) unrec.push(c);
|
||
|
|
else if (c.level === 10) top.push(c);
|
||
|
|
else (byLv[c.level] = byLv[c.level] || []).push(c);
|
||
|
|
});
|
||
|
|
const placeRow = (arr, y) => {
|
||
|
|
const L = ROW_X + 100, R = ROW_X + ROW_W;
|
||
|
|
const total = arr.length * CARD_W + Math.max(0, arr.length - 1) * 44;
|
||
|
|
let x = Math.max(L, (L + R - total) / 2);
|
||
|
|
arr.forEach(c => { G.cardPos[c.id] = { x: x, y: y }; x += CARD_W + 44; });
|
||
|
|
};
|
||
|
|
placeRow(top, LV10_Y);
|
||
|
|
const lvs = Object.keys(byLv).map(Number).sort((a, b) => b - a);
|
||
|
|
lvs.forEach(lv => placeRow(byLv[lv], lvRowY(lv)));
|
||
|
|
const zone = $('unrecZone');
|
||
|
|
zone.style.left = UNREC_X + 'px'; zone.style.top = UNREC_Y + 'px'; zone.style.width = UNREC_W + 'px'; zone.style.height = UNREC_H + 'px';
|
||
|
|
unrec.forEach((c, i) => {
|
||
|
|
G.cardPos[c.id] = { x: UNREC_X + 16 + (i % 2) * 200, y: UNREC_Y + 52 + Math.floor(i / 2) * 130 };
|
||
|
|
});
|
||
|
|
}
|
||
|
|
/* 10 个等级格子横条 + 标签(公司行不画格子) */
|
||
|
|
function renderLevelRows() {
|
||
|
|
canvasInner.querySelectorAll('.lv-row').forEach(el => el.remove());
|
||
|
|
ROWS.forEach(r => {
|
||
|
|
const el = document.createElement('div');
|
||
|
|
el.className = 'lv-row'; el.dataset.lv = r.lv;
|
||
|
|
el.style.left = ROW_X + 'px'; el.style.top = r.y + 'px'; el.style.width = ROW_W + 'px'; el.style.height = CARD_H + 'px';
|
||
|
|
el.innerHTML = '<span class="row-label">等级 ' + r.lv + (r.lv === 10 ? ' · 顶层' : '') + '</span>';
|
||
|
|
canvasInner.insertBefore(el, $('unrecZone'));
|
||
|
|
});
|
||
|
|
}
|