From 2de0b7149b3b4d8b28d58229b568d330f7232cb7 Mon Sep 17 00:00:00 2001 From: liyongde <1419499670@qq.com> Date: Tue, 29 Jul 2025 17:32:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=89=A9=E6=96=99=E3=80=81=E5=8D=95?= =?UTF-8?q?=E4=BD=8D=E5=AF=BC=E5=85=A5=E6=95=B0=E6=8D=AE=E3=80=81=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E6=A8=A1=E6=9D=BF=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/nl/common/utils/FileUtil.java | 18 ++ .../controller/MaterialbaseController.java | 17 ++ .../controller/MeasureUnitController.java | 16 ++ .../service/IMdMeMaterialbaseService.java | 9 +- .../service/IMdPbMeasureunitService.java | 7 +- .../impl/MdMeMaterialbaseServiceImpl.java | 85 +++++++++- .../impl/MdPbMeasureunitServiceImpl.java | 72 +++++++- .../service/impl/PdaIosInServiceImpl.java | 4 +- .../resources/excel/material_template.xlsx | Bin 0 -> 9585 bytes .../main/resources/excel/unit_template.xlsx | Bin 0 -> 9459 bytes .../wms/basedata/material/UploadDialog.vue | 34 +++- .../views/wms/basedata/material/material.js | 10 +- .../wms/basedata/measure/UploadDialog.vue | 157 ++++++++++++++++++ .../src/views/wms/basedata/measure/index.vue | 18 +- .../wms/basedata/measure/mdPbMeasureunit.js | 18 +- 15 files changed, 447 insertions(+), 18 deletions(-) create mode 100644 lms/nladmin-system/nlsso-server/src/main/resources/excel/material_template.xlsx create mode 100644 lms/nladmin-system/nlsso-server/src/main/resources/excel/unit_template.xlsx create mode 100644 lms/nladmin-ui/src/views/wms/basedata/measure/UploadDialog.vue diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/common/utils/FileUtil.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/common/utils/FileUtil.java index a03479e..b61198f 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/common/utils/FileUtil.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/common/utils/FileUtil.java @@ -17,6 +17,7 @@ package org.nl.common.utils; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.URLUtil; import cn.hutool.poi.excel.BigExcelWriter; import cn.hutool.poi.excel.ExcelUtil; import org.apache.poi.util.IOUtils; @@ -25,6 +26,7 @@ import org.nl.common.exception.BadRequestException; import org.nl.config.language.LangProcess; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletOutputStream; @@ -344,4 +346,20 @@ public class FileUtil extends cn.hutool.core.io.FileUtil { return getMd5(getByte(file)); } + public static byte[] getByteByTemplate(String templateName) throws IOException { + // 使用 ClassPathResource 获取资源 + ClassPathResource resource = new ClassPathResource(templateName); + InputStream inputStream = resource.getInputStream(); + return IoUtil.readBytes(inputStream); + } + + public static void download(String fileName, byte[] fileBytes, HttpServletResponse response) throws IOException { + response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode(fileName)); + response.addHeader("Content-Length", "" + fileBytes.length); + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); + response.setContentType("application/octet-stream;charset=UTF-8"); + IoUtil.write(response.getOutputStream(), true, fileBytes); + } + } diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/controller/MaterialbaseController.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/controller/MaterialbaseController.java index 54406b9..78ab2e3 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/controller/MaterialbaseController.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/controller/MaterialbaseController.java @@ -11,10 +11,14 @@ import org.nl.wms.basedata_manage.service.IMdMeMaterialbaseService; import org.nl.wms.basedata_manage.service.dao.MdMeMaterialbase; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; import java.util.Map; import java.util.Set; @@ -69,5 +73,18 @@ public class MaterialbaseController { return new ResponseEntity<>(HttpStatus.NO_CONTENT); } + @PostMapping("/importExcel") + @Log("导入物料") + public ResponseEntity importExcel(@RequestPart("file") MultipartFile file) { + iMdMeMaterialbaseService.importExcel(file); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("下载导入模板") + @GetMapping(value = "/downloadImportMaterialTemplate", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + public void downloadImportUserTemplate(HttpServletResponse response) { + iMdMeMaterialbaseService.downloadImportMaterialTemplate(response); + } + } diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/controller/MeasureUnitController.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/controller/MeasureUnitController.java index 812a121..38412b7 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/controller/MeasureUnitController.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/controller/MeasureUnitController.java @@ -10,10 +10,13 @@ import org.nl.wms.basedata_manage.service.IMdPbMeasureunitService; import org.nl.wms.basedata_manage.service.dao.MdPbMeasureunit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; import java.util.Map; import java.util.Set; @@ -61,4 +64,17 @@ public class MeasureUnitController { return new ResponseEntity<>(HttpStatus.OK); } + @PostMapping("/importExcel") + @Log("导入单位") + public ResponseEntity importExcel(@RequestPart("file") MultipartFile file) { + iMdPbMeasureunitService.importExcel(file); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("下载导入模板") + @GetMapping(value = "/downloadImportUnitTemplate", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + public void downloadImportUnitTemplate(HttpServletResponse response) { + iMdPbMeasureunitService.downloadImportUnitTemplate(response); + } + } diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/IMdMeMaterialbaseService.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/IMdMeMaterialbaseService.java index 0002f90..7a679c1 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/IMdMeMaterialbaseService.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/IMdMeMaterialbaseService.java @@ -5,7 +5,9 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; import org.nl.common.domain.query.PageQuery; import org.nl.wms.basedata_manage.service.dao.MdMeMaterialbase; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; import java.util.Map; import java.util.Set; @@ -55,7 +57,12 @@ public interface IMdMeMaterialbaseService extends IService { /** * 根据编码获取物料 * @param material_code 物料编码 + * @param flag 为空是否抛出异常 * @return 返回结果 */ - MdMeMaterialbase getByCode(String material_code); + MdMeMaterialbase getByCode(String material_code, Boolean flag); + + void importExcel(MultipartFile file); + + void downloadImportMaterialTemplate(HttpServletResponse response); } diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/IMdPbMeasureunitService.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/IMdPbMeasureunitService.java index c241ed0..7696c9e 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/IMdPbMeasureunitService.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/IMdPbMeasureunitService.java @@ -4,7 +4,9 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; import org.nl.common.domain.query.PageQuery; import org.nl.wms.basedata_manage.service.dao.MdPbMeasureunit; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; import java.util.Map; import java.util.Set; @@ -49,6 +51,9 @@ public interface IMdPbMeasureunitService extends IService { * @param unit_code 编码 * @return 实体类 */ - MdPbMeasureunit getByCode(String unit_code); + MdPbMeasureunit getByCode(String unit_code, Boolean flag); + void importExcel(MultipartFile file); + + void downloadImportUnitTemplate(HttpServletResponse response); } diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/impl/MdMeMaterialbaseServiceImpl.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/impl/MdMeMaterialbaseServiceImpl.java index 55c6fc9..fd25568 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/impl/MdMeMaterialbaseServiceImpl.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/impl/MdMeMaterialbaseServiceImpl.java @@ -1,16 +1,20 @@ package org.nl.wms.basedata_manage.service.impl; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.IoUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.URLUtil; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.apache.poi.ss.usermodel.*; import org.nl.common.domain.query.PageQuery; import org.nl.common.exception.BadRequestException; +import org.nl.common.utils.FileUtil; import org.nl.common.utils.IdUtil; import org.nl.common.utils.SecurityUtils; import org.nl.wms.basedata_manage.service.IMdMeMaterialbaseService; @@ -18,9 +22,14 @@ import org.nl.wms.basedata_manage.service.dao.MdMeMaterialbase; import org.nl.wms.basedata_manage.service.dao.mapper.MdMeMaterialbaseMapper; import org.nl.wms.ext_manage.service.WmsToErpService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -43,6 +52,8 @@ public class MdMeMaterialbaseServiceImpl extends ServiceImpl queryAll(Map whereJson, PageQuery page) { @@ -62,7 +73,7 @@ public class MdMeMaterialbaseServiceImpl extends ServiceImpl ids) { this.baseMapper.deleteBatchIds(ids); } @Override - @Transactional + @Transactional(rollbackFor = Exception.class) public void materialSync(JSONObject whereJson) { JSONObject resultJson = wmsToErpService.materialSync(whereJson); List dataList = resultJson.getJSONArray("data").toJavaList(JSONObject.class); @@ -145,16 +156,76 @@ public class MdMeMaterialbaseServiceImpl extends ServiceImpl().lambda().nested(r -> { r.eq(MdMeMaterialbase::getMaterial_id, materialCode) .or() .eq(MdMeMaterialbase::getMaterial_code, materialCode); })); - if (ObjectUtil.isEmpty(one)) { + if (ObjectUtil.isEmpty(one) && flag) { throw new BadRequestException("物料信息为【" + materialCode + "】不存在!"); } return one; } + + @Override + public void importExcel(MultipartFile file) { + // 1. 校验文件 + if (file.isEmpty()) { + throw new IllegalArgumentException("上传文件不能为空"); + } + + try (InputStream inputStream = file.getInputStream(); + Workbook workbook = WorkbookFactory.create(inputStream)) { + + // 2. 获取第一个Sheet + Sheet sheet = workbook.getSheetAt(0); + + // 3. 从第二行开始遍历 (索引1) + List dataList = new ArrayList<>(); + for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) { + Row row = sheet.getRow(rowIndex); + if (row == null) continue; // 跳过空行 + Cell materialCodeCell = row.getCell(0); + MdMeMaterialbase byCode = materialbaseService.getByCode(String.valueOf(materialCodeCell), false); + if (ObjectUtil.isNotEmpty(byCode)) { + throw new BadRequestException("物料[" + materialCodeCell + "]已存在!"); + } + + // 4. 读取6个字段 + MdMeMaterialbase entity = new MdMeMaterialbase(); + entity.setMaterial_id(IdUtil.getStringId()); + entity.setMaterial_code(String.valueOf(materialCodeCell)); + entity.setMaterial_name(String.valueOf(row.getCell(1))); + entity.setMaterial_spec(String.valueOf(row.getCell(2))); + entity.setMaterial_model(String.valueOf(row.getCell(3))); + entity.setBase_unit_id(String.valueOf(row.getCell(4))); + entity.setAss_unit_id(String.valueOf(row.getCell(5))); + entity.setCreate_id(SecurityUtils.getCurrentUserId()); + entity.setCreate_name(SecurityUtils.getCurrentNickName()); + entity.setCreate_time(DateUtil.now()); + dataList.add(entity); + } + + // 6. 批量保存(根据实际持久层实现) + materialbaseService.saveBatch(dataList); + + } catch (IOException e) { + throw new RuntimeException("文件读取失败: " + e.getMessage()); + } catch (Exception e) { + throw new RuntimeException("导入失败: " + e.getMessage()); + } + + } + + @Override + public void downloadImportMaterialTemplate(HttpServletResponse response) { + try { + byte[] byteByTemplate = FileUtil.getByteByTemplate("excel/material_template.xlsx"); + FileUtil.download("物料导入模板.xlsx", byteByTemplate, response); + } catch (Exception e) { + log.error(">>> 下载导入模板失败:", e); + } + } } diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/impl/MdPbMeasureunitServiceImpl.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/impl/MdPbMeasureunitServiceImpl.java index b0b972f..92af76b 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/impl/MdPbMeasureunitServiceImpl.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/impl/MdPbMeasureunitServiceImpl.java @@ -8,17 +8,27 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.apache.poi.ss.usermodel.*; import org.nl.common.domain.query.PageQuery; import org.nl.common.exception.BadRequestException; +import org.nl.common.utils.FileUtil; import org.nl.common.utils.IdUtil; import org.nl.common.utils.SecurityUtils; import org.nl.wms.basedata_manage.enums.BaseDataEnum; import org.nl.wms.basedata_manage.service.IMdPbMeasureunitService; +import org.nl.wms.basedata_manage.service.dao.MdMeMaterialbase; import org.nl.wms.basedata_manage.service.dao.MdPbMeasureunit; import org.nl.wms.basedata_manage.service.dao.mapper.MdPbMeasureunitMapper; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Set; @@ -95,14 +105,72 @@ public class MdPbMeasureunitServiceImpl extends ServiceImpl().lambda() .eq(MdPbMeasureunit::getUnit_code, unit_code) ); - if (ObjectUtil.isEmpty(one)) { + if (ObjectUtil.isEmpty(one) && flag) { throw new BadRequestException("计量单位编码为【"+unit_code+"】不存在!"); } return one; } + + @Override + public void importExcel(MultipartFile file) { + // 1. 校验文件 + if (file.isEmpty()) { + throw new IllegalArgumentException("上传文件不能为空"); + } + + try (InputStream inputStream = file.getInputStream(); + Workbook workbook = WorkbookFactory.create(inputStream)) { + + // 2. 获取第一个Sheet + Sheet sheet = workbook.getSheetAt(0); + + // 3. 从第二行开始遍历 (索引1) + List dataList = new ArrayList<>(); + for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) { + Row row = sheet.getRow(rowIndex); + if (row == null) { + continue; // 跳过空行 + } + Cell cell1 = row.getCell(0); + MdPbMeasureunit byCode = this.getByCode(String.valueOf(cell1), false); + if (ObjectUtil.isNotEmpty(byCode)) { + throw new BadRequestException("物料[" + cell1 + "]已存在!"); + } + + // 4. 读取6个字段 + MdPbMeasureunit entity = new MdPbMeasureunit(); + entity.setMeasure_unit_id(IdUtil.getStringId()); + entity.setUnit_code(String.valueOf(cell1)); + entity.setUnit_name(String.valueOf(row.getCell(1))); + entity.setQty_precision(new BigDecimal(String.valueOf(row.getCell(2)))); + entity.setCreate_id(SecurityUtils.getCurrentUserId()); + entity.setCreate_name(SecurityUtils.getCurrentNickName()); + entity.setCreate_time(DateUtil.now()); + dataList.add(entity); + } + + // 6. 批量保存 + this.saveBatch(dataList); + + } catch (IOException e) { + throw new RuntimeException("文件读取失败: " + e.getMessage()); + } catch (Exception e) { + throw new RuntimeException("导入失败: " + e.getMessage()); + } + } + + @Override + public void downloadImportUnitTemplate(HttpServletResponse response) { + try { + byte[] byteByTemplate = FileUtil.getByteByTemplate("excel/unit_template.xlsx"); + FileUtil.download("单位导入模板.xlsx", byteByTemplate, response); + } catch (Exception e) { + log.error(">>> 下载导入模板失败:", e); + } + } } diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda_manage/ios_manage/service/impl/PdaIosInServiceImpl.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda_manage/ios_manage/service/impl/PdaIosInServiceImpl.java index 617381f..a017ba1 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda_manage/ios_manage/service/impl/PdaIosInServiceImpl.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda_manage/ios_manage/service/impl/PdaIosInServiceImpl.java @@ -188,7 +188,7 @@ public class PdaIosInServiceImpl implements PdaIosInService { // 数量 String qty = whereJson.getString("qty"); MdPbStoragevehicleinfo vehicleDao = iMdPbStoragevehicleinfoService.getByCode(whereJson.getString("vehicle_code")); - MdMeMaterialbase materDao = iMdMeMaterialbaseService.getByCode(materialId); + MdMeMaterialbase materDao = iMdMeMaterialbaseService.getByCode(materialId, true); MdPbMeasureunit unitDao = iMdPbMeasureunitService.getById(materDao.getBase_unit_id()); // 校验 if (ObjectUtil.isEmpty(vehicleDao) || ObjectUtil.isEmpty(materDao) || ObjectUtil.isEmpty(materDao)) { @@ -657,7 +657,7 @@ public class PdaIosInServiceImpl implements PdaIosInService { ArrayList tableData = new ArrayList<>(); HashMap dtl = new HashMap<>(); GroupPlate plateDao = plateDaoList.get(0); - MdMeMaterialbase materDao = iMdMeMaterialbaseService.getByCode(plateDao.getMaterial_id()); + MdMeMaterialbase materDao = iMdMeMaterialbaseService.getByCode(plateDao.getMaterial_id(), true); dtl.put("storagevehicle_code", plateDao.getStoragevehicle_code()); dtl.put("material_id", materDao.getMaterial_id()); dtl.put("material_code", materDao.getMaterial_code()); diff --git a/lms/nladmin-system/nlsso-server/src/main/resources/excel/material_template.xlsx b/lms/nladmin-system/nlsso-server/src/main/resources/excel/material_template.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4c8bf5da95d96019ceb3d3111433ea10f1705227 GIT binary patch literal 9585 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 literal 0 HcmV?d00001 diff --git a/lms/nladmin-system/nlsso-server/src/main/resources/excel/unit_template.xlsx b/lms/nladmin-system/nlsso-server/src/main/resources/excel/unit_template.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..2b2f6111cd84aa316b4d9140c513569ed0ca957e GIT binary patch literal 9459 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 Wa)=Md185ZuHViUU?%UIczy1f1>1E6S literal 0 HcmV?d00001 diff --git a/lms/nladmin-ui/src/views/wms/basedata/material/UploadDialog.vue b/lms/nladmin-ui/src/views/wms/basedata/material/UploadDialog.vue index f526491..06c3989 100644 --- a/lms/nladmin-ui/src/views/wms/basedata/material/UploadDialog.vue +++ b/lms/nladmin-ui/src/views/wms/basedata/material/UploadDialog.vue @@ -28,7 +28,10 @@ 将文件拖到此处,或 点击上传 -
只能上传Excel文件,且不超过10MB
+
+ 只能上传Excel文件,且不超过10MB + 下载模板 +
取 消 @@ -96,6 +99,35 @@ export default { uploadByJsqd(file) { this.file1 = file }, + downloadImportTemplate() { + crudMaterial.downloadImportMaterialTemplate().then(res => { + // 1. 创建Blob对象 + const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); + + // 2. 创建临时下载链接 + const downloadUrl = window.URL.createObjectURL(blob); + + // 3. 创建隐藏的标签 + const link = document.createElement('a'); + link.href = downloadUrl; + + // 设置下载文件名(根据后端返回或固定名称) + link.download = '物料导入模板.xlsx'; + + // 4. 添加到DOM并触发点击 + document.body.appendChild(link); + link.click(); + + // 5. 清理资源 + document.body.removeChild(link); + window.URL.revokeObjectURL(downloadUrl); + + }).catch(error => { + console.error('下载失败:', error); + // 这里可以添加错误提示,如ElementUI的Message + this.$message.error('模板下载失败,请重试'); + }) + }, submit() { if (this.beforeAvatarUpload(this.file1)) { this.fileList.name = this.file1.name diff --git a/lms/nladmin-ui/src/views/wms/basedata/material/material.js b/lms/nladmin-ui/src/views/wms/basedata/material/material.js index 37c8a46..c8e8bbb 100644 --- a/lms/nladmin-ui/src/views/wms/basedata/material/material.js +++ b/lms/nladmin-ui/src/views/wms/basedata/material/material.js @@ -62,4 +62,12 @@ export function excelImport(data) { data }) } -export default { add, edit, del, excelImport, getMaterOptType, isAlongMaterType, getProductSeries, materialSync } + +export function downloadImportMaterialTemplate(data) { + return request({ + url: 'api/Materia/downloadImportMaterialTemplate', + method: 'get', + responseType: 'blob' + }) +} +export default { add, edit, del, excelImport, getMaterOptType, isAlongMaterType, getProductSeries, materialSync, downloadImportMaterialTemplate } diff --git a/lms/nladmin-ui/src/views/wms/basedata/measure/UploadDialog.vue b/lms/nladmin-ui/src/views/wms/basedata/measure/UploadDialog.vue new file mode 100644 index 0000000..f9e921d --- /dev/null +++ b/lms/nladmin-ui/src/views/wms/basedata/measure/UploadDialog.vue @@ -0,0 +1,157 @@ + + + + diff --git a/lms/nladmin-ui/src/views/wms/basedata/measure/index.vue b/lms/nladmin-ui/src/views/wms/basedata/measure/index.vue index 8f88c82..6c06d2d 100644 --- a/lms/nladmin-ui/src/views/wms/basedata/measure/index.vue +++ b/lms/nladmin-ui/src/views/wms/basedata/measure/index.vue @@ -13,7 +13,18 @@ /> - + + + 导入 + + @@ -70,6 +81,7 @@ + @@ -80,11 +92,12 @@ import rrOperation from '@crud/RR.operation' import crudOperation from '@crud/CRUD.operation' import udOperation from '@crud/UD.operation' import pagination from '@crud/Pagination' +import UploadDialog from './UploadDialog.vue' const defaultForm = { measure_unit_id: null, unit_code: null, unit_name: null, qty_precision: null, is_used: '1', create_id: null, create_name: null, create_time: null, update_optid: null, update_optname: null, update_time: null, is_delete: null, ext_id: null } export default { dicts: ['is_used'], name: 'MdPbMeasureunit', - components: { pagination, crudOperation, rrOperation, udOperation }, + components: { UploadDialog, pagination, crudOperation, rrOperation, udOperation }, mixins: [presenter(), header(), form(defaultForm), crud()], cruds() { return CRUD({ title: '计量单位', @@ -101,6 +114,7 @@ export default { return { permission: { }, + uploadShow: false, rules: { measure_unit_id: [ { required: true, message: '不能为空', trigger: 'blur' } diff --git a/lms/nladmin-ui/src/views/wms/basedata/measure/mdPbMeasureunit.js b/lms/nladmin-ui/src/views/wms/basedata/measure/mdPbMeasureunit.js index ae700b9..a3ac91b 100644 --- a/lms/nladmin-ui/src/views/wms/basedata/measure/mdPbMeasureunit.js +++ b/lms/nladmin-ui/src/views/wms/basedata/measure/mdPbMeasureunit.js @@ -32,4 +32,20 @@ export function getUnit(params) { }) } -export default { add, edit, del, getUnit } +export function excelImport(data) { + return request({ + url: 'api/mdPbMeasureunit/importExcel', + method: 'post', + data + }) +} + +export function downloadImportUnitTemplate(data) { + return request({ + url: 'api/mdPbMeasureunit/downloadImportUnitTemplate', + method: 'get', + responseType: 'blob' + }) +} + +export default { add, edit, del, getUnit, excelImport, downloadImportUnitTemplate }