From 36ea48192699fc6dafa6e87bc5fd7d1ab381029a Mon Sep 17 00:00:00 2001 From: mashuai Date: Mon, 14 Oct 2024 16:16:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=95=E4=BD=8D=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../biz/constant/MaterialConstants.java | 10 + .../controller/BmUnitTypeController.java | 116 ++++++++ .../material/basic/domain/BmUnitType.java | 29 ++ .../basic/mapper/BmUnitTypeMapper.java | 53 ++++ .../basic/service/IBmUnitTypeService.java | 64 +++++ .../service/impl/BmUnitTypeServiceImpl.java | 256 ++++++++++++++++++ .../material/basic/BmUnitTypeMapper.xml | 64 +++++ .../material/template/BmUnitTypeTemplate.xlsx | Bin 0 -> 9870 bytes 8 files changed, 592 insertions(+) create mode 100644 bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/controller/BmUnitTypeController.java create mode 100644 bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/domain/BmUnitType.java create mode 100644 bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/mapper/BmUnitTypeMapper.java create mode 100644 bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/service/IBmUnitTypeService.java create mode 100644 bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/service/impl/BmUnitTypeServiceImpl.java create mode 100644 bonus-modules/bonus-material/src/main/resources/mapper/material/basic/BmUnitTypeMapper.xml create mode 100644 bonus-modules/bonus-material/src/main/resources/mapper/material/template/BmUnitTypeTemplate.xlsx diff --git a/bonus-common-biz/src/main/java/com/bonus/common/biz/constant/MaterialConstants.java b/bonus-common-biz/src/main/java/com/bonus/common/biz/constant/MaterialConstants.java index 9db1b115..1f4b9a9e 100644 --- a/bonus-common-biz/src/main/java/com/bonus/common/biz/constant/MaterialConstants.java +++ b/bonus-common-biz/src/main/java/com/bonus/common/biz/constant/MaterialConstants.java @@ -13,6 +13,16 @@ public class MaterialConstants */ public static final String UTF8 = "UTF-8"; + /** + * xls + */ + public static final String XLS = "xls"; + + /** + * XLSX + */ + public static final String XLSX = "xlsx"; + /** * 身份证正则表达式 */ diff --git a/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/controller/BmUnitTypeController.java b/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/controller/BmUnitTypeController.java new file mode 100644 index 00000000..bfc36b1a --- /dev/null +++ b/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/controller/BmUnitTypeController.java @@ -0,0 +1,116 @@ +package com.bonus.material.basic.controller; + +import com.bonus.common.core.utils.poi.ExcelUtil; +import com.bonus.common.core.web.controller.BaseController; +import com.bonus.common.core.web.domain.AjaxResult; +import com.bonus.common.core.web.page.TableDataInfo; +import com.bonus.common.log.annotation.SysLog; +import com.bonus.common.log.enums.OperaType; +import com.bonus.common.security.annotation.RequiresPermissions; +import com.bonus.material.basic.domain.BmUnit; +import com.bonus.material.basic.domain.BmUnitType; +import com.bonus.material.basic.service.IBmUnitTypeService; +import com.bonus.material.common.annotation.PreventRepeatSubmit; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * @Author ma_sh + * @create 2024/10/14 15:25 + */ +@Api(tags = "往来单位管理接口") +@RestController +@RequestMapping("/bm_unit_type") +public class BmUnitTypeController extends BaseController { + + + @Resource + private IBmUnitTypeService bmUnitTypeService; + + /** + * 查询往来单位类型管理列表 + */ + @ApiOperation(value = "查询往来单位类型管理列表") + @RequiresPermissions("basic:unitType:list") + @GetMapping("/list") + public TableDataInfo list(BmUnitType bmUnitType) + { + startPage(); + List list = bmUnitTypeService.selectBmUnitList(bmUnitType); + return getDataTable(list); + } + + @ApiOperation(value = "获取往来单位类型详细信息") + @RequiresPermissions("basic:unitType:query") + @GetMapping(value = "/{typeId}") + public AjaxResult getInfo(@PathVariable("id") Long typeId) + { + return AjaxResult.success(bmUnitTypeService.selectListByID(typeId)); + } + + @ApiOperation(value = "新增往来单位类型管理") + @RequiresPermissions("basic:unitType:add") + @PostMapping + public AjaxResult add(@RequestBody BmUnitType bmUnitType) + { + return bmUnitTypeService.insertBmUnitType(bmUnitType); + } + + @ApiOperation(value = "修改往来单位类型管理") + @RequiresPermissions("basic:unitType:edit") + @PutMapping + public AjaxResult edit(@RequestBody BmUnitType bmUnitType) + { + return bmUnitTypeService.updateBmUnitType(bmUnitType); + } + + @ApiOperation(value = "删除往来单位类型管理") + @RequiresPermissions("basic:unitType:remove") + @DeleteMapping("/{typeId}") + public AjaxResult remove(@PathVariable Long typeId) + { + return bmUnitTypeService.deleteBmUnitTypeByUnitTypeIds(typeId); + } + + /** + * 导入模版下载 + */ + @PostMapping("/downLoad") + public void downLoadExcelFile(){ + HttpServletResponse resp = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); + bmUnitTypeService.downLoadTemplate(resp); + } + + @ApiOperation(value = "导入往来单位类型管理列表") + @PreventRepeatSubmit + @RequiresPermissions("basic:unitType:importData") + @SysLog(title = "往来单位类型管理导入", businessType = OperaType.EXPORT, logType = 1,module = "仓储管理->导入往来单位类型管理列表") + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file) + { + return bmUnitTypeService.importData(file); + } + + /** + * 导出往来单位类型管理列表 + */ + @ApiOperation(value = "导出往来单位类型管理列表") + @PreventRepeatSubmit + @RequiresPermissions("basic:unitType:export") + @SysLog(title = "往来单位管理", businessType = OperaType.EXPORT, logType = 1,module = "仓储管理->导出往来单位类型管理") + @PostMapping("/export") + public void export(HttpServletResponse response, BmUnitType bmUnitType) + { + List list = bmUnitTypeService.selectBmUnitList(bmUnitType); + ExcelUtil util = new ExcelUtil(BmUnitType.class); + util.exportExcel(response, list, "往来单位管理数据"); + } +} diff --git a/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/domain/BmUnitType.java b/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/domain/BmUnitType.java new file mode 100644 index 00000000..17ee58c2 --- /dev/null +++ b/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/domain/BmUnitType.java @@ -0,0 +1,29 @@ +package com.bonus.material.basic.domain; + +import com.bonus.common.core.web.domain.BaseEntity; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @Author ma_sh + * @create 2024/10/14 15:29 + */ +@Data +public class BmUnitType extends BaseEntity { + + @ApiModelProperty(value = "主键id") + private Long typeId; + + @ApiModelProperty(value = "单位类型名称") + private String typeName; + + @ApiModelProperty(value = "数据所属组织") + private String companyId; + + /** 删除标志(0代表存在 2代表删除) */ + private String delFlag; + + @ApiModelProperty(value = "单位类型状态 0代表启用,1代表不启用") + private int status; + +} diff --git a/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/mapper/BmUnitTypeMapper.java b/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/mapper/BmUnitTypeMapper.java new file mode 100644 index 00000000..fd6be0f7 --- /dev/null +++ b/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/mapper/BmUnitTypeMapper.java @@ -0,0 +1,53 @@ +package com.bonus.material.basic.mapper; + +import com.bonus.material.basic.domain.BmUnitType; + +import java.util.List; + +/** + * @Author ma_sh + * @create 2024/10/14 15:27 + */ +public interface BmUnitTypeMapper { + /** + * 查询单位类型列表 + * @param bmUnitType + * @return + */ + List selectBmUnitList(BmUnitType bmUnitType); + + /** + * 根据主键查询单位类型 + * @param typeId + * @return + */ + BmUnitType selectListByID(Long typeId); + + /** + * 根据类型名称查询单位类型 + * @param typeName + * @return + */ + BmUnitType selectBmUnitTypeByTypeName(String typeName); + + /** + * 新增单位类型 + * @param bmUnitType + * @return + */ + int insertBmUnitType(BmUnitType bmUnitType); + + /** + * 修改单位类型 + * @param bmUnitType + * @return + */ + int updateBmUnitType(BmUnitType bmUnitType); + + /** + * 删除单位类型 + * @param typeId + * @return + */ + int deleteBmUnitTypeByUnitTypeIds(Long typeId); +} diff --git a/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/service/IBmUnitTypeService.java b/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/service/IBmUnitTypeService.java new file mode 100644 index 00000000..cc82bfb3 --- /dev/null +++ b/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/service/IBmUnitTypeService.java @@ -0,0 +1,64 @@ +package com.bonus.material.basic.service; + +import com.bonus.common.core.web.domain.AjaxResult; +import com.bonus.material.basic.domain.BmUnit; +import com.bonus.material.basic.domain.BmUnitType; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * @Author ma_sh + * @create 2024/10/14 15:26 + */ +public interface IBmUnitTypeService { + + /** + * 查询单位类型列表 + * @param bmUnitType + * @return + */ + List selectBmUnitList(BmUnitType bmUnitType); + + /** + * 根据id查询单位类型 + * @param typeId + * @return + */ + BmUnitType selectListByID(Long typeId); + + /** + * 新增单位类型 + * @param bmUnitType + * @return + */ + AjaxResult insertBmUnitType(BmUnitType bmUnitType); + + /** + * 修改单位类型 + * @param bmUnitType + * @return + */ + AjaxResult updateBmUnitType(BmUnitType bmUnitType); + + /** + * 删除单位类型 + * @param typeId + * @return + */ + AjaxResult deleteBmUnitTypeByUnitTypeIds(Long typeId); + + /** + * 导入模板 + * @param resp + */ + void downLoadTemplate(HttpServletResponse resp); + + /** + * 导入数据 + * @param file + * @return + */ + AjaxResult importData(MultipartFile file); +} diff --git a/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/service/impl/BmUnitTypeServiceImpl.java b/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/service/impl/BmUnitTypeServiceImpl.java new file mode 100644 index 00000000..4984e096 --- /dev/null +++ b/bonus-modules/bonus-material/src/main/java/com/bonus/material/basic/service/impl/BmUnitTypeServiceImpl.java @@ -0,0 +1,256 @@ +package com.bonus.material.basic.service.impl; + +import com.bonus.common.biz.constant.MaterialConstants; +import com.bonus.common.biz.enums.HttpCodeEnum; +import com.bonus.common.core.utils.StringUtils; +import com.bonus.common.core.utils.poi.ExcelUtil; +import com.bonus.common.core.web.domain.AjaxResult; +import com.bonus.material.basic.domain.BmUnitType; +import com.bonus.material.basic.mapper.BmUnitTypeMapper; +import com.bonus.material.basic.service.IBmUnitTypeService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; +import java.util.Objects; + +/** + * @Author ma_sh + * @create 2024/10/14 15:26 + */ +@Service +@Slf4j +public class BmUnitTypeServiceImpl implements IBmUnitTypeService { + + @Resource + private BmUnitTypeMapper bmUnitTypeMapper; + + /** + * 查询单位类型关联单位列表 + * @param bmUnitType + * @return + */ + @Override + public List selectBmUnitList(BmUnitType bmUnitType) { + return bmUnitTypeMapper.selectBmUnitList(bmUnitType); + } + + /** + * 根据ID查询单位类型关联单位 + * @param typeId + * @return + */ + @Override + public BmUnitType selectListByID(Long typeId) { + return bmUnitTypeMapper.selectListByID(typeId); + } + + /** + * 新增单位类型列表 + * @param bmUnitType + * @return + */ + @Override + public AjaxResult insertBmUnitType(BmUnitType bmUnitType) { + //根据单位类型名称查询,去重 + BmUnitType unitType = bmUnitTypeMapper.selectBmUnitTypeByTypeName(bmUnitType.getTypeName()); + if (unitType != null) { + return AjaxResult.error(HttpCodeEnum.NAME_DUPLICATE.getCode(), HttpCodeEnum.NAME_DUPLICATE.getMsg()); + } + int result = bmUnitTypeMapper.insertBmUnitType(bmUnitType); + if (result > 0) { + return AjaxResult.success(); + } + return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), HttpCodeEnum.FAIL.getMsg()); + } + + /** + * 修改单位类型列表 + * @param bmUnitType + * @return + */ + @Override + public AjaxResult updateBmUnitType(BmUnitType bmUnitType) { + //根据单位类型名称查询,去重 + BmUnitType unitType = bmUnitTypeMapper.selectBmUnitTypeByTypeName(bmUnitType.getTypeName()); + if (unitType != null) { + if (!Objects.equals(unitType.getTypeName(), bmUnitType.getTypeName())) { + return AjaxResult.error(HttpCodeEnum.NAME_DUPLICATE.getCode(), HttpCodeEnum.NAME_DUPLICATE.getMsg()); + } + } + int result = bmUnitTypeMapper.updateBmUnitType(bmUnitType); + if (result > 0) { + return AjaxResult.success(); + } + return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), HttpCodeEnum.FAIL.getMsg()); + } + + /** + * 删除单位类型列表 + * @param typeId + * @return + */ + @Override + public AjaxResult deleteBmUnitTypeByUnitTypeIds(Long typeId) { + //首先根据单位类型查询是否关联单位 + int result = bmUnitTypeMapper.deleteBmUnitTypeByUnitTypeIds(typeId); + if (result > 0) { + return AjaxResult.success(HttpCodeEnum.SUCCESS.getMsg(), result); + } + return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), HttpCodeEnum.FAIL.getMsg()); + } + + @Override + public void downLoadTemplate(HttpServletResponse response) { + //模板名称 + String templateName = "BmUnitTypeTemplate.xlsx"; + OutputStream out = null; + InputStream input = null; + try { + input = this.getClass().getClassLoader().getResourceAsStream("template/BmUnitTypeTemplate.xlsx"); + response.setCharacterEncoding("UTF-8"); + response.setHeader("content-Type", "application/vnd.ms-excel"); + response.setHeader("Content-Disposition", + "attachment;filename=" + new String((templateName).getBytes(), "iso-8859-1")); + response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); + out = response.getOutputStream(); + // 缓冲区 + byte[] buffer = new byte[1024]; + int bytesToRead = -1; + // 通过循环将读入内容输出到浏览器中 + while ((bytesToRead = input.read(buffer)) != -1) { + out.write(buffer, 0, bytesToRead); + } + } catch (IOException e) { + log.error(e.getMessage()); + } finally { + IOUtils.closeQuietly(input); + IOUtils.closeQuietly(out); + } + } + + /** + * 导入单位类型列表 + * @param file + * @return + */ + @Override + public AjaxResult importData(MultipartFile file) { + String fileName = file.getOriginalFilename(); + if (fileName != null) { + String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1); + if (!MaterialConstants.XLSX.equalsIgnoreCase(fileExtension)) { + // 文件后缀名不符合要求 + return AjaxResult.error("导入失败:文件后缀名不符合要求,必须为xlsx结尾"); + } + } + try { + InputStream inputStream = file.getInputStream(); + Workbook workbook = new XSSFWorkbook(inputStream); + + Sheet sheet = workbook.getSheetAt(0); + // 得到Excel的行数 + int totalRows = sheet.getPhysicalNumberOfRows(); + + // 检查是否有行数 + if (totalRows <= 1) { + throw new IllegalArgumentException("导入失败:Excel文件中没有数据,请检查后重新导入"); + } + // 读取第一行表头 + Row headerRow = sheet.getRow(0); + + if (headerRow == null) { + throw new IllegalArgumentException("导入失败:文件中没有表头"); + } + // 获取表头的列数 + int totalCells = headerRow.getPhysicalNumberOfCells(); + // 假设预期的表头列数为2列,可以根据实际需求修改这个条件 + if (totalCells != 2) { + throw new IllegalArgumentException("导入失败:表头列数与预期不符,请检查导入模板"); + } + // 读取表头内容并验证每一列,看是否符合模版要求 + for (int cellNum = 0; cellNum < totalCells; cellNum++) { + Cell cell = headerRow.getCell(cellNum); + // 获取单元格内容并去除首尾空格 + String headerValue = cell.getStringCellValue().trim(); + // 根据列索引进行验证 + switch (cellNum) { + case 0: + if (!"单位类型".equals(headerValue)) { + throw new IllegalArgumentException("第 " + (cellNum + 1) + " 列表头列名与预期不符,请检查导入模板"); + } + break; + case 1: + if (!"状态(0 启用 1 不启用)".equals(headerValue)) { + throw new IllegalArgumentException("第 " + (cellNum + 1) + " 列表头列名与预期不符,请检查导入模板"); + } + break; + default: + break; + } + } + //读取Excel表格数据,做非空判断 + // 循环Excel行数 + DataFormatter dataFormatter = new DataFormatter(); + for (int r = 1; r < totalRows; r++) { + Row row = sheet.getRow(r); + // 循环Excel列数 + for (int c = 0; c < totalCells; c++) { + String cellValue = dataFormatter.formatCellValue(row.getCell(c)); + switch (c) { + case 0: + checkCellNotEmpty(cellValue, r, c); + break; + case 1: + checkCellNotEmpty(cellValue, r, c); + break; + default: + throw new IllegalArgumentException( + String.format("第 %d 行,第 %d 列超出范围,请检查后重新导入", r + 1, c + 1)); + } + } + } + ExcelUtil util = new ExcelUtil<>(BmUnitType.class); + List bmUnitTypeList = util.importExcel(file.getInputStream()); + int result = 0; + for (BmUnitType bmUnitType : bmUnitTypeList) { + //根据单位类型名称查询,去重 + BmUnitType unitType = bmUnitTypeMapper.selectBmUnitTypeByTypeName(bmUnitType.getTypeName()); + if (unitType != null) { + //进行更新操作 + result += bmUnitTypeMapper.updateBmUnitType(unitType); + } else { + result += bmUnitTypeMapper.insertBmUnitType(bmUnitType); + } + } + if (result > 0) { + return AjaxResult.success(HttpCodeEnum.SUCCESS.getMsg(), result); + } + } catch (IOException e) { + e.printStackTrace(); + } + return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), HttpCodeEnum.FAIL.getMsg()); + } + + /** + * 提取方法用于检查单元格内容是否为空,并抛出异常 + * @param cellValue + * @param rowNum + * @param colNum + */ + private void checkCellNotEmpty(String cellValue, int rowNum, int colNum) { + if (StringUtils.isBlank(cellValue)) { + throw new IllegalArgumentException( + String.format("第 %d 行,第 %d 列数据为空,请检查后重新导入", rowNum + 1, colNum + 1)); + } + } +} diff --git a/bonus-modules/bonus-material/src/main/resources/mapper/material/basic/BmUnitTypeMapper.xml b/bonus-modules/bonus-material/src/main/resources/mapper/material/basic/BmUnitTypeMapper.xml new file mode 100644 index 00000000..1bfa44fd --- /dev/null +++ b/bonus-modules/bonus-material/src/main/resources/mapper/material/basic/BmUnitTypeMapper.xml @@ -0,0 +1,64 @@ + + + + + insert into bm_unit_type + + type_name, + status, + company_id, + del_flag, + create_by, + create_time, + update_by, + update_time, + + + #{typeName}, + #{status}, + #{companyId}, + 0, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + + + + update bm_unit_type + + type_name = #{typeName}, + status = #{status}, + company_id = #{companyId}, + update_by = #{updateBy}, + update_time = #{updateTime}, + + where type_id = #{typeId} + + + + update bm_unit_type set del_flag = 2 where type_id = #{typeId} + + + + + + + + \ No newline at end of file diff --git a/bonus-modules/bonus-material/src/main/resources/mapper/material/template/BmUnitTypeTemplate.xlsx b/bonus-modules/bonus-material/src/main/resources/mapper/material/template/BmUnitTypeTemplate.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..1601d17a9096d22a5f39c66b8728977e0965f044 GIT binary patch literal 9870 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 YC zqah@4XgPYT5lOC}r?fC?cgY2mB~5f>2 z$erletb>|C)YNjS8pug?><}W~Mq?SAQX*WbC%klw(JCxgf5sX5$DEzKdg*D-G3rbIA=e z-k%2U(Zuv*XT5^sl*FF*2`B3i>fR(Y$|>VRqjL)&_j?7Z_1=4%uL6(PYa=;tZ$U+K z@D~_Al0HAXKz`pK(0K*}2O|Q_VW8pNq2!R@mpS^U(%%izGsjP* zsIULz`SAe#FJ;fwnV;iX+4J~Yqsu?_{od;GO#D+H<=@%<)%fx|M8EfO{NfG*o$SAq z{@K;>JNxgA3BTAcLH76;`(JGe|Ldlo%kMwO^Gz#&Qdc1B^S>DWi4qs#-^|tT3;o@$ zJ?r_2lK$V>{>{q$F6Z~`;x9QQphf?uT;uN&eoxB$l0Xk??Rb{(SBmEU|K52)P=Hwf ztmggmg#2F5`=!z7?`*%Sd%rLF_iW-X0hFNLACTU^!}h-x{oFtCb3E^`-On9e=YxCEBJBwQT~>fhI;lnz|cTHvLJ1= IB+sAz57%uGXaE2J literal 0 HcmV?d00001