feat(轮胎基础信息): 新增轮胎批量入库功能并且新增字段库存状态inventory_status,导入默认为空(显示已发货待入库”)
实现批量入库功能,包括以下核心变更: 1. 新增入库编码字段支持批量导入与分组管理,导入默认为空(显示已发货待入库”) 2. 添加批量入库预览、执行与撤回接口 3. 实现单条独立事务处理保证失败隔离 4. 增加库存状态显示与批量操作权限控制 5. 提供前端批量入库操作页面与结果展示 支持按入库编码对轮胎批次进行统一管理,提升大批量轮胎入库效率master
parent
26b2e1bbcc
commit
80248fb10b
@ -0,0 +1,181 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
|
||||
<head>
|
||||
<th:block th:include="include :: header('轮胎批量入库')" />
|
||||
<style>
|
||||
.batch-panel { padding: 15px; }
|
||||
.batch-actions { margin-top: 10px; }
|
||||
.batch-summary { margin-top: 15px; }
|
||||
.batch-table { margin-top: 10px; max-height: 360px; overflow: auto; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="gray-bg">
|
||||
<div class="container-div batch-panel">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 search-collapse">
|
||||
<form id="batchForm" class="form-inline">
|
||||
<div class="form-group">
|
||||
<label>入库编码:</label>
|
||||
<input id="inboundCode" name="inboundCode" type="text" class="form-control" placeholder="请输入入库编码" autocomplete="off"/>
|
||||
</div>
|
||||
<div class="batch-actions">
|
||||
<a class="btn btn-primary" onclick="previewBatch()" shiro:hasPermission="tyre:inventory:batch">
|
||||
<i class="fa fa-search"></i> 预览批次
|
||||
</a>
|
||||
<a class="btn btn-success" onclick="submitBatch()" shiro:hasPermission="tyre:inventory:batch">
|
||||
<i class="fa fa-upload"></i> 一键入库
|
||||
</a>
|
||||
<a class="btn btn-danger" onclick="rollbackBatch()" shiro:hasPermission="tyre:inventory:batchRollback">
|
||||
<i class="fa fa-undo"></i> 撤回入库
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-sm-12 batch-summary" id="summaryPanel" style="display:none;"></div>
|
||||
<div class="col-sm-12 batch-table" id="detailPanel" style="display:none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:include="include :: footer" />
|
||||
<script th:inline="javascript">
|
||||
var prefix = ctx + "tyre/inventory";
|
||||
var processing = false;
|
||||
|
||||
function normalizeCode() {
|
||||
var code = $.trim($("#inboundCode").val());
|
||||
if (!code) {
|
||||
$.modal.alertWarning("请输入入库编码");
|
||||
return "";
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
function previewBatch() {
|
||||
var code = normalizeCode();
|
||||
if (!code) {
|
||||
return;
|
||||
}
|
||||
postBatch(prefix + "/batchInbound/preview", code, function (data) {
|
||||
renderPreview(data);
|
||||
});
|
||||
}
|
||||
|
||||
function submitBatch() {
|
||||
var code = normalizeCode();
|
||||
if (!code) {
|
||||
return;
|
||||
}
|
||||
$.modal.confirm("确认按入库编码 [" + escapeHtml(code) + "] 一键入库?", function () {
|
||||
// 入库是批量写库存与流水的动作,前端二次确认用于避免现场误点。
|
||||
postBatch(prefix + "/batchInbound", code, function (data) {
|
||||
renderResult("批量入库完成", data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function rollbackBatch() {
|
||||
var code = normalizeCode();
|
||||
if (!code) {
|
||||
return;
|
||||
}
|
||||
$.modal.confirm("确认撤回入库编码 [" + escapeHtml(code) + "] 仍在库的库存记录?", function () {
|
||||
// 撤回只处理仍在库的当前库存记录,已发生后续出库的轮胎由后端跳过。
|
||||
postBatch(prefix + "/batchInbound/rollback", code, function (data) {
|
||||
renderResult("批量撤回完成", data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function postBatch(url, code, callback) {
|
||||
if (processing) {
|
||||
return;
|
||||
}
|
||||
processing = true;
|
||||
setButtonsDisabled(true);
|
||||
$.modal.loading("处理中,请稍候...");
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: "post",
|
||||
data: { inboundCode: code },
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
callback(res.data || {});
|
||||
} else {
|
||||
$.modal.alertError(res.msg || "操作失败");
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
$.modal.alertError("请求失败,请稍后重试");
|
||||
},
|
||||
complete: function () {
|
||||
$.modal.closeLoading();
|
||||
processing = false;
|
||||
setButtonsDisabled(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderPreview(data) {
|
||||
var html = "<div class='alert alert-info'>批次:" + escapeHtml(data.inboundCode) +
|
||||
",共 " + (data.total || 0) + " 条,已存在 " + (data.exists || 0) +
|
||||
" 条,待入库 " + (data.pending || 0) + " 条</div>";
|
||||
$("#summaryPanel").html(html).show();
|
||||
renderItems(data.items || [], "status");
|
||||
}
|
||||
|
||||
function renderResult(title, data) {
|
||||
if (typeof data === "number") {
|
||||
// 后端写操作按 RuoYi Service 风格返回影响条数,页面只展示本次实际成功处理数。
|
||||
$("#summaryPanel").html("<div class='alert alert-success'>" + title + ",成功处理 " + data + " 条</div>").show();
|
||||
$("#detailPanel").hide().empty();
|
||||
return;
|
||||
}
|
||||
var html = "<div class='alert alert-success'>" + title + ",批次:" + escapeHtml(data.inboundCode) +
|
||||
",共 " + (data.total || 0) + " 条,成功 " + (data.success || 0) +
|
||||
" 条,跳过 " + (data.skip || 0) + " 条,失败 " + (data.fail || 0) + " 条</div>";
|
||||
$("#summaryPanel").html(html).show();
|
||||
renderFailures(data.failures || []);
|
||||
}
|
||||
|
||||
function renderItems(items, statusField) {
|
||||
var rows = items.map(function (item) {
|
||||
return "<tr><td>" + escapeHtml(item.tyreEpc) + "</td><td>" + escapeHtml(item.tyreNo) +
|
||||
"</td><td>" + escapeHtml(item.tyreBrand) + "</td><td>" + escapeHtml(item.tyreModel) +
|
||||
"</td><td>" + escapeHtml(item[statusField]) + "</td></tr>";
|
||||
}).join("");
|
||||
var table = "<table class='table table-bordered table-striped'><thead><tr><th>RFID标签</th><th>胎号</th><th>品牌</th><th>型号</th><th>状态</th></tr></thead><tbody>" + rows + "</tbody></table>";
|
||||
$("#detailPanel").html(table).show();
|
||||
}
|
||||
|
||||
function renderFailures(failures) {
|
||||
if (!failures.length) {
|
||||
$("#detailPanel").hide().empty();
|
||||
return;
|
||||
}
|
||||
var rows = failures.map(function (item) {
|
||||
return "<tr><td>" + escapeHtml(item.tyreEpc) + "</td><td>" + escapeHtml(item.tyreNo) +
|
||||
"</td><td>" + escapeHtml(item.reason) + "</td></tr>";
|
||||
}).join("");
|
||||
var table = "<table class='table table-bordered table-striped'><thead><tr><th>RFID标签</th><th>胎号</th><th>失败原因</th></tr></thead><tbody>" + rows + "</tbody></table>";
|
||||
$("#detailPanel").html(table).show();
|
||||
}
|
||||
|
||||
function setButtonsDisabled(disabled) {
|
||||
$(".batch-actions .btn").toggleClass("disabled", disabled);
|
||||
}
|
||||
|
||||
function escapeHtml(value) {
|
||||
return String(value == null ? "" : value)
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
|
||||
$("#batchForm").on("submit", function (e) {
|
||||
e.preventDefault();
|
||||
previewBatch();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,69 @@
|
||||
package com.ruoyi.system.domain.vo;
|
||||
|
||||
/**
|
||||
* 批量入库预览明细。
|
||||
*
|
||||
* @author zch
|
||||
*/
|
||||
public class InboundBatchPreviewItemVo
|
||||
{
|
||||
private String tyreEpc; // 轮胎 RFID/EPC 唯一标识
|
||||
|
||||
private String tyreNo; // 轮胎外部编号
|
||||
|
||||
private String tyreBrand; // 轮胎品牌
|
||||
|
||||
private String tyreModel; // 轮胎型号
|
||||
|
||||
private String status; // 状态:待入库 / 已存在库存记录
|
||||
|
||||
public String getTyreEpc()
|
||||
{
|
||||
return tyreEpc;
|
||||
}
|
||||
|
||||
public void setTyreEpc(String tyreEpc)
|
||||
{
|
||||
this.tyreEpc = tyreEpc;
|
||||
}
|
||||
|
||||
public String getTyreNo()
|
||||
{
|
||||
return tyreNo;
|
||||
}
|
||||
|
||||
public void setTyreNo(String tyreNo)
|
||||
{
|
||||
this.tyreNo = tyreNo;
|
||||
}
|
||||
|
||||
public String getTyreBrand()
|
||||
{
|
||||
return tyreBrand;
|
||||
}
|
||||
|
||||
public void setTyreBrand(String tyreBrand)
|
||||
{
|
||||
this.tyreBrand = tyreBrand;
|
||||
}
|
||||
|
||||
public String getTyreModel()
|
||||
{
|
||||
return tyreModel;
|
||||
}
|
||||
|
||||
public void setTyreModel(String tyreModel)
|
||||
{
|
||||
this.tyreModel = tyreModel;
|
||||
}
|
||||
|
||||
public String getStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status)
|
||||
{
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue