Files
cma-management/frontend/src/components/map-canvas/ConnectionManagerDialog.vue
T

167 lines
5.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<MyDialog :model-value="modelValue" @update:model-value="$emit('update:modelValue', $event)" title="连接管理" :width="780">
<!-- 新增连线非拖拽方式 -->
<div class="cm-add-row">
<el-select v-model="form.from" placeholder="源目标" filterable style="width:230px;" @change="form.to = ''">
<el-option-group v-for="g in groupedOptions" :key="g.label" :label="g.label">
<el-option v-for="o in g.items" :key="o.key" :label="o.name" :value="o.key" />
</el-option-group>
</el-select>
<span class="cm-arrow"></span>
<el-select v-model="form.to" placeholder="目标目标" filterable style="width:230px;">
<el-option-group v-for="g in groupedOptions" :key="g.label" :label="g.label">
<el-option v-for="o in g.items" :key="o.key" :label="o.name" :value="o.key" />
</el-option-group>
</el-select>
<el-select v-model="form.effect" style="width:96px;">
<el-option label="正向" value="positive" />
<el-option label="负向" value="negative" />
</el-select>
<el-button type="primary" :disabled="!form.from || !form.to" @click="onAdd">添加连线</el-button>
</div>
<div v-if="connections.length === 0" class="cm-empty">
暂无连线请通过上方表单或画布拖拽下层上层创建
</div>
<table v-else class="cm-table">
<thead>
<tr><th>#</th><th>源目标</th><th>方向</th><th>目标目标</th><th>强度</th><th>操作</th></tr>
</thead>
<tbody>
<tr v-for="(conn, idx) in connections" :key="idx">
<td class="cm-idx">{{ idx + 1 }}</td>
<td :title="conn.from">{{ nodeLabel(conn.from) }}</td>
<td class="cm-dir"></td>
<td :title="conn.to">{{ nodeLabel(conn.to) }}</td>
<td>
<el-tag
:type="conn.effect === 'negative' ? 'danger' : 'success'"
size="small"
style="cursor:pointer;"
@click="toggleEffect(idx)"
title="点击切换正/负向"
>{{ conn.effect === 'negative' ? '负向' : '正向' }} </el-tag>
</td>
<td>
<el-button size="small" type="danger" text @click="$emit('delete-connection', idx)">删除</el-button>
</td>
</tr>
</tbody>
</table>
<div class="cm-hint">
提示拖拽连线按 BSC 支撑方向下层上层 同层自动校验本面板可维护任意方向连线
</div>
</MyDialog>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import MyDialog from '../MyDialog.vue'
const props = defineProps<{
modelValue: boolean
connections: any[]
nodeOptions: { key: string; name: string; layerName: string }[]
layerLabels?: Record<string, string>
}>()
const emit = defineEmits<{
(e: 'update:modelValue', v: boolean): void
(e: 'add-connection', payload: { from: string; to: string; effect?: string }): void
(e: 'delete-connection', idx: number): void
(e: 'update-connection', idx: number, patch: any): void
}>()
const form = ref<{ from: string; to: string; effect: string }>({ from: '', to: '', effect: 'positive' })
/** 按层分组的节点选项 */
const groupedOptions = computed(() => {
const groups: { label: string; items: { key: string; name: string }[] }[] = []
const byLayer: Record<string, { key: string; name: string }[]> = {}
for (const o of props.nodeOptions) {
const ln = o.layerName || '其他'
if (!byLayer[ln]) byLayer[ln] = []
byLayer[ln].push({ key: o.key, name: o.name })
}
for (const label of Object.keys(byLayer)) {
groups.push({ label, items: byLayer[label] })
}
return groups
})
function nodeLabel(key: string): string {
const o = props.nodeOptions.find(n => n.key === key)
return o ? `${o.layerName} · ${o.name}` : key
}
function toggleEffect(idx: number) {
const conn = props.connections[idx]
if (!conn) return
emit('update-connection', idx, { effect: conn.effect === 'negative' ? 'positive' : 'negative' })
}
function onAdd() {
if (!form.value.from || !form.value.to) return
emit('add-connection', { from: form.value.from, to: form.value.to, effect: form.value.effect })
form.value = { from: '', to: '', effect: 'positive' }
}
</script>
<style scoped>
.cm-add-row {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 0 14px;
border-bottom: 1px dashed #e4e7ed;
margin-bottom: 12px;
flex-wrap: wrap;
}
.cm-arrow {
color: #909399;
font-size: 16px;
flex-shrink: 0;
}
.cm-empty {
text-align: center;
color: #909399;
padding: 32px 0;
font-size: 13px;
}
.cm-table {
width: 100%;
border-collapse: collapse;
font-size: 13px;
}
.cm-table th {
text-align: left;
padding: 8px 10px;
background: #f5f7fa;
color: #606266;
font-weight: 600;
border-bottom: 1px solid #e4e7ed;
}
.cm-table td {
padding: 8px 10px;
border-bottom: 1px solid #f0f0f0;
color: #303133;
max-width: 240px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.cm-table tr:hover td {
background: #f8faff;
}
.cm-idx { color: #909399; width: 32px; }
.cm-dir { color: #409eff; text-align: center; width: 36px; }
.cm-hint {
margin-top: 12px;
font-size: 12px;
color: #909399;
background: #f8f9fb;
padding: 8px 12px;
border-radius: 6px;
}
</style>