mitao
4 天以前 ab0ad84b5c577036f9ed5b53d2e90e81e5ba3de9
Merge branch 'feature_asset'
11个文件已修改
5个文件已添加
709 ■■■■■ 已修改文件
pom.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AssetTypeController.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AssetWarehouseController.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/dto/asset/AssetTypeDTO.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/dto/asset/AssetWarehouseDTO.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/AssetInventoryRecord.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/AssetType.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/query/AssetWarehousePageQuery.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/AssetTypeService.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/AssetWarehouseService.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/AssetTypeServiceImpl.java 189 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/AssetWarehouseServiceImpl.java 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/asset/AssetTypeTreeVO.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/asset/AssetWarehouseVO.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -166,7 +166,6 @@
        <module>ruoyi-quartz</module>
        <module>ruoyi-generator</module>
        <module>ruoyi-common</module>
        <module>ruoyi-applet</module>
    </modules>
    <packaging>pom</packaging>
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AssetTypeController.java
@@ -1,8 +1,25 @@
package com.ruoyi.web.controller.api;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.dto.asset.AssetTypeDTO;
import com.ruoyi.system.service.AssetTypeService;
import com.ruoyi.system.vo.asset.AssetTypeTreeVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.List;
/**
 * <p>
@@ -12,9 +29,42 @@
 * @author WuGuanFengYue
 * @since 2025-09-15
 */
