duyongjia
2024-12-10 913f4af81e7ad477110bfe2ff430163b9225898c
增加人工入库、人工出库、人工移库功能
已修改8个文件
已添加1个文件
940 ■■■■■ 文件已修改
代码管理/WCS/WIDESEAWCS_Client/config/buttons.js 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WIDESEAWCS_Client/src/extension/taskinfo/extend/taskManual.vue 414 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WIDESEAWCS_Client/src/extension/taskinfo/task.js 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/ITaskService.cs 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/TaskInfo/Dt_Task.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/TaskController.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs 364 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs 71 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/DoubleStackerCraneJob.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
´úÂë¹ÜÀí/WCS/WIDESEAWCS_Client/config/buttons.js
@@ -69,6 +69,33 @@
    }
},
{
    name: "人工入库",
    icon: '',
    class: '',
    value: 'ManualInbound',
    type: 'warning',
    onClick: function () {
    }
},
{
    name: "人工出库",
    icon: '',
    class: '',
    value: 'ManualOutbound',
    type: 'warning',
    onClick: function () {
    }
},
{
    name: "人工移库",
    icon: '',
    class: '',
    value: 'ManualTransfer',
    type: 'warning',
    onClick: function () {
    }
},
{
    name: "查看完整路由",
    icon: '',
    class: '',
´úÂë¹ÜÀí/WCS/WIDESEAWCS_Client/src/extension/taskinfo/extend/taskManual.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,414 @@
<template>
  <div>
    <!-- äººå·¥å…¥åº“ -->
    <vol-box
      :lazy="true"
      :width="400"
      :height="300"
      v-model="inbound.model"
      title="人工入库"
      :onModelClose="cancelIn"
    >
      <div style="padding: 10px 20px">
        <vol-form
          ref="sendInTask"
          :formRules="inbound.data"
          :formFields="inbound.fields"
        ></vol-form>
      </div>
      <template #footer>
        <div>
          <el-button
            type="danger"
            size="big"
            icon="md-checkmark-circle"
            long
            @click="SendInTask"
            >确认入库</el-button
          >
          <el-button
            type="primary"
            size="big"
            icon="md-checkmark-circle"
            long
            @click="cancelIn"
            >取消</el-button
          >
        </div>
      </template>
    </vol-box>
    <!-- äººå·¥å‡ºåº“ -->
    <vol-box
      :lazy="true"
      :width="400"
      :height="300"
      v-model="outbound.model"
      title="人工出库"
      :onModelClose="cancelOut"
    >
      <div style="padding: 10px 20px">
        <vol-form
          ref="sendInTask"
          :formRules="outbound.data"
          :formFields="outbound.fields"
        ></vol-form>
      </div>
      <template #footer>
        <div>
          <el-button
            type="danger"
            size="big"
            icon="md-checkmark-circle"
            long
            @click="SendOutTask"
            >确认入库</el-button
          >
          <el-button
            type="primary"
            size="big"
            icon="md-checkmark-circle"
            long
            @click="cancelOut"
            >取消</el-button
          >
        </div>
      </template>
    </vol-box>
    <!-- äººå·¥ç§»åº“ -->
    <vol-box
      :lazy="true"
      :width="400"
      :height="300"
      v-model="transfer.model"
      title="人工移库"
      :onModelClose="cancelTransfer"
    >
      <div style="padding: 10px 20px">
        <vol-form
          ref="sendInTask"
          :formRules="transfer.data"
          :formFields="transfer.fields"
        ></vol-form>
      </div>
      <template #footer>
        <div>
          <el-button
            type="danger"
            size="big"
            icon="md-checkmark-circle"
            long
            @click="SendTransfer"
            >确认入库</el-button
          >
          <el-button
            type="primary"
            size="big"
            icon="md-checkmark-circle"
            long
            @click="cancelTransfer"
            >取消</el-button
          >
        </div>
      </template>
    </vol-box>
  </div>
</template>
<script>
import VolBox from "@/components/basic/VolBox.vue";
import VolForm from "@/components/basic/VolForm.vue";
//这里使用的vue2语法,也可以写成vue3语法
export default {
  components: { "vol-box": VolBox, "vol-form": VolForm },
  methods: {},
  data() {
    return {
      inbound: {
        model: false,
        fields: {
          cmd: 3001,
          src_station: 1001,
          dest_station: null,
          CarId: '',
        },
        data: [
          [
            {
              type: "select",
              required: true,
              title: "入库站点",
              field: "src_station",
              data: [
                { key: 1001, value: "八厂" },
                { key: 1002, value: "九厂" },
              ],
            },
          ],
          [
            {
              type: "number",
              required: true,
              title: "终点库位",
              field: "dest_station"
            },
          ],
          [
            {
              type: "text",
              required: true,
              title: "料车编号",
              field: "CarId",
            },
          ],
        ],
      },
      outbound: {
        model: false,
        fields: {
          cmd: 102,
          src_station: null,
          dest_station: 1001,
          CarId: '',
        },
        data: [
        [
            {
              type: "number",
              required: true,
              title: "来源库位",
              field: "src_station"
            },
          ],
          [
            {
              type: "select",
              required: true,
              title: "出库站点",
              field: "dest_station",
              data: [
                { key: 1001, value: "八厂" },
                { key: 1002, value: "九厂" },
              ],
            },
          ],
          [
            {
              type: "text",
              required: true,
              title: "料车编号",
              field: "CarId",
            },
          ],
        ],
      },
      transfer: {
        model: false,
        fields: {
          cmd: 103,
          src_station: null,
          dest_station: null,
          CarId: '',
        },
        data: [
        [
            {
              type: "number",
              required: true,
              title: "来源库位",
              field: "src_station"
            },
          ],
          [
            {
              type: "number",
              required: true,
              title: "终点库位",
              field: "dest_station"
            },
          ],
          [
            {
              type: "text",
              required: true,
              title: "料车编号",
              field: "CarId",
            },
          ],
        ],
      },
    };
  },
  computed: {
    isValidInDest() {
      const regex = /^[0-9]{1,5}$/;
      return regex.test(this.inbound.fields.dest_station);
    },
    isValidoutSrc() {
      const regex = /^[0-9]{1,5}$/;
      return regex.test(this.outbound.fields.src_station);
    },
    isValidTranSrc() {
      const regex = /^[0-9]{1,5}$/;
      return regex.test(this.transfer.fields.src_station);
    },
    isValidTranDest() {
      const regex = /^[0-9]{1,5}$/;
      return regex.test(this.transfer.fields.dest_station);
    }
  },
  methods: {
    //人工入库
    open(type) {
      switch (type) {
        case "inbound":
          this.inbound.model = true;
          break;
        case "outbound":
          this.outbound.model = true;
          break;
        case "transfer":
          this.transfer.model = true;
          break;
        default:
          break;
      }
    },
    cancelIn(){
      this.$refs.sendInTask.reset()
      this.inbound.model = false;
      let param = {
        cmd: this.inbound.fields.cmd,
        src_station: this.inbound.fields.src_station,
        dest_station: this.inbound.fields.dest_station,
        carId: this.inbound.fields.CarId,
      };
      console.log(param);
    },
    cancelOut(){
      this.$refs.sendInTask.reset()
      this.outbound.model = false;
      let param = {
        cmd: this.outbound.fields.cmd,
        src_station: this.outbound.fields.src_station,
        dest_station: this.outbound.fields.dest_station,
        carId: this.inbound.fields.CarId,
      };
      console.log(param);
    },
    cancelTransfer(){
      this.$refs.sendInTask.reset()
      this.transfer.model = false;
      let param = {
        cmd: this.transfer.fields.cmd,
        src_station: this.transfer.fields.src_station,
        dest_station: this.transfer.fields.dest_station,
        carId: this.transfer.fields.CarId,
      };
      console.log(param);
    },
    //人工入库
    SendInTask() {
      if (this.inbound.fields.src_station==''||this.inbound.fields.dest_station==0||this.inbound.fields.CarId=='') {
        return this.$Message.error(
          "请输入符合条件的参数"
        );
      }
      if (!this.isValidInDest) {
        return this.$Message.error(
          "终点库位只包含数字且最大长度为5位"
        );
      }
      let param = {
        cmd: this.inbound.fields.cmd,
        src_station: this.inbound.fields.src_station,
        dest_station: this.inbound.fields.dest_station,
        carId: this.inbound.fields.CarId,
      };
      this.http
        .post("/api/Task/ReceiveWCSTask", param, "任务创建中...")
        .then((x) => {
          if (x.status == true) {
            this.$Message.success("新建入库任务成功");
            //关闭弹框
            this.inbound.model = false;
            //清空表单
            this.$refs.sendInTask.reset();
            this.$parent.refresh();
          } else {
            this.$Message.error(x.message);
          }
        });
    },
    //人工出库
    SendOutTask() {
      if (this.outbound.fields.src_station==0||this.outbound.fields.dest_station==''||this.outbound.fields.CarId=='') {
        return this.$Message.error(
          "请输入符合条件的参数"
        );
      }
      if (!this.isValidoutSrc) {
        return this.$Message.error(
          "来源库位只包含数字且最大长度为5位"
        );
      }
      let param = {
        cmd: this.outbound.fields.cmd,
        src_station: this.outbound.fields.src_station,
        dest_station: this.outbound.fields.dest_station,
        carId: this.outbound.fields.CarId,
      };
      this.http
        .post("/api/Task/ReceiveWCSTask", param, "任务创建中...")
        .then((x) => {
          if (x.status == true) {
            this.$Message.success("新建出库任务成功");
            //关闭弹框
            this.outbound.model = false;
            //清空表单
            this.$refs.sendInTask.reset();
            this.$parent.refresh();
          } else {
            this.$Message.error(x.message);
          }
        });
    },
    //人工移库库
    SendTransfer() {
      if (this.transfer.fields.src_station==0||this.transfer.fields.dest_station==0||this.transfer.fields.CarId=='') {
        return this.$Message.error(
          "请输入符合条件的参数"
        );
      }
      if (!this.isValidTranSrc) {
        return this.$Message.error(
          "来源库位只包含数字且最大长度为5位"
        );
      }
      if (!this.isValidTranDest) {
        return this.$Message.error(
          "终点库位只包含数字且最大长度为5位"
        );
      }
      let param = {
        cmd: this.transfer.fields.cmd,
        src_station: this.transfer.fields.src_station,
        dest_station: this.transfer.fields.dest_station,
        carId: this.transfer.fields.CarId,
      };
      this.http
        .post("/api/Task/ReceiveWCSTask", param, "任务创建中...")
        .then((x) => {
          if (x.status == true) {
            this.$Message.success("新建移库任务成功");
            //关闭弹框
            this.transfer.model = false;
            //清空表单
            this.$refs.sendInTask.reset();
            this.$parent.refresh();
          } else {
            this.$Message.error(x.message);
          }
        });
    },
  },
};
</script>
´úÂë¹ÜÀí/WCS/WIDESEAWCS_Client/src/extension/taskinfo/task.js
@@ -1,10 +1,11 @@
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
import gridBody from './extend/taskExecuteDetail.vue'
import gridHeader from './extend/taskManual.vue'
let extension = {
    components: {
        //查询界面扩展组件
        gridHeader: '',
        gridHeader: gridHeader,
        gridBody: gridBody,
        gridFooter: '',
        //新建、编辑弹出框扩展组件
@@ -50,7 +51,27 @@
                        });
                }
            }
            //人工入库按钮
            var ManualButton = this.buttons.find((x) => x.value == "ManualInbound");
            if (ManualButton) {
                ManualButton.onClick = () => {
                    this.$refs.gridHeader.open("inbound");
                }
            }
            //人工出库按钮
            var ManualOutButton = this.buttons.find((x) => x.value == "ManualOutbound");
            if (ManualOutButton) {
                ManualOutButton.onClick = () => {
                    this.$refs.gridHeader.open("outbound");
                }
            }
            //人工移库按钮
            var ManualTransferButton = this.buttons.find((x) => x.value == "ManualTransfer");
            if (ManualTransferButton) {
                ManualTransferButton.onClick = () => {
                    this.$refs.gridHeader.open("transfer");
                }
            }
            var previousButton = this.buttons.find((x) => x.value == "Previous");
            if (previousButton) previousButton.hidden = true;
            var nextButton = this.buttons.find((x) => x.value == "Next");
