refactor: 出库管理-添加领料单,弹窗选择采购码(产品),搜索长描述、公称直径(L)、公称直径(S);选中后带回完整长描述,公称直径(L),公称直径(S);长描述多参数搜索用英文逗号隔开

This commit is contained in:
hwd
2025-09-27 16:57:34 +08:00
parent 27e3eb5821
commit 7b817a5edf
12 changed files with 614 additions and 29 deletions

View File

@@ -2,6 +2,8 @@ package com.vverp.controller.admin;
import com.vverp.base.Setting;
import com.vverp.dto.ProductBaseDTO;
import com.vverp.dto.ProductQueryDto;
import com.vverp.dto.ProductSearchDto;
import com.vverp.entity.*;
import com.vverp.enums.OrderStatus;
import com.vverp.moli.util.*;
@@ -272,6 +274,26 @@ public class ProductController extends BaseController {
}
}
// 根据长描述、公称直径(L)、公称直径(S)筛选产品
@RequestMapping("/dialog/selectSearchLddlds")
public String selectSearchLddlds(ModelMap modelMap, String indexSn) {
modelMap.addAttribute("hasProductType", false);
modelMap.addAttribute("dialogName", "sblddldsDialog");
modelMap.addAttribute("indexSn", indexSn);
return "/product/dialog/selectSearchLddlds";
}
@RequestMapping("/listLddlds")
@ResponseBody
public RespData listLddlds(ProductQueryDto queryDto) {
try {
List<ProductSearchDto> list = productService.listAll(queryDto);
return RespData.success(list);
} catch (Exception e) {
e.printStackTrace();
return RespData.error("获取失败");
}
}
@RequestMapping("/selectPage")
@ResponseBody
public RespData selectPage(Pageable pageable) {

View File

@@ -1,6 +1,8 @@
package com.vverp.dao;
import com.vverp.dto.ProductBaseDTO;
import com.vverp.dto.ProductQueryDto;
import com.vverp.dto.ProductSearchDto;
import com.vverp.entity.Product;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Repository;
@@ -130,6 +132,34 @@ public class ProductDao extends BaseDao<Product, Long> {
return entityManager.createQuery(criteriaQuery).getResultList();
}
public List<ProductSearchDto> listAll(ProductQueryDto queryDto) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<ProductSearchDto> criteriaQuery = criteriaBuilder.createQuery(ProductSearchDto.class);
Root<Product> root = criteriaQuery.from(Product.class);
criteriaQuery.select(criteriaBuilder.construct(ProductSearchDto.class, root.get("id"), root.get("name"), root.get("code"), root.get("productType").get("id"), root.get("longDescription"), root.get("diameterL"), root.get("diameterS")));
Predicate all = criteriaBuilder.conjunction();
if (queryDto.getType() != null) {
all = criteriaBuilder.and(all, criteriaBuilder.equal(root.get("type"), queryDto.getType()));
}
if (queryDto.getProductTypeId() != null) {
all = criteriaBuilder.and(all, criteriaBuilder.equal(root.get("productType").get("id"), queryDto.getProductTypeId()));
}
if (queryDto.getDiameterL() != null) {
all = criteriaBuilder.and(all, criteriaBuilder.equal(root.get("diameterL"), queryDto.getDiameterL()));
}
if (queryDto.getDiameterS() != null) {
all = criteriaBuilder.and(all, criteriaBuilder.equal(root.get("diameterS"), queryDto.getDiameterS()));
}
if (StringUtils.isNotBlank(queryDto.getLongDescription())) {
for (String s : queryDto.getLongDescription().split(",")) {
all = criteriaBuilder.and(all, criteriaBuilder.like(root.get("longDescription"), "%" + s + "%"));
}
}
criteriaQuery.where(all);
return entityManager.createQuery(criteriaQuery).getResultList();
}
public Page<Product> selectPage(Pageable pageable) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Product> criteriaQuery = criteriaBuilder.createQuery(Product.class);

View File