@Api(tags = {"资产-资产类型管理相关接口"})
@Validated
@RestController
@RequestMapping("/asset-type")
@RequiredArgsConstructor
public class AssetTypeController {
    private final AssetTypeService assetTypeService;
    @ApiOperation("获取资产类型树形数据")
    @GetMapping("/tree")
    public R<List<AssetTypeTreeVO>> getAssetTypeTree() {
        List<AssetTypeTreeVO> treeData = assetTypeService.getAssetTypeTree();
        return R.ok(treeData);
    }
    @ApiOperation("新增资产类型")
    @PostMapping("/add")
    public R<Void> addAssetType(@Valid @RequestBody AssetTypeDTO dto) {
        assetTypeService.addAssetType(dto);
        return R.ok();
    }
    @ApiOperation("编辑资产类型")
    @PutMapping("/edit")
    public R<Void> editAssetType(@Valid @RequestBody AssetTypeDTO dto) {
        assetTypeService.editAssetType(dto);
        return R.ok();
    }
    @ApiOperation("删除资产类型")
    @DeleteMapping("/{id}")
    public R<Void> deleteAssetType(@ApiParam(name = "id", value = "资产类型ID", required = true) @PathVariable Integer id) {
        assetTypeService.deleteAssetType(id);
        return R.ok();
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AssetWarehouseController.java
@@ -1,8 +1,26 @@
package com.ruoyi.web.controller.api;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.dto.asset.AssetWarehouseDTO;
import com.ruoyi.system.query.AssetWarehousePageQuery;
import com.ruoyi.system.service.AssetWarehouseService;
import com.ruoyi.system.vo.asset.AssetWarehouseVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
/**
 * <p>
@@ -12,9 +30,41 @@
 * @author WuGuanFengYue
 * @since 2025-09-15
 */
@Api(tags = {"资产-仓库管理相关接口"})
@Validated
@RestController
@RequestMapping("/asset-warehouse")
@RequiredArgsConstructor
public class AssetWarehouseController {
    private final AssetWarehouseService assetWarehouseService;
    @ApiOperation("获取仓库分页列表")
    @PostMapping("/page-list")
    public R<IPage<AssetWarehouseVO>> getPageList(@RequestBody AssetWarehousePageQuery pageQuery) {
        IPage<AssetWarehouseVO> page = assetWarehouseService.getPageList(pageQuery);
        return R.ok(page);
    }
    @ApiOperation("新增仓库")
    @PostMapping("/add")
    public R<Void> addWarehouse(@Valid @RequestBody AssetWarehouseDTO dto) {
        assetWarehouseService.add(dto);
        return R.ok();
    }
    @ApiOperation("编辑仓库")
    @PutMapping("/add")
    public R<Void> editWarehouse(@Valid @RequestBody AssetWarehouseDTO dto) {
        assetWarehouseService.edit(dto);
        return R.ok();
    }
    @ApiOperation("删除仓库")
    @DeleteMapping("/{id}")
    public R<Void> deleteWarehouse(@ApiParam(name = "id", value = "仓库ID", required = true) @PathVariable Integer id) {
        assetWarehouseService.delete(id);
        return R.ok();
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/dto/asset/AssetTypeDTO.java
New file
@@ -0,0 +1,37 @@
package com.ruoyi.system.dto.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
 * 资产类型数据传输对象
 *
 * @author WuGuanFengYue
 * @date 2025/9/15
 */
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel("资产类型数据传输对象")
public class AssetTypeDTO implements Serializable {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty(value = "资产类型ID,编辑时必填")
    private Integer id;
    @ApiModelProperty(value = "父级资产类型ID,为空则添加一级资产类型")
    private Integer parentId;
    @ApiModelProperty(value = "资产类型名称", required = true)
    @NotBlank(message = "资产类型名称不能为空")
    private String typeName;
    @ApiModelProperty(value = "资产简写", required = true)
    @NotBlank(message = "资产简写不能为空")
    private String typeCode;
}
ruoyi-system/src/main/java/com/ruoyi/system/dto/asset/AssetWarehouseDTO.java
New file
@@ -0,0 +1,47 @@
package com.ruoyi.system.dto.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
import java.math.BigDecimal;
/**
 * @author mitao
 * @date 2025/9/15
 */
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel("仓库数据传输对象")
public class AssetWarehouseDTO implements Serializable {
    private static final long serialVersionUID = -64233615037814733L;
    @ApiModelProperty(value = "主键")
    private Integer id;
    @ApiModelProperty(value = "仓库名称")
    @NotBlank(message = "仓库名称不能为空")
    private String warehouseName;
    @ApiModelProperty(value = "权属部门ID")
    private Integer deptId;
    @ApiModelProperty(value = "面积(平方米)")
    private BigDecimal area;
    @ApiModelProperty(value = "位置")
    private String location;
    @ApiModelProperty(value = "负责人姓名")
    @NotBlank(message = "负责人姓名不能为空")
    private String managerName;
    @ApiModelProperty(value = "联系电话")
    @NotBlank(message = "联系电话不能为空")
    private String managerPhone;
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
@@ -1,8 +1,9 @@
package com.ruoyi.system.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.ruoyi.common.core.domain.entity.SysDept;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * 部门管理 数据层
@@ -115,4 +116,6 @@
     * @return 结果
     */
    public int deleteDeptById(Long deptId);
    public List<SysDept> selectByIds(@Param("deptIds") List<Integer> deptIds);
}
ruoyi-system/src/main/java/com/ruoyi/system/model/AssetInventoryRecord.java
@@ -10,6 +10,7 @@
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * <p>
@@ -35,13 +36,35 @@
    @TableField("asset_main_id")
    private Integer assetMainId;
    @ApiModelProperty(value = "仓库ID")
    @TableField("warehouse_id")
    private Integer warehouseId;
    @ApiModelProperty(value = "出入库类型 0-入库,1-出库")
    @TableField("type")
    private Boolean type;
    private Integer type;
    @ApiModelProperty(value = "备注(记录出入库类型,如资产入库、借用、借用归还、资产变更、领用、盘点、处置等)")
    @TableField("remarks")
    private String remarks;
    @ApiModelProperty(value = "创建时间")
    @TableField("create_time")
    private LocalDateTime createTime;
    @ApiModelProperty(value = "创建人")
    @TableField("create_by")
    private String createBy;
    @ApiModelProperty(value = "更新时间")
    @TableField("update_time")
    private LocalDateTime updateTime;
    @ApiModelProperty(value = "更新人")
    @TableField("update_by")
    private String updateBy;
    @ApiModelProperty(value = "是否删除 0-否,1-是")
    @TableField("disabled")
    private Boolean disabled;
}
ruoyi-system/src/main/java/com/ruoyi/system/model/AssetType.java
@@ -66,7 +66,7 @@
    @ApiModelProperty(value = "是否删除 0-否,1-是")
    @TableField("disabled")
    private Boolean disabled;
    private Integer disabled;
}
ruoyi-system/src/main/java/com/ruoyi/system/query/AssetWarehousePageQuery.java
New file
@@ -0,0 +1,20 @@
package com.ruoyi.system.query;
import com.ruoyi.common.core.domain.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * @author mitao
 * @date 2025/9/15
 */
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel("仓库分页查询对象")
public class AssetWarehousePageQuery extends BasePage {
    private static final long serialVersionUID = -2968978743484299082L;
    @ApiModelProperty("关键字" )
    private String keyword;
}
ruoyi-system/src/main/java/com/ruoyi/system/service/AssetTypeService.java
@@ -1,7 +1,11 @@
package com.ruoyi.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.system.dto.asset.AssetTypeDTO;
import com.ruoyi.system.model.AssetType;
import com.ruoyi.system.vo.asset.AssetTypeTreeVO;
import java.util.List;
/**
 * <p>
@@ -13,4 +17,28 @@
 */
public interface AssetTypeService extends IService<AssetType> {
    /**
     * 获取资产类型树形数据
     * @return 资产类型树形列表
     */
    List<AssetTypeTreeVO> getAssetTypeTree();
    /**
     * 新增资产类型
     * @param dto 资产类型数据传输对象
     */
    void addAssetType(AssetTypeDTO dto);
    /**
     * 编辑资产类型
     * @param dto 资产类型数据传输对象
     */
    void editAssetType(AssetTypeDTO dto);
    /**
     * 删除资产类型
     * @param id 资产类型ID
     */
    void deleteAssetType(Integer id);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/AssetWarehouseService.java
@@ -1,7 +1,11 @@
package com.ruoyi.system.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.system.dto.asset.AssetWarehouseDTO;
import com.ruoyi.system.model.AssetWarehouse;
import com.ruoyi.system.query.AssetWarehousePageQuery;
import com.ruoyi.system.vo.asset.AssetWarehouseVO;
/**
 * <p>
@@ -12,5 +16,27 @@
 * @since 2025-09-15
 */
public interface AssetWarehouseService extends IService<AssetWarehouse> {
    /**
     * 获取仓库分页列表
     * @param pageQuery
     * @return
     */
    IPage<AssetWarehouseVO> getPageList(AssetWarehousePageQuery pageQuery);
    /**
     * 添加仓库
     * @param dto
     */
    void add(AssetWarehouseDTO dto);
    /**
     * 编辑仓库
     * @param dto
     */
    void edit(AssetWarehouseDTO dto);
    /**
     * 删除仓库
     * @param id
     */
    void delete(Integer id);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/AssetTypeServiceImpl.java
@@ -1,10 +1,26 @@
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.extension.service.impl.ServiceImpl;
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.AssetMain;
import com.ruoyi.system.model.AssetType;
import com.ruoyi.system.service.AssetMainService;
import com.ruoyi.system.service.AssetTypeService;
import com.ruoyi.system.vo.asset.AssetTypeTreeVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
 * <p>
@@ -15,6 +31,179 @@
 * @since 2025-09-15
 */
@Service
@RequiredArgsConstructor
public class AssetTypeServiceImpl extends ServiceImpl<AssetTypeMapper, AssetType> implements AssetTypeService {
    private final AssetMainService assetMainService;
    @Override
    public List<AssetTypeTreeVO> getAssetTypeTree() {
        // 查询所有未删除的资产类型数据
        LambdaQueryWrapper<AssetType> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByAsc(AssetType::getLevel)
                .orderByAsc(AssetType::getId);
        List<AssetType> allAssetTypes = this.list(queryWrapper);
        if (CollUtil.isEmpty(allAssetTypes)) {
            return new ArrayList<>();
        }
        // 转换为VO对象
        List<AssetTypeTreeVO> assetTypeVOs = BeanUtil.copyToList(allAssetTypes, AssetTypeTreeVO.class);
        // 按父级ID分组
        Map<Integer, List<AssetTypeTreeVO>> parentIdMap = assetTypeVOs.stream()
                .collect(Collectors.groupingBy(AssetTypeTreeVO::getParentId));
        // 构建树形结构
        List<AssetTypeTreeVO> rootNodes = parentIdMap.get(0);
        if (CollUtil.isEmpty(rootNodes)) {
            return new ArrayList<>();
        }
        // 为每个根节点设置子节点
        for (AssetTypeTreeVO rootNode : rootNodes) {
            List<AssetTypeTreeVO> children = parentIdMap.get(rootNode.getId());
            rootNode.setChildren(children != null ? children : new ArrayList<>());
        }
        return rootNodes;
    }
    @Override
    public void addAssetType(AssetTypeDTO dto) {
        // 校验资产类型名称是否重复
        LambdaQueryWrapper<AssetType> nameQueryWrapper = new LambdaQueryWrapper<>();
        nameQueryWrapper.eq(AssetType::getTypeName, dto.getTypeName());
        AssetType existingByName = this.getOne(nameQueryWrapper);
        if (Objects.nonNull(existingByName)) {
            throw new ServiceException("资产类型名称已存在");
        }
        // 校验资产简写是否重复
        LambdaQueryWrapper<AssetType> 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<AssetMain> assetMainQueryWrapper = new LambdaQueryWrapper<>();
        assetMainQueryWrapper.eq(AssetMain::getAssetTypeId, dto.getId());
        long assetMainCount = assetMainService.count(assetMainQueryWrapper);
        if (assetMainCount > 0) {
            throw new ServiceException("该资产类型已关联资产记录,不能编辑");
        }
        // 校验资产类型名称是否重复(排除自身)
        LambdaQueryWrapper<AssetType> 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<AssetType> 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<AssetType> childQueryWrapper = new LambdaQueryWrapper<>();
        childQueryWrapper.eq(AssetType::getParentId, id);
        long childCount = this.count(childQueryWrapper);
        if (childCount > 0) {
            throw new ServiceException("该资产类型存在子类型,不能删除");
        }
        // 校验是否有关联的资产记录
        LambdaQueryWrapper<AssetMain> assetMainQueryWrapper = new LambdaQueryWrapper<>();
        assetMainQueryWrapper.eq(AssetMain::getAssetTypeId, id);
        long assetMainCount = assetMainService.count(assetMainQueryWrapper);
        if (assetMainCount > 0) {
            throw new ServiceException("该资产类型已关联资产记录,不能删除");
        }
        // 删除资产类型
        this.removeById(id);
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/AssetWarehouseServiceImpl.java
@@ -1,10 +1,31 @@
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.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.dto.asset.AssetWarehouseDTO;
import com.ruoyi.system.mapper.AssetWarehouseMapper;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.model.AssetInventoryRecord;
import com.ruoyi.system.model.AssetWarehouse;
import com.ruoyi.system.query.AssetWarehousePageQuery;
import com.ruoyi.system.service.AssetInventoryRecordService;
import com.ruoyi.system.service.AssetWarehouseService;
import com.ruoyi.system.vo.asset.AssetWarehouseVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
 * <p>
@@ -15,6 +36,87 @@
 * @since 2025-09-15
 */
@Service
@RequiredArgsConstructor
public class AssetWarehouseServiceImpl extends ServiceImpl<AssetWarehouseMapper, AssetWarehouse> implements AssetWarehouseService {
    private final AssetInventoryRecordService assetInventoryRecordService;
    private final SysDeptMapper sysDeptMapper;
    @Override
    public IPage<AssetWarehouseVO> getPageList(AssetWarehousePageQuery pageQuery) {
        LambdaQueryWrapper<AssetWarehouse> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(pageQuery.getKeyword())) {
            queryWrapper.like(AssetWarehouse::getWarehouseName, pageQuery.getKeyword())
                    .or()
                    .like(AssetWarehouse::getManagerName, pageQuery.getKeyword());
        }
        Page<AssetWarehouse> page = this.page(new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize()), queryWrapper);
        Page<AssetWarehouseVO> pageVO = new Page<>();
        BeanUtil.copyProperties(page, pageVO, "records");
        List<AssetWarehouseVO> assetWarehouseVOS = BeanUtil.copyToList(page.getRecords(), AssetWarehouseVO.class);
        if (CollUtil.isEmpty(assetWarehouseVOS)) {
            return pageVO;
        }
        List<Integer> warehouseIds = assetWarehouseVOS.stream().map(AssetWarehouseVO::getId).collect(Collectors.toList());
        List<Integer> deptIds = assetWarehouseVOS.stream().map(AssetWarehouseVO::getDeptId).distinct().collect(Collectors.toList());
        List<SysDept> sysDepts = sysDeptMapper.selectByIds(deptIds);
        Map<Integer, String> deptMap = sysDepts.stream()
                .collect(Collectors.toMap(item->item.getDeptId().intValue(), SysDept::getDeptName));
        //查询库存数量
        Map<Integer, List<AssetInventoryRecord>> inventoryRecordMap = assetInventoryRecordService.lambdaQuery()
                .in(AssetInventoryRecord::getWarehouseId, warehouseIds)
                .list().stream().collect(Collectors.groupingBy(AssetInventoryRecord::getWarehouseId));
        //计算当前库存
        assetWarehouseVOS.forEach(warehouseVO -> {
            List<AssetInventoryRecord> assetInventoryRecords = inventoryRecordMap.get(warehouseVO.getId());
            if (CollUtil.isEmpty(assetInventoryRecords)) {
                warehouseVO.setCurrentStock(0);
            }
            long inStock = assetInventoryRecords.stream().filter(item -> item.getType().equals(0)).count();
            long outStock = assetInventoryRecords.stream().filter(item -> item.getType().equals(1)).count();
            warehouseVO.setCurrentStock((int) (inStock - outStock));
            //设置部门名称
            warehouseVO.setDeptName(deptMap.getOrDefault(warehouseVO.getDeptId(), ""));
        });
        pageVO.setRecords(assetWarehouseVOS);
        return pageVO;
    }
    @Override
    public void add(AssetWarehouseDTO dto) {
        AssetWarehouse assetWarehouse = BeanUtil.copyProperties(dto, AssetWarehouse.class);
        String username = SecurityUtils.getUsername();
        assetWarehouse.setCreateBy(username);
        this.save(assetWarehouse);
    }
    @Override
    public void edit(AssetWarehouseDTO dto) {
        if (Objects.isNull(dto.getId())) {
            throw new ServiceException("仓库ID不能为空");
        }
        AssetWarehouse assetWarehouse = BeanUtil.copyProperties(dto, AssetWarehouse.class);
        String username = SecurityUtils.getUsername();
        assetWarehouse.setUpdateBy(username);
        this.updateById(assetWarehouse);
    }
    @Override
    public void delete(Integer id) {
        if (Objects.isNull(id)) {
            throw new ServiceException("仓库ID不能为空");
        }
        List<AssetInventoryRecord> list = assetInventoryRecordService.lambdaQuery().eq(AssetInventoryRecord::getWarehouseId, id).list();
        if (CollUtil.isNotEmpty(list)) {
            List<Integer> inStockIds = list.stream().filter(item -> item.getType().equals(0)).map(AssetInventoryRecord::getAssetMainId).collect(Collectors.toList());
            list.stream().filter(item -> item.getType().equals(1)).forEach(item -> {
                inStockIds.remove(item.getAssetMainId());
            });
            if (CollUtil.isNotEmpty(inStockIds)) {
                throw new ServiceException("该仓库存在库存记录,不能删除");
            }
        }
        this.removeById(id);
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/asset/AssetTypeTreeVO.java
New file
@@ -0,0 +1,57 @@
package com.ruoyi.system.vo.asset;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
/**
 * 资产类型树形视图对象
 *
 * @author WuGuanFengYue
 * @date 2025/9/15
 */
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel("资产类型树形视图对象")
public class AssetTypeTreeVO implements Serializable {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty(value = "主键")
    private Integer id;
    @ApiModelProperty(value = "资产类型名称")
    private String typeName;
    @ApiModelProperty(value = "资产简写")
    private String typeCode;
    @ApiModelProperty(value = "父级ID,0表示一级分类")
    private Integer parentId;
    @ApiModelProperty(value = "层级:1-一级分类,2-二级分类")
    private Integer level;
    @ApiModelProperty(value = "创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    @ApiModelProperty(value = "创建人")
    private String createBy;
    @ApiModelProperty(value = "更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    @ApiModelProperty(value = "更新人")
    private String updateBy;
    @ApiModelProperty(value = "子节点列表")
    private List<AssetTypeTreeVO> children;
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/asset/AssetWarehouseVO.java
New file
@@ -0,0 +1,49 @@
package com.ruoyi.system.vo.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
/**
 * @author mitao
 * @date 2025/9/15
 */
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel("仓库视图对象")
public class AssetWarehouseVO implements Serializable {
    private static final long serialVersionUID = 6352690221179631751L;
    @ApiModelProperty(value = "主键")
    private Integer id;
    @ApiModelProperty(value = "仓库名称")
    private String warehouseName;
    @ApiModelProperty(value = "权属部门ID")
    private Integer deptId;
    @ApiModelProperty(value = "权属部门名称")
    private String deptName;
    @ApiModelProperty(value = "面积(平方米)")
    private BigDecimal area;
    @ApiModelProperty(value = "位置")
    private String location;
    @ApiModelProperty(value = "负责人姓名")
    private String managerName;
    @ApiModelProperty(value = "联系电话")
    private String managerPhone;
    @ApiModelProperty(value = "当前库存数量" )
    private Integer currentStock;
}
ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
@@ -86,7 +86,22 @@
        <include refid="selectDeptVo"/>
        where dept_name=#{deptName} and parent_id = #{parentId} and del_flag = '0' limit 1
    </select>
    <select id="selectByIds" resultType="com.ruoyi.common.core.domain.entity.SysDept"
            parameterType="java.util.List">
        select * from sys_dept
        <where>
            del_flag = '0'
            <if test="deptIds !=null and deptIds.size() != 0">
                and dept_id in
                <foreach collection="deptIds" item="item" open="(" separator="," close=")">
                    #{item}
                </foreach>
            </if>
        </where>
        order by id desc
    </select>
    <insert id="insertDept" parameterType="SysDept">
         insert into sys_dept(
             <if test="deptId != null and deptId != 0">dept_id,</if>