feat: 新增订单日期范围筛选、明细管理与分类接口

1. 为订单和订单明细BO新增签订、交货日期范围查询字段并配置日期格式化
2. 实现订单日期范围筛选逻辑,新增日期加一天工具方法处理带时间字段的范围查询
3. 重构订单明细列表查询逻辑,支持按合同号、需方、日期范围关联主表筛选
4. 新增通用分类管理接口与页面
5. 优化合同列表页面,新增详情编辑跳转与日期范围筛选
6. 新增订单明细全量查询与单订单明细编辑页面
This commit is contained in:
王文昊
2026-05-16 14:20:30 +08:00
parent dc9c4547fd
commit 52f92c1d69
10 changed files with 2104 additions and 40 deletions

View File

@@ -249,5 +249,20 @@ public class CrmOrderBo extends BaseEntity {
private List<Long> orderIds;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date signDateStart;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date signDateEnd;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date deliveryDateStart;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date deliveryDateEnd;
}

View File

@@ -6,6 +6,10 @@ import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
/**
* 正式订单明细业务对象 crm_order_item
@@ -143,4 +147,30 @@ public class CrmOrderItemBo extends BaseEntity {
*/
private String purpose;
/**
* 筛选:合同号(模糊,按订单主表 crm_order.contract_code
*/
private String contractCode;
/**
* 筛选:需方(模糊,按订单主表 crm_order.customer
*/
private String customer;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date signDateStart;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date signDateEnd;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date deliveryDateStart;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date deliveryDateEnd;
}

View File

@@ -1,6 +1,7 @@
package com.klp.crm.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -35,7 +36,6 @@ import com.klp.mapper.WmsReceivableMapper;
import com.klp.mapper.WmsDeliveryWaybillMapper;
import com.klp.mapper.WmsDeliveryWaybillDetailMapper;
import com.klp.service.IWmsMaterialCoilService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import java.util.*;
import java.util.stream.Collectors;
@@ -72,26 +72,19 @@ public class CrmOrderItemServiceImpl implements ICrmOrderItemService {
*/
@Override
public TableDataInfo<CrmOrderItemVo> queryPageList(CrmOrderItemBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<CrmOrderItem> lqw = buildQueryWrapper(bo);
Page<CrmOrderItemVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
List<CrmOrderItemVo> records = result.getRecords();
if (records != null && !records.isEmpty()) {
List<Long> orderIds = records.stream()
.map(CrmOrderItemVo::getOrderId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
if (!orderIds.isEmpty()) {
CrmOrderBo crmOrder = new CrmOrderBo();
crmOrder.setOrderIds(orderIds);
List<CrmOrderVo> orderList = crmOrderService.queryList(crmOrder);
Map<Long, CrmOrderVo> orderMap = orderList.stream()
.collect(Collectors.toMap(CrmOrderVo::getOrderId, o -> o, (a, b) -> a));
for (CrmOrderItemVo item : records) {
item.setOrderInfo(orderMap.get(item.getOrderId()));
}
}
List<Long> orderIdScope = resolveOrderIdScope(bo);
if (orderIdScope != null && orderIdScope.isEmpty()) {
Page<CrmOrderItemVo> emptyPage = new Page<>(ObjectUtil.defaultIfNull(pageQuery.getPageNum(), 1),
ObjectUtil.defaultIfNull(pageQuery.getPageSize(), 10), 0);
emptyPage.setRecords(Collections.emptyList());
return TableDataInfo.build(emptyPage);
}
LambdaQueryWrapper<CrmOrderItem> lqw = buildQueryWrapper(bo);
if (orderIdScope != null) {
lqw.in(CrmOrderItem::getOrderId, orderIdScope);
}
Page<CrmOrderItemVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
fillOrderInfoOnItems(result.getRecords());
return TableDataInfo.build(result);
}
@@ -100,8 +93,72 @@ public class CrmOrderItemServiceImpl implements ICrmOrderItemService {
*/
@Override
public List<CrmOrderItemVo> queryList(CrmOrderItemBo bo) {
List<Long> orderIdScope = resolveOrderIdScope(bo);
if (orderIdScope != null && orderIdScope.isEmpty()) {
return Collections.emptyList();
}
LambdaQueryWrapper<CrmOrderItem> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
if (orderIdScope != null) {
lqw.in(CrmOrderItem::getOrderId, orderIdScope);
}
List<CrmOrderItemVo> list = baseMapper.selectVoList(lqw);
fillOrderInfoOnItems(list);
return list;
}
/**
* 按合同号/需方筛选时,解析为订单 ID 列表;无此类筛选返回 null不按订单 ID 限制)。
* 若同时传 orderId则仅在匹配集合内保留该订单。
*/
private List<Long> resolveOrderIdScope(CrmOrderItemBo bo) {
boolean hasContractFilter = StringUtils.isNotBlank(bo.getContractCode());
boolean hasCustomerFilter = StringUtils.isNotBlank(bo.getCustomer());
boolean hasSignDateFilter = bo.getSignDateStart() != null || bo.getSignDateEnd() != null;
boolean hasDeliveryDateFilter = bo.getDeliveryDateStart() != null || bo.getDeliveryDateEnd() != null;
if (!hasContractFilter && !hasCustomerFilter && !hasSignDateFilter && !hasDeliveryDateFilter) {
return null;
}
LambdaQueryWrapper<CrmOrder> ow = Wrappers.lambdaQuery();
ow.eq(CrmOrder::getDelFlag, 0L);
ow.like(hasContractFilter, CrmOrder::getContractCode, bo.getContractCode());
ow.like(hasCustomerFilter, CrmOrder::getCustomer, bo.getCustomer());
// 日期范围查询:开始日期 >= 开始,结束日期 < 结束+1天处理带时间的字段
ow.ge(bo.getSignDateStart() != null, CrmOrder::getSignTime, bo.getSignDateStart());
ow.lt(bo.getSignDateEnd() != null, CrmOrder::getSignTime, addOneDay(bo.getSignDateEnd()));
ow.ge(bo.getDeliveryDateStart() != null, CrmOrder::getDeliveryDate, bo.getDeliveryDateStart());
ow.lt(bo.getDeliveryDateEnd() != null, CrmOrder::getDeliveryDate, addOneDay(bo.getDeliveryDateEnd()));
List<CrmOrder> orders = crmOrderMapper.selectList(ow);
List<Long> matched = orders.stream().map(CrmOrder::getOrderId).collect(Collectors.toList());
if (bo.getOrderId() != null) {
if (!matched.contains(bo.getOrderId())) {
return Collections.emptyList();
}
return Collections.singletonList(bo.getOrderId());
}
return matched;
}
private void fillOrderInfoOnItems(List<CrmOrderItemVo> records) {
if (records == null || records.isEmpty()) {
return;
}
List<Long> orderIds = records.stream()
.map(CrmOrderItemVo::getOrderId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
if (orderIds.isEmpty()) {
return;
}
CrmOrderBo crmOrder = new CrmOrderBo();
crmOrder.setOrderIds(orderIds);
List<CrmOrderVo> orderList = crmOrderService.queryList(crmOrder);
Map<Long, CrmOrderVo> orderMap = orderList.stream()
.collect(Collectors.toMap(CrmOrderVo::getOrderId, o -> o, (a, b) -> a));
for (CrmOrderItemVo item : records) {
item.setOrderInfo(orderMap.get(item.getOrderId()));
}
}
private LambdaQueryWrapper<CrmOrderItem> buildQueryWrapper(CrmOrderItemBo bo) {
@@ -114,7 +171,7 @@ public class CrmOrderItemServiceImpl implements ICrmOrderItemService {
lqw.eq(StringUtils.isNotBlank(bo.getSpecialRequire()), CrmOrderItem::getSpecialRequire, bo.getSpecialRequire());
lqw.eq(bo.getItemAmount() != null, CrmOrderItem::getItemAmount, bo.getItemAmount());
lqw.eq(StringUtils.isNotBlank(bo.getFinishedProductSpec()), CrmOrderItem::getFinishedProductSpec, bo.getFinishedProductSpec());
lqw.eq(StringUtils.isNotBlank(bo.getMaterial()), CrmOrderItem::getMaterial, bo.getMaterial());
lqw.like(StringUtils.isNotBlank(bo.getMaterial()), CrmOrderItem::getMaterial, bo.getMaterial());
lqw.eq(StringUtils.isNotBlank(bo.getGrade()), CrmOrderItem::getGrade, bo.getGrade());
lqw.eq(bo.getWeight() != null, CrmOrderItem::getWeight, bo.getWeight());
lqw.eq(StringUtils.isNotBlank(bo.getWidthTolerance()), CrmOrderItem::getWidthTolerance, bo.getWidthTolerance());
@@ -176,6 +233,17 @@ public class CrmOrderItemServiceImpl implements ICrmOrderItemService {
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 日期加一天(用于处理带时间的日期字段范围查询)
*/
private Date addOneDay(Date date) {
if (date == null) return null;
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DATE, 1);
return calendar.getTime();
}
@Override
public CrmContractOrderFinanceVo queryFinanceAndObjectionByContractId(Long contractId) {
CrmContractOrderFinanceVo result = new CrmContractOrderFinanceVo();

View File

@@ -238,6 +238,11 @@ public class CrmOrderServiceImpl implements ICrmOrderService {
qw.eq(bo.getContractId() != null, "co.contract_id", bo.getContractId());
qw.like(StringUtils.isNotBlank(bo.getAnnexFiles()), "co.annex_files", bo.getAnnexFiles());
qw.eq(bo.getIsTop() != null, "co.is_top", bo.getIsTop());
// 日期范围查询:开始日期 >= 开始,结束日期 < 结束+1天处理带时间的字段
qw.ge(bo.getSignDateStart() != null, "co.sign_time", bo.getSignDateStart());
qw.lt(bo.getSignDateEnd() != null, "co.sign_time", addOneDay(bo.getSignDateEnd()));
qw.ge(bo.getDeliveryDateStart() != null, "co.delivery_date", bo.getDeliveryDateStart());
qw.lt(bo.getDeliveryDateEnd() != null, "co.delivery_date", addOneDay(bo.getDeliveryDateEnd()));
if(bo.getOrderIds() !=null){
qw.in(!bo.getOrderIds().isEmpty(), "co.order_id", bo.getOrderIds());
}
@@ -304,4 +309,15 @@ public class CrmOrderServiceImpl implements ICrmOrderService {
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 日期加一天(用于处理带时间的日期字段范围查询)
*/
private Date addOneDay(Date date) {
if (date == null) return null;
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DATE, 1);
return calendar.getTime();
}
}