feat: 套轴日志看板

This commit is contained in:
2025-05-27 20:31:53 +08:00
parent 5467a7514c
commit 8fedac67aa
10 changed files with 623 additions and 34 deletions

View File

@@ -0,0 +1,416 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>套轴点位日志记录实时看板</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #183a5c 0%, #274b7a 100%); /* 深科技蓝渐变背景 */
color: #cfd8e3; /* 浅灰蓝文本 */
margin: 0;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
h1 {
color: #ffffff; /* 亮蓝标题40a9ff */
text-align: center;
font-size: 2.5em;
margin-bottom: 30px;
text-shadow: 0 2px 12px #274b7a;
}
.dashboard-container {
display: flex;
justify-content: space-around;
width: 100%;
max-width: 1800px;
margin-bottom: 30px;
}
.device-card {
background: #223a5c; /* 中深蓝卡片背景 */
border: 1px solid #40a9ff; /* 亮蓝边框 */
border-radius: 10px;
padding: 20px;
width: 45%;
min-height: 300px;
height: 350px; /* 新增:固定高度 */
box-shadow: 0 2px 16px rgba(64,169,255,0.12);
transition: transform 0.3s, box-shadow 0.3s;
display: flex;
flex-direction: column;
}
.log-entries {
flex: 1;
overflow-y: auto;
max-height: 250px;
/* 美化滚动条 */
scrollbar-width: thin;
scrollbar-color: #40a9ff #223a5c;
}
.log-entries::-webkit-scrollbar {
width: 8px;
}
.log-entries::-webkit-scrollbar-thumb {
background: linear-gradient(135deg, #40a9ff 0%, #274b7a 100%);
border-radius: 6px;
}
.log-entries::-webkit-scrollbar-track {
background: #223a5c;
border-radius: 6px;
}
/* .device-card:hover {
transform: translateY(-5px) scale(1.02);
box-shadow: 0 0 30px #40a9ff;
} */
.device-card h2 {
color: #ffffff;
border-bottom: 1px solid #274b7a;
padding-bottom: 10px;
margin-top: 0;
font-size: 1.5em;
}
.log-entry {
background: #274b7a;
color: #cfd8e3;
padding: 8px;
margin-bottom: 8px;
border-radius: 4px;
border-left: 3px solid #40a9ff;
font-size: 0.95em;
word-wrap: break-word;
}
.table-container {
width: 95%;
max-width: 1800px;
background: #223a5c;
border: 1px solid #40a9ff;
border-radius: 10px;
padding: 0 20px 20px 20px;
margin-top: 20px;
box-shadow: 0 2px 16px rgba(64,169,255,0.12);
}
.table-container h2 {
color: #ffffff;
text-align: center;
font-size: 1.8em;
margin-bottom: 20px;
}
table {
width: 100%;
border-collapse: collapse;
color: #cfd8e3;
background: #274b7a;
}
th, td {
border: 1px solid #3b6ea5;
padding: 10px;
text-align: left;
font-size: 0.95em;
}
th {
background: linear-gradient(90deg, #274b7a 0%, #3b6ea5 100%);
color: #40a9ff;
}
tbody tr:nth-child(odd) {
background: #223a5c;
}
tbody tr:hover {
background: #3b6ea5;
}
.timeout-row-warning {
background: #5c1a1a !important;
color: #f8d7da;
}
.timeout-row-warning td {
color: #f8d7da !important;
}
</style>
</head>
<body>
<h1>套轴点位日志记录实时看板</h1>
<div class="dashboard-container">
<div class="device-card" id="device-B_CBJ01">
<h2>B_CBJ01<span id="tip-B_CBJ01" style="font-size:0.7em;color:#ffec3d;margin-left:12px;"></span></h2>
<!-- 添加tip2显示区域 -->
<div id="tip2-B_CBJ01" style="color:#ffec3d;font-size:0.9em;margin-bottom:10px;background:rgba(64,169,255,0.1);padding:5px;border-radius:4px;"></div>
<div class="log-entries">
<!-- 日志条目将在这里动态添加 -->
</div>
</div>
<div class="device-card" id="device-B_CBJ02">
<h2>B_CBJ02<span id="tip-B_CBJ02" style="font-size:0.7em;color:#ffec3d;margin-left:12px;"></span></h2>
<!-- 添加tip2显示区域 -->
<div id="tip2-B_CBJ02" style="color:#ffec3d;font-size:0.9em;margin-bottom:10px;background:rgba(64,169,255,0.1);padding:5px;border-radius:4px;"></div>
<div class="log-entries">
<!-- 日志条目将在这里动态添加 -->
</div>
</div>
</div>
<!-- 新增的表格容器 -->
<div class="table-container">
<h2>套轴监控系统实时数据</h2>
<table id="slitter-table">
<thead>
<tr>
<th>设备</th>
<th>子卷号</th>
<th>轴位置</th>
<th>气胀轴尺寸</th>
<th>气胀轴代数</th>
<th>气胀轴状态</th>
<th>呼叫时间</th>
<th>管芯规格</th>
<th>套轴标记</th>
</tr>
</thead>
<tbody id="slitter-table-body">
<!-- 表格数据将在这里动态添加 -->
</tbody>
</table>
</div>
<script>
const logApiUrl = 'http://localhost:9999/api/wms/apply/v2/tzInfo';
const devices = ['B_CBJ01', 'B_CBJ02'];
const refreshInterval = 5000; // 刷新间隔统一为5秒
async function fetchLogData(deviceCode) {
try {
const response = await fetch(logApiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ device_code: deviceCode }),
});
if (!response.ok) {
const errorText = await response.text();
console.error(`HTTP error response for ${deviceCode} (log):`, errorText);
throw new Error(`HTTP error! status: ${response.status} for ${deviceCode} (log). Response: ${errorText}`);
}
const responseText = await response.text();
if (!responseText) {
console.warn(`Empty response received for ${deviceCode} (log)`);
return [];
}
try {
const data = JSON.parse(responseText);
return data;
} catch (e) {
console.error(`Error parsing JSON for ${deviceCode} (log):`, e);
console.error(`Raw response text for ${deviceCode} (log):`, responseText);
throw new Error(`Failed to parse JSON response for ${deviceCode} (log). Raw text: ${responseText.substring(0, 100)}...`);
}
} catch (error) {
console.error(`Error fetching log data for ${deviceCode}:`, error);
return [`获取 ${deviceCode} 日志数据失败: ${error.message}`];
}
}
function displayLogData(deviceCode, data) {
const deviceElement = document.getElementById(`device-${deviceCode}`);
if (!deviceElement) {
console.error(`Element with ID 'device-${deviceCode}' not found.`);
return;
}
const logEntriesContainer = deviceElement.querySelector('.log-entries');
logEntriesContainer.innerHTML = '';
if (Array.isArray(data) && data.length > 0) {
data.forEach(entry => {
const logEntryDiv = document.createElement('div');
logEntryDiv.classList.add('log-entry');
logEntryDiv.textContent = entry;
logEntriesContainer.appendChild(logEntryDiv);
});
} else {
const noDataEntry = document.createElement('div');
noDataEntry.classList.add('log-entry');
noDataEntry.textContent = '暂无日志信息。';
logEntriesContainer.appendChild(noDataEntry);
}
}
async function updateLogDashboard() {
for (const device of devices) {
const data = await fetchLogData(device);
displayLogData(device, data);
}
}
// 新增表格数据相关逻辑
const tableApiUrl = 'http://127.0.0.1:9999/api/pda/slitter/showManualView';
async function fetchTableData() {
try {
const response = await fetch(tableApiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
project: "套轴监控系统",
timestamp: Date.now() // 使用当前时间戳
}),
});
if (!response.ok) {
const errorText = await response.text();
console.error('HTTP error response for table data:', errorText);
throw new Error(`HTTP error! status: ${response.status} for table data. Response: ${errorText}`);
}
const responseText = await response.text();
if (!responseText) {
console.warn('Empty response received for table data');
return [];
}
try {
const data = JSON.parse(responseText);
return data;
} catch (e) {
console.error('Error parsing JSON for table data:', e);
console.error('Raw response text for table data:', responseText);
throw new Error(`Failed to parse JSON response for table data. Raw text: ${responseText.substring(0, 100)}...`);
}
} catch (error) {
console.error('Error fetching table data:', error);
// 可以选择在表格中显示错误信息
const tableBody = document.getElementById('slitter-table-body');
if (tableBody) {
tableBody.innerHTML = `<tr><td colspan="7">获取表格数据失败: ${error.message}</td></tr>`;
}
return []; // 返回空数组以避免后续处理错误
}
}
function displayTableData(data) {
const tableBody = document.getElementById('slitter-table-body');
if (!tableBody) {
console.error("Element with ID 'slitter-table-body' not found.");
return;
}
tableBody.innerHTML = ''; // 清空旧数据
if (Array.isArray(data) && data.length > 0) {
data.forEach(item => {
const row = tableBody.insertRow();
row.insertCell().textContent = item.resource_name || 'N/A';
row.insertCell().textContent = item.container_name || 'N/A';
row.insertCell().textContent = item.up_or_down === '1' ? '上' : (item.up_or_down === '2' ? '下' : item.up_or_down || 'N/A');
row.insertCell().textContent = item.qzz_size || 'N/A';
row.insertCell().textContent = item.qzz_generation || 'N/A';
let statusText = '已完成';
if (item.status === '01') {
statusText = '准备套轴';
} else if (item.status === '02') {
statusText = '正在配送';
} else if (item.status === '03') {
statusText = '配送完成';
} else if (item.status) {
statusText = item.status;
}
row.insertCell().textContent = statusText;
const startTimeCell = row.insertCell();
startTimeCell.textContent = item.start_time || 'N/A';
row.insertCell().textContent = item.tube || 'N/A';
let tzText = '未套轴';
if (item.is_paper_ok === '2') {
tzText = '已套轴';
}
row.insertCell().textContent = tzText || 'N/A';
// 检查start_time是否超过2小时并设置行样式
if (item.start_time) {
const startTime = new Date(item.start_time.replace(/-/g, '/'));
const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000);
if (startTime < twoHoursAgo) {
row.classList.add('timeout-row-warning'); // 应用于整行
}
}
});
} else {
const row = tableBody.insertRow();
const cell = row.insertCell();
cell.colSpan = 7;
cell.textContent = '暂无数据。';
cell.style.textAlign = 'center';
}
}
async function updateTableDashboard() {
const data = await fetchTableData();
displayTableData(data);
}
// 新增获取tip并显示在标题后
const tipApiUrl = 'http://localhost:9999/api/wms/apply/v2/tzTaskINfo';
async function fetchAndDisplayTip(deviceCode) {
try {
const response = await fetch(tipApiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ device_code: deviceCode })
});
let tip = '';
let tip2 = '';
if (response.ok) {
const data = await response.json();
tip = data.tip || '';
tip2 = data.tip2 || '';
// 显示tip2在对应设备标题下方
document.getElementById('tip2-' + deviceCode).textContent = tip2;
}
document.getElementById('tip-' + deviceCode).textContent = tip;
} catch (e) {
document.getElementById('tip-' + deviceCode).textContent = '';
document.getElementById('tip2-' + deviceCode).textContent = '';
}
}
function updateAllTips() {
devices.forEach(device => fetchAndDisplayTip(device));
}
// 初始加载tip
updateAllTips();
// 定时刷新tip
setInterval(updateAllTips, refreshInterval);
// 初始加载数据
updateLogDashboard();
updateTableDashboard();
// 定时刷新数据
setInterval(updateLogDashboard, refreshInterval);
setInterval(updateTableDashboard, refreshInterval); // 表格也使用相同的刷新间隔
</script>
</body>
</html>

