wanshenmean
12 小时以前 2f7c7a0621ee2e84c47ccd054889a71e8ce4fdd0
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs
@@ -166,7 +166,7 @@
            var state = _stateManager.GetState(ipAddress);
            // 换盘任务使用批次格式
            // 换盘任务批次模式
            if (task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode())
            {
                int targetNormalCount = task.RobotTaskTotalNum;
@@ -174,78 +174,94 @@
                bool isFlowA = task.RobotSourceAddressLineCode is "11001" or "11010";
                // 流向A Phase 2:放假电芯到目标托盘
                if (isFlowA && state?.ChangePalletPhase == 2)
                // ==================== Phase 2: 放正常电芯到目标托盘(两流向相同)====================
                // PickFinished 到达:Phase 1 的 Pick 命令完成,现在下发 Put 命令放正常电芯
                if (state?.ChangePalletPhase == 2)
                {
                    int remaining = 48 - currentCompletedCount;
                    if (remaining <= 0) return;
                    int remainingNormal = targetNormalCount - currentCompletedCount;
                    if (remainingNormal <= 0)
                    {
                        // 正常电芯全部放完,等待 HandlePutFinishedAsync 切换到 Phase 3
                        return;
                    }
                    int batchStart = targetNormalCount + 1 + (state.CurrentBatchIndex - 1);
                    int putCount = Math.Min(4, remaining);
                    int batchStart = (currentCompletedCount / 4) * 4 + 1;
                    int putCount = Math.Min(4, remainingNormal);
                    var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount);
                    await _taskProcessor.SendPutWithBatchAsync(task, state, task.RobotTargetAddress, start, end);
                    // Phase 保持为 2,等 HandlePutFinishedAsync 处理完放货计数后再切回 Phase 1
                    _stateManager.TryUpdateStateSafely(ipAddress, state);
                    return;
                }
                // 流向B Phase 4:放假电芯到5号位
                if (!isFlowA && state?.ChangePalletPhase == 4)
                // ==================== Phase 4: 放假电芯(两流向分叉)====================
                // PickFinished 到达:Phase 3 的 Pick 命令完成,现在下发 Put 命令放假电芯
                if (state?.ChangePalletPhase == 4)
                {
                    int fakeCount = 48 - targetNormalCount;
                    int completedFake = Math.Max(0, currentCompletedCount - targetNormalCount);
                    int remainingFake = fakeCount - completedFake;
                    if (remainingFake <= 0) return;
                    var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(Math.Min(4, remainingFake));
                    if (positions.Count == 0)
                    if (remainingFake <= 0)
                    {
                        _logger.LogError("HandlePickFinishedStateAsync:无可用假电芯点位,任务号: {TaskNum}", task.RobotTaskNum);
                        // 假电芯全部放完,等待 allputfinished 触发 Phase 5 入库
                        return;
                    }
                    int start = positions.Min();
                    int end = positions.Max();
                    await _taskProcessor.SendPutWithBatchAsync(task, state, "5", start, end);
                    return;
                }
                // 流向B Phase 2:放正常电芯到目标托盘
                if (!isFlowA && state?.ChangePalletPhase == 2)
                {
                    int remainingNormal = targetNormalCount - currentCompletedCount;
                    if (remainingNormal <= 0) return;
                    int batchStart = ((currentCompletedCount - 1) / 4) * 4 + 1;
                    int putCount = Math.Min(4, remainingNormal);
                    var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount);
                    await _taskProcessor.SendPutWithBatchAsync(task, state, task.RobotTargetAddress, start, end);
                    return;
                }
                // 默认:使用原有格式
                taskString = $"Putbattery,{task.RobotTargetAddress}";
            }
            else
            {
                // 非换盘任务:使用原有格式
                if (state != null && state.IsGroupPallet && task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode())
                {
                    // 组盘任务:放货需判断是否NG,如果NG则放到NG口
                    if (state.IsScanNG)
                    if (isFlowA)
                    {
                        taskString = $"Putbattery,4";
                        // 流向A:放假电芯到目标托盘
                        int batchStart = targetNormalCount + 1 + (state.CurrentBatchIndex - 1);
                        int putCount = Math.Min(4, remainingFake);
                        var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount);
                        await _taskProcessor.SendPutWithBatchAsync(task, state, task.RobotTargetAddress, start, end);
                        state.CurrentBatchIndex += putCount;
                        // Phase 保持为 4,等 HandlePutFinishedAsync 处理完后再切回 Phase 3
                        _stateManager.TryUpdateStateSafely(ipAddress, state);
                    }
                    else
                    {
                        taskString = $"Putbattery,{task.RobotTargetAddress}";
                        // 流向B:放假电芯到5号位
                        var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(Math.Min(4, remainingFake));
                        if (positions.Count == 0)
                        {
                            _logger.LogError("HandlePickFinishedStateAsync:无可用假电芯点位,任务号: {TaskNum}", task.RobotTaskNum);
                            return;
                        }
                        int start = positions.Min();
                        int end = positions.Max();
                        await _taskProcessor.SendPutWithBatchAsync(task, state, "5", start, end);
                        // Phase 保持为 4,等 HandlePutFinishedAsync 处理完后再切回 Phase 3
                        _stateManager.TryUpdateStateSafely(ipAddress, state);
                    }
                    return;
                }
                // 非批次模式或其他阶段不下发指令
                return;
            }
            // 非换盘任务:使用原有格式
            if (state != null && state.IsGroupPallet && task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode())
            {
                if (state.IsScanNG)
                {
                    taskString = $"Putbattery,4";
                }
                else
                {
                    taskString = $"Putbattery,{task.RobotTargetAddress}";
                }
            }
            else
                taskString = $"Putbattery,{task.RobotTargetAddress}";
            bool result = await _clientManager.SendToClientAsync(ipAddress, taskString);
