<!DOCTYPE html>
|
<html lang="en">
|
<head>
|
<meta charset="UTF-8">
|
<title>WCS控制中心</title>
|
<link rel="stylesheet" href="../../static/css/animate.min.css">
|
<link rel="stylesheet" href="../../static/vue/element/element.css">
|
<link rel="stylesheet" href="../../static/css/watch/console_vue.css">
|
<script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
|
<script type="text/javascript" src="../../static/layui/layui.js"></script>
|
<script type="text/javascript" src="../../static/js/handlebars/handlebars-v4.5.3.js"></script>
|
<script type="text/javascript" src="../../static/js/common.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 src="../../static/js/gsap.min.js"></script>
|
<script src="../../static/js/pixi-legacy.min.js"></script>
|
</head>
|
<body>
|
<div id="app">
|
<div style="display: flex;margin-left: 20px;">
|
<div style="width: 20%;height: 60vh;margin-right: 20px;margin-top: 30px;">
|
<el-tabs type="border-card" v-model="activateCard" @tab-click="handleCardClick">
|
<el-tab-pane label="堆垛机" name="crn">
|
<watch-crn-card ref="watchCrnCard" :param="crnParam"></watch-crn-card>
|
</el-tab-pane>
|
<el-tab-pane label="双工位堆垛机" name="dualCrn">
|
<watch-dual-crn-card ref="watchDualCrnCard" :param="dualCrnParam"></watch-dual-crn-card>
|
</el-tab-pane>
|
<el-tab-pane label="输送站" name="devp">
|
<devp-card ref="devpCard" :param="devpParam"></devp-card>
|
</el-tab-pane>
|
<el-tab-pane label="RGV" name="rgv">
|
<watch-rgv-card ref="watchRgvCard" :param="rgvParam"></watch-rgv-card>
|
</el-tab-pane>
|
<!-- <el-tab-pane label="地图配置" name="mapSetting">
|
<map-setting-card :param="mapSettingParam"></map-setting-card>
|
</el-tab-pane> -->
|
</el-tabs>
|
</div>
|
|
<map-canvas :lev="currentLev" :crn-param="crnParam" :rgv-param="rgvParam" :devp-param="devpParam" @crn-click="openCrn" @dual-crn-click="openDualCrn" @station-click="openSite" style="width: 80%; height: 100vh;"></map-canvas>
|
|
<div style="position: absolute;top: 15px;left: 50%;display: flex;">
|
<div v-if="levList.length > 1" v-for="(lev,index) in levList" :key="index" style="margin-right: 10px;">
|
<el-button :type="currentLev == lev ? 'primary' : ''" @click="switchLev(lev)" size="mini">{{ lev }}F</el-button>
|
</div>
|
</div>
|
</div>
|
|
</div>
|
|
<script src="../../components/WatchCrnCard.js"></script>
|
<script src="../../components/WatchDualCrnCard.js"></script>
|
<script src="../../components/DevpCard.js"></script>
|
<script src="../../components/MapSettingCard.js"></script>
|
<script src="../../components/WatchRgvCard.js"></script>
|
<script src="../../components/MapCanvas.js"></script>
|
<script>
|
let ws;
|
var app = new Vue({
|
el: '#app',
|
data: {
|
map: [],//地图数据
|
levList: [],
|
currentLev: 1,
|
systemStatus: true,//系统运行状态
|
consoleInterval: null,//定时器存储变量
|
rgvPosition: [],
|
activateCard: 'crn',
|
crnParam: {
|
crnNo: 0
|
},
|
dualCrnParam: {
|
crnNo: 0
|
},
|
mapSettingParam: {
|
zoom: 70
|
},
|
devpParam: {
|
stationId: 0
|
},
|
rgvParam: {
|
rgvNo: 0
|
},
|
locMastData: [],//库位数据
|
wsReconnectTimer: null,
|
wsReconnectAttempts: 0,
|
wsReconnectBaseDelay: 1000,
|
wsReconnectMaxDelay: 15000
|
},
|
created() {
|
this.init()
|
},
|
mounted() {
|
},
|
beforeDestroy() {
|
if (this.wsReconnectTimer) { clearTimeout(this.wsReconnectTimer); this.wsReconnectTimer = null; }
|
if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) { try { ws.close(); } catch (e) {} }
|
},
|
watch: {
|
|
},
|
methods: {
|
sendWs(data) {
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
ws.send(data);
|
}
|
},
|
webSocketOnOpen() {
|
console.log("WebSocket连接成功");
|
if (this.wsReconnectTimer) { clearTimeout(this.wsReconnectTimer); this.wsReconnectTimer = null; }
|
this.wsReconnectAttempts = 0;
|
this.getMap();
|
},
|
webSocketOnError() {
|
console.log("WebSocket连接发生错误");
|
this.scheduleWsReconnect();
|
},
|
webSocketClose() {
|
console.log("WebSocket连接关闭");
|
this.scheduleWsReconnect();
|
},
|
webSocketOnMessage(e) {
|
const result = JSON.parse(e.data);
|
if (result.url == "/crn/table/crn/state") {
|
if(this.$refs.watchCrnCard) {
|
this.$refs.watchCrnCard.setCrnList(JSON.parse(result.data));
|
}
|
} else if (result.url == "/dualcrn/table/crn/state") {
|
if(this.$refs.watchDualCrnCard) {
|
this.$refs.watchDualCrnCard.setDualCrnList(JSON.parse(result.data));
|
}
|
} else if (result.url == "/console/latest/data/station") {
|
if(this.$refs.devpCard) {
|
this.$refs.devpCard.setStationList(JSON.parse(result.data));
|
}
|
} else if (result.url == "/rgv/table/rgv/state") {
|
if(this.$refs.watchRgvCard) {
|
this.$refs.watchRgvCard.setRgvList(JSON.parse(result.data));
|
}
|
} else if (result.url == "/basMap/lev/" + this.currentLev + "/auth") {
|
// 地图数据
|
let res = JSON.parse(result.data);
|
if (res.code === 200) {
|
this.map = res.data;
|
}
|
}
|
},
|
getMap() {
|
this.sendWs(JSON.stringify({
|
"url": "/basMap/lev/" + this.currentLev + "/auth",
|
"data": {}
|
}))
|
},
|
init() {
|
this.connectWs();
|
|
this.getSystemRunningStatus() //获取系统运行状态
|
this.getLevList() //获取地图层级列表
|
this.getLocMastData() //获取库位数据
|
},
|
connectWs() {
|
if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) { return; }
|
ws = new WebSocket("ws://" + window.location.host + baseUrl + "/console/websocket");
|
ws.onopen = this.webSocketOnOpen;
|
ws.onerror = this.webSocketOnError;
|
ws.onmessage = this.webSocketOnMessage;
|
ws.onclose = this.webSocketClose;
|
},
|
scheduleWsReconnect() {
|
if (this.wsReconnectTimer) { return; }
|
const attempt = this.wsReconnectAttempts + 1;
|
const jitter = Math.floor(Math.random() * 300);
|
const delay = Math.min(this.wsReconnectMaxDelay, this.wsReconnectBaseDelay * Math.pow(2, this.wsReconnectAttempts)) + jitter;
|
this.wsReconnectTimer = setTimeout(() => {
|
this.wsReconnectTimer = null;
|
this.wsReconnectAttempts = attempt;
|
this.connectWs();
|
}, delay);
|
},
|
getLevList() {
|
let that = this;
|
$.ajax({
|
url: baseUrl + "/basMap/getLevList",
|
headers: {
|
'token': localStorage.getItem('token')
|
},
|
method: "get",
|
success: (res) => {
|
let data = res.data;
|
that.levList = data;
|
}
|
})
|
},
|
switchLev(lev) {
|
this.currentLev = lev;
|
this.getMap()
|
this.getLocMastData()
|
},
|
openCrn(id) {
|
this.crnParam.crnNo = id;
|
this.activateCard = 'crn';
|
console.log(id);
|
},
|
openDualCrn(id) {
|
this.dualCrnParam.crnNo = id;
|
this.activateCard = 'dualCrn';
|
console.log(id);
|
|
},
|
openRgv(id) {
|
this.rgvParam.rgvNo = id;
|
this.activateCard = 'rgv';
|
},
|
openSite(id) {
|
this.devpParam.stationId = id;
|
this.activateCard = 'devp';
|
},
|
systemSwitch() {
|
// 系统开关
|
let that = this
|
if (this.systemStatus) {
|
this.$prompt('请输入口令,并停止WCS系统', '提示', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
}).then(({
|
value
|
}) => {
|
that.doSwitch(0, value)
|
}).catch(() => {
|
|
});
|
} else {
|
this.doSwitch(1)
|
}
|
},
|
doSwitch(operatorType, password) {
|
let that = this
|
$.ajax({
|
url: baseUrl + "/console/system/switch",
|
headers: {
|
'token': localStorage.getItem('token')
|
},
|
data: {
|
operatorType: operatorType,
|
password: password
|
},
|
method: 'POST',
|
success: function(res) {
|
if (res.code === 200) {
|
if (res.data.status) {
|
$('#system-toggle-checked').attr("checked", true);
|
$('#system-run-desc').html("系统运行中...");
|
that.systemStatus = true;
|
parent.systemRunning = true;
|
} else {
|
$('#system-toggle-checked').attr("checked", false);
|
$('#system-run-desc').html("系统已停止!");
|
that.systemStatus = false;
|
parent.systemRunning = false;
|
}
|
} else if (res.code === 403) {
|
parent.location.href = baseUrl + "/login";
|
} else {
|
that.$message({
|
message: res.msg,
|
type: 'error'
|
});
|
}
|
}
|
});
|
},
|
getSystemRunningStatus() {
|
// 获取wcs系统运行状态
|
let that = this
|
$.ajax({
|
url: baseUrl + "/console/system/running/status",
|
headers: {
|
'token': localStorage.getItem('token')
|
},
|
method: 'POST',
|
success: function(res) {
|
if (res.code === 200) {
|
if (res.data.status) {
|
$('#system-toggle-checked').attr("checked", true);
|
$('#system-run-desc').html("系统运行中...");
|
that.systemStatus = true;
|
parent.systemRunning = true;
|
} else {
|
$('#system-toggle-checked').attr("checked", false);
|
$('#system-run-desc').html("系统已停止!");
|
that.systemStatus = false;
|
parent.systemRunning = false;
|
}
|
} else if (res.code === 403) {
|
parent.location.href = baseUrl + "/login";
|
} else {
|
that.$message({
|
message: res.msg,
|
type: 'error'
|
});
|
}
|
}
|
});
|
},
|
getCrnTargetCell(crnEl, bay) {
|
if (!crnEl || bay == null) {
|
return null;
|
}
|
let rowEl = crnEl.closest('tr');
|
if (!rowEl || rowEl.length === 0) {
|
return null;
|
}
|
let targetCell = null;
|
let colCounter = 0;
|
let startCount = false;
|
rowEl.find('td').each(function () {
|
// 以当前行中首次出现的track-item为起点进行列计数
|
const isTrackCrn = $(this).find('.track-crn').length > 0;
|
if (!startCount && !isTrackCrn) {
|
return;
|
}
|
let span = parseInt($(this).attr('colspan'), 10);
|
if (isNaN(span) || span < 1) {
|
span = 1;
|
}
|
if (!startCount && isTrackCrn) {
|
startCount = true;
|
}
|
colCounter += span;
|
if (targetCell == null && colCounter >= bay) {
|
targetCell = $(this);
|
return false;
|
}
|
});
|
return targetCell;
|
},
|
getDeviceNo(obj) {
|
if (this.isJson(obj)) {
|
let data = JSON.parse(obj)
|
if (data.deviceNo == null || data.deviceNo == undefined) {
|
return -1;
|
}
|
return data.deviceNo;
|
}else {
|
return -1;
|
}
|
},
|
getStationId(obj) {
|
if (this.isJson(obj)) {
|
let data = JSON.parse(obj)
|
if (data.stationId == null || data.stationId == undefined) {
|
return -1;
|
}
|
return data.stationId;
|
}else {
|
return -1;
|
}
|
},
|
getTrackSiteNo(obj) {
|
if (this.isJson(obj)) {
|
let data = JSON.parse(obj)
|
if (data.trackSiteNo == null || data.trackSiteNo == undefined) {
|
return -1;
|
}
|
return data.trackSiteNo;
|
}else {
|
return -1;
|
}
|
},
|
isJson(str) {
|
try {
|
JSON.parse(str);
|
return true;
|
} catch (e) {
|
return false;
|
}
|
},
|
handleCardClick(tab, event) {
|
|
},
|
//获取库位数据
|
getLocMastData() {
|
let that = this;
|
$.ajax({
|
url: baseUrl + "/console/map/locList",
|
headers: {
|
'token': localStorage.getItem('token')
|
},
|
method: "get",
|
data: {},
|
success: (res) => {
|
if (res.code === 200) {
|
that.locMastData = res.data;
|
}
|
}
|
})
|
},
|
//根据地图坐标获取库位的排列信息
|
getShelfLocInfo(rowIdx, colIdx) {
|
if (!this.locMastData || this.locMastData.length === 0) {
|
return '';
|
}
|
// 在locMastData中查找匹配的库位
|
// locType字段存储的是地图坐标信息
|
let locInfo = this.locMastData.find(loc => {
|
if (!loc.locType) return false;
|
// locType格式类似 "0-1-1" (mapX-mapY-lev)
|
let parts = loc.locType.split('-');
|
if (parts.length >= 2) {
|
return parseInt(parts[0]) === rowIdx && parseInt(parts[1]) === colIdx;
|
}
|
return false;
|
});
|
|
if (locInfo && locInfo.row1 && locInfo.bay1) {
|
return locInfo.row1 + '-' + locInfo.bay1;
|
}
|
return '';
|
},
|
}
|
})
|
</script>
|
</body>
|
</html>
|