@@ -1,18 +0,0 @@
package com.vverp.dto;
/**
* @author
* @date 2020/11/17 上午11:20
*/
public class ProductQuery {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@@ -0,0 +1,72 @@
package com.vverp.dto;
import com.vverp.entity.Product;
import java.math.BigDecimal;
public class ProductQueryDto {
private String name; // 名称
private String code; // 编码
private Product.Type type; //
private Long productTypeId; // 产品类别id
private String longDescription; // 长描述
private BigDecimal diameterL; // 公称直径(L)
private BigDecimal diameterS; // 公称直径(S)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Product.Type getType() {
return type;
}
public void setType(Product.Type type) {
this.type = type;
}
public Long getProductTypeId() {
return productTypeId;
}
public void setProductTypeId(Long productTypeId) {
this.productTypeId = productTypeId;
}
public String getLongDescription() {
return longDescription;
}
public void setLongDescription(String longDescription) {
this.longDescription = longDescription;
}
public BigDecimal getDiameterL() {
return diameterL;
}
public void setDiameterL(BigDecimal diameterL) {
this.diameterL = diameterL;
}
public BigDecimal getDiameterS() {
return diameterS;
}
public void setDiameterS(BigDecimal diameterS) {
this.diameterS = diameterS;
}
}

View File