@@ -376,7 +392,9 @@
            else if (task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode())
            {
                const int targetTotal = 48;
                // 换盘任务进入批次模式,分阶段处理正常电芯和假电芯 (机器人任务总数)
                int targetNormalCount = task.RobotTaskTotalNum;
                // 当前已完成数量(取货完成的数量),初始为状态中的 RobotTaskTotalNum,后续根据取货完成的数量动态更新
                int currentCompletedCount = stateForUpdate.RobotTaskTotalNum;
                // 判断流向(null-safe)
@@ -396,159 +414,82 @@
                    stateForUpdate.CurrentBatchIndex = 1;
                    _logger.LogInformation("HandlePutFinishedStateAsync:换盘任务进入批次模式,任务号: {TaskNum},流向: {Flow}",
                        task.RobotTaskNum, isFlowA ? "A" : "B");
                    _stateManager.TryUpdateStateSafely(ipAddress, stateForUpdate);
                }
                // ==================== 流向A:补假电芯到目标托盘 ====================
                if (isFlowA)
                // ==================== Phase 1: 取正常电芯(两流向相同)====================
                if (stateForUpdate.ChangePalletPhase == 1)
                {
                    // Phase 1: 取假电芯(从5号位,使用 PositionIndex)
                    if (stateForUpdate.ChangePalletPhase == 1)
                    int remainingNormal = targetNormalCount - currentCompletedCount;
                    if (remainingNormal <= 0)
                    {
                        int remaining = targetTotal - currentCompletedCount;
                        if (remaining <= 0)
                        {
                            stateForUpdate.ChangePalletPhase = 0;
                            stateForUpdate.CurrentBatchIndex = 1;
                            stateForUpdate.IsInFakeBatteryMode = false;
                            _logger.LogInformation("HandlePutFinishedStateAsync:流向A完成,任务号: {TaskNum}", task.RobotTaskNum);
                            return;
                        }
                        int pickCount = Math.Min(4, remaining);
                        var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(pickCount);
                        if (positions.Count == 0)
                        {
                            _logger.LogError("HandlePutFinishedStateAsync:无可用假电芯点位,任务号: {TaskNum}", task.RobotTaskNum);
                            return;
                        }
                        await _taskProcessor.SendSocketRobotFakeBatteryPickAsync(task, stateForUpdate, positions);
                        stateForUpdate.ChangePalletPhase = 2;
                        // 正常电芯取完,切换到 Phase 3 取假电芯
                        stateForUpdate.ChangePalletPhase = 3;
                        stateForUpdate.CurrentBatchIndex = 1; // 假电芯批次从头开始
                        _logger.LogInformation("HandlePutFinishedStateAsync:正常电芯取完,切换到Phase 3取假电芯,任务号: {TaskNum}", task.RobotTaskNum);
                        _stateManager.TryUpdateStateSafely(ipAddress, stateForUpdate);
                        return;
                    }
                    // Phase 2: 放假电芯到目标托盘(从 targetNormalCount+1 开始递增)
                    else if (stateForUpdate.ChangePalletPhase == 2)
                    {
                        int remaining = targetTotal - currentCompletedCount;
                        if (remaining <= 0)
                        {
                            stateForUpdate.ChangePalletPhase = 0;
                            stateForUpdate.CurrentBatchIndex = 1;
                            stateForUpdate.IsInFakeBatteryMode = false;
                            _logger.LogInformation("HandlePutFinishedStateAsync:流向A完成,任务号: {TaskNum}", task.RobotTaskNum);
                            return;
                        }
                        // 计算放货批次编号:从 targetNormalCount + 1 开始
                        int batchStart = targetNormalCount + 1 + (stateForUpdate.CurrentBatchIndex - 1);
                        int putCount = Math.Min(4, remaining);
                        var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount);
                    int pickCount = Math.Min(4, remainingNormal);
                    var (start, end) = _taskProcessor.BuildBatchRange(stateForUpdate.CurrentBatchIndex, pickCount);
                        await _taskProcessor.SendPutWithBatchAsync(task, stateForUpdate, task.RobotTargetAddress, start, end);
                    await _taskProcessor.SendPickWithBatchAsync(task, stateForUpdate, task.RobotSourceAddress, start, end);
                        stateForUpdate.CurrentBatchIndex += putCount;
                        stateForUpdate.ChangePalletPhase = 1;
                    }
                    stateForUpdate.CurrentBatchIndex += pickCount;
                    // 发完 Pick 后切换到 Phase=2,等 PickFinished 触发 HandlePickFinishedStateAsync 下发放货指令
                    stateForUpdate.ChangePalletPhase = 2;
                    _stateManager.TryUpdateStateSafely(ipAddress, stateForUpdate);
                    return;
                }
                // ==================== 流向B:取正常电芯 + 回收假电芯 ====================
                else
                // ==================== Phase 3: 处理假电芯(流向A/B 分叉),自己循环 ====================
                if (stateForUpdate.ChangePalletPhase == 3)
                {
                    // Phase 1: 取正常电芯(从源地址,从1开始递增)
                    if (stateForUpdate.ChangePalletPhase == 1)
                    int fakeCount = targetTotal - targetNormalCount;
                    int completedFake = Math.Max(0, currentCompletedCount - targetNormalCount);
                    int remainingFake = fakeCount - completedFake;
                    if (remainingFake <= 0)
                    {
                        int remainingNormal = targetNormalCount - currentCompletedCount;
                        if (remainingNormal <= 0)
                        {
                            // 正常电芯取完,切换到 Phase 3
                            stateForUpdate.ChangePalletPhase = 3;
                            stateForUpdate.CurrentBatchIndex = targetNormalCount + 1;
                            _logger.LogInformation("HandlePutFinishedStateAsync:正常电芯全部取完,进入Phase 3回收假电芯,任务号: {TaskNum}", task.RobotTaskNum);
                            return;
                        }
                        int pickCount = Math.Min(4, remainingNormal);
                        var (start, end) = _taskProcessor.BuildBatchRange(stateForUpdate.CurrentBatchIndex, pickCount);
                        await _taskProcessor.SendPickWithBatchAsync(task, stateForUpdate, task.RobotSourceAddress, start, end);
                        stateForUpdate.CurrentBatchIndex += pickCount;
                        stateForUpdate.ChangePalletPhase = 2;
                        // 假电芯全部处理完,切换到 Phase 5 等待入库
                        stateForUpdate.ChangePalletPhase = 5;
                        _logger.LogInformation("HandlePutFinishedStateAsync:假电芯处理完毕,切换到Phase 5等待入库,任务号: {TaskNum}", task.RobotTaskNum);
                        _stateManager.TryUpdateStateSafely(ipAddress, stateForUpdate);
                        return;
                    }
                    // Phase 2: 放正常电芯到目标托盘(放货编号与取货编号一致)
                    else if (stateForUpdate.ChangePalletPhase == 2)
                    if (isFlowA)
                    {
                        int remainingNormal = targetNormalCount - currentCompletedCount;
                        if (remainingNormal <= 0)
                        {
                            // 正常电芯放完,切换到 Phase 3
                            stateForUpdate.ChangePalletPhase = 3;
                            stateForUpdate.CurrentBatchIndex = targetNormalCount + 1;
                            _logger.LogInformation("HandlePutFinishedStateAsync:正常电芯全部放完,进入Phase 3回收假电芯,任务号: {TaskNum}", task.RobotTaskNum);
                            return;
                        }
                        // 计算本批放货编号:基于 currentCompletedCount 推导批次起始
                        int batchStart = ((currentCompletedCount - 1) / 4) * 4 + 1;
                        int putCount = Math.Min(4, remainingNormal);
                        var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount);
                        await _taskProcessor.SendPutWithBatchAsync(task, stateForUpdate, task.RobotTargetAddress, start, end);
                        stateForUpdate.ChangePalletPhase = 1;
                    }
                    // Phase 3: 取假电芯(从源地址,从 targetNormalCount+1 开始递增)
                    else if (stateForUpdate.ChangePalletPhase == 3)
                    {
                        int fakeCount = targetTotal - targetNormalCount;
                        int completedFake = Math.Max(0, currentCompletedCount - targetNormalCount);
                        int remainingFake = fakeCount - completedFake;
                        if (remainingFake <= 0)
                        {
                            stateForUpdate.ChangePalletPhase = 0;
                            stateForUpdate.CurrentBatchIndex = 1;
                            stateForUpdate.IsInFakeBatteryMode = false;
                            _logger.LogInformation("HandlePutFinishedStateAsync:流向B完成,任务号: {TaskNum}", task.RobotTaskNum);
                            return;
                        }
                        int pickCount = Math.Min(4, remainingFake);
                        var (start, end) = _taskProcessor.BuildBatchRange(stateForUpdate.CurrentBatchIndex, pickCount);
                        await _taskProcessor.SendPickWithBatchAsync(task, stateForUpdate, task.RobotSourceAddress, start, end);
                        stateForUpdate.CurrentBatchIndex += pickCount;
                        stateForUpdate.ChangePalletPhase = 4;
                    }
                    // Phase 4: 放假电芯到5号位(使用 PositionIndex)
                    else if (stateForUpdate.ChangePalletPhase == 4)
                    {
                        int fakeCount = targetTotal - targetNormalCount;
                        int completedFake = Math.Max(0, currentCompletedCount - targetNormalCount);
                        int remainingFake = fakeCount - completedFake;
                        if (remainingFake <= 0)
                        {
                            stateForUpdate.ChangePalletPhase = 0;
                            stateForUpdate.CurrentBatchIndex = 1;
                            stateForUpdate.IsInFakeBatteryMode = false;
                            _logger.LogInformation("HandlePutFinishedStateAsync:流向B完成,任务号: {TaskNum}", task.RobotTaskNum);
                            return;
                        }
                        // 流向A:从5号位取假电芯
                        var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(Math.Min(4, remainingFake));
                        if (positions.Count == 0)
                        {
                            _logger.LogError("HandlePutFinishedStateAsync:无可用假电芯点位,任务号: {TaskNum}", task.RobotTaskNum);
                            return;
                        }
                        int start = positions.Min();
                        int end = positions.Max();
                        await _taskProcessor.SendPutWithBatchAsync(task, stateForUpdate, "5", start, end);
                        stateForUpdate.ChangePalletPhase = 3;
                        await _taskProcessor.SendSocketRobotFakeBatteryPickAsync(task, stateForUpdate, positions);
                    }
                    else
                    {
                        // 流向B:从源地址取假电芯
                        int pickCount = Math.Min(4, remainingFake);
                        var (start, end) = _taskProcessor.BuildBatchRange(stateForUpdate.CurrentBatchIndex, pickCount);
                        await _taskProcessor.SendPickWithBatchAsync(task, stateForUpdate, task.RobotSourceAddress, start, end);
                        stateForUpdate.CurrentBatchIndex += pickCount;
                    }
                    // 发完 Pick 后切换到 Phase=4,等 PickFinished 触发 HandlePickFinishedStateAsync 下发放货指令
                    stateForUpdate.ChangePalletPhase = 4;
                    _stateManager.TryUpdateStateSafely(ipAddress, stateForUpdate);
                    return;
                }
                // ==================== Phase 5: 完成入库(allputfinished / allpickfinished 触发)====================
                if (stateForUpdate.ChangePalletPhase == 5)
                {
                    // Phase 5 由 allpickfinished/allputfinished 触发入库,本方法不再下发指令
                    return;
                }
            }
            else