diff --git a/DOAN.Admin.WebApi/Controllers/MES/Material/productionMaterial/MmRecordOutboundController.cs b/DOAN.Admin.WebApi/Controllers/MES/Material/productionMaterial/MmRecordOutboundController.cs
index 685812d..cec69b1 100644
--- a/DOAN.Admin.WebApi/Controllers/MES/Material/productionMaterial/MmRecordOutboundController.cs
+++ b/DOAN.Admin.WebApi/Controllers/MES/Material/productionMaterial/MmRecordOutboundController.cs
@@ -1,8 +1,10 @@
-using Microsoft.AspNetCore.Mvc;
-using DOAN.Model.BZFM.Dto;
-using DOAN.Model.BZFM;
-using DOAN.Service.BZFM.IBZFMService;
using DOAN.Admin.WebApi.Filters;
+using DOAN.Model;
+using DOAN.Model.BZFM;
+using DOAN.Model.BZFM.Dto;
+using DOAN.Service.BZFM;
+using DOAN.Service.BZFM.IBZFMService;
+using Microsoft.AspNetCore.Mvc;
//创建时间:2025-12-25
namespace DOAN.Admin.WebApi.Controllers.BZFM
@@ -98,5 +100,56 @@ namespace DOAN.Admin.WebApi.Controllers.BZFM
return ToResponse(_MmRecordOutboundService.Delete(idArr));
}
+ ///
+ /// 导入
+ ///
+ /// 使用IFromFile必须使用name属性否则获取不到文件
+ ///
+ [HttpPost("importData")]
+ [Log(Title = "出库记录导入", BusinessType = BusinessType.IMPORT, IsSaveRequestData = false, IsSaveResponseData = true)]
+ [ActionPermissionFilter(Permission = "mmrecordoutbound:import")]
+ public IActionResult ImportData([FromForm(Name = "file")] IFormFile formFile)
+ {
+ if (formFile == null)
+ {
+ return SUCCESS(null);
+ }
+ ImportResultDto response = _MmRecordOutboundService.ImportRecordOutbound(formFile, HttpContext.GetName());
+
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 下载出库记录导入模板
+ ///
+ ///
+ [HttpGet("importTemplate")]
+ [Log(Title = "出库记录模板", BusinessType = BusinessType.EXPORT)]
+ [AllowAnonymous]
+ public IActionResult ImportTemplateExcel()
+ {
+ // create an empty sample list of export DTO to generate header row
+ var sample = new List();
+ var result = DownloadImportTemplate(sample, "recordoutbound");
+ return ExportExcel(result.Item2, result.Item1);
+ }
+
+ ///
+ /// 出库记录导出
+ ///
+ ///
+ ///
+ [HttpGet("export")]
+ [Log(Title = "出库记录导出", BusinessType = BusinessType.EXPORT)]
+ [ActionPermissionFilter(Permission = "mmrecordoutbound:export")]
+ public IActionResult MaterialExport([FromQuery] MmRecordOutboundQueryDto recordoutbound)
+ {
+ var list = _MmRecordOutboundService.SelectRecordoutboundList(recordoutbound, new PagerInfo(1, 10000));
+
+ var data = (list?.Result ?? new List());
+
+ var result = ExportExcelMini(data, "recordoutbound", "出库记录");
+ return ExportExcel(result.Item2, result.Item1);
+ }
}
}
\ No newline at end of file
diff --git a/DOAN.Model/MES/Material/Dto/MmRecordInboundDto.cs b/DOAN.Model/MES/Material/Dto/MmRecordInboundDto.cs
index 1e93a71..04eb49f 100644
--- a/DOAN.Model/MES/Material/Dto/MmRecordInboundDto.cs
+++ b/DOAN.Model/MES/Material/Dto/MmRecordInboundDto.cs
@@ -121,7 +121,7 @@ namespace DOAN.Model.BZFM.Dto
public int Id { get; set; }
[ExcelColumn(Name = "入库单号")]
- [SugarColumn(ColumnName = "Inbound_no")]
+ [SugarColumn(ColumnName = "inbound_no")]
public string InboundNo { get; set; }
[ExcelColumn(Name = "物料编码")]
diff --git a/DOAN.Model/MES/Material/Dto/MmRecordOutboundDto.cs b/DOAN.Model/MES/Material/Dto/MmRecordOutboundDto.cs
index 4a198af..c77d57e 100644
--- a/DOAN.Model/MES/Material/Dto/MmRecordOutboundDto.cs
+++ b/DOAN.Model/MES/Material/Dto/MmRecordOutboundDto.cs
@@ -107,4 +107,69 @@ namespace DOAN.Model.BZFM.Dto
// 1-蓝单正向 2-红单逆向
public int ReceiptType { get; set; } = 1;
}
+
+ //
+ /// 出库记录导入导出
+ ///
+ [SugarTable("mm_recordoutbound", "出库记录")]
+ public class MmRecordOutboundExcelDto
+ {
+ [ExcelColumn(Name = "id")]
+ [SugarColumn(IsIdentity = true, IsPrimaryKey = true)]
+ public int Id { get; set; }
+
+ [ExcelColumn(Name = "出库单号")]
+ [SugarColumn(ColumnName = "outbound_no")]
+ public string OutboundNo { get; set; }
+
+ [ExcelColumn(Name = "物料编码")]
+ [SugarColumn(ColumnName = "material_code")]
+ public string MaterialCode { get; set; }
+
+ [ExcelColumn(Name = "物料名称")]
+ [SugarColumn(ColumnName = "material_name")]
+ public string MaterialName { get; set; }
+
+ [ExcelColumn(Name = "批次号")]
+ [SugarColumn(ColumnName = "batch_no")]
+ public string BatchNo { get; set; }
+
+ [ExcelColumn(Name = "出库数量")]
+ [SugarColumn(ColumnName = "quantity")]
+ public decimal Quantity { get; set; }
+
+ [ExcelColumn(Name = "出库类型")]
+ [SugarColumn(ColumnName = "transaction_Type")]
+ public string TransactionType { get; set; }
+
+ [ExcelColumn(Name = "操作员")]
+ [SugarColumn(ColumnName = "operator")]
+ public string Operator { get; set; }
+
+ [ExcelColumn(Name = "仓库编码")]
+ [SugarColumn(ColumnName = "warehouse_code")]
+ public string WarehouseCode { get; set; }
+
+ [ExcelColumn(Name = "仓库名称")]
+ [SugarColumn(ColumnName = "warehouse_name")]
+ public string WarehouseName { get; set; }
+
+ [ExcelColumn(Name = "库位编码")]
+ [SugarColumn(ColumnName = "location_code")]
+ public string LocationCode { get; set; }
+
+ [ExcelColumn(Name = "库位名称")]
+ [SugarColumn(ColumnName = "location_name")]
+ public string LocationName { get; set; }
+
+ [ExcelColumn(Name = "关联订单号")]
+ [SugarColumn(ColumnName = "order_no")]
+ public string OrderNo { get; set; }
+
+ public string SupplierName { get; set; }
+
+ [ExcelColumn(Name = "创建时间")]
+ [SugarColumn(ColumnName = "created_time")]
+ public DateTime? CreatedTime { get; set; }
+ }
}
\ No newline at end of file
diff --git a/DOAN.Service/MES/Material/IService/IMmRecordOutboundService.cs b/DOAN.Service/MES/Material/IService/IMmRecordOutboundService.cs
index 75c8623..d6ff6d9 100644
--- a/DOAN.Service/MES/Material/IService/IMmRecordOutboundService.cs
+++ b/DOAN.Service/MES/Material/IService/IMmRecordOutboundService.cs
@@ -1,5 +1,6 @@
-using DOAN.Model.BZFM.Dto;
using DOAN.Model.BZFM;
+using DOAN.Model.BZFM.Dto;
+using Microsoft.AspNetCore.Http;
namespace DOAN.Service.BZFM.IBZFMService
{
@@ -16,6 +17,13 @@ namespace DOAN.Service.BZFM.IBZFMService
MmRecordOutbound AddMmRecordOutbound(MmRecordOutbound parm);
int UpdateMmRecordOutbound(MmRecordOutbound parm);
+ //
+ /// 导入
+ ///
+ ///
+ ///
+ ImportResultDto ImportRecordOutbound(IFormFile formFile, string username);
+ public PagedInfo SelectRecordoutboundList(MmRecordOutboundQueryDto recordoutbound, PagerInfo pager);
}
}
diff --git a/DOAN.Service/MES/Material/MmRecordOutboundService.cs b/DOAN.Service/MES/Material/MmRecordOutboundService.cs
index 68d0b91..9eca396 100644
--- a/DOAN.Service/MES/Material/MmRecordOutboundService.cs
+++ b/DOAN.Service/MES/Material/MmRecordOutboundService.cs
@@ -5,6 +5,9 @@ using DOAN.Service.BZFM.IBZFMService;
using Infrastructure.Attribute;
using Infrastructure.Converter;
using Infrastructure.Extensions;
+using Microsoft.AspNetCore.Http;
+using NPOI.SS.UserModel;
+using NPOI.XSSF.UserModel;
namespace DOAN.Service.BZFM
{
@@ -96,5 +99,262 @@ namespace DOAN.Service.BZFM
return predicate;
}
+
+ ///
+ /// 导入数据
+ ///
+ ///
+ ///
+ public ImportResultDto ImportRecordOutbound(IFormFile formFile, string username)
+ {
+ string message = "导出成功";
+ List recordoutboundList = new();
+ using (var stream = formFile.OpenReadStream())
+ {
+ try
+ {
+ IWorkbook workbook = new XSSFWorkbook(stream);
+ ISheet sheet = workbook.GetSheetAt(0);
+
+ #region 读取excel
+
+ // 遍历每一行
+ for (int row = 1; row <= sheet.LastRowNum; row++)
+ {
+ IRow currentRow = sheet.GetRow(row);
+ if (currentRow != null) // 确保行不为空
+ {
+ MmRecordOutboundExcelDto recordoutbound = new MmRecordOutboundExcelDto();
+
+ //00 ID
+ NPOI.SS.UserModel.ICell currentCell_00 = currentRow.GetCell(0);
+ recordoutbound.Id = (int)currentCell_00?.NumericCellValue;
+
+ //01 创建时间
+ NPOI.SS.UserModel.ICell currentCell_01 = currentRow.GetCell(1);
+ recordoutbound.CreatedTime = currentCell_01?.DateCellValue ?? DateTime.Now;
+
+ //02 出库单号
+ NPOI.SS.UserModel.ICell currentCell_02 = currentRow.GetCell(2);
+ recordoutbound.OutboundNo = currentCell_02?.ToString();
+ if (
+ currentCell_02 == null
+ || string.IsNullOrEmpty(recordoutbound.OutboundNo)
+ )
+ {
+ message = $"出库单号不可为空,第{row + 1}行";
+ break;
+ }
+
+ //03 物料编码
+ NPOI.SS.UserModel.ICell currentCell_03 = currentRow.GetCell(3);
+ recordoutbound.MaterialCode = currentCell_03?.ToString();
+ if (
+ currentCell_03 == null
+ || string.IsNullOrEmpty(recordoutbound.MaterialCode)
+ )
+ {
+ message = $"物料编码不可为空,第{row + 1}行";
+ break;
+ }
+
+ //04 物料名称
+ NPOI.SS.UserModel.ICell currentCell_04 = currentRow.GetCell(4);
+ recordoutbound.MaterialName = currentCell_04?.ToString();
+ if (
+ currentCell_04 == null
+ || string.IsNullOrEmpty(recordoutbound.MaterialName)
+ )
+ {
+ message = $"物料名称不可为空,第{row + 1}行";
+ break;
+ }
+
+ //05 仓库编码
+ NPOI.SS.UserModel.ICell currentCell_05 = currentRow.GetCell(5);
+ recordoutbound.WarehouseCode = currentCell_05?.ToString();
+ if (
+ currentCell_05 == null
+ || string.IsNullOrEmpty(recordoutbound.WarehouseCode)
+ )
+ {
+ message = $"仓库编码不可为空,第{row + 1}行";
+ break;
+ }
+
+ //06 仓库名称
+ NPOI.SS.UserModel.ICell currentCell_06 = currentRow.GetCell(6);
+ recordoutbound.WarehouseName = currentCell_06?.ToString();
+ if (
+ currentCell_06 == null
+ || string.IsNullOrEmpty(recordoutbound.WarehouseName)
+ )
+ {
+ message = $"仓库名称不可为空,第{row + 1}行";
+ break;
+ }
+
+ //07 库位编码
+ NPOI.SS.UserModel.ICell currentCell_07 = currentRow.GetCell(7);
+ recordoutbound.LocationCode = currentCell_05?.ToString();
+ if (
+ currentCell_07 == null
+ || string.IsNullOrEmpty(recordoutbound.LocationCode)
+ )
+ {
+ message = $"库位编码不可为空,第{row + 1}行";
+ break;
+ }
+
+ //08 库位名称
+ NPOI.SS.UserModel.ICell currentCell_08 = currentRow.GetCell(8);
+ recordoutbound.LocationName = currentCell_06?.ToString();
+ if (
+ currentCell_08 == null
+ || string.IsNullOrEmpty(recordoutbound.LocationName)
+ )
+ {
+ message = $"库位名称不可为空,第{row + 1}行";
+ break;
+ }
+
+ //09 出库数量
+ NPOI.SS.UserModel.ICell currentCell_09 = currentRow.GetCell(9);
+ string QuantityStr = currentCell_09?.ToString();
+
+ if (currentCell_09 == null || string.IsNullOrWhiteSpace(QuantityStr))
+ {
+ message = $"出库数量不可为空,第{row + 1}行";
+ break;
+ }
+
+ // 尝试转换为decimal
+ if (!decimal.TryParse(QuantityStr, out decimal Quantity))
+ {
+ message = $"出库数量格式错误(必须是数字),第{row + 1}行";
+ break;
+ }
+
+ //验证数值范围(可根据业务需求调整)
+ if (Quantity < 0)
+ {
+ message = $"出库数量不能为负数,第{row + 1}行";
+ break;
+ }
+ recordoutbound.Quantity = Quantity;
+
+ //10 出库类型
+ NPOI.SS.UserModel.ICell currentCell_10 = currentRow.GetCell(10);
+ recordoutbound.TransactionType = currentCell_08?.ToString();
+ if (
+ currentCell_10 == null
+ || string.IsNullOrEmpty(recordoutbound.TransactionType)
+ )
+ {
+ message = $"入库类型不可为空,第{row + 1}行";
+ break;
+ }
+
+ //11关联订单号
+ NPOI.SS.UserModel.ICell currentCell_11 = currentRow.GetCell(11);
+ recordoutbound.OrderNo = currentCell_11?.ToString() ?? string.Empty;
+
+ //12 操作员
+ NPOI.SS.UserModel.ICell currentCell_12 = currentRow.GetCell(12);
+ recordoutbound.Operator = currentCell_12?.ToString() ?? string.Empty;
+
+ recordoutboundList.Add(recordoutbound);
+ }
+ }
+
+ #endregion
+ }
+ catch (Exception ex)
+ {
+ return null;
+ }
+
+
+ }
+ // TODO 3.调用SplitInsert方法实现导入操作,注意主键列的配置(建议优化为,ID相同则修改,不同则新增)
+
+ var x = Context
+ .Storageable(recordoutboundList)
+ //.SplitInsert(it => !it.Any())
+ //.WhereColumns(it => it.Id) //如果不是主键可以这样实现(多字段it=>new{it.x1,it.x2})
+ .ToStorage();
+ var result = x.AsInsertable.ExecuteCommand();
+ var result2 = x.AsUpdateable.IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommand(); //插入可插入部分;
+
+ var importResult = new ImportResultDto
+ {
+ Message = message,
+ Inserted = x.InsertList.Count,
+ Updated = x.UpdateList.Count,
+ ErrorCount = x.ErrorList.Count,
+ IgnoredCount = x.IgnoreList.Count,
+ Deleted = x.DeleteList.Count,
+ Total = x.TotalList.Count,
+ };
+ //输出统计
+ Console.WriteLine(importResult);
+ // 4.收集错误与忽略信息,返回导入结果ImportResultDto 提示,需要修改IServer相关返回格式
+ foreach (var item in x.ErrorList)
+ {
+ importResult.Errors.Add(
+ new ImportErrorDto
+ {
+ MaterialCode = item.Item.MaterialCode,
+ Message = item.StorageMessage,
+ }
+ );
+ }
+ foreach (var item in x.IgnoreList)
+ {
+ importResult.Ignored.Add(
+ new ImportErrorDto
+ {
+ MaterialCode = item.Item.MaterialCode,
+ Message = item.StorageMessage,
+ }
+ );
+ }
+
+ return importResult;
+ }
+
+ ///
+ /// 导出入库记录列表
+ ///
+ ///
+ public PagedInfo SelectRecordoutboundList(
+ MmRecordOutboundQueryDto recordoutbound,
+ PagerInfo pager
+ )
+ {
+ // Use the same predicate builder as GetList to support consistent filtering
+ var predicate = QueryExp(recordoutbound);
+
+ var query = Queryable()
+ .Where(predicate.ToExpression())
+ .Select(it => new MmRecordOutboundExcelDto
+ {
+ Id = it.Id,
+ CreatedTime = it.CreatedTime,
+ OutboundNo = it.OutboundNo,
+ MaterialCode = it.MaterialCode,
+ MaterialName = it.MaterialName,
+ WarehouseCode = it.WarehouseCode,
+ WarehouseName = it.WarehouseName,
+ LocationCode = it.LocationCode,
+ LocationName = it.LocationName,
+ Quantity = it.Quantity,
+ TransactionType = it.TransactionType,
+ OrderNo = it.OrderNo,
+ Operator = it.Operator,
+ });
+
+ return query.ToPage(pager);
+ }
}
}
\ No newline at end of file