kazelee
2025-05-20 ef839d119eec2c28fac5f5ba175d71f926afae44
修复数据库表字段不匹配、读取重量错误处理等逻辑
3个文件已添加
15个文件已修改
4个文件已删除
412 ■■■■ 已修改文件
.vs/HH.WCS.Mobox3.AnGang/FileContentIndex/05336dc4-4629-4a97-bb9a-4516a380cd0d.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
.vs/HH.WCS.Mobox3.AnGang/FileContentIndex/0aee5537-94af-4049-9107-4c61afb239ee.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
.vs/HH.WCS.Mobox3.AnGang/FileContentIndex/7e201a71-d554-4ded-906f-7da951526801.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
.vs/HH.WCS.Mobox3.AnGang/FileContentIndex/bd85daa8-32a5-4c87-9f8f-b1ed513fa1f8.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
Consts/AreaCode.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Consts/AreaName.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Consts/TaskName.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Controllers/DebugController.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Dtos/Request/MoboxRequest.cs 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3.AnGang.csproj 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Helpers/DbHelper.cs 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Helpers/PathHelper.cs 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Helpers/TaskHelper.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Helpers/WCSHelper.cs 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Models/TN_CG_Detail.cs 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Models/TN_Location.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Models/TN_Task.cs 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Services/AgvService.cs 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Services/DebugService.cs 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Services/MoboxService.cs 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
config/config.comment.json 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
config/config.json 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.vs/HH.WCS.Mobox3.AnGang/FileContentIndex/05336dc4-4629-4a97-bb9a-4516a380cd0d.vsidx
Binary files differ
.vs/HH.WCS.Mobox3.AnGang/FileContentIndex/0aee5537-94af-4049-9107-4c61afb239ee.vsidx
Binary files differ
.vs/HH.WCS.Mobox3.AnGang/FileContentIndex/7e201a71-d554-4ded-906f-7da951526801.vsidx
Binary files differ
.vs/HH.WCS.Mobox3.AnGang/FileContentIndex/bd85daa8-32a5-4c87-9f8f-b1ed513fa1f8.vsidx
Binary files differ
Consts/AreaCode.cs
@@ -6,6 +6,7 @@
namespace HH.WCS.Mobox3.AnGang.Consts {
    public class AreaCode {
        public const string 收发货位区 = "P";
        public const string 收发区 = "SFQ";
        public const string 货架区 = "HJQ";
    }
}
Consts/AreaName.cs
File was deleted
Consts/TaskName.cs
@@ -6,7 +6,7 @@
namespace HH.WCS.Mobox3.AnGang.Consts {
    public class TaskName {
        public const string 货品入库 = "货品入库";
        public const string 产品入库 = "产品入库";
        public const string 产品部分出库 = "产品部分出库";
        public const string 产品部分回库 = "产品部分回库";
        public const string 盘点理货出库 = "盘点理货出库";
Controllers/DebugController.cs
@@ -19,6 +19,7 @@
using HH.WCS.Mobox3.AnGang.Debug;
using static HH.WCS.Mobox3.AnGang.Dtos.Request.DebugRequest;
using static HH.WCS.Mobox3.AnGang.Dtos.Response.DebugResponse;
using static HH.WCS.Mobox3.AnGang.Models.DebugModel;
namespace HH.WCS.Mobox3.AnGang.Controllers
{
@@ -55,8 +56,8 @@
        /// <returns></returns>
        [HttpPost]
        [Route("InsertLocCntrCg")]
        public string InsertLocCntrCg() {
            return DebugService.InsertLocCntrCg();
        public string InsertLocCntrCg(LocCntrCg model) {
            return DebugService.InsertLocCntrCg(model);
        }
        [HttpPost]
Dtos/Request/MoboxRequest.cs
@@ -35,22 +35,17 @@
            /// 起点货位
            /// </summary>
            [JsonProperty("StartLoc")]
            public string startLoc { get; set; }
            public string StartLoc { get; set; }
            /// <summary>
            /// 终点货架(可选)
            /// </summary>
            [JsonProperty("Nrow")]
            public string endShelf { get; set; }
            public string Row { get; set; }
        }
        public class SelectLocationInfo {
            public string forklift_no { get; set; }
            ///// <summary>
            ///// 任务号
            ///// </summary>
            //public string taskNo { get; set; }
            public string endLoc { get; set; }
        }
HH.WCS.Mobox3.AnGang.csproj
@@ -261,7 +261,6 @@
    <Compile Include="Consts\AgvStateCode.cs" />
    <Compile Include="Consts\AgvStateName.cs" />
    <Compile Include="Consts\AreaCode.cs" />
    <Compile Include="Consts\AreaName.cs" />
    <Compile Include="Consts\LockStateCode.cs" />
    <Compile Include="Consts\LockStateName.cs" />
    <Compile Include="Consts\TaskName.cs" />
@@ -279,7 +278,6 @@
    <Compile Include="Dtos\Response\ErpResponse.cs" />
    <Compile Include="Helpers\AgvHelper.cs" />
    <Compile Include="Helpers\DbHelper.cs" />
    <Compile Include="Helpers\PathHelper.cs" />
    <Compile Include="Models\DebugModel.cs" />
    <Compile Include="Models\TN_Inbound_Order.cs" />
    <Compile Include="Models\TN_Outbound_Order.cs" />
@@ -333,6 +331,7 @@
  <ItemGroup>
    <None Include=".editorconfig" />
    <None Include="App.config" />
    <None Include="config\config.comment.json" />
    <None Include="config\config.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
@@ -364,8 +363,6 @@
      <Name>NetSDKCS</Name>
    </ProjectReference>
  </ItemGroup>
  <ItemGroup>
    <Folder Include="debug\" />
  </ItemGroup>
  <ItemGroup />
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Helpers/DbHelper.cs
@@ -14,9 +14,13 @@
    /// 数据库帮助类:包括单例模式和创建新连接的方法
    /// </summary>
    public static class DbHelper {
        private static readonly SqlSugarScope _sqlSugar;
        private static SqlSugarScope _sqlSugar;
        static DbHelper() {
            Init();
        }
        public static void Init() {
            _sqlSugar = new SqlSugarScope(new ConnectionConfig() {
                ConnectionString = Settings.Config.SqlServer,
                DbType = DbType.SqlServer,
@@ -25,8 +29,7 @@
            },
            db => {
                // 监控所有超过1秒的Sql
                db.Aop.OnLogExecuted = (sql, p) =>
                {
                db.Aop.OnLogExecuted = (sql, p) => {
                    // 执行时间超过1秒
                    if (db.Ado.SqlExecutionTime.TotalSeconds > 1) {
                        Console.WriteLine(sql + "\r\n" + db.Utilities.SerializeObject(p.ToDictionary(it => it.ParameterName, it => it.Value)));
Helpers/PathHelper.cs
File was deleted
Helpers/TaskHelper.cs
@@ -24,7 +24,7 @@
        /// <param name="mst"></param>
        /// <param name="load"></param>
        internal static void CacheBitUpdate(TN_Task mst, bool load) {
            var trayCarryCount = mst.N_CNTR_COUNT > 0 ? mst.N_CNTR_COUNT : 1;
            //var trayCarryCount = mst.N_CNTR_COUNT > 0 ? mst.N_CNTR_COUNT : 1;
            if (load) {
                Console.WriteLine($"任务{mst.S_CODE} 货位{mst.S_START_LOC}取货完成,起点解绑容器{mst.S_CNTR_CODE}");
                LogHelper.Info($"任务{mst.S_CODE} 货位{mst.S_START_LOC}取货完成,起点解绑容器{mst.S_CNTR_CODE}");
Helpers/WCSHelper.cs
@@ -7,6 +7,7 @@
using System.Text;
using System.Threading.Tasks;
using HH.WCS.Mobox3.AnGang.Helpers;
using HH.WCS.Mobox3.AnGang.Consts;
namespace HH.WCS.Mobox3.AnGang.Helper {
    internal class WCSHelper {
@@ -60,11 +61,25 @@
        {
            var fromLoc = LocationHelper.GetLocation(from);
            var endLoc = LocationHelper.GetLocation(to);
            var endArea = "";
            if (endLoc == null) {
                if (taskType == TaskName.产品入库) {
                    endArea = "HJQ"; // 货架区
                }
                else {
                    LogHelper.Info("终点货位不存在,且任务类型不是PDA货品入库");
                }
            }
            else {
                endArea = endLoc.S_AREA_CODE;
            }
            TN_Task TN_Task = new TN_Task()
            {
                S_CODE = GenerateTaskNo(),
                S_START_AREA = fromLoc.S_AREA_CODE,
                S_END_AREA = endLoc?.S_AREA_CODE ?? "", // 如果为null返回空字符串
                S_END_AREA = endArea,
                S_START_LOC = from,
                S_END_LOC = to,
                S_TYPE = taskType,
@@ -83,43 +98,6 @@
            }
            else
            {
                LogHelper.Info($"插入任务失败,{log}");
            }
            return res;
        }
        /// <summary>
        /// 根据终点Area创建搬送任务
        /// </summary>
        /// <param name="from"></param>
        /// <param name="toArea"></param>
        /// <param name="taskType"></param>
        /// <param name="pri"></param>
        /// <param name="cntrInfo"></param>
        /// <returns></returns>
        internal static bool CreateTaskWithArea(string from, string toArea, string taskType, int pri, string cntrInfo) {
            var fromLoc = LocationHelper.GetLocation(from);
            //var endLoc = LocationHelper.GetLocation(to);
            TN_Task TN_Task = new TN_Task() {
                S_CODE = GenerateTaskNo(),
                S_START_AREA = fromLoc.S_AREA_CODE,
                S_END_AREA = toArea,
                S_START_LOC = from,
                S_END_LOC = "", // 不指定终点货位
                S_TYPE = taskType,
                N_PRIORITY = pri,
                N_SCHEDULE_TYPE = 3, // 国自
                N_B_STATE = 0,
                S_CNTR_CODE = cntrInfo,
            };
            var log = JsonConvert.SerializeObject(TN_Task);
            var db = DbHelper.GetDbClient();
            var res = db.Insertable(TN_Task).ExecuteCommand() > 0;
            if (res) {
                LogHelper.Info($"插入任务成功,{log}");
            }
            else {
                LogHelper.Info($"插入任务失败,{log}");
            }
            return res;
Models/TN_CG_Detail.cs
@@ -13,37 +13,35 @@
        /// <summary>
        /// 货品 ID
        /// </summary>
        public string S_CG_ID { get; set; }
        public string S_CG_ID { get; set; } = "";
        public string S_CAR_CODE { get; set; }//车号
        public string S_CNTR_CODE { get; set; } = "";//容器编码
       
        public string S_CNTR_CODE { get; set; }//容器编码
        public string S_ITEM_CODE { get; set; } = "";//货品编码
        public string S_ITEM_CODE { get; set; }//货品编码
        public string S_ITEM_SPEC { get; set; }//货品规格
        public string S_ITEM_SPEC { get; set; } = "";//货品规格
        /// <summary>
        /// 货品状态:0合格 1待检 2不合格 3正在检验;下线即待检
        /// </summary>
        public string S_ITEM_STATE { get; set; }
        public string S_ITEM_STATE { get; set; } = "待检";
        /// <summary>
        /// 货品状态_字典:0合格 1待检 2不合格 3正在检验;下线即待检
        /// </summary>
        public int N_ITEM_STATE { get; set; }
        public int N_ITEM_STATE { get; set; } = 1;
        public string S_BATCH_NO { get; set; }//批次号
        public string S_BATCH_NO { get; set; } = ""; //批次号
        
        public float F_QTY { get; set; }//数量
        /// <summary>
        /// 数量:这里当做重量
        /// </summary>
        public float F_QTY { get; set; } = 0f;
        public string S_SPE { get; set; }//规格
        /// <summary>
        /// 图片链接
        /// </summary>
        public string S_IMG_URL { get; set; }
        public string S_IMG_URL { get; set; } = "";
    }
}
Models/TN_Location.cs
@@ -13,7 +13,7 @@
        /// <summary>
        /// 货位名称
        /// </summary>
        public string S_NAME { get; set; }
        public string S_NAME { get; set; } = "";
        /// <summary>
        /// 货位所在区域 ID
@@ -23,7 +23,7 @@
        /// <summary>
        /// 国自 AGV 对应的库位名称
        /// </summary>
        public string S_AGV_SITE { get; set; }
        public string S_AGV_SITE { get; set; } = "";
        /// <summary>
        /// 货位容量
@@ -58,7 +58,7 @@
        /// <summary>
        /// 锁的来源-任务号
        /// </summary>
        public string S_LOCK_OP { get; set; }
        public string S_LOCK_OP { get; set; } = "";
        [Navigate(NavigateType.OneToMany, nameof(TN_Loc_Container.S_LOC_CODE))]
        public List<TN_Loc_Container> LocCntrRels { get; set; }
@@ -77,6 +77,6 @@
        /// <summary>
        /// 货架编码
        /// </summary>
        public string S_SHELF_CODE { get; set; }
        public int N_ROW { get; set; }
    }
}
Models/TN_Task.cs
@@ -15,7 +15,7 @@
        /// <summary>
        /// AGV 车号
        /// </summary>
        public string S_EQ_NO { get; set; }
        public string S_EQ_NO { get; set; } = "";
        public string S_TYPE { get; set; }
        public string S_B_STATE { get; set; } = "等待";
        /// <summary>
@@ -33,15 +33,15 @@
        public string S_CODE { get; set; }
        public string S_EQ_TASK_CODE { get; set; }
        public string S_CNTR_CODE { get; set; }
        public string S_OP_NAME { get; set; }
        public string S_CNTR_CODE { get; set; } = "";
        public string S_OP_NAME { get; set; } = "";
    
        public int N_CNTR_COUNT { get; internal set; }
        //public int N_CNTR_COUNT { get; internal set; }
        /// <summary>
        /// 任务的货物重量
        /// </summary>
        public float F_WEIGHT { get; set; }
        ///// <summary>
        ///// 任务的货物重量
        ///// </summary>
        //public float F_WEIGHT { get; set; }
        internal static string GetStateStr(int state) {
            //0等待      1已推送        2执行    3完成    4错误
Services/AgvService.cs
@@ -46,7 +46,7 @@
                result.ResultCode = 0;
                result.ResultMsg = "success";
                LogHelper.Info(result.ResultMsg, "API");
                LogHelper.Info(result.ResultMsg + $": state {model.state}", "API");
                return result;
            }
            catch (Exception ex) {
@@ -85,14 +85,14 @@
                    WCSHelper.UpdateStatus(TN_Task, "取货完成"); // 任务状态改成取货完成
                    var captureTask = Task.Run(() => {
                        if (TN_Task.S_TYPE == TaskName.货品入库 || TN_Task.S_TYPE == TaskName.产品部分回库) {
                        if (TN_Task.S_TYPE == TaskName.产品入库 || TN_Task.S_TYPE == TaskName.产品部分回库) {
                            CapturePic(TN_Task);
                        }
                    });
                    var setEndLocTask = Task.Run(() => {
                        // 只要任务为产品入库(PDA),就需要重新指定终点(默认endLoc为"")
                        if (TN_Task.S_TYPE == "产品入库(PDA)") {
                        if (TN_Task.S_TYPE == TaskName.产品入库) {
                            SetEndLoc(TN_Task);
                        }
                    });
@@ -126,6 +126,7 @@
            var filepath = SnapManager.GetCapturePicturePath();
            if (string.IsNullOrEmpty(filepath)) {
                LogHelper.Info("图片地址为空");
                return;
            }
@@ -140,50 +141,73 @@
        public static void SetEndLoc(TN_Task tn_task) {
            var db = DbHelper.GetDbClient();
            var endLoc = new TN_Location();
            var endLoc = db.Queryable<TN_Location>()
                .First(a => a.S_CODE == tn_task.S_END_LOC);
            // 如果已经设置的终点货位,就不要再进入这个流程
            if (endLoc != null) {
                LogHelper.Info("已经设置了终点货位:" + JsonConvert.SerializeObject(endLoc));
                return;
            }
            var cgDetail = db.Queryable<TN_CG_Detail>()
                .Where(d => d.S_CNTR_CODE == tn_task.S_CNTR_CODE).First();
            if (cgDetail == null) {
                LogHelper.Info("设置终点货位失败:当前任务的托盘号在物料表中不存在");
                return;
            }
            var data = GZRobot.CustomBuf();
            if (data.Count == 0) {
                LogHelper.Info("设置终点货位失败:没有接受到来自国自AGV的重量信息");
                //return;
                //return; // TODO 正式运行有国自AGV的时候恢复
            }
            else {
                var weight = float.Parse(data[0].parameter_varchar200_up);
                tn_task.F_WEIGHT = weight;
                cgDetail.F_QTY = weight;
                if (db.Updateable<TN_Task>(tn_task).UpdateColumns(it => it.F_WEIGHT).ExecuteCommand() <= 0) {
                    LogHelper.Info("修改Task重量失败");
                if (db.Updateable<TN_CG_Detail>(cgDetail).UpdateColumns(it => it.F_QTY).ExecuteCommand() <= 0) {
                    LogHelper.Info("修改物料表重量失败");
                    return;
                }
            }
            // 终点货架为空时,不判断,交给人工处理
            if (tn_task.S_END_AREA == "") {
            if (tn_task.S_END_LOC == "0") {
                LogHelper.Info("终点货架为空,不处理");
                return;
            }
            if (!int.TryParse(tn_task.S_END_LOC.Trim(), out int row)) {
                LogHelper.Info($"终点货架号 '{tn_task.S_END_LOC}' 无法转成数字");
                return;
            }
            // 只当之前指定终点货架后,才尝试计算终点货位
            if (tn_task.F_WEIGHT > 1500) {
            if (cgDetail.F_QTY > 1500) {
                // 重量超过1.5t,需要选择1-3层货架
                endLoc = db.Queryable<TN_Location>().First(a => a.S_SHELF_CODE == tn_task.S_END_AREA && LocationHelper.IsFree(a) && a.N_CURRENT_NUM == 0 && a.N_LAYER <= 3);
                endLoc = db.Queryable<TN_Location>()
                    .First(a => a.N_ROW == row && a.N_LAYER <= 3
                    && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y");
            }
            else if (tn_task.F_WEIGHT > 0) {
            else if (cgDetail.F_QTY > 0) {
                // 重量未超过1.5t,在指定货架随便选择1个
                endLoc = db.Queryable<TN_Location>().First(a => a.S_SHELF_CODE == tn_task.S_END_AREA && LocationHelper.IsFree(a) && a.N_CURRENT_NUM == 0);
                endLoc = db.Queryable<TN_Location>().First(a => a.N_ROW == row
                    && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y");
            }
            else {
                // 没有接收到重量,或重量出错
                endLoc = null;
                LogHelper.Info($"错误的重量信息:{tn_task.F_WEIGHT}");
                LogHelper.Info($"错误的重量信息:{cgDetail.F_QTY}");
                return;
            }
            // 如果没有符合条件的货位,置空,等待PDA重新确定
            if (endLoc == null) {
                tn_task.S_END_AREA = "";
                tn_task.S_END_LOC = "";
                tn_task.S_END_AREA = "HJQ";
                tn_task.S_END_LOC = "0";
                // 不需要再给GZ AGV传空值,一开始就没给具体货位,只给了Area
@@ -196,16 +220,16 @@
                //GZRobot.UpdateInteractInfo(request);
                using (var trans = db.Ado.UseTran()) {
                    if (db.Updateable<TN_Task>(tn_task).UpdateColumns(it => new { it.S_END_LOC, it.F_WEIGHT })
                    if (db.Updateable<TN_Task>(tn_task).UpdateColumns(it => new { it.S_END_LOC })
                        .ExecuteCommand() > 0) {
                        //LocationHelper.LockLoc(endLoc.S_CODE, 1);//终点入库锁
                        trans.CommitTran();
                        LogHelper.Info($"重新计算后没有合适货位,任务 {tn_task.S_CODE} 修改成功,修改终点货架和货位为空");
                        LogHelper.Info($"重新计算后没有合适货位,任务 {tn_task.S_CODE} 修改成功,修改终点货位为 0空");
                    }
                    else {
                        trans.RollbackTran();
                        LogHelper.Info($"重新计算后没有合适货位,任务 {tn_task.S_CODE} 修改失败,修改终点货架和货位为空");
                        LogHelper.Info($"重新计算后没有合适货位,任务 {tn_task.S_CODE} 修改失败,修改终点货位为 0空");
                    }
                }
            }
@@ -214,17 +238,17 @@
                tn_task.S_END_LOC = endLoc.S_CODE;
                using (var trans = db.Ado.UseTran()) {
                    if (db.Updateable<TN_Task>(tn_task).UpdateColumns(it => new { it.S_END_LOC, it.F_WEIGHT })
                    if (db.Updateable<TN_Task>(tn_task).UpdateColumns(it => new { it.S_END_LOC })
                        .ExecuteCommand() > 0) {
                        LocationHelper.LockLoc(endLoc.S_CODE, 1);//终点入库锁
                        trans.CommitTran();
                        LogHelper.Info($"计算货位成功,任务 {tn_task.S_CODE} 修改成功,终点货架为 {endLoc.S_SHELF_CODE},修改终点位置为 {endLoc.S_CODE}");
                        LogHelper.Info($"计算货位成功,任务 {tn_task.S_CODE} 修改成功,终点货架为 {endLoc.N_ROW},修改终点位置为 {endLoc.S_CODE}");
                    }
                    else {
                        trans.RollbackTran();
                        LogHelper.Info($"计算货位成功,任务 {tn_task.S_CODE} 修改失败,终点货架为 {endLoc.S_SHELF_CODE},修改终点位置为 {endLoc.S_CODE}");
                        LogHelper.Info($"计算货位成功,任务 {tn_task.S_CODE} 修改失败,终点货架为 {endLoc.N_ROW},修改终点位置为 {endLoc.S_CODE}");
                    }
                }
            }
Services/DebugService.cs
@@ -125,32 +125,15 @@
            return "成功";
        }
        public static string InsertLocCntrCg() {
            string filePath = PathHelper.GetProjDir("./debug/loc_cntr_cg.csv");
        public static string InsertLocCntrCg(LocCntrCg locCntrCg) {
            var db = DbHelper.GetDbClient();
            try {
                var configuration = new CsvConfiguration(CultureInfo.InvariantCulture) {
                    // 配置选项
                    Delimiter = ",",               // 分隔符
                    HasHeaderRecord = true,        // 有标题行
                    MissingFieldFound = null,      // 忽略缺失字段
                    HeaderValidated = null,        // 跳过标题验证
                    BadDataFound = context => { }  // 处理错误数据
                };
                var locCntrCgList = new List<LocCntrCg>();
                using (var reader = new StreamReader(filePath))
                using (var csv = new CsvReader(reader, configuration)) {
                    // 读取记录
                    locCntrCgList = csv.GetRecords<LocCntrCg>().ToList();
                }
                using (var tran = db.UseTran()) {
                    foreach (var locCntrCg in locCntrCgList) {
                        LogHelper.Info("LogCntrCg:" + JsonConvert.SerializeObject(locCntrCg));
                        if (string.IsNullOrEmpty(locCntrCg.LocCode)) break;
                    if (string.IsNullOrEmpty(locCntrCg.LocCode)) {
                        return "参数非法";
                    }
                        var loc = db.Queryable<TN_Location>().First(a => a.S_CODE == locCntrCg.LocCode);
                        if (loc == null) {
@@ -179,8 +162,9 @@
                        //}
                        if (string.IsNullOrEmpty(locCntrCg.CntrCode)) {
                        tran.CommitTran();
                            LogHelper.Info("容器号为空,不再读取后面的数据");
                            continue;
                        return "容器号为空,不再读取后面的数据";
                        }
                        var locCntrRel = db.Queryable<TN_Loc_Container>().First(a => a.S_LOC_CODE == locCntrCg.LocCode
@@ -203,8 +187,9 @@
                        }
                        if (string.IsNullOrEmpty(locCntrCg.ItemCode)) {
                        tran.CommitTran();
                            LogHelper.Info("物料号为空,不再读取后面的数据");
                            continue;
                        return "物料号为空,不再读取后面的数据";
                        }
                        var cgDetail = db.Queryable<TN_CG_Detail>().First(a => a.S_CNTR_CODE == locCntrCg.CntrCode
@@ -218,26 +203,30 @@
                                return "插入失败";
                            }
                        }
                    }
                    tran.CommitTran();
                }
                return "插入数据成功";
            }
            catch (FileNotFoundException) {
                return $"Error: File not found - {filePath}";
            }
            catch (Exception ex) {
                return $"Error reading CSV file: {ex.Message}";
                return $"{ex.Message}";
            }
        }
        public static string SetTaskWeight(SetTaskWeightInfo model) {
            var db = DbHelper.GetDbClient();
            var cgDetail = db.Queryable<TN_CG_Detail, TN_Task>((d, t) => d.S_CNTR_CODE == t.S_CNTR_CODE)
                .Where((d, t) => t.S_CODE == model.TaskNo).First();
            if (cgDetail == null) {
                return "找不到对应的物料信息";
            }
            cgDetail.F_QTY = model.Weight;
            try {
                if (db.Updateable<TN_Task>().SetColumns(it => it.F_WEIGHT == model.Weight).Where(it => it.S_CODE == model.TaskNo)
                if (db.Updateable<TN_CG_Detail>(cgDetail).UpdateColumns(it => it.F_QTY)
                    .ExecuteCommand() <= 0 ) {
                    return "修改失败";
                }
Services/MoboxService.cs
@@ -24,22 +24,17 @@
            LogHelper.Info("触发API:产品入库(PDA)" + JsonConvert.SerializeObject(model), "API");
            var db = DbHelper.GetDbClient();
            var startLoc = new TN_Location();
            //var endLoc = new TN_Location();
            try {
                // 起点位置必须:为空、无锁、启用、属于收发区域
                startLoc = db.Queryable<TN_Location>().
                    First(a => a.S_CODE == model.startLoc && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.S_SHELF_CODE == AreaCode.收发货位区);
                    First(a => a.S_CODE == model.StartLoc
                    && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y"
                    && a.S_AREA_CODE == AreaCode.收发区);
                if (startLoc == null) {
                    return BuildSimpleResult(1, $"起点位置{model.startLoc}不存在!");
                    return BuildSimpleResult(1, $"起点位置{model.StartLoc}不存在!");
                }
                //if (!LocationHelper.IsStartLocationTransferOk(model.startLoc,
                //    a => a.S_SHELF_CODE == Settings.Areas[0],
                //    out startLoc)) {
                //    return BuildSimpleResult(1, $"起点位置{model.startLoc}不存在!");
                //}
                // 容器 ID 和 物料 ID 未指定,由系统直接生成
                var cntID = Guid.NewGuid().ToString("D");
@@ -55,14 +50,17 @@
                    S_CNTR_CODE = cntID,
                };
                var endArea = ""; // 默认终点区域为空
                var endLoc = "0"; // 假的默认终点地址
                // 指定货位排号(不能为空、空字符串或空格)
                if (model.endShelf != null && model.endShelf.Trim() != "") {
                    endArea = model.endShelf;
                    // 没有在配置文件找到这个货架号
                    if (!Settings.AreaMap[AreaName.货架区].Contains(endArea)) {
                        return BuildSimpleResult(2, $"货架号 {model.endShelf} 不存在");
                if (model.Row != null && model.Row.Trim() != "") {
                    endLoc = model.Row; // 用排号字符串当做假地址
                    if (!int.TryParse(model.Row.Trim(), out int row)) {
                        return BuildSimpleResult(2, $"{model.Row} 不合法:无法转成整数类型");
                    }
                    // 货架排号只能是 0 - 8
                    if (row <= 0 || row > 8) {
                        return BuildSimpleResult(2, $"货架号 {model.Row} 必须是1-8之间的整数");
                    }
                }
@@ -71,19 +69,19 @@
                    if (db.Insertable<TN_Loc_Container>(cntLoc).ExecuteCommand() > 0
                        && db.Insertable<TN_CG_Detail>(cgCnt).ExecuteCommand() > 0) {
                        //创建产品入库任务:创建搬送任务,起点终点容器
                        if (WCSHelper.CreateTaskWithArea(startLoc.S_CODE, endArea, "产品入库(PDA)", 3, cntID)) {
                        if (WCSHelper.CreateTask(startLoc.S_CODE, endLoc, TaskName.产品入库, 3, cntID)) {
                            //如果操作TN_Location会造成死锁
                            LocationHelper.LockLoc(startLoc.S_CODE, 2);//起点出库锁,
                            //LocationHelper.LockLoc(endLoc.S_CODE, 1);//终点入库锁
                            trans.CommitTran();
                            return BuildSimpleResult(0, $"生成 产品入库(PDA) 成功,容器号 {cntID} ,起点 {startLoc.S_CODE} ,终点货架 {endArea} ,终点货位未指定");
                            return BuildSimpleResult(0, $"生成 产品入库 成功,容器号 {cntID} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc} ,终点货位未指定");
                        }
                        else {
                            trans.RollbackTran();
                            return BuildSimpleResult(5, $"生成 产品入库(PDA) 失败,容器号 {cntID} ,起点 {startLoc.S_CODE} ,终点货架 {endArea} ,终点货位未指定");
                            return BuildSimpleResult(5, $"生成 产品入库 失败,容器号 {cntID} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc} ,终点货位未指定");
                        }
                    }
                    else {
@@ -107,36 +105,50 @@
            try {
                // 任务号存在:终点货架和终点位置为空,且任务为产品入库(PDA)
                //var task = db.Queryable<TN_Task>().First(a => a.S_CODE == model.taskNo && a.S_END_AREA == "" && a.S_END_LOC == "" && a.S_TYPE == "产品入库(PDA)");
                var task = db.Queryable<TN_Task>().First(a => a.S_EQ_NO == model.forklift_no && a.S_END_AREA == "" && a.S_END_LOC == "" && a.S_TYPE == "产品入库(PDA)");
                //var task = db.Queryable<TN_Task>().First(a => a.S_EQ_NO == model.forklift_no && a.S_END_AREA == "HJQ" && a.S_END_LOC == "0" && a.S_TYPE == "产品入库(PDA)");
                var task = db.Queryable<TN_Task>()
                    .Where(a => a.S_B_STATE == "取货完成" && a.S_TYPE == TaskName.产品入库)
                    .OrderBy(a => a.T_CREATE, SqlSugar.OrderByType.Desc).First();
                
                if (task == null) {
                    //return BuildSimpleResult(2, $"任务号 {model.taskNo} 不存在,或不满足终点货架为空、终点位置为空且为 产品入库(PDA) 任务");
                    return BuildSimpleResult(2, $"小车 '{model.forklift_no}' 当前不存在任务,或不满足终点货架为空、终点位置为空且为 产品入库(PDA) 任务");
                    return BuildSimpleResult(2, $"当前不存在状态为 取货完成 的 产品入库 任务");
                }
                if (task.S_END_LOC != null && task.S_END_LOC != "0") {
                    return BuildSimpleResult(3, $"该任务已有终点");
                }
                var cgDetail = db.Queryable<TN_CG_Detail>()
                    .Where(a => a.S_CNTR_CODE == task.S_CNTR_CODE).First();
                if (cgDetail == null) {
                    return BuildSimpleResult(4, $"托盘物料不存在");
                }
                var endLoc = new TN_Location();
                if (task.F_WEIGHT > 1500) {
                if (cgDetail.F_QTY > 1500) {
                    // 重量超过1.5t,需要选择1-3层货架
                    endLoc = db.Queryable<TN_Location>().First(
                        a => a.S_CODE == model.endLoc && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.N_CURRENT_NUM == 0 && a.N_LAYER <= 3);
                        a => a.S_CODE == model.endLoc && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.N_CURRENT_NUM == 0 && a.N_LAYER <= 3 && a.S_AREA_CODE == AreaCode.货架区);
                }
                else if (cgDetail.F_QTY > 0) {
                    endLoc = db.Queryable<TN_Location>().First(
                        a => a.S_CODE == model.endLoc && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.N_CURRENT_NUM == 0 && a.S_AREA_CODE == AreaCode.货架区);
                }
                else {
                    endLoc = db.Queryable<TN_Location>().First(
                        a => a.S_CODE == model.endLoc && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.N_CURRENT_NUM == 0);
                    return BuildSimpleResult(5, $"物料重量信息不合法:{cgDetail.F_QTY}");
                }
                // 没有符合条件的货位
                if (endLoc == null) {
                    return BuildSimpleResult(3, $"货位{model.endLoc}不满足要求:不存在或不满足称重放置要求");
                    return BuildSimpleResult(6, $"货位{model.endLoc}不存在,或不满足称重放置要求");
                }
                // 修改任务终点为PDA指定终点
                task.S_END_LOC = endLoc.S_CODE;
                task.S_END_AREA = endLoc.S_SHELF_CODE;
                using (var trans = db.Ado.UseTran()) {
                    if (db.Updateable<TN_Task>(task).ExecuteCommand() > 0) {
                    if (db.Updateable<TN_Task>(task).UpdateColumns(a => a.S_END_LOC).ExecuteCommand() > 0) {
                        LocationHelper.LockLoc(endLoc.S_CODE, 1);//终点入库锁
                        trans.CommitTran();
@@ -145,7 +157,7 @@
                    else {
                        trans.RollbackTran();
                        return BuildSimpleResult(4, $"任务{task.S_CODE}修改失败,修改终点位置为{endLoc.S_CODE}");
                        return BuildSimpleResult(7, $"任务{task.S_CODE}修改失败,修改终点位置为{endLoc.S_CODE}");
                    }
                }
            }
@@ -177,7 +189,7 @@
                    return BuildSimpleResult(3, $"起点位置 {model.startLoc} 没有绑定容器,无可出库的物料");
                }
                var endLoc = db.Queryable<TN_Location>().First(a => a.S_CODE == model.endLoc && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.S_AREA_CODE == AreaCode.收发货位区);
                var endLoc = db.Queryable<TN_Location>().First(a => a.S_CODE == model.endLoc && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.S_AREA_CODE == AreaCode.收发区);
                if (endLoc == null) {
                    return BuildSimpleResult(4, $"终点位置 {model.endLoc} 不具备放货条件");
@@ -185,17 +197,17 @@
                using (var trans = db.Ado.UseTran()) {
                    // 解绑:起点货位与待搬运容器(不需要手动deleteable操作,内部会自动操作的)
                    if (WCSHelper.CreateTask(startLoc.S_CODE, endLoc.S_CODE, "产品部分出库(WMS)", 3, locCtnrRel.S_CNTR_CODE))//创建搬送任务,起点终点容器
                    if (WCSHelper.CreateTask(startLoc.S_CODE, endLoc.S_CODE, TaskName.产品部分出库, 3, locCtnrRel.S_CNTR_CODE))//创建搬送任务,起点终点容器
                        {//如果操作TN_Location会造成死锁
                        LocationHelper.LockLoc(startLoc.S_CODE, 2);//起点出库锁,
                        LocationHelper.LockLoc(endLoc.S_CODE, 1);//终点入库锁
                        trans.CommitTran();
                        return BuildSimpleResult(0, $"生成 产品出库(WMS) 成功,容器号{locCtnrRel.S_CNTR_CODE},起点{startLoc.S_CODE},终点{endLoc.S_CODE}");
                        return BuildSimpleResult(0, $"生成 产品部分出库 成功,容器号{locCtnrRel.S_CNTR_CODE},起点{startLoc.S_CODE},终点{endLoc.S_CODE}");
                    }
                    else {
                        trans.RollbackTran();
                        return BuildSimpleResult(5, $"生成 产品出库(WMS) 失败,容器号{locCtnrRel.S_CNTR_CODE},起点{startLoc.S_CODE},终点{endLoc.S_CODE}");
                        return BuildSimpleResult(5, $"生成 产品部分出库 失败,容器号{locCtnrRel.S_CNTR_CODE},起点{startLoc.S_CODE},终点{endLoc.S_CODE}");
                    }
                }
            }
@@ -215,7 +227,7 @@
            try {
                // 起点位置:取放货区(有货物、没有锁、已启用)
                var startLoc = db.Queryable<TN_Location>().First(a => a.S_CODE == model.startLoc && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.S_AREA_CODE == AreaCode.收发货位区);
                var startLoc = db.Queryable<TN_Location>().First(a => a.S_CODE == model.startLoc && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.S_AREA_CODE == AreaCode.收发区);
                if (startLoc == null) {
                    return BuildSimpleResult(2, $"起点位置 {model.startLoc} 不符合回库条件");
                }
@@ -263,7 +275,7 @@
            try {
                // 起点位置:取放货区(有货物、没有锁、已启用)
                var startLoc = db.Queryable<TN_Location>().First(a => a.S_CODE == model.startLoc && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.S_AREA_CODE == AreaCode.收发货位区);
                var startLoc = db.Queryable<TN_Location>().First(a => a.S_CODE == model.startLoc && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.S_AREA_CODE == AreaCode.收发区);
                if (startLoc == null) {
                    return BuildSimpleResult(2, $"起点位置 {model.startLoc} 不符合出库条件");
                }
@@ -311,7 +323,7 @@
            try {
                // 起点位置:取放货区(有货物、没有锁、已启用)
                var startLoc = db.Queryable<TN_Location>().First(a => a.S_CODE == model.startLoc && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.S_AREA_CODE == AreaCode.收发货位区);
                var startLoc = db.Queryable<TN_Location>().First(a => a.S_CODE == model.startLoc && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.S_AREA_CODE == AreaCode.收发区);
                if (startLoc == null) {
                    return BuildSimpleResult(2, $"起点位置 {model.startLoc} 不符合回库条件");
                }
config/config.comment.json
New file
@@ -0,0 +1,28 @@
{
    "WebApiUrl": "http://127.0.0.1:8901",
    "RCSApiUrl": "http://127.0.0.1:6001",
    "NDCApiUrl": "http://127.0.0.1:5201/api/order/",
    "SqlServer": "Data Source=192.168.1.144;Initial Catalog=YinKouAnGan;User ID=hhuser;Password=Am123123",
    //"SqlServer": "Data Source=(local);Initial Catalog=AnGangTest;User ID=sa;Password=123456",
    "TCPServerIP": "127.0.0.1",
    "TCPServerPort": 8085,
    "Areas": [
        {
            "Name": "收发区",
            "Codes": [ "SFQ" ]
        },
        {
            "Name": "货架区",
            "Codes": [ "HJQ" ]
        }
    ],
    "Snap": [
        {
            "Ip": "172.23.8.95",
            "Port": 37777,
            "Name": "admin",
            "Pwd": "123456"
        }
    ],
    "CaptureUrl": "http://127.0.0.1/"
}
config/config.json
@@ -7,12 +7,12 @@
    "TCPServerPort": 8085,
    "Areas": [
        {
            "Name": "收发货位区",
            "Codes": [ "P" ]
            "Name": "收发区",
            "Codes": [ "SFQ" ]
        },
        {
            "Name": "货架区",
            "Codes": [ "B111", "B112", "B113", "B114", "B115", "B116", "B117", "B118" ]
            "Codes": [ "HJQ" ]
        }
    ],
    "Snap": [