feat: 添加仓库功能

This commit is contained in:
曹鹏飞 2025-07-02 11:38:49 +08:00
parent 4d4c5bf554
commit bf98a574f4
15 changed files with 878 additions and 1 deletions

View File

@ -0,0 +1,106 @@
package com.nflg.wms.admin.controller;
import com.nflg.wms.admin.service.WarehouseControllerService;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.qo.EnableQO;
import com.nflg.wms.common.pojo.qo.WarehouseAddQO;
import com.nflg.wms.common.pojo.qo.WarehouseSearchQO;
import com.nflg.wms.common.pojo.qo.WarehouseUpdateQO;
import com.nflg.wms.common.pojo.vo.WarehouseVO;
import com.nflg.wms.repository.entity.DictionaryItem;
import com.nflg.wms.starter.BaseController;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
/**
* 仓库管理
*/
@RestController
@RequestMapping("/warehouse")
public class WarehouseController extends BaseController {
@Resource
private WarehouseControllerService warehouseControllerService;
/**
* 获取工厂列表
*/
@GetMapping("getFactorys")
public ApiResult<List<DictionaryItem>> getFactorys(){
return ApiResult.success(warehouseControllerService.getFactorys());
}
/**
* 新增仓库
*/
@PostMapping("add")
public ApiResult<Void> add(@Valid @RequestBody WarehouseAddQO request){
warehouseControllerService.add(request);
return ApiResult.success();
}
/**
* 更新仓库
*/
@PostMapping("update")
public ApiResult<Void> update(@Valid @RequestBody WarehouseUpdateQO request){
warehouseControllerService.update(request);
return ApiResult.success();
}
/**
* 删除仓库
*/
@PostMapping("delete")
public ApiResult<Void> delete(@Valid @NotNull Long id){
warehouseControllerService.delete(id);
return ApiResult.success();
}
/**
* 启用/禁用仓库
* @param request 请求参数
*/
@PostMapping("/enable")
public ApiResult<Void> enable(@Valid @RequestBody EnableQO request){
warehouseControllerService.enable(request);
return ApiResult.success();
}
/**
* 搜索仓库
* @param request 搜索参数
*/
@PostMapping("search")
public ApiResult<PageData<WarehouseVO>> search(@Valid @RequestBody WarehouseSearchQO request){
return ApiResult.success(warehouseControllerService.search(request));
}
/**
* 导入仓库
* @param file 文件
*/
@Transactional
@PostMapping("import")
public ApiResult importFromExcel(HttpServletResponse response, @RequestParam(value = "file") MultipartFile file) throws IOException {
return warehouseControllerService.importFromExcel(response,file);
}
/**
* 导出选中的仓库为空时导出模版
* @param ids 选中的id集合
*/
@PostMapping("export")
public void exportSelect(HttpServletResponse response,@RequestBody List<Long> ids) throws Exception {
warehouseControllerService.exportSelect(response,ids);
}
}

View File

@ -0,0 +1,185 @@
package com.nflg.wms.admin.service;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.nflg.wms.common.constant.Constant;
import com.nflg.wms.common.constant.STATE;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.dto.WarehouseExcelExportDTO;
import com.nflg.wms.common.pojo.dto.WarehouseExcelImportDTO;
import com.nflg.wms.common.pojo.qo.EnableQO;
import com.nflg.wms.common.pojo.qo.WarehouseAddQO;
import com.nflg.wms.common.pojo.qo.WarehouseSearchQO;
import com.nflg.wms.common.pojo.qo.WarehouseUpdateQO;
import com.nflg.wms.common.pojo.vo.WarehouseVO;
import com.nflg.wms.common.util.DateTimeUtil;
import com.nflg.wms.common.util.EecExcelUtil;
import com.nflg.wms.common.util.UserUtil;
import com.nflg.wms.common.util.VUtil;
import com.nflg.wms.repository.entity.DictionaryItem;
import com.nflg.wms.repository.entity.Warehouse;
import com.nflg.wms.repository.service.IDictionaryItemService;
import com.nflg.wms.repository.service.IWarehouseService;
import com.nflg.wms.starter.service.FileUploadService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.ttzero.excel.entity.ListSheet;
import org.ttzero.excel.entity.Workbook;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Component
public class WarehouseControllerService {
@Resource
private IWarehouseService warehouseService;
@Resource
private IDictionaryItemService dictionaryItemService;
@Resource
private FileUploadService fileUploadService;
public void add(@Valid WarehouseAddQO request) {
Warehouse warehouse= Convert.convert(Warehouse.class, request);
warehouse.setCreateBy(UserUtil.getUserName());
warehouse.setCreateTime(LocalDateTime.now());
warehouseService.add(warehouse);
}
public void update(@Valid WarehouseUpdateQO request) {
Warehouse warehouse= Convert.convert(Warehouse.class, request);
warehouse.setUpdateBy(UserUtil.getUserName());
warehouse.setUpdateTime(LocalDateTime.now());
warehouseService.update(warehouse);
}
public void delete(@Valid @NotNull Long id) {
warehouseService.delete(id);
}
public List<DictionaryItem> getFactorys() {
return dictionaryItemService.getListByDictionaryCode(Constant.DICTIONARY_FACTORY);
}
public void enable(@Valid EnableQO request) {
warehouseService.enable(request);
}
public IPage<WarehouseVO> search(@Valid WarehouseSearchQO request) {
return warehouseService.search(request);
}
public void exportSelect(HttpServletResponse response, List<Long> ids) throws IOException {
List<WarehouseVO> warehouseVOS = CollectionUtil.isNotEmpty(ids) ? warehouseService.getList(ids) : new ArrayList<>();
List<WarehouseExcelExportDTO> datas = warehouseVOS.stream().map(warehouse -> Convert.convert(WarehouseExcelExportDTO.class, warehouse)).collect(Collectors.toList());
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode("仓库导出.xlsx", StandardCharsets.UTF_8));
if (CollectionUtil.isEmpty(datas)) {
datas.add(new WarehouseExcelExportDTO()
.setNo("(必填)仓库编号")
.setName("(必填)仓库名称")
.setPhone("联系电话")
.setAddress("所在地点")
.setUserName("责任人姓名")
.setCheckUserName("盘点责任人姓名")
.setFactoryName("所属工厂")
.setRemark("备注信息,此行为提示信息,导入时请删除"));
}
new Workbook()
.addSheet(new ListSheet<>(datas))
.writeTo(response.getOutputStream());
}
@Transactional
public ApiResult importFromExcel(HttpServletResponse response, MultipartFile file) throws IOException {
List<WarehouseExcelImportDTO> data = EecExcelUtil.getExcelContext(file.getInputStream(), WarehouseExcelImportDTO.class);
VUtil.trueThrowBusinessError(CollectionUtil.isEmpty(data)).throwMessage("导入文件内容为空");
if (updateCheckAndImport(data)) {
return ApiResult.success();
} else {
try(ByteArrayOutputStream osOut = new ByteArrayOutputStream()) {
new Workbook()
.addSheet(new ListSheet<>(data))
.writeTo(osOut);
try(ByteArrayInputStream isIn = new ByteArrayInputStream(osOut.toByteArray())) {
return ApiResult.error(STATE.DataNoCheckPass, "导入文件失败",fileUploadService.upload("temp/" + DateTimeUtil.format(LocalDate.now(),"yyyyMMdd")+"/"+ IdUtil.fastUUID() + ".xlsx", isIn));
}
}catch (Exception e){
return ApiResult.error(STATE.BusinessError, "保存文件出错");
}
}
}
@Transactional
public boolean updateCheckAndImport(List<WarehouseExcelImportDTO> data) {
List<DictionaryItem> factorys = dictionaryItemService.getListByDictionaryCode(Constant.DICTIONARY_FACTORY);
List<Warehouse> warehouses = new ArrayList<>();
for (WarehouseExcelImportDTO dto : data) {
Warehouse warehouse = new Warehouse();
StringBuilder sb = new StringBuilder();
if (Objects.isNull(dto.getNo())) {
sb.append("仓库编号不能为空;");
} else {
warehouse = warehouseService.lambdaQuery().eq(Warehouse::getNo, dto.getNo()).one();
if (Objects.isNull(warehouse)) {
warehouse = new Warehouse()
.setNo(dto.getNo())
.setEnable(true)
.setCreateBy(UserUtil.getUserName())
.setCreateTime(LocalDateTime.now());
}else {
warehouse.setUpdateBy(UserUtil.getUserName());
warehouse.setUpdateTime(LocalDateTime.now());
}
}
if (StrUtil.isBlank(dto.getName())){
sb.append("仓库名称不能为空;");
}else {
warehouse.setName(dto.getName());
}
warehouse.setUserName(dto.getUserName());
warehouse.setCheckUserName(dto.getCheckUserName());
warehouse.setPhone(dto.getPhone());
warehouse.setAddress(dto.getAddress());
if (StrUtil.isBlank(dto.getFactoryName())){
sb.append("所属工厂不能为空;");
}else {
DictionaryItem factory = factorys.stream().filter(s -> StrUtil.equals(s.getName(), dto.getFactoryName())).findFirst().orElse(null);
if (Objects.isNull(factory)){
sb.append("所属工厂无效;");
}else {
warehouse.setFactoryId(factory.getId());
}
}
warehouse.setRemark(dto.getRemark());
dto.setError(sb.toString());
warehouses.add(warehouse);
}
if (data.stream().noneMatch(it -> StrUtil.isNotBlank(it.getError()))) {
warehouseService.saveOrUpdateBatch(warehouses);
return true;
}
return false;
}
}

View File

@ -26,5 +26,7 @@ public class Constant {
public static final String DICTIONARY_ITEM_EMAIL_CONTENT_RESET_PASSWORD_NOTIFY = "ResetPassword";
public static final String DICTIONARY_FACTORY = "Factory";
public static String DICTIONARY_SUPPLIERS_CATEGORY="SuppliersCategory";
}

View File

@ -0,0 +1,58 @@
package com.nflg.wms.common.pojo.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import org.ttzero.excel.annotation.ExcelColumn;
@Data
@Accessors(chain = true)
public class WarehouseExcelExportDTO {
/**
* 仓库编码
*/
@ExcelColumn("*仓库编码")
private String no;
/**
* 仓库名称
*/
@ExcelColumn("*仓库名称")
private String name;
/**
* 责任人
*/
@ExcelColumn("责任人")
private String userName;
/**
* 盘点责任人
*/
@ExcelColumn("盘点责任人")
private String checkUserName;
/**
* 联系电话
*/
@ExcelColumn("联系电话")
private String phone;
/**
* 所在地点
*/
@ExcelColumn("所在地点")
private String address;
/**
* 所属工厂
*/
@ExcelColumn("所属工厂")
private String factoryName;
/**
* 备注
*/
@ExcelColumn("备注")
private String remark;
}

View File

@ -0,0 +1,64 @@
package com.nflg.wms.common.pojo.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import org.ttzero.excel.annotation.ExcelColumn;
@Data
@Accessors(chain = true)
public class WarehouseExcelImportDTO {
/**
* 仓库编码
*/
@ExcelColumn("*仓库编码")
private String no;
/**
* 仓库名称
*/
@ExcelColumn("*仓库名称")
private String name;
/**
* 责任人
*/
@ExcelColumn("责任人")
private String userName;
/**
* 盘点责任人
*/
@ExcelColumn("盘点责任人")
private String checkUserName;
/**
* 联系电话
*/
@ExcelColumn("联系电话")
private String phone;
/**
* 所在地点
*/
@ExcelColumn("所在地点")
private String address;
/**
* 所属工厂
*/
@ExcelColumn("所属工厂")
private String factoryName;
/**
* 备注
*/
@ExcelColumn("备注")
private String remark;
/**
* 错误信息
*/
@ExcelColumn("错误信息")
private String error;
}

View File

@ -0,0 +1,58 @@
package com.nflg.wms.common.pojo.qo;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
public class WarehouseAddQO {
/**
* 仓库编码
*/
@NotBlank
private String no;
/**
* 仓库名称
*/
@NotBlank
private String name;
/**
* 责任人
*/
private String userName;
/**
* 盘点责任人
*/
private String checkUserName;
/**
* 联系电话
*/
private String phone;
/**
* 所在地点
*/
private String address;
/**
* 是否启用
*/
@NotBlank
private Boolean enable;
/**
* 备注
*/
private String remark;
/**
* 所属工厂
*/
@NotNull
private Long factoryId;
}

View File

@ -0,0 +1,17 @@
package com.nflg.wms.common.pojo.qo;
import lombok.Data;
@Data
public class WarehouseSearchQO extends PageQO{
/**
* 仓库编号
*/
private String no;
/**
* 仓库名称
*/
private String name;
}

View File

@ -0,0 +1,11 @@
package com.nflg.wms.common.pojo.qo;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
public class WarehouseUpdateQO extends WarehouseAddQO{
@NotNull
private Long id;
}

View File

@ -0,0 +1,91 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class WarehouseVO {
private Long id;
/**
* 仓库编码
*/
private String no;
/**
* 仓库名称
*/
private String name;
/**
* 责任人
*/
private String userName;
/**
* 盘点责任人
*/
private String checkUserName;
/**
* 联系电话
*/
private String phone;
/**
* 所在地点
*/
private String address;
/**
* 是否启用
*/
private Boolean enable;
/**
* 备注
*/
private String remark;
/**
* 创建人
*/
private String createBy;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 最后更新人
*/
private String updateBy;
/**
* 最后更新时间
*/
private LocalDateTime updateTime;
/**
* SAP同步状态
*/
private Short sapState;
/**
* SAP同步错误信息
*/
private String sapError;
/**
* 所属工厂
*/
private Long factoryId;
/**
* 所属工厂名称
*/
private String factoryName;
}

View File

@ -0,0 +1,106 @@
package com.nflg.wms.repository.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 仓库
* </p>
*
* @author 代码生成器生成
* @since 2025
*/
@Getter
@Setter
@ToString
@Accessors(chain = true)
public class Warehouse implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 仓库编码
*/
private String no;
/**
* 仓库名称
*/
private String name;
/**
* 责任人
*/
private String userName;
/**
* 盘点责任人
*/
private String checkUserName;
/**
* 联系电话
*/
private String phone;
/**
* 所在地点
*/
private String address;
/**
* 是否启用
*/
private Boolean enable;
/**
* 备注
*/
private String remark;
/**
* 创建人
*/
private String createBy;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 最后更新人
*/
private String updateBy;
/**
* 最后更新时间
*/
private LocalDateTime updateTime;
/**
* SAP同步状态
*/
private Short sapState;
/**
* SAP同步错误信息
*/
private String sapError;
/**
* 所属工厂
*/
private Long factoryId;
}

View File

@ -0,0 +1,25 @@
package com.nflg.wms.repository.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nflg.wms.common.pojo.qo.WarehouseSearchQO;
import com.nflg.wms.common.pojo.vo.WarehouseVO;
import com.nflg.wms.repository.entity.Warehouse;
import java.util.List;
/**
* <p>
* 仓库 Mapper 接口
* </p>
*
* @author 代码生成器生成
* @since 2025
*/
public interface WarehouseMapper extends BaseMapper<Warehouse> {
IPage<WarehouseVO> search(WarehouseSearchQO request, Page<?> objectPage);
List<WarehouseVO> getList(List<Long> ids);
}

View File

@ -0,0 +1,35 @@
package com.nflg.wms.repository.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.nflg.wms.common.pojo.qo.EnableQO;
import com.nflg.wms.common.pojo.qo.WarehouseSearchQO;
import com.nflg.wms.common.pojo.vo.WarehouseVO;
import com.nflg.wms.repository.entity.Warehouse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import java.util.List;
/**
* <p>
* 仓库 服务类
* </p>
*
* @author 代码生成器生成
* @since 2025
*/
public interface IWarehouseService extends IService<Warehouse> {
void add(Warehouse warehouse);
void update(Warehouse warehouse);
void delete(@Valid @NotNull Long id);
void enable(@Valid EnableQO request);
IPage<WarehouseVO> search(@Valid WarehouseSearchQO request);
List<WarehouseVO> getList(List<Long> ids);
}

View File