´úÂë¹ÜÀí/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/ITaskService.cs
@@ -63,6 +63,8 @@
        /// <returns>返回处理结果</returns>
        WebResponseContent ReceiveMESTask([NotNull] MESTaskDTO taskDTO);
        WebResponseContent ReceiveWCSTask([NotNull] MESTaskDTO taskDTO);
        /// <summary>
        /// æ ¹æ®æ‰˜ç›˜å·ã€èµ·å§‹åœ°å€å‘WMS请求任务
        /// </summary>
@@ -138,6 +140,13 @@
        /// <returns></returns>
        Dt_Task QueryStackerCraneTaskByAGVRequest(string deviceNo);
        /// <summary>
        /// æŸ¥è¯¢AGV进入中的入库任务数量
        /// </summary>
        /// <param name="deviceNo"></param>
        /// <returns></returns>
        Dt_Task QueryStackerCraneTaskByAGVIning(string deviceNo);
        /// <summary>
        /// å¯¹åº”WMS请求 3001-AGV放货完成
@@ -176,6 +185,21 @@
        /// <param name="taskNum">任务号</param>
        /// <param name="message">异常信息</param>
        WebResponseContent UpdateTaskExceptionMessage(int taskNum, string message);
        /// <summary>
        /// æ›´æ–°æ˜¯å¦è¿›å…¥å‡é™æœºæ ‡å¿—(0,未进入 1,已进入)
        /// </summary>
        /// <param name="taskNum"></param>
        /// <param name="Inflag"></param>
        /// <returns></returns>
        WebResponseContent UpdateTaskAllowIn(int taskNum, int Inflag);
        /// <summary>
        /// æ˜¯å¦å·²å›žä¼ MES2001标志(0,未回传 1,已回传)
        /// </summary>
        /// <param name="taskNum"></param>
        /// <param name="Inflag"></param>
        /// <returns></returns>
        WebResponseContent UpdateTaskIsBack(int taskNum, int Inflag);
        /// <summary>
        /// æ›´æ–°ä»»åŠ¡çŠ¶æ€ä¿¡æ¯ï¼Œå¹¶åŒæ­¥è‡³WMS