View File

@@ -47,6 +47,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
@@ -102,6 +103,7 @@ public class AutoCallAirShaftTask extends Prun {
public final static String TZ_DAY = "TZ_DAY";
public final static String USE_XN = "USE_XN";
public String stepStr = "";
public List<String> stepErrorInfo = new ArrayList<>();
/**
* hint: 目前只是考虑了上区域
@@ -122,11 +124,12 @@ public class AutoCallAirShaftTask extends Prun {
// 1、获取空的插拔轴位(无任务)
List<BstIvtShafttubeivt> emptyPoints = bstIvtShafttubeivtService.getAllShaftPointsByConditions("2",
"0", "0");
// emptyPoints.forEach(empty -> doCallShaft(empty, isOnlyPulling, tzDay, paramObj));
for (BstIvtShafttubeivt empty : emptyPoints) {
stepStr = "";
stepErrorInfo = new ArrayList<>();
doCallShaft(empty, isOnlyPulling, tzDay, paramObj, useXn);
redisUtils.set("INFO" + empty.getPoint_code(), stepStr);
redisUtils.set("ERROR" + empty.getPoint_code(), stepErrorInfo);
}
}
@@ -137,6 +140,7 @@ public class AutoCallAirShaftTask extends Prun {
String location = empty.getPoint_location();
stepStr += "1";
if (ObjectUtil.isNotEmpty(isOnlyPulling) && SlitterConstant.SLITTER_YES.equals(isOnlyPulling.getValue())) {
stepErrorInfo.add("系统设置了只做拔轴,详细看参数表:" + IS_ONLY_PULLING);
// 只做拔轴
makePullShaft(empty, specification);
return;
@@ -150,12 +154,6 @@ public class AutoCallAirShaftTask extends Prun {
} else {
planAll = slittingproductionplanService.getAllCutPlan(integer);
}
// 排序
/* List<SlitterPlanDistinctDto> planAll = planAllNoSort.stream()
.sorted(Comparator.comparing(
dto -> LocalDateTime.parse(dto.getStart_time(), TIME_FORMATTER)
))
.collect(Collectors.toList());*/
// 过滤
String value = paramObj.getValue();
List<String> prefixList = Arrays.asList(value.split("[,]"));
@@ -165,6 +163,7 @@ public class AutoCallAirShaftTask extends Prun {
checkComputationPoint(p, empty) && checkHasTask(p))
.collect(Collectors.toList());
if (plans.size() == 0) {
stepErrorInfo.add("找不到需要套轴的信息,只做拔轴。");
// 如果不需要套轴,就只做拔轴
makePullShaft(empty, specification);
return;
@@ -225,6 +224,7 @@ public class AutoCallAirShaftTask extends Prun {
.collect(Collectors.toList());
if (qzzs.size() == 0) {
log.info("没有半个点位,或者对应的另一半分切计划没有找到!");
stepErrorInfo.add("找不到需要套轴的信息,只做拔轴。");
// 如果不需要套轴,就只做拔轴
makePullShaft(empty, specification);
return;
@@ -235,6 +235,7 @@ public class AutoCallAirShaftTask extends Prun {
if (ObjectUtil.isEmpty(tzOKPlans)) {
stepStr += ",13";
log.info("计划找不到");
stepErrorInfo.add("找不到气胀轴:" + qzzs + "对应的计划。");
return;
}
PdmBiSlittingproductionplan oneTzOkPlan = tzOKPlans.get(0);
@@ -246,6 +247,7 @@ public class AutoCallAirShaftTask extends Prun {
}
if (plans.size() == 0) {
log.info("没有找到对应的另一半分切计划没有找到");
stepErrorInfo.add("没有找到对应的另一半分切计划, 只做拔轴");
// 如果不需要套轴,就只做拔轴
makePullShaft(empty, specification);
return;
@@ -263,6 +265,7 @@ public class AutoCallAirShaftTask extends Prun {
.orElse(null);
if (planDto == null) {
log.warn("过滤3/6寸和代数输出结果为空跳过此次套轴直接拔轴。此时点位对应代数{}", specification);
stepErrorInfo.add("过滤3/6寸和代数输出结果为空跳过此次套轴直接拔轴。此时点位对应代数{}" + specification);
// 如果不需要套轴,就只做拔轴
makePullShaft(empty, specification);
return;
@@ -303,11 +306,13 @@ public class AutoCallAirShaftTask extends Prun {
List<BstIvtCutpointivt> qzzPoint = bcutpointivtService.getPointByTypeAndShaftSize("1", qzzSize, specification);
log.info("查找到满足到对应尺寸的点位-{}", qzzPoint);
if (qzzPoint.size() == 0) {
stepErrorInfo.add("没有可拔轴的点位。");
stepStr += ",16";
//若套轴暂存位没有相同规格的气胀轴,直接去气胀轴库找即可
// 调用ACS滚条气涨轴下来
if (!toAcsOutShaft(qzzSize,location, empty)) {
log.error("呼叫出轴失败-穿拔轴{}不进行套轴,跳过!", empty.getPoint_code());
stepErrorInfo.add("呼叫出轴失败-穿拔轴" + empty.getPoint_code() + "不进行套轴,跳过!");
return;
}
toCallAgvMovePaperTube(needPlans, location, empty);
@@ -325,6 +330,7 @@ public class AutoCallAirShaftTask extends Prun {
if (oldQzzNo == null) {
log.error("当前气胀轴的编码为空!");
stepStr += ",96";
stepErrorInfo.add(startPoint.getPoint_code() + "的气胀轴编码为空,请检查...");
return;
}
String startPointCode = ObjectUtil.isNotEmpty(startPoint.getQzz_no1())
@@ -332,6 +338,7 @@ public class AutoCallAirShaftTask extends Prun {
if (startPointCode == null) {
log.error("当前点位的编码为空!");
stepStr += ",96";
stepErrorInfo.add(startPoint.getPoint_code() + "的点位编码为空检查A或B点位的信息是否正常");
return;
}
stepStr += ",34";
@@ -385,6 +392,7 @@ public class AutoCallAirShaftTask extends Prun {
startPoint.setRemark("气胀轴" + oldQzzNo + "的计划不存在,无效点位自动禁用。");
startPoint.setUpdate_time(DateUtil.now());
bcutpointivtService.updateById(startPoint);
stepErrorInfo.add("当前气胀轴编码{" + oldQzzNo + "},找不到对应的计划, 点位" + startPoint.getPoint_code() + "已被禁用。");
return;
}
// 保存所需要的分切计划数据到点位上(套轴对接位)更新分切计划
@@ -514,6 +522,7 @@ public class AutoCallAirShaftTask extends Prun {
// 缺省的数量
int needQuantity = 0;
// 判断当前区域location对应的备货区是否含有相同的纸管 校验了不在搬运中
// todo: 要考虑防止所需要的托盘被搬走!
// type=1桁架底下的托盘, 关联对象material_code=纸管, qty > 0
List<BstIvtStockingivt> useList = stockingivtService.getPaperTubePoint("1", tubes.get(0), location, 0);
if (useList.size() > 0) {
@@ -552,6 +561,7 @@ public class AutoCallAirShaftTask extends Prun {
noticeService.createNotice("备货区找不到[" + tubes.get(0) + "]的纸管信息",
"点位[" + empty.getPoint_name() + "]无法从备货区找到纸管信息",
NoticeTypeEnum.EXCEPTION.getCode());
stepErrorInfo.add("备货区找不到[" + tubes.get(0) + "]的纸管信息");
return false;
}
// 找到就创建AGV搬运任务
@@ -584,6 +594,7 @@ public class AutoCallAirShaftTask extends Prun {
noticeService.createNotice("备货区找不到空位置搬运",
"点位[" + empty.getPoint_name() + "]无法从备货区找到空位",
NoticeTypeEnum.EXCEPTION.getCode());
stepErrorInfo.add("备货区找不到空位置搬运。");
return false;
}
BstIvtStockingivt endPoint = list.get(0);
@@ -598,6 +609,7 @@ public class AutoCallAirShaftTask extends Prun {
param.put("product_area", SlitterConstant.SLITTER_TASK_AREA);
stockAreaSendVehicleTask.createTask(param);
stepStr += ",26";
stepErrorInfo.add("备货区交换托盘中...请等待。");
return true;
}
@@ -616,6 +628,7 @@ public class AutoCallAirShaftTask extends Prun {
stepStr += ",28";
if (shafttubeivts.size() == 0) {
log.error("气胀轴库找不到[" + qzzSize + "]规格的气涨轴位");
stepErrorInfo.add("气胀轴库找不到[" + qzzSize + "]规格的气涨轴位");
stepStr += ",98";
return false;
}
@@ -630,9 +643,10 @@ public class AutoCallAirShaftTask extends Prun {
// todo: 暂时都是B1
device_obj.put("product_area", "B1");
JSONObject pointStatus = wmsToAcsService.getPointStatus(device_rows);
if (ObjectUtil.isEmpty(pointStatus) || ObjectUtil.isEmpty(pointStatus.getJSONArray("data"))) {
if (ObjectUtil.isEmpty(pointStatus) || ObjectUtil.isEmpty(pointStatus.getJSONObject("data")) || ObjectUtil.isEmpty(pointStatus.getJSONArray("data"))) {
stepStr += ",98";
log.error("获取气胀轴库信息失败");
stepErrorInfo.add("获取ACS气胀轴库信息失败...");
return false;
}
boolean judgment1 = true;
@@ -660,6 +674,7 @@ public class AutoCallAirShaftTask extends Prun {
stepStr += ",30";
if (!judgment1 && !judgment2) {
log.warn("没有气胀轴不给ACS写出轴信息");
stepErrorInfo.add("呼叫气胀轴失败,没有气胀轴(密集库/暂存架不给ACS写出轴信息");
stepStr += ",98";
return false;
}
@@ -767,6 +782,7 @@ public class AutoCallAirShaftTask extends Prun {
//根据point_code排序
if (notTaskPoints.size() == 0) {
stepStr += ",99";
stepErrorInfo.add("只进行拔轴,没有可以拔轴的点位。");
return;
}
stepStr += ",9";
@@ -780,6 +796,7 @@ public class AutoCallAirShaftTask extends Prun {
.orElse(null);
if (cutpointivt == null) {
stepStr += ",99";
stepErrorInfo.add("只进行拔轴,没有可以拔轴的点位。");
return;
}
stepStr += ",10";
@@ -797,7 +814,7 @@ public class AutoCallAirShaftTask extends Prun {
.set("is_used","0")
.set("remark","气胀轴" + qzzNo + "的计划不存在,无效点位自动禁用")
.set("update_time",DateUtil.now()));
stepErrorInfo.add("气胀轴" + qzzNo + "的计划不存在,无效点位自动禁用。");
return;
}
PdmBiSlittingproductionplan plan = list.get(0);
@@ -822,6 +839,7 @@ public class AutoCallAirShaftTask extends Prun {
param.put("is_bushing", SlitterConstant.SLITTER_NO);
param.put("is_pulling", SlitterConstant.SLITTER_YES);
trussCallAirShaftTask.createTask(param);
stepErrorInfo.add("只做拔轴,拔轴任务已经创建...");
stepStr += ",11";
}

View File

@@ -3,9 +3,7 @@ package org.nl.b_lms.sch.tasks.slitter.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.nl.b_lms.pdm.bi.slittingproductionplan.service.dao.PdmBiSlittingproductionplan;
import org.nl.b_lms.sch.tasks.slitter.service.SlitterService;
import org.nl.common.utils.TaskUtils;
import org.nl.modules.common.utils.RedisUtils;
import org.nl.modules.logging.annotation.Log;
import org.springframework.beans.factory.annotation.Autowired;
@@ -16,11 +14,6 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @Author: lyd
* @Description:
@@ -47,4 +40,16 @@ public class SlitterController {
public ResponseEntity<Object> tzInfo(@RequestBody JSONObject entity){
return new ResponseEntity<>(redisUtils.get("INFO" + entity.getString("device_code")), HttpStatus.CREATED);
}
@PostMapping("/v2/tzInfo")
@Log("套轴BCP透明链路2")
@SaIgnore
public ResponseEntity<Object> tzInfo2(@RequestBody JSONObject entity){
return new ResponseEntity<>(redisUtils.get("ERROR" + entity.getString("device_code")), HttpStatus.CREATED);
}
@PostMapping("/v2/tzTaskINfo")
@Log("套轴BCP透明链路2")
@SaIgnore
public ResponseEntity<Object> tzTaskINfo(@RequestBody JSONObject entity){
return new ResponseEntity<>(slitterService.tzTaskINfo(entity), HttpStatus.OK);
}
}

View File

@@ -62,4 +62,6 @@ public interface SlitterMapper {
List<BstIvtCutpointivt> nbjGetEmptyCutPointNotTask(String area, BigDecimal sortSeq, String location);
List<CallPlanViewVO> showManualView();
List<CallPlanViewVO> showManualViewNoXn();
}

View File

@@ -147,6 +147,7 @@
p.split_group,
p.up_or_down,
p.qzz_size,
p.container_name,
p.qzz_generation,
p.is_paper_ok,
MIN(p.start_time) AS start_time,
@@ -168,6 +169,7 @@
p.restruct_container_name,
p.split_group,
p.up_or_down,
p.container_name,
p.qzz_size,
p.is_paper_ok,
p.manufacture_sort,
@@ -182,4 +184,51 @@
manufacture_sort desc,
start_time
</select>
<select id="showManualViewNoXn" resultType="org.nl.b_lms.sch.tasks.slitter.mapper.dto.CallPlanViewVO">
SELECT p.workorder_id,
p.resource_name,
CASE
WHEN LENGTH(p.parent_container_name) > 0 THEN
p.parent_container_name
ELSE p.restruct_container_name
END AS parent_container_name,
p.container_name,
p.split_group,
p.up_or_down,
p.qzz_size,
p.qzz_generation,
p.is_paper_ok,
MIN(p.start_time) AS start_time,
IF(p.paper_tube_or_FRP = '1', p.paper_tube_description, p.FRP_description) AS tube,
MIN(p.`status`) AS `status`
FROM `pdm_bi_slittingproductionplan` p
WHERE p.`status` <![CDATA[ < ]]> '09'
AND p.is_delete = '0'
AND IFNULL(p.up_or_down, '') <![CDATA[ <> ]]> ''
AND IFNULL(p.left_or_right, '') <![CDATA[ <> ]]> ''
AND DATE (p.start_time) >= DATE_SUB(CURDATE()
, INTERVAL 1 DAY)
AND '1' = (SELECT c.is_used FROM st_ivt_cutpointivt c WHERE c.ext_code = p.resource_name AND c.product_area IN ('B1', 'B2'))
GROUP BY
p.workorder_id,
p.resource_name,
p.parent_container_name,
p.restruct_container_name,
p.split_group,
p.up_or_down,
p.qzz_size,
p.is_paper_ok,
p.manufacture_sort,
p.start_time,
p.qzz_generation,
p.paper_tube_or_FRP,
p.paper_tube_description,
p.FRP_description,
p.container_name
ORDER BY
`status`,
qzz_size,
manufacture_sort desc,
start_time
</select>
</mapper>

View File

@@ -18,6 +18,7 @@ public class CallPlanViewVO implements Serializable {
* 分切设备
*/
private String resource_name;
private String container_name;
/**
* 母卷
*/

View File

@@ -369,4 +369,6 @@ public interface SlitterService {
* @return
*/
JSONObject cutCacheInventory(JSONObject param);
JSONObject tzTaskINfo(JSONObject entity);
}

View File

@@ -9,9 +9,7 @@ import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.nl.b_lms.bst.ivt.cutpointivt.service.IBstIvtCutpointivtService;
@@ -46,10 +44,13 @@ import org.nl.b_lms.sch.tasks.slitter.util.SlitterTaskUtil;
import org.nl.common.utils.SecurityUtils;
import org.nl.common.utils.TaskUtils;
import org.nl.modules.common.exception.BadRequestException;
import org.nl.modules.common.utils.RedisUtils;
import org.nl.modules.wql.core.bean.WQLObject;
import org.nl.system.service.notice.ISysNoticeService;
import org.nl.system.service.param.ISysParamService;
import org.nl.system.service.param.dao.Param;
import org.nl.wms.basedata.master.service.ClassstandardService;
import org.nl.wms.basedata.master.service.dto.ClassstandardDto;
import org.nl.wms.ext.acs.service.WmsToAcsService;
import org.nl.wms.sch.manage.TaskStatusEnum;
import org.redisson.api.RLock;
@@ -78,6 +79,7 @@ import static org.nl.b_lms.sch.tasks.slitter.util.SlitterTaskUtil.getPointLocati
@Slf4j
@Service
public class SlitterServiceImpl implements SlitterService {
public final static String USE_XN = "USE_XN";
@Autowired
private BstIvtStockingivtMapper bstIvtStockingivtMapper;
@@ -129,25 +131,35 @@ public class SlitterServiceImpl implements SlitterService {
private ReturnShaftAgvTask returnShaftAgvTask;
@Autowired
private ISysNoticeService noticeService;
@Autowired
private RedisUtils redisUtils;
@Autowired
private ClassstandardService classstandardService;
@Override
public JSONObject acsRequestShaftLoadTube(JSONObject param) {
// hint: 现在的考虑都是基于B1,B2的车间后续的B3、B4需要再次修改
log.info("acs申请套轴的输入参数为{}", param);
JSONObject res = new JSONObject();
JSONObject con = new JSONObject();
String deviceCode = param.getString("device_code");
List<String> stepTipLogs = getRedisListValue("ERROR" + deviceCode);
String size = param.getString("size");
BstIvtShafttubeivt point = shafttubeivtService.getByPointCode(deviceCode, false);
Param autoSendEmpty = paramService.findByCode("autoSendEmpty");
if (ObjectUtil.isEmpty(autoSendEmpty)) {
stepTipLogs.add("未配置是否直接送气胀轴请检查参数表autoSendEmpty");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("未配置是否直接送气胀轴");
}
log.info("获取的穿拔轴点位数据:{}", point);
// 判断尺寸是否相同
if (!size.equals(point.getQzz_size())) {
log.error("设备:{}对应的气胀轴尺寸不批对,需要气胀轴尺寸:{},实际尺寸:{}", deviceCode, point.getQzz_size(), size);
stepTipLogs.add("套轴请求->设备:{ " + deviceCode + " }对应的气胀轴尺寸不批对" +
",需要气胀轴尺寸:{ " + point.getQzz_size() + " },实际尺寸:{ " + size + " }," +
" 请检查电气任务与LMS穿拔轴点位信息是否一致, 如果实际为空,让电气复位启动即可。");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("设备:{ " + deviceCode + " }对应的气胀轴尺寸不批对" +
",需要气胀轴尺寸:{ " + point.getQzz_size() + " },实际尺寸:{ " + size + " }");
}
@@ -242,14 +254,19 @@ public class SlitterServiceImpl implements SlitterService {
// 参数设备号type插拔轴位qzzSize
JSONObject res = new JSONObject();
String deviceCode = param.getString("device_code");
List<String> stepTipLogs = getRedisListValue("ERROR" + deviceCode);
String qzzNo = param.getString("qzz_no");
if (ObjectUtil.isEmpty(qzzNo)) {
log.error("气涨轴编码不能为空!");
stepTipLogs.add("出现错误,点位气涨轴编码不能为空!");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("气涨轴编码不能为空!");
}
List<PdmBiSlittingproductionplan> plans = slittingproductionplanService.getByQzzNo(qzzNo);
if (plans.size() == 0) {
log.error("查询不到气胀轴编码「" + qzzNo + "」对应状态[结束]的子卷信息!");
stepTipLogs.add("查询不到气胀轴编码「" + qzzNo + "」对应状态[结束]的子卷信息!");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("查询不到气胀轴编码「" + qzzNo + "」对应的子卷信息!");
}
String containers = plans.stream().map(PdmBiSlittingproductionplan::getContainer_name).collect(Collectors.joining(","));
@@ -274,6 +291,7 @@ public class SlitterServiceImpl implements SlitterService {
JSONObject res = new JSONObject();
// 穿拔轴位
String deviceCode = param.getString("device_code");
List<String> stepTipLogs = getRedisListValue("ERROR" + deviceCode);
// 纸管
String weight1 = param.getString("weight1");
String material1 = param.getString("material1");
@@ -285,6 +303,8 @@ public class SlitterServiceImpl implements SlitterService {
.lt(SchBaseTask::getTask_status, "07"));
if (list.size() > 0) {
log.error("点位[{}]存在未完成得任务!", deviceCode);
stepTipLogs.add("套轴完成->点位[" + deviceCode + "]存在未完成得任务!");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("点位[" + deviceCode + "]存在未完成得任务!");
}
BstIvtShafttubeivt startPoint = shafttubeivtService.getOne(new LambdaQueryWrapper<BstIvtShafttubeivt>()
@@ -294,6 +314,8 @@ public class SlitterServiceImpl implements SlitterService {
.filter(value -> value != null && !value.isEmpty()).collect(Collectors.toList());
if (collect.size() == 0) {
log.error("找不到[{}]对应的分切计划!", deviceCode);
stepTipLogs.add("套轴完成->找不到[" + deviceCode + "]点位记录的分切计划!");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("找不到[" + deviceCode + "]对应的分切计划!");
}
List<PdmBiSlittingproductionplan> plans = slittingproductionplanService.list(
@@ -339,6 +361,8 @@ public class SlitterServiceImpl implements SlitterService {
}
}
} else {
stepTipLogs.add("套轴完成->[" + collect + "]对应的分切计划状态已更改,创建任务失败!");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("[" + collect + "]对应的分切计划状态已更改,异常处理位没位置!");
}
}
@@ -375,6 +399,8 @@ public class SlitterServiceImpl implements SlitterService {
List<BstIvtCutpointivt> emptyNotTaskPoint = bcutpointivtService.getNBJAreaNotTaskPointByStatus(
"1", "1", startPoint.getPoint_location(), "1");
if (emptyNotTaskPoint.size() == 0) {
stepTipLogs.add("套轴完成->找不到可用套轴对接位!");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("找不到可用套轴对接位!");
}
cutPoint = emptyNotTaskPoint.get(0);
@@ -408,6 +434,8 @@ public class SlitterServiceImpl implements SlitterService {
taskParam.put("product_area", SlitterConstant.SLITTER_TASK_AREA);
trussSendAirShaftTask.createTask(taskParam);
} else {
stepTipLogs.add("套轴完成->系统繁忙,稍后在试!");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("系统繁忙,稍后在试!");
}
} finally {
@@ -429,6 +457,7 @@ public class SlitterServiceImpl implements SlitterService {
String lock = "lock";
JSONObject res = new JSONObject();
String deviceCode = param.getString("device_code");
List<String> stepTipLogs = getRedisListValue("ERROR" + deviceCode);
String qzzSize = param.getString("size");
RLock lockPoint = redissonClient.getLock(lock + qzzSize);
boolean tryLockPoint = lockPoint.tryLock(0, TimeUnit.SECONDS);
@@ -439,6 +468,8 @@ public class SlitterServiceImpl implements SlitterService {
.eq(SchBaseTask::getPoint_code1, deviceCode)
.lt(SchBaseTask::getTask_status, "07"));
if (list.size() > 0) {
stepTipLogs.add(">>>气胀轴入库请求异常:点位[" + deviceCode + "]存在未完成的任务,无法创建到气涨轴暂存位的任务!");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("点位[" + deviceCode + "]存在未完成得任务!");
}
BstIvtShafttubeivt startPoint = shafttubeivtService.getByPointCode(deviceCode, false);
@@ -454,6 +485,8 @@ public class SlitterServiceImpl implements SlitterService {
.eq(BstIvtShafttubeivt::getPoint_location, startPoint.getPoint_location())
.eq(BstIvtShafttubeivt::getPoint_type, "8"));
if (ObjectUtil.isEmpty(putWaitPoint)) {
stepTipLogs.add(">>>气胀轴入库请求异常:未找到可存放气涨轴规格「" + qzzSize + "」的等待点位。");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("未找到可存放气涨轴规格「" + qzzSize + "」的等待点位");
}
// 创建任务
@@ -466,6 +499,8 @@ public class SlitterServiceImpl implements SlitterService {
param.put("is_bushing", "0");
trussCallShaftCacheTask.createTask(param);
} else {
stepTipLogs.add(">>>气胀轴入库请求异常:系统繁忙,稍后在试!");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("系统繁忙,稍后在试!");
}
} finally {
@@ -483,12 +518,15 @@ public class SlitterServiceImpl implements SlitterService {
log.info("ACS申请从气涨轴暂存位呼叫气胀轴的输入参数为{}", param);
JSONObject res = new JSONObject();
String deviceCode = param.getString("device_code");
List<String> stepTipLogs = getRedisListValue("ERROR" + deviceCode);
String qzzSize = param.getString("size");
// 判断是否有未完成的任务
List<SchBaseTask> list = taskService.list(new LambdaQueryWrapper<SchBaseTask>()
.eq(SchBaseTask::getPoint_code1, deviceCode)
.lt(SchBaseTask::getTask_status, "07"));
if (list.size() > 0) {
stepTipLogs.add(">>>气胀轴出库请求异常:点位[" + deviceCode + "]存在未完成的任务,无法创建从气涨轴暂存位取轴的任务!");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("点位[" + deviceCode + "]存在未完成得任务!");
}
BstIvtShafttubeivt startPoint = shafttubeivtService.getByPointCode(deviceCode, false);
@@ -502,6 +540,8 @@ public class SlitterServiceImpl implements SlitterService {
.eq(BstIvtShafttubeivt::getPoint_location, startPoint.getPoint_location())
.eq(BstIvtShafttubeivt::getPoint_type, "7"));
if (ObjectUtil.isEmpty(pickWaitPoint)) {
stepTipLogs.add(">>>气胀轴出库请求异常:未找到可存放气涨轴规格「" + qzzSize + "」的等待点位!");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("未找到可存放气涨轴规格「" + qzzSize + "」的等待点位");
}
// BstIvtShafttubeivt shafttubeivt = shafttubeivts.get(0);
@@ -943,18 +983,6 @@ public class SlitterServiceImpl implements SlitterService {
papervehicleService.update(mdPbPapervehicle);
}
// todo: 如果qty=0创建AGV送空任务新的task_type、后期优化可以新增诺宝取货完成提前释放货位任务状态变成071
// if (remove) { // hint: 错误
// // 证明删除成功,创建任务搬走
// // 查找一个没有任务的空位
// List<BstIvtStockingivt> list = stockingivtService.getEmptyPointNotTask(device.getPoint_location(), "0");
// if (list.size() == 0) {
// noticeService.createNotice("管芯抓取备货区找不到空位置搬运",
// "管芯抓取点位[" + device.getPoint_name() + "]无法从备货区找到空位",
// NoticeTypeEnum.EXCEPTION.getCode());
// return res;
// }
// BstIvtStockingivt stockingivt = list.get(0);
// }
}
return res;
}
@@ -2246,7 +2274,11 @@ public class SlitterServiceImpl implements SlitterService {
@Override
public List<CallPlanViewVO> showManualView(JSONObject param) {
return slitterMapper.showManualView();
Param useXn = paramService.findByCode(USE_XN);
if (ObjectUtil.isNotEmpty(useXn) && "1".equals(useXn.getValue())) {
return slitterMapper.showManualView();
}
return slitterMapper.showManualViewNoXn();
}
@Override
@@ -2702,4 +2734,46 @@ public class SlitterServiceImpl implements SlitterService {
return res;
}
@Override
public JSONObject tzTaskINfo(JSONObject entity) {
String deviceCode = entity.getString("device_code");
BstIvtShafttubeivt tzPoint = shafttubeivtService.getByPointCode(deviceCode, false);
SchBaseTask one = taskService.getOne(new LambdaQueryWrapper<SchBaseTask>()
.eq(SchBaseTask::getIs_delete, "0")
.lt(SchBaseTask::getTask_status, "07")
.and(la2 -> la2.eq(SchBaseTask::getPoint_code1, deviceCode).or()
.eq(SchBaseTask::getPoint_code2, deviceCode)), false);
String tip = "";
String tip2 = "";
if (ObjectUtil.isNotEmpty(one)) {
ClassstandardDto code = classstandardService.findByCode(one.getTask_type());
tip += "正在执行" + code.getClass_name() + "任务, ";
}
List<String> tubes = Stream.of(tzPoint.getTube_code1(), tzPoint.getTube_code2()).filter(ObjectUtil::isNotEmpty).collect(Collectors.toList());
List<String> containers = Stream.of(tzPoint.getContainer_name1(), tzPoint.getContainer_name2()).filter(ObjectUtil::isNotEmpty).collect(Collectors.toList());
if (ObjectUtil.isNotEmpty(tzPoint.getTube_code1()) || ObjectUtil.isNotEmpty(tzPoint.getTube_code2())) {
tip += "该点位需要套轴";
tip2 += "正在为计划" + containers + "套轴,管芯数据:" + tubes;
} else {
tip += "该点位不需要套轴";
if ("1".equals(tzPoint.getHave_qzz())) {
tip2 += "正在执行拔轴...";
} else {
tip2 += "点位空闲...";
}
}
JSONObject res = new JSONObject();
res.put("tip", tip);
res.put("tip2", tip2);
return res;
}
public List<String> getRedisListValue(String key) {
List<String> stepTipLogs = (List<String>) redisUtils.get(key);
if (CollectionUtil.isEmpty(stepTipLogs)) {
stepTipLogs = new ArrayList<>();
}
return stepTipLogs;
}
}

View File

@@ -1,5 +1,6 @@
package org.nl.wms.ext.acs.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
@@ -51,6 +52,7 @@ import org.nl.common.utils.CodeUtil;
import org.nl.common.utils.MapOf;
import org.nl.common.utils.RedissonUtils;
import org.nl.modules.common.exception.BadRequestException;
import org.nl.modules.common.utils.RedisUtils;
import org.nl.modules.wql.WQL;
import org.nl.modules.wql.core.bean.WQLObject;
import org.nl.modules.wql.util.SpringContextHolder;
@@ -183,7 +185,8 @@ public class AcsToWmsServiceImpl implements AcsToWmsService {
private IStIvtIostorinvOutService iStIvtIostorinvOutService;
@Autowired
private IBstIvtShafttubeivtService shafttubeivtService;
@Autowired
private RedisUtils redisUtils;
/**
* task_id任务标识
@@ -2822,6 +2825,7 @@ public class AcsToWmsServiceImpl implements AcsToWmsService {
if (task.getPoint_code1().contains("QHD")) {
// 请求取货
String deviceCode = task.getPoint_code2();
List<String> stepTipLogs = getRedisListValue("ERROR" + deviceCode);
BstIvtShafttubeivt startPoint = shafttubeivtService.getByPointCode(deviceCode, false);
JSONObject requestParam = JSONObject.parseObject(task.getRequest_param());
String qzzSize = requestParam.getString("qzz_size");
@@ -2829,6 +2833,8 @@ public class AcsToWmsServiceImpl implements AcsToWmsService {
List<BstIvtShafttubeivt> shafttubeivts = shafttubeivtService.getNotTaskShaftCache(qzzSize,
startPoint.getQzz_generation(), startPoint.getPoint_location());
if (shafttubeivts.size() == 0) {
stepTipLogs.add(">>>桁架取轴二次请求异常:未找到气涨轴规格「" + qzzSize + "」的暂存位");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("未找到气涨轴规格「" + qzzSize + "」的暂存位");
}
BstIvtShafttubeivt shafttubeivt = shafttubeivts.get(0);
@@ -2854,7 +2860,10 @@ public class AcsToWmsServiceImpl implements AcsToWmsService {
startPoint.setQzz_size(qzzSize);
// 获取空位
List<BstIvtShafttubeivt> shafttubeivts = shafttubeivtService.getNotTaskShaftCacheEmpty(startPoint);
List<String> stepTipLogs = getRedisListValue("ERROR" + deviceCode);
if (shafttubeivts.size() == 0) {
stepTipLogs.add(">>>桁架放轴二次请求异常:未找到可存放气涨轴规格「" + qzzSize + "」的空暂存位");
redisUtils.set("ERROR" + deviceCode, stepTipLogs);
throw new BadRequestException("未找到可存放气涨轴规格「" + qzzSize + "」的空暂存位");
}
BstIvtShafttubeivt shafttubeivt = shafttubeivts.get(0);
@@ -2909,4 +2918,12 @@ public class AcsToWmsServiceImpl implements AcsToWmsService {
log.info("acsRequestPoint输出参数为--------------------------" + result.toString());
return result;
}
public List<String> getRedisListValue(String key) {
List<String> stepTipLogs = (List<String>) redisUtils.get(key);
if (CollectionUtil.isEmpty(stepTipLogs)) {
stepTipLogs = new ArrayList<>();
}
return stepTipLogs;
}
}

View File

@@ -10,6 +10,7 @@ import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.nl.b_lms.bst.ivt.papervehicle.service.dao.mapper.MdPbPapervehicleMapper;
import org.nl.b_lms.bst.ivt.shafttubeivt.service.dao.BstIvtShafttubeivt;
import org.nl.b_lms.bst.ivt.shafttubeivt.service.dao.mapper.BstIvtShafttubeivtMapper;
import org.nl.b_lms.pdm.bi.slittingproductionplan.service.IPdmBiSlittingproductionplanService;
@@ -72,10 +73,14 @@ public class EventTest {
@Autowired
private SchBasePointMapper schBasePointMapper;
@Autowired
private MdPbPapervehicleMapper papervehicleMapper;
@Autowired
private IPdmBiSlittingproductionplanService slittingproductionplanService;
@Test
public void sss() {
System.out.println(schBasePointMapper.queryKZPoint());
// System.out.println(schBasePointMapper.queryKZPoint());
List<String> list = Arrays.asList("482210000000001");
System.out.println(papervehicleMapper.getGXs("0", list));
}
@Test