@ -0,0 +1,91 @@
package com.nflg.wms.repository.service.impl;
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.nflg.wms.common.pojo.qo.EnableQO;
import com.nflg.wms.common.pojo.qo.WarehouseSearchQO;
import com.nflg.wms.common.pojo.vo.WarehouseVO;
import com.nflg.wms.common.util.UserUtil;
import com.nflg.wms.common.util.VUtil;
import com.nflg.wms.repository.entity.Warehouse;
import com.nflg.wms.repository.mapper.WarehouseMapper;
import com.nflg.wms.repository.service.IAuditLogService;
import com.nflg.wms.repository.service.IWarehouseService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
/**
* <p>
* 仓库 服务实现类
* </p>
*
* @author 代码生成器生成
* @since 2025
*/
@Service
public class WarehouseServiceImpl extends ServiceImpl<WarehouseMapper, Warehouse> implements IWarehouseService {
@Resource
private IAuditLogService auditLogService;
@Transactional
@Override
public void add(Warehouse warehouse) {
VUtil.trueThrowBusinessError(lambdaQuery().eq(Warehouse::getNo, warehouse.getNo()).exists())
.throwMessage("仓库编码已存在");
save(warehouse);
auditLogService.addInsert(Warehouse.class,warehouse, warehouse.getCreateBy());
}
@Transactional
@Override
public void update(Warehouse warehouse) {
VUtil.trueThrowBusinessError(lambdaQuery().eq(Warehouse::getNo, warehouse.getNo()).ne(Warehouse::getId, warehouse.getId()).exists())
.throwMessage("仓库编码已存在");
Warehouse old = getById(warehouse.getId());
VUtil.trueThrowBusinessError(Objects.isNull(old)).throwMessage("仓库不存在");
updateById(warehouse);
Warehouse newModel = getById(warehouse.getId());
auditLogService.addUpdate(Warehouse.class, old, newModel, warehouse.getUpdateBy());
}
@Transactional
@Override
public void delete(Long id) {
// TODO 删除仓库判断是否绑定了储位
Warehouse old = getById(id);
VUtil.trueThrowBusinessError(Objects.isNull(old)).throwMessage("仓库不存在");
removeById(id);
auditLogService.addDelete(Warehouse.class, old, UserUtil.getUserName());
}
@Override
public void enable(EnableQO request) {
Warehouse old = getById(request.getId());
VUtil.trueThrowBusinessError(Objects.isNull(old)).throwMessage("仓库不存在");
lambdaUpdate()
.set(Warehouse::getEnable, request.getEnable())
.set(Warehouse::getUpdateBy, UserUtil.getUserName())
.set(Warehouse::getUpdateTime, LocalDateTime.now())
.eq(Warehouse::getId, request.getId())
.update();
Warehouse newModel = getById(request.getId());
auditLogService.addUpdate(Warehouse.class, old, newModel, UserUtil.getUserName());
}
@Override
public IPage<WarehouseVO> search(WarehouseSearchQO request) {
return baseMapper.search(request, new Page<>(request.getPage(), request.getPageSize()));
}
@Override
public List<WarehouseVO> getList(List<Long> ids) {
return baseMapper.getList(ids);
}
}

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nflg.wms.repository.mapper.WarehouseMapper">
<select id="search" resultType="com.nflg.wms.common.pojo.vo.WarehouseVO">
select w.*,di.name as factory_name
from warehouse w
left join dictionary_item di on w.factory_id=di.id
<where>
<if test="request.no != null and request.no != ''">
and w.no like concat('%',#{request.no},'%')
</if>
<if test="request.name != null and request.name != ''">
and w.name like concat('%',#{request.name},'%')
</if>
</where>
</select>
<select id="getList" resultType="com.nflg.wms.common.pojo.vo.WarehouseVO">
select w.*,di.name as factory_name
from warehouse w
left join dictionary_item di on w.factory_id=di.id
where w.id in
<foreach item="item" collection="ids" separator="," open="(" close=")">
#{item}
</foreach>
</select>
</mapper>

View File

@ -33,7 +33,7 @@ public class CodeGeneratorTest {
)
.strategyConfig(builder -> {
builder
.addInclude("material") //只生成指定表
.addInclude("warehouse") //只生成指定表
.entityBuilder().idType(IdType.ASSIGN_ID)
.enableLombok()
.enableChainModel()