´úÂë¹ÜÀí/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/TaskInfo/Dt_Task.cs
@@ -144,7 +144,7 @@
        public DateTime? Dispatchertime { get; set; }
        /// <summary>
        /// å¤‡æ³¨ ä¸Šæ–™ä»»åŠ¡æ—¶ ç”¨äºŽå­˜ä¸Šæ–™æ–™è½¦çš„æ€»å±‚数和当前层数 æ ¼å¼ï¼šæ€»å±‚æ•°-当前层数  å‡ºåº“任务时,写总层数
        /// å¤‡æ³¨ ä¸Šæ–™ä»»åŠ¡æ—¶ ç”¨äºŽå­˜ä¸Šæ–™æ–™è½¦çš„æ€»å±‚数和当前层数 æ ¼å¼ï¼šæ€»å±‚æ•°-当前层数;  å‡ºåº“任务时:写总层数;  è‡ªåŠ¨å…¥åº“æ—¶å†™ï¼šæ˜¯å¦å›žä¼ å…è®¡æ—¶è¿›å…¥
        /// </summary>
        [ImporterHeader(Name = "备注")]
        [ExporterHeader(DisplayName = "备注")]
´úÂë¹ÜÀí/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/TaskController.cs
@@ -62,6 +62,17 @@
        }
        /// <summary>
        /// æŽ¥æ”¶WCS人工任务信息
        /// </summary>
        /// <param name="taskDTO">WCS任务对象</param>
        /// <returns>返回处理结果</returns>
        [HttpPost, Route("ReceiveWCSTask"), AllowAnonymous]
        public WebResponseContent ReceiveWCSTask([FromBody] MESTaskDTO taskDTO)
        {
            return Service.ReceiveWCSTask(taskDTO);
        }
        /// <summary>
        /// ä»»åŠ¡å–æ¶ˆ(堆垛机回解决不了的故障需清除任务,清除任务后,需在WCS上取消任务)
        /// </summary>
        /// <param name="key"></param>
