xwt
2025-10-30 dabfdd9dbf0364b1134daaad86af7e13f6437295
StandardInterface/MES.Service/service/QC/LljService.cs
@@ -1,10 +1,13 @@
using System.Data;
using System.Xml;
using System.Linq;
using Masuit.Tools;
using MES.Service.DB;
using MES.Service.Dto.service;
using MES.Service.Modes;
using MES.Service.util;
using SqlSugar;
using Tea.Utils;
using DbType = System.Data.DbType;
@@ -22,38 +25,250 @@
        var totalCount = 0;
        //var itemIds = GetQaItem(db, queryObj.createUser);
        // 使用数据库分页查询,一次查询50条,提升性能
        // 判断是否为管理员账号
        bool isAdmin = queryObj.createUser == "PL017" || queryObj.createUser == "HMLYY" || queryObj.createUser == "HMCS";
        List<LtsLlj> pageList;
        if (isAdmin)
        {
            // 管理员账号:直接查询主表,避免JOIN导致的重复记录
            pageList = db.Queryable<LtsLlj>()
                .WhereIF(
                    StringUtil.IsNotNullOrEmpty(queryObj.result) &&
                    "未完成".Equals(queryObj.result),
                    a => a.FcheckResu == null)
                .WhereIF(
                    StringUtil.IsNotNullOrEmpty(queryObj.result) &&
                    !"未完成".Equals(queryObj.result),
                    a => a.FcheckResu != null)
                .WhereIF(id > 0, a => a.Id == id)
                //加筛选条件,根据选择的搜索字段进行精确搜索
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 1, // 物料编号搜索
                    a => a.ItemNo != null && a.ItemNo.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 2, // 物料名称搜索
                    a => a.ItemName != null && a.ItemName.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 3, // 供应商搜索
                    a => a.SuppName != null && a.SuppName.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 4, // 到货单号搜索
                    a => a.LotNo != null && a.LotNo.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 5, // 检验单号搜索
                    a => a.ReleaseNo != null && a.ReleaseNo.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 6, // 物料规格搜索
                    a => a.ItemModel != null && a.ItemModel.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .Select(a => new LtsLlj
                {
                    Id = a.Id,
                    ItemNo = a.ItemNo,
                    ItemId = a.ItemId,
                    ItemName = a.ItemName,
                    ItemModel = a.ItemModel,
                    SuppName = a.SuppName,
                    LotNo = a.LotNo,
                    ReleaseNo = a.ReleaseNo,
                    FcheckResu = a.FcheckResu,
                    CreateDate = a.CreateDate,
                    FcovertQty = a.FcovertQty,
                    DEPARTMENTNAME = a.DEPARTMENTNAME,
                    FngDesc = a.FngDesc,
                    UrgentFlag = a.UrgentFlag,
                    Ftype = a.Ftype,
                    LotNo1 = a.LotNo1,
                    EMERGENCY = a.EMERGENCY,
                    Status = a.Status,
                    IqcDate = a.IqcDate,
                    // 添加维护人员信息(管理员不需要此字段)
                    Fcode = null,
                    // 添加破坏实验数量
                    PHSY = a.PHSY,
                    // 添加不良原因
                    BLYY = a.BLYY,
                    // 添加所属车间
                    SSCJ = a.SSCJ,
                    // 添加评审状态
                    PSZT = a.PSZT,
                    // 添加检验项目维护状态
                    Jyxm = a.Jyxm,
                    // 添加版本号(用于FTP路径)
                    Fversion = a.Fversion
                })
                .OrderBy("IQC_DATE DESC")
                .OrderBy("CASE WHEN EMERGENCY = 1 THEN 0 ELSE 1 END")
                .OrderBy("CASE WHEN JYXM = 0 THEN 0 ELSE 1 END")
                .OrderBy("CASE WHEN STATUS = '已提交' THEN 1 ELSE 0 END")
                .OrderBy("CREATE_DATE")
                .ToPageList(queryObj.PageIndex, queryObj.Limit, ref totalCount);
        }
        else
        {
            // 普通用户:使用JOIN查询,根据维护情况判断权限
            pageList = db.Queryable<LtsLlj, V_LljUser>((a, v) =>
                    new JoinQueryInfos(JoinType.Left, a.ItemNo == v.ItemNo))
                .WhereIF(
                    StringUtil.IsNotNullOrEmpty(queryObj.result) &&
                    "未完成".Equals(queryObj.result),
                    (a, v) => a.FcheckResu == null)
                .WhereIF(
                    StringUtil.IsNotNullOrEmpty(queryObj.result) &&
                    !"未完成".Equals(queryObj.result),
                    (a, v) => a.FcheckResu != null)
                .WhereIF(id > 0, (a, v) => a.Id == id)
                // 权限控制:普通用户需要根据物料维护情况判断
                .WhereIF(queryObj.UserIndex == "0",
                    (a, v) =>
                        // 如果物料被维护,只有维护人员可以看到
                        (v.Fcode != null && v.Fcode == queryObj.createUser) ||
                        // 如果物料未被维护,所有人都可以看到
                        (v.Fcode == null))
                //加筛选条件,根据选择的搜索字段进行精确搜索
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 1, // 物料编号搜索
                    (a, v) => a.ItemNo != null && a.ItemNo.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 2, // 物料名称搜索
                    (a, v) => a.ItemName != null && a.ItemName.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 3, // 供应商搜索
                    (a, v) => a.SuppName != null && a.SuppName.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 4, // 到货单号搜索
                    (a, v) => a.LotNo != null && a.LotNo.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 5, // 检验单号搜索
                    (a, v) => a.ReleaseNo != null && a.ReleaseNo.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 6, // 物料规格搜索
                    (a, v) => a.ItemModel != null && a.ItemModel.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .Select((a, v) => new LtsLlj
                {
                    Id = a.Id,
                    ItemNo = a.ItemNo,
                    ItemId = a.ItemId,
                    ItemName = a.ItemName,
                    ItemModel = a.ItemModel,
                    SuppName = a.SuppName,
                    LotNo = a.LotNo,
                    ReleaseNo = a.ReleaseNo,
                    FcheckResu = a.FcheckResu,
                    CreateDate = a.CreateDate,
                    FcovertQty = a.FcovertQty,
                    DEPARTMENTNAME = a.DEPARTMENTNAME,
                    FngDesc = a.FngDesc,
                    UrgentFlag = a.UrgentFlag,
                    Ftype = a.Ftype,
                    LotNo1 = a.LotNo1,
                    EMERGENCY = a.EMERGENCY,
                    Status = a.Status,
                    IqcDate = a.IqcDate,
                    // 添加维护人员信息
                    Fcode = v.Fcode,
                    // 添加破坏实验数量
                    PHSY = a.PHSY,
                    // 添加不良原因
                    BLYY = a.BLYY,
                    // 添加所属车间
                    SSCJ = a.SSCJ,
                    // 添加评审状态
                    PSZT = a.PSZT,
                    // 添加检验项目维护状态
                    Jyxm = a.Jyxm,
                    // 添加版本号(用于FTP路径)
                    Fversion = a.Fversion
                })
                .OrderBy("IQC_DATE DESC")
                .OrderBy("CASE WHEN EMERGENCY = 1 THEN 0 ELSE 1 END")
                .OrderBy("CASE WHEN JYXM = 0 THEN 0 ELSE 1 END")
                .OrderBy("CASE WHEN STATUS = '已提交' THEN 1 ELSE 0 END")
                .OrderBy("CREATE_DATE")
                .ToPageList(queryObj.PageIndex, queryObj.Limit, ref totalCount);
        }
        var pageList = db.Queryable<LtsLlj>()
            .WhereIF(
                StringUtil.IsNotNullOrEmpty(queryObj.result) &&
                "未完成".Equals(queryObj.result),
                a => a.FcheckResu == null)
            .WhereIF(
                StringUtil.IsNotNullOrEmpty(queryObj.result) &&
                !"未完成".Equals(queryObj.result),
                a => a.FcheckResu != null)
            .WhereIF(id > 0, a => a.Id == id)
            //加筛选条件,根据供应商,物料编码,物料名称搜索
            //.WhereIF(queryObj.SearchValue!=null && queryObj.SearchValue!="", (a) => a.SuppName == queryObj.SearchValue|| a.ItemName == queryObj.SearchValue || a.ItemNo == queryObj.SearchValue )
            .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue),
                a => a.SuppName.ToLower()
                         .Contains(queryObj.SearchValue.ToLower())
                     || a.ItemName.ToLower()
                         .Contains(queryObj.SearchValue.ToLower())
                     || a.ItemNo.ToLower()
                         .Contains(queryObj.SearchValue.ToLower())
                     || a.LotNo.ToLower()
                        .Contains(queryObj.SearchValue.ToLower())
                     || a.ReleaseNo.ToLower()
                        .Contains(queryObj.SearchValue.ToLower())
                     || a.ItemModel.ToLower()
                        .Contains(queryObj.SearchValue.ToLower()))
            .OrderByDescending(a => a.Id)
            .ToPageList(queryObj.PageIndex, queryObj.Limit, ref totalCount);
            var emergencyValues = pageList.Select(item => item.EMERGENCY).ToList();
        return (pageList, totalCount);
        // 批量获取检验项目数量,避免N+1查询问题
        if (pageList.Any())
        {
            var releaseNos = pageList.Select(x => x.ReleaseNo).Distinct().ToList();
            // 为每个检验单设置检验项目数量和NewFngDesc字段
            foreach (var item in pageList)
            {
                var count = db.Queryable<MesQaItemsDetectDetail5>()
                    .Where(x => x.ReleaseNo == item.ReleaseNo)
                    .Count();
                item.InspectionItemCount = count;
                item.NewFngDesc = item.FngDesc;
            }
        }
        // 计算所有数据的去重总数(不是当前页的去重数)
        int allDataQuery;
        if (isAdmin)
        {
            // 管理员账号:直接查询主表
            allDataQuery = db.Queryable<LtsLlj>()
                .WhereIF(
                    StringUtil.IsNotNullOrEmpty(queryObj.result) &&
                    "未完成".Equals(queryObj.result),
                    a => a.FcheckResu == null)
                .WhereIF(
                    StringUtil.IsNotNullOrEmpty(queryObj.result) &&
                    !"未完成".Equals(queryObj.result),
                    a => a.FcheckResu != null)
                .WhereIF(id > 0, a => a.Id == id)
                //加筛选条件,根据选择的搜索字段进行精确搜索
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 1, // 物料编号搜索
                    a => a.ItemNo != null && a.ItemNo.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 2, // 物料名称搜索
                    a => a.ItemName != null && a.ItemName.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 3, // 供应商搜索
                    a => a.SuppName != null && a.SuppName.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 4, // 到货单号搜索
                    a => a.LotNo != null && a.LotNo.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 5, // 检验单号搜索
                    a => a.ReleaseNo != null && a.ReleaseNo.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 6, // 物料规格搜索
                    a => a.ItemModel != null && a.ItemModel.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .Select(a => a.ReleaseNo)
                .Distinct()
                .Count();
        }
        else
        {
            // 普通用户:使用JOIN查询
            allDataQuery = db.Queryable<LtsLlj, V_LljUser>((a, v) =>
                    new JoinQueryInfos(JoinType.Left, a.ItemNo == v.ItemNo))
                .WhereIF(
                    StringUtil.IsNotNullOrEmpty(queryObj.result) &&
                    "未完成".Equals(queryObj.result),
                    (a, v) => a.FcheckResu == null)
                .WhereIF(
                    StringUtil.IsNotNullOrEmpty(queryObj.result) &&
                    !"未完成".Equals(queryObj.result),
                    (a, v) => a.FcheckResu != null)
                .WhereIF(id > 0, (a, v) => a.Id == id)
                // 权限控制:普通用户需要根据物料维护情况判断
                .WhereIF(queryObj.UserIndex == "0",
                    (a, v) =>
                        // 如果物料被维护,只有维护人员可以看到
                        (v.Fcode != null && v.Fcode == queryObj.createUser) ||
                        // 如果物料未被维护,所有人都可以看到
                        (v.Fcode == null))
                //加筛选条件,根据选择的搜索字段进行精确搜索
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 1, // 物料编号搜索
                    (a, v) => a.ItemNo != null && a.ItemNo.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 2, // 物料名称搜索
                    (a, v) => a.ItemName != null && a.ItemName.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 3, // 供应商搜索
                    (a, v) => a.SuppName != null && a.SuppName.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 4, // 到货单号搜索
                    (a, v) => a.LotNo != null && a.LotNo.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 5, // 检验单号搜索
                    (a, v) => a.ReleaseNo != null && a.ReleaseNo.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .WhereIF(!string.IsNullOrEmpty(queryObj.SearchValue) && queryObj.selectedIndex == 6, // 物料规格搜索
                    (a, v) => a.ItemModel != null && a.ItemModel.ToLower().Contains(queryObj.SearchValue.ToLower()))
                .Select((a, v) => a.ReleaseNo)
                .Distinct()
                .Count();
        }
        var emergencyValues = pageList.Select(item => item.EMERGENCY).ToList();
        return (pageList, allDataQuery);
    }
    //根据检验标准来计算检验个数
