自动化立体仓库 - WCS系统
#
LSH
2024-03-02 e315f19e12a301c8406ce4594a617e477e50ab7b
#
30个文件已添加
4个文件已修改
3704 ■■■■■ 已修改文件
src/main/java/com/zy/asrs/entity/BasSte.java 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/BasSteErr.java 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/BasSteErrLog.java 263 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/BasSteOpt.java 341 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/mapper/BasSteErrLogMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/mapper/BasSteErrMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/mapper/BasSteMapper.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/mapper/BasSteOptMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/BasSteErrLogService.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/BasSteErrService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/BasSteOptService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/BasSteService.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/BasSteErrLogServiceImpl.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/BasSteErrServiceImpl.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/BasSteOptServiceImpl.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/BasSteServiceImpl.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/utils/SteUtils.java 424 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/News.java 220 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/cache/OutputQueue.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/SlaveType.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/SteABType.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/SteChargeType.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/SteHisTaskStatusType.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/SteLocaType.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/SteStatusType.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/SteTaskModeType.java 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/SteSlave.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/command/SteCommand.java 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/protocol/SteProtocol.java 302 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/SiemensDevpThread.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/SteThread.java 529 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/index.html 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/news.html 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/ste.html 508 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/BasSte.java
New file
@@ -0,0 +1,197 @@
package com.zy.asrs.entity;
import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.core.common.Cools;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
@Data
@TableName("asr_bas_ste")
public class BasSte implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 穿梭车号
     */
    @ApiModelProperty(value= "穿梭车号")
    @TableId(value = "ste_no", type = IdType.INPUT)
    @TableField("ste_no")
    private Integer steNo;
    /**
     * 可入
     */
    @ApiModelProperty(value= "可入")
    @TableField("in_enable")
    private String inEnable;
    /**
     * 可出
     */
    @ApiModelProperty(value= "可出")
    @TableField("out_enable")
    private String outEnable;
    /**
     * 状态
     */
    @ApiModelProperty(value= "状态")
    @TableField("ste_sts")
    private Integer steSts;
    /**
     * 任务号
     */
    @ApiModelProperty(value= "任务号")
    @TableField("wrk_no")
    private Integer wrkNo;
    /**
     * 任务号
     */
    @ApiModelProperty(value= "堆垛机号")
    @TableField("crn_no")
    private Integer crnNo;
    /**
     * 排
     */
    @ApiModelProperty(value= "排")
    private Integer row;
    /**
     * 列
     */
    @ApiModelProperty(value= "列")
    private Integer bay;
    /**
     * 层
     */
    @ApiModelProperty(value= "层")
    private Integer lev;
    /**
     * 历史排
     */
    @ApiModelProperty(value= "历史排")
    @TableField("his_row")
    private Integer hisRow;
    /**
     * 历史列
     */
    @ApiModelProperty(value= "历史列")
    @TableField("his_bay")
    private Integer hisBay;
    /**
     * 历史层
     */
    @ApiModelProperty(value= "历史层")
    @TableField("his_lev")
    private Integer hisLev;
    /**
     * 暂存库位
     */
    @ApiModelProperty(value= "暂存库位")
    @TableField("idle_loc")
    private String idleLoc;
    /**
     * 错误码
     */
    @ApiModelProperty(value= "错误码")
    @TableField("ste_err")
    private Long steErr;
    /**
     * 标记
     */
    @ApiModelProperty(value= "标记")
    @TableField("pak_mk")
    private String pakMk;
    /**
     * 自动充电
     */
    @ApiModelProperty(value= "自动充电")
    @TableField("auto_charge")
    private String autoCharge;
    /**
     * 最低电量
     */
    @ApiModelProperty(value= "最低电量")
    @TableField("charge_line")
    private String chargeLine;
    /**
     * 状态 1: 正常  0: 禁用
     */
    @ApiModelProperty(value= "状态 1: 正常  0: 禁用  ")
    private Integer status;
    /**
     * 添加人员
     */
    @ApiModelProperty(value= "添加人员")
    @TableField("create_by")
    private Long createBy;
    /**
     * 添加时间
     */
    @ApiModelProperty(value= "添加时间")
    @TableField("create_time")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date createTime;
    /**
     * 修改人员
     */
    @ApiModelProperty(value= "修改人员")
    @TableField("update_by")
    private Long updateBy;
    /**
     * 修改时间
     */
    @ApiModelProperty(value= "修改时间")
    @TableField("update_time")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date updateTime;
    /**
     * 备注
     */
    @ApiModelProperty(value= "备注")
    private String memo;
    public String getCreateTime$(){
        if (Cools.isEmpty(this.createTime)){
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.createTime);
    }
    public String getUpdateTime$(){
        if (Cools.isEmpty(this.updateTime)){
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.updateTime);
    }
}
src/main/java/com/zy/asrs/entity/BasSteErr.java
New file
@@ -0,0 +1,148 @@
package com.zy.asrs.entity;
import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.core.common.Cools;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
@TableName("asr_bas_ste_err")
public class BasSteErr implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 异常码
     */
    @ApiModelProperty(value= "异常码")
    @TableId(value = "error_code", type = IdType.INPUT)
    @TableField("error_code")
    private Long errorCode;
    /**
     * 异常
     */
    @ApiModelProperty(value= "异常")
    @TableField("err_name")
    private String errName;
    /**
     * 修改人员
     */
    @ApiModelProperty(value= "修改人员")
    @TableField("modi_user")
    private Long modiUser;
    /**
     * 修改时间
     */
    @ApiModelProperty(value= "修改时间")
    @TableField("modi_time")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date modiTime;
    /**
     * 添加人员
     */
    @ApiModelProperty(value= "添加人员")
    @TableField("appe_user")
    private Long appeUser;
    /**
     * 添加时间
     */
    @ApiModelProperty(value= "添加时间")
    @TableField("appe_time")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date appeTime;
    public BasSteErr() {}
    public BasSteErr(Long errorCode,String errName,Long modiUser,Date modiTime,Long appeUser,Date appeTime) {
        this.errorCode = errorCode;
        this.errName = errName;
        this.modiUser = modiUser;
        this.modiTime = modiTime;
        this.appeUser = appeUser;
        this.appeTime = appeTime;
    }