´úÂë¹ÜÀí/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs
@@ -24,6 +24,7 @@
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
@@ -483,6 +484,253 @@
        }
        /// <summary>
        /// wcs手工生成任务
        /// </summary>
        /// <param name="taskDTO">WCS任务对象</param>
        /// <returns>返回处理结果</returns>
        public WebResponseContent ReceiveWCSTask([NotNull] MESTaskDTO taskDTO)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                taskDTO.task_id = GetTaskNo();
                string inparam = JsonConvert.SerializeObject(taskDTO);
                ServiceLogger.WriteDebug("ReceiveWCSTask", $"ReceiveWCSTask方法入参{inparam}");
                Dt_Task task = new Dt_Task();
                Dt_Task taskinfo = BaseDal.QueryFirst(x => x.TaskNum == taskDTO.task_id);
                if (taskDTO.cmd == 101)//如果是101按旧的任务号去查
                {
                    taskinfo = BaseDal.QueryFirst(x => x.TaskNum == taskDTO.weight);
                }
                if (taskDTO.cmd != 3001 && taskDTO.cmd != 101 && taskinfo != null)
                {
                    ServiceLogger.WriteDebug("ReceiveWCSTask", $"任务号重复,任务号:{taskDTO.task_id}");
                    return content = WebResponseContent.Instance.Error($"任务号重复,任务号:{taskDTO.task_id}");
                }
                Dt_LocationInfo locationsrc = _locationInfoRepository.QueryFirst(x => x.Remark == taskDTO.src_station.ToString());
                Dt_LocationInfo locationdsc = _locationInfoRepository.QueryFirst(x => x.Remark == taskDTO.dest_station.ToString());
                switch (taskDTO.cmd)
                {
                    case 3001://AGV放货完成 WMS发3001的同时WCS需在job中写提升信号
                        if (BaseDal.QueryFirst(x => x.TaskNum == taskDTO.task_id) == null)//手动入库直接发3001,需要生成任务,因为没有1001环节
                        {
                            taskDTO.dest_rack =int.Parse(taskDTO.dest_station.ToString().Substring(0, 1));
                            taskDTO.dest_row = int.Parse(taskDTO.dest_station.ToString().Substring(1, 2).TrimStart('0'));
                            taskDTO.dest_col = int.Parse(taskDTO.dest_station.ToString().Substring(3, 2).TrimStart('0'));
                            task.TaskType = (int)TaskInboundTypeEnum.Inbound;
                            task.TaskState = (int)TaskInStatusEnum.AGV_InExecuting;
                            task.Roadway = "SC01";
                            task.Grade = 2;
                            if (locationsrc != null)
                            {
                                task.SourceAddress = locationsrc.LocationCode;
                            }
                            else
                            {
                                ServiceLogger.WriteDebug("ReceiveWCSTask", $"WCS未查询到源站点对应的库位,源站点:{taskDTO.dest_station.ToString()}");
                                return content = WebResponseContent.Instance.Error($"WCS未查询到源站点对应的库位,源站点:{taskDTO.dest_station.ToString()}");
                            }
                        }
                        break;
                    case 101://提升机提升完成
                        if (taskinfo != null)
                        {
                            //更新任务表中NextAddress字段为新的任务号   taskDTO.weight-旧的任务号   taskDTO.task_id-新的任务号
                            UpdateTaskStatus(taskinfo.TaskId, taskDTO.task_id, (int)TaskInStatusEnum.AGV_InFinish);
                            _taskExecuteDetailService.AddTaskExecuteDetail(taskinfo.TaskId, $"AGV搬运完成");
                            ServiceLogger.WriteDebug("ReceiveWCSTask", $"AGV搬运完成(101)更新状态成功,任务号:{taskinfo.TaskId}");
                            return content = WebResponseContent.Instance.OK($"AGV搬运完成(101)更新状态成功,任务号:{taskinfo.TaskId}");
                        }
                        else
                        {
                            ServiceLogger.WriteDebug("ReceiveWCSTask", $"AGV搬运完成(101)更新状态时,查询不到任务号");
                            return content = WebResponseContent.Instance.Error($"AGV搬运完成(101)更新状态时,查询不到任务号");
                        }
                        break;
                    case 103://产品移库(移库,出库)
                        taskDTO.src_rack = int.Parse(taskDTO.src_station.ToString().Substring(0, 1));
                        taskDTO.src_row = int.Parse(taskDTO.src_station.ToString().Substring(1, 2).TrimStart('0'));
                        taskDTO.src_col = int.Parse(taskDTO.src_station.ToString().Substring(3, 2).TrimStart('0'));
                        taskDTO.dest_rack = int.Parse(taskDTO.dest_station.ToString().Substring(0, 1));
                        taskDTO.dest_row = int.Parse(taskDTO.dest_station.ToString().Substring(1, 2).TrimStart('0'));
                        taskDTO.dest_col = int.Parse(taskDTO.dest_station.ToString().Substring(3, 2).TrimStart('0'));
                        taskDTO.total = 9;
                        task.TaskType = (int)TaskRelocationTypeEnum.Relocation;
                        task.TaskState = (int)TaskOutStatusEnum.OutNew;
                        task.Roadway = "SC01";
                        if (taskDTO.total > 0)
                        {
                            task.Remark = taskDTO.total.ToString();//取出库的总层数
                        }
                        task.Grade = 1;
                        break;
                    case 102:
                        if (taskDTO.dest_station == 1001 || taskDTO.dest_station == 1002)//异常出库
                        {
                            taskDTO.src_rack = int.Parse(taskDTO.src_station.ToString().Substring(0, 1));
                            taskDTO.src_row = int.Parse(taskDTO.src_station.ToString().Substring(1, 2).TrimStart('0'));
                            taskDTO.src_col = int.Parse(taskDTO.src_station.ToString().Substring(3, 2).TrimStart('0'));
                            task.TaskType = (int)TaskOutboundTypeEnum.OutInventory;
                            task.TaskState = (int)TaskOutStatusEnum.OutNew;
                            task.Roadway = "SC01";
                            task.Grade = 1;
                        }
                        if (locationdsc != null)
                        {
                            task.TargetAddress = locationdsc.LocationCode;
                        }
                        else
                        {
                            ServiceLogger.WriteDebug("ReceiveWCSTask", $"WCS未查询到目标站点对应的库位,目标站点:{taskDTO.dest_station.ToString()}");
                            return content = WebResponseContent.Instance.Error($"WCS未查询到目标站点对应的库位,目标站点:{taskDTO.dest_station.ToString()}");
                        }
                        break;
                    default:
                        break;
                }
                task.TaskNum = taskDTO.task_id;
                task.PalletCode = taskDTO.CarId;
                if (string.IsNullOrEmpty(task.SourceAddress))//如果不是站点,直接取行列层
                {
                    task.SourceAddress = $"SC01-{taskDTO.src_rack.ToString().PadLeft(3, '0')}-{taskDTO.src_col.ToString().PadLeft(3, '0')}-{taskDTO.src_row.ToString().PadLeft(3, '0')}";
                }
                if (string.IsNullOrEmpty(task.TargetAddress))//如果不是站点,直接取行列层
                {
                    task.TargetAddress = $"SC01-{taskDTO.dest_rack.ToString().PadLeft(3, '0')}-{taskDTO.dest_col.ToString().PadLeft(3, '0')}-{taskDTO.dest_row.ToString().PadLeft(3, '0')}";
                }
                task.Creater = "WCS";
                task.WMSId = 3;//WCS人工建任务
                //判断货位状态
                Dt_LocationInfo srcLocation = _locationInfoRepository.QueryFirst(x => x.LocationCode == task.SourceAddress);
                Dt_LocationInfo tarLocation = _locationInfoRepository.QueryFirst(x => x.LocationCode == task.TargetAddress);
                if (srcLocation != null && tarLocation != null)
                {
                    if (srcLocation.EnableStatus == (int)EnableStatusEnum.Disable)
                    {
                        ServiceLogger.WriteDebug("ReceiveWCSTask", $"源地址已禁用:{srcLocation.LocationCode}");
                        return content = WebResponseContent.Instance.Error($"源地址已禁用:{srcLocation.LocationCode}");
                    }
                    if (tarLocation.EnableStatus == (int)EnableStatusEnum.Disable)
                    {
                        ServiceLogger.WriteDebug("ReceiveWCSTask", $"目标地址已禁用:{tarLocation.LocationCode}");
                        return content = WebResponseContent.Instance.Error($"目标地址已禁用:{tarLocation.LocationCode}");
                    }
                    if (taskDTO.cmd != 101)//入库时不需要判断是否锁定,锁定状态是在生成任务时锁定
                    {
                        if (taskinfo != null && taskDTO.cmd == 3001 && taskinfo.WMSId == 3)//如果是手动入库,发3001,会生成任务,需要判断库位是否锁定;自动模式发1001的时候就生成了任务,再发3001就不需要判断是否锁定了
                        {
                            if (srcLocation.LocationStatus == (int)LocationStatusEnum.Lock)
                            {
                                ServiceLogger.WriteDebug("ReceiveWCSTask", $"源地址已锁定:{srcLocation.LocationCode}");
                                return content = WebResponseContent.Instance.Error($"源地址已锁定:{srcLocation.LocationCode}");
                            }
                            if (tarLocation.LocationStatus == (int)LocationStatusEnum.Lock)
                            {
                                ServiceLogger.WriteDebug("ReceiveWCSTask", $"目标地址已锁定:{tarLocation.LocationCode}");
                                return content = WebResponseContent.Instance.Error($"目标地址已锁定:{tarLocation.LocationCode}");
                            }
                        }
                    }
                    if (task.TaskType == (int)TaskInboundTypeEnum.Inbound)//入库  è·¯å¾„:提升机库位-->库位
                    {
                        //WCS查询库位状态是否为“空闲”并且未禁用,锁定库位修改库位状态为“锁定”,生成WCS产品入库任务,加入WCS任务队列中。
                        if (tarLocation.LocationStatus != (int)LocationStatusEnum.Free)
                        {
                            ServiceLogger.WriteDebug("ReceiveWCSTask", $"入库-目标地址不是空闲状态:{tarLocation.LocationCode}");
                            return content = WebResponseContent.Instance.Error($"入库-目标地址不是空闲状态:{tarLocation.LocationCode}");
                        }
                        tarLocation.LocationStatus = (int)LocationStatusEnum.Lock;
                    }
                    else if (task.TaskType == (int)TaskRelocationTypeEnum.Relocation)  //产品移库(移库,出库共用)  è·¯å¾„:库位-->库位/暂存库位
                    {
                        //WCS查询库位状态是否为“有货”,库位/暂存库位是否“空闲”
                        if (srcLocation.LocationStatus != (int)LocationStatusEnum.InStock)
                        {
                            ServiceLogger.WriteDebug("ReceiveWCSTask", $"移库-源地址不是有货状态:{srcLocation.LocationCode}");
                            return content = WebResponseContent.Instance.Error($"移库-源地址不是有货状态:{srcLocation.LocationCode}");
                        }
                        if (tarLocation.LocationStatus != (int)LocationStatusEnum.Free)
                        {
                            ServiceLogger.WriteDebug("ReceiveWCSTask", $"移库-目标地址不是空闲状态:{srcLocation.LocationCode}");
                            return content = WebResponseContent.Instance.Error($"移库-目标地址不是空闲状态:{srcLocation.LocationCode}");
                        }
                        srcLocation.LocationStatus = (int)LocationStatusEnum.Lock;
                        tarLocation.LocationStatus = (int)LocationStatusEnum.Lock;
                    }
                    else if (task.TaskType == (int)TaskOutboundTypeEnum.OutInventory)  //异常出库(退库) è·¯å¾„:库位-->提升机库位
                    {
                        //WCS查询库位状态是否为“有货”
                        if (srcLocation.LocationStatus != (int)LocationStatusEnum.InStock)
                        {
                            ServiceLogger.WriteDebug("ReceiveWCSTask", $"异常出库-源地址不是有货状态:{srcLocation.LocationCode}");
                            return content = WebResponseContent.Instance.Error($"异常出库-源地址不是有货状态:{srcLocation.LocationCode}");
                        }
                        srcLocation.LocationStatus = (int)LocationStatusEnum.Lock;
                    }
                }
                else
                {
                    ServiceLogger.WriteDebug("ReceiveWCSTask", $"库位地址不存在,任务号:{task.TaskNum}");
                    return content = WebResponseContent.Instance.Error($"库位地址不存在,任务号:{task.TaskNum}");
                }
                try
                {
                    //开启事物
                    _unitOfWorkManage.BeginTran();
                    _locationInfoRepository.UpdateData(tarLocation);
                    _locationInfoRepository.UpdateData(srcLocation);
                    BaseDal.AddData(task);
                    Dt_Task tasktemp = BaseDal.QueryFirst(x => x.TaskNum == task.TaskNum);
                    _taskExecuteDetailService.AddTaskExecuteDetail(tasktemp.TaskId, "接收WCS任务");
                    //提交事务
                    _unitOfWorkManage.CommitTran();
                }
                catch (Exception)
                {
                    _unitOfWorkManage.RollbackTran();
                    throw;
                }
                ServiceLogger.WriteDebug("ReceiveWCSTask", $"接收任务成功,任务号:{task.TaskNum}");
                content = WebResponseContent.Instance.OK($"接收任务成功,任务号:{task.TaskNum}", task);
            }
            catch (Exception ex)
            {
                ServiceLogger.WriteDebug("ReceiveWCSTask", $"任务接收错误,错误信息:{ex.StackTrace}");
                content = WebResponseContent.Instance.Error($"任务接收错误,错误信息:{ex.Message}");
            }
            return content;
        }
        /// <summary>
        /// èŽ·å–ä»»åŠ¡å·
        /// </summary>
        /// <returns></returns>
        public int GetTaskNo()
        {
            DataTable dt = BaseDal.QueryTable("SELECT FORMAT(NEXT VALUE FOR dbo.seqTaskNum, '0000000');");
            return int.Parse("9"+ dt.Rows[0][0].ToString());
        }
        /// <summary>
        /// æ ¹æ®æ‰˜ç›˜å·ã€èµ·å§‹åœ°å€å‘WMS请求任务
        /// </summary>