@@ -101,8 +316,97 @@
        return msg;
    }
    //紧急放行
    //public string[] EmergencyRelease(int id)
    //{
    //    var db = SqlSugarHelper.GetInstance();
    //    int emergencyStatus = db.Queryable<MesQaItemsDetect01>()
    //                            .Where(t => t.Id == id)
    //                            .Select(t => t.EMERGENCY)
    //                            .First();
    //    if (emergencyStatus != 0)
    //    {
    //        return new string[] { "1", "非紧急状态,无法执行紧急放行" };
    //    }
    //    var outputResult = new SugarParameter("PO_RESULT", null,
    //        DbType.Int32, ParameterDirection.Output, 4000);
    //    var outputMessage = new SugarParameter("PO_MSG", null,
    //        DbType.String, ParameterDirection.Output, 4000);
    //    var parameters = new List<SugarParameter>
    //{
    //    new("P_ID", id, DbType.Int32, ParameterDirection.Input),
    //    outputResult,
    //    outputMessage
    //};
    //    db.Ado.ExecuteCommand(
    //        "BEGIN prc_MES_QA_ITEMS_update1(:P_ID, :PO_RESULT, :PO_MSG); END;",
    //        parameters.ToArray());
    //    var lotNo1 = db.Queryable<MesQaItemsDetect01>()
    //               .Where(t => t.Id == id)
    //               .Select(t => t.LotNo1)
    //               .First();
    //    var resultValue = outputResult.Value?.ToString();
    //    var messageValue = outputMessage.Value?.ToString();
    //    return new string[] { resultValue, messageValue, lotNo1?.ToString() ?? "" };
    //}
    //public string[] WithdrawEmergencyRelease(int id)
    //{
    //    var db = SqlSugarHelper.GetInstance();
    //    int emergencyStatus = db.Queryable<MesQaItemsDetect01>()
    //                            .Where(t => t.Id == id)
    //                            .Select(t => t.EMERGENCY)
    //                            .First();
    //    if (emergencyStatus != 0)
    //    {
    //        return new string[] { "1", "非紧急状态,无需撤回" };
    //    }
    //    var outputResult = new SugarParameter("PO_RESULT", null,
    //        DbType.Int32, ParameterDirection.Output, 4000);
    //    var outputMessage = new SugarParameter("PO_MSG", null,
    //        DbType.String, ParameterDirection.Output, 4000);
    //    var parameters = new List<SugarParameter>
    //{
    //    new("P_ID", id, DbType.Int32, ParameterDirection.Input),
    //    outputResult,
    //    outputMessage
    //};
    //    db.Ado.ExecuteCommand(
    //        "BEGIN prc_MES_QA_ITEMS_update2(:P_ID, :PO_RESULT, :PO_MSG); END;",
    //        parameters.ToArray());
    //    var lotNo1 = db.Queryable<MesQaItemsDetect01>()
    //               .Where(t => t.Id == id)
    //               .Select(t => t.LotNo1)
    //               .First();
    //    var resultValue = outputResult.Value?.ToString();
    //    var messageValue = outputMessage.Value?.ToString();
    //    return new string[] { resultValue, messageValue, lotNo1?.ToString() ?? "" };
    //}
    public string[] EmergencyRelease(int id)
    {
        var db = SqlSugarHelper.GetInstance();
@@ -187,7 +491,8 @@
        var resultValue = outputResult.Value?.ToString();
        var messageValue = outputMessage.Value?.ToString();
        return new string[] { resultValue, messageValue, lotNo1?.ToString() ?? "" };
    }
    }
    private string ExtractSubstring(string input, char startChar, char endChar)
    {
        var startIndex = input.IndexOf(startChar);
@@ -203,6 +508,224 @@
        return input.Substring(startIndex + 1, length);
    }
    /// <summary>
    /// 获取附件信息
    /// </summary>
    /// <param name="ItemNo">物料编码</param>
    /// <param name="fversion">版本号(可选,用于过滤)</param>
    /// <returns>附件列表</returns>
    public List<QamftpDto> GetAttachments(string ItemNo, string fversion = null)
    {
        //if (string.IsNullOrEmpty(ItemNo))
        //{
           // throw new ArgumentException("检验单号不能为空");
        //}
        var db = SqlSugarHelper.GetInstance();
        try
        {
            var query = db.Queryable<MesQamftp>()
                .Where(x => x.ItemNo == ItemNo)
                .Where(x => x.Ftype == "来料检");  // 添加FTYPE = '来料检'的限制
            // 如果传入了fversion,则按Fversion过滤
            if (!string.IsNullOrEmpty(fversion))
            {
                query = query.Where(x => x.Fversion == fversion);
            }
            return query
                .OrderBy(x => x.Fdate, OrderByType.Desc)
                // .ThenBy(x => x.CreateDate, OrderByType.Desc)
                .Select(x => new QamftpDto
                {
                    Id = x.Id,
                    itemNo = x.ItemNo,
                    Ftype = x.Ftype,
                    Fattach = x.Fattach,
                    Fversion = x.Fversion,
                    Fdate = x.Fdate,
                    CreateBy = x.CreateBy,
                    CreateDate = x.CreateDate,
                    Company = x.Company,
                    Factory = x.Factory,
                    F_type = x.F_type,
                    LastupdateBy = x.LastupdateBy,
                    LastupdateDate = x.LastupdateDate,
                    ItemId = x.ItemId
                }).ToList();
        }
        catch (Exception ex)
        {
            throw new Exception($"查询附件信息失败: {ex.Message}");
        }
    }
    public byte[] GetFtpFile(string itemNo, string fileName, string ftpServer, string fversion = null)
    {
        // 参数验证
        if (string.IsNullOrEmpty(itemNo) || string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(ftpServer))
        {
            throw new ArgumentException("参数不能为空: itemNo, fileName, ftpServer");
        }
        string ftpUser = "hm_ftp";
        string ftpPwd = "dell_123";
        // 标准化FTP服务器地址
        string normalizedServer = NormalizeFtpServer(ftpServer);
        // 构建FTP文件路径 - 来料检使用IQC目录,使用fversion作为子目录
        string ftpPath;
        if (!string.IsNullOrEmpty(fversion))
        {
            ftpPath = $"{normalizedServer}/IQC/{itemNo}/{fversion}/{fileName}";
        }
        else
        {
            ftpPath = $"{normalizedServer}/IQC/{itemNo}/{fileName}";
        }
        try
        {
            var request = (System.Net.FtpWebRequest)System.Net.WebRequest.Create(ftpPath);
            request.Method = System.Net.WebRequestMethods.Ftp.DownloadFile;
            request.Credentials = new System.Net.NetworkCredential(ftpUser, ftpPwd);
            request.UseBinary = true;
            request.UsePassive = false;
            request.Timeout = 30000; // 30秒超时
            request.ReadWriteTimeout = 30000;
            using (var response = (System.Net.FtpWebResponse)request.GetResponse())
            using (var ftpStream = response.GetResponseStream())
            using (var ms = new System.IO.MemoryStream())
            {
                if (ftpStream == null)
                {
                    throw new Exception("FTP响应流为空");
                }
                ftpStream.CopyTo(ms);
                var fileBytes = ms.ToArray();
                if (fileBytes.Length == 0)
                {
                    return null; // 文件为空或不存在
                }
                return fileBytes;
            }
        }
        catch (System.Net.WebException ex)
        {
            if (ex.Response is System.Net.FtpWebResponse ftpResponse)
            {
                switch (ftpResponse.StatusCode)
                {
                    case System.Net.FtpStatusCode.ActionNotTakenFileUnavailable:
                        return null; // 文件不存在
                    case System.Net.FtpStatusCode.NotLoggedIn:
                        throw new Exception("FTP认证失败,请检查用户名和密码");
                    case System.Net.FtpStatusCode.ActionNotTakenFilenameNotAllowed:
                        throw new Exception("文件名不被允许或路径无效");
                    default:
                        throw new Exception($"FTP错误 ({ftpResponse.StatusCode}): {ftpResponse.StatusDescription}");
                }
            }
            // 处理超时和网络错误
            if (ex.Status == System.Net.WebExceptionStatus.Timeout)
            {
                throw new Exception("FTP连接超时,请稍后重试");
            }
            throw new Exception($"FTP连接失败: {ex.Message}");
        }
        catch (Exception ex)
        {
            throw new Exception($"获取文件失败: {ex.Message}");
        }
    }
    private string NormalizeFtpServer(string ftpServer)
    {
        if (string.IsNullOrEmpty(ftpServer))
        {
            throw new ArgumentException("FTP服务器地址不能为空");
        }
        // 确保以ftp://开头
        string normalizedServer = ftpServer.StartsWith("ftp://") ? ftpServer : $"ftp://{ftpServer}";
        // 特殊处理已知服务器地址
        if (normalizedServer == "ftp://36.26.21.214")
        {
            normalizedServer = "ftp://36.26.21.214:21";
        }
        else if (!normalizedServer.Contains(":") && normalizedServer.StartsWith("ftp://"))
        {
            normalizedServer += ":21"; // 默认FTP端口
        }
        // 开发环境使用本地服务器
        normalizedServer = "ftp://192.168.1.22:21";
        return normalizedServer;
    }
    public string GetContentType(string fileName)
    {
        if (string.IsNullOrEmpty(fileName))
            return "application/octet-stream";
        var extension = System.IO.Path.GetExtension(fileName).ToLower();
        return extension switch
        {
            // PDF文件
            ".pdf" => "application/pdf",
            // 图片文件
            ".jpg" or ".jpeg" => "image/jpeg",
            ".png" => "image/png",
            ".gif" => "image/gif",
            ".bmp" => "image/bmp",
            ".webp" => "image/webp",
            ".svg" => "image/svg+xml",
            ".ico" => "image/x-icon",
            // 文本文件
            ".txt" => "text/plain; charset=utf-8",
            ".log" => "text/plain; charset=utf-8",
            ".md" => "text/markdown; charset=utf-8",
            ".csv" => "text/csv; charset=utf-8",
            ".xml" => "text/xml; charset=utf-8",
            ".json" => "application/json; charset=utf-8",
            // Office文档
            ".doc" => "application/msword",
            ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            ".xls" => "application/vnd.ms-excel",
            ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            ".ppt" => "application/vnd.ms-powerpoint",
            ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
            // 压缩文件
            ".zip" => "application/zip",
            ".rar" => "application/x-rar-compressed",
            ".7z" => "application/x-7z-compressed",
            // 其他常见格式
            ".dwg" => "application/acad",
            ".dxf" => "application/dxf",
            ".step" or ".stp" => "application/step",
            ".iges" or ".igs" => "application/iges",
            // 默认二进制流
            _ => "application/octet-stream"
        };
    }
    public int saveItem(LLJDto rkjDto)
    {
        var items = rkjDto.items;
@@ -305,7 +828,7 @@
                FcheckItemDesc = a.FspecRequ,
                Funit = a.Funit,
                Meom = a.Meom,
            }).ToList();
            }).OrderBy(a => SqlFunc.IIF(a.Fstand != null, 0, 1)).OrderBy(a => a.FcheckItem, OrderByType.Desc).ToList();
    }
    public int SetQSItemDetail(MesQaItemsDetectDetail12 detail)
@@ -558,32 +1081,52 @@
        return withOracle;
    }
    //主表修改备注字段
    //主表修改字段
    public int saveRemarksGid(LLJDto dto)
    {
        return SqlSugarHelper.UseTransactionWithOracle(db =>
        {
            return db.Updateable<MesQaItemsDetect01>()
                .SetColumns(it =>
                    it.FngDesc == dto.Remarks) //SetColumns是可以叠加的 写2个就2个字段赋值
                .SetColumns(it => it.FngDesc == dto.Remarks)
                .Where(it => it.ReleaseNo == dto.releaseNo)
                .ExecuteCommand();
        });
    }
    //主表修改破坏实验
    public int savePhsyGid(LLJDto dto)
    {
        return SqlSugarHelper.UseTransactionWithOracle(db =>
        {
            return db.Updateable<MesQaItemsDetect01>()
                .SetColumns(it => it.PHSY == dto.PHSY)
                .Where(it => it.ReleaseNo == dto.releaseNo)
                .ExecuteCommand();
        });
    }
    // 主表修改下拉框字段
    public int saveDropdownFields(LLJDto dto)
    {
        return SqlSugarHelper.UseTransactionWithOracle(db =>
        {
            return db.Updateable<MesQaItemsDetect01>()
                .SetColumns(it => it.BLYY == dto.BLYY)
                .SetColumns(it => it.PSZT == dto.PSZT)
                .SetColumns(it => it.SSCJ == dto.SSCJ)
                .Where(it => it.ReleaseNo == dto.releaseNo)
                .ExecuteCommand();
        });
    }
    //子表修改备注字段
    public int saveRemarksPid(LLJDto dto)
    {
        return SqlSugarHelper.UseTransactionWithOracle(db =>
        {
            return db.Updateable<MesQaItemsDetectDetail5>()
                 .SetColumns(it =>
                     it.Funit == dto.Remarks) //SetColumns是可以叠加的 写2个就2个字段赋值
                .Where(it => it.Id == dto.pid)
                .ExecuteCommand();
            return db.Updateable<MesQaItemsDetectDetail5>()
                 .SetColumns(it =>
                     it.Meom == dto.Meom)
                .SetColumns(it => new MesQaItemsDetectDetail5
                {
                    Funit = dto.Remarks,
                    Meom = dto.Meom
                })
                .Where(it => it.Id == dto.pid)
                .ExecuteCommand();
        });
@@ -690,4 +1233,293 @@
            throw new Exception(ex.Message);
        }
    }
    public List<MesItems> GetWomdab(string daa001)
    {
        //if (string.IsNullOrEmpty(ItemNo))
        //{
        // throw new ArgumentException("检验单号不能为空");
        //}
        var db = SqlSugarHelper.GetInstance();
        try
        {
            return db.Queryable<Womdab>()
                    .LeftJoin<MesItems>((w, m) => w.Dab003 == m.ItemId.ToString()) // 需要替换为实际的关联字段
                    .Where((w, m) => w.Dab001 == daa001)
                    .OrderBy((w, m) => w.Dab003, OrderByType.Desc)
                    // .ThenBy((w, m) => w.CreateDate, OrderByType.Desc)
                    .Select((w, m) => new MesItems
                    {
                           ItemNo = m.ItemNo,
                           ItemName = m.ItemName,
                           ItemModel = m.ItemModel
                    }).ToList();
        }
        catch (Exception ex)
        {
           throw new Exception($"查询附件信息失败: {ex.Message}");
        }
    }
    public List<MesItems> GetWomdabById(string daa001,string ItemNo)
    {
        //if (string.IsNullOrEmpty(ItemNo))
        //{
        // throw new ArgumentException("检验单号不能为空");
        //}
        var db = SqlSugarHelper.GetInstance();
        try
        {
            return db.Queryable<Womdab>()
                    .LeftJoin<MesItems>((w, m) => w.Dab003 == m.ItemId.ToString()) // 需要替换为实际的关联字段
                    .Where((w, m) => w.Dab001 == daa001 && m.ItemNo.Contains(ItemNo))
                    .OrderBy((w, m) => w.Dab003, OrderByType.Desc)
                    // .ThenBy((w, m) => w.CreateDate, OrderByType.Desc)
                    .Select((w, m) => new MesItems
                    {
                        ItemNo = m.ItemNo,
                        ItemName = m.ItemName,
                        ItemModel = m.ItemModel
                    }).ToList();
        }
        catch (Exception ex)
        {
            throw new Exception($"查询附件信息失败: {ex.Message}");
        }
    }
    /// <summary>
    /// 根据二维码查询物料信息
    /// </summary>
    /// <param name="itemBarcode">二维码内容</param>
    /// <param name="currentBillNo">当前检验单的到货单号(已废弃,保留参数兼容性)</param>
    /// <returns>物料信息</returns>
    public List<MaterialInfoDto> GetMaterialByBarcode(string itemBarcode, string currentBillNo)
    {
        var db = SqlSugarHelper.GetInstance();
        try
        {
            // 使用JOIN查询MES_INV_ITEM_BARCODES和MES_ITEMS表
            var materialInfo = db.Queryable<MesInvItemBarcodes>()
                .LeftJoin<MesItems>((b, m) => b.ItemId == m.Id)
                .Where((b, m) => b.ItemBarcode == itemBarcode && b.ComeFlg == 1)
                .Select((b, m) => new MaterialInfoDto
                {
                    ItemNo = b.ItemNo,        // 物料编码
                    OldQty = b.Oldqty,        // 数量
                    ItemId = b.ItemId,        // 物料ID
                    ItemName = m.ItemName,    // 物料名称
                    ItemModel = m.ItemModel,  // 规格型号
                    BillNo = b.BillNo         // 到货单号
                })
                .ToList();
            // 移除到货单号校验,直接返回查询结果
            return materialInfo;
        }
        catch (Exception ex)
        {
            throw new Exception($"查询物料信息失败: {ex.Message}");
        }
    }
    /// <summary>
    /// 查询破坏实验记录是否存在
    /// </summary>
    /// <param name="billNo">到货单号</param>
    /// <param name="releaseNo">检验单号</param>
    /// <returns>是否存在记录</returns>
    public bool CheckPhsyRecordExists(string billNo, string releaseNo)
    {
        var db = SqlSugarHelper.GetInstance();
        try
        {
            var count = db.Queryable<MesInvPhsy>()
                .Where(x => x.BillNo == billNo && x.ReleaseNo == releaseNo)
                .Count();
            return count > 0;
        }
        catch (Exception ex)
        {
            throw new Exception($"查询破坏实验记录失败: {ex.Message}");
        }
    }
    /// <summary>
    /// 获取破坏实验记录详细信息
    /// </summary>
    /// <param name="billNo">到货单号</param>
    /// <param name="releaseNo">检验单号</param>
    /// <returns>破坏实验记录信息</returns>
    public List<PhsyRecordInfoDto> GetPhsyRecordInfo(string billNo, string releaseNo)
    {
        var db = SqlSugarHelper.GetInstance();
        try
        {
            // 先查询破坏实验记录
            var phsyRecords = db.Queryable<MesInvPhsy>()
                .Where(x => x.BillNo == billNo && x.ReleaseNo == releaseNo)
                .ToList();
            var result = new List<PhsyRecordInfoDto>();
            foreach (var record in phsyRecords)
            {
                // 尝试通过条码查询物料信息
                var materialInfo = db.Queryable<MesInvItemBarcodes>()
                    .LeftJoin<MesItems>((b, m) => b.ItemId == m.Id)
                    .Where((b, m) => b.ItemBarcode == record.ItemBarcode)
                    .Select((b, m) => new {
                        ItemNo = b.ItemNo,
                        ItemName = m.ItemName,
                        ItemModel = m.ItemModel
                    })
                    .First();
                var dto = new PhsyRecordInfoDto
                {
                    ItemBarcode = record.ItemBarcode,
                    ItemNo = materialInfo?.ItemNo ?? record.ItemBarcode,
                    ItemName = materialInfo?.ItemName ?? "已记录物料",
                    ItemModel = materialInfo?.ItemModel ?? "已记录规格",
                    BillNo = record.BillNo,
                    Yqty = record.Yqty,
                    Cqty = record.Cqty,
                    CreateDate = record.CreateDate
                };
                result.Add(dto);
            }
            return result;
        }
        catch (Exception ex)
        {
            throw new Exception($"获取破坏实验记录信息失败: {ex.Message}");
        }
    }
    /// <summary>
    /// 调用破坏实验存储过程
    /// </summary>
    /// <param name="itemBarcode">扫描的条码值</param>
    /// <param name="yqty">扫码查询出来的条码数量</param>
    /// <param name="cqty">填写的破坏实验数量</param>
    /// <param name="billNo">查询到的到货单号</param>
    /// <param name="lx">操作类型:1新增,2修改,3删除</param>
    /// <param name="releaseNo">检验单号</param>
    /// <param name="itemId">物料ID</param>
    /// <returns>执行结果</returns>
    public (int result, string message) CallPhsyUpdateProcedure(string itemBarcode, decimal yqty, decimal cqty, string billNo, int lx, string releaseNo, decimal? itemId = null)
    {
        var db = SqlSugarHelper.GetInstance();
        try
        {
            // 定义输入参数
            var inputParam1 = new SugarParameter("P_ITEM_BARCODE", itemBarcode, DbType.String, ParameterDirection.Input);
            var inputParam2 = new SugarParameter("P_YQTY", yqty, DbType.Decimal, ParameterDirection.Input);
            var inputParam3 = new SugarParameter("P_CQTY", cqty, DbType.Decimal, ParameterDirection.Input);
            var inputParam4 = new SugarParameter("P_BILL_NO", billNo, DbType.String, ParameterDirection.Input);
            var inputParam5 = new SugarParameter("P_LX", lx, DbType.Int32, ParameterDirection.Input);
            var inputParam6 = new SugarParameter("ITEM_ID", itemId ?? 0, DbType.Decimal, ParameterDirection.Input);
            var inputParam7 = new SugarParameter("P_RELEASE_NO", releaseNo, DbType.String, ParameterDirection.Input);
            // 定义输出参数
            var outputResult = new SugarParameter("PO_RESULT", null, DbType.Int32, ParameterDirection.Output);
            var outputMessage = new SugarParameter("PO_MSG", null, DbType.String, ParameterDirection.Output, 4000);
            // 使用SqlSugar执行存储过程
            db.Ado.ExecuteCommand("BEGIN PRC_INV_PHSYUPDATE(:P_ITEM_BARCODE, :P_YQTY, :P_CQTY, :P_BILL_NO, :P_LX, :ITEM_ID, :P_RELEASE_NO, :PO_RESULT, :PO_MSG); END;",
                inputParam1, inputParam2, inputParam3, inputParam4, inputParam5, inputParam6, inputParam7, outputResult, outputMessage);
            // 获取输出参数的值
            var result = outputResult.Value == null ? 1 : Convert.ToInt32(outputResult.Value);
            var message = outputMessage.Value?.ToString() ?? "";
            return (result, message);
        }
        catch (Exception ex)
        {
            return (1, $"调用存储过程失败: {ex.Message}");
        }
    }
    /// <summary>
    /// 设置堵穴信息
    /// </summary>
    /// <param name="releaseNo">检验单号</param>
    /// <param name="blockedHoles">堵穴信息,格式如"1,2,3"</param>
    /// <param name="itemId">检验项目ID</param>
    /// <returns>执行结果</returns>
    public (int result, string message) SetBlockedHoles(string releaseNo, string blockedHoles, decimal itemId)
    {
        var db = SqlSugarHelper.GetInstance();
        try
        {
            // 解析堵穴信息
            var blockedHolesList = blockedHoles.Split(',', ',')
                .Select(s => s.Trim())
                .Where(s => !string.IsNullOrEmpty(s))
                .Select(s => int.Parse(s))
                .ToList();
            // 获取检验项目信息
            var item = db.Queryable<MesQaItemsDetectDetail5>()
                .Where(x => x.Id == itemId && x.ReleaseNo == releaseNo)
                .First();
            if (item == null)
            {
                return (1, "检验项目不存在");
            }
            // 解析开穴数
            var holeCount = ParseHoleCount(item.FcheckItem);
            if (holeCount == 0)
            {
                return (1, "该检验项目没有穴数信息");
            }
            // 验证堵穴数量不能大于等于开穴数
            if (blockedHolesList.Count >= holeCount)
            {
                return (1, $"堵穴数量不能大于等于开穴数({holeCount})");
            }
            // 验证堵穴号是否在有效范围内
            foreach (var hole in blockedHolesList)
            {
                if (hole < 1 || hole > holeCount)
                {
                    return (1, $"堵穴号必须在1-{holeCount}之间");
                }
            }
            // 计算新的检验数量
            var newCheckQyt = item.CheckQyt - (item.CheckQyt / holeCount) * blockedHolesList.Count;
            // 更新数据库
            var result = SqlSugarHelper.UseTransactionWithOracle(db =>
            {
                return db.Updateable<MesQaItemsDetectDetail5>()
                    .SetColumns(x => x.Dnum == blockedHoles)
                    .SetColumns(x => x.CheckQyt == newCheckQyt)
                    .Where(x => x.Id == itemId && x.ReleaseNo == releaseNo)
                    .ExecuteCommand();
            });
            if (result > 0)
            {
                return (0, "堵穴设置成功");
            }
            else
            {
                return (1, "堵穴设置失败");
            }
        }
        catch (Exception ex)
        {
            return (1, $"设置堵穴失败: {ex.Message}");
        }
    }
    /// <summary>
    /// 解析检验项目名称中的穴数
    /// </summary>
    /// <param name="checkItemName">检验项目名称</param>
    /// <returns>穴数,如果没有穴数信息返回0</returns>
    private int ParseHoleCount(string checkItemName)
    {
        if (string.IsNullOrEmpty(checkItemName))
            return 0;
        // 匹配格式:尺寸检查(5穴)或 尺寸检查(5穴)
        var match = System.Text.RegularExpressions.Regex.Match(checkItemName, @"[((](\d+)穴[))]");
        return match.Success ? int.Parse(match.Groups[1].Value) : 0;
    }
}