<!DOCTYPE html>
|
<html lang="zh-CN">
|
<head>
|
<meta charset="UTF-8">
|
<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.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
<title>WCS输送设备管理</title>
|
<link rel="stylesheet" href="../static/css/normalize.css">
|
<link rel="stylesheet" href="../static/css/common.css">
|
<link rel="stylesheet" href="../static/css/pipeline.css">
|
<style>
|
.io-mode-box {
|
float: left;
|
width: 16%;
|
text-align: center;
|
}
|
|
.io-mode-box label {
|
font-weight: bolder;
|
}
|
|
.ioModeBtn {
|
vertical-align: middle;
|
width: 50%;
|
height: 30px;
|
text-shadow: inherit;
|
font-size: 15px;
|
margin: 0 5px;
|
display: inline-block;
|
background-color: #FF5722;
|
border: none;
|
color: #FFF;
|
box-shadow: 1px 1px 5px #B6B6B6;
|
border-radius: 3px;
|
cursor: pointer;
|
}
|
</style>
|
<script src="../static/js/jquery/jquery-3.3.1.min.js"></script>
|
<script src="../static/js/common.js"></script>
|
<script src="../static/js/layer/layer.js"></script>
|
</head>
|
<body>
|
<!-- 左侧按钮区域 -->
|
<aside class="sidebar" style="padding: 10px; height: 100%; float: left; width: 6%;">
|
<div class="button-window"></div>
|
</aside>
|
|
<!-- 主内容区域 -->
|
<div class="main-content" style="height: 100%; padding-left: 6%;">
|
<div class="container" style="padding: 10px; height: 100%;">
|
<!-- 主要内容 -->
|
<main>
|
<!-- 站点状态数据监控版 -->
|
<section id="site-monitor" class="main-board">
|
<!-- 表格 -->
|
<!-- 固定表头:table加table-layout: fixed; th加position:sticky;top: 0; -->
|
<table id="site-table" class="status-table" style="table-layout: fixed;">
|
<!-- 表头 -->
|
<thead class="table-header" style="position:sticky;top: 0;">
|
<tr>
|
<th>站号</th>
|
<th>工作号</th>
|
<th>自动</th>
|
<th>有物</th>
|
<th>可入</th>
|
<th>可出</th>
|
<th>入库标记</th>
|
<th>空板信号</th>
|
<th>目标站</th>
|
<th>高低库位</th>
|
</tr>
|
</thead>
|
<!-- 表格内容 -->
|
<tbody class="table-body"></tbody>
|
</table>
|
</section>
|
</main>
|
|
<!-- 页脚区域 -->
|
<footer>
|
<textarea id="output" class="output-log"></textarea>
|
</footer>
|
|
<!-- 站点详情弹窗 -->
|
<div id="site-detl" class="site-detail-form" style="display: none;">
|
<form class="detail-form">
|
<div class="form-item">
|
<label class="form-label" for="siteId">站号:</label>
|
<div class="form-input">
|
<input id="siteId" name="siteId" class="layui-input" type="number" lay-verify="required|number" autocomplete="off" disabled="disabled">
|
</div>
|
</div>
|
<div class="form-item">
|
<label class="form-label" for="workNo">工作号:</label>
|
<div class="form-input">
|
<input id="workNo" name="workNo" type="number" class="layui-input" lay-verify="number" autocomplete="off">
|
</div>
|
</div>
|
<div class="form-item">
|
<label class="form-label" for="staNo">目标站:</label>
|
<div class="form-input">
|
<input id="staNo" name="staNo" type="number" class="layui-input" lay-verify="number" autocomplete="off">
|
</div>
|
</div>
|
<div class="form-item">
|
<label class="form-label" for="pakMk">入库标记:</label>
|
<div class="form-input">
|
<input id="pakMk" name="pakMk" type="text" class="layui-input" autocomplete="off">
|
</div>
|
</div>
|
<div class="form-item form-button-container">
|
<button type="button" class="form-button" id="save">保存</button>
|
<button type="button" class="form-button" id="cancel" style="background-color: #D0D0D0;">取消</button>
|
</div>
|
</form>
|
</div>
|
</div>
|
</div>
|
</body>
|
<script>
|
// 自执行函数表达式,避免全局变量污染
|
(function() {
|
// 初始化变量
|
let isSiteUpdatePaused = false;
|
let plcErrorTableBlankRows = 0;
|
let siteTableBlankRows = 0;
|
let plcErrorTableFullRows = 0;
|
let siteTableFullRows = 0;
|
const outputDom = document.getElementById("output");
|
let ioModeData = [];
|
let layerDetl = null;
|
let timers = [];
|
|
// DOM加载完成后初始化
|
$(document).ready(function() {
|
// 初始化表格
|
initPlcErrorTable();
|
initSiteTable();
|
|
// 加载初始数据
|
getPlcError();
|
getSite();
|
|
// 初始化定时器
|
initTimers();
|
});
|
|
// 初始化定时器
|
function initTimers() {
|
// 每秒更新PLC错误、站点信息和IO模式
|
timers.push(setInterval(() => {
|
getPlcError();
|
if (!isSiteUpdatePaused) {
|
getSite();
|
}
|
getIoModeInfo();
|
}, 1000));
|
|
// 每500毫秒更新站点输出日志
|
timers.push(setInterval(() => {
|
getSiteOutput();
|
}, 500));
|
}
|
|
|
|
/**
|
* 强制切换入出库模式
|
* @param {string} el - 元素ID
|
*/
|
function ioModeSwitch(el) {
|
const floor = el.split("-")[2];
|
const targetFloor = ioModeData.find(e => e.floor === Number(floor));
|
|
if (targetFloor && (targetFloor.modeVal === 3 || targetFloor.modeVal === 4)) {
|
layer.confirm('确定切换为入库模式吗?', () => {
|
ajaxRequest({
|
url: `${baseUrl}/site/io/mode/action/site`,
|
method: 'POST',
|
data: { floor: targetFloor.floor },
|
success: (res) => {
|
layer.msg("暂时不能切换!", { icon: 1 });
|
}
|
});
|
layer.closeAll();
|
});
|
}
|
}
|
|
// 获取PLC异常信息表
|
function getPlcError() {
|
const tableEl = $('#plc-error-table');
|
tableEl.children("tr").children("td").html("");
|
|
ajaxRequest({
|
url: `${baseUrl}/site/table/plc/errors`,
|
method: 'POST',
|
success: (res) => {
|
if (res.data) {
|
const tableData = res.data;
|
for (let i = 0; i < tableData.length; i++) {
|
const tr = tableEl.find("tr").eq(i + 1);
|
tr.children("td").eq(0).html(tableData[i].no);
|
tr.children("td").eq(1).html(tableData[i].plcDesc);
|
tr.children("td").eq(2).html(tableData[i].error);
|
}
|
}
|
}
|
});
|
}
|
|
// 获取站点信息表
|
function getSite() {
|
const tableEl = $('#site-table');
|
|
ajaxRequest({
|
url: `${baseUrl}/site/table/site`,
|
method: 'POST',
|
success: (res) => {
|
if (res.data) {
|
const tableData = res.data;
|
if (tableData.length > siteTableBlankRows && tableData.length !== siteTableFullRows) {
|
initSiteTable(tableData.length - siteTableBlankRows);
|
siteTableFullRows = tableData.length;
|
}
|
|
for (let i = 0; i < tableData.length; i++) {
|
const tr = tableEl.find("tr").eq(i + 1);
|
setVal(tr.children("td").eq(0), tableData[i].devNo);
|
setVal(tr.children("td").eq(1), tableData[i].workNo);
|
setVal(tr.children("td").eq(2), tableData[i].autoing);
|
setVal(tr.children("td").eq(3), tableData[i].loading);
|
setVal(tr.children("td").eq(4), tableData[i].inEnable);
|
setVal(tr.children("td").eq(5), tableData[i].outEnable);
|
setVal(tr.children("td").eq(6), tableData[i].pakMk);
|
setVal(tr.children("td").eq(7), tableData[i].emptyMk);
|
setVal(tr.children("td").eq(8), tableData[i].staNo);
|
setVal(tr.children("td").eq(9), tableData[i].locType1);
|
}
|
}
|
}
|
});
|
}
|
|
// 获取输送设备日志输出
|
function getSiteOutput() {
|
ajaxRequest({
|
url: `${baseUrl}/site/output/site`,
|
method: 'POST',
|
success: (res) => {
|
if (res.data) {
|
output(res.data);
|
}
|
},
|
error: (res) => {
|
alert(res.msg);
|
}
|
});
|
}
|
|
// 日志输出框
|
function output(content) {
|
outputDom.value += content;
|
outputDom.scrollTop = outputDom.scrollHeight;
|
}
|
|
// PLC异常空白表格渲染
|
function initPlcErrorTable(row) {
|
let line;
|
if (row === undefined) {
|
const one = $('#plc-error-table thead').height();
|
const total = $('.plc-log-body').height();
|
const count = parseInt(total / one) - 1;
|
plcErrorTableBlankRows = count;
|
line = count;
|
} else {
|
line = row;
|
}
|
|
let html = "";
|
for (let i = 0; i < line; i++) {
|
html += ` <tr>
|
<td></td>
|
<td></td>
|
<td></td>
|
</tr>`;
|
}
|
$('#plc-error-table tbody').after(html);
|
}
|
|
// 站点空白表格渲染
|
function initSiteTable(row) {
|
let line;
|
if (row === undefined) {
|
const one = $('#site-table thead').height();
|
const total = $('#site-monitor').height();
|
const count = parseInt(total / one) - 1;
|
siteTableBlankRows = count;
|
line = count;
|
} else {
|
line = row;
|
}
|
|
let html = "";
|
for (let i = 0; i < line; i++) {
|
html += ` <tr>
|
<td></td>
|
<td></td>
|
<td></td>
|
<td></td>
|
<td></td>
|
<td></td>
|
<td></td>
|
<td></td>
|
<td></td>
|
<td></td>
|
</tr>`;
|
}
|
$('#site-table tbody').after(html);
|
}
|
|
// 详情操作
|
$(document).on('dblclick', '#site-table tr', function() {
|
isSiteUpdatePaused = true;
|
const siteId = $(this).children("td").eq(0).html();
|
|
if (siteId) {
|
layerDetl = layer.open({
|
type: 1,
|
title: false,
|
shadeClose: true,
|
offset: 'rt',
|
anim: 5,
|
shade: [0],
|
area: ['340px', '255px'],
|
closeBtn: 0,
|
content: $("#site-detl"),
|
success: (layero, index) => {
|
http.get(`${baseUrl}/site/detl/${siteId}`, null, (res) => {
|
if (res.data) {
|
$('#siteId').val(siteId);
|
$('#workNo').val(res.data.workNo);
|
$('#staNo').val(res.data.staNo);
|
$('#pakMk').val(res.data.pakMk);
|
}
|
});
|
},
|
end: () => {
|
$('#siteId').val("");
|
$('#workNo').val("");
|
$('#staNo').val("");
|
$('#pakMk').val("");
|
isSiteUpdatePaused = false;
|
}
|
});
|
}
|
});
|
|
// 保存站点信息
|
$(document).on('click', '#save', function() {
|
http.post(`${baseUrl}/site/detl/update`, {
|
siteId: $('#siteId').val(),
|
workNo: $('#workNo').val(),
|
staNo: $('#staNo').val(),
|
pakMk: $('#pakMk').val()
|
}, (res) => {
|
layer.msg("修改成功", { icon: 1 });
|
});
|
});
|
|
// 取消站点信息修改
|
$(document).on('click', '#cancel', function() {
|
$('#siteId').val("");
|
$('#workNo').val("");
|
$('#staNo').val("");
|
$('#pakMk').val("");
|
layer.close(layerDetl);
|
});
|
|
// 通用AJAX请求函数
|
function ajaxRequest(options) {
|
const defaultOptions = {
|
headers: { 'token': localStorage.getItem('token') },
|
success: () => {},
|
error: () => {}
|
};
|
|
const opts = { ...defaultOptions, ...options };
|
|
$.ajax({
|
url: opts.url,
|
headers: opts.headers,
|
method: opts.method,
|
data: opts.data,
|
success: (res) => {
|
if (res.code === 200) {
|
opts.success(res);
|
} else if (res.code === 403) {
|
window.location.href = `${baseUrl}/login`;
|
} else {
|
console.log(res.msg);
|
//opts.error(res);
|
}
|
},
|
error: (jqXHR, textStatus, errorThrown) => {
|
console.error('AJAX Error:', textStatus, errorThrown);
|
//opts.error({ msg: '请求失败,请稍后重试' });
|
}
|
});
|
}
|
})();
|
|
</script>
|
</html>
|