@@ -614,8 +862,19 @@
        /// <param name="deviceNo"></param>
        /// <returns></returns>
        public Dt_Task QueryStackerCraneTaskByAGVRequest(string deviceNo)
        {
        {
            return BaseDal.QueryFirst(x => x.Roadway == deviceNo && (TaskInboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskInStatusEnum.InNew), TaskOrderBy);
        }
        /// <summary>
        /// æŸ¥è¯¢AGV进入中的入库任务
        /// </summary>
        /// <param name="deviceNo"></param>
        /// <returns></returns>
        public Dt_Task QueryStackerCraneTaskByAGVIning(string deviceNo)
        {
            return BaseDal.QueryFirst(x => x.Roadway == deviceNo && (TaskInboundTypes.Contains(x.TaskType)&&x.CurrentAddress=="1"), TaskOrderBy);
        }
        /// <summary>
        /// å¯¹åº”WMS请求 3001-AGV放货完成
@@ -702,6 +961,56 @@
                content = WebResponseContent.Instance.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// è‡ªåŠ¨å…¥åº“æ—¶æ›´æ–°æ˜¯å¦è¿›å…¥å‡é™æœºæ ‡å¿—ï¼ˆ0,未进入 1,已进入)
        /// </summary>
        /// <param name="taskNum"></param>
        /// <param name="Inflag"></param>
        /// <returns></returns>
        public WebResponseContent UpdateTaskAllowIn(int taskNum, int Inflag)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
                if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】");
                task.CurrentAddress = Inflag.ToString();
                task.ModifyDate = DateTime.Now;
                BaseDal.UpdateData(task);
            }
            catch (Exception ex)
            {
                content = WebResponseContent.Instance.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// æ˜¯å¦å·²å›žä¼ MES2001标志(0,未回传 1,已回传)
        /// </summary>
        /// <param name="taskNum"></param>
        /// <param name="Inflag"></param>
        /// <returns></returns>
        public WebResponseContent UpdateTaskIsBack(int taskNum, int Inflag)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
                if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】");
                task.Remark = Inflag.ToString();
                task.ModifyDate = DateTime.Now;
                BaseDal.UpdateData(task);
            }
            catch (Exception ex)
            {
                content = WebResponseContent.Instance.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
@@ -1141,12 +1450,15 @@
                        }
                        else
                        {
                            MESSendCMD sendcmd = new MESSendCMD { cmd = 201, task_id = task.TaskNum, status = 6 };
                            MESResponse res = ApiInvoke.SendTaskCMD(sendcmd);
                            if (res != null && res.code != 0)
                            if (task.WMSId != 3)
                            {
                                ServiceLogger.WriteDebug("StackCraneTaskCompleted", $"大堆垛机完成异常出库任务后回传MES失败!,任务号:【{taskNum}】,失败信息:【{res.message}】");
                                content = WebResponseContent.Instance.Error($"大堆垛机完成异常出库任务后回传MES失败!,任务号:【{taskNum}】,失败信息:【{res.message}】");
                                MESSendCMD sendcmd = new MESSendCMD { cmd = 201, task_id = task.TaskNum, status = 6 };
                                MESResponse res = ApiInvoke.SendTaskCMD(sendcmd);
                                if (res != null && res.code != 0)
                                {
                                    ServiceLogger.WriteDebug("StackCraneTaskCompleted", $"大堆垛机完成异常出库任务后回传MES失败!,任务号:【{taskNum}】,失败信息:【{res.message}】");
                                    content = WebResponseContent.Instance.Error($"大堆垛机完成异常出库任务后回传MES失败!,任务号:【{taskNum}】,失败信息:【{res.message}】");
                                }
                            }
                        }
