fix(工单排序): 修复工单上下移动时的排序问题
添加空值检查和使用事务确保排序操作的原子性,同时优化查询逻辑以提高可靠性
This commit is contained in:
@@ -11,6 +11,7 @@ using DOAN.Service.MES.product.IService;
|
||||
using Infrastructure;
|
||||
using Infrastructure.Attribute;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using NLog;
|
||||
using NPOI.SS.UserModel;
|
||||
using NPOI.XSSF.UserModel;
|
||||
using SqlSugar;
|
||||
@@ -20,9 +21,380 @@ namespace DOAN.Service.MES.product
|
||||
/// <summary>
|
||||
/// 工单导入服务
|
||||
/// </summary>
|
||||
[AppService(ServiceType = typeof(IProWorkorderImportService), ServiceLifetime = LifeTime.Transient)]
|
||||
[AppService(
|
||||
ServiceType = typeof(IProWorkorderImportService),
|
||||
ServiceLifetime = LifeTime.Transient
|
||||
)]
|
||||
public class ProWorkorderImportService : BaseService<ProWorkorder>, IProWorkorderImportService
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志记录器
|
||||
/// </summary>
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
/// <summary>
|
||||
/// 生成唯一的工单编号
|
||||
/// </summary>
|
||||
/// <param name="workorder">工单对象</param>
|
||||
/// <param name="dateValue">日期值</param>
|
||||
/// <param name="currentIndex">当前编号索引</param>
|
||||
/// <param name="nickCode">昵称代码</param>
|
||||
/// <param name="maxAttempts">最大尝试次数</param>
|
||||
/// <returns>生成的工单编号和更新后的索引</returns>
|
||||
private Tuple<string, int> GenerateUniqueWorkorderNo(ProWorkorder workorder, DateTime dateValue, int currentIndex, string nickCode, int maxAttempts = 100)
|
||||
{
|
||||
string workorderNo;
|
||||
bool isUnique;
|
||||
int attempts = 0;
|
||||
|
||||
do
|
||||
{
|
||||
attempts++;
|
||||
if (attempts > maxAttempts)
|
||||
{
|
||||
throw new Exception(
|
||||
$"生成工单编号失败,超过最大尝试次数({maxAttempts}),productionCode: {workorder.productionCode}"
|
||||
);
|
||||
}
|
||||
|
||||
workorderNo =
|
||||
dateValue.ToString("yyyyMMdd")
|
||||
+ "_"
|
||||
+ workorder.GroupCode
|
||||
+ workorder.RouteCode
|
||||
+ "_"
|
||||
+ nickCode
|
||||
+ "_"
|
||||
+ currentIndex.ToString("000");
|
||||
// 检查编号是否已存在
|
||||
isUnique = !Context
|
||||
.Queryable<ProWorkorder>()
|
||||
.Where(it => it.Workorder == workorderNo)
|
||||
.Any();
|
||||
if (!isUnique)
|
||||
{
|
||||
currentIndex++;
|
||||
}
|
||||
} while (!isUnique);
|
||||
|
||||
return new Tuple<string, int>(workorderNo, currentIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定productionCode当天的最大工单编号索引
|
||||
/// </summary>
|
||||
/// <param name="productionCode">产品代码</param>
|
||||
/// <param name="dateValue">日期值</param>
|
||||
/// <returns>最大编号索引</returns>
|
||||
private int GetMaxWorkorderIndex(string productionCode, DateTime dateValue)
|
||||
{
|
||||
var maxIndex = Context
|
||||
.Queryable<ProWorkorder>()
|
||||
.Where(it => it.WorkorderDate == dateValue.Date)
|
||||
.Where(it => it.productionCode == productionCode)
|
||||
.Select(it => it.Workorder)
|
||||
.ToList()
|
||||
.Where(w => w.StartsWith(dateValue.ToString("yyyyMMdd")))
|
||||
.Select(w =>
|
||||
{
|
||||
var parts = w.Split('_');
|
||||
if (parts.Length >= 4 && int.TryParse(parts[3], out int index))
|
||||
return index;
|
||||
return 0;
|
||||
})
|
||||
.Max();
|
||||
|
||||
return maxIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从Excel文件读取工单数据
|
||||
/// </summary>
|
||||
/// <param name="formFile">Excel文件</param>
|
||||
/// <param name="username">用户名</param>
|
||||
/// <param name="dateValue">返回的日期值</param>
|
||||
/// <returns>工单列表</returns>
|
||||
private List<ProWorkorder> ReadWorkordersFromExcel(IFormFile formFile, string username, out DateTime dateValue)
|
||||
{
|
||||
List<ProWorkorder> workorderList = new List<ProWorkorder>();
|
||||
dateValue = DateTime.Now;
|
||||
|
||||
using (var stream = formFile.OpenReadStream())
|
||||
{
|
||||
IWorkbook workbook = new XSSFWorkbook(stream);
|
||||
ISheet sheet = workbook.GetSheetAt(0);
|
||||
|
||||
// 处理第2行 获取日期
|
||||
IRow secondRow = sheet.GetRow(1);
|
||||
ICell cell = secondRow.GetCell(0);
|
||||
// 安全获取日期值
|
||||
if (cell != null && cell.DateCellValue.HasValue)
|
||||
{
|
||||
dateValue = cell.DateCellValue.Value;
|
||||
}
|
||||
|
||||
// 遍历每一行
|
||||
for (int row = 4; row <= sheet.LastRowNum; row++)
|
||||
{
|
||||
IRow currentRow = sheet.GetRow(row);
|
||||
if (currentRow != null) // 确保行不为空
|
||||
{
|
||||
ProWorkorder workorder = new ProWorkorder();
|
||||
|
||||
//00 主体品名
|
||||
ICell currentCell_01 = currentRow.GetCell(0);
|
||||
workorder.productionName = currentCell_01?.ToString();
|
||||
if (
|
||||
currentCell_01 == null
|
||||
|| string.IsNullOrEmpty(workorder.productionName)
|
||||
)
|
||||
{
|
||||
throw new Exception($"{row + 1}行【主体品名】不可为空");
|
||||
}
|
||||
|
||||
//01 成品型号
|
||||
ICell currentCell_02 = currentRow.GetCell(1);
|
||||
workorder.productionCode = currentCell_02?.ToString();
|
||||
if (
|
||||
currentCell_02 == null
|
||||
|| string.IsNullOrEmpty(workorder.productionCode)
|
||||
)
|
||||
{
|
||||
throw new Exception($"{row + 1}行【主体型号】不可为空");
|
||||
}
|
||||
|
||||
//02 单位
|
||||
ICell currentCell_04 = currentRow.GetCell(2);
|
||||
workorder.Unit = currentCell_04?.ToString() ?? string.Empty;
|
||||
|
||||
//3 计划数量
|
||||
ICell currentCell_07 = currentRow.GetCell(3);
|
||||
if (currentCell_07 != null)
|
||||
{
|
||||
if (currentCell_07.CellType == CellType.Numeric)
|
||||
{
|
||||
workorder.PlanNum = (int)currentCell_07.NumericCellValue;
|
||||
}
|
||||
else if (currentCell_07.CellType == CellType.String && int.TryParse(currentCell_07.StringCellValue, out int planNum))
|
||||
{
|
||||
workorder.PlanNum = planNum;
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.PlanNum = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.PlanNum = 0;
|
||||
}
|
||||
if (workorder.PlanNum < 0)
|
||||
{
|
||||
workorder.PlanNum = 0;
|
||||
}
|
||||
|
||||
//4 原材料名称
|
||||
ICell currentCell_11 = currentRow.GetCell(4);
|
||||
workorder.MaterialName = currentCell_11?.ToString();
|
||||
if (
|
||||
currentCell_11 == null
|
||||
|| string.IsNullOrEmpty(workorder.MaterialName)
|
||||
)
|
||||
{
|
||||
throw new Exception($"{row + 1}行【材料型号】不可为空");
|
||||
}
|
||||
|
||||
//5 原材料编号
|
||||
ICell currentCell_12 = currentRow.GetCell(5);
|
||||
workorder.MaterialCode = currentCell_12?.ToString();
|
||||
if (
|
||||
currentCell_12 == null
|
||||
|| string.IsNullOrEmpty(workorder.MaterialCode)
|
||||
)
|
||||
{
|
||||
throw new Exception($"{row + 1}行【材料编码】不可为空");
|
||||
}
|
||||
|
||||
//6 原材料材质
|
||||
ICell currentCell_13 = currentRow.GetCell(6);
|
||||
workorder.MaterialtextureCode = currentCell_13?.ToString() ?? string.Empty;
|
||||
|
||||
//7 炉号
|
||||
ICell currentCell_14 = currentRow.GetCell(7);
|
||||
workorder.StoveCode = currentCell_14?.ToString() ?? string.Empty;
|
||||
|
||||
//8 图号
|
||||
ICell currentCell_15 = currentRow.GetCell(8);
|
||||
workorder.DrawingCode = currentCell_15?.ToString() ?? string.Empty;
|
||||
|
||||
//9 版本
|
||||
ICell currentCell_16 = currentRow.GetCell(9);
|
||||
workorder.Version = currentCell_16?.ToString() ?? string.Empty;
|
||||
|
||||
//10 指导日期
|
||||
ICell cell17 = currentRow.GetCell(10);
|
||||
// 安全获取日期值
|
||||
if (cell17 != null && cell17.DateCellValue.HasValue)
|
||||
{
|
||||
workorder.InstructionDate = cell17.DateCellValue.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.InstructionDate = dateValue;
|
||||
}
|
||||
|
||||
// 11 车间code
|
||||
ICell currentCell_18 = currentRow.GetCell(11);
|
||||
if (currentCell_18 == null)
|
||||
{
|
||||
workorder.WorkshopCode = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentCell_18.CellType == CellType.Numeric)
|
||||
{
|
||||
workorder.WorkshopCode = currentCell_18.NumericCellValue.ToString();
|
||||
}
|
||||
else if (currentCell_18.CellType == CellType.String)
|
||||
{
|
||||
workorder.WorkshopCode = currentCell_18.StringCellValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.WorkshopCode = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
//12 组号code
|
||||
ICell currentCell_19 = currentRow.GetCell(12);
|
||||
if (currentCell_19 == null)
|
||||
{
|
||||
workorder.GroupCode = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentCell_19.CellType == CellType.Numeric)
|
||||
{
|
||||
workorder.GroupCode = currentCell_19.NumericCellValue.ToString();
|
||||
}
|
||||
else if (currentCell_19.CellType == CellType.String)
|
||||
{
|
||||
workorder.GroupCode = currentCell_19.StringCellValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.GroupCode = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
//13 班号code
|
||||
ICell currentCell_20 = currentRow.GetCell(13);
|
||||
if (currentCell_20 == null)
|
||||
{
|
||||
workorder.RouteCode = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentCell_20.CellType == CellType.Numeric)
|
||||
{
|
||||
workorder.RouteCode = currentCell_20.NumericCellValue.ToString();
|
||||
}
|
||||
else if (currentCell_20.CellType == CellType.String)
|
||||
{
|
||||
workorder.RouteCode = currentCell_20.StringCellValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.RouteCode = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
//14 优先级
|
||||
ICell currentCell_21 = currentRow.GetCell(14);
|
||||
if (currentCell_21 == null)
|
||||
{
|
||||
workorder.Priority = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
string priorityStr = string.Empty;
|
||||
if (currentCell_21.CellType == CellType.String)
|
||||
{
|
||||
priorityStr = currentCell_21.StringCellValue;
|
||||
}
|
||||
else if (currentCell_21.CellType == CellType.Numeric)
|
||||
{
|
||||
priorityStr = currentCell_21.NumericCellValue.ToString();
|
||||
}
|
||||
|
||||
if (priorityStr == "优先")
|
||||
{
|
||||
workorder.Priority = 3;
|
||||
}
|
||||
else if (priorityStr == "插单")
|
||||
{
|
||||
workorder.Priority = 2;
|
||||
}
|
||||
else if (priorityStr == "正常" || string.IsNullOrEmpty(priorityStr))
|
||||
{
|
||||
workorder.Priority = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.Priority = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//15 节拍
|
||||
ICell currentCell_22 = currentRow.GetCell(15);
|
||||
if (currentCell_22 != null)
|
||||
{
|
||||
if (currentCell_22.CellType == CellType.Numeric)
|
||||
{
|
||||
workorder.Beat = (int)currentCell_22.NumericCellValue;
|
||||
}
|
||||
else if (currentCell_22.CellType == CellType.String && int.TryParse(currentCell_22.StringCellValue, out int beat))
|
||||
{
|
||||
workorder.Beat = beat;
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.Beat = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.Beat = 0;
|
||||
}
|
||||
|
||||
//16 进料单号(外购)
|
||||
ICell currentCell_010 = currentRow.GetCell(16);
|
||||
workorder.FeedOrder = currentCell_010?.StringCellValue ?? string.Empty;
|
||||
|
||||
//17 客户单号(出货)
|
||||
ICell currentCell_011 = currentRow.GetCell(17);
|
||||
workorder.CustomerOrder = currentCell_011?.StringCellValue ?? string.Empty;
|
||||
|
||||
//18 备注
|
||||
ICell currentCell_012 = currentRow.GetCell(18);
|
||||
workorder.Remark01 = currentCell_012?.StringCellValue ?? string.Empty;
|
||||
|
||||
workorder.Id = SnowFlakeSingle.Instance.NextId().ToString();
|
||||
workorder.CreatedBy = username;
|
||||
workorder.CreatedTime = DateTime.Now;
|
||||
workorder.WorkorderDate = dateValue;
|
||||
workorder.DefectNum = 0;
|
||||
workorder.ShipmentNum = 0;
|
||||
workorder.Status = 1;
|
||||
|
||||
workorderList.Add(workorder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return workorderList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导入工单 必须整删除 整改
|
||||
/// </summary>
|
||||
@@ -32,225 +404,84 @@ namespace DOAN.Service.MES.product
|
||||
public int ImportData(IFormFile formFile, string username)
|
||||
{
|
||||
int result = 0;
|
||||
List<ProWorkorder> workorderList = new List<ProWorkorder>();
|
||||
DateTime dateValue = DateTime.MinValue;
|
||||
List<ProWorkorder> workorderList;
|
||||
DateTime dateValue;
|
||||
// XXX 改为从物料清单获取信息
|
||||
List<MmMaterial> mmMaterials = Context
|
||||
.Queryable<MmMaterial>()
|
||||
.Where(it => it.Status == "启用")
|
||||
.ToList();
|
||||
|
||||
using (var stream = formFile.OpenReadStream())
|
||||
try
|
||||
{
|
||||
try
|
||||
Logger.Info($"开始导入工单数据,用户名: {username}");
|
||||
workorderList = ReadWorkordersFromExcel(formFile, username, out dateValue);
|
||||
Logger.Info($"读取到 {workorderList.Count} 条工单数据");
|
||||
|
||||
// 按productionCode分组并顺序编号
|
||||
// 先按productionCode分组,确保同一产品的工单连续排序
|
||||
var productionCodeGroups = workorderList
|
||||
.GroupBy(w => w.productionCode)
|
||||
.ToList();
|
||||
|
||||
// 获取所有工单的最大sort值,用于后续排序
|
||||
var maxSort = Context
|
||||
.Queryable<ProWorkorder>()
|
||||
.Where(it => it.WorkorderDate == dateValue.Date)
|
||||
//.Select(it => it.Sort)
|
||||
.Max(it => it.Sort).Value;
|
||||
|
||||
// 从maxSort + 10开始,确保sort值按10、20、30...递增
|
||||
int currentSort = (maxSort / 10) * 10 + 10;
|
||||
|
||||
foreach (var group in productionCodeGroups)
|
||||
{
|
||||
IWorkbook workbook = new XSSFWorkbook(stream);
|
||||
ISheet sheet = workbook.GetSheetAt(0);
|
||||
Logger.Info($"处理产品代码: {group.Key},共 {group.Count()} 条工单");
|
||||
// 获取当前productionCode当天已有的最大编号
|
||||
int maxIndex = GetMaxWorkorderIndex(group.Key, dateValue);
|
||||
// 从最大编号+1开始顺序编号
|
||||
int currentIndex = maxIndex + 1;
|
||||
Logger.Info($"产品代码: {group.Key},当前最大编号索引: {maxIndex},开始编号: {currentIndex}");
|
||||
|
||||
// 处理第2行 获取日期
|
||||
IRow secondRow = sheet.GetRow(1);
|
||||
ICell cell = secondRow.GetCell(0);
|
||||
// 将单元格的数字值转换为DateTime
|
||||
dateValue = cell.DateCellValue.Value;
|
||||
|
||||
#region 读取excel
|
||||
// 遍历每一行
|
||||
for (int row = 4; row <= sheet.LastRowNum; row++)
|
||||
foreach (var workorder in group)
|
||||
{
|
||||
IRow currentRow = sheet.GetRow(row);
|
||||
if (currentRow != null) // 确保行不为空
|
||||
{
|
||||
ProWorkorder workorder = new ProWorkorder();
|
||||
string nickCode = mmMaterials
|
||||
.Where(it => it.MaterialCode == workorder.productionCode)
|
||||
.Select(it => it.Type)
|
||||
.FirstOrDefault();
|
||||
|
||||
//00 主体品名
|
||||
ICell currentCell_01 = currentRow.GetCell(0);
|
||||
workorder.productionName = currentCell_01?.ToString();
|
||||
if (currentCell_01 == null || string.IsNullOrEmpty(workorder.productionName))
|
||||
{
|
||||
throw new Exception($"{row + 1}行【主体品名】不可为空");
|
||||
}
|
||||
// 生成唯一的工单编号
|
||||
var generateResult = GenerateUniqueWorkorderNo(workorder, dateValue, currentIndex, nickCode);
|
||||
workorder.Workorder = generateResult.Item1;
|
||||
// 使用连续的sort值,不受编号冲突影响
|
||||
workorder.Sort = currentSort;
|
||||
|
||||
//01 成品型号
|
||||
ICell currentCell_02 = currentRow.GetCell(1);
|
||||
workorder.productionCode = currentCell_02?.ToString();
|
||||
if (currentCell_02 == null || string.IsNullOrEmpty(workorder.productionCode))
|
||||
{
|
||||
throw new Exception($"{row + 1}行【主体型号】不可为空");
|
||||
}
|
||||
|
||||
//02 单位
|
||||
ICell currentCell_04 = currentRow.GetCell(2);
|
||||
workorder.Unit = currentCell_04?.ToString();
|
||||
|
||||
//3 计划数量
|
||||
ICell currentCell_07 = currentRow.GetCell(3);
|
||||
workorder.PlanNum = (int)currentCell_07?.NumericCellValue;
|
||||
if (currentCell_07 == null || workorder.PlanNum < 0)
|
||||
{
|
||||
workorder.PlanNum = 0;
|
||||
}
|
||||
|
||||
//4 原材料名称
|
||||
ICell currentCell_11 = currentRow.GetCell(4);
|
||||
workorder.MaterialName = currentCell_11?.ToString();
|
||||
if (currentCell_11 == null || string.IsNullOrEmpty(workorder.MaterialName))
|
||||
{
|
||||
throw new Exception($"{row + 1}行【材料型号】不可为空");
|
||||
}
|
||||
|
||||
//5 原材料编号
|
||||
ICell currentCell_12 = currentRow.GetCell(5);
|
||||
workorder.MaterialCode = currentCell_12?.ToString();
|
||||
if (currentCell_12 == null || string.IsNullOrEmpty(workorder.MaterialCode))
|
||||
{
|
||||
throw new Exception($"{row + 1}行【材料编码】不可为空");
|
||||
}
|
||||
|
||||
//6 原材料材质
|
||||
ICell currentCell_13 = currentRow.GetCell(6);
|
||||
workorder.MaterialtextureCode = currentCell_13?.ToString();
|
||||
|
||||
//7 炉号
|
||||
ICell currentCell_14 = currentRow.GetCell(7);
|
||||
workorder.StoveCode = currentCell_14?.ToString();
|
||||
|
||||
//8 图号
|
||||
ICell currentCell_15 = currentRow.GetCell(8);
|
||||
workorder.DrawingCode = currentCell_15?.ToString();
|
||||
|
||||
//9 版本
|
||||
ICell currentCell_16 = currentRow.GetCell(9);
|
||||
workorder.Version = currentCell_16?.ToString();
|
||||
|
||||
//10 指导日期
|
||||
ICell cell17 = currentRow.GetCell(10);
|
||||
// 将单元格的数字值转换为DateTime
|
||||
workorder.InstructionDate = cell17.DateCellValue.Value;
|
||||
|
||||
// 11 车间code
|
||||
ICell currentCell_18 = currentRow.GetCell(11);
|
||||
if (currentCell_18 == null)
|
||||
{
|
||||
workorder.WorkshopCode = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentCell_18.CellType == CellType.Numeric)
|
||||
{
|
||||
workorder.WorkshopCode = currentCell_18.NumericCellValue.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.WorkshopCode = currentCell_18.StringCellValue;
|
||||
}
|
||||
}
|
||||
|
||||
//12 组号code
|
||||
ICell currentCell_19 = currentRow.GetCell(12);
|
||||
if (currentCell_19 == null)
|
||||
{
|
||||
workorder.GroupCode = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentCell_19.CellType == CellType.Numeric)
|
||||
{
|
||||
workorder.GroupCode = currentCell_19.NumericCellValue.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.GroupCode = currentCell_19.StringCellValue;
|
||||
}
|
||||
}
|
||||
|
||||
//13 班号code
|
||||
ICell currentCell_20 = currentRow.GetCell(13);
|
||||
if (currentCell_20 == null)
|
||||
{
|
||||
workorder.RouteCode = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentCell_20.CellType == CellType.Numeric)
|
||||
{
|
||||
workorder.RouteCode = currentCell_20.NumericCellValue.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.RouteCode = currentCell_20.StringCellValue;
|
||||
}
|
||||
}
|
||||
|
||||
//14 优先级
|
||||
ICell currentCell_21 = currentRow.GetCell(14);
|
||||
if (currentCell_21.StringCellValue == "优先")
|
||||
{
|
||||
workorder.Priority = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentCell_21.StringCellValue == "插单")
|
||||
{
|
||||
workorder.Priority = 2;
|
||||
}
|
||||
else if (currentCell_21.StringCellValue == "正常" || string.IsNullOrEmpty(currentCell_11.StringCellValue))
|
||||
{
|
||||
workorder.Priority = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//15 节拍
|
||||
ICell currentCell_22 = currentRow.GetCell(15);
|
||||
workorder.Beat = (int)currentCell_22?.NumericCellValue;
|
||||
|
||||
//16 进料单号(外购)
|
||||
ICell currentCell_010 = currentRow.GetCell(16);
|
||||
workorder.FeedOrder = currentCell_010?.StringCellValue;
|
||||
|
||||
//17 客户单号(出货)
|
||||
ICell currentCell_011 = currentRow.GetCell(17);
|
||||
workorder.CustomerOrder = currentCell_011?.StringCellValue;
|
||||
|
||||
//18 备注
|
||||
ICell currentCell_012 = currentRow.GetCell(18);
|
||||
workorder.Remark01 = currentCell_012?.StringCellValue;
|
||||
|
||||
workorder.Id = SnowFlakeSingle.Instance.NextId().ToString();
|
||||
workorder.CreatedBy = username;
|
||||
workorder.CreatedTime = DateTime.Now;
|
||||
workorder.WorkorderDate = dateValue;
|
||||
workorder.Status = 1;
|
||||
|
||||
// 工单 2024-9-13-最终顺序号
|
||||
int index = (row - 3);
|
||||
//TODO nickCode改为从物料清单进行获取
|
||||
string nickCode = mmMaterials
|
||||
.Where(it => it.MaterialCode == workorder.productionCode)
|
||||
.Select(it => it.Type)
|
||||
.FirstOrDefault();
|
||||
|
||||
workorder.Workorder = dateValue.ToString("yyyyMMdd") + "_" + workorder.GroupCode + workorder.RouteCode + "_" + nickCode + "_" + index.ToString("000");
|
||||
workorder.Sort = index * 10;
|
||||
|
||||
CultureInfo culture = CultureInfo.CurrentCulture;
|
||||
workorderList.Add(workorder);
|
||||
}
|
||||
Logger.Info($"生成工单编号: {workorder.Workorder},产品: {workorder.productionName},sort: {currentSort}");
|
||||
currentIndex = generateResult.Item2 + 1;
|
||||
// 增加sort值,确保下一个工单的sort值为当前值+10
|
||||
currentSort += 10;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
UseTran2(() =>
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
Logger.Info($"删除日期 {dateValue.ToShortDateString()} 的现有工单数据");
|
||||
Context
|
||||
.Deleteable<ProWorkorder>()
|
||||
.Where(it => it.WorkorderDate == dateValue)
|
||||
.ExecuteCommand();
|
||||
Logger.Info($"插入新工单数据,共 {workorderList.Count} 条");
|
||||
result = Context.Insertable(workorderList).ExecuteCommand();
|
||||
});
|
||||
|
||||
Logger.Info($"工单导入完成,成功导入 {result} 条数据");
|
||||
return result;
|
||||
}
|
||||
|
||||
UseTran2(() =>
|
||||
catch (Exception ex)
|
||||
{
|
||||
Context.Deleteable<ProWorkorder>().Where(it => it.WorkorderDate == dateValue).ExecuteCommand();
|
||||
result = Context.Insertable(workorderList).ExecuteCommand();
|
||||
});
|
||||
|
||||
return result;
|
||||
Logger.Error(ex, $"导入工单时出错: {ex.Message}");
|
||||
throw new Exception($"导入工单时出错,错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -262,239 +493,77 @@ namespace DOAN.Service.MES.product
|
||||
public int ImportDataAppend(IFormFile formFile, string username)
|
||||
{
|
||||
int result = 0;
|
||||
List<ProWorkorder> workorderList = new List<ProWorkorder>();
|
||||
DateTime dateValue = DateTime.MinValue;
|
||||
List<ProWorkorder> workorderList;
|
||||
DateTime dateValue;
|
||||
// XXX 改为从物料清单获取信息
|
||||
List<MmMaterial> mmMaterials = Context
|
||||
.Queryable<MmMaterial>()
|
||||
.Where(it => it.Status == "启用")
|
||||
.ToList();
|
||||
|
||||
using (var stream = formFile.OpenReadStream())
|
||||
try
|
||||
{
|
||||
try
|
||||
Logger.Info($"开始追加导入工单数据,用户名: {username}");
|
||||
workorderList = ReadWorkordersFromExcel(formFile, username, out dateValue);
|
||||
Logger.Info($"读取到 {workorderList.Count} 条工单数据");
|
||||
|
||||
// 按productionCode分组并顺序编号
|
||||
var productionCodeGroups = workorderList.GroupBy(w => w.productionCode).ToList();
|
||||
|
||||
// 获取所有工单的最大sort值,用于后续排序
|
||||
var maxSort = Context
|
||||
.Queryable<ProWorkorder>()
|
||||
.Where(it => it.WorkorderDate == dateValue.Date)
|
||||
//.Select(it => it.Sort)
|
||||
.Max(it => it.Sort).Value;
|
||||
|
||||
// 从maxSort + 10开始,确保sort值按10、20、30...递增
|
||||
int currentSort = (maxSort / 10) * 10 + 10;
|
||||
|
||||
foreach (var group in productionCodeGroups)
|
||||
{
|
||||
IWorkbook workbook = new XSSFWorkbook(stream);
|
||||
ISheet sheet = workbook.GetSheetAt(0);
|
||||
Logger.Info($"处理产品代码: {group.Key},共 {group.Count()} 条工单");
|
||||
// 获取当前productionCode当天已有的最大编号
|
||||
int maxIndex = GetMaxWorkorderIndex(group.Key, dateValue);
|
||||
// 从最大编号+1开始顺序编号
|
||||
int currentIndex = maxIndex + 1;
|
||||
Logger.Info($"产品代码: {group.Key},当前最大编号索引: {maxIndex},开始编号: {currentIndex}");
|
||||
|
||||
// 处理第2行 获取日期
|
||||
IRow secondRow = sheet.GetRow(1);
|
||||
ICell cell = secondRow.GetCell(0);
|
||||
// 将单元格的数字值转换为DateTime
|
||||
dateValue = cell.DateCellValue.Value;
|
||||
|
||||
// 遍历每一行
|
||||
for (int row = 4; row <= sheet.LastRowNum; row++)
|
||||
foreach (var workorder in group)
|
||||
{
|
||||
IRow currentRow = sheet.GetRow(row);
|
||||
if (currentRow != null) // 确保行不为空
|
||||
{
|
||||
ProWorkorder workorder = new ProWorkorder();
|
||||
string nickCode = mmMaterials
|
||||
.Where(it => it.MaterialCode == workorder.productionCode)
|
||||
.Select(it => it.Type)
|
||||
.FirstOrDefault();
|
||||
|
||||
#region 读取excel
|
||||
//00 成品名称
|
||||
ICell currentCell_01 = currentRow.GetCell(0);
|
||||
workorder.productionName = currentCell_01?.ToString();
|
||||
if (currentCell_01 == null || string.IsNullOrEmpty(workorder.productionName))
|
||||
{
|
||||
throw new Exception($"{row + 1}行【主体品名】不可为空");
|
||||
}
|
||||
// 生成唯一的工单编号
|
||||
var generateResult = GenerateUniqueWorkorderNo(workorder, dateValue, currentIndex, nickCode);
|
||||
workorder.Workorder = generateResult.Item1;
|
||||
// 使用连续的sort值,不受编号冲突影响
|
||||
workorder.Sort = currentSort;
|
||||
|
||||
//01 成品型号
|
||||
ICell currentCell_02 = currentRow.GetCell(1);
|
||||
workorder.productionCode = currentCell_02?.ToString();
|
||||
if (currentCell_02 == null || string.IsNullOrEmpty(workorder.productionCode))
|
||||
{
|
||||
throw new Exception($"{row + 1}行【主体型号】不可为空");
|
||||
}
|
||||
|
||||
//02 单位
|
||||
ICell currentCell_04 = currentRow.GetCell(2);
|
||||
workorder.Unit = currentCell_04?.ToString();
|
||||
|
||||
//3 计划数量
|
||||
ICell currentCell_07 = currentRow.GetCell(3);
|
||||
workorder.PlanNum = (int)currentCell_07?.NumericCellValue;
|
||||
if (currentCell_07 == null || workorder.PlanNum < 0)
|
||||
{
|
||||
workorder.PlanNum = 0;
|
||||
}
|
||||
|
||||
//4 原材料名称
|
||||
ICell currentCell_11 = currentRow.GetCell(4);
|
||||
workorder.MaterialName = currentCell_11?.ToString();
|
||||
if (currentCell_11 == null || string.IsNullOrEmpty(workorder.MaterialName))
|
||||
{
|
||||
throw new Exception($"{row + 1}行【材料型号】不可为空");
|
||||
}
|
||||
|
||||
//5 原材料编号
|
||||
ICell currentCell_12 = currentRow.GetCell(5);
|
||||
workorder.MaterialCode = currentCell_12?.ToString();
|
||||
if (currentCell_12 == null || string.IsNullOrEmpty(workorder.MaterialCode))
|
||||
{
|
||||
throw new Exception($"{row + 1}行【材料编码】不可为空");
|
||||
}
|
||||
|
||||
//6 材质
|
||||
ICell currentCell_13 = currentRow.GetCell(6);
|
||||
workorder.MaterialtextureCode = currentCell_13?.ToString();
|
||||
|
||||
//7 炉号
|
||||
ICell currentCell_14 = currentRow.GetCell(7);
|
||||
workorder.StoveCode = currentCell_14?.ToString();
|
||||
|
||||
//8 图号
|
||||
ICell currentCell_15 = currentRow.GetCell(8);
|
||||
workorder.DrawingCode = currentCell_15?.ToString();
|
||||
|
||||
//9 版本
|
||||
ICell currentCell_16 = currentRow.GetCell(9);
|
||||
workorder.Version = currentCell_16?.ToString();
|
||||
|
||||
//10 指导日期
|
||||
ICell cell17 = currentRow.GetCell(10);
|
||||
// 将单元格的数字值转换为DateTime
|
||||
workorder.InstructionDate = cell17.DateCellValue.Value;
|
||||
if(cell17 == null)
|
||||
{
|
||||
workorder.InstructionDate = dateValue;
|
||||
}
|
||||
|
||||
// 11 车间code
|
||||
ICell currentCell_18 = currentRow.GetCell(11);
|
||||
if (currentCell_18 == null)
|
||||
{
|
||||
workorder.WorkshopCode = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentCell_18.CellType == CellType.Numeric)
|
||||
{
|
||||
workorder.WorkshopCode = currentCell_18.NumericCellValue.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.WorkshopCode = currentCell_18.StringCellValue;
|
||||
}
|
||||
}
|
||||
|
||||
//12 组号code
|
||||
ICell currentCell_19 = currentRow.GetCell(12);
|
||||
if (currentCell_19 == null)
|
||||
{
|
||||
workorder.GroupCode = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentCell_19.CellType == CellType.Numeric)
|
||||
{
|
||||
workorder.GroupCode = currentCell_19.NumericCellValue.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.GroupCode = currentCell_19.StringCellValue;
|
||||
}
|
||||
}
|
||||
|
||||
//13 班号code
|
||||
ICell currentCell_20 = currentRow.GetCell(13);
|
||||
if (currentCell_20 == null)
|
||||
{
|
||||
workorder.RouteCode = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentCell_20.CellType == CellType.Numeric)
|
||||
{
|
||||
workorder.RouteCode = currentCell_20.NumericCellValue.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
workorder.RouteCode = currentCell_20.StringCellValue;
|
||||
}
|
||||
}
|
||||
|
||||
//14 优先级
|
||||
ICell currentCell_21 = currentRow.GetCell(14);
|
||||
if (currentCell_21.StringCellValue == "优先")
|
||||
{
|
||||
workorder.Priority = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentCell_21.StringCellValue == "插单")
|
||||
{
|
||||
workorder.Priority = 2;
|
||||
}
|
||||
else if (currentCell_21.StringCellValue == "正常" || string.IsNullOrEmpty(currentCell_11.StringCellValue))
|
||||
{
|
||||
workorder.Priority = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//15 节拍
|
||||
ICell currentCell_22 = currentRow.GetCell(15);
|
||||
workorder.Beat = (int)currentCell_22?.NumericCellValue;
|
||||
|
||||
//16 进料单号(外购)
|
||||
ICell currentCell_010 = currentRow.GetCell(16);
|
||||
workorder.FeedOrder = currentCell_010?.StringCellValue;
|
||||
|
||||
//17 客户单号(出货)
|
||||
ICell currentCell_011 = currentRow.GetCell(17);
|
||||
workorder.CustomerOrder = currentCell_011?.StringCellValue;
|
||||
|
||||
//18 备注
|
||||
ICell currentCell_012 = currentRow.GetCell(18);
|
||||
workorder.Remark01 = currentCell_012?.StringCellValue;
|
||||
#endregion
|
||||
|
||||
workorder.Id = SnowFlakeSingle.Instance.NextId().ToString();
|
||||
workorder.CreatedBy = username;
|
||||
workorder.CreatedTime = DateTime.Now;
|
||||
workorder.WorkorderDate = dateValue;
|
||||
workorder.Status = 1;
|
||||
|
||||
// 获取当前日期工单最大顺序号和序号
|
||||
DateTime currentDate = dateValue.Date;
|
||||
var MaxWorkorder = Context
|
||||
.Queryable<ProWorkorder>()
|
||||
.Where(it => it.WorkorderDate == currentDate)
|
||||
.OrderByDescending(it => it.Sort)
|
||||
.Select(it => new { it.Workorder, it.Sort })
|
||||
.First();
|
||||
|
||||
// 工单 2024-9-13-最终顺序号
|
||||
int index = (row - 3);
|
||||
//TODO nickCode改为从物料清单进行获取
|
||||
string nickCode = mmMaterials
|
||||
.Where(it => it.MaterialCode == workorder.productionCode)
|
||||
.Select(it => it.Type)
|
||||
.FirstOrDefault();
|
||||
|
||||
workorder.Workorder = dateValue.ToString("yyyyMMdd") + "_" + workorder.GroupCode + workorder.RouteCode + "_" + nickCode + "_" + index.ToString("000");
|
||||
workorder.Sort = index * 10 + (MaxWorkorder?.Sort ?? 0);
|
||||
|
||||
CultureInfo culture = CultureInfo.CurrentCulture;
|
||||
workorderList.Add(workorder);
|
||||
}
|
||||
Logger.Info($"生成工单编号: {workorder.Workorder},产品: {workorder.productionName},sort: {currentSort}");
|
||||
currentIndex = generateResult.Item2 + 1;
|
||||
// 增加sort值,确保下一个工单的sort值为当前值+10
|
||||
currentSort += 10;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
UseTran2(() =>
|
||||
{
|
||||
throw new Exception(ex.Message);
|
||||
}
|
||||
// 追加导入,不删除现有数据
|
||||
Logger.Info($"追加插入工单数据,共 {workorderList.Count} 条");
|
||||
result = Context.Insertable(workorderList).ExecuteCommand();
|
||||
});
|
||||
|
||||
Logger.Info($"工单追加导入完成,成功导入 {result} 条数据");
|
||||
return result;
|
||||
}
|
||||
|
||||
UseTran2(() =>
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Context.Deleteable<ProWorkorder>().Where(it => it.WorkorderDate == dateValue).ExecuteCommand();
|
||||
result = Context.Insertable(workorderList).ExecuteCommand();
|
||||
});
|
||||
|
||||
|
||||
return result;
|
||||
Logger.Error(ex, $"追加导入工单时出错: {ex.Message}");
|
||||
throw new Exception($"追加导入工单时出错,错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,35 +65,73 @@ namespace DOAN.Service.MES.product
|
||||
public int MoveWorkorder(string id, int type)
|
||||
{
|
||||
int result = 0;
|
||||
ProWorkorder toMove = Context
|
||||
.Queryable<ProWorkorder>()
|
||||
.Where(it => it.Id == id)
|
||||
.First();
|
||||
var pervious = Context
|
||||
.Queryable<ProWorkorder>()
|
||||
.Where(it => it.WorkorderDate == toMove.WorkorderDate);
|
||||
|
||||
//上移动
|
||||
if (type == 1)
|
||||
try
|
||||
{
|
||||
pervious = pervious
|
||||
.Where(it => it.Sort <= toMove.Sort)
|
||||
.OrderByDescending(it => it.Sort);
|
||||
}
|
||||
//下移
|
||||
else if (type == 2)
|
||||
{
|
||||
pervious = pervious.Where(it => it.Sort >= toMove.Sort).OrderBy(it => it.Sort);
|
||||
}
|
||||
// 获取要移动的工单
|
||||
ProWorkorder toMove = Context
|
||||
.Queryable<ProWorkorder>()
|
||||
.Where(it => it.Id == id)
|
||||
.First();
|
||||
|
||||
ProWorkorder exchange = pervious.Skip(1).Take(1).First();
|
||||
if (exchange != null)
|
||||
// 检查工单是否存在
|
||||
if (toMove == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// 检查Sort值是否存在
|
||||
if (!toMove.Sort.HasValue)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
ProWorkorder exchange = null;
|
||||
|
||||
// 上移动:找到Sort值小于当前工单的最大Sort值的工单
|
||||
if (type == 1)
|
||||
{
|
||||
exchange = Context
|
||||
.Queryable<ProWorkorder>()
|
||||
.Where(it => it.WorkorderDate == toMove.WorkorderDate)
|
||||
.Where(it => it.PlanNum > 0)
|
||||
.Where(it => it.Sort.HasValue && it.Sort < toMove.Sort)
|
||||
.OrderByDescending(it => it.Sort)
|
||||
.First();
|
||||
}
|
||||
// 下移:找到Sort值大于当前工单的最小Sort值的工单
|
||||
else if (type == 2)
|
||||
{
|
||||
exchange = Context
|
||||
.Queryable<ProWorkorder>()
|
||||
.Where(it => it.WorkorderDate == toMove.WorkorderDate)
|
||||
.Where(it => it.PlanNum > 0)
|
||||
.Where(it => it.Sort.HasValue && it.Sort > toMove.Sort)
|
||||
.OrderBy(it => it.Sort)
|
||||
.First();
|
||||
}
|
||||
|
||||
// 检查交换工单是否存在
|
||||
if (exchange != null && exchange.Sort.HasValue)
|
||||
{
|
||||
// 使用事务确保两个工单的Sort值同时更新
|
||||
UseTran2(() =>
|
||||
{
|
||||
// 交换Sort值
|
||||
int temp = toMove.Sort.Value;
|
||||
toMove.Sort = exchange.Sort;
|
||||
exchange.Sort = temp;
|
||||
|
||||
// 更新工单
|
||||
result += Context.Updateable(toMove).ExecuteCommand();
|
||||
result += Context.Updateable(exchange).ExecuteCommand();
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
int temp = toMove.Sort.Value;
|
||||
toMove.Sort = exchange.Sort;
|
||||
exchange.Sort = temp;
|
||||
result += Context.Updateable(toMove).ExecuteCommand();
|
||||
result += Context.Updateable(exchange).ExecuteCommand();
|
||||
// 记录错误日志
|
||||
Console.WriteLine($"移动工单时出错: {ex.Message}");
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user