using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using DOAN.Model;
using DOAN.Model.BZFM;
using DOAN.Model.MES.base_;
using DOAN.Model.MES.product;
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;
namespace DOAN.Service.MES.product
{
///
/// 工单导入服务
///
[AppService(
ServiceType = typeof(IProWorkorderImportService),
ServiceLifetime = LifeTime.Transient
)]
public class ProWorkorderImportService : BaseService, IProWorkorderImportService
{
///
/// 日志记录器
///
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
///
/// 生成唯一的工单编号
///
/// 工单对象
/// 日期值
/// 当前编号索引
/// 昵称代码
/// 最大尝试次数
/// 生成的工单编号和更新后的索引
private Tuple 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()
.Where(it => it.Workorder == workorderNo)
.Any();
if (!isUnique)
{
currentIndex++;
}
} while (!isUnique);
return new Tuple(workorderNo, currentIndex);
}
///
/// 获取指定productionCode当天的最大工单编号索引
///
/// 产品代码
/// 日期值
/// 最大编号索引
private int GetMaxWorkorderIndex(string productionCode, DateTime dateValue)
{
var workorderNumbers = Context
.Queryable()
.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;
})
.ToList();
// 如果没有找到记录,返回0
return workorderNumbers.Count > 0 ? workorderNumbers.Max() : 0;
}
///
/// 从Excel文件读取工单数据
///
/// Excel文件
/// 用户名
/// 返回的日期值
/// 工单列表
private List ReadWorkordersFromExcel(IFormFile formFile, string username, out DateTime dateValue)
{
List workorderList = new List();
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;
}
///
/// 导入工单 必须整删除 整改
///
///
///
///
public int ImportData(IFormFile formFile, string username)
{
int result = 0;
List workorderList;
DateTime dateValue;
// XXX 改为从物料清单获取信息
List mmMaterials = Context
.Queryable()
.Where(it => it.Status == "启用")
.ToList();
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 maxSortNullable = Context
.Queryable()
.Where(it => it.WorkorderDate == dateValue.Date)
//.Select(it => it.Sort)
.Max(it => it.Sort);
// 如果没有找到记录,设置默认值0
int maxSort = maxSortNullable.HasValue ? maxSortNullable.Value : 0;
// 从maxSort + 10开始,确保sort值按10、20、30...递增
int currentSort = (maxSort / 10) * 10 + 10;
foreach (var group in productionCodeGroups)
{
Logger.Info($"处理产品代码: {group.Key},共 {group.Count()} 条工单");
// 获取当前productionCode当天已有的最大编号
int maxIndex = GetMaxWorkorderIndex(group.Key, dateValue);
// 从最大编号+1开始顺序编号
int currentIndex = maxIndex + 1;
Logger.Info($"产品代码: {group.Key},当前最大编号索引: {maxIndex},开始编号: {currentIndex}");
foreach (var workorder in group)
{
string nickCode = mmMaterials
.Where(it => it.MaterialCode == workorder.productionCode)
.Select(it => it.Type)
.FirstOrDefault();
// 生成唯一的工单编号
var generateResult = GenerateUniqueWorkorderNo(workorder, dateValue, currentIndex, nickCode);
workorder.Workorder = generateResult.Item1;
// 使用连续的sort值,不受编号冲突影响
workorder.Sort = currentSort;
Logger.Info($"生成工单编号: {workorder.Workorder},产品: {workorder.productionName},sort: {currentSort}");
currentIndex = generateResult.Item2 + 1;
// 增加sort值,确保下一个工单的sort值为当前值+10
currentSort += 10;
}
}
UseTran2(() =>
{
Logger.Info($"删除日期 {dateValue.ToShortDateString()} 的现有工单数据");
Context
.Deleteable()
.Where(it => it.WorkorderDate == dateValue)
.ExecuteCommand();
Logger.Info($"插入新工单数据,共 {workorderList.Count} 条");
result = Context.Insertable(workorderList).ExecuteCommand();
});
Logger.Info($"工单导入完成,成功导入 {result} 条数据");
return result;
}
catch (Exception ex)
{
Logger.Error(ex, $"导入工单时出错: {ex.Message}");
throw new Exception($"导入工单时出错,错误: {ex.Message}");
}
}
///
/// 分批导入,追加导入
///
///
///
///
public int ImportDataAppend(IFormFile formFile, string username)
{
int result = 0;
List workorderList;
DateTime dateValue;
// XXX 改为从物料清单获取信息
List mmMaterials = Context
.Queryable()
.Where(it => it.Status == "启用")
.ToList();
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 maxSortNullable = Context
.Queryable()
.Where(it => it.WorkorderDate == dateValue.Date)
//.Select(it => it.Sort)
.Max(it => it.Sort);
// 如果没有找到记录,设置默认值0
int maxSort = maxSortNullable.HasValue ? maxSortNullable.Value : 0;
// 从maxSort + 10开始,确保sort值按10、20、30...递增
int currentSort = (maxSort / 10) * 10 + 10;
foreach (var group in productionCodeGroups)
{
Logger.Info($"处理产品代码: {group.Key},共 {group.Count()} 条工单");
// 获取当前productionCode当天已有的最大编号
int maxIndex = GetMaxWorkorderIndex(group.Key, dateValue);
// 从最大编号+1开始顺序编号
int currentIndex = maxIndex + 1;
Logger.Info($"产品代码: {group.Key},当前最大编号索引: {maxIndex},开始编号: {currentIndex}");
foreach (var workorder in group)
{
string nickCode = mmMaterials
.Where(it => it.MaterialCode == workorder.productionCode)
.Select(it => it.Type)
.FirstOrDefault();
// 生成唯一的工单编号
var generateResult = GenerateUniqueWorkorderNo(workorder, dateValue, currentIndex, nickCode);
workorder.Workorder = generateResult.Item1;
// 使用连续的sort值,不受编号冲突影响
workorder.Sort = currentSort;
Logger.Info($"生成工单编号: {workorder.Workorder},产品: {workorder.productionName},sort: {currentSort}");
currentIndex = generateResult.Item2 + 1;
// 增加sort值,确保下一个工单的sort值为当前值+10
currentSort += 10;
}
}
UseTran2(() =>
{
// 追加导入,不删除现有数据
Logger.Info($"追加插入工单数据,共 {workorderList.Count} 条");
result = Context.Insertable(workorderList).ExecuteCommand();
});
Logger.Info($"工单追加导入完成,成功导入 {result} 条数据");
return result;
}
catch (Exception ex)
{
Logger.Error(ex, $"追加导入工单时出错: {ex.Message}");
throw new Exception($"追加导入工单时出错,错误: {ex.Message}");
}
}
}
}