@@ -1154,7 +1466,7 @@
                    catch (Exception ex)
                    {
                        _unitOfWorkManage.RollbackTran();
                        //任务执行失败,货位状态还原
                        ServiceLogger.WriteDebug("StackCraneTaskCompleted", $"大堆垛机执行出库任务失败!,任务号:【{taskNum}】,失败信息:【{ex.Message}】");
                        content = WebResponseContent.Instance.Error($"大堆垛机执行出库任务失败!,任务号:【{taskNum}】,失败信息:【{ex.Message}】");
                    }
@@ -1187,16 +1499,19 @@
                        MESSendCMD sendcmd = new MESSendCMD { cmd = 201, task_id = int.Parse(task.NextAddress), status = 6 };
                        string inparam = JsonConvert.SerializeObject(sendcmd);
                        ServiceLogger.WriteDebug("StackCraneTaskCompleted", $"大堆垛机完成入库任务后回传MES入参:{inparam}");
                        MESResponse res = ApiInvoke.SendTaskCMD(sendcmd);
                        if (res != null && res.code != 0)
                        if (task.WMSId != 3)
                        {
                            ServiceLogger.WriteDebug("StackCraneTaskCompleted", $"大堆垛机完成入库任务后回传MES失败!,任务号:【{taskNum}】,失败信息:【{res.message}】");
                            content = WebResponseContent.Instance.Error($"大堆垛机完成入库任务后回传MES失败!,任务号:【{taskNum}】,失败信息:【{res.message}】");
                        }
                        else
                        {
                            ServiceLogger.WriteDebug("StackCraneTaskCompleted", $"大堆垛机完成入库任务后回传MES成功!,任务号:【{taskNum}】");
                            MESResponse res = ApiInvoke.SendTaskCMD(sendcmd);
                            if (res != null && res.code != 0)
                            {
                                ServiceLogger.WriteDebug("StackCraneTaskCompleted", $"大堆垛机完成入库任务后回传MES失败!,任务号:【{taskNum}】,失败信息:【{res.message}】");
                                content = WebResponseContent.Instance.Error($"大堆垛机完成入库任务后回传MES失败!,任务号:【{taskNum}】,失败信息:【{res.message}】");
                            }
                            else
                            {
                                ServiceLogger.WriteDebug("StackCraneTaskCompleted", $"大堆垛机完成入库任务后回传MES成功!,任务号:【{taskNum}】");
                            }
                        }
                    }
@@ -1230,14 +1545,17 @@
                        _unitOfWorkManage.CommitTran();
                        //移库完成,回传MES
                        //回传到WMS
                        MESSendCMD sendcmd = new MESSendCMD { cmd = 201, task_id = task.TaskNum, status = 6 };
                        string inparam = JsonConvert.SerializeObject(sendcmd);
                        ServiceLogger.WriteDebug("StackCraneTaskCompleted", $"大堆垛机完成出库任务后回传MES入参:{inparam}");
                        MESResponse res = ApiInvoke.SendTaskCMD(sendcmd);
                        if (res != null && res.code != 0)
                        if (task.WMSId != 3)
                        {
                            ServiceLogger.WriteDebug("StackCraneTaskCompleted", $"大堆垛机完成出库任务后回传MES失败!,任务号:【{taskNum}】,失败信息:【{res.message}】");
                            content = WebResponseContent.Instance.Error($"大堆垛机完成出库任务后回传MES失败!,任务号:【{taskNum}】,失败信息:【{res.message}】");
                            MESSendCMD sendcmd = new MESSendCMD { cmd = 201, task_id = task.TaskNum, status = 6 };
                            string inparam = JsonConvert.SerializeObject(sendcmd);
                            ServiceLogger.WriteDebug("StackCraneTaskCompleted", $"大堆垛机完成出库任务后回传MES入参:{inparam}");
                            MESResponse res = ApiInvoke.SendTaskCMD(sendcmd);
                            if (res != null && res.code != 0)
                            {
                                ServiceLogger.WriteDebug("StackCraneTaskCompleted", $"大堆垛机完成出库任务后回传MES失败!,任务号:【{taskNum}】,失败信息:【{res.message}】");
                                content = WebResponseContent.Instance.Error($"大堆垛机完成出库任务后回传MES失败!,任务号:【{taskNum}】,失败信息:【{res.message}】");
                            }
                        }
                        //if(task.TaskType== (int)TaskRelocationTypeEnum.Relocation&&!string.IsNullOrEmpty(task.Remark.Trim()))//出库任务写总层数标识
                        //{
