<!DOCTYPE html>
|
<html lang="en">
|
<head>
|
<meta charset="utf-8">
|
<title>站点设备关系配置</title>
|
<meta name="renderer" content="webkit">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<!-- Element UI CSS -->
|
<link rel="stylesheet" href="../../static/vue/element/element.css">
|
<link rel="stylesheet" href="../../static/css/cool.css">
|
<style>
|
html, body {
|
height: 100%;
|
margin: 0;
|
padding: 0;
|
background-color: #f0f2f5;
|
}
|
#app {
|
height: 100%;
|
padding: 20px;
|
box-sizing: border-box;
|
display: flex;
|
flex-direction: column;
|
}
|
.main-card {
|
flex: 1;
|
display: flex;
|
flex-direction: column;
|
overflow: hidden;
|
}
|
.flow-container {
|
flex: 1;
|
display: flex;
|
position: relative;
|
background: #fff;
|
border: 1px solid #ebeef5;
|
overflow: hidden; /* Hide scrollbars of container */
|
}
|
|
.column {
|
width: 300px;
|
display: flex;
|
flex-direction: column;
|
border-right: 1px solid #ebeef5;
|
background-color: #fcfcfc;
|
z-index: 10;
|
}
|
.column.right {
|
border-right: none;
|
border-left: 1px solid #ebeef5;
|
position: absolute;
|
right: 0;
|
top: 0;
|
bottom: 0;
|
}
|
|
.column-header {
|
padding: 15px;
|
text-align: center;
|
font-weight: bold;
|
background-color: #f5f7fa;
|
border-bottom: 1px solid #ebeef5;
|
color: #606266;
|
}
|
|
.list-container {
|
flex: 1;
|
overflow-y: auto;
|
padding: 10px;
|
}
|
|
.node-item {
|
padding: 12px;
|
margin-bottom: 10px;
|
background-color: #fff;
|
border: 1px solid #dcdfe6;
|
border-radius: 4px;
|
cursor: grab;
|
transition: all 0.3s;
|
position: relative;
|
color: #606266;
|
font-size: 14px;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
}
|
.node-item:hover {
|
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
|
border-color: #409eff;
|
}
|
.node-item.active {
|
background-color: #ecf5ff;
|
border-color: #409eff;
|
color: #409eff;
|
}
|
|
/* Specific styles for Station nodes */
|
.station-node {
|
border-left: 4px solid #67c23a;
|
}
|
|
/* Specific styles for Device nodes */
|
.device-node {
|
border-left: 4px solid #e6a23c;
|
}
|
|
/* Middle canvas area */
|
.canvas-area {
|
flex: 1;
|
position: relative;
|
margin-right: 300px; /* Space for right column */
|
background-color: #fafafa;
|
overflow: hidden;
|
}
|
|
svg {
|
position: absolute;
|
top: 0;
|
left: 0;
|
width: 100%;
|
height: 100%;
|
pointer-events: none; /* Let clicks pass through */
|
}
|
|
svg line {
|
stroke: #909399;
|
stroke-width: 2;
|
cursor: pointer;
|
pointer-events: stroke; /* Capture events on the stroke itself */
|
transition: stroke-width 0.2s, stroke 0.2s;
|
}
|
svg line:hover {
|
stroke: #f56c6c;
|
stroke-width: 4;
|
}
|
|
/* Drag ghost image customization if needed */
|
.dragging {
|
opacity: 0.5;
|
}
|
|
/* Connection Point Indicators */
|
.connector {
|
width: 10px;
|
height: 10px;
|
background-color: #909399;
|
border-radius: 50%;
|
position: absolute;
|
top: 50%;
|
transform: translateY(-50%);
|
}
|
.station-node .connector {
|
right: -16px; /* Position outside the box */
|
display: none; /* Only show when necessary or active */
|
}
|
.device-node .connector {
|
left: -16px;
|
display: none;
|
}
|
|
.toolbar {
|
padding: 10px 0;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
}
|
</style>
|
</head>
|
<body>
|
|
<div id="app" v-cloak>
|
<el-card class="main-card" :body-style="{ padding: '0px', display: 'flex', flexDirection: 'column', height: '100%' }">
|
<div slot="header" class="clearfix">
|
<span style="font-weight: bold; font-size: 16px;">站点与堆垛机任务关联配置</span>
|
<div style="float: right;">
|
<el-button type="primary" icon="el-icon-check" size="small" @click="saveData" :loading="saving">保存配置</el-button>
|
<el-button icon="el-icon-refresh" size="small" @click="loadData">刷新</el-button>
|
</div>
|
</div>
|
|
<div class="toolbar" style="padding: 10px 20px; border-bottom: 1px solid #ebeef5;">
|
<el-alert
|
title="操作说明:拖拽左侧的【站点】到右侧的【设备】上即可建立关联。点击连线可删除关联。"
|
type="info"
|
show-icon
|
:closable="false">
|
</el-alert>
|
</div>
|
|
<div class="flow-container" ref="flowContainer">
|
<!-- Left: Stations -->
|
<div class="column">
|
<div class="column-header">站点列表 ({{ stations.length }})</div>
|
<div class="list-container" ref="stationList">
|
<div
|
v-for="item in stations"
|
:key="'s-' + item.stationId"
|
:id="'station-' + item.stationId"
|
class="node-item station-node"
|
:class="{ active: isStationConnected(item.stationId) }"
|
draggable="true"
|
@dragstart="onDragStart($event, item, 'station')"
|
@dragend="onDragEnd"
|
>
|
<span>{{ item.stationId }}</span>
|
</div>
|
</div>
|
</div>
|
|
<!-- Middle: Canvas -->
|
<div class="canvas-area">
|
<svg width="100%" height="100%">
|
<line
|
v-for="(link, index) in lines"
|
:key="index"
|
:x1="link.x1"
|
:y1="link.y1"
|
:x2="link.x2"
|
:y2="link.y2"
|
@click="confirmDelete(index)"
|
>
|
<title>点击删除关联: 站点 {{ link.stationId }} -> 设备 {{ link.deviceNo }}</title>
|
</line>
|
|
<!-- Dragging Line Preview -->
|
<line
|
v-if="draggingLine"
|
:x1="draggingLine.x1"
|
:y1="draggingLine.y1"
|
:x2="draggingLine.x2"
|
:y2="draggingLine.y2"
|
stroke="#409eff"
|
stroke-dasharray="5,5"
|
stroke-width="2"
|
/>
|
</svg>
|
</div>
|
|
<!-- Right: Devices -->
|
<div class="column right">
|
<div class="column-header">堆垛机设备 ({{ devices.length }})</div>
|
<div class="list-container" ref="deviceList">
|
<div
|
v-for="item in devices"
|
:key="'d-' + item.type + '-' + item.deviceNo"
|
:id="'device-' + item.type + '-' + item.deviceNo"
|
class="node-item device-node"
|
:class="{ active: isDeviceConnected(item.deviceNo, item.type) }"
|
@dragover.prevent
|
@drop="onDrop($event, item)"
|
>
|
<span>{{ item.name }}</span>
|
<el-tag size="mini" :type="item.type === 'Crn' ? 'success' : 'warning'">{{ item.type === 'Crn' ? '堆垛机' : '双工位' }}</el-tag>
|
</div>
|
</div>
|
</div>
|
</div>
|
</el-card>
|
</div>
|
|
<!-- Libraries -->
|
<script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
|
<script type="text/javascript" src="../../static/vue/js/vue.min.js"></script>
|
<script type="text/javascript" src="../../static/vue/element/element.js"></script>
|
<script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script>
|
<script type="text/javascript" src="../../static/js/basStationDevice/basStationDevice.js"></script>
|
</body>
|
</html>
|