@@ -0,0 +1,88 @@
package com.vverp.dto;
import java.math.BigDecimal;
public class ProductSearchDto {
private Long id;
private String name; // 名称
private String code; // 编码
private Long productTypeId; // 产品类别id
private String productTypeName; // 产品类别
private String longDescription; // 长描述
private BigDecimal diameterL; // 公称直径(L)
private BigDecimal diameterS; // 公称直径(S)
public ProductSearchDto(Long id, String name, String code, Long productTypeId, String longDescription, BigDecimal diameterL, BigDecimal diameterS) {
this.id = id;
this.name = name;
this.code = code;
this.productTypeId = productTypeId;
this.longDescription = longDescription;
this.diameterL = diameterL;
this.diameterS = diameterS;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Long getProductTypeId() {
return productTypeId;
}
public void setProductTypeId(Long productTypeId) {
this.productTypeId = productTypeId;
}
public String getProductTypeName() {
return productTypeName;
}
public void setProductTypeName(String productTypeName) {
this.productTypeName = productTypeName;
}
public String getLongDescription() {
return longDescription;
}
public void setLongDescription(String longDescription) {
this.longDescription = longDescription;
}
public BigDecimal getDiameterL() {
return diameterL;
}
public void setDiameterL(BigDecimal diameterL) {
this.diameterL = diameterL;
}
public BigDecimal getDiameterS() {
return diameterS;
}
public void setDiameterS(BigDecimal diameterS) {
this.diameterS = diameterS;
}
}

View File

@@ -2,6 +2,8 @@ package com.vverp.service;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import com.vverp.dto.ProductBaseDTO;
import com.vverp.dto.ProductQueryDto;
import com.vverp.dto.ProductSearchDto;
import com.vverp.entity.Product;
import com.vverp.entity.ProductType;
import com.vverp.moli.util.Filter;
@@ -55,6 +57,9 @@ public class ProductService extends BaseService<Product, Long> {
public List<ProductBaseDTO> listAll(String productTypeChain, String search) {
return productDao.listAll(productTypeChain, search);
}
public List<ProductSearchDto> listAll(ProductQueryDto queryDto) {
return productDao.listAll(queryDto);
}
public Page<Product> selectPage(Pageable pageable) {
return productDao.selectPage(pageable);

View File

@@ -255,7 +255,7 @@
<script type="text/javascript" src="https://runyi-static.oss-cn-hangzhou.aliyuncs.com/js/jquery.orgchart.min.js"></script>
<!--<script type="text/javascript" th:src="@{../resources/js/colResizable-1.6.js}"></script>-->
<script type="text/javascript" src="https://runyi-static.oss-cn-hangzhou.aliyuncs.com/js/colResizable-1.6.js"></script>
<script type="text/javascript" th:src="@{../resources/js/select-field.js?v=1}"></script>
<script type="text/javascript" th:src="@{../resources/js/select-field.js?v=2}"></script>
<script type="text/javascript" th:src="@{../resources/js/select-filter.js}"></script>
<script>
document.write('<script src="../resources/js/complex-add.js?rand=' + Math.random() + '"><\/script>');

View File

@@ -0,0 +1,347 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<div th:id="|${dialogName != null ? dialogName : 'selectProductDialog'}|" class="dialog functionDialog listPage" data-width="983" data-height="615">
<style>
.dialogBody, .dialogContent, .dialogFooter {
position: unset !important;
}
table thead tr {
position: sticky;
top: 0;
z-index: 3;
}
.functionDialog .top-wrapper {
/*margin-bottom: 10px;*/
/*width: 100%;*/
padding: 0 !important;
}
.functionDialog .add-product {
display: inline-block;
padding: 6px 10px;
text-align: center;
border: 1px solid #99c97f;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
color: #99c97f;
}
.functionDialog .main-body {
font-size: 0;
}
.functionDialog .left-wrapper {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
display: inline-block;
vertical-align: top;
margin-right: 2%;
width: 23%;
height: 465px;
border: 1px solid #d0d0d0;
}
.functionDialog .right-wrapper {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
display: inline-block;
vertical-align: top;
width: 75%;
height: 465px;
border: 1px solid #d0d0d0;
}
.functionDialog .wrapper {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
display: inline-block;
vertical-align: top;
width: 100%;
height: 465px;
border: 1px solid #d0d0d0;
}
.functionDialog .main-body .head {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0 15px;
height: 40px;
border-bottom: 1px solid #d5d5d4;
}
.functionDialog .main-body .the-title {
font-size: 15px;
line-height: 40px;
}
.functionDialog .main-body .content {
height: 423px;
}
.functionDialog .left-wrapper .content {
overflow-y: scroll;
}
.functionDialog .right-wrapper .content {
overflow: auto;
}
.functionDialog .content.listBody {
width: 100%;
}
.functionDialog .content tr {
border-bottom: 1px solid #d0d0d0;
}
.functionDialog .content th,
.functionDialog .content td {
border-right: 1px solid #d0d0d0;
}
#productTable .input-wrapper {
width: 60px;
}
#productTable .input-wrapper input {
width: 60px;
}
</style>
<div class="title">
<span class="">产品选择</span>
<div class="dialogClose"></div>
</div>
<div class="dialogBody">
<div class="dialogContent">
<form>
<div class="top-wrapper toolBar">
<div class="filter-wrapper">
<div class="filter-item">
<label>长描述:</label>
<input class="filter-input" type="text" name="longDescription">
</div>
<div class="filter-item">
<label>公称直径(L):</label>
<input class="filter-input" type="number" name="diameterL">
</div>
<div class="filter-item">
<label>公称直径(S):</label>
<input class="filter-input" type="number" name="diameterS">
</div>
<a class="confirm-button">搜索</a>
<a class="clear-filter">清除搜索</a>
</div>
</div>
<div class="main-body">
<th:block th:if="${hasProductType}">
<div class="left-wrapper">
<div class="head">
<span class="the-title">产品类别</span>
</div>
<div class="content">
<ul id="productTypeTree" class="ztree type-tree"></ul>
</div>
</div>
</th:block>
<div th:class="|${hasProductType ? 'right-wrapper' : 'wrapper'}|">
<div class="head">
<span class="the-title">产品列表</span>
</div>
<div class="content tableWrap" style="margin: 0;">
<table id="productTable">
<thead>
<tr>
<th class="checkbox-col"><input class="checkbox" type="checkbox" style="display: none"></th>
<th>专业名称</th>
<th>采购码</th>
<th style="min-width: 200px">长描述</th>
<th>公称直径(L)</th>
<th>公称直径(S)</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</form>
</div>
<div class="dialogFooter">
<a class="cancel">取消</a>
<a class="confirm">确认</a>
</div>
</div>
<th:block th:if="${hasProductType}">
<script src="/resources/js/z-tree/product-type-view.js"></script>
</th:block>
<script th:inline="javascript">
var $dialog = $("#"+[[${dialogName != null ? dialogName : 'selectProductDialog'}]]+"");
if ($dialog.find('#productTypeTree').length > 0) {
listAllType(null, true);
}
Dialog.start({
dialog: $dialog,
confirm: function () {
var selectedIds = $("#productTable").selectedIds();
var selected = [];
var flag = true;
$("#productTable tbody tr").each(function () {
var id = $(this).find(".checkbox-col .single-checkbox").attr("data-id");
if (indexOf(selectedIds, id) !== -1) {
var item = {
id: id,
code: $(this).find('[data-field="code"]').text(),
name: $(this).find('[data-field="name"]').text(),
longDescription: $(this).find('[data-field="longDescription"]').text(),
diameterL: $(this).find('[data-field="diameterL"]').text(),
diameterS: $(this).find('[data-field="diameterS"]').text()
};
selected.push(item);
return false;
}
});
if (flag) {
if (selected.length === 0) {
Dialog.error("请选择产品");
} else {
selectSearchLddldsCallback([[${indexSn}]], selected);
Dialog.success("操作成功");
Dialog.close($dialog);
}
}
}
});
function indexOf(arr, target) {
for (var i in arr) {
if (target === arr[i]) {
return i;
}
}
return -1;
}
// 产品类型
var productTypeId;
// 点击树节点回调函数
function zTreeOnClick(event, treeId, treeNode) {
if (treeNode.id === productTypeId) {
return false;
}
if (treeNode.id === 0 && !productTypeId) {
return false;
}
productTypeId = treeNode.id;
loadTableData(productTypeId);
$dialog.find(".right-wrapper .the-title").text(treeNode.name);
}
// 渲染表格
function renderTable(trHtml) {
$dialog.find("#productTable tbody").html("");
$dialog.find("#productTable .checkbox-col .checkbox").prop("checked", false);
if (trHtml) {
$dialog.find("#productTable tbody").html(trHtml);
}
$dialog.find("#productTable").selectField({
base: false,
multiSelect: true,
multiSelectSingle: true
});
}
renderTable();
// 加载表格数据
function loadTableData(productTypeId) {
if ($dialog.opLock) {
console.log("拦住");
return false;
} else {
$dialog.opLock = true;
console.log("获取锁");
}
var requestData = {};
if (productTypeId) {
requestData.productTypeId = productTypeId;
}
$dialog.find(".top-wrapper .filter-wrapper .filter-item [name]").each(function (index, item) {
let name = $(item).attr('name');
let val = $(item).val();
if (name != null && name !== '' || val != null && val !== '') {
requestData[name] = val;
}
});
if (requestData['longDescription'] == null || requestData['longDescription'] === '') {
Dialog.error('长描述不能为空');
$dialog.opLock = false;
console.log("释放锁");
return false;
}
requestData["type"] = "conduit";
$.ajax({
url: "/admin/product/listLddlds.html",
dataType: "json",
data: requestData,
success: function (res) {
if (res.data) {
var trHtml = '';
res.data.forEach(function (item) {
var longDescription = item.longDescription ? item.longDescription : '';
var code = item.code ? item.code : '';
var name = item.name ? item.name : '';
var diameterL = item.diameterL ? item.diameterL : '';
var diameterS = item.diameterS ? item.diameterS : '';
trHtml += '<tr>' +
' <td class="checkbox-col"><input data-id="' + item.id + '" class="checkbox" type="checkbox"></td>' +
' <td data-field="name">' + name + '</td>' +
' <td data-field="code">' + code + '</td>' +
' <td data-field="longDescription">' + longDescription + '</td>' +
' <td data-field="diameterL">' + diameterL + '</td>' +
' <td data-field="diameterS">' + diameterS + '</td>' +
' </tr>';
});
renderTable(trHtml);
}
$dialog.opLock = false;
console.log("释放锁");
},
error: function () {
console.log("ajax error");
$dialog.opLock = false;
console.log("释放锁");
}
});
}
// 搜索
$dialog.find(".top-wrapper .confirm-button").on('click', function () {
loadTableData(productTypeId);
});
$dialog.find(".top-wrapper .clear-filter").on('click', function () {
$dialog.find(".top-wrapper .filter-wrapper .filter-item input").each(function (index, item) {
$(item).val(null);
});
$dialog.find(".top-wrapper .filter-wrapper .filter-item select").each(function (index, item) {
$(item).val(null).trigger('change');
});
loadTableData(productTypeId);
});
</script>
</div>
</html>

View File

@@ -36,7 +36,10 @@
href="javascript:Dialog.functionDialog(null, null, '/admin/common/selectInsideField.html?name=inside-useOrder-table');">
<i class="fa fa-cog"></i>
</a></th>
<th data-column="productId">采购码</th>
<th style="min-width: 200px" data-column="productId">采购码</th>
<th style="min-width: 400px" data-column="longDescription">长描述</th>
<th data-column="diameterL">公称直径(L)</th>
<th data-column="diameterS">公称直径(S)</th>
<th data-column="count">数量</th>
<th data-column="memo">备注</th>
<th class="fixed" data-column="##">操作</th>
@@ -46,9 +49,14 @@
<tr th:each="index : ${#numbers.sequence(1,5)}">
<td th:text="${index}"></td>
<td>
<select class="product-select" data-change="selectChange" data-not-select>
<!-- <select class="product-select" data-change="selectChange" data-not-select>-->
<select class="product-select" data-not-select
data-extra data-moreFunc="openProductSblddldsDialog">
</select>
</td>
<td><input class="productProp longDescription" type="text" readonly></td>
<td><input class="productProp diameterL" type="text" readonly></td>
<td><input class="productProp diameterS" type="text" readonly></td>
<td><input data-input="count" data-required type="number"></td>
<td><input data-input="memo" type="text"></td>
<td class="fixed"><span class="remove">X</span></td>
@@ -74,8 +82,26 @@
<script>
var $table = $(".tableWrap table");
$table.complexAdd({
entity: 'useOrder'
entity: 'useOrder',
onlyExtra: true // 只从弹窗中选中,不用下拉选择
});
var selectChange = $table.selectChange;
// var selectChange = $table.selectChange;
// 弹窗选中回调
function selectSearchLddldsCallback(indexSn, selected) {
let $tr = $table.find("tbody tr").eq(Number(indexSn));
let $productSelect = $tr.find('.product-select');
if (selected.length > 0) {
let item = selected[0];
console.log(item)
$productSelect.html("<option value='" + item.id + "'>" + item.name + "(" + item.code + ")" + "</option>");
$productSelect.val(item.id).trigger('change');
$tr.find(".longDescription").val(item.longDescription);
$tr.find(".diameterL").val(item.diameterL);
$tr.find(".diameterS").val(item.diameterS);
}
}
</script>
</html>

View File

@@ -1186,9 +1186,9 @@ function initSelectAction($selects) {
updateExtra(that, $dot, $remove);
$dot.on('click', function () {
$dot.on('click', function (e) {
if (moreFunc) {
window[moreFunc]();
window[moreFunc](e);
}
});

View File

@@ -8,7 +8,9 @@
$table = $(table);
options = optionsX;
if (!optionsX.onlyExtra) {
fillProductList();
}
initTable();
initForm(options.successMsg);
initDeleteLine();
@@ -791,6 +793,10 @@ function _concatUrl(url, str) {
function openProductDialog() {
Dialog.functionDialog(null, null, 'product/dialog/select.html');
}
// 根据长描述、公称直径(L)、公称直径(S)筛选产品:领料出库添加
function openProductSblddldsDialog(e) {
Dialog.functionDialog(null, null, 'product/dialog/selectSearchLddlds.html?indexSn='+$(e.target).closest('tr').index());
}
function selectProductCallback(selected) {
var $table = $('.complexAddBody .tableWrap table');

View File

@@ -48,7 +48,7 @@
}
if (options.multiSelect) {
initMultiSelect($table);
initMultiSelect($table, options.multiSelectSingle);
}
};
@@ -372,15 +372,17 @@
};
// 初始化【多选】
var initMultiSelect = function ($table) {
var initMultiSelect = function ($table, single) {
var $checkboxCol = $table.find('.checkbox-col');
$checkboxCol.each(function () {
var id = $(this).find('.checkbox').attr('data-id');
if (id) {
$(this).html('<span class="single-checkbox" data-id="' + id + '"></span>');
} else {
if (!single) {
$(this).html('<span class="single-checkbox"></span>');
}
}
});
var $singleCheckbox = $table.find(".single-checkbox");
@@ -395,6 +397,11 @@
$singleCheckbox.on('click', function () {
var flag = $(this).attr('data-flag');
flag = flag === 'true' ? 'false' : 'true';
if (flag === 'true' && single) {
$table.find("td.checkbox-col .single-checkbox[data-flag='true']").each(function () {
loadSingleCheckboxDom($(this), 'false')
});
}
loadSingleCheckboxDom($(this), flag);
var tagName = $(this).parents('.checkbox-col')[0].tagName;