´úÂë¹ÜÀí/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs
@@ -54,11 +54,12 @@
        public Task Execute(IJobExecutionContext context)
        {
            
             WriteDebug("线程统计日志", "线程数" + ThreadPool.ThreadCount);
             //WriteDebug("线程统计日志", "线程数" + ThreadPool.ThreadCount);
             //CommonStackerCrane commonStackerCrane = (CommonStackerCrane)context.JobDetail.JobDataMap.Get("JobParams");
             CommonStackerCrane commonStackerCrane = Storage.Devices.FirstOrDefault(x => x.DeviceCode == "SC01") as CommonStackerCrane;
            try
            {
            {
                if (commonStackerCrane != null)
                {
                   //WriteDebug("大堆垛机运行日志", $"大堆垛机任务执行中...");
@@ -75,8 +76,7 @@
                        {
                            Dt_Task? task = GetTask(commonStackerCrane);
                            if (task != null)
                            {
                            {
                                WriteDebug(nameof(CommonStackerCraneJob), $"大堆垛机任务号{task.TaskNum}");
                                StackerCraneTaskCommand? stackerCraneTaskCommand = ConvertToStackerCraneTaskCommand(task);
                                if (stackerCraneTaskCommand != null)
@@ -136,7 +136,7 @@
                    //读取大堆垛机任务号和任务完成确认状态(因为封装的事件经常不触发,所以加个直接读的逻辑,以免出现堆垛机一直接处于等待wcs确认)
                    byte IsOver = commonStackerCrane.Communicator.Read<byte>("DB106.22");
                    int tasknum = commonStackerCrane.Communicator.Read<int>("DB106.18");
                    WriteDebug(nameof(CommonStackerCraneJob), $"大堆垛机SC01任务号堆垛机任务号:{tasknum}状态:{IsOver}");
                    //WriteDebug(nameof(CommonStackerCraneJob), $"大堆垛机SC01任务号堆垛机任务号:{tasknum}状态:{IsOver}");
                    if (IsOver == 6)
                    {
                        if (commonStackerCrane.GetValue<StackerCraneDBName, short>(StackerCraneDBName.WorkType) != 5)
@@ -191,10 +191,24 @@
                        {
                            IsAllow = commonStackerCrane.Communicator.Read<short>("DB2.8.0");
                        }
                        if (IsAllow == 1)//如果为1,则允计AGV进入,回传WMS
                        //查询任务标记为1的任务为空才允计回传
                        WriteDebug(nameof(CommonStackerCraneJob), $"任务号:{task1001.TaskNum}-是否允计:{IsAllow}");
                        Dt_Task? taskAgvIning = _taskService.QueryStackerCraneTaskByAGVIning("SC01");
                        if (IsAllow == 1&&taskAgvIning==null)//如果为1,则允计AGV进入,回传WMS
                        {
                            _taskService.UpdateTaskAllowIn(task1001.TaskNum, 1);
                            WriteDebug(nameof(CommonStackerCraneJob), $"更新是否进入升降机标志值1,任务号{task1001.TaskNum}");
                            IsAllow = 0;//更新成功,置0不允许
                            MESSendCMD sendcmd = new MESSendCMD { cmd = 2001, task_id = task1001.TaskNum, status = 6 };
                            MESResponse res = ApiInvoke.SendTaskCMD(sendcmd);
                            //if (res != null && res.code == 0)//回传2001成功
                            //{
                                //WCS读到允许信号后任务标记1,表示AGV已进入提升机,Dt_Task ä¸­çš„CurrentAddress做为标记字段
                                //_taskService.UpdateTaskAllowIn(task1001.TaskNum, 1);
                                //WriteDebug(nameof(CommonStackerCraneJob), $"更新是否进入升降机标志值1,任务号{task1001.TaskNum}");
                            //}
                        }
                    }
                    Dt_Task? task3001 = _taskService.QueryStackerCraneTaskByAGVPutFinish("SC01");
@@ -206,26 +220,23 @@
                        if (task3001.SourceAddress == "SC01-002-000-001")//WMS 1001站点
                        {
                            //提升机是否处于就绪状态
                            int IsReady = commonStackerCrane.Communicator.Read<short>("DB2.0.0");
                            WriteDebug(nameof(CommonStackerCraneJob), $"提升机状态:{IsReady}任务号:{task3001.TaskNum}");
                            WriteDebug(nameof(CommonStackerCraneJob), $"提升机是否就绪状态:{IsReady}任务号:{task3001.TaskNum}");
                            //写入提升信息
                            IsWriteOne = commonStackerCrane.Communicator.Read<short>("DB1.0.0");
                            if (IsWriteOne == 0 && IsReady == 1)
                            {
                                commonStackerCrane.Communicator.Write<short>("DB1.0.0", 1);
                            }
                            }
                            //读取提升机信号,确定是否提升完成
                            IsFinish = commonStackerCrane.Communicator.Read<short>("DB2.2.0");
                        }
                        else if (task3001.SourceAddress == "SC01-002-000-002")//WMS 1002站点
                        {
                            //提升机是否处于就绪状态
                            int IsReady = commonStackerCrane.Communicator.Read<short>("DB2.0.0");
                            WriteDebug(nameof(CommonStackerCraneJob), $"提升机状态:{IsReady}任务号:{task3001.TaskNum}");
                            WriteDebug(nameof(CommonStackerCraneJob), $"提升机是否就绪状态:{IsReady}任务号:{task3001.TaskNum}");
                            //写入提升信息
                            IsWriteTwo = commonStackerCrane.Communicator.Read<short>("DB1.6.0");
                            if (IsWriteTwo == 0 && IsReady == 1)
@@ -235,17 +246,37 @@
                           
                            //读取提升机信号,确定是否提升完成
                            IsFinish = commonStackerCrane.Communicator.Read<short>("DB2.10.0");
                        }
                        if (IsFinish == 1)//如果为1,则表示提升完成,回传WMS
                        {
                            MESSendCMD sendcmd = new MESSendCMD { cmd = 2002, task_id = task3001.TaskNum, status = 6 };
                            MESResponse res = ApiInvoke.SendTaskCMD(sendcmd);
                            string inparam = JsonConvert.SerializeObject(sendcmd);
                            WriteDebug(nameof(CommonStackerCraneJob), $"提升机提升完成,回传WMS,入参:{inparam}");
                            if (res != null && res.code != 0)
                            if (task3001.WMSId == 3)// WCS人工入库
                            {
                                WriteDebug(nameof(CommonStackerCraneJob), $"提升机提升完成,回传WMS失败!任务号{task3001.TaskNum}");
                                MESTaskDTO taskDTO = new MESTaskDTO();
                                taskDTO.weight = task3001.TaskNum;//旧任务号
                                taskDTO.cmd = 101;
                                _taskService.ReceiveWCSTask(taskDTO);
                            }
                            else
                            {
                                MESSendCMD sendcmd = new MESSendCMD { cmd = 2002, task_id = task3001.TaskNum, status = 6 };
                                MESResponse res = ApiInvoke.SendTaskCMD(sendcmd);
                                string inparam = JsonConvert.SerializeObject(sendcmd);
                                WriteDebug(nameof(CommonStackerCraneJob), $"提升机提升完成,回传WMS,入参:{inparam}");
                                if (res != null && res.code == 0)
                                {
                                    _taskService.UpdateTaskAllowIn(task3001.TaskNum, 0);
                                    WriteDebug(nameof(CommonStackerCraneJob), $"更新是否进入升降机标志值0,任务号{task3001.TaskNum}");
                                }
                                else
                                {
                                    WriteDebug(nameof(CommonStackerCraneJob), $"提升机提升完成,回传WMS失败!任务号{task3001.TaskNum}");
                                }
                            }
                        }
                       
´úÂë¹ÜÀí/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/DoubleStackerCraneJob.cs
@@ -66,7 +66,7 @@
                    CommonStackerCrane? StackerCrane = GetStrackerCrane(task, stackerCraneOne, stackerCraneTwo);
                    if (StackerCrane != null)
                    {
                        WriteDebug(nameof(DoubleStackerCraneJob), $"小堆垛机任务号{task.TaskNum}");
                        WriteDebug(nameof(DoubleStackerCraneJob), $"小堆垛机任务号{task.TaskNum}--{StackerCrane.DeviceCode}");
                        StackerCraneTaskCommand? stackerCraneTaskCommand = ConvertToStackerCraneTaskCommand(task);
                        if (stackerCraneTaskCommand != null)
                        {