package com.ruoyi.system.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.basic.PageInfo; import com.ruoyi.common.core.domain.entity.TDept; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.system.dto.asset.AssetTypeDTO; import com.ruoyi.system.mapper.AssetTypeMapper; import com.ruoyi.system.model.AssetInventoryRecord; import com.ruoyi.system.model.AssetMain; import com.ruoyi.system.model.AssetType; import com.ruoyi.system.query.AssetInventoryListQuery; import com.ruoyi.system.query.AssetStatisticsListDetailQuery; import com.ruoyi.system.query.AssetStatisticsListQuery; import com.ruoyi.system.service.AssetInventoryRecordService; import com.ruoyi.system.service.AssetMainService; import com.ruoyi.system.service.AssetTypeService; import com.ruoyi.system.vo.AssetInventoryVO; import com.ruoyi.system.vo.AssetStatisticsDetailVO; import com.ruoyi.system.vo.AssetStatisticsVO; import com.ruoyi.system.vo.asset.AssetTypeTreeVO; import com.ruoyi.system.vo.system.NotificationVO; import io.swagger.annotations.ApiModelProperty; import io.swagger.models.auth.In; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; import java.util.stream.Collectors; /** *

* 资产类型表 服务实现类 *

* * @author WuGuanFengYue * @since 2025-09-15 */ @Service @RequiredArgsConstructor(onConstructor_ = {@Lazy}) public class AssetTypeServiceImpl extends ServiceImpl implements AssetTypeService { private final AssetMainService assetMainService; private final AssetTypeService assetTypeService; private final AssetInventoryRecordService assetInventoryRecordService; @Override public List getAssetTypeTree() { // 查询所有未删除的资产类型数据 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.orderByAsc(AssetType::getLevel) .orderByAsc(AssetType::getId); List allAssetTypes = this.list(queryWrapper); if (CollUtil.isEmpty(allAssetTypes)) { return new ArrayList<>(); } // 转换为VO对象 List assetTypeVOs = BeanUtil.copyToList(allAssetTypes, AssetTypeTreeVO.class); // 预查询:找出存在资产关联的资产类型ID集合(去重) List allTypeIds = allAssetTypes.stream().map(AssetType::getId).collect(Collectors.toList()); QueryWrapper usedTypeQuery = new QueryWrapper<>(); usedTypeQuery.select("distinct asset_type_id").in("asset_type_id", allTypeIds); List usedTypeRows = assetMainService.list(usedTypeQuery); Set usedTypeIdSet = usedTypeRows.stream() .map(AssetMain::getAssetTypeId) .filter(Objects::nonNull) .collect(Collectors.toSet()); // 按父级ID分组 Map> parentIdMap = assetTypeVOs.stream() .collect(Collectors.groupingBy(AssetTypeTreeVO::getParentId)); // 计算可删除标记:一级仅判断是否有子分类;二级仅判断是否有关联资产 for (AssetTypeTreeVO vo : assetTypeVOs) { if (Objects.equals(vo.getLevel(), 1)) { boolean hasChildren = parentIdMap.containsKey(vo.getId()) && CollUtil.isNotEmpty(parentIdMap.get(vo.getId())); vo.setCanDelete(!hasChildren); } else { boolean hasAssets = usedTypeIdSet.contains(vo.getId()); vo.setCanDelete(!hasAssets); } } // 构建树形结构 List rootNodes = parentIdMap.get(0); if (CollUtil.isEmpty(rootNodes)) { return new ArrayList<>(); } // 为每个根节点设置子节点 for (AssetTypeTreeVO rootNode : rootNodes) { List children = parentIdMap.get(rootNode.getId()); rootNode.setChildren(children != null ? children : new ArrayList<>()); } return rootNodes; } @Override public void addAssetType(AssetTypeDTO dto) { // 校验资产类型名称是否重复 LambdaQueryWrapper nameQueryWrapper = new LambdaQueryWrapper<>(); nameQueryWrapper.eq(AssetType::getTypeName, dto.getTypeName()); AssetType existingByName = this.getOne(nameQueryWrapper); if (Objects.nonNull(existingByName)) { throw new ServiceException("资产类型名称已存在"); } // 校验资产简写是否重复 LambdaQueryWrapper codeQueryWrapper = new LambdaQueryWrapper<>(); codeQueryWrapper.eq(AssetType::getTypeCode, dto.getTypeCode()); AssetType existingByCode = this.getOne(codeQueryWrapper); if (Objects.nonNull(existingByCode)) { throw new ServiceException("资产类型简写已存在"); } // 创建资产类型对象 AssetType assetType = new AssetType(); assetType.setTypeName(dto.getTypeName()); assetType.setTypeCode(dto.getTypeCode()); // 处理层级逻辑 if (Objects.isNull(dto.getParentId()) || dto.getParentId().equals(0)) { // 添加一级资产类型 assetType.setParentId(0); assetType.setLevel(1); } else { // 添加二级资产类型,先校验父级是否存在 AssetType parentAssetType = this.getById(dto.getParentId()); if (Objects.isNull(parentAssetType)) { throw new ServiceException("父级资产类型不存在"); } if (!parentAssetType.getLevel().equals(1)) { throw new ServiceException("只能在一级资产类型下添加二级资产类型"); } assetType.setParentId(dto.getParentId()); assetType.setLevel(2); } // 设置创建信息 String username = SecurityUtils.getUsername(); assetType.setCreateBy(username); // 保存资产类型 this.save(assetType); } @Override public void editAssetType(AssetTypeDTO dto) { // 校验资产类型ID是否为空 if (Objects.isNull(dto.getId())) { throw new ServiceException("资产类型ID不能为空"); } // 校验资产类型是否存在 AssetType existingAssetType = this.getById(dto.getId()); if (Objects.isNull(existingAssetType)) { throw new ServiceException("资产类型不存在"); } // 校验是否有关联的资产记录 LambdaQueryWrapper assetMainQueryWrapper = new LambdaQueryWrapper<>(); assetMainQueryWrapper.eq(AssetMain::getAssetTypeId, dto.getId()); long assetMainCount = assetMainService.count(assetMainQueryWrapper); if (assetMainCount > 0) { throw new ServiceException("该资产类型已关联资产记录,不能编辑"); } // 校验资产类型名称是否重复(排除自身) LambdaQueryWrapper nameQueryWrapper = new LambdaQueryWrapper<>(); nameQueryWrapper.eq(AssetType::getTypeName, dto.getTypeName()) .ne(AssetType::getId, dto.getId()); AssetType existingByName = this.getOne(nameQueryWrapper); if (Objects.nonNull(existingByName)) { throw new ServiceException("资产类型名称已存在"); } // 校验资产简写是否重复(排除自身) LambdaQueryWrapper codeQueryWrapper = new LambdaQueryWrapper<>(); codeQueryWrapper.eq(AssetType::getTypeCode, dto.getTypeCode()) .ne(AssetType::getId, dto.getId()); AssetType existingByCode = this.getOne(codeQueryWrapper); if (Objects.nonNull(existingByCode)) { throw new ServiceException("资产简写已存在"); } // 更新资产类型信息 AssetType assetType = new AssetType(); assetType.setId(dto.getId()); assetType.setTypeName(dto.getTypeName()); assetType.setTypeCode(dto.getTypeCode()); // 设置更新信息 String username = SecurityUtils.getUsername(); assetType.setUpdateBy(username); // 更新资产类型 this.updateById(assetType); } @Override public void deleteAssetType(Integer id) { // 校验资产类型ID是否为空 if (Objects.isNull(id)) { throw new ServiceException("资产类型ID不能为空"); } // 校验资产类型是否存在 AssetType existingAssetType = this.getById(id); if (Objects.isNull(existingAssetType)) { throw new ServiceException("资产类型不存在"); } // 校验是否有子类型 LambdaQueryWrapper childQueryWrapper = new LambdaQueryWrapper<>(); childQueryWrapper.eq(AssetType::getParentId, id); long childCount = this.count(childQueryWrapper); if (childCount > 0) { throw new ServiceException(String.format("【%s】存在子类型,不能删除", existingAssetType.getTypeName())); } // 校验是否有关联的资产记录 LambdaQueryWrapper assetMainQueryWrapper = new LambdaQueryWrapper<>(); assetMainQueryWrapper.eq(AssetMain::getAssetTypeId, id); long assetMainCount = assetMainService.count(assetMainQueryWrapper); if (assetMainCount > 0) { throw new ServiceException(String.format("【%s】已关联资产记录,不能删除", existingAssetType.getTypeName())); } // 删除资产类型 this.removeById(id); } @Override @Transactional(rollbackFor = Exception.class) public void batchDeleteAssetType(List ids) { // 校验ID列表是否为空 if (CollUtil.isEmpty(ids)) { throw new ServiceException("删除的资产类型ID列表不能为空"); } // 收集删除失败的信息 List failedMessages = new ArrayList<>(); // 逐个删除资产类型 for (Integer id : ids) { try { this.deleteAssetType(id); } catch (ServiceException e) { failedMessages.add(e.getMessage()); } } // 如果有删除失败的情况,抛出异常 if (CollUtil.isNotEmpty(failedMessages)) { throw new ServiceException("批量删除失败:" + String.join(";", failedMessages)); } } @Override public String getAssetCodePrefix(Integer assetTypeId) { if (assetTypeId == null) { throw new ServiceException("资产类型ID不能为空"); } // 查询当前资产类型 AssetType currentAssetType = this.getById(assetTypeId); if (currentAssetType == null) { throw new ServiceException("资产类型不存在"); } String parentTypeCode = ""; String subTypeCode = currentAssetType.getTypeCode(); // 如果是二级分类,需要获取父级分类的简写 if (currentAssetType.getLevel() == 2 && currentAssetType.getParentId() != null && currentAssetType.getParentId() != 0) { AssetType parentAssetType = this.getById(currentAssetType.getParentId()); if (parentAssetType != null) { parentTypeCode = parentAssetType.getTypeCode(); } } else if (currentAssetType.getLevel() == 1) { // 如果是一级分类,父级简写为空,子类简写就是当前类型简写 parentTypeCode = currentAssetType.getTypeCode(); subTypeCode = ""; } return parentTypeCode + subTypeCode; } @Override public PageInfo pageList(AssetStatisticsListQuery query) { if (StringUtils.hasLength(query.getNameOrCode())){ // 查询出资产名称或者资产编号符合条件的code List assetTypeIds = assetMainService.lambdaQuery().like(AssetMain::getAssetName, query.getNameOrCode()) .or() .like(AssetMain::getAssetCode, query.getNameOrCode()) .list() .stream() .map(AssetMain::getAssetTypeId) .collect(Collectors.toList()); query.setAssetMainIds(assetTypeIds); if (assetTypeIds.isEmpty()){ return new PageInfo<>(); } } PageInfo pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); List list = this.baseMapper.pageList(query,pageInfo); List listNoLimit = this.baseMapper.pageListNoLimit(query); List assetTypeIds = listNoLimit.stream().map(AssetStatisticsVO::getAssetTypeIdSecond).collect(Collectors.toList()); if (assetTypeIds.isEmpty()){ return new PageInfo<>(); } Map> assetMainMap = assetMainService.lambdaQuery() .in(!query.getDeptIds().isEmpty(),AssetMain::getOwnershipDeptId, query.getDeptIds()) .in(AssetMain::getAssetTypeId, assetTypeIds).list() .stream() .collect(Collectors.groupingBy(AssetMain::getAssetTypeId)); for (AssetStatisticsVO asset : list) { Integer totalCount= 0; Integer idleCount= 0; Integer useCount= 0; Integer disposeCount= 0; Integer otherCount= 0; BigDecimal totalValue = new BigDecimal("0"); List assetMains = assetMainMap.get(asset.getAssetTypeIdSecond()); if (!assetMains.isEmpty()){ for (AssetMain assetMain : assetMains) { if (assetMain.getAssetStatus().contains("闲置")){ idleCount += assetMain.getQuantity(); }else if (assetMain.getAssetStatus().contains("使用中")){ useCount += assetMain.getQuantity(); }else if (assetMain.getAssetStatus().contains("损坏") || assetMain.getAssetStatus().contains("报废")){ disposeCount += assetMain.getQuantity(); }else{ otherCount += assetMain.getQuantity(); } totalCount+= assetMain.getQuantity(); totalValue = totalValue.add(new BigDecimal(assetMain.getQuantity()) .multiply(assetMain.getUnitPrice()).setScale(2, RoundingMode.HALF_DOWN)); } } asset.setIdleCount(idleCount); asset.setUseCount(useCount); asset.setDisposeCount(disposeCount); asset.setOtherCount(otherCount); asset.setTotalCount(totalCount); asset.setTotalValue(totalValue); } pageInfo.setRecords(list); return pageInfo; } @Override public PageInfo pageListDetail(AssetStatisticsListDetailQuery query) { String assetTypeName = null; AssetType assetType = assetTypeService.getById(query.getAssetTypeIdSecond()); if (assetType!=null){ AssetType assetTypeParent = assetTypeService.getById(assetType.getParentId()); if (assetTypeParent!=null){ assetTypeName = assetTypeParent.getTypeName()+">"+assetType.getTypeName(); } } if (StringUtils.hasLength(query.getNameOrCode())){ // 查询出资产名称或者资产编号符合条件的code List assetTypeIds = assetMainService.lambdaQuery().like(AssetMain::getAssetName, query.getNameOrCode()) .or() .like(AssetMain::getAssetCode, query.getNameOrCode()) .list() .stream() .map(AssetMain::getAssetTypeId) .collect(Collectors.toList()); query.setAssetMainIds(assetTypeIds); if (assetTypeIds.isEmpty()){ return new PageInfo<>(); } } PageInfo pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); List list = this.baseMapper.pageListDetail(query,pageInfo); for (AssetStatisticsDetailVO assetStatisticsDetailVO : list) { assetStatisticsDetailVO.setAssetTypeName(assetTypeName); } pageInfo.setRecords(list); return pageInfo; } @Override public PageInfo pageListInventory(AssetInventoryListQuery query) { AssetType assetType = this.baseMapper.selectById(query.getAssetTypeId()); if (assetType.getParentId()==0){ List assetTypeChild = this.baseMapper.selectList(new LambdaQueryWrapper() .eq(AssetType::getParentId, assetType.getId())).stream().map(AssetType::getId) .collect(Collectors.toList()); List list = new ArrayList<>(assetTypeChild); list.add(assetType.getId()); query.setAssetTypeIds( list); }else{ query.setAssetTypeIds(Collections.singletonList(assetType.getId())); } PageInfo pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); List list = this.baseMapper.pageListInventory(query,pageInfo); Map> assetMainMap = assetMainService.lambdaQuery().in(AssetMain::getId, query.getAssetMainIds()).list() .stream().collect(Collectors.groupingBy(AssetMain::getAssetTypeId)); List assetInventoryRecords = assetInventoryRecordService.lambdaQuery().in(AssetInventoryRecord::getAssetMainId, query.getAssetMainIds()).list(); for (AssetInventoryVO assetInventoryVO : list) { int inCount = 0; int outCount = 0; int inStockCount = 0; BigDecimal inStockMoney = new BigDecimal("0"); BigDecimal inMoney = new BigDecimal("0"); BigDecimal outMoney = new BigDecimal("0"); List assetMains = assetMainMap.get(assetInventoryVO.getAssetTypeIdSecond()); for (AssetInventoryRecord assetInventoryRecord : assetInventoryRecords) { if (assetInventoryRecord.getType()==0){ AssetMain assetMain = assetMains.stream().filter(e -> e.getId().equals(assetInventoryRecord.getAssetMainId())) .findFirst().orElse(null); if (assetMain!=null){ inCount+=assetMain.getQuantity(); inMoney = inMoney.add(new BigDecimal(assetMain.getQuantity()) .multiply(assetMain.getUnitPrice()).setScale(2, RoundingMode.HALF_DOWN)); } }else{ AssetMain assetMain = assetMains.stream().filter(e -> e.getId().equals(assetInventoryRecord.getAssetMainId())) .findFirst().orElse(null); if (assetMain!=null){ outCount+=assetMain.getQuantity(); outMoney = outMoney.add(new BigDecimal(assetMain.getQuantity()) .multiply(assetMain.getUnitPrice()).setScale(2, RoundingMode.HALF_DOWN)); } } } assetInventoryVO.setInCount(inCount); assetInventoryVO.setOutCount(outCount); assetInventoryVO.setInMoney(inMoney); assetInventoryVO.setOutMoney(outMoney); List inStorage = assetMains.stream().filter(e -> e.getDisposed() == 0 && e.getInUse() == 0 && e.getBorrowed() == 0).collect(Collectors.toList()); for (AssetMain assetMain : inStorage) { inStockCount+=assetMain.getQuantity(); inStockMoney = inStockMoney.add(new BigDecimal(assetMain.getQuantity()) .multiply(assetMain.getUnitPrice()).setScale(2, RoundingMode.HALF_DOWN)); } assetInventoryVO.setInStockCount(inStockCount); assetInventoryVO.setInStockMoney(inStockMoney); } pageInfo.setRecords(list); return pageInfo; } @Override public PageInfo pageListInventoryDetail(AssetStatisticsListDetailQuery query) { PageInfo pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); List list = this.baseMapper.pageListInventoryDetail(query,pageInfo); List assetTypes = assetTypeService.list(); for (AssetStatisticsDetailVO assetStatisticsDetailVO : list) { Integer type = assetStatisticsDetailVO.getType(); if (type==0){ String typeName = "入库"; AssetType assetType = assetTypes.stream().filter(e -> e.getId().equals(assetStatisticsDetailVO.getAssetTypeId())) .findFirst().orElse(null); if (assetType!=null){ typeName =typeName+"("+assetType.getTypeName()+")"; } assetStatisticsDetailVO.setTypeName(typeName); }else{ String typeName = "出库"; AssetType assetType = assetTypes.stream().filter(e -> e.getId().equals(assetStatisticsDetailVO.getAssetTypeId())) .findFirst().orElse(null); if (assetType!=null){ typeName =typeName+"("+assetType.getTypeName()+")"; } assetStatisticsDetailVO.setTypeName(typeName); } } pageInfo.setRecords(list); return pageInfo; } }