|
|
@@ -33,6 +33,8 @@ export function useTopology() {
|
|
|
/** 绑定选择态:双击「测风点位/数据布点」后等待单击目标 */
|
|
|
const selectMode = ref(false);
|
|
|
const selectedSourceId = ref('');
|
|
|
+ /** 待绑定源节点 id(放大+描边标记,进入选择态后生效,退出后清除) */
|
|
|
+ const markedSourceId = ref('');
|
|
|
/** 操作栏部门选择:选中任意层级部门后过滤部门树(该部门及其后代)并按该部门查询数据;空=全局 */
|
|
|
const selectedDeptId = ref('');
|
|
|
|
|
|
@@ -185,14 +187,21 @@ export function useTopology() {
|
|
|
seenIds.add(n.id);
|
|
|
const cat = categories[n.category] || categories[0];
|
|
|
const statusColor = statusColorMap[n.status || 'normal'];
|
|
|
+ const isMarked = n.id === markedSourceId.value;
|
|
|
+ const itemStyle: any = { color: statusColor || cat.color };
|
|
|
+ // 待绑定源节点:放大 + 红色描边,让用户明确当前正在操作哪个节点
|
|
|
+ if (isMarked) {
|
|
|
+ itemStyle.borderColor = '#ff4d4f';
|
|
|
+ itemStyle.borderWidth = 3;
|
|
|
+ }
|
|
|
echartsNodes.push({
|
|
|
id: n.id,
|
|
|
name: n.name,
|
|
|
category: n.category,
|
|
|
value: n.name,
|
|
|
symbol: cat.symbol,
|
|
|
- symbolSize: cat.symbolSize,
|
|
|
- itemStyle: { color: statusColor || cat.color },
|
|
|
+ symbolSize: isMarked ? cat.symbolSize + 8 : cat.symbolSize,
|
|
|
+ itemStyle,
|
|
|
raw: n,
|
|
|
});
|
|
|
}
|
|
|
@@ -225,7 +234,14 @@ export function useTopology() {
|
|
|
|
|
|
// ——— 单击 ———
|
|
|
chartInstance.on('click', (params: any) => {
|
|
|
- if (!params.data) return;
|
|
|
+ // 待绑定态下单击空白处 → 取消选择
|
|
|
+ if (!params.data) {
|
|
|
+ if (selectMode.value) {
|
|
|
+ exitSelectMode();
|
|
|
+ message.info('已取消绑定');
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
if (params.dataType === 'node') {
|
|
|
if (editMode.value && selectMode.value) {
|
|
|
@@ -277,22 +293,53 @@ export function useTopology() {
|
|
|
}
|
|
|
selectMode.value = true;
|
|
|
selectedSourceId.value = sourceId;
|
|
|
+ markedSourceId.value = sourceId;
|
|
|
+ // 重绘应用放大 + 描边标记,并高亮关联连线
|
|
|
+ renderTopology(topologyData);
|
|
|
highlightPath(sourceId);
|
|
|
const tip =
|
|
|
src.category === CAT_POINT
|
|
|
- ? `已选中"${src.name}",请单击一个「矿井」绑定所属矿。双击空白处取消。`
|
|
|
- : `已选中"${src.name}",请单击一个「测风点位」绑定。双击空白处取消。`;
|
|
|
+ ? `已选中"${src.name}",请单击一个「矿井」或「数据布点」绑定。单击空白处取消。`
|
|
|
+ : `已选中"${src.name}",请单击一个「测风点位」绑定。单击空白处取消。`;
|
|
|
message.info(tip);
|
|
|
}
|
|
|
|
|
|
function exitSelectMode() {
|
|
|
selectMode.value = false;
|
|
|
selectedSourceId.value = '';
|
|
|
+ markedSourceId.value = '';
|
|
|
chartInstance?.dispatchAction({ type: 'downplay' });
|
|
|
+ // 重绘移除待绑定源节点的放大/描边标记
|
|
|
+ renderTopology(topologyData);
|
|
|
}
|
|
|
|
|
|
// ==================== 绑定逻辑 ====================
|
|
|
|
|
|
+ /** 按数据布点原始 id 解析其显示名(用于确认文案,避免直接展示 id) */
|
|
|
+ function deviceNameOf(rawId?: string) {
|
|
|
+ const dev = topologyData.nodes.find((n) => n.category === CAT_DEVICE && n.rawId === rawId);
|
|
|
+ return dev?.name || rawId || '';
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 统一确认弹窗并执行编辑(一次 updateArea 调用,后端负责用新 id 替换旧绑定) */
|
|
|
+ function confirmBind(confirmText: string, params: any) {
|
|
|
+ Modal.confirm({
|
|
|
+ title: '确认绑定',
|
|
|
+ content: confirmText,
|
|
|
+ okText: '确认绑定',
|
|
|
+ cancelText: '取消',
|
|
|
+ onOk: async () => {
|
|
|
+ try {
|
|
|
+ await updateArea(params);
|
|
|
+ await loadTopology();
|
|
|
+ message.success('绑定成功');
|
|
|
+ } catch {
|
|
|
+ message.error('绑定失败');
|
|
|
+ }
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
async function attemptBind(sourceId: string, targetId: string) {
|
|
|
exitSelectMode();
|
|
|
if (sourceId === targetId) {
|
|
|
@@ -303,8 +350,8 @@ export function useTopology() {
|
|
|
const tgt = topologyData.nodes.find((n) => n.id === targetId);
|
|
|
if (!src || !tgt) return;
|
|
|
|
|
|
+ // 测风点位 → 矿井:编辑测风点位的 mineCode(允许改绑)
|
|
|
if (src.category === CAT_POINT && tgt.category === CAT_ORG) {
|
|
|
- // 测风点位 → 矿井:编辑测风点位的 mineCode
|
|
|
if (!tgt.isLeaf) {
|
|
|
message.warning('仅支持绑定到矿井(叶子节点)');
|
|
|
return;
|
|
|
@@ -321,60 +368,34 @@ export function useTopology() {
|
|
|
const confirmText = src.mineCode
|
|
|
? `该测风点位已绑定到矿编码"${src.mineCode}",确认改绑到"${tgt.name}"?`
|
|
|
: `确认将"${src.name}"绑定到"${tgt.name}"?`;
|
|
|
- Modal.confirm({
|
|
|
- title: '确认绑定',
|
|
|
- content: confirmText,
|
|
|
- okText: '确认绑定',
|
|
|
- cancelText: '取消',
|
|
|
- onOk: async () => {
|
|
|
- try {
|
|
|
- await updateArea({ id: src.rawId, mineCode: fax });
|
|
|
- await loadTopology();
|
|
|
- message.success('绑定成功');
|
|
|
- } catch {
|
|
|
- message.error('绑定失败');
|
|
|
- }
|
|
|
- },
|
|
|
- });
|
|
|
+ confirmBind(confirmText, { id: src.rawId, mineCode: fax });
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if (src.category === CAT_DEVICE && tgt.category === CAT_POINT) {
|
|
|
- // 数据布点 → 测风点位:编辑测风点位的 windrectId
|
|
|
- // 一对一:该数据布点已被其他测风点位绑定则拦截
|
|
|
- const boundPoint = topologyData.links.find((l) => l.target === src.id && l.source !== tgt.id && l.kind === 'sensor');
|
|
|
- if (boundPoint) {
|
|
|
- const other = topologyData.nodes.find((n) => n.id === boundPoint.source);
|
|
|
- message.warning(`该数据布点已被测风点位"${other?.name || boundPoint.source}"绑定`);
|
|
|
- return;
|
|
|
- }
|
|
|
- const alreadyLinked = topologyData.links.some((l) => l.kind === 'sensor' && l.source === tgt.id && l.target === src.id);
|
|
|
- if (alreadyLinked) {
|
|
|
- message.warning('已存在该绑定关系');
|
|
|
- return;
|
|
|
- }
|
|
|
- const confirmText = tgt.windrectId
|
|
|
- ? `该测风点位已绑定数据布点"${tgt.windrectId}",确认改绑到"${src.name}"?`
|
|
|
- : `确认将"${src.name}"绑定到测风点位"${tgt.name}"?`;
|
|
|
- Modal.confirm({
|
|
|
- title: '确认绑定',
|
|
|
- content: confirmText,
|
|
|
- okText: '确认绑定',
|
|
|
- cancelText: '取消',
|
|
|
- onOk: async () => {
|
|
|
- try {
|
|
|
- await updateArea({ id: tgt.rawId, windrectId: src.rawId });
|
|
|
- await loadTopology();
|
|
|
- message.success('绑定成功');
|
|
|
- } catch {
|
|
|
- message.error('绑定失败');
|
|
|
- }
|
|
|
- },
|
|
|
- });
|
|
|
+ // 测风点位 → 数据布点 / 数据布点 → 测风点位:均编辑测风点位的 windrectId(后端一次调用替换旧绑定)
|
|
|
+ let pointNode: TopoNodeData;
|
|
|
+ let deviceNode: TopoNodeData;
|
|
|
+ if (src.category === CAT_POINT && tgt.category === CAT_DEVICE) {
|
|
|
+ pointNode = src;
|
|
|
+ deviceNode = tgt;
|
|
|
+ } else if (src.category === CAT_DEVICE && tgt.category === CAT_POINT) {
|
|
|
+ pointNode = tgt;
|
|
|
+ deviceNode = src;
|
|
|
+ } else {
|
|
|
+ message.warning('仅支持「测风点位→矿井/数据布点」或「数据布点→测风点位」的绑定');
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- message.warning('仅支持「测风点位→矿井」或「数据布点→测风点位」的绑定');
|
|
|
+ const alreadyLinked = topologyData.links.some((l) => l.kind === 'sensor' && l.source === pointNode.id && l.target === deviceNode.id);
|
|
|
+ if (alreadyLinked) {
|
|
|
+ message.warning('已存在该绑定关系');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const oldDeviceName = deviceNameOf(pointNode.windrectId);
|
|
|
+ const confirmText = pointNode.windrectId
|
|
|
+ ? `该测风点位已绑定数据布点"${oldDeviceName}",确认改绑到"${deviceNode.name}"?`
|
|
|
+ : `确认将"${deviceNode.name}"绑定到测风点位"${pointNode.name}"?`;
|
|
|
+ confirmBind(confirmText, { id: pointNode.rawId, windrectId: deviceNode.rawId });
|
|
|
}
|
|
|
|
|
|
// ==================== 解绑逻辑 ====================
|
|
|
@@ -484,7 +505,7 @@ export function useTopology() {
|
|
|
if (on) {
|
|
|
renderTopology(topologyData, true);
|
|
|
chartInstance.setOption({ series: [{ roam: false }] as any });
|
|
|
- message.info('绑定模式已开启:双击「测风点位」→ 单击「矿井」绑定所属矿;双击「数据布点」→ 单击「测风点位」绑定;双击连线解绑');
|
|
|
+ message.info('绑定模式已开启:双击「测风点位」→ 单击「矿井」或「数据布点」绑定;双击「数据布点」→ 单击「测风点位」绑定;双击连线解绑');
|
|
|
} else {
|
|
|
renderTopology(topologyData);
|
|
|
message.info('已退出绑定模式');
|