@@ -0,0 +1,732 @@
package com.klp.service.impl ;
import cn.hutool.core.bean.BeanUtil ;
import com.klp.common.core.page.TableDataInfo ;
import com.klp.common.core.domain.PageQuery ;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page ;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper ;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper ;
import com.baomidou.mybatisplus.core.toolkit.Wrappers ;
import com.klp.common.utils.StringUtils ;
import lombok.RequiredArgsConstructor ;
import org.springframework.stereotype.Service ;
import org.springframework.transaction.annotation.Transactional ;
import com.klp.domain.bo.WmsMaterialCoilBo ;
import com.klp.domain.bo.WmsGenerateRecordBo ;
import com.klp.domain.vo.WmsMaterialCoilVo ;
import com.klp.domain.vo.WmsGenerateRecordVo ;
import com.klp.domain.vo.WmsWarehouseVo ;
import com.klp.domain.vo.WmsRawMaterialVo ;
import com.klp.domain.WmsMaterialCoil ;
import com.klp.domain.WmsStock ;
import com.klp.domain.bo.WmsStockBo ;
import com.klp.domain.vo.WmsStockVo ;
import com.klp.mapper.WmsMaterialCoilMapper ;
import com.klp.mapper.WmsStockMapper ;
import com.klp.service.IWmsMaterialCoilService ;
import com.klp.service.IWmsStockService ;
import com.klp.service.IWmsGenerateRecordService ;
import com.klp.service.IWmsWarehouseService ;
import com.klp.service.IWmsRawMaterialService ;
import com.fasterxml.jackson.databind.ObjectMapper ;
import java.util.List ;
import java.util.Collection ;
import java.util.ArrayList ;
import java.util.Map ;
import java.util.HashMap ;
import java.util.stream.Collectors ;
import java.util.HashSet ;
import java.util.Set ;
/**
* 钢卷物料表Service业务层处理
*
* @author Joshi
* @date 2025-07-18
*/
@RequiredArgsConstructor
@Service
public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
private final WmsMaterialCoilMapper baseMapper ;
private final WmsStockMapper stockMapper ;
private final IWmsStockService stockService ;
private final IWmsGenerateRecordService generateRecordService ;
private final IWmsWarehouseService warehouseService ;
private final IWmsRawMaterialService rawMaterialService ;
/**
* 查询钢卷物料表
*/
@Override
public WmsMaterialCoilVo queryById ( Long coilId ) {
WmsMaterialCoilVo vo = baseMapper . selectVoById ( coilId ) ;
if ( vo = = null ) {
return null ;
}
// 查询关联对象
fillRelatedObjects ( vo ) ;
return vo ;
}
/**
* 填充关联对象信息
*/
private void fillRelatedObjects ( WmsMaterialCoilVo vo ) {
// 查询所在库区信息
if ( vo . getWarehouseId ( ) ! = null ) {
WmsWarehouseVo warehouse = warehouseService . queryById ( vo . getWarehouseId ( ) ) ;
vo . setWarehouse ( warehouse ) ;
}
// 查询下一库区信息
if ( vo . getNextWarehouseId ( ) ! = null ) {
WmsWarehouseVo nextWarehouse = warehouseService . queryById ( vo . getNextWarehouseId ( ) ) ;
vo . setNextWarehouse ( nextWarehouse ) ;
}
// 查询二维码信息
if ( vo . getQrcodeRecordId ( ) ! = null ) {
WmsGenerateRecordVo qrcodeRecord = generateRecordService . queryById ( vo . getQrcodeRecordId ( ) ) ;
vo . setQrcodeRecord ( qrcodeRecord ) ;
}
// 查询原材料信息( 当itemType为raw_material时)
if ( " raw_material " . equals ( vo . getItemType ( ) ) & & vo . getItemId ( ) ! = null ) {
WmsRawMaterialVo rawMaterial = rawMaterialService . queryById ( vo . getItemId ( ) ) ;
vo . setRawMaterial ( rawMaterial ) ;
}
// 查询产品信息( 当itemType为product时)
// TODO: 当产品VO定义后, 添加产品查询逻辑
if ( " product " . equals ( vo . getItemType ( ) ) & & vo . getItemId ( ) ! = null ) {
// 产品查询逻辑待实现
}
}
/**
* 查询钢卷物料表列表
*/
@Override
public TableDataInfo < WmsMaterialCoilVo > queryPageList ( WmsMaterialCoilBo bo , PageQuery pageQuery ) {
LambdaQueryWrapper < WmsMaterialCoil > lqw = buildQueryWrapper ( bo ) ;
Page < WmsMaterialCoilVo > result = baseMapper . selectVoPage ( pageQuery . build ( ) , lqw ) ;
return TableDataInfo . build ( result ) ;
}
/**
* 查询钢卷物料表列表
*/
@Override
public List < WmsMaterialCoilVo > queryList ( WmsMaterialCoilBo bo ) {
LambdaQueryWrapper < WmsMaterialCoil > lqw = buildQueryWrapper ( bo ) ;
return baseMapper . selectVoList ( lqw ) ;
}
private LambdaQueryWrapper < WmsMaterialCoil > buildQueryWrapper ( WmsMaterialCoilBo bo ) {
LambdaQueryWrapper < WmsMaterialCoil > lqw = Wrappers . lambdaQuery ( ) ;
lqw . like ( StringUtils . isNotBlank ( bo . getEnterCoilNo ( ) ) , WmsMaterialCoil : : getEnterCoilNo , bo . getEnterCoilNo ( ) ) ;
lqw . like ( StringUtils . isNotBlank ( bo . getCurrentCoilNo ( ) ) , WmsMaterialCoil : : getCurrentCoilNo , bo . getCurrentCoilNo ( ) ) ;
lqw . like ( StringUtils . isNotBlank ( bo . getSupplierCoilNo ( ) ) , WmsMaterialCoil : : getSupplierCoilNo , bo . getSupplierCoilNo ( ) ) ;
lqw . eq ( bo . getDataType ( ) ! = null , WmsMaterialCoil : : getDataType , bo . getDataType ( ) ) ;
lqw . eq ( bo . getWarehouseId ( ) ! = null , WmsMaterialCoil : : getWarehouseId , bo . getWarehouseId ( ) ) ;
lqw . eq ( bo . getHasMergeSplit ( ) ! = null , WmsMaterialCoil : : getHasMergeSplit , bo . getHasMergeSplit ( ) ) ;
lqw . eq ( bo . getStatus ( ) ! = null , WmsMaterialCoil : : getStatus , bo . getStatus ( ) ) ;
return lqw ;
}
/**
* 新增钢卷物料表
*/
@Override
@Transactional ( rollbackFor = Exception . class )
public Boolean insertByBo ( WmsMaterialCoilBo bo ) {
// 1. 生成二维码
Long qrcodeRecordId = generateQrcodeForInsert ( bo ) ;
bo . setQrcodeRecordId ( qrcodeRecordId ) ;
// 2. 如果warehouseId为空, 查找或创建stock
if ( bo . getWarehouseId ( ) = = null ) {
Long warehouseId = findOrCreateStock ( bo ) ;
bo . setWarehouseId ( warehouseId ) ;
}
// 3. 插入钢卷数据
WmsMaterialCoil add = BeanUtil . toBean ( bo , WmsMaterialCoil . class ) ;
add . setDataType ( 1 ) ; // 新增的钢卷默认为当前数据
validEntityBeforeSave ( add ) ;
boolean flag = baseMapper . insert ( add ) > 0 ;
if ( flag ) {
bo . setCoilId ( add . getCoilId ( ) ) ;
}
return flag ;
}
/**
* 生成二维码(新增)
*/
private Long generateQrcodeForInsert ( WmsMaterialCoilBo bo ) {
try {
Map < String , Object > contentMap = new HashMap < > ( ) ;
String currentCoilNo = bo . getCurrentCoilNo ( ) ! = null ? bo . getCurrentCoilNo ( ) : bo . getEnterCoilNo ( ) ;
contentMap . put ( " enter_coil_no " , bo . getEnterCoilNo ( ) ) ; // 入场钢卷号(唯一不变)
contentMap . put ( " current_coil_no " , currentCoilNo ) ; // 当前钢卷号(可变)
// 创建steps数组
List < Map < String , Object > > steps = new ArrayList < > ( ) ;
Map < String , Object > step1 = new HashMap < > ( ) ;
step1 . put ( " step " , 1 ) ;
step1 . put ( " action " , " 新增 " ) ;
step1 . put ( " current_coil_no " , currentCoilNo ) ;
// 判断是合卷还是分卷
if ( bo . getHasMergeSplit ( ) ! = null & & bo . getHasMergeSplit ( ) = = 2 ) {
// 合卷:父编号字符串用逗号分隔
step1 . put ( " operation " , " 合卷 " ) ;
step1 . put ( " parent_coil_nos " , bo . getParentCoilNos ( ) ) ;
} else if ( bo . getHasMergeSplit ( ) ! = null & & bo . getHasMergeSplit ( ) = = 1 ) {
// 分卷:多个当前钢卷号用逗号分隔
step1 . put ( " operation " , " 分卷 " ) ;
step1 . put ( " current_coil_nos " , currentCoilNo ) ;
} else {
// 默认:当前钢卷号
step1 . put ( " operation " , " 新增 " ) ;
}
steps . add ( step1 ) ;
contentMap . put ( " steps " , steps ) ;
ObjectMapper objectMapper = new ObjectMapper ( ) ;
String contentJson = objectMapper . writeValueAsString ( contentMap ) ;
WmsGenerateRecordBo recordBo = new WmsGenerateRecordBo ( ) ;
recordBo . setContent ( contentJson ) ;
recordBo . setSerialNumber ( bo . getEnterCoilNo ( ) ) ; // 使用入场钢卷号作为编号
recordBo . setQrcodeType ( 0L ) ;
recordBo . setIsEnabled ( 0L ) ;
recordBo . setSize ( 200L ) ;
WmsGenerateRecordVo record = generateRecordService . insertByBo ( recordBo ) ;
return record . getRecordId ( ) ;
} catch ( Exception e ) {
throw new RuntimeException ( " 生成二维码失败: " + e . getMessage ( ) ) ;
}
}
/**
* 查找或创建stock
*/
private Long findOrCreateStock ( WmsMaterialCoilBo bo ) {
if ( bo . getItemType ( ) = = null | | bo . getItemId ( ) = = null ) {
throw new RuntimeException ( " 物品类型和物品ID不能为空 " ) ;
}
// 查询是否存在相同的stock
WmsStockBo stockBo = new WmsStockBo ( ) ;
stockBo . setItemType ( bo . getItemType ( ) ) ;
stockBo . setItemId ( bo . getItemId ( ) ) ;
List < WmsStockVo > stockList = stockService . queryList ( stockBo ) ;
if ( ! stockList . isEmpty ( ) ) {
// 如果找到相同的stock, 返回第一个的warehouseId
return stockList . get ( 0 ) . getWarehouseId ( ) ;
} else {
// 如果没有找到, 创建一个新的stock
WmsStock newStock = new WmsStock ( ) ;
newStock . setItemType ( bo . getItemType ( ) ) ;
newStock . setItemId ( bo . getItemId ( ) ) ;
// 新创建的stock没有指定warehouse, 可以为null
stockMapper . insert ( newStock ) ;
return newStock . getWarehouseId ( ) ;
}
}
/**
* 修改钢卷物料表
* 如果newCoils不为空, 则进行批量更新( 分卷/合卷)
* 如果newCoils为空, 则进行单个更新
*/
@Override
@Transactional ( rollbackFor = Exception . class )
public Boolean updateByBo ( WmsMaterialCoilBo bo ) {
if ( bo . getCoilId ( ) = = null ) {
throw new RuntimeException ( " 钢卷ID不能为空 " ) ;
}
// 判断是否批量更新
if ( bo . getNewCoils ( ) ! = null & & ! bo . getNewCoils ( ) . isEmpty ( ) ) {
// 批量更新逻辑(分卷/合卷)
return updateByBatch ( bo ) ;
} else {
// 单个更新逻辑
return updateBySingle ( bo ) ;
}
}
/**
* 简单更新钢卷物料表
* 直接更新属性内容,不进行历史记录处理
*/
@Override
@Transactional ( rollbackFor = Exception . class )
public Boolean updateSimple ( WmsMaterialCoilBo bo ) {
if ( bo . getCoilId ( ) = = null ) {
throw new RuntimeException ( " 钢卷ID不能为空 " ) ;
}
// 查询原钢卷是否存在
WmsMaterialCoil oldCoil = baseMapper . selectById ( bo . getCoilId ( ) ) ;
if ( oldCoil = = null ) {
throw new RuntimeException ( " 钢卷不存在 " ) ;
}
// 直接更新钢卷属性
WmsMaterialCoil updateCoil = BeanUtil . toBean ( bo , WmsMaterialCoil . class ) ;
validEntityBeforeSave ( updateCoil ) ;
// 使用MyBatis-Plus的updateById方法直接更新
boolean flag = baseMapper . updateById ( updateCoil ) > 0 ;
return flag ;
}
/**
* 单个更新
*/
private Boolean updateBySingle ( WmsMaterialCoilBo bo ) {
// 查询原钢卷
WmsMaterialCoil oldCoil = baseMapper . selectById ( bo . getCoilId ( ) ) ;
if ( oldCoil = = null ) {
throw new RuntimeException ( " 原钢卷不存在 " ) ;
}
// 1. 更新二维码,添加操作记录
updateQrcodeContent ( oldCoil . getQrcodeRecordId ( ) , bo ) ;
// 2. 将原数据更新为历史数据( data_type=0)
LambdaUpdateWrapper < WmsMaterialCoil > updateWrapper = new LambdaUpdateWrapper < > ( ) ;
updateWrapper . eq ( WmsMaterialCoil : : getCoilId , bo . getCoilId ( ) )
. set ( WmsMaterialCoil : : getDataType , 0 ) ; // 设置为历史数据
baseMapper . update ( null , updateWrapper ) ;
// 3. 插入一条新的当前数据( data_type=1)
WmsMaterialCoil newCoil = BeanUtil . toBean ( bo , WmsMaterialCoil . class ) ;
newCoil . setCoilId ( null ) ; // 清空ID, 让数据库自动生成新的ID
newCoil . setDataType ( 1 ) ; // 设置为当前数据
newCoil . setQrcodeRecordId ( oldCoil . getQrcodeRecordId ( ) ) ; // 继承二维码ID
validEntityBeforeSave ( newCoil ) ;
boolean flag = baseMapper . insert ( newCoil ) > 0 ;
if ( flag ) {
bo . setCoilId ( newCoil . getCoilId ( ) ) ;
}
return flag ;
}
/**
* 批量更新(分卷/合卷)
*/
private Boolean updateByBatch ( WmsMaterialCoilBo bo ) {
// 查询原钢卷
WmsMaterialCoil oldCoil = baseMapper . selectById ( bo . getCoilId ( ) ) ;
if ( oldCoil = = null ) {
throw new RuntimeException ( " 原钢卷不存在 " ) ;
}
// 判断是分卷还是合卷
boolean isSplit = false ;
boolean isMerge = false ;
for ( WmsMaterialCoilBo newCoilBo : bo . getNewCoils ( ) ) {
if ( newCoilBo . getHasMergeSplit ( ) ! = null ) {
if ( newCoilBo . getHasMergeSplit ( ) = = 1 ) {
isSplit = true ;
break ;
} else if ( newCoilBo . getHasMergeSplit ( ) = = 2 ) {
isMerge = true ;
break ;
}
}
}
// 1. 将原数据更新为历史数据( data_type=0)
LambdaUpdateWrapper < WmsMaterialCoil > updateWrapper = new LambdaUpdateWrapper < > ( ) ;
updateWrapper . eq ( WmsMaterialCoil : : getCoilId , bo . getCoilId ( ) )
. set ( WmsMaterialCoil : : getDataType , 0 ) ; // 设置为历史数据
baseMapper . update ( null , updateWrapper ) ;
// 2. 插入多条新的当前数据( data_type=1)
List < WmsMaterialCoil > newCoils = new ArrayList < > ( ) ;
List < String > allNewCoilNos = new ArrayList < > ( ) ;
// 收集所有新钢卷号
for ( WmsMaterialCoilBo newCoilBo : bo . getNewCoils ( ) ) {
allNewCoilNos . add ( newCoilBo . getCurrentCoilNo ( ) ) ;
}
if ( isSplit ) {
// 分卷:为每个子钢卷生成独立的二维码
for ( WmsMaterialCoilBo newCoilBo : bo . getNewCoils ( ) ) {
WmsMaterialCoil newCoil = BeanUtil . toBean ( newCoilBo , WmsMaterialCoil . class ) ;
newCoil . setCoilId ( null ) ;
newCoil . setDataType ( 1 ) ;
newCoil . setEnterCoilNo ( oldCoil . getEnterCoilNo ( ) ) ;
// 为每个子钢卷生成独立二维码
Long newQrcodeId = generateQrcodeForSplit ( oldCoil , newCoilBo , allNewCoilNos ) ;
newCoil . setQrcodeRecordId ( newQrcodeId ) ;
validEntityBeforeSave ( newCoil ) ;
baseMapper . insert ( newCoil ) ;
newCoils . add ( newCoil ) ;
}
} else if ( isMerge ) {
// 合卷:合并多个二维码信息为一个
Long mergedQrcodeId = generateQrcodeForMerge ( oldCoil , bo . getNewCoils ( ) ) ;
for ( WmsMaterialCoilBo newCoilBo : bo . getNewCoils ( ) ) {
WmsMaterialCoil newCoil = BeanUtil . toBean ( newCoilBo , WmsMaterialCoil . class ) ;
newCoil . setCoilId ( null ) ;
newCoil . setDataType ( 1 ) ;
newCoil . setEnterCoilNo ( oldCoil . getEnterCoilNo ( ) ) ;
newCoil . setQrcodeRecordId ( mergedQrcodeId ) ; // 所有合卷后的钢卷共享一个二维码
validEntityBeforeSave ( newCoil ) ;
baseMapper . insert ( newCoil ) ;
newCoils . add ( newCoil ) ;
}
}
return true ;
}
/**
* 为分卷生成新二维码(每个子钢卷一个)
*/
private Long generateQrcodeForSplit ( WmsMaterialCoil oldCoil , WmsMaterialCoilBo newCoilBo , List < String > allNewCoilNos ) {
try {
Map < String , Object > contentMap = new HashMap < > ( ) ;
contentMap . put ( " enter_coil_no " , oldCoil . getEnterCoilNo ( ) ) ;
contentMap . put ( " current_coil_no " , newCoilBo . getCurrentCoilNo ( ) ) ;
// 复制原钢卷的历史steps
List < Map < String , Object > > steps = new ArrayList < > ( ) ;
if ( oldCoil . getQrcodeRecordId ( ) ! = null ) {
WmsGenerateRecordVo oldRecord = generateRecordService . queryById ( oldCoil . getQrcodeRecordId ( ) ) ;
if ( oldRecord ! = null ) {
ObjectMapper objectMapper = new ObjectMapper ( ) ;
@SuppressWarnings ( " unchecked " )
Map < String , Object > oldContentMap = objectMapper . readValue ( oldRecord . getContent ( ) , Map . class ) ;
@SuppressWarnings ( " unchecked " )
List < Map < String , Object > > oldSteps = ( List < Map < String , Object > > ) oldContentMap . get ( " steps " ) ;
if ( oldSteps ! = null ) {
steps . addAll ( oldSteps ) ;
}
}
}
// 添加分卷步骤
Map < String , Object > splitStep = new HashMap < > ( ) ;
splitStep . put ( " step " , steps . size ( ) + 1 ) ;
splitStep . put ( " action " , " 更新 " ) ;
splitStep . put ( " operation " , " 分卷 " ) ;
splitStep . put ( " old_current_coil_no " , oldCoil . getCurrentCoilNo ( ) ) ;
splitStep . put ( " new_current_coil_nos " , String . join ( " , " , allNewCoilNos ) ) ;
splitStep . put ( " child_coils " , allNewCoilNos ) ;
steps . add ( splitStep ) ;
contentMap . put ( " steps " , steps ) ;
ObjectMapper objectMapper = new ObjectMapper ( ) ;
String contentJson = objectMapper . writeValueAsString ( contentMap ) ;
WmsGenerateRecordBo recordBo = new WmsGenerateRecordBo ( ) ;
recordBo . setContent ( contentJson ) ;
recordBo . setSerialNumber ( oldCoil . getEnterCoilNo ( ) + " - " + newCoilBo . getCurrentCoilNo ( ) ) ;
recordBo . setQrcodeType ( 0L ) ;
recordBo . setIsEnabled ( 0L ) ;
recordBo . setSize ( 200L ) ;
WmsGenerateRecordVo record = generateRecordService . insertByBo ( recordBo ) ;
return record . getRecordId ( ) ;
} catch ( Exception e ) {
throw new RuntimeException ( " 生成分卷二维码失败: " + e . getMessage ( ) ) ;
}
}
/**
* 为合卷生成新二维码(合并多个父钢卷的二维码信息)
*/
private Long generateQrcodeForMerge ( WmsMaterialCoil oldCoil , List < WmsMaterialCoilBo > newCoils ) {
try {
if ( newCoils . isEmpty ( ) ) {
throw new RuntimeException ( " 合卷后的钢卷数据不能为空 " ) ;
}
WmsMaterialCoilBo mergedCoilBo = newCoils . get ( 0 ) ;
Map < String , Object > contentMap = new HashMap < > ( ) ;
contentMap . put ( " enter_coil_no " , oldCoil . getEnterCoilNo ( ) ) ;
contentMap . put ( " current_coil_no " , mergedCoilBo . getCurrentCoilNo ( ) ) ;
// 合并所有父钢卷的历史steps
List < Map < String , Object > > steps = new ArrayList < > ( ) ;
// 如果有父钢卷号,获取它们的二维码信息并合并
if ( mergedCoilBo . getParentCoilNos ( ) ! = null & & ! mergedCoilBo . getParentCoilNos ( ) . trim ( ) . isEmpty ( ) ) {
String [ ] parentCoilNos = mergedCoilBo . getParentCoilNos ( ) . split ( " , " ) ;
for ( String parentCoilNo : parentCoilNos ) {
// 查找父钢卷
LambdaQueryWrapper < WmsMaterialCoil > parentLqw = Wrappers . lambdaQuery ( ) ;
parentLqw . eq ( WmsMaterialCoil : : getCurrentCoilNo , parentCoilNo . trim ( ) )
. eq ( WmsMaterialCoil : : getDataType , 1 ) ;
List < WmsMaterialCoil > parentCoils = baseMapper . selectList ( parentLqw ) ;
if ( ! parentCoils . isEmpty ( ) & & parentCoils . get ( 0 ) . getQrcodeRecordId ( ) ! = null ) {
WmsGenerateRecordVo parentQr = generateRecordService . queryById ( parentCoils . get ( 0 ) . getQrcodeRecordId ( ) ) ;
if ( parentQr ! = null ) {
ObjectMapper objectMapper = new ObjectMapper ( ) ;
@SuppressWarnings ( " unchecked " )
Map < String , Object > parentContentMap = objectMapper . readValue ( parentQr . getContent ( ) , Map . class ) ;
@SuppressWarnings ( " unchecked " )
List < Map < String , Object > > parentSteps = ( List < Map < String , Object > > ) parentContentMap . get ( " steps " ) ;
if ( parentSteps ! = null ) {
steps . addAll ( parentSteps ) ;
}
}
}
}
}
// 添加原钢卷的历史
if ( oldCoil . getQrcodeRecordId ( ) ! = null ) {
WmsGenerateRecordVo oldRecord = generateRecordService . queryById ( oldCoil . getQrcodeRecordId ( ) ) ;
if ( oldRecord ! = null ) {
ObjectMapper objectMapper = new ObjectMapper ( ) ;
@SuppressWarnings ( " unchecked " )
Map < String , Object > oldContentMap = objectMapper . readValue ( oldRecord . getContent ( ) , Map . class ) ;
@SuppressWarnings ( " unchecked " )
List < Map < String , Object > > oldSteps = ( List < Map < String , Object > > ) oldContentMap . get ( " steps " ) ;
if ( oldSteps ! = null ) {
steps . addAll ( oldSteps ) ;
}
}
}
// 添加合卷步骤
Map < String , Object > mergeStep = new HashMap < > ( ) ;
mergeStep . put ( " step " , steps . size ( ) + 1 ) ;
mergeStep . put ( " action " , " 更新 " ) ;
mergeStep . put ( " operation " , " 合卷 " ) ;
mergeStep . put ( " parent_coil_nos " , mergedCoilBo . getParentCoilNos ( ) ) ;
mergeStep . put ( " new_current_coil_no " , mergedCoilBo . getCurrentCoilNo ( ) ) ;
steps . add ( mergeStep ) ;
contentMap . put ( " steps " , steps ) ;
ObjectMapper objectMapper = new ObjectMapper ( ) ;
String contentJson = objectMapper . writeValueAsString ( contentMap ) ;
WmsGenerateRecordBo recordBo = new WmsGenerateRecordBo ( ) ;
recordBo . setContent ( contentJson ) ;
recordBo . setSerialNumber ( oldCoil . getEnterCoilNo ( ) + " - " + mergedCoilBo . getCurrentCoilNo ( ) ) ;
recordBo . setQrcodeType ( 0L ) ;
recordBo . setIsEnabled ( 0L ) ;
recordBo . setSize ( 200L ) ;
WmsGenerateRecordVo record = generateRecordService . insertByBo ( recordBo ) ;
return record . getRecordId ( ) ;
} catch ( Exception e ) {
throw new RuntimeException ( " 生成合卷二维码失败: " + e . getMessage ( ) ) ;
}
}
/**
* 更新二维码内容(单个更新)
*/
private void updateQrcodeContent ( Long qrcodeRecordId , WmsMaterialCoilBo bo ) {
try {
// 获取原钢卷信息
WmsMaterialCoil oldCoil = baseMapper . selectById ( bo . getCoilId ( ) ) ;
// 获取原二维码记录
WmsGenerateRecordVo oldRecord = generateRecordService . queryById ( qrcodeRecordId ) ;
if ( oldRecord = = null ) {
throw new RuntimeException ( " 二维码记录不存在 " ) ;
}
// 解析现有content
ObjectMapper objectMapper = new ObjectMapper ( ) ;
Map < String , Object > contentMap = objectMapper . readValue ( oldRecord . getContent ( ) , Map . class ) ;
// 获取现有steps
@SuppressWarnings ( " unchecked " )
List < Map < String , Object > > steps = ( List < Map < String , Object > > ) contentMap . get ( " steps " ) ;
if ( steps = = null ) {
steps = new ArrayList < > ( ) ;
}
// 添加新的step, 记录钢卷号的变化
Map < String , Object > newStep = new HashMap < > ( ) ;
newStep . put ( " step " , steps . size ( ) + 1 ) ;
newStep . put ( " action " , " 更新 " ) ;
newStep . put ( " old_current_coil_no " , oldCoil . getCurrentCoilNo ( ) ) ; // 原当前钢卷号
newStep . put ( " new_current_coil_no " , bo . getCurrentCoilNo ( ) ) ; // 新当前钢卷号
// 判断操作类型
if ( bo . getHasMergeSplit ( ) ! = null & & bo . getHasMergeSplit ( ) = = 2 ) {
newStep . put ( " operation " , " 合卷 " ) ;
newStep . put ( " parent_coil_nos " , bo . getParentCoilNos ( ) ) ;
} else if ( bo . getHasMergeSplit ( ) ! = null & & bo . getHasMergeSplit ( ) = = 1 ) {
newStep . put ( " operation " , " 分卷 " ) ;
newStep . put ( " new_current_coil_nos " , bo . getCurrentCoilNo ( ) ) ;
} else {
newStep . put ( " operation " , " 更新 " ) ;
}
steps . add ( newStep ) ;
contentMap . put ( " steps " , steps ) ;
// 更新当前钢卷号到最外层(方便快速查看)
contentMap . put ( " current_coil_no " , bo . getCurrentCoilNo ( ) ) ;
// 更新二维码记录
String newContentJson = objectMapper . writeValueAsString ( contentMap ) ;
WmsGenerateRecordBo updateBo = new WmsGenerateRecordBo ( ) ;
updateBo . setRecordId ( qrcodeRecordId ) ;
updateBo . setContent ( newContentJson ) ;
generateRecordService . updateByBo ( updateBo ) ;
} catch ( Exception e ) {
throw new RuntimeException ( " 更新二维码失败: " + e . getMessage ( ) ) ;
}
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave ( WmsMaterialCoil entity ) {
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除钢卷物料表
*/
@Override
public Boolean deleteWithValidByIds ( Collection < Long > ids , Boolean isValid ) {
if ( isValid ) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper . deleteBatchIds ( ids ) > 0 ;
}
/**
* 钢卷溯源查询
* 根据入场钢卷号查询二维码, 解析content中的steps, 然后根据steps中的钢卷号反向查询数据库
*
* @param enterCoilNo 入场钢卷号
* @param currentCoilNo 当前钢卷号(可选,用于查询特定子钢卷)
* @return 溯源结果(包含二维码信息和数据库记录)
*/
@Override
public Map < String , Object > queryTrace ( String enterCoilNo , String currentCoilNo ) {
try {
// 1. 根据入场钢卷号查询二维码记录
WmsGenerateRecordBo qrBo = new WmsGenerateRecordBo ( ) ;
qrBo . setSerialNumber ( enterCoilNo ) ;
List < WmsGenerateRecordVo > qrRecords = generateRecordService . queryList ( qrBo ) ;
if ( qrRecords . isEmpty ( ) ) {
throw new RuntimeException ( " 未找到对应的二维码记录 " ) ;
}
// 取第一个(应该只有一个)
WmsGenerateRecordVo qrRecord = qrRecords . get ( 0 ) ;
// 2. 解析二维码content中的steps
ObjectMapper objectMapper = new ObjectMapper ( ) ;
@SuppressWarnings ( " unchecked " )
Map < String , Object > contentMap = objectMapper . readValue ( qrRecord . getContent ( ) , Map . class ) ;
@SuppressWarnings ( " unchecked " )
List < Map < String , Object > > steps = ( List < Map < String , Object > > ) contentMap . get ( " steps " ) ;
// 3. 从steps中提取所有钢卷号
Set < String > coilNos = new HashSet < > ( ) ;
if ( steps ! = null ) {
for ( Map < String , Object > step : steps ) {
// 提取各种可能的钢卷号字段
extractCoilNo ( step , " current_coil_no " , coilNos ) ;
extractCoilNo ( step , " new_current_coil_no " , coilNos ) ;
extractCoilNo ( step , " old_current_coil_no " , coilNos ) ;
extractCoilNo ( step , " new_current_coil_nos " , coilNos ) ;
extractCoilNo ( step , " merged_from " , coilNos ) ;
extractCoilNo ( step , " parent_coil_nos " , coilNos ) ;
}
}
// 4. 如果指定了当前钢卷号,过滤出相关的钢卷号
Set < String > filteredCoilNos = coilNos ;
if ( currentCoilNo ! = null & & ! currentCoilNo . trim ( ) . isEmpty ( ) ) {
final String filterValue = currentCoilNo ; // 用于lambda的final变量
filteredCoilNos = coilNos . stream ( )
. filter ( coilNo - > coilNo . contains ( filterValue ) )
. collect ( Collectors . toSet ( ) ) ;
}
// 5. 根据提取的钢卷号反向查询数据库
List < WmsMaterialCoilVo > result = new ArrayList < > ( ) ;
if ( ! filteredCoilNos . isEmpty ( ) ) {
LambdaQueryWrapper < WmsMaterialCoil > lqw = Wrappers . lambdaQuery ( ) ;
lqw . eq ( WmsMaterialCoil : : getEnterCoilNo , enterCoilNo ) ;
// 查询包含提取出的钢卷号的记录
final Set < String > finalCoilNos = filteredCoilNos ; // 用于lambda的final变量
lqw . and ( wrapper - > {
int count = 0 ;
for ( String coilNo : finalCoilNos ) {
if ( count = = 0 ) {
wrapper . like ( WmsMaterialCoil : : getCurrentCoilNo , coilNo ) ;
} else {
wrapper . or ( ) . like ( WmsMaterialCoil : : getCurrentCoilNo , coilNo ) ;
}
count + + ;
}
} ) ;
lqw . orderByAsc ( WmsMaterialCoil : : getCreateTime ) ;
result = baseMapper . selectVoList ( lqw ) ;
}
// 6. 构建返回结果
Map < String , Object > resultMap = new HashMap < > ( ) ;
resultMap . put ( " qrcode " , qrRecord ) ;
resultMap . put ( " steps " , steps ) ;
resultMap . put ( " records " , result ) ;
return resultMap ;
} catch ( Exception e ) {
throw new RuntimeException ( " 溯源查询失败: " + e . getMessage ( ) ) ;
}
}
/**
* 从step中提取钢卷号
*/
private void extractCoilNo ( Map < String , Object > step , String fieldName , Set < String > coilNos ) {
Object value = step . get ( fieldName ) ;
if ( value ! = null ) {
String strValue = value . toString ( ) ;
if ( strValue . contains ( " , " ) ) {
// 如果是逗号分隔的多个钢卷号,分割后添加
String [ ] coilArray = strValue . split ( " , " ) ;
for ( String coilNo : coilArray ) {
coilNos . add ( coilNo . trim ( ) ) ;
}
} else {
coilNos . add ( strValue . trim ( ) ) ;
}
}
}
}