//    BasSteErr basSteErr = new BasSteErr(
//            null,    // 异常码[非空]
//            null,    // 异常
//            null,    // 修改人员
//            null,    // 修改时间
//            null,    // 添加人员
//            null    // 添加时间
//    );
    public Long getErrorCode() {
        return errorCode;
    }
    public void setErrorCode(Long errorCode) {
        this.errorCode = errorCode;
    }
    public String getErrName() {
        return errName;
    }
    public void setErrName(String errName) {
        this.errName = errName;
    }
    public Long getModiUser() {
        return modiUser;
    }
    public void setModiUser(Long modiUser) {
        this.modiUser = modiUser;
    }
    public Date getModiTime() {
        return modiTime;
    }
    public String getModiTime$(){
        if (Cools.isEmpty(this.modiTime)){
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.modiTime);
    }
    public void setModiTime(Date modiTime) {
        this.modiTime = modiTime;
    }
    public Long getAppeUser() {
        return appeUser;
    }
    public void setAppeUser(Long appeUser) {
        this.appeUser = appeUser;
    }
    public Date getAppeTime() {
        return appeTime;
    }
    public String getAppeTime$(){
        if (Cools.isEmpty(this.appeTime)){
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.appeTime);
    }
    public void setAppeTime(Date appeTime) {
        this.appeTime = appeTime;
    }
}
src/main/java/com/zy/asrs/entity/BasSteErrLog.java
New file
@@ -0,0 +1,263 @@
package com.zy.asrs.entity;
import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.core.common.Cools;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
@Data
@TableName("asr_bas_ste_err_log")
public class BasSteErrLog implements Serializable {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty(value= "")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * 编号
     */
    @ApiModelProperty(value= "编号")
    private String uuid;
    /**
     * 工作号
     */
    @ApiModelProperty(value= "工作号")
    @TableField("wrk_no")
    private Integer wrkNo;
    /**
     * 发生时间
     */
    @ApiModelProperty(value= "发生时间")
    @TableField("start_time")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date startTime;
    /**
     * 结束时间
     */
    @ApiModelProperty(value= "结束时间")
    @TableField("end_time")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date endTime;
    /**
     * 工作状态
     */
    @ApiModelProperty(value= "工作状态")
    @TableField("wrk_sts")
    private Long wrkSts;
    /**
     * 入出库类型
     */
    @ApiModelProperty(value= "入出库类型")
    @TableField("io_type")
    private Integer ioType;
    /**
     * 穿梭车
     */
    @ApiModelProperty(value= "穿梭车")
    @TableField("ste_no")
    private Integer steNo;
    /**
     * plc
     */
    @ApiModelProperty(value= "plc")
    @TableField("plc_no")
    private Integer plcNo;
    /**
     * 目标库位
     */
    @ApiModelProperty(value= "目标库位")
    @TableField("loc_no")
    private String locNo;
    /**
     * 目标站
     */
    @ApiModelProperty(value= "目标站")
    @TableField("sta_no")
    private Integer staNo;
    /**
     * 源站
     */
    @ApiModelProperty(value= "源站")
    @TableField("source_sta_no")
    private Integer sourceStaNo;
    /**
     * 源库位
     */
    @ApiModelProperty(value= "源库位")
    @TableField("source_loc_no")
    private String sourceLocNo;
    /**
     * 条码
     */
    @ApiModelProperty(value= "条码")
    private String barcode;
    /**
     * 异常码
     */
    @ApiModelProperty(value= "异常码")
    @TableField("err_code")
    private Integer errCode;
    /**
     * 异常
     */
    @ApiModelProperty(value= "异常")
    private String error;
    /**
     * 异常情况 1: 未处理  2: 已修复
     */
    @ApiModelProperty(value= "异常情况 1: 未处理  2: 已修复  ")
    private Integer status;
    /**
     * 添加时间
     */
    @ApiModelProperty(value= "添加时间")
    @TableField("create_time")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date createTime;
    /**
     * 添加人员
     */
    @ApiModelProperty(value= "添加人员")
    @TableField("create_by")
    private Long createBy;
    /**
     * 修改时间
     */
    @ApiModelProperty(value= "修改时间")
    @TableField("update_time")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date updateTime;
    /**
     * 修改人员
     */
    @ApiModelProperty(value= "修改人员")
    @TableField("update_by")
    private Long updateBy;
    /**
     * 备注
     */
    @ApiModelProperty(value= "备注")
    private String memo;
    public BasSteErrLog() {}
    public BasSteErrLog(String uuid, Integer wrkNo, Date startTime, Date endTime, Long wrkSts, Integer ioType, Integer steNo, Integer plcNo, String locNo, Integer staNo, Integer sourceStaNo, String sourceLocNo, String barcode, Integer errCode, String error, Integer status, Date createTime, Long createBy, Date updateTime, Long updateBy, String memo) {
        this.uuid = uuid;
        this.wrkNo = wrkNo;
        this.startTime = startTime;
        this.endTime = endTime;
        this.wrkSts = wrkSts;
        this.ioType = ioType;
        this.steNo = steNo;
        this.plcNo = plcNo;
        this.locNo = locNo;
        this.staNo = staNo;
        this.sourceStaNo = sourceStaNo;
        this.sourceLocNo = sourceLocNo;
        this.barcode = barcode;
        this.errCode = errCode;
        this.error = error;
        this.status = status;
        this.createTime = createTime;
        this.createBy = createBy;
        this.updateTime = updateTime;
        this.updateBy = updateBy;
        this.memo = memo;
    }
//    BasSteErrLog basSteErrLog = new BasSteErrLog(
//            null,    // 编号
//            null,    // 工作号
//            null,    // 发生时间
//            null,    // 结束时间
//            null,    // 工作状态
//            null,    // 入出库类型
//            null,    // 穿梭车
//            null,    // plc
//            null,    // 目标库位
//            null,    // 目标站
//            null,    // 源站
//            null,    // 源库位
//            null,    // 条码
//            null,    // 异常码
//            null,    // 异常
//            null,    // 异常情况
//            null,    // 添加时间
//            null,    // 添加人员
//            null,    // 修改时间
//            null,    // 修改人员
//            null    // 备注
//    );
    public String getStartTime$(){
        if (Cools.isEmpty(this.startTime)){
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.startTime);
    }
    public String getEndTime$(){
        if (Cools.isEmpty(this.endTime)){
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.endTime);
    }
    public String getStatus$(){
        if (null == this.status){ return null; }
        switch (this.status){
            case 1:
                return "未处理";
            case 2:
                return "已修复";
            default:
                return String.valueOf(this.status);
        }
    }
    public String getCreateTime$(){
        if (Cools.isEmpty(this.createTime)){
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.createTime);
    }
    public String getUpdateTime$(){
        if (Cools.isEmpty(this.updateTime)){
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.updateTime);
    }
}
src/main/java/com/zy/asrs/entity/BasSteOpt.java
New file
@@ -0,0 +1,341 @@
package com.zy.asrs.entity;
import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.core.common.Cools;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
@TableName("asr_bas_ste_opt")
public class BasSteOpt implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * ID
     */
    @ApiModelProperty(value= "ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * 任务号
     */
    @ApiModelProperty(value= "任务号")
    @TableField("wrk_no")
    private Integer wrkNo;
    /**
     * 穿梭车
     */
    @ApiModelProperty(value= "穿梭车")
    @TableField("ste_no")
    private Integer steNo;
    /**
     * 下发时间
     */
    @ApiModelProperty(value= "下发时间")
    @TableField("send_time")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date sendTime;
    /**
     * 作业
     */
    @ApiModelProperty(value= "作业")
    private String mode;
    /**
     * 源排
     */
    @ApiModelProperty(value= "源排")
    @TableField("source_row")
    private Integer sourceRow;
    /**
     * 源列
     */
    @ApiModelProperty(value= "源列")
    @TableField("source_bay")
    private Integer sourceBay;
    /**
     * 源层
     */
    @ApiModelProperty(value= "源层")
    @TableField("source_lev")
    private Integer sourceLev;
    /**
     * 源站
     */
    @ApiModelProperty(value= "源站")
    @TableField("source_sta")
    private Integer sourceSta;
    /**
     * 目标排
     */
    @ApiModelProperty(value= "目标排")
    @TableField("pos_row")
    private Integer posRow;
    /**
     * 目标列
     */
    @ApiModelProperty(value= "目标列")
    @TableField("pos_bay")
    private Integer posBay;
    /**
     * 目标层
     */
    @ApiModelProperty(value= "目标层")
    @TableField("pos_lev")
    private Integer posLev;
    /**
     * 目标站
     */
    @ApiModelProperty(value= "目标站")
    @TableField("pos_sta")
    private Integer posSta;
    /**
     * 响应结果 1: 正常  0: 失败
     */
    @ApiModelProperty(value= "响应结果 1: 正常  0: 失败  ")
    private Integer response;
    /**
     * 修改时间
     */
    @ApiModelProperty(value= "修改时间")
    @TableField("update_time")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date updateTime;
    /**
     * 修改人员
     */
    @ApiModelProperty(value= "修改人员")
    @TableField("update_by")
    private Long updateBy;
    /**
     * 备注
     */
    @ApiModelProperty(value= "备注")
    private String memo;
    public BasSteOpt() {}
    public BasSteOpt(Integer wrkNo,Integer steNo,Date sendTime,String mode,Integer sourceRow,Integer sourceBay,Integer sourceLev,Integer sourceSta,Integer posRow,Integer posBay,Integer posLev,Integer posSta,Integer response,Date updateTime,Long updateBy,String memo) {
        this.wrkNo = wrkNo;
        this.steNo = steNo;
        this.sendTime = sendTime;
        this.mode = mode;
        this.sourceRow = sourceRow;
        this.sourceBay = sourceBay;
        this.sourceLev = sourceLev;
        this.sourceSta = sourceSta;
        this.posRow = posRow;
        this.posBay = posBay;
        this.posLev = posLev;
        this.posSta = posSta;
        this.response = response;
        this.updateTime = updateTime;
        this.updateBy = updateBy;
        this.memo = memo;
    }
//    BasSteOpt basSteOpt = new BasSteOpt(
//            null,    // 任务号
//            null,    // 穿梭车
//            null,    // 下发时间
//            null,    // 作业
//            null,    // 源排
//            null,    // 源列
//            null,    // 源层
//            null,    // 源站
//            null,    // 目标排
//            null,    // 目标列
//            null,    // 目标层
//            null,    // 目标站
//            null,    // 响应结果
//            null,    // 修改时间
//            null,    // 修改人员
//            null    // 备注
//    );
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public Integer getWrkNo() {
        return wrkNo;
    }
    public void setWrkNo(Integer wrkNo) {
        this.wrkNo = wrkNo;
    }
    public Integer getSteNo() {
        return steNo;
    }
    public void setSteNo(Integer steNo) {
        this.steNo = steNo;
    }
    public Date getSendTime() {
        return sendTime;
    }
    public String getSendTime$(){
        if (Cools.isEmpty(this.sendTime)){
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.sendTime);
    }
    public void setSendTime(Date sendTime) {
        this.sendTime = sendTime;
    }
    public String getMode() {
        return mode;
    }
    public void setMode(String mode) {
        this.mode = mode;
    }
    public Integer getSourceRow() {
        return sourceRow;
    }
    public void setSourceRow(Integer sourceRow) {
        this.sourceRow = sourceRow;
    }
    public Integer getSourceBay() {
        return sourceBay;
    }
    public void setSourceBay(Integer sourceBay) {
        this.sourceBay = sourceBay;
    }
    public Integer getSourceLev() {
        return sourceLev;
    }
    public void setSourceLev(Integer sourceLev) {
        this.sourceLev = sourceLev;
    }
    public Integer getSourceSta() {
        return sourceSta;
    }
    public void setSourceSta(Integer sourceSta) {
        this.sourceSta = sourceSta;
    }
    public Integer getPosRow() {
        return posRow;
    }
    public void setPosRow(Integer posRow) {
        this.posRow = posRow;
    }
    public Integer getPosBay() {
        return posBay;
    }
    public void setPosBay(Integer posBay) {
        this.posBay = posBay;
    }
    public Integer getPosLev() {
        return posLev;
    }
    public void setPosLev(Integer posLev) {
        this.posLev = posLev;
    }
    public Integer getPosSta() {
        return posSta;
    }
    public void setPosSta(Integer posSta) {
        this.posSta = posSta;
    }
    public Integer getResponse() {
        return response;
    }
    public String getResponse$(){
        if (null == this.response){ return null; }
        switch (this.response){
            case 1:
                return "正常";
            case 0:
                return "失败";
            default:
                return String.valueOf(this.response);
        }
    }
    public void setResponse(Integer response) {
        this.response = response;
    }
    public Date getUpdateTime() {
        return updateTime;
    }
    public String getUpdateTime$(){
        if (Cools.isEmpty(this.updateTime)){
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.updateTime);
    }
    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }
    public Long getUpdateBy() {
        return updateBy;
    }
    public void setUpdateBy(Long updateBy) {
        this.updateBy = updateBy;
    }
    public String getMemo() {
        return memo;
    }
    public void setMemo(String memo) {
        this.memo = memo;
    }
}
src/main/java/com/zy/asrs/mapper/BasSteErrLogMapper.java
New file
@@ -0,0 +1,12 @@
package com.zy.asrs.mapper;
import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.zy.asrs.entity.BasSteErrLog;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface BasSteErrLogMapper extends BaseMapper<BasSteErrLog> {
}
src/main/java/com/zy/asrs/mapper/BasSteErrMapper.java
New file
@@ -0,0 +1,12 @@
package com.zy.asrs.mapper;
import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.zy.asrs.entity.BasSteErr;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface BasSteErrMapper extends BaseMapper<BasSteErr> {
}
src/main/java/com/zy/asrs/mapper/BasSteMapper.java
New file
@@ -0,0 +1,17 @@
package com.zy.asrs.mapper;
import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.zy.asrs.entity.BasSte;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface BasSteMapper extends BaseMapper<BasSte> {
    int updatePos(@Param("steNo")Integer steNo, @Param("row")Integer row, @Param("bay")Integer bay, @Param("lev")Integer lev);
    int updatePakMk(@Param("steNo")Integer steNo, @Param("pakMk")String pakMk);
}
src/main/java/com/zy/asrs/mapper/BasSteOptMapper.java
New file
@@ -0,0 +1,12 @@
package com.zy.asrs.mapper;
import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.zy.asrs.entity.BasSteOpt;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface BasSteOptMapper extends BaseMapper<BasSteOpt> {
}
src/main/java/com/zy/asrs/service/BasSteErrLogService.java
New file
@@ -0,0 +1,12 @@
package com.zy.asrs.service;
import com.baomidou.mybatisplus.service.IService;
import com.zy.asrs.entity.BasSteErrLog;
public interface BasSteErrLogService extends IService<BasSteErrLog> {
    BasSteErrLog findLatestByTaskNo(Integer steNo, Integer taskNo);
    BasSteErrLog findLatest(Integer steNo);
}
src/main/java/com/zy/asrs/service/BasSteErrService.java
New file
@@ -0,0 +1,8 @@
package com.zy.asrs.service;
import com.baomidou.mybatisplus.service.IService;
import com.zy.asrs.entity.BasSteErr;
public interface BasSteErrService extends IService<BasSteErr> {
}
src/main/java/com/zy/asrs/service/BasSteOptService.java
New file
@@ -0,0 +1,8 @@
package com.zy.asrs.service;
import com.baomidou.mybatisplus.service.IService;
import com.zy.asrs.entity.BasSteOpt;
public interface BasSteOptService extends IService<BasSteOpt> {
}
src/main/java/com/zy/asrs/service/BasSteService.java
New file
@@ -0,0 +1,14 @@
package com.zy.asrs.service;
import com.baomidou.mybatisplus.service.IService;
import com.zy.asrs.entity.BasSte;
public interface BasSteService extends IService<BasSte> {
    Boolean updatePos(Integer steNo, Integer row, Integer bay, Integer lev);
    Boolean updatePakMk(Integer steNo, String pakMk);
    Integer hasCarOfLocNo(String locNo);
}
src/main/java/com/zy/asrs/service/impl/BasSteErrLogServiceImpl.java
New file
@@ -0,0 +1,35 @@
package com.zy.asrs.service.impl;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.zy.asrs.entity.BasSteErrLog;
import com.zy.asrs.mapper.BasSteErrLogMapper;
import com.zy.asrs.service.BasSteErrLogService;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("basSteErrLogService")
public class BasSteErrLogServiceImpl extends ServiceImpl<BasSteErrLogMapper, BasSteErrLog> implements BasSteErrLogService {
    @Override
    public BasSteErrLog findLatestByTaskNo(Integer steNo, Integer taskNo) {
        List<BasSteErrLog> basSteErrLogs = this.baseMapper.selectList(new EntityWrapper<BasSteErrLog>().eq("ste_no", steNo).eq("wrk_no", taskNo).orderBy("start_time", false));
        if (basSteErrLogs == null || basSteErrLogs.size() == 0) {
            return null;
        } else {
            return basSteErrLogs.get(0);
        }
    }
    @Override
    public BasSteErrLog findLatest(Integer steNo) {
        List<BasSteErrLog> basSteErrLogs = this.baseMapper.selectList(new EntityWrapper<BasSteErrLog>().eq("ste_no", steNo).orderBy("start_time", false));
        if (basSteErrLogs == null || basSteErrLogs.size() == 0) {
            return null;
        } else {
            return basSteErrLogs.get(0);
        }
    }
}
src/main/java/com/zy/asrs/service/impl/BasSteErrServiceImpl.java
New file
@@ -0,0 +1,12 @@
package com.zy.asrs.service.impl;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.zy.asrs.entity.BasSteErr;
import com.zy.asrs.mapper.BasSteErrMapper;
import com.zy.asrs.service.BasSteErrService;
import org.springframework.stereotype.Service;
@Service("basSteErrService")
public class BasSteErrServiceImpl extends ServiceImpl<BasSteErrMapper, BasSteErr> implements BasSteErrService {
}
src/main/java/com/zy/asrs/service/impl/BasSteOptServiceImpl.java
New file
@@ -0,0 +1,12 @@
package com.zy.asrs.service.impl;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.zy.asrs.entity.BasSteOpt;
import com.zy.asrs.mapper.BasSteOptMapper;
import com.zy.asrs.service.BasSteOptService;
import org.springframework.stereotype.Service;
@Service("basSteOptService")
public class BasSteOptServiceImpl extends ServiceImpl<BasSteOptMapper, BasSteOpt> implements BasSteOptService {
}
src/main/java/com/zy/asrs/service/impl/BasSteServiceImpl.java
New file
@@ -0,0 +1,41 @@
package com.zy.asrs.service.impl;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.zy.asrs.entity.BasSte;
import com.zy.asrs.mapper.BasSteMapper;
import com.zy.asrs.service.BasSteService;
import com.zy.asrs.utils.Utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j
@Service("basSteService")
public class BasSteServiceImpl extends ServiceImpl<BasSteMapper, BasSte> implements BasSteService {
    @Override
    public Boolean updatePos(Integer steNo, Integer row, Integer bay, Integer lev) {
        return this.baseMapper.updatePos(steNo, row, bay, lev) > 0;
    }
    @Override
    public Boolean updatePakMk(Integer steNo, String pakMk) {
        return this.baseMapper.updatePakMk(steNo, pakMk) > 0;
    }
    @Override
    public Integer hasCarOfLocNo(String locNo) {
        List<BasSte> basStes = this.selectList(new EntityWrapper<>());
        for (BasSte basSte : basStes) {
            if (Utils.getRow(locNo) == basSte.getRow()
                && Utils.getBay(locNo) == basSte.getBay()
                && Utils.getLev(locNo) == basSte.getLev()){
                return basSte.getSteNo();
            }
        }
        return null;
    }
}
src/main/java/com/zy/asrs/utils/SteUtils.java
New file
@@ -0,0 +1,424 @@
package com.zy.asrs.utils;
import com.core.common.Arith;
import com.core.common.Cools;
import com.zy.core.properties.SlaveProperties;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
 * Created by vincent on 2020/8/27
 */
public class SteUtils {
    public static final List<Integer> SHUTTLE_GROUP_ROW_LIST = new ArrayList<Integer>() {{
        add(2);add(3);add(4);add(5);add(6);add(7);add(8);add(9);add(10);
        add(11);add(12);
    }};
    public static final List<Integer> SECOND_GROUP_ROW_LIST = new ArrayList<Integer>() {{
        add(2);
        add(3);
        add(4);
        add(5);
        add(6);
    }};
    public static final List<Integer> THIRD_GROUP_ROW_LIST = new ArrayList<Integer>() {{
        add(8);
        add(9);
        add(10);
        add(11);
        add(12);
    }};
    public static final List<Integer> THIRD_GROUP_BAY_LIST = new ArrayList<Integer>() {{
        add(4);
        add(10);
        add(16);
        add(22);
    }};
    private static final DecimalFormat fmt = new DecimalFormat("##0.00");
    public static float scale(Float f){
        if (f == null || f == 0f || Float.isNaN(f)) {
            return 0f;
        }
        return (float) Arith.multiplys(2, f, 1);
    }
    public static String zerofill(String msg, Integer count){
        if (msg.length() == count){
            return msg;
        } else if (msg.length() > count){
            return msg.substring(0, 16);
        } else {
            StringBuilder msgBuilder = new StringBuilder(msg);
            for (int i = 0; i<count-msg.length(); i++){
                msgBuilder.insert(0,"0");
            }
            return msgBuilder.toString();
        }
    }
    public static Integer getGroupRow(String locNo, Boolean pakin, Integer crnNo){
        int row = getRow(locNo);
        return getGroupRow(row, pakin, crnNo);
    }
    public static List<String> getGroupLocNo(String locNo){
        int row = getRow(locNo);
        int bay = getBay(locNo);
        List<String> result = new ArrayList<>();
        if (bay==4 || bay==10 || bay==16 || bay==22){
            if(row<7 && row>1)
            {
                if (SECOND_GROUP_ROW_LIST.contains(row)) {
                    for (Integer groupRow : SECOND_GROUP_ROW_LIST) {
                        result.add(zerofill(String.valueOf(groupRow), 2) + locNo.substring(2));
                    }
                }
            } else if(row>7 && row<13){
                if (THIRD_GROUP_ROW_LIST.contains(row)) {
                    for (Integer groupRow : THIRD_GROUP_ROW_LIST) {
                        result.add(zerofill(String.valueOf(groupRow), 2) + locNo.substring(2));
                    }
                }
            }
        } else{
            if (SHUTTLE_GROUP_ROW_LIST.contains(row)) {
                for (Integer groupRow : SHUTTLE_GROUP_ROW_LIST) {
                    result.add(zerofill(String.valueOf(groupRow), 2) + locNo.substring(2));
                }
            }
        }
        return result;
    }
    public static Integer getGroupRow(Integer row, Boolean pakin, Integer crnNo) {
        if (pakin) {
            if (SHUTTLE_GROUP_ROW_LIST.contains(row)) {
                return crnNo == 1 ? 2 : 12;
            } else {
                return row;
            }
        } else {
            if (SHUTTLE_GROUP_ROW_LIST.contains(row)) {
                return crnNo == 1 ? 2 : 12;
            } else {
                return row;
            }
        }
    }
    /**
     * 判断库位是否为穿梭库位
     * @param locNo
     * @return
     */
    public static Boolean isShuttle(String locNo) {
        int row = Utils.getRow(locNo);
        if (row >= 2 && row <= 12) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }
    /**
     * 入库,堆垛机号1:最外层库位是2排; 2:最外层库位是12排
     * 出库,堆垛机号1:最外层库位是2排; 2:最外层库位是12排
     * @param locNo 库位号
     * @param pakin 入库
     * @param crnNo 堆垛机号
     * @return
     */
    public static Boolean isOutMost(String locNo, Boolean pakin, Integer crnNo) {
        switch (crnNo){
            case 1:
                return Integer.parseInt(locNo.substring(0, 2)) == 2;
            case 2:
                return Integer.parseInt(locNo.substring(0, 2)) == 12;
        }
        return false;
    }
    // -------------------------------------------------------------------------------------------------------------------
    /**
     * 判断是否为深库位
     */
    public static boolean isDeepLoc(SlaveProperties slaveProperties, String locNo){
        if (slaveProperties.isDoubleDeep()) {
            int row = getRow(locNo);
            return slaveProperties.getDoubleLocs().contains(row);
        } else {
            return false;
        }
    }
    /**
     * 判断是否为深库位
     */
    public static boolean isDeepLoc(SlaveProperties slaveProperties, Integer row){
        if (slaveProperties.isDoubleDeep()) {
            return slaveProperties.getDoubleLocs().contains(row);
        } else {
            return false;
        }
    }
    /**
     * 判断是否为浅库位
     */
    public static boolean isShallowLoc(SlaveProperties slaveProperties, String locNo){
        if (slaveProperties.isDoubleDeep()) {
            int row = getRow(locNo);
            return !slaveProperties.getDoubleLocs().contains(row);
        } else {
            return false;
        }
    }
    /**
     * 判断是否为浅库位
     */
    public static boolean isShallowLoc(SlaveProperties slaveProperties, Integer row){
        if (slaveProperties.isDoubleDeep()) {
            return !slaveProperties.getDoubleLocs().contains(row);
        } else {
            return false;
        }
    }
    /**
     * 获取 深库位对应的浅库位号
     */
    public static String getShallowLoc(SlaveProperties slaveProperties, String deepLoc) {
        int row = getRow(deepLoc);
        int remainder = (int) Arith.remainder(row, slaveProperties.getGroupCount());
        int shallowRow = remainder == 1 ? (row + 1) : (row - 1);
        return zerofill(String.valueOf(shallowRow), 2) + deepLoc.substring(2);
    }
    /**
     * 获取 深库位排对应的浅库位排
     */
    public static Integer getShallowRow(SlaveProperties slaveProperties, Integer deepRow) {
        int remainder = (int) Arith.remainder(deepRow, slaveProperties.getGroupCount());
        return remainder == 1 ? (deepRow + 1) : (deepRow - 1);
    }
    /**
     * 获取 浅库位对应的深库位号
     */
    public static String getDeepLoc(SlaveProperties slaveProperties, String shallowLoc) {
        int row = getRow(shallowLoc);
        int remainder = (int) Arith.remainder(row, slaveProperties.getGroupCount());
        int targetRow;
        if (remainder == 2) {
            targetRow = row - 1;
        } else if (remainder == 1) {
            targetRow = row + 1;
        } else {
            throw new RuntimeException(shallowLoc + "不是浅库位,系统繁忙");
        }
        return zerofill(String.valueOf(targetRow), 2) + shallowLoc.substring(2);
    }
    /**
     * 获取 浅库位排对应的深库位排
     */
    public static Integer getDeepRow(SlaveProperties slaveProperties, Integer shallowRow) {
        int remainder = (int) Arith.remainder(shallowRow, slaveProperties.getGroupCount());
        int targetRow;
        if (remainder == 2) {
            targetRow = shallowRow - 1;
        } else if (remainder == 1) {
            targetRow = shallowRow + 1;
        } else {
            throw new RuntimeException(shallowRow + "不是浅库位排,系统繁忙");
        }
        return targetRow;
    }
    /**
     * 通过库位号获取 排
     */
    public static int getRow(String locNo) {
        if (!Cools.isEmpty(locNo)) {
            return Integer.parseInt(locNo.substring(0, 2));
        }
        throw new RuntimeException("库位解析异常");
    }
    /**
     * 通过库位号获取 列
     */
    public static int getBay(String locNo) {
        if (!Cools.isEmpty(locNo)) {
            return Integer.parseInt(locNo.substring(2, 5));
        }
        throw new RuntimeException("库位解析异常");
    }
    /**
     * 通过库位号获取 层
     */
    public static int getLev(String locNo) {
        if (!Cools.isEmpty(locNo)) {
            return Integer.parseInt(locNo.substring(5, 7));
        }
        throw new RuntimeException("库位解析异常");
    }
    /**
     * 通过排列层拼接出库位号
     */
    public static String append(int row, int bay, int lev) {
        return zerofill(String.valueOf(row), 2) + zerofill(String.valueOf(bay), 3) + zerofill(String.valueOf(lev), 2);
    }
    /**
     * 当检索到双深库位的浅库位时,如果深库位无货,则放入对应的深库位
     */
    public static void toDeepIfEmptyByShallow(String shallowLoc) {
        int row = getRow(shallowLoc);
        int remainder = (int) Arith.remainder(row, 4);
        int targetRow = 0;
        if (remainder == 2) {
            targetRow = row - 1;
        } else if (remainder == 3) {
            targetRow = row + 1;
        } else {
            throw new RuntimeException(shallowLoc + "不是浅库位,系统繁忙");
        }
        String targetLoc = zerofill(String.valueOf(targetRow), 2) + shallowLoc.substring(2);
    }
    public static String getLocNo(Number row, Number bay, Number lev) {
        return zerofill(String.valueOf(row), 2) + zerofill(String.valueOf(bay), 3) + zerofill(String.valueOf(lev), 2);
    }
    // 外侧方向的货位  优先入库方向/优先出库方向 ===>> 反之
    public static List<String> getGroupOutsideLoc(String locNo,Integer crnNo){
        //此方法取此排外侧库位
        int row = getRow(locNo);
        int bay = getBay(locNo);
        List<String> result = new ArrayList<>();
        if (THIRD_GROUP_BAY_LIST.contains(bay)){
            if (THIRD_GROUP_ROW_LIST.contains(row)) {
                List<Integer> clone = Arrays.asList(new Integer[THIRD_GROUP_ROW_LIST.size()]);
                Collections.copy(clone, THIRD_GROUP_ROW_LIST);
                Collections.reverse(clone);
                for (Integer integer : clone) {
                    if (integer > row) {
                        result.add(zerofill(String.valueOf(integer), 2) + locNo.substring(2));
                    } else {
                        break;
                    }
                }
            }else if (SECOND_GROUP_ROW_LIST.contains(row)) {
                for (Integer integer : SECOND_GROUP_ROW_LIST) {
                    if (integer < row) {
                        result.add(zerofill(String.valueOf(integer), 2) + locNo.substring(2));
                    } else {
                        break;
                    }
                }
            }
        }else {
            if (SHUTTLE_GROUP_ROW_LIST.contains(row)) {
                if (crnNo==1){
                    for (Integer integer : SHUTTLE_GROUP_ROW_LIST) {
                        if (integer < row) {
                            result.add(zerofill(String.valueOf(integer), 2) + locNo.substring(2));
                        } else {
                            break;
                        }
                    }
                }else {
                    List<Integer> clone = Arrays.asList(new Integer[SHUTTLE_GROUP_ROW_LIST.size()]);
                    Collections.copy(clone, SHUTTLE_GROUP_ROW_LIST);
                    Collections.reverse(clone);
                    for (Integer integer : clone) {
                        if (integer > row) {
                            result.add(zerofill(String.valueOf(integer), 2) + locNo.substring(2));
                        } else {
                            break;
                        }
                    }
                }
            }
        }
        return result;
    }
    // 外侧方向的货位  优先入库方向/优先出库方向 ===>> 反之
    public static List<String> getGroupOutsideLocPakin(String locNo,Integer crnNo){
        //   此方法取此排内侧库位
        int row = getRow(locNo);
        int bay = getBay(locNo);
        List<String> result = new ArrayList<>();
        if (THIRD_GROUP_BAY_LIST.contains(bay)){
            if (THIRD_GROUP_ROW_LIST.contains(row)) {
                for (Integer integer : THIRD_GROUP_ROW_LIST) {
                    if (integer < row) {
                        result.add(zerofill(String.valueOf(integer), 2) + locNo.substring(2));
                    } else {
                        break;
                    }
                }
            }else if (SECOND_GROUP_ROW_LIST.contains(row)) {
                List<Integer> clone = Arrays.asList(new Integer[SECOND_GROUP_ROW_LIST.size()]);
                Collections.copy(clone, SECOND_GROUP_ROW_LIST);
                Collections.reverse(clone);
                for (Integer integer : clone) {
                    if (integer > row) {
                        result.add(zerofill(String.valueOf(integer), 2) + locNo.substring(2));
                    } else {
                        break;
                    }
                }
            }
        }else {
            if (SHUTTLE_GROUP_ROW_LIST.contains(row)) {
                if (crnNo==2){
                    for (Integer integer : SHUTTLE_GROUP_ROW_LIST) {
                        if (integer < row) {
                            result.add(zerofill(String.valueOf(integer), 2) + locNo.substring(2));
                        } else {
                            break;
                        }
                    }
                }else {
                    List<Integer> clone = Arrays.asList(new Integer[SHUTTLE_GROUP_ROW_LIST.size()]);
                    Collections.copy(clone, SHUTTLE_GROUP_ROW_LIST);
                    Collections.reverse(clone);
                    for (Integer integer : clone) {
                        if (integer > row) {
                            result.add(zerofill(String.valueOf(integer), 2) + locNo.substring(2));
                        } else {
                            break;
                        }
                    }
                }
            }
        }
        return result;
    }
}
src/main/java/com/zy/core/News.java
New file
@@ -0,0 +1,220 @@
package com.zy.core;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.lang.reflect.Array;
import java.text.SimpleDateFormat;
import java.util.*;
/**
 * news stories for zoneyung
 * Created by vincent on 2022/12/22
 */
@Slf4j
@Component
public class News {
    public static void main(String[] args) {
        News.info("info{}", 1);
        News.warn("warn{}", 2);
        News.error("error{}", 3);
        System.out.println(News.print());
    }
    interface NewsSupport<T> { boolean execute(T t); }
    private static final NewsQueue<NewsDomain> NEWS_QUEUE = new NewsQueue<>(NewsDomain.class, 1024);
    @Value("${logging.enableEveryThreadLog}")
    private Boolean enableEveryThreadLog;
    //是否开启线程日志功能
    private static Boolean enable;
    @PostConstruct
    public void getEnableEveryThreadLog() {
        enable = this.enableEveryThreadLog;
    }
    @SuppressWarnings({"unchecked"})
    static class NewsQueue<T> {
        private final transient Class<T> cls;
        private final T[] arr;
        private final int capacity;
        private int head;
        private int tail;
        { this.head = 0; this.tail = 0; }
        public NewsQueue(Class<T> cls, int capacity) {
            this.cls = cls;
            this.arr = (T[]) Array.newInstance(cls, capacity);
            this.capacity = capacity;
        }
        public synchronized boolean offer(T t) {
            if (this.tail == this.capacity) {
                this.peek();
            }
            this.reform();
            this.arr[this.tail] = t;
            this.tail ++;
            return true;
        }
        public synchronized boolean put(T t) {
            if (this.tail == this.capacity) {
                return false;
            } else {
                this.reform();
            }
            this.arr[this.tail] = t;
            this.tail ++;
            return true;
        }
        public synchronized T peek() {
            if (this.head == this.tail) {
                return null;
            }
            T t = this.arr[this.head];
            this.head ++;
            this.reform();
            return t;
        }
        private void reform() {
            for (int i = this.head; i < this.tail; i++) {
                this.arr[i-this.head] = this.arr[i];
            }
            this.tail -= this.head;
            this.head = 0;
        }
        public synchronized int size() {
            return this.tail - this.head;
        }
        public synchronized List<T> data() {
            T[] ts = (T[]) Array.newInstance(this.cls, size());
            if (this.tail - this.head >= 0) {
                System.arraycopy(this.arr, this.head, ts, 0, this.tail - this.head);
            }
            return Arrays.asList(ts);
        }
    }
    public static void info(String format, Object... arguments) {
        if (enable) {
            MDC.put("threadName", "currentThread-" + Thread.currentThread().getName());
        }
        log.info(format, arguments);
        offer(NewsLevel.INFO, format, arguments);
        MDC.remove("threadName");
    }
    public static void infoNot(String format, Object... arguments) {
        log.info(format, arguments);
    }
    public static void warn(String format, Object... arguments) {
        if (enable) {
            MDC.put("threadName", "currentThread-" + Thread.currentThread().getName());
        }
        log.warn(format, arguments);
        offer(NewsLevel.WARN, format, arguments);
        MDC.remove("threadName");
    }
    public static void error(String format, Object... arguments) {
        if (enable) {
            MDC.put("threadName", "currentThread-" + Thread.currentThread().getName());
        }
        log.error(format, arguments);
        offer(NewsLevel.ERROR, format, arguments);
        MDC.remove("threadName");
    }
    public static void debug(String format, Object... arguments) {
        offer(NewsLevel.DEBUG, format, arguments);
    }
    public static String printStr() {
        StringBuilder sb = new StringBuilder("[");
        List<NewsDomain> domains = NEWS_QUEUE.data();
        for (int i = 0; i < domains.size(); i++) {
            NewsDomain domain = domains.get(i);
            sb.append("{");
            sb.append("\"l\":").append(domain.level.idx).append(",");
            sb.append("\"v\":\"").append(domain.content).append("\"").append(",");
            sb.append("\"t\":\"").append(domain.date).append("\"");
            sb.append("}");
            if (i < domains.size() - 1) {
                sb.append(",");
            }
        }
        sb.append("]");
        return sb.toString();
    }
    public static List<Map<String, Object>> print() {
        List<Map<String, Object>> res = new ArrayList<>();
        for (NewsDomain datum : NEWS_QUEUE.data()) {
            Map<String, Object> map = new HashMap<>();
            map.put("l", datum.level.idx);
            map.put("v", datum.content);
            map.put("t", datum.date);
            res.add(map);
        }
        return res;
    }
    private static boolean offer(NewsLevel level, String msg, Object[] args) {
        return NEWS_QUEUE.offer(new NewsDomain(level, replace(msg, args), (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date())));
    }
    private static String replace(String str, Object[] objs){
        if (null == objs || objs.length == 0 || null == str || "".equals(str.trim())) {
            return str;
        } else {
            StringBuilder sb = new StringBuilder(str);
            for (Object obj : objs) {
                int idx = sb.indexOf("{}");
                if (idx == -1) { break; }
                sb.replace(idx, idx + 2, String.valueOf(obj));
            }
            return sb.toString();
        }
    }
    static class NewsDomain {
        public NewsLevel level;
        public String content;
        public String date;
        public NewsDomain(NewsLevel level, String content, String date) {
            this.level = level;
            this.content = content;
            this.date = date;
        }
    }
    enum NewsLevel {
        INFO(1),
        WARN(2),
        ERROR(3),
        DEBUG(4),
        ;
        public int idx;
        NewsLevel(int idx) {
            this.idx = idx;
        }
    }
}
src/main/java/com/zy/core/cache/OutputQueue.java
@@ -17,4 +17,6 @@
    public static ArrayBlockingQueue<JSONObject> BARCODE = new ArrayBlockingQueue<>(32);
    // rgv输出日志
    public static ArrayBlockingQueue<String> RGV = new ArrayBlockingQueue<>(32);
    // 穿梭车输出日志
    public static ArrayBlockingQueue<String> STE = new ArrayBlockingQueue<>(32);
}
src/main/java/com/zy/core/enums/SlaveType.java
@@ -8,7 +8,8 @@
    Led,
    Scale,
    Car,
    Rgv
    Rgv,
    Ste
    ;
    public static SlaveType findInstance(String s){
src/main/java/com/zy/core/enums/SteABType.java
New file
@@ -0,0 +1,10 @@
package com.zy.core.enums;
public enum SteABType {
    A,
    B,
    ;
}
src/main/java/com/zy/core/enums/SteChargeType.java
New file
@@ -0,0 +1,46 @@
package com.zy.core.enums;
import com.core.common.Cools;
public enum SteChargeType {
    FIRST(1, "0100101"),
    SECOND(2, "1300101"),
    ;
    SteChargeType(int ssbm, String locNo) {
        this.ssbm = ssbm;
        this.locNo = locNo;
    }
    public int ssbm;
    public String locNo;
    public static SteChargeType get(String locNo) {
        if (Cools.isEmpty(locNo)) {
            return null;
        }
        SteChargeType[] values = SteChargeType.values();
        for (SteChargeType value : values) {
            if (value.locNo.equals(locNo)) {
                return value;
            }
        }
        return null;
    }
    public static SteChargeType get(int ssbm) {
        if (Cools.isEmpty(ssbm)) {
            return null;
        }
        SteChargeType[] values = SteChargeType.values();
        for (SteChargeType value : values) {
            if (value.ssbm == ssbm) {
                return value;
            }
        }
        return null;
    }
}
src/main/java/com/zy/core/enums/SteHisTaskStatusType.java
New file
@@ -0,0 +1,41 @@
package com.zy.core.enums;
public enum SteHisTaskStatusType {
    INIT(0, "初始"),
    COMPLETE(1, "执行完成"),
    REMOVE(2, "删除"),
    ;
    public Integer id;
    public String desc;
    SteHisTaskStatusType(Integer id, String desc) {
        this.id = id;
        this.desc = desc;
    }
    public static SteHisTaskStatusType get(Short id) {
        if (null == id) {
            return null;
        }
        for (SteHisTaskStatusType type : SteHisTaskStatusType.values()) {
            if (type.id.equals(id.intValue())) {
                return type;
            }
        }
        return null;
    }
    public static SteHisTaskStatusType get(SteHisTaskStatusType type) {
        if (null == type) {
            return null;
        }
        for (SteHisTaskStatusType statusType : SteHisTaskStatusType.values()) {
            if (statusType == type) {
                return statusType;
            }
        }
        return null;
    }
}
src/main/java/com/zy/core/enums/SteLocaType.java
New file
@@ -0,0 +1,42 @@
package com.zy.core.enums;
public enum SteLocaType {
    NONE(0, "未知"),
    A(1, "A点"),
    B(2, "B点"),
    A_WAITING(3, "A待机点"),
    B_WAITING(4, "B待机点"),
    ;
    public Integer id;
    public String desc;
    SteLocaType(Integer id, String desc) {
        this.id = id;
        this.desc = desc;
    }
    public static SteLocaType get(Short id) {
        if (null == id) {
            return null;
        }
        for (SteLocaType type : SteLocaType.values()) {
            if (type.id.equals(id.intValue())) {
                return type;
            }
        }
        return null;
    }
    public static SteLocaType get(SteLocaType type) {
        if (null == type) {
            return null;
        }
        for (SteLocaType crnStatusType : SteLocaType.values()) {
            if (crnStatusType == type) {
                return crnStatusType;
            }
        }
        return null;
    }
}
src/main/java/com/zy/core/enums/SteStatusType.java
New file
@@ -0,0 +1,43 @@
package com.zy.core.enums;
public enum SteStatusType {
    IDLE(0, "空闲"),
    MOVING(1, "作业中"),
    SOS(2, "报警"),
    WAITING(10, "等待确认"),
    OFF_LINE(-1, "未知"),
    OTHER(100, "其它"),
    ;
    public Integer id;
    public String desc;
    SteStatusType(Integer id, String desc) {
        this.id = id;
        this.desc = desc;
    }
    public static SteStatusType get(Short id) {
        if (null == id) {
            return null;
        }
        for (SteStatusType type : SteStatusType.values()) {
            if (type.id.equals(id.intValue())) {
                return type;
            }
        }
        return OFF_LINE;
    }
    public static SteStatusType get(SteStatusType type) {
        if (null == type) {
            return null;
        }
        for (SteStatusType crnStatusType : SteStatusType.values()) {
            if (crnStatusType == type) {
                return crnStatusType;
            }
        }
        return null;
    }
}
src/main/java/com/zy/core/enums/SteTaskModeType.java
New file
@@ -0,0 +1,129 @@
package com.zy.core.enums;
import com.core.exception.CoolException;
import com.zy.asrs.utils.SteUtils;
import com.zy.asrs.utils.Utils;
import com.zy.core.model.protocol.SteProtocol;
public enum SteTaskModeType {
    INIT(0, "初始"),    // 初始
    OUT_RIGHT(1, "右出库"),    // 右出库
    OUT_LEFT(2, "左出库"),    // 左出库
    IN_RIGHT(4, "右入库"),    // 右入库
    IN_LEFT(3, "左入库"),    // 左入库
    MOVE_LEFT(5, "左移库"),    // 左移库
    MOVE_RIGHT(6, "右移库"),    // 右移库
    GO_ORIGIN(8, "去右端"),    // 回反原点
    BACK_ORIGIN(7, "去左端"),      // 回原点
    WAITING_RIGHT(10, "右待机"),        // A点
    WAITING_LEFT(9, "左待机"),       // B点
//    FIT_LEFT(11, "左搬移"),   // 左搬移
//    FIT_RIGHT(12, "右搬移"),      // 右搬移
    CHARGE_LEFT(13, "左充电"),         // 左充电
    CHARGE_RIGHT(14, "右充电"),         // 左充电
//    CHECK_LEFT(14, "左盘点"),     // 左盘点
//    CHECK_RIGHT(15, "右盘点"),    // 右盘点
    CLOSE_CHARGE(17, "断开充电"),   // 断开充电
    ;
    public Integer id;
    public String desc;
    SteTaskModeType(Integer id, String desc) {
        this.id = id;
        this.desc = desc;
    }
    public static SteTaskModeType get(Short id) {
        if (null == id) {
            return null;
        }
        for (SteTaskModeType type : SteTaskModeType.values()) {
            if (type.id.equals(id.intValue())) {
                return type;
            }
        }
        return null;
    }
    public static SteTaskModeType get(SteTaskModeType type) {
        if (null == type) {
            return null;
        }
        for (SteTaskModeType crnTaskModeType : SteTaskModeType.values()) {
            if (crnTaskModeType == type) {
                return crnTaskModeType;
            }
        }
        return null;
    }
    public static SteTaskModeType findInByLoc(String locNo, Integer crnNo) {
        switch (SteUtils.getGroupRow(locNo, true, crnNo)) {
            case 2:
                return SteTaskModeType.IN_RIGHT;   // 右
            case 12:
                return SteTaskModeType.IN_LEFT;    // 左
            default:
                throw new CoolException("解析穿梭车原点定位失败");
        }
    }
    public static SteTaskModeType findOutByLoc(String locNo, Integer crnNo) {
        switch (SteUtils.getGroupRow(locNo, false, crnNo)) {
            case 2:
                return SteTaskModeType.OUT_LEFT;   // 右
            case 12:
                return SteTaskModeType.OUT_RIGHT;    // 左
            default:
                throw new CoolException("解析穿梭车原点定位失败");
        }
    }
    public static SteTaskModeType findOutByLoc2(String locNo, Integer crnNo) {
        switch (SteUtils.getGroupRow(locNo, false, crnNo)) {
            case 2:
                return SteTaskModeType.GO_ORIGIN;   // 8
            case 12:
                return SteTaskModeType.BACK_ORIGIN;    // 7
            default:
                throw new CoolException("解析穿梭车原点定位失败");
        }
    }
    // -----------------------------------------------
    // 去待搬点
    public static SteTaskModeType findOriginByLoc(SteProtocol steProtocol, Integer crnNo) {
        int row = steProtocol.getRow().intValue();
        if (SteUtils.SHUTTLE_GROUP_ROW_LIST.contains(row)) {
            return crnNo == 1 ? SteTaskModeType.BACK_ORIGIN : SteTaskModeType.GO_ORIGIN;
        } else if (row==13 || row==1){
            return SteTaskModeType.INIT;
        } else {
            throw new CoolException("解析穿梭车原点定位失败");
        }
    }
    public static SteTaskModeType findOriginByLoc(Integer row, Integer crnNo) {
        if (SteUtils.SHUTTLE_GROUP_ROW_LIST.contains(row)) {
            return crnNo == 1 ? SteTaskModeType.BACK_ORIGIN : SteTaskModeType.GO_ORIGIN;
        } else if (row==13 || row==1){
            return SteTaskModeType.INIT;
        } else {
            throw new CoolException("解析穿梭车原点定位失败");
        }
    }
    public static SteTaskModeType findWaiting(Integer row, Integer crnNo) {
        if (SteUtils.SHUTTLE_GROUP_ROW_LIST.contains(row)) {
            return crnNo == 1 ? SteTaskModeType.WAITING_LEFT : SteTaskModeType.WAITING_RIGHT;
        } else if (row==1||row==13){
            return SteTaskModeType.INIT;
        } else {
            throw new CoolException("解析穿梭车原点定位失败");
        }
    }
}
src/main/java/com/zy/core/model/SteSlave.java
New file
@@ -0,0 +1,49 @@
package com.zy.core.model;
import com.zy.core.Slave;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.ArrayList;
import java.util.List;
/**
 * Created by vincent on 2020/8/10
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class SteSlave extends Slave {
    private Integer rack;
    private Integer slot;
    private Boolean demo;
    // 穿梭车入库站点
    private List<CrnStn> steInStn = new ArrayList<>();
    // 穿梭车出库站点
    private List<CrnStn> steOutStn = new ArrayList<>();
    @Data
    public static class CrnStn {
        // 输送线plc编号
        private Integer devpPlcId;
        // 穿梭车站点编号
        private Integer staNo;
        // 排
        private Integer row;
        // 列
        private Integer bay;
        // 层
        private Integer lev;
    }
}
src/main/java/com/zy/core/model/command/SteCommand.java
New file
@@ -0,0 +1,95 @@
package com.zy.core.model.command;
import com.alibaba.fastjson.annotation.JSONField;
import com.zy.core.enums.SteTaskModeType;
import lombok.Data;
/**
 * 穿梭车命令报文
 * Created by vincent on 2020/8/11
 */
@Data
public class SteCommand {
    // 穿梭车号
    private Integer steNo = 0;
    // 任务号
    private Integer taskNo = 0;
    // 作业类型
    private Short taskMode = 0;
    // 正在执行任务
    public Boolean execute = Boolean.FALSE;
    // 确认任务完成
    public Boolean complete = Boolean.FALSE;
    @JSONField(serialize = false)
    private SteTaskModeType taskModeType;
    // 排
    private Short row;
    // 列
    private Short bay;
    // 层
    private Short lev;
    // 起始设备号
    private Short startSsbm;
    // 目的设备号
    private Short endSsbm;
    // 控制模式 0=脱机 1=联机
    private Short controlMode;
    // 开启信号 1-启动
    private Short open;
    // 初始化
    private Short init;
    // 复位信号 1=复位
    private Boolean reset;
    // 删除指令 1=删除
    private Boolean delete;
    // 托盘间距 中间托盘之间距离 单位毫米
    private Short space;
    // 间距确认
    private Short spaceYes;
    // 排修改
    private Short rowModify;
    // 列修改
    private Short bayModify;
    // 层修改
    private Short levModify;
    // 修改确认
    private Short modifyYes;
    /**
     * 输入穿梭车运行禁止 1运行,0禁止
     */
    private Short run;
    public void setTaskMode(Short taskMode){
        this.taskMode = taskMode;
        this.taskModeType = SteTaskModeType.get(taskModeType);
    }
    public void setTaskMode(SteTaskModeType type) {
        this.taskModeType = type;
        this.taskMode = SteTaskModeType.get(type).id.shortValue();
    }
}
src/main/java/com/zy/core/model/protocol/SteProtocol.java
New file
@@ -0,0 +1,302 @@
package com.zy.core.model.protocol;
import com.core.common.Cools;
import com.core.common.SpringUtils;
import com.zy.asrs.entity.BasSte;
import com.zy.asrs.service.BasSteService;
import com.zy.core.News;
import com.zy.core.enums.SteHisTaskStatusType;
import com.zy.core.enums.SteLocaType;
import com.zy.core.enums.SteStatusType;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
/**
 * Created by vincent on 2020/8/7
 */
@Slf4j
@Data
public class SteProtocol {
    /**
     * 设备号
     */
    private Short steNo;
    /**
     * 1 = 联机模式
     * 0 = 脱机模式
     */
    public Short mode;
    /**
     IDLE(0, "空闲"),
     MOVING(1, "作业中"),
     SOS(2, "报警"),
     WAITING(3, "任务完成等待WCS确认"),
     */
    public Short status;
    public SteStatusType statusType;
    /**
     * 任务号
     */
    public Short taskNo = 0;
    /**
     * 正在执行任务
     */
    public Boolean execute;
    /**
     * 任务完成,等待WCS确认
     */
    public Boolean waiting;
    /**
     * 异常码1
     */
    public Short alarm;
    /**
     * 异常码2
     */
    public Short alarm0;
    /**
     * 电池电量
     */
    public Float charge = 0.0F;
    public void setCharge(Float charge) {
        if (charge >= 0) {
            this.charge = charge;
        }
    }
    /**
     * 满电
     */
    public Boolean fullCharge;
    /**
     * 低电量
     */
    public Boolean lowCharge;
    /**
     * 电池馈电    0,欠电,1低电 2满电
     */
    public Short feed;
    /**
     * 当前位置     1,近点,2远点,3A点,4B点
     */
    public Short loca;
    public SteLocaType locaType;
    /**
     * 近点距离
     */
    public Double closer;
    /**
     * 当前速度
     */
    public Double speed = 0.0D;
    /**
     * 高低位 0,低位,1高位
     */
    public Short pos;
    /**
     * 有货 0,没货,1有货
     */
    public Short load;
    /**
     * 在轨道上 0不在,1在
     */
    public Short track;
    /**
     * 任务类型
     */
    public Short taskType;
    /**
     * 排
     */
    public Short row;
    /**
     * 列
     */
    public Short bay;
    /**
     * 层
     */
    public Short lev;
    /**
     * 过账指令任务号
     */
    public Integer hisTaskNo;
    /**
     * 过账指令状态
     * 0初始 1执行完成 2删除
     */
    public Short hisTaskStatus;
    public SteHisTaskStatusType hisTaskStatusType;
    /**
     * 盘点数量
     */
    public Short checkQty;
    /**
     * 就绪状态  0未就绪 1就绪
     */
    public Short ready;
    /**
     * 打开充电桩号
     */
    public Short chargeNo;
    /**
     * 心跳指令 1-2每秒切换一次
     */
    public Short heart;
    /**
     * 堆垛机禁止运行 1运行,0禁止
     */
    public Short crnStopRun;
    /**
     * 堆垛机禁止伸叉 1运行,0禁止
     */
    public Short crnStopFork;
    /**
     * 堆垛机搬移允许 0不允许   1允许
     */
    public Short crnAllowRun;
    /**
     * 充电状态  1:在充电;0:不在充电
     */
    private Short chargeStatus;
    // 入库取空
    private Boolean inEmpty;
    // 出库取空
    private Boolean outEmpty;
    // 充电桩
    private Boolean steCharge;
    public void setStatus(Short status){
        this.status = status;
        this.statusType = SteStatusType.get(status);
    }
    public void setStatus(SteStatusType type){
        this.statusType = type;
        this.status = SteStatusType.get(type).id.shortValue();
    }
    public void setLoca(Short loca){
        this.loca = loca;
        this.locaType = SteLocaType.get(loca);
    }
    public void setLoca(SteLocaType type){
        this.locaType = type;
        this.loca = SteLocaType.get(type).id.shortValue();
    }
    public void setHisTaskStatus(Short hisTaskStatus){
        this.hisTaskStatus = hisTaskStatus;
        this.hisTaskStatusType = SteHisTaskStatusType.get(hisTaskStatus);
    }
    public void setHisTaskStatus(SteHisTaskStatusType type){
        this.hisTaskStatusType = type;
        this.hisTaskStatus = SteHisTaskStatusType.get(type).id.shortValue();
    }
    /**
     * 最近一次入出库类型
     *       I:入库
     *       O:出库
     */
    private String lastIo = "I";
    private String pakMk = "-";
    public BasSte toSqlModel(BasSte basSte){
        if (alarm!=null) {
            basSte.setSteErr(alarm.longValue());
        }
        basSte.setWrkNo(taskNo.intValue());
//        if (basSte.getPakMk().equals("N")) {
//            if (!Cools.isEmpty(row)) {
//                basSte.setRow(row.intValue());
//            }
//            if (!Cools.isEmpty(bay)) {
//                basSte.setBay(bay.intValue());
//            }
//            if (!Cools.isEmpty(lev)) {
//                basSte.setLev(lev.intValue());
//            }
//        }
        return basSte;
    }
    // 是否处于空闲待命状态
    public Boolean isIdle() {
        boolean res = this.statusType.equals(SteStatusType.IDLE)
                && this.mode == 1
                && this.pakMk.equals("N")
                && !isAlarm()
                && this.chargeStatus == 0
                && isEnable()
                ;
        if (!res) {
            return res;
        } else {
            // 电量
            try {
                String chargeLine = SpringUtils.getBean(BasSteService.class).selectById(this.steNo).getChargeLine();
                return charge > Float.parseFloat(chargeLine);
            } catch (Exception e) {
                News.error("fail", e);
                return false;
            }
        }
    }
    // 是否处于报警状态
    public Boolean isAlarm() {
        return this.alarm > 1;
    }
    public Boolean isEnable() {
        if (Cools.isEmpty(row, bay, lev)) {
            return false;
        }
        return row > 0 && bay > 0 && lev > 0;
    }
}
src/main/java/com/zy/core/thread/SiemensDevpThread.java
@@ -42,6 +42,8 @@
    private DevpSlave slave;
    private SiemensS7Net siemensS7Net;
    private Map<Integer, StaProtocol> station = new ConcurrentHashMap<>();
    public boolean charge0;     //请求充电
    public boolean charge1;     //请求充电
    private short heartBeatVal = 1;
    public static final ArrayList<Integer> staNos1 = new ArrayList<Integer>() {{
        add(100);add(101);add(102);add(103);
src/main/java/com/zy/core/thread/SteThread.java
New file
@@ -0,0 +1,529 @@
package com.zy.core.thread;
import HslCommunication.Core.Types.OperateResult;
import HslCommunication.Core.Types.OperateResultExOne;
import HslCommunication.Profinet.Siemens.SiemensPLCS;
import HslCommunication.Profinet.Siemens.SiemensS7Net;
import com.alibaba.fastjson.JSON;
import com.core.common.Cools;
import com.core.common.DateUtils;
import com.core.common.SpringUtils;
import com.core.exception.CoolException;
import com.zy.asrs.entity.BasSte;
import com.zy.asrs.entity.BasSteOpt;
import com.zy.asrs.service.BasSteOptService;
import com.zy.asrs.service.BasSteService;
import com.zy.core.News;
import com.zy.core.ThreadHandler;
import com.zy.core.cache.MessageQueue;
import com.zy.core.cache.OutputQueue;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.enums.SlaveType;
import com.zy.core.enums.SteStatusType;
import com.zy.core.model.SteSlave;
import com.zy.core.model.Task;
import com.zy.core.model.command.SteCommand;
import com.zy.core.model.protocol.SteProtocol;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.text.MessageFormat;
import java.util.Date;
/**
 * shuttle 穿梭车线程
 * Created by vincent on 2020/8/4
 * 不能有 槽号 和 机架号
 */
@Data
@Slf4j
public class SteThread implements Runnable, ThreadHandler {
    private SiemensS7Net siemensS7Net;
    private SteSlave slave;
    private SteProtocol steProtocol;
    private short heartBeatVal = 1;
    private boolean V20011 = true;
    private boolean V20001 = true;
    private boolean resetFlag = false;
    public SteThread(SteSlave slave) {
        this.slave = slave;
    }
    @Override
    @SuppressWarnings("InfiniteLoopStatement")
    public void run() {
        this.connect();
        while (true) {
            try {
                int step = 1;
                Task task = MessageQueue.poll(SlaveType.Ste, slave.getId());
                if (task != null) {
                    step = task.getStep();
                }
                switch (step) {
                    // 读数据
                    case 1:
                        readStatus();
                        break;
                    // 写入数据
                    case 2:
                        write((SteCommand) task.getData());
                        break;
                    default:
                        break;
                }
                // 心跳
//                heartbeat();
                Thread.sleep(500);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 初始化堆垛机状态
     */
    private void initSte() {
        if (null == steProtocol) {
            steProtocol = new SteProtocol();
        }
        steProtocol.setSteNo(slave.getId().shortValue());
        steProtocol.setMode((short) 0);
        steProtocol.setStatus(SteStatusType.OFF_LINE);
        steProtocol.setTaskNo((short) 0);
        steProtocol.setExecute(false);
        steProtocol.setWaiting(false);
    }
    @Override
    public boolean connect() {
        boolean result = false;
        // 不能有 槽号 和 机架号
        siemensS7Net = new SiemensS7Net(SiemensPLCS.S200Smart, slave.getIp());
//        siemensS7Net.setRack(slave.getRack().byteValue());
//        siemensS7Net.setSlot(slave.getSlot().byteValue());
        OperateResult connect = siemensS7Net.ConnectServer();
        if(connect.IsSuccess){
            result = true;
            OutputQueue.STE.offer(MessageFormat.format( "【{0}】穿梭车plc连接成功 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
            News.info("穿梭车plc连接成功 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
        } else {
            OutputQueue.STE.offer(MessageFormat.format("【{0}】穿梭车plc连接失败!!! ===>> [id:{1}] [ip:{2}] [port:{3}] ", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
            News.error("穿梭车plc连接失败!!! ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
            initSte();
        }
//        melsecMcNet.ConnectClose();
        return result;
    }
    /**
     * 读取状态
     */
    private void readStatus(){
        try {
            OperateResultExOne<byte[]> result = siemensS7Net.Read("V800", (short) 70);
            if (result.IsSuccess) {
                if (null == steProtocol) {
                    steProtocol = new SteProtocol();
                    steProtocol.setSteNo(slave.getId().shortValue());
                }
//                steProtocol.setSteNo(siemensS7Net.getByteTransform().TransInt16(result.Content, 0));
                steProtocol.setMode(siemensS7Net.getByteTransform().TransInt16(result.Content, 2));
                steProtocol.setStatus(siemensS7Net.getByteTransform().TransInt16(result.Content, 4));
                OperateResultExOne<Boolean> executeRes = siemensS7Net.ReadBool("V2001.0");
                if (executeRes.IsSuccess) {
                    steProtocol.setExecute(executeRes.Content);
                }
                OperateResultExOne<Boolean> waitingRes = siemensS7Net.ReadBool("V2001.1");
                if (waitingRes.IsSuccess) {
                    steProtocol.setWaiting(waitingRes.Content);
                }
//                if (steProtocol.getSteNo()==1){
//                    if (!steProtocol.getWaiting().equals(V20011)){
//                        News.error("小车号 ={} :V2001.1地址读取值不一致,读={}  记录={}",steProtocol.getSteNo(),steProtocol.getWaiting(),V20011);
//                    }
//                    V20011=steProtocol.getWaiting();
//                    OperateResultExOne<Boolean> waitingRes2 = siemensS7Net.ReadBool("V2000.1");
//                    if (waitingRes2.IsSuccess) {
//                        if (!waitingRes2.Content.equals(V20001)){
//                            News.error("小车号 ={} :V2000.1地址读取值不一致,读={} 记录={}",steProtocol.getSteNo(),waitingRes2.Content,V20001);
//                        }
//                        V20001=waitingRes2.Content;
//                    }
//                    OperateResultExOne<Boolean> waitingRes3 = siemensS7Net.ReadBool("V2500.1");
//                    if (waitingRes3.IsSuccess) {
//                        if (!waitingRes3.Content.equals(waitingRes2.Content)){
//                            News.error("小车号 ={} :V2000.1地址读取值不一致,读={} , V2500.1地址读取值不一致,读={}",steProtocol.getSteNo(),waitingRes2.Content,waitingRes3.Content);
//                        }
//                    }
//                }
                OperateResultExOne<Boolean> inEmptyRes = siemensS7Net.ReadBool("V2001.2");
                if (inEmptyRes.IsSuccess) {
                    steProtocol.setInEmpty(inEmptyRes.Content);
                }
                OperateResultExOne<Boolean> outEmptyRes = siemensS7Net.ReadBool("V2001.3");
                if (outEmptyRes.IsSuccess) {
                    steProtocol.setOutEmpty(outEmptyRes.Content);
                }
                steProtocol.setAlarm(siemensS7Net.getByteTransform().TransInt16(result.Content, 6));
                steProtocol.setAlarm0(siemensS7Net.getByteTransform().TransInt16(result.Content, 8));
                steProtocol.setCharge(siemensS7Net.getByteTransform().TransSingle(result.Content, 10));
//                steProtocol.setFullCharge();
//                steProtocol.setLowCharge();
                steProtocol.setFeed(siemensS7Net.getByteTransform().TransInt16(result.Content, 14));
                steProtocol.setLoca(siemensS7Net.getByteTransform().TransInt16(result.Content, 16));
//                steProtocol.setCloser();
//                steProtocol.setSpeed();
                steProtocol.setPos(siemensS7Net.getByteTransform().TransInt16(result.Content, 18));
                steProtocol.setLoad(siemensS7Net.getByteTransform().TransInt16(result.Content, 20));
                steProtocol.setTrack(siemensS7Net.getByteTransform().TransInt16(result.Content, 22));
                steProtocol.setTaskNo(siemensS7Net.getByteTransform().TransInt16(result.Content, 24));
                steProtocol.setTaskType(siemensS7Net.getByteTransform().TransInt16(result.Content, 28));
                steProtocol.setRow(siemensS7Net.getByteTransform().TransInt16(result.Content, 30));
                steProtocol.setBay(siemensS7Net.getByteTransform().TransInt16(result.Content, 32));
                steProtocol.setLev(siemensS7Net.getByteTransform().TransInt16(result.Content, 34));
//                steProtocol.setHisTaskNo(siemensS7Net.getByteTransform().TransInt32(result.Content, 58));
//                steProtocol.setHisTaskStatus(siemensS7Net.getByteTransform().TransInt16(result.Content, 62));
//                steProtocol.setCheckQty(siemensS7Net.getByteTransform().TransInt16(result.Content, 64));
                steProtocol.setReady(siemensS7Net.getByteTransform().TransInt16(result.Content, 36));
//                steProtocol.setChargeNo(siemensS7Net.getByteTransform().TransInt16(result.Content, 68));
//                steProtocol.setHeart(siemensS7Net.getByteTransform().TransInt16(result.Content, 72));
                steProtocol.setCrnStopRun(siemensS7Net.getByteTransform().TransInt16(result.Content, 38));
                steProtocol.setCrnStopFork(siemensS7Net.getByteTransform().TransInt16(result.Content, 40));
                steProtocol.setCrnAllowRun(siemensS7Net.getByteTransform().TransInt16(result.Content, 42));
                steProtocol.setChargeStatus(siemensS7Net.getByteTransform().TransInt16(result.Content, 44));
                OperateResultExOne<Boolean> steChargeRes = siemensS7Net.ReadBool("V740.6");
                if (steChargeRes.IsSuccess) {
                    steProtocol.setSteCharge(steChargeRes.Content);
                    if (steChargeRes.Content){
                        steProtocol.setChargeStatus((short)1);
                    }
                }
                OutputQueue.STE.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功", DateUtils.convert(new Date()), slave.getId()));
                // 复位信号
                if (steProtocol.getWaiting()) {
                    News.info("-------------第一步、[穿梭车号:{}, 工作号:{}]==>> 状态为{},等待WCS确认!!{}",
                            slave.getId(),steProtocol.getTaskNo(),steProtocol.getStatus(), resetFlag);
                    if (resetFlag) {
                        News.info("第二步、收到主线程复位标记 resetFlag = true,[穿梭车号:{}, 工作号:{}]==>> 状态为{},等待WCS确认!!{}",
                                slave.getId(),steProtocol.getTaskNo(),steProtocol.getStatus(), resetFlag);
                        SteCommand steCommand = new SteCommand();
                        steCommand.setComplete(true);
                        if (write(steCommand) && confirmPos()) {
                            resetFlag = false;
                            News.info("第三步、发送复位命令成功 resetFlag = false,[穿梭车号:{}, 工作号:{}]==>> 状态为{},等待WCS确认!!{}",
                                    slave.getId(),steProtocol.getTaskNo(),steProtocol.getStatus(), resetFlag);
                        }
                    }
                }
                // 根据实时信息更新数据库
                BasSteService service = SpringUtils.getBean(BasSteService.class);
                if (null != service) {
                    // 同步pakMk
                    BasSte one = service.selectById(slave.getId());
                    if (one != null) {
                        steProtocol.setPakMk(one.getPakMk());
                    }
                    BasSte basSte = new BasSte();
                    basSte.setSteNo(slave.getId());
                    if (!service.updateById(steProtocol.toSqlModel(basSte))){
                        News.error("穿梭车plc数据库更新失败 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
                    }
                }
            } else {
                OutputQueue.STE.offer(MessageFormat.format("【{0}】{1}穿梭车plc状态信息失败", DateUtils.convert(new Date()), slave.getId()));
                throw new CoolException(MessageFormat.format( "穿梭车plc状态信息失败 ===>> [id:{0}] [ip:{1}] [port:{2}]", slave.getId(), slave.getIp(), slave.getPort()));
            }
        } catch (Exception e) {
//            e.printStackTrace();
            OutputQueue.STE.offer(MessageFormat.format("【{0}】读取穿梭车plc状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
//            News.error("读取穿梭车plc状态信息失败 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
            initSte();
        }
    }
    /**
     * 写入数据
     */
    private boolean write(SteCommand command) throws InterruptedException {
        if (null == command) {
            News.error("穿梭车写入命令为空");
            return false;
        }
        //判断小车是否在充电
        SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, 1);
        if (devpThread.charge0
                && !Cools.isEmpty(command.getRow(),command.getBay(),command.getLev())
                && command.getRow().intValue()==1 && command.getBay().intValue()==1 && command.getLev().intValue()==1){
            // led 异常显示
            LedThread ledThread1 = (LedThread) SlaveConnection.get(SlaveType.Led, 1);
            LedThread ledThread2 = (LedThread) SlaveConnection.get(SlaveType.Led, 2);
            LedThread ledThread3 = (LedThread) SlaveConnection.get(SlaveType.Led, 3);
            if (ledThread1 != null && ledThread2 != null && ledThread3 != null) {
                MessageQueue.offer(SlaveType.Led, 1, new Task(3, "穿梭车正在1排充电桩充电"));
                MessageQueue.offer(SlaveType.Led, 2, new Task(3, "穿梭车正在1排充电桩充电"));
                MessageQueue.offer(SlaveType.Led, 3, new Task(3, "穿梭车正在1排充电桩充电"));
            }
            News.error("穿梭车正在1排充电桩充电");
            return false;
        }else if (devpThread.charge1
                && !Cools.isEmpty(command.getRow(),command.getBay(),command.getLev())
                && command.getRow().intValue()==13 && command.getBay().intValue()==1 && command.getLev().intValue()==1){
            // led 异常显示
            LedThread ledThread1 = (LedThread) SlaveConnection.get(SlaveType.Led, 1);
            LedThread ledThread2 = (LedThread) SlaveConnection.get(SlaveType.Led, 2);
            LedThread ledThread3 = (LedThread) SlaveConnection.get(SlaveType.Led, 3);
            if (ledThread1 != null && ledThread2 != null && ledThread3 != null) {
                MessageQueue.offer(SlaveType.Led, 1, new Task(3, "穿梭车正在13排充电桩充电"));
                MessageQueue.offer(SlaveType.Led, 2, new Task(3, "穿梭车正在13排充电桩充电"));
                MessageQueue.offer(SlaveType.Led, 3, new Task(3, "穿梭车正在13排充电桩充电"));
            }
            News.error("穿梭车正在13排充电桩充电");
            return false;
        }
        command.setSteNo(slave.getId());
        OperateResult result = null;
        // 开始任务
        if (!command.getComplete()) {
            //组织任务前,先清空写任务确认位,以及任务完成确认位
            siemensS7Net.Write("V2000.0", false);
            siemensS7Net.Write("V2000.1", false);
//            siemensS7Net.Write("V2500.1", false);
            Thread.sleep(200);
            OperateResultExOne<Boolean> waitingRes2 = siemensS7Net.ReadBool("V2000.1");
            if (waitingRes2.IsSuccess) {
                if(!waitingRes2.Content){
                    News.error("重置任务完成确认位成功");
                } else {
                    News.error("重置任务完成确认位失败1");
                }
            } else {
                News.error("重置任务完成确认位失败2");
            }
            // 1.任务号
            OperateResult result0 = siemensS7Net.Write("V998", command.getTaskNo().shortValue());
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 作业
            if (command.getTaskMode() != 0) {
                // 2.作业
                OperateResult result1 = siemensS7Net.Write("V1000", command.getTaskMode());
                // 3.确认开始任务
                if (result0.IsSuccess && result1.IsSuccess) {
                    result = siemensS7Net.Write("V2000.0", true);
                    siemensS7Net.Write("V2000.1", false);
//                    siemensS7Net.Write("V2500.1", false);
                }
            // 其他指令
            } else {
                // 控制模式
                if (command.getControlMode() != null) {
                    result =  siemensS7Net.Write("V1010", command.getControlMode());
                // 复位信号
                } else if (command.getReset() != null) {
                    result =  siemensS7Net.Write("V2000.2", command.getReset());
                // 删除指令
                } else if (command.getDelete() != null) {
                    result =  siemensS7Net.Write("V2000.3", command.getDelete());
                // 无效指令
                } else if (command.getRun() != null) {
                    result =  siemensS7Net.Write("V1016", command.getRun());
                    // 无效指令
                }else {
                    return false;
                }
            }
        // 任务完成
        } else {
            siemensS7Net.Write("V2000.0", false);
            siemensS7Net.Write("V998", (short) 0);
            siemensS7Net.Write("V1000", (short) 0);
            result = siemensS7Net.Write("V2000.1", true);
//            result = siemensS7Net.Write("V2500.1", true);
        }
        try {
            // 日志记录
            if (!command.getComplete() && command.getTaskMode() != 0) {
                BasSteOptService bean = SpringUtils.getBean(BasSteOptService.class);
                if (null != bean) {
                    BasSteOpt basSteOpt = new BasSteOpt(
                            command.getTaskNo(),    // 任务号
                            command.getSteNo(),    // 穿梭车
                            new Date(),    // 下发时间
                            command.getTaskModeType().desc,    // 作业
                            null,    // 源排
                            null,    // 源列
                            null,    // 源层
                            null,    // 源站
                            null,    // 目标排
                            null,    // 目标列
                            null,    // 目标层
                            null,    // 目标站
                            null,    // 响应结果
                            null,    // 修改时间
                            null,    // 修改人员
                            null    // 备注
                    );
                    bean.insert(basSteOpt);
                }
            }
        } catch (Exception ignore) {}
        if (result != null && result.IsSuccess) {
            // 维护数据库排列层
            if (!steProtocol.getWaiting()) {
                if (!Cools.isEmpty(command.getRow(), command.getBay(), command.getLev())) {
                    this.modifyPos(command.getRow().intValue(), command.getBay().intValue(), command.getLev().intValue());
                }
            }
            News.info("穿梭车命令下发[id:{}] >>>>> {}", slave.getId(), JSON.toJSON(command));
            OutputQueue.STE.offer(MessageFormat.format("【{0}】[id:{1}] >>>>> 命令下发: {2}", DateUtils.convert(new Date()), slave.getId(), JSON.toJSON(command)));
            return true;
        } else {
            OutputQueue.STE.offer(MessageFormat.format("【{0}】写入穿梭车plc数据失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
            News.error("写入穿梭车plc数据失败 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
            return false;
        }
    }
    public void modifyPos(Integer row, Integer bay, Integer lev) {
        BasSteService service = SpringUtils.getBean(BasSteService.class);
        if (!service.updatePos(this.slave.getId(), row, bay, lev)) {
            News.error("更新{}号穿梭车定位失败 ===>> 排:【{}】, 列:【{}】,层:【{}】", this.slave.getId(), row, bay, lev);
        }
    }
    public boolean confirmPos() {
        BasSteService service = SpringUtils.getBean(BasSteService.class);
        BasSte basSte = service.selectById(slave.getId());
        if (basSte != null) {
            // 更新plc数据块
            short[] arr = new short[] {basSte.getRow().shortValue(), basSte.getBay().shortValue(), basSte.getLev().shortValue()};
            OperateResult result = siemensS7Net.Write("V1002", arr);
            if (result.IsSuccess) {
                // 更新数据库
                if (service.updatePakMk(this.slave.getId(), "N")) {
                    return true;
                } else {
                    News.error("{}号穿梭车修改数据库定位失败!!!", slave.getId());
                }
            }
        }
        return false;
    }
    public boolean modifyPosHandle(Integer row, Integer bay, Integer lev) {
        short[] arr = new short[] {row.shortValue(), bay.shortValue(), lev.shortValue()};
        OperateResult result = siemensS7Net.Write("V1002", arr);
        if (!result.IsSuccess) {
            News.error("更新{}号穿梭车定位失败 ===>> 排:【{}】, 列:【{}】,层:【{}】", this.slave.getId(), row, bay, lev);
            return false;
        }
        BasSteService service = SpringUtils.getBean(BasSteService.class);
        if (!service.updatePos(this.slave.getId(), row, bay, lev)) {
            News.error("更新{}号穿梭车定位失败 ===>> 排:【{}】, 列:【{}】,层:【{}】", this.slave.getId(), row, bay, lev);
            return false;
        }
        return true;
    }
    @Override
    public void close() {
//        siemensS7Net.ConnectClose();
    }
    /**
     * 心跳
     */
    private void heartbeat(){
        if (heartBeatVal == 1) {
            heartBeatVal = 2;
        } else {
            heartBeatVal = 1;
        }
        OperateResult write = siemensS7Net.Write("D10", heartBeatVal);
        if (!write.IsSuccess) {
            News.error("输送线plc编号={} 心跳失败", slave.getId());
        }
    }
//    public void modifyPos(int wrkNo, int row, int bay, int lev) {
//        BasSteService service = SpringUtils.getBean(BasSteService.class);
//        if (!service.updatePos(wrkNo,this.slave.getId(), row, bay, lev)) {
//            News.error("更新{}号穿梭车定位失败 ===>> 排:【{}】, 列:【{}】,层:【{}】", this.slave.getId(), row, bay, lev);
//        }
//    }
    /******************************************************************************************/
    /**************************************** 测试专用 *****************************************/
    /*****************************************************************************************/
    public static void main(String[] args) throws InterruptedException {
        SteSlave slave = new SteSlave();
        slave.setId(1);
        slave.setIp("192.168.2.1");
        slave.setPort(502);
        SteThread thread = new SteThread(slave);
        thread.connect();
        thread.readStatus();
        System.out.println(JSON.toJSONString(thread.steProtocol));
        // 任务作业
//        SteCommand command = new SteCommand();
//        command.setSteNo(1); // 堆垛机编号
//        Random random = new Random();
//        int taskNo = random.nextInt(9090);
//        command.setTaskNo(taskNo); // 工作号
//        command.setTaskMode(SteTaskModeType.MOVE_LEFT); // 任务模式
//        thread.write(command);
        // 任务完成
//        SteCommand command = new SteCommand();
//        command.setSteNo(1); // 堆垛机编号
//        command.setComplete(Boolean.TRUE); // 任务模式
//        thread.write(command);
        // 控制模式
//        SteCommand command = new SteCommand();
//        command.setControlMode((short) 1);
//        thread.write(command);
        // 复位信号
//        SteCommand command = new SteCommand();
//        command.setReset(Boolean.TRUE);
//        thread.write(command);
        // 删除指令
//        SteCommand command = new SteCommand();
//        command.setDelete(Boolean.TRUE);
//        thread.write(command);
        // 穿梭车运行禁止
        SteCommand command = new SteCommand();
        command.setRun((short)0);
        thread.write(command);
    }
}
src/main/webapp/views/index.html
@@ -19,6 +19,7 @@
            <li><a id="pipeline" onclick="nav(this.id)" class="nav-unselect" href="#">输送设备</a></li>
            <li><a id="crn" onclick="nav(this.id)" class="nav-unselect" href="#">堆垛机</a></li>
            <li><a id="rgv" onclick="nav(this.id)" class="nav-unselect" href="#">RGV</a></li>
            <li><a id="ste" onclick="nav(this.id)" class="nav-unselect" href="#">穿梭车</a></li>
        </ul>
    </div>
</div>
src/main/webapp/views/news.html
New file
@@ -0,0 +1,114 @@
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>NEWS</title>
    <style>
        /** {*/
        /*    padding: 0;*/
        /*    margin: 0;*/
        /*}*/
        .container {
            height: 100%;
            width: 100%;
        }
        /*=============== SCROLL UP ===============*/
        .scrollup {
            text-decoration: none;
            text-align: center;
            width: 25px;
            height: 18px;
            position: fixed;
            right: 1rem;
            bottom: -55%;
            background-color: rgb(108,167,168);
            box-shadow: 0 8px 12px hsla(228, 66%, 45%, .1);
            display: inline-flex;
            padding: .35rem;
            border-radius: .25rem;
            color: #ffffff;
            z-index: 10;
            transition: .3s;
            font-size: 8px;
        }
        .scrollup:hover {
            transform: translateY(-.25rem);
        }
        /* Show Scroll Up*/
        .show-scroll {
            bottom: 5%;
        }
        .news-desc {
            font-size: 14px;
        }
        .level-1 {
            color: #333333;
        }
        .level-2 {
            color: #1E9FFF;
        }
        .level-3 {
            color: red;
        }
    </style>
</head>
<body>
<div class="container">
</div>
<a class="scrollup" id="scroll-up">
    <span>顶部</span>
</a>
</body>
<script src="../static/js/jquery/jquery-3.3.1.min.js"></script>
<script src="../static/js/handlebars/handlebars-v4.5.3.js"></script>
<script src="../static/js/common.js"></script>
<script>
    var autoScroll = true;
    function scrollUp(){
        const scrollUp = document.getElementById('scroll-up');
        if(this.scrollY >= 100) scrollUp.classList.add('show-scroll'); else scrollUp.classList.remove('show-scroll')
    }
    window.addEventListener('scroll', scrollUp)
    $(document).on('click ','#scroll-up', function () {
        window.scrollTo(0, 0);
        autoScroll = false;
    })
    $(document).on('click ','body', function () {
        autoScroll = false;
    })
    setInterval(()=>{
        $.ajax({
            url: baseUrl + "/news/print",
            // headers: {'token': localStorage.getItem('token')},
            method: 'GET',
            success: function (res) {
                if (res.code === 200) {
                    let template = Handlebars.compile($('#newsTpl').html());
                    $('.container').html(template({list: res.data}));
                    if (autoScroll) {
                        window.scrollTo(0, document.body.scrollHeight)
                    }
                } else if (res.code === 403) {
                    window.location.href = baseUrl + "/login";
                } else {
                    console.error(res.msg);
                }
            }
        })
    }, 1000)
</script>
<script type="text/template" id="newsTpl">
    {{#each list}}
    <div class="news-desc level-{{l}}">
        <span>{{t}}</span>&nbsp;-&nbsp;<span>{{v}}</span>
    </div>
    {{/each}}
</script>
</html>
src/main/webapp/views/ste.html
New file
@@ -0,0 +1,508 @@
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>穿梭车监控管理</title>
    <link rel="stylesheet" type="text/css" href="../static/css/normalize.css">
    <link rel="stylesheet" type="text/css" href="../static/css/common.css">
    <link rel="stylesheet" type="text/css" href="../static/layui/css/layui.css">
    <link rel="stylesheet" href="../static/css/ste.css">
    <script type="text/javascript" src="../static/js/jquery/jquery-3.3.1.min.js"></script>
    <script type="text/javascript" src="../static/js/layer/layer.js"></script>
    <script type="text/javascript" src="../static/layui/layui.js"></script>
    <script type="text/javascript" src="../static/js/common.js"></script>
</head>
<body>
    <div style="padding: 10px;height: 100%;float: left;width: 6%">
        <div class="button-window"></div>
    </div>
    <div style="height: 100%;padding-left: 6%">
        <div style="padding: 10px;height: 100%">
            <!-- 日志监控板 -->
            <div class="log-board">
                <div class="command-log">
                    <div data-steNo="1" class="ste-command-item">
                        <label>1#</label>
                        <button class="demoBtn pos-btn">数据维护</button>
<!--                        <button id="mode-1" class="demoBtn mode-btn" > - </button>-->
                    </div>
                    <div data-steNo="2" class="ste-command-item">
                        <label>2#</label>
                        <button class="demoBtn pos-btn">数据维护</button>
<!--                        <button id="mode-2" class="demoBtn mode-btn" > - </button>-->
                    </div>
                    <div data-steNo="3" class="ste-command-item">
                        <label>3#</label>
                        <button class="demoBtn pos-btn">数据维护</button>
<!--                        <button id="mode-3" class="demoBtn mode-btn" > - </button>-->
                    </div>
                </div>
                <!-- 堆垛机状态位信息 -->
                <div class="ste-state">
                    <table id="ste-state-table">
                        <thead>
                            <tr>
                                <th>穿梭车</th>
                                <th>模式</th>
                                <th>状态</th>
                                <th>有物</th>
                                <th>在轨</th>
                                <th>电量</th>
                                <th>排</th>
                                <th>列</th>
                                <th>层</th>
                                <th>等待WCS确认</th>
                                <th>定位</th>
                                <th>充电状态</th>
                                <th>报警信息1</th>
                                <th>报警信息2</th>
                            </tr>
                        </thead>
                        <tbody>
                        </tbody>
                    </table>
                </div>
            </div>
            <!-- 穿梭车状态 -->
            <div class="ste-msg">
                <table id="ste-msg-table">
                    <thead>
                        <tr>
                            <th>穿梭车</th>
                            <th>工作号</th>
                            <th>状态</th>
                            <th>源站</th>
                            <th>目标站</th>
                            <th>源库位</th>
                            <th>目标库位</th>
                            <th>速度</th>
                            <th>近点距离</th>
                            <th>作业标记</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </div>
            <!-- 手动操作 -->
            <div class="ste-operation">
                <!-- 遮罩层 -->
                <div class="ste-operation-shade">
                    <span class="ste-operation-shade-span">
                        WCS 系统运行中,请停止后操作
                    </span>
                </div>
                <!-- 设备任务选择 -->
                <div class="task-select">
                    <!-- 选择 -->
                    <div id="ste-select" class="operator-item">
                        <span class="select-title">穿梭车号</span>
                        <div class="select-container">
                            <label><input type="radio" name="steSelect" value="1" checked>&nbsp;1号穿梭车</label>
                            <label><input type="radio" name="steSelect" value="2">&nbsp;2号穿梭车</label>
                            <label><input type="radio" name="steSelect" value="3">&nbsp;3号穿梭车</label>
                        </div>
                    </div>
                </div>
                <!-- 设备任务操作 -->
                <div class="task-operator">
                    <fieldset>
                        <legend>手动操作</legend>
                        <div class="button-group">
                            <button class="item" onclick="steOperator(99)">联机</button>
                            <button class="item" onclick="steOperator(100)">脱机</button>
                            <button class="item" onclick="steOperator(1)">向右出库</button>
                            <button class="item" onclick="steOperator(2)">向左出库</button>
                            <button class="item" onclick="steOperator(3)">从右入库</button>
                            <button class="item" onclick="steOperator(4)">从左入库</button>
                            <button class="item" onclick="steOperator(5)">左移库</button>
                            <button class="item" onclick="steOperator(6)">右移库</button>
                            <button class="item" onclick="steOperator(7)">去右端</button>
                            <button class="item" onclick="steOperator(8)">去左端</button>
                            <button class="item" onclick="steOperator(9)">右待机</button>
                            <button class="item" onclick="steOperator(10)">左待机</button>
<!--                            <button class="item" onclick="steOperator(11)">左搬移</button>-->
<!--                            <button class="item" onclick="steOperator(12)">右搬移</button>-->
<!--                            <button class="item" onclick="steOperator(13)">左充电</button>-->
<!--                            <button class="item" onclick="steOperator(14)">右充电</button>-->
                            <button class="item" onclick="steOperator(20)">断开充电桩</button>
                            <button class="item" onclick="steOperator(21)">小车充电结束</button>
<!--                            <button class="item" onclick="steOperator(14)">左盘点</button>-->
<!--                            <button class="item" onclick="steOperator(15)">右盘点</button>-->
                            <button class="item" onclick="steOperator(16)">任务完成</button>
                        </div>
                    </fieldset>
                </div>
            </div>
            <!-- 穿梭车日志输出 -->
            <div class="ste-output-board">
                <textarea id="ste-output"></textarea>
            </div>
        </div>
    </div>
    <div id="ste-detl" style="display: none">
        <div>
            <div class="form-item">
                <label class="form-label">穿梭车号:</label>
                <div class="form-input">
                    <input id="steNo" name="steNo" class="layui-input" lay-verify="required|number" autocomplete="off" disabled="disabled">
                </div>
            </div>
            <div class="form-item">
                <label class="form-label">工作号:</label>
                <div class="form-input">
                    <input id="workNo" name="workNo" type="number" class="layui-input" lay-verify="number" autocomplete="off">
                </div>
            </div>
            <div class="form-item">
                <label class="form-label">排:</label>
                <div class="form-input">
                    <input id="row" name="row" type="number" class="layui-input" lay-verify="number" autocomplete="off">
                </div>
            </div>
            <div class="form-item">
                <label class="form-label">列:</label>
                <div class="form-input">
                    <input id="bay" name="bay" type="number" class="layui-input" autocomplete="off">
                </div>
            </div>
            <div class="form-item">
                <label class="form-label">层:</label>
                <div class="form-input">
                    <input id="lev" name="lev" type="number" class="layui-input" autocomplete="off">
                </div>
            </div>
            <div class="form-item">
                <label class="form-label">堆垛机:</label>
                <div class="form-input">
                    <input id="crnNo" name="crnNo" type="number" class="layui-input" autocomplete="off">
                </div>
            </div>
            <div class="form-item">
                <label class="form-label">作业标记:</label>
                <div class="form-input">
                    <input id="pakMk" name="pakMk" type="text" class="layui-input" autocomplete="off">
                </div>
            </div>
            <div class="form-item form-button-container">
                <button class="form-button" id="save">保存</button>
                <button class="form-button" id="cancel" style="background-color: #D0D0D0">取消</button>
            </div>
        </di>
    </div>
</body>
</html>
<script>
    // 空白行数
    var steStateTableBlankRows = 0;
    var steMsgTableBlankRows = 0;
    // 实际行数
    var steStateTableFullRows = 0;
    var steMsgTableFullRows = 0;
    // 初始化
    var steOutputDom = document.getElementById("ste-output");
    $(document).ready(function() {
        initSteStateTable();
        getSteStateInfo();
        initSteMsgTable();
        getSteMsgInfo();
        operatorBlockShow();
    });
    setInterval(function () {
        getSteStateInfo()
        getSteMsgInfo();
    },1000)
    setInterval(function () {
        getSteOutput();
        operatorBlockShow();
    },500);
    // 判断手动操作模块是否可用
    function operatorBlockShow() {
        if (parent.systemRunning) {
            $('.ste-operation').css("opacity", "0.5");
            $('.ste-operation-shade').show();
            $('.ste-operation-shade-span').show();
        }  else {
            $('.ste-operation').css("opacity", "1");
            $('.ste-operation-shade').hide();
            $('.ste-operation-shade-span').hide();
        }
    }
    var layerIdx;
    $(document).on('click ','.pos-btn', function () {
        let steNo = Number($(this).parent().attr("data-steNo"));
        layerIdx = layer.open({
            type: 1,
            title: false,
            shadeClose: true,
            offset: [$(this).offset().top + 30 + 'px', $(this).offset().left + 'px'],
            anim: 5,
            shade: [0],
            area: ['310px', '370px'],
            closeBtn: 0,
            content: $("#ste-detl"),
            success: function(layero, index){
                http.get(baseUrl+ "/ste/detl/"+steNo, null, function (res) {
                    $('#steNo').val(steNo);
                    $('#workNo').val(res.data.workNo);
                    $('#row').val(res.data.row);
                    $('#bay').val(res.data.bay);
                    $('#lev').val(res.data.lev);
                    $('#crnNo').val(res.data.crnNo);
                    $('#pakMk').val(res.data.pakMk);
                })
            },
            end: function () {
                $('#steNo').val("");
                $('#workNo').val("");
                $('#row').val("");
                $('#bay').val("");
                $('#lev').val("");
                $('#crnNo').val("");
                $('#pakMk').val("");
            }
        })
    })
    $(document).on('click ','.mode-btn', function () {
        let steNo = Number($(this).parent().attr("data-steNo"));
        layer.confirm("改变" + steNo + ' 号穿梭车在线状态吗?', function(){
            var index = layer.load(1, {
                shade: [0.1,'#fff']
            });
            $.ajax({
                url: baseUrl+ "/ste/mode/switch",
                headers: {'token': localStorage.getItem('token')},
                data: {
                    steNo: Number(steNo),
                    password: 'root'
                },
                method: 'POST',
                success: function (res) {
                    layer.close(index);
                    if (res.code === 200){
                        layer.msg(res.msg, {icon: 1});
                    } else if (res.code === 403){
                        window.location.href = baseUrl+"/login";
                    }  else {
                        layer.msg(res.msg, {icon: 2});
                    }
                }
            });
        });
    })
    $(document).on('click ','#save', function () {
        http.post(baseUrl+ "/ste/detl/update", {
            steNo: $('#steNo').val(),
            workNo: $('#workNo').val(),
            row:  $('#row').val(),
            bay: $('#bay').val(),
            lev:  $('#lev').val(),
            crnNo: $('#crnNo').val(),
            pakMk: $('#pakMk').val(),
        }, function (res) {
            layer.msg("修改成功", {icon: 1,});
            layer.close(layerIdx);
        })
    })
    $(document).on('click ','#cancel', function () {
        layer.close(layerIdx);
    })
    // 穿梭车信息表获取 ---- 表一
    function getSteStateInfo() {
        let tableEl = $('#ste-state-table');
        $.ajax({
            url: baseUrl+ "/ste/table/ste/state",
            headers: {'token': localStorage.getItem('token')},
            method: 'POST',
            success: function (res) {
                if (res.code === 200){
                    let table = res.data;
                    if (table.length > steStateTableBlankRows && table.length !== steStateTableFullRows) {
                        initSteStateTable(table.length-steStateTableBlankRows);
                        steStateTableFullRows = table.length;
                    }
                    for (let i=1;i<=table.length;i++){
                        $("#mode-"+table[i-1].steNo).html(table[i-1].statusVal===0?'联机':'脱机');
                        let tr = tableEl.find("tr").eq(i);
                        setVal(tr.children("td").eq(0), table[i-1].steNo);
                        setVal(tr.children("td").eq(1), table[i-1].statusType);
                        setVal(tr.children("td").eq(2), table[i-1].status);
                        setVal(tr.children("td").eq(3), table[i-1].loading);
                        setVal(tr.children("td").eq(4), table[i-1].track);
                        setVal(tr.children("td").eq(5), table[i-1].charge);
                        setVal(tr.children("td").eq(6), table[i-1].row);
                        setVal(tr.children("td").eq(7), table[i-1].bay);
                        setVal(tr.children("td").eq(8), table[i-1].lev);
                        setVal(tr.children("td").eq(9), table[i-1].waiting);
                        setVal(tr.children("td").eq(10), table[i-1].loca);
                        setVal(tr.children("td").eq(11), table[i-1].chargeStatus);
                        setVal(tr.children("td").eq(12), table[i-1].alarm1);
                        setVal(tr.children("td").eq(13), table[i-1].alarm2);
                    }
                } else if (res.code === 403){
                    window.location.href = baseUrl+"/login";
                }  else {
                    console.log(res.msg);
                }
            }
        });
    }
    // 穿梭车数据表获取 ---- 表二
    function getSteMsgInfo() {
        let tableEl = $('#ste-msg-table');
        $.ajax({
            url: baseUrl+ "/ste/table/ste/msg",
            headers: {'token': localStorage.getItem('token')},
            method: 'POST',
            success: function (res) {
                if (res.code === 200){
                    var table = res.data;
                    if (table.length > steMsgTableBlankRows && table.length !== steMsgTableFullRows) {
                        initSteMsgTable(table.length-steMsgTableBlankRows);
                        steMsgTableFullRows = table.length;
                    }
                    for (var i=1;i<=table.length;i++){
                        var tr = tableEl.find("tr").eq(i);
                        setVal(tr.children("td").eq(0), table[i-1].steNo);
                        setVal(tr.children("td").eq(1), table[i-1].workNo);
                        setVal(tr.children("td").eq(2), table[i-1].status);
                        setVal(tr.children("td").eq(3), table[i-1].sourceStaNo);
                        setVal(tr.children("td").eq(4), table[i-1].staNo);
                        setVal(tr.children("td").eq(5), table[i-1].sourceLocNo);
                        setVal(tr.children("td").eq(6), table[i-1].locNo);
                        setVal(tr.children("td").eq(7), table[i-1].speed);
                        setVal(tr.children("td").eq(8), table[i-1].closer);
                        setVal(tr.children("td").eq(9), table[i-1].pakMk);
                    }
                } else if (res.code === 403){
                    window.location.href = baseUrl+"/login";
                }  else {
                    console.log(res.msg);
                }
            }
        });
    }
    // 穿梭车日志输出 -----------------------------------------------------------------------
    function getSteOutput() {
        $.ajax({
            url: baseUrl + "/ste/output/ste",
            headers: {'token': localStorage.getItem('token')},
            method: 'POST',
            success: function (res) {
                if (res.code === 200) {
                    steOutput(res.data);
                } else if (res.code === 403) {
                    window.location.href = baseUrl + "/login";
                } else {
                    console.log(res.msg);
                }
            }
        })
    }
    // 任务指令下发
    function steOperator(steTaskMode) {
        http.post(baseUrl+"/ste/operator/ste", {
            steNo: $('input[name="steSelect"]:checked').val(),
            steTaskMode: steTaskMode
        }, function (res) {
            layer.msg(res.msg, {icon: 1});
        });
    }
    // ------------------------------------------------------------------------------------------------
    // 穿梭车信息表获取  ----- 表一
    function initSteStateTable(row) {
        let line;
        if (row === undefined){
            let one = $('#ste-state-table thead').height();
            let total = $('.ste-state').height();
            let count = total / one;
            count = parseInt(count) - 1;
            steStateTableBlankRows = count;
            line = count;
        } else {
            line = row;
        }
        let html = "";
        for (let i = 0; i < line; i ++){
            html += " <tr>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "     </tr>\n";
        }
        $('#ste-state-table tbody').after(html);
    }
    // 穿梭车数据表获取  ----- 表二
    function initSteMsgTable(row) {
        let line;
        if (row === undefined){
            let one = $('#ste-msg-table thead').height();
            let total = $('.ste-msg').height();
            let count = total / one;
            count = parseInt(count) - 1;
            steMsgTableBlankRows = count;
            line = count;
        } else {
            line = row;
        }
        let html = "";
        for (let i = 0; i < line; i ++){
            html += " <tr>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "       <td></td>\n" +
                "     </tr>\n";
        }
        $('#ste-msg-table tbody').after(html);
    }
    // 日志输出框
    function steOutput(content){
        steOutputDom.value += content;
        steOutputDom.scrollTop = steOutputDom.scrollHeight;
    }
</script>