czt
2026-01-08 4c58f8f132adf830917b6b8f49f8c8de87aaf748
数量检测提交2-检测协议实现
已添加24个文件
已修改9个文件
1879 ■■■■■ 文件已修改
fzzy-igdss-core/src/main/java/com/fzzy/igds/constant/ProtocolEnum.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/igds/data/QuantityProgressData.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/igds/notify/NotifyWebInvoker.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/igds/notify/NotifyWebInvokerImpl.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/igds/request/QuantityRequest.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/igds/service/FileService.java 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/igds/service/QuantityService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/igds/utils/Base64Util.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/pom.xml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/ServerRunner.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/io/manager/QuantityRemoteManager.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/io/service/RemoteQuantityService.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/io/service/impl/DefaultRemoteQuantityImpl.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/analysis/AnalysisService.java 299 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/command/BhznRemoteQuantityImpl.java 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/command/CommandBuilder.java 210 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/command/QueryProgressTask.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/dto/IoMessage.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/dto/Req1001.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/dto/Resp1002.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/dto/Resp2003.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/dto/Resp2004.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/dto/Resp2005.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/dto/Resp2006.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/server/BhznQuantityMessageConsumer.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/server/BhznQuantityServerEngine.java 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/server/BhznQuantitySessionListener.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/util/ServerUtils.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/java/com/fzzy/Application.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/java/com/fzzy/security/SecurityController.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/java/com/fzzy/security/manager/SecManager.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/static/security/quantity.js 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/templates/security/quantity.html 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/igds/constant/ProtocolEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package com.fzzy.igds.constant;
/**
 * @Description æŠ“拍方式
 * @Author CZT
 * @Date 2026/01/08 16:48
 */
public enum ProtocolEnum {
    TCP_DEFAULT("TCP_DEFAULT", "系统默认协议"),
    TCP_MS_STORAGE("TCP_MS_STORAGE", "眉山数量检测协议"),
    TCP_XSX_V1("TCP_XSX_V1", "鑫胜鑫主协议1.0"),
    TCP_ZLDZ_GRAIN_V1("TCP_ZLDZ_GRAIN_V1", "正来电子粮情协议1.0"),
    TCP_FZZY_V3("TCP_FZZY_V3", "风正致远V3.0协议"),
    TCP_FZZY_IOT_V3("TCP_FZZY_IOT_V3", "风正致远物联网V3.0协议"),
    TCP_SHUHAN_V1("TCP_SHUHAN_V1", "蜀汉数量检测V1"),
    TCP_FZZY_WEIGHT("TCP_FZZY_WEIGHT", "FZZY-地磅主控协议"),
    RK_WEATHER_V30("RK_WEATHER_V30", "建大仁科气象站云V30"),
    TCP_FZZY_QUANTITY_V35("TCP_FZZY_QUANTITY_V35", "风正致远数量检测V35"),
    TCP_BHZH_GRAIN_FM_V1("TCP_BHZH_GRAIN_FM_V1", "邦海智能无线主机版V1"),
    TCP_BHZH_GRAIN_V2("TCP_BHZH_GRAIN_V2", "邦海智能有线版V2"),
    TCP_BEIBO_GRAIN_V1("TCP_BEIBO_GRAIN_V1", "贝博粮情分机服务端协议"),
    FZZY_OPENAPI_HTTP("FZZY_OPENAPI_HTTP", "风正致远API-HTTP协议");
    private String code;
    private String msg;
    ProtocolEnum(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public String getCode() {
        return code;
    }
    public String getMsg() {
        return msg;
    }
}
fzzy-igdss-core/src/main/java/com/fzzy/igds/data/QuantityProgressData.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
package com.fzzy.igds.data;
import com.bstek.dorado.annotation.PropertyDef;
import lombok.Data;
import java.io.Serializable;
/**
 * è™«å®³æ£€æµ‹è¿›åº¦ ä¿¡æ¯å°è£…
 *
 * @author vince
 */
@Data
public class QuantityProgressData implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    @PropertyDef(label = "控制柜ID")
    private String serId;
    @PropertyDef(label = "组织编码")
    private String companyId;
    @PropertyDef(label = "仓库ID")
    private String depotId;
    @PropertyDef(label = "库区ID")
    private String deptId;
    @PropertyDef(label = "当前状态")
    private String state;
    @PropertyDef(label = "进度百分比")
    private int progress;
    @PropertyDef(label = "说明")
    private String msg = "";
}
fzzy-igdss-core/src/main/java/com/fzzy/igds/notify/NotifyWebInvoker.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
package com.fzzy.igds.notify;
import com.fzzy.igds.constant.OrderRespEnum;
import com.fzzy.igds.data.QuantityProgressData;
/**
 * @Description
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
public interface NotifyWebInvoker {
    String BEAN_ID = "notifyWebInvoker";
    /**
     * ç›´æŽ¥é€šçŸ¥é¡µé¢
     *
     * @param companyId
     * @param orderResp
     * @param notifyMsg
     */
    void notifyWeb(String companyId, OrderRespEnum orderResp, String bizType,String notifyMsg);
    void notifyQuantityProgress(QuantityProgressData progress);
}
fzzy-igdss-core/src/main/java/com/fzzy/igds/notify/NotifyWebInvokerImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
package com.fzzy.igds.notify;
import com.fzzy.igds.constant.OrderRespEnum;
import com.fzzy.igds.data.QuantityProgressData;
import com.fzzy.igds.websocket.WebSocketPacket;
import com.fzzy.igds.websocket.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
 * @Description
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Slf4j
@Component
public class NotifyWebInvokerImpl implements NotifyWebInvoker {
    @Override
    public void notifyWeb(String companyId, OrderRespEnum orderResp,
                          String bizType, String notifyMsg) {
        // é€šçŸ¥å‰ç«¯
        WebSocketPacket packet = new WebSocketPacket();
        packet.setBizType(bizType);
        packet.setCompanyId(companyId);
        packet.setOrderResp(orderResp.getCode());
        packet.setData(notifyMsg);
        WebSocketServer.sendByPocket(packet);
    }
    @Override
    public void notifyQuantityProgress(QuantityProgressData progress) {
        // é€šçŸ¥å‰ç«¯è¿›åº¦ä¿¡æ¯
        WebSocketPacket packet = new WebSocketPacket();
        packet.setBizType("quantity");
        packet.setCompanyId(progress.getCompanyId());
        packet.setOrderResp(OrderRespEnum.ORDER_INPROGRESS.getCode());
        packet.setData(progress);
        packet.setDeptId(progress.getDeptId());
        WebSocketServer.sendByPocket(packet);
    }
}
fzzy-igdss-core/src/main/java/com/fzzy/igds/request/QuantityRequest.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
package com.fzzy.igds.request;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * ç²®æƒ…检测请求
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class QuantityRequest extends ExeBaseRequest {
    /**
     * äº‘台功能 ç¼–码 PTZFunc
     */
    public String func ;
    /**
     * äº‘台功能附加参数,比如速度,预设点位
     */
    public String par;
    private Double length1 = 0.0 ;
    private Double length2 = 0.0 ;
    private Double length3 = 0.0 ;
    private Double length4 = 0.0 ;
    private Double width= 0.0;
    private Double height= 0.0;
    private Double lineHeight = 0.0;
    private Double density = 0.0;
    private Double length = 0.0;
    private String ytIp;
    private Integer ytPort;
    private String  depotType;//仓房类型
    private Double volumeAdd = 0.0;//v体积补偿 å•位 m³
    private Double weightAdd = 0.0;//重量补偿 å•位KG
    private String sn;
    //用于开始采集的时候提前生成批次编号
    private String batchId;
}
fzzy-igdss-core/src/main/java/com/fzzy/igds/service/FileService.java
@@ -89,14 +89,28 @@
                data.setBizTag(bizTag);
            }
            data.setCreateTime(new Date());
            data.setCreateBy(ContextUtil.getLoginUserName());
            data.setUpdateTime(new Date());
            data.setUpdateBy(ContextUtil.getLoginUserName());
            fileMapper.insert(data);
            saveFile(data);
        }
    }
    /**
     *
     * @param data
     */
    public void saveFile(FileInfo data) {
        data.setUpdateTime(new Date());
        data.setUpdateBy(ContextUtil.getLoginUserName());
        if(StringUtils.isBlank(data.getId())){
            data.setId(ContextUtil.UUID());
            data.setCreateTime(new Date());
            data.setCreateBy(ContextUtil.getLoginUserName());
        }
        fileMapper.insert(data);
    }
    /**
     * æ ¹æ®æ¡ä»¶æŸ¥è¯¢æ•°æ®
@@ -139,6 +153,7 @@
        if("TEMP".equals(pathTag)) return getTempFilePath();
        if("CONF".equals(pathTag)) return getConfPath();
        if("TEMPLATE".equals(pathTag)) return getTemplateFilePath();
        if("QUANTITY".equals(pathTag)) return getQuantityPath();
        if("WORD".equals(pathTag)) return getWordPath();
        return getCommonFilePath();
@@ -148,6 +163,19 @@
     * èŽ·å–äº‹ä»¶æ–‡ä»¶è·¯å¾„
     * @return
     */
    public String getQuantityPath() {
        String basePath = FrameworkConfig.getProfile() + "QUANTITY/" + DateFormatUtils.format(new Date(), "yyyyMM") + "/";
        File file = new File(basePath);
        if (!file.exists()) {
            file.mkdirs();
        }
        return basePath;
    }
    /**
     * èŽ·å–äº‹ä»¶æ–‡ä»¶è·¯å¾„
     * @return
     */
    public String getEventFilePath() {
        String basePath = FrameworkConfig.getProfile() + "EVENT/" + DateFormatUtils.format(new Date(), "yyyyMM") + "/";
        File file = new File(basePath);
fzzy-igdss-core/src/main/java/com/fzzy/igds/service/QuantityService.java
@@ -89,6 +89,15 @@
    }
    /**
     * ä¿å­˜æ•°æ®
     *
     * @param data
     */
    public void saveData(Quantity data) {
        quantityMapper.insert(data);
    }
    /**
     * æŸ¥è¯¢é…ç½®ä¿¡æ¯ï¼Œæ ¹æ®åº“区编码获取
     *
     * @param companyId
fzzy-igdss-core/src/main/java/com/fzzy/igds/utils/Base64Util.java
@@ -1,15 +1,18 @@
package com.fzzy.igds.utils;
import lombok.extern.slf4j.Slf4j;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.io.*;
import java.util.Base64;
/**
 * @Description å›¾ç‰‡Base处理
 * @Author CZT
 * @Date 2026/1/7 11:07
 */
@Slf4j
public class Base64Util {
    public static String BASE_IMG_START = "data:image/jpg;base64,";
@@ -85,4 +88,59 @@
        }
    }
    /**
     * base64转为图片
     *
     * @param path   æ–‡ä»¶è·¯å¾„:到文件夹即可,代码里会在文件夹里生成对应的jpg文件
     * @param base64
     * @return
     */
    public static String base64ToJpg(String path, String fileName, String base64) {
        // åˆ¤æ–­æ–‡ä»¶è·¯å¾„是否存在
        File filePath = new File(path);
        if (!filePath.exists()) {
            filePath.mkdirs();
        }
        // åˆ›å»ºæ–‡ä»¶
        String jpgFile = path + "\\" + fileName + ".jpg";
        File file = new File(jpgFile);
        boolean jpgFileExist = false;
        try {
            jpgFileExist = file.createNewFile();
            log.info("jpg文件创建成功");
        } catch (IOException e) {
            log.info("jpg文件创建失败");
            e.printStackTrace();
        }
        if (jpgFileExist) {
            // è§£å¯†
            Base64.Decoder decoder = Base64.getDecoder();
            // åŽ»æŽ‰base64前缀 data:image/jpeg;base64,
            base64 = base64.substring(base64.indexOf(",", 1) + 1, base64.length());
            byte[] b = decoder.decode(base64);
            // å¤„理数据
            for (int i = 0; i < b.length; ++i) {
                if (b[i] < 0) {
                    b[i] += 256;
                }
            }
            // ä¿å­˜å›¾ç‰‡
            try {
                FileOutputStream out = new FileOutputStream(jpgFile);
                out.write(b);
                out.flush();
                out.close();
                // å†™å…¥æˆåŠŸè¿”å›žæ–‡ä»¶è·¯å¾„
                return jpgFile;
            } catch (FileNotFoundException e) {
                log.info("文件未找到");
                e.printStackTrace();
            } catch (IOException e) {
                log.info("写入失败");
                e.printStackTrace();
            }
        }
        return "文件不存在";
    }
}
fzzy-igdss-io/pom.xml
@@ -67,9 +67,6 @@
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
        </resources>
    </build>
</project>
fzzy-igdss-io/src/main/java/com/fzzy/igds/ServerRunner.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package com.fzzy.igds;
import com.fzzy.igds.quantity.server.BhznQuantityServerEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
 * @Description å¯ä»¥æ ¹æ®é…ç½®æ–‡ä»¶çµæ´»è°ƒæ•´,配置随系统自动启动服务 -- æ‰§è¡Œé¡ºåº10-19
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Component(ServerRunner.BEAN_ID)
@Order(value = 10)
public class ServerRunner implements CommandLineRunner {
    public static final String BEAN_ID = "quantity.serverRunner";
    @Resource
    private BhznQuantityServerEngine serverEngine;
    @Override
    public void run(String... strings) throws Exception {
        serverEngine.start(BhznQuantityServerEngine.PORT);
    }
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/io/manager/QuantityRemoteManager.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
package com.fzzy.igds.io.manager;
import com.fzzy.igds.io.service.RemoteQuantityService;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
 * @Description æŽ¥å£Api所有协议的协议类,根据不同的协议配置调用不同的协议实现
 * @Author CZT
 * @Date 2025/12/9 9:56
 */
@Component(QuantityRemoteManager.BEAN_ID)
public class QuantityRemoteManager implements ApplicationContextAware {
    public static final String BEAN_ID = "quantity.remoteManager";
    public static Map<String, RemoteQuantityService> remoteQuantityMap = new HashMap<>();
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        Map<String, RemoteQuantityService> quantityMap = applicationContext
                .getBeansOfType(RemoteQuantityService.class);
        for (String key : quantityMap.keySet()) {
            remoteQuantityMap.put(quantityMap.get(key).getProtocol(),
                    quantityMap.get(key));
        }
    }
    /**
     * æ ¹æ®åè®®èŽ·å–å®žçŽ°
     *
     * @param protocol
     * @return
     */
    public RemoteQuantityService getRemoteQuantityService(String protocol) {
        return remoteQuantityMap.get(protocol);
    }
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/io/service/RemoteQuantityService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,70 @@
package com.fzzy.igds.io.service;
import com.fzzy.igds.request.QuantityRequest;
import com.fzzy.igds.response.BaseResponse;
/**
 * @Desc: æ•°é‡æ£€æµ‹åŠŸèƒ½æŽ¥å£å®šä¹‰
 * @author: Andy
 * @update-time: 2022/12/22
 */
public interface RemoteQuantityService {
    /**
     * å½“前协议名称,系统根据协议名称自动调用分机匹配的协议实现
     *
     * @return
     */
    String getProtocol();
    /**
     * æ•°é‡æ£€æµ‹å¼€å§‹æ‰§è¡Œæ£€æµ‹
     *
     * @param request
     * @return
     */
    BaseResponse checkStart(QuantityRequest request);
    /**
     * @Desc:远程下发配置信息
     * @author: Andy
     * @update-time: 2022/12/22
     */
    BaseResponse remoteConf(QuantityRequest request);
    /**
     * æš‚停检测功能
     *
     * @param request
     * @return
     */
    BaseResponse checkStop(QuantityRequest request);
    /**
     * è¿‡ç¨‹æŠ“拍照片
     *
     * @param request
     * @return
     */
    BaseResponse snapImg(QuantityRequest request);
    /**
     * å…³é—­æŠ¥è­¦
     *
     * @param request
     * @return
     */
    BaseResponse closeWarn(QuantityRequest request);
    /**
     * æ‘„像头云台控制
     *
     * @param Request
     * @return
     */
    BaseResponse ptz(QuantityRequest Request);
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/io/service/impl/DefaultRemoteQuantityImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
package com.fzzy.igds.io.service.impl;
import com.fzzy.igds.constant.OrderRespEnum;
import com.fzzy.igds.constant.ProtocolEnum;
import com.fzzy.igds.io.service.RemoteQuantityService;
import com.fzzy.igds.request.QuantityRequest;
import com.fzzy.igds.response.BaseResponse;
import org.springframework.stereotype.Repository;
@Repository
public class DefaultRemoteQuantityImpl implements RemoteQuantityService {
    @Override
    public String getProtocol() {
        return ProtocolEnum.TCP_DEFAULT.getCode();
    }
    @Override
    public BaseResponse checkStart(QuantityRequest request) {
        return new BaseResponse(OrderRespEnum.NO_PROTOCOL);
    }
    @Override
    public BaseResponse remoteConf(QuantityRequest request) {
        return null;
    }
    @Override
    public BaseResponse checkStop(QuantityRequest request) {
        return new BaseResponse(OrderRespEnum.NO_PROTOCOL);
    }
    @Override
    public BaseResponse snapImg(QuantityRequest request) {
        return new BaseResponse(OrderRespEnum.NO_PROTOCOL);
    }
    @Override
    public BaseResponse closeWarn(QuantityRequest request) {
        return new BaseResponse(OrderRespEnum.NO_PROTOCOL);
    }
    @Override
    public BaseResponse ptz(QuantityRequest Request) {
        return new BaseResponse(OrderRespEnum.NO_PROTOCOL);
    }
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/analysis/AnalysisService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,299 @@
package com.fzzy.igds.quantity.analysis;
import com.alibaba.fastjson.JSON;
import com.fzzy.igds.constant.Constant;
import com.fzzy.igds.data.QuantityProgressData;
import com.fzzy.igds.domain.Depot;
import com.fzzy.igds.domain.FileInfo;
import com.fzzy.igds.domain.Quantity;
import com.fzzy.igds.domain.QuantityConf;
import com.fzzy.igds.notify.NotifyWebInvoker;
import com.fzzy.igds.quantity.command.BhznRemoteQuantityImpl;
import com.fzzy.igds.quantity.command.CommandBuilder;
import com.fzzy.igds.quantity.dto.IoMessage;
import com.fzzy.igds.quantity.dto.Resp2003;
import com.fzzy.igds.quantity.dto.Resp2004;
import com.fzzy.igds.quantity.dto.Resp2006;
import com.fzzy.igds.quantity.server.BhznQuantityServerEngine;
import com.fzzy.igds.quantity.util.ServerUtils;
import com.fzzy.igds.request.QuantityRequest;
import com.fzzy.igds.service.DepotService;
import com.fzzy.igds.service.FileService;
import com.fzzy.igds.service.QuantityService;
import com.fzzy.igds.utils.ContextUtil;
import com.ruoyi.common.config.FrameworkConfig;
import com.ruoyi.common.core.redis.RedisCache;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
 * @Description åè®®è§£æžå…¥å£
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Slf4j
@Component("fzzy.quantityAnalysisService")
public class AnalysisService{
    @Autowired
    private DepotService depotService;
    @Autowired
    private QuantityService quantityService;
    @Autowired
    private NotifyWebInvoker notifyWebInvoker;
    @Autowired
    private FileService fileService;
    @Autowired
    private RedisCache redisUtil;
    @Autowired
    private BhznQuantityServerEngine bhznQuantityServerEngine;
    @Autowired
    private BhznRemoteQuantityImpl remoteQuantity;
    /**
     * @param sessionKey ip:port
     */
    public void analysis(String sessionKey, IoMessage message) throws Exception {
        if (message == null) return;
        String[] attr = sessionKey.split(":");
        String ip = attr[0];
        Integer port = Integer.valueOf(attr[1]);
        String checkMsg = checkMsg(message);
        if (null != checkMsg) {
            log.warn("数量检测---->>>平台:,分机SN={},报文信息-={},响应吗返回不正确,无法进行解析," + checkMsg, message.getSn(), message.toString());
            return;
        }
        QuantityConf conf = quantityService.getCacheQuantityConfBySn(message.getSn());
        if (null == conf) {
            //说明当前设备未注册平台,直接踢出连接
            log.info("数量检测---->>>平台:登陆认证SN-{}-平台未注册,直接踢出连接", message.getSn());
            bhznQuantityServerEngine.destroy(ip, port);
            return;
        }
        switch (message.getFunctionId()) {
            case "1001"://服务端下发配置
                //不处理
                break;
            case "1002"://终端请求时间同步
                analysis1002(ip, port, conf, message);
                break;
            case "1003"://终端设备请求登陆
                analysis1003(ip, port, conf, message);
                break;
            case "2001"://开始检测
                //
                break;
            case "2002"://停止检测
                //
                break;
            case "2003"://服务端查询进度
                analysis2003(ip, port, conf, message);
                break;
            case "2004"://终端发起结果上报
                analysis2004(ip, port, conf, message);
                break;
            case "2005"://服务端发起数据点位提取
                analysis2005(ip, port, conf, message);
                break;
            case "2006"://服务端请求抓拍,终端返回图像信息
                analysis2006(ip, port, conf, message);
                break;
            case "2007"://终端主动发起心跳维持
                analysis2007(ip, port, conf, message);
                break;
            default:
                break;
        }
    }
    /**
     * ç”¨æˆ·ç™»é™†æˆåŠŸï¼Œæ›´æ–°æ•°æ®å’Œç¼“å­˜ï¼Œè¿›å…¥å½“å‰æŽ¥å£è¡¨ç¤ºå¹³å°å·²ç»è®¤è¯é€šè¿‡ï¼Œç›´æŽ¥æ›´æ–°å¹¶è¿”å›žæ­£å¸¸ä¿¡æ¯
     *
     * @param ip
     * @param port
     * @param conf
     * @param message
     */
    private void analysis1003(String ip, Integer port, QuantityConf conf, IoMessage message) {
        conf.setIp(ip);
        conf.setPort(port);
        conf.setStatus(Constant.YN_Y);
        quantityService.updateQuantityConfBySn(conf);
        //返回正常
        remoteQuantity.sendMsg(ip, port, CommandBuilder.getInstance().build1003Message(message));
    }
    /**
     * è¿”回给终端当前时间
     *
     * @param quantityConf
     * @param message
     */
    private void analysis1002(String ip, Integer port, QuantityConf quantityConf, IoMessage message) {
        //直接返回
        remoteQuantity.sendMsg(ip, port, CommandBuilder.getInstance().build1002Message(message));
    }
    /**
     * è§£æžç»ˆç«¯è¿”回的采集进度
     *
     * @param message
     */
    private void analysis2003(String ip, Integer port, QuantityConf conf, IoMessage message) {
        String key = ServerUtils.buildRequestKey(conf.getCompanyId(), conf.getSn());
        QuantityRequest quantityRequest = (QuantityRequest) redisUtil.getCacheObject(key);
        if (quantityRequest == null) {
            log.error("没有找到发送的命令,可能已经超时,取消解析:" + message.toString());
            return;
        }
        QuantityProgressData progressData = new QuantityProgressData();
        progressData.setCompanyId(conf.getCompanyId());
        progressData.setDepotId(conf.getDepotId());
        progressData.setDeptId(conf.getDeptId());
        Resp2003 content = JSON.parseObject(message.getContent(), Resp2003.class);
        if (content == null) {
            log.error("没有找到关联配置,取消解析:" + message.toString());
            return;
        }
        Depot depot = depotService.getCacheDepot(conf.getCompanyId(),
                conf.getDepotId());
        progressData.setProgress(content.getProgress());
        log.info(depot.getName() + "数量监测执行进度:" + progressData.getProgress());
        progressData.setMsg(depot.getName() + "数量监测执行进度:"
                + progressData.getProgress());
        notifyWebInvoker.notifyQuantityProgress(progressData);
        //根据进度抓拍
        if (progressData.getProgress() >= 1 && progressData.getProgress() <= 25) {
            remoteQuantity.sendMsg(ip, port, CommandBuilder.getInstance().build2006Message(message));
        }
        if (progressData.getProgress() > 25 && progressData.getProgress() <= 50) {
            remoteQuantity.sendMsg(ip, port, CommandBuilder.getInstance().build2006Message(message));
        }
        if (progressData.getProgress() > 50 && progressData.getProgress() <= 75) {
            remoteQuantity.sendMsg(ip, port, CommandBuilder.getInstance().build2006Message(message));
        }
        if (progressData.getProgress() > 75 && progressData.getProgress() <= 99) {
            remoteQuantity.sendMsg(ip, port, CommandBuilder.getInstance().build2006Message(message));
        }
    }
    /**
     * è§£æžç»ˆç«¯è¿”回的结果,并返回成功
     *
     * @param conf
     * @param message
     */
    private void analysis2004(String ip, Integer port, QuantityConf conf, IoMessage message) {
        Resp2004 content = JSON.parseObject(message.getContent(), Resp2004.class);
        if (content == null) {
            log.error("没有数据,取消解析:" + message.toString());
            return;
        }
        String key = ServerUtils.buildRequestKey(conf.getCompanyId(), conf.getSn());
        QuantityRequest request = (QuantityRequest) redisUtil.getCacheObject(key);
        if (request == null) {
            log.error("没有获取到发送命令,取消解析:" + message.toString());
            return;
        }
        Depot depot = depotService.getCacheDepot(conf.getCompanyId(), conf.getDepotId());
        Quantity quantityData = new Quantity();
        quantityData.setBatchId(request.getBatchId());
        quantityData.setReceiveDate(new Date());
        quantityData.setBulk(content.getVolume());
        quantityData.setWeight(content.getWeight());
        quantityData.setDepotId(depot.getId());
        quantityData.setDeptId(depot.getDeptId());
        quantityData.setCompanyId(depot.getCompanyId());
        quantityData.setPoints("");
        quantityService.saveData(quantityData);
        //直接返回
        remoteQuantity.sendMsg(ip, port, CommandBuilder.getInstance().build2004Message(message));
    }
    /**
     * è§£æžç»ˆç«¯è¿”回的点位数据
     *
     * @param quantityConf
     * @param message
     */
    private void analysis2005(String ip, Integer port, QuantityConf quantityConf, IoMessage message) {
        // todo
    }
    /**
     * è§£æžæŠ“拍的图片信息
     *
     * @param conf
     * @param message
     */
    private void analysis2006(String ip, Integer port, QuantityConf conf, IoMessage message) {
        Resp2006 content = JSON.parseObject(message.getContent(), Resp2006.class);
        if (content == null) {
            log.error("没有数据,取消解析:" + message.toString());
            return;
        }
        String key = ServerUtils.buildRequestKey(conf.getCompanyId(), conf.getSn());
        QuantityRequest res = (QuantityRequest) redisUtil.getCacheObject(key);
        if (res == null) {
            log.error("没有获取到发送命令,取消解析:" + message.toString());
            return;
        }
        String fileName = ContextUtil.generateId()+ ".jpg";
        String savePath = fileService.getFileSavePath("QUANTITY");
        String filePath = savePath+fileName;
        fileService.baseImg2Disk(filePath, content.getData());
        FileInfo data = new FileInfo();
        data.setId(ContextUtil.UUID());
        data.setCreateTime(new Date());
        data.setFileName(fileName);
        data.setFilePath(filePath.replace(FrameworkConfig.getProfile(), "/profile/"));
        data.setBizId(res.getBatchId());
        data.setBizTag("quantity");
        data.setCompanyId(conf.getCompanyId());
        fileService.saveFile(data);
    }
    /**
     * å¿ƒè·³åé¦ˆ
     *
     * @param quantityConf
     * @param message
     */
    private void analysis2007(String ip, Integer port, QuantityConf quantityConf, IoMessage message) {
        remoteQuantity.sendMsg(ip, port, CommandBuilder.getInstance().build2007Message(message));
    }
    public String checkMsg(IoMessage message) {
        if (StringUtils.isEmpty(message.getResult())) return null;
        if (ServerUtils.RESP_0.equals(message.getResult())) return null;
        if (ServerUtils.RESP_1.equals(message.getResult())) return "命令格式错误";
        if (ServerUtils.RESP_2.equals(message.getResult())) return "命令数据检验异常";
        if (ServerUtils.RESP_3.equals(message.getResult())) return "发送超时错误";
        if (ServerUtils.RESP_4.equals(message.getResult())) return "终端设备不在线";
        if (ServerUtils.RESP_5.equals(message.getResult())) return "终端设备执行中";
        if (ServerUtils.RESP_6.equals(message.getResult())) return "终端设备抓拍失败";
        if (ServerUtils.RESP_9.equals(message.getResult())) return "其它错误";
        return null;
    }
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/command/BhznRemoteQuantityImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,140 @@
package com.fzzy.igds.quantity.command;
import com.fzzy.igds.constant.OrderRespEnum;
import com.fzzy.igds.constant.ProtocolEnum;
import com.fzzy.igds.io.service.RemoteQuantityService;
import com.fzzy.igds.notify.NotifyWebInvoker;
import com.fzzy.igds.quantity.dto.IoMessage;
import com.fzzy.igds.quantity.server.BhznQuantityServerEngine;
import com.fzzy.igds.quantity.util.ServerUtils;
import com.fzzy.igds.request.QuantityRequest;
import com.fzzy.igds.response.BaseResponse;
import com.ld.io.api.InvokeResult;
import com.ruoyi.common.core.redis.RedisCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
/**
 * @Description
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Slf4j
@Component(BhznRemoteQuantityImpl.BEAN_ID)
public class BhznRemoteQuantityImpl implements RemoteQuantityService {
    public static final String BEAN_ID = "fzzy.remoteQuantityService";
    @Autowired
    private BhznQuantityServerEngine bhznQuantityServerEngine;
    @Autowired
    private NotifyWebInvoker notifyWebInvoker;
    @Autowired
    private RedisCache redisUtil;
    @Override
    public String getProtocol() {
        return ProtocolEnum.TCP_FZZY_QUANTITY_V35.getCode();
    }
    @Override
    public BaseResponse checkStart(QuantityRequest request) {
        try {
            String key = ServerUtils.buildRequestKey(request.getCompanyId(), request.getSn());
            IoMessage message = CommandBuilder.getInstance().build2001Message(request);
            InvokeResult result = sendMsg(request.getIp(), request.getPort(), message);
            // å¦‚果有执行异常,直接通知到前端
            if (InvokeResult.SUCCESS != result) {
                log.info("平台------>>>>数量检测:开始检测-失败{}", result.getMessage());
                notifyWebInvoker.notifyWeb(request.getCompanyId(), OrderRespEnum.ORDER_ERROR, "SYS", request.getSerName() + " 开始检测,命令执行失败");
                return new BaseResponse(OrderRespEnum.ORDER_ERROR.getCode(),
                        "开始检测执行失败:" + result.getMessage());
            }
            //最长保存一个小时
            redisUtil.setCacheObject(key, request, 60 * 60 , TimeUnit.SECONDS);
            //启动子任务定时查询进度
            FutureTask<String> futureTask = new FutureTask<>(new QueryProgressTask(redisUtil, this, key));
            ExecutorService executorService = Executors.newCachedThreadPool();
            executorService.submit(futureTask);
            executorService.shutdown();
        } catch (Exception e) {
            return new BaseResponse(OrderRespEnum.ORDER_ERROR.getCode(),
                    "执行失败:" + e.getMessage());
        }
        return new BaseResponse(OrderRespEnum.ORDER_SUCCESS);
    }
    @Override
    public BaseResponse remoteConf(QuantityRequest request) {
        //检测之前先下发配置
        IoMessage message = CommandBuilder.getInstance().build1001Message(request);
        InvokeResult result = sendMsg(request.getIp(), request.getPort(), message);
        if (InvokeResult.SUCCESS != result) {
            log.info("平台------>>>>数量检测:下发配置失败-失败{}", result.getMessage());
            notifyWebInvoker.notifyWeb(request.getCompanyId(), OrderRespEnum.ORDER_ERROR, "SYS", request.getSerName() + " 下发检测配置,命令执行失败");
            return new BaseResponse(OrderRespEnum.ORDER_ERROR.getCode(),
                    "下发配置执行失败:" + result.getMessage());
        }
        return new BaseResponse(OrderRespEnum.ORDER_SUCCESS);
    }
    @Override
    public BaseResponse checkStop(QuantityRequest request) {
        //检测之前先下发配置
        IoMessage message = CommandBuilder.getInstance().build2002Message(request);
        InvokeResult result = sendMsg(request.getIp(), request.getPort(), message);
        if (InvokeResult.SUCCESS != result) {
            log.info("平台------>>>>数量检测:停止检测-失败{}", result.getMessage());
            notifyWebInvoker.notifyWeb(request.getCompanyId(), OrderRespEnum.ORDER_ERROR, "SYS", request.getSerName() + " 停止检测失败,命令执行失败");
            return new BaseResponse(OrderRespEnum.ORDER_ERROR.getCode(),
                    "停止检测执行失败:" + result.getMessage());
        }
        String key = ServerUtils.buildRequestKey(request.getCompanyId(),request.getSn());
        //删除缓存
        redisUtil.deleteObject(key);
        return new BaseResponse(OrderRespEnum.ORDER_SUCCESS);
    }
    @Override
    public BaseResponse snapImg(QuantityRequest request) {
        return new BaseResponse(OrderRespEnum.NO_PROTOCOL);
    }
    @Override
    public BaseResponse closeWarn(QuantityRequest request) {
        return new BaseResponse(OrderRespEnum.NO_FUNCTION);
    }
    @Override
    public BaseResponse ptz(QuantityRequest Request) {
        return new BaseResponse(OrderRespEnum.NO_FUNCTION);
    }
    public InvokeResult sendMsg(String ip, Integer port, IoMessage message) {
        String msg = CommandBuilder.getInstance().build(message);
        log.info("平台------>>>>数量检测:报文信息-{}", msg);
        InvokeResult result = bhznQuantityServerEngine.push(ip, port, msg.getBytes());
        return result;
    }
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/command/CommandBuilder.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,210 @@
package com.fzzy.igds.quantity.command;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fzzy.igds.quantity.dto.IoMessage;
import com.fzzy.igds.quantity.dto.Req1001;
import com.fzzy.igds.quantity.dto.Resp1002;
import com.fzzy.igds.quantity.util.ServerUtils;
import com.fzzy.igds.request.QuantityRequest;
/**
 * @Description å‘½ä»¤ç”Ÿæˆ
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
public class CommandBuilder {
    /**
     * ä¸‹å‘配置
     *
     * @param request
     * @return
     */
    public IoMessage build1001Message(QuantityRequest request) {
        IoMessage message = new IoMessage();
        // è°ƒæ•´ä¿¡æ¯
        buildInfo(message, request);
        Req1001 req1001 = new Req1001();
        req1001.setHeight(request.getHeight().intValue());
        req1001.setOrien(1);
        req1001.setVoluWeight(request.getDensity().intValue());
        req1001.setStorageType("01".equals(request.getDepotType()) ? 1 : 0);
        req1001.setWeightAdd(request.getWeightAdd().intValue());
        req1001.setVolumeAdd(request.getVolumeAdd().intValue());
        if ("01".equals(request.getDepotType())) {
            req1001.setStorageType(1);
            req1001.setLength(new Double((request.getLength() * 100.00)).intValue());
            req1001.setWidth(new Double((request.getWidth() * 100.00)).intValue());
        } else {
            req1001.setStorageType(0);
            req1001.setRadius(new Double((request.getWidth() * 100.00)).intValue()); //筒仓时候宽度当作半径
        }
        message.setContent(JSON.toJSONString(req1001));
        message.setFunctionId(ServerUtils.FUNCTION_1001);
        return message;
    }
    /**
     * å›žå¤æ—¶é—´
     *
     * @return
     */
    public IoMessage build1002Message(IoMessage message) {
        message.setFunctionId(ServerUtils.FUNCTION_1002);
        Resp1002 resp1002 = new Resp1002();
        resp1002.setTime(System.currentTimeMillis());
        message.setContent(JSON.toJSONString(resp1002));
        return message;
    }
    /**
     * å›žå¤ç™»é™†æˆåŠŸ
     *
     * @return
     */
    public IoMessage build1003Message(IoMessage message) {
        message.setFunctionId(ServerUtils.FUNCTION_1003);
        message.setContent(null);
        return message;
    }
    /**
     * å¼€å§‹æ£€æµ‹
     *
     * @param request
     * @return
     */
    public IoMessage build2001Message(QuantityRequest request) {
        IoMessage message = new IoMessage();
        // è°ƒæ•´ä¿¡æ¯
        buildInfo(message, request);
        message.setFunctionId(ServerUtils.FUNCTION_2001);
        return message;
    }
    /**
     * åœæ­¢æ£€æµ‹
     *
     * @param request
     * @return
     */
    public IoMessage build2002Message(QuantityRequest request) {
        IoMessage message = new IoMessage();
        // è°ƒæ•´ä¿¡æ¯
        buildInfo(message, request);
        message.setFunctionId(ServerUtils.FUNCTION_2002);
        return message;
    }
    /**
     * è¿›åº¦æŸ¥è¯¢
     *
     * @param request
     * @return
     */
    public IoMessage build2003Message(QuantityRequest request) {
        IoMessage message = new IoMessage();
        // è°ƒæ•´ä¿¡æ¯
        buildInfo(message, request);
        message.setFunctionId(ServerUtils.FUNCTION_2003);
        return message;
    }
    /**
     * ç»“果上报
     *
     * @param
     * @return
     */
    public IoMessage build2004Message(IoMessage message) {
        message.setFunctionId(ServerUtils.FUNCTION_2004);
        message.setContent(null);
        return message;
    }
    /**
     * æŸ¥è¯¢ç‚¹ä½æ•°æ®
     *
     * @param request
     * @return
     */
    public IoMessage build2005Message(QuantityRequest request) {
        IoMessage message = new IoMessage();
        // è°ƒæ•´ä¿¡æ¯
        buildInfo(message, request);
        message.setFunctionId(ServerUtils.FUNCTION_2005);
        return message;
    }
    /**
     * æŠ“拍
     *
     * @param message
     * @return
     */
    public IoMessage build2006Message(IoMessage message) {
        message.setFunctionId(ServerUtils.FUNCTION_2006);
        message.setContent("");
        return message;
    }
    /**
     * æŠ“拍
     *
     * @param request
     * @return
     */
    public IoMessage build2006Message(QuantityRequest request) {
        IoMessage message = new IoMessage();
        // è°ƒæ•´ä¿¡æ¯
        buildInfo(message, request);
        message.setFunctionId(ServerUtils.FUNCTION_2006);
        return message;
    }
    /**
     * å¿ƒè·³è¿”回
     *
     * @param message
     * @return
     */
    public IoMessage build2007Message(IoMessage message) {
        //message.setFunctionId(ServerUtils.FUNCTION_2007);
        return message;
    }
    public void buildInfo(IoMessage message, QuantityRequest request) {
        message.setSn(request.getSn());
        message.setOrderId(ServerUtils.createOrderId());
        message.setSign(ServerUtils.SIGN_DEFAULT);
        message.setResult(ServerUtils.RESP_0);
        message.setVersion(ServerUtils.VERSION_1);
    }
    /**
     * æ ¹æ®ç”Ÿæˆçš„命令,进行调整
     *
     * @param message
     */
    public String build(IoMessage message) {
        StringBuffer hexSb = new StringBuffer();
        hexSb.append(ServerUtils.MSG_BEGIN);
        hexSb.append(JSONObject.toJSONString(message));
        hexSb.append((ServerUtils.MSG_END));
        return hexSb.toString();
    }
    private static CommandBuilder instance = new CommandBuilder();
    private CommandBuilder() {
    }
    public static CommandBuilder getInstance() {
        return instance;
    }
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/command/QueryProgressTask.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
package com.fzzy.igds.quantity.command;
import com.fzzy.igds.quantity.dto.IoMessage;
import com.fzzy.igds.request.QuantityRequest;
import com.ruoyi.common.core.redis.RedisCache;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Callable;
/**
 * @Description æ•°é‡æ£€æµ‹è¿›åº¦æŸ¥è¯¢ï¼Œé»˜è®¤æ‰§è¡Œä¸‰æ¬¡æŸ¥è¯¢å’Œä¸‰æ¬¡æŠ“拍
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Slf4j
public class QueryProgressTask implements Callable<String> {
    private RedisCache redisUtil;
    private String redisKey;
    private BhznRemoteQuantityImpl remoteQuantityService;
    public QueryProgressTask() {
        super();
    }
    public QueryProgressTask(RedisCache redisUtil, BhznRemoteQuantityImpl remoteQuantityService, String redisKey) {
        super();
        this.redisUtil = redisUtil;
        this.remoteQuantityService = remoteQuantityService;
        this.redisKey = redisKey;
    }
    @Override
    public String call() throws Exception {
        int index = 1;
        while (index <= 10) {
            index++;
            try {
                Thread.sleep(1000 * 35);
                QuantityRequest request = (QuantityRequest) redisUtil.getCacheObject(redisKey);
                if (null == request) {
                    index = 11;
                    log.debug("子命令执行进度查询结束:检测完成" );
                    return "SUCCESS";
                }
                IoMessage message = CommandBuilder.getInstance().build2003Message(request);
                log.debug("平台---->>数量检测:子命令执行进度查询:" + message.toString());
                remoteQuantityService.sendMsg(request.getIp(), request.getPort(), message);
                Thread.sleep(1000 * 3);
            } catch (Exception e) {
                log.error("平台---->>数量检测:子命令执行出现异常:" + e.getMessage());
                log.error(e.getMessage(), e);
            }
        }
        return "SUCCESS";
    }
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/dto/IoMessage.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
package com.fzzy.igds.quantity.dto;
import lombok.Data;
import java.io.Serializable;
/**
 * @Description è¿”回信息封装
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Data
public class IoMessage implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private String sn;//序列号
    private String version = "V1.0";
    private String sign = "0000";
    private String functionId;
    private String result;
    private String orderId;
    private String content;//消息体
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/dto/Req1001.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
package com.fzzy.igds.quantity.dto;
import lombok.Data;
import java.io.Serializable;
/**
 * @Description è¿”回信息封装
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Data
public class Req1001 implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private int height;//安装高度
    private int  orien;//安装朝向 8个标准方向,1-东,2-西,3-南,4-北,5-东南,6-西南,7-东北,8-西北
    private int voluWeight;//容重仓库粮食容重,如果不填写,后期测量,只返回体积,不返回重量信息
    private int storageType;// ä»“房类型  0-筒仓,1-平房仓,
    private int length;//仓房长  å•位厘米
    private int width;// ä»“房宽 å•位厘米
    private int radius;// ç­’仓半径
    private int coneHeight;//筒仓下锥高度
    private int probeX;//x轴坐标偏移量
    private int probeY;//y轴坐标偏移量
    private int volumeAdd;//v体积补偿 å•位 m³
    private int weightAdd;//重量补偿 å•位KG
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/dto/Resp1002.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.fzzy.igds.quantity.dto;
import lombok.Data;
import java.io.Serializable;
/**
 * @Description è¿”回信息封装
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Data
public class Resp1002 implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private long time;//    æ—¶é—´æˆ³ï¼Œå½“前毫秒值
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/dto/Resp2003.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.fzzy.igds.quantity.dto;
import lombok.Data;
import java.io.Serializable;
/**
 * @Description è¿”回信息封装
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Data
public class Resp2003 implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private int index;//    æ£€æµ‹ç´¯ç§¯æ¬¡æ•°
    private int progress;//    0-100,表示0%-100%
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/dto/Resp2004.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
package com.fzzy.igds.quantity.dto;
import lombok.Data;
import java.io.Serializable;
/**
 * @Description è¿”回信息封装
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Data
public class Resp2004 implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private int height;    //高度 å•位厘米
    private double volume;    //体积
    private double weight;    //重量
    private int index;    //检测累积次数
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/dto/Resp2005.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
package com.fzzy.igds.quantity.dto;
import lombok.Data;
import java.io.Serializable;
/**
 * @Description è¿”回信息封装
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Data
public class Resp2005 implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private int index;//    æ£€æµ‹ç´¯ç§¯æ¬¡æ•°
    private int curPackage;//    å½“前包数
    private int sumPackeage;//    æ€»åŒ…æ•°
    private int orien;//    å®‰è£…朝向
    private int dataCount;//    åæ ‡ä¸ªæ•°
    private String data;//    åæ ‡æ•°æ®
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/dto/Resp2006.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.fzzy.igds.quantity.dto;
import lombok.Data;
import java.io.Serializable;
/**
 * @Description è¿”回信息封装
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Data
public class Resp2006 implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private String data;//    å›¾ç‰‡æ•°æ® base64格式
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/server/BhznQuantityMessageConsumer.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
package com.fzzy.igds.quantity.server;
import com.fzzy.igds.quantity.analysis.AnalysisService;
import com.fzzy.igds.quantity.dto.IoMessage;
import com.fzzy.igds.quantity.util.ServerUtils;
import com.ld.io.api.IoMsgConsumer;
import com.ld.io.api.IoSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
 * @Description è¿”回信息封装
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Service
@Slf4j
public class BhznQuantityMessageConsumer implements IoMsgConsumer {
    @Autowired
    private AnalysisService analysisService;
    /**
     * å¤„理消息
     *
     * @param ioSession
     * @param bytes
     */
    @Override
    public void consume(IoSession ioSession, byte[] bytes) {
        if (null == bytes) {
            log.error("Reply bytes is null");
            return;
        }
        try {
            String message = new String(bytes, ServerUtils.CHARSET);
            message = message.substring(message.indexOf(ServerUtils.MSG_BEGIN) + ServerUtils.MSG_BEGIN.length());
            log.info("数量检测---->>平台:报文信息:" + message);
            IoMessage ioMessage = ServerUtils.buildMessage(message);
            analysisService.analysis(ioSession.getBusinessKey(), ioMessage);
        } catch (Exception e) {
            log.error("数量检测---->>平台:报文异常:" + e.getMessage());
        }
    }
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/server/BhznQuantityServerEngine.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,115 @@
package com.fzzy.igds.quantity.server;
import com.fzzy.igds.quantity.util.ServerUtils;
import com.ld.io.api.InvokeResult;
import com.ld.io.api.IoServerOption;
import com.ld.io.api.IoSession;
import com.ld.io.api.IoSessionQuery;
import com.ld.io.netty.NettyServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
 * @Description é£Žæ­£è‡´è¿œåè®®Server启动类
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Slf4j
@Service
public class BhznQuantityServerEngine {
    public static final Integer PORT = 9306;
    @Autowired
    private BhznQuantityMessageConsumer defaultMessageConsumer;
    @Autowired
    private BhznQuantitySessionListener defaultSessionListener;
    private IoSessionQuery sessionQuery;
    public void start(Integer port) {
        IoServerOption ioServerOption = new IoServerOption();
        if (null != port) {
            ioServerOption.setPort(port);
        } else {
            ioServerOption.setPort(PORT);
        }
        ioServerOption.setDelimiter(ServerUtils.MSG_END.getBytes());
        NettyServer ioServer = new NettyServer(ioServerOption, defaultMessageConsumer, defaultSessionListener);
        ioServer.startup();
        sessionQuery = ioServer.getSessionQuery();
        log.info("* ");
        log.info("* ========================");
        log.info("* ");
        log.info("* [QUANTITY-FZZY-SERVER:FZZY_TCP_QUANTITY_V3.5,PORT={}]", PORT);
        log.info("* ");
        log.info("* ========================");
        log.info("* ");
        System.out.println("* ========================");
        System.out.println("* ");
        System.out.println("* [QUANTITY-FZZY-SERVER:FZZY_TCP_QUANTITY_V3.5,PORT={}]" + port);
        System.out.println("* ");
        System.out.println("* ========================");
    }
    public IoSessionQuery getSessionQuery() {
        return sessionQuery;
    }
    /**
     * å‘送信息
     *
     * @param ip
     * @param port
     * @param msg
     * @return
     */
    public InvokeResult push(String ip, int port, byte[] msg) {
        IoSessionQuery sessionFactory = getSessionQuery();
        List<IoSession> sessions = sessionFactory.getAllSession();
        IoSession session = null;
        for (IoSession ioSession : sessions) {
            if (ServerUtils.getServerKey(ip, port).equals(ioSession.getBusinessKey())) {
                session = ioSession;
                break;
            }
        }
        if (null == session) {
            return InvokeResult.CHANNEL_CLOSED;
        }
        return session.invoke(msg);
    }
    /**
     * ä¸»åŠ¨é”€æ¯å½“å‰è¿žæŽ¥
     *
     * @param ip
     * @param port
     * @return
     */
    public InvokeResult destroy(String ip, int port) {
        IoSessionQuery sessionFactory = getSessionQuery();
        List<IoSession> sessions = sessionFactory.getAllSession();
        IoSession session = null;
        for (IoSession ioSession : sessions) {
            if (ServerUtils.getServerKey(ip, port).equals(ioSession.getBusinessKey())) {
                session = ioSession;
                break;
            }
        }
        if (null == session) {
            return InvokeResult.SUCCESS;
        }
        // æ‰§è¡Œè¿žæŽ¥é”€æ¯
        session.destroy();
        return InvokeResult.SUCCESS;
    }
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/server/BhznQuantitySessionListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package com.fzzy.igds.quantity.server;
import com.fzzy.igds.quantity.util.ServerUtils;
import com.ld.io.api.IoSession;
import com.ld.io.api.IoSessionListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
 * @Description
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Slf4j
@Service
public class BhznQuantitySessionListener implements IoSessionListener {
    @Override
    public void onCreate(IoSession session) {
        log.info("++++新建连接++++-IP={},PORT={}", session.getAddress(), session.getPort());
        // æ·»åŠ è‡ªå®šä¹‰ä¸šåŠ¡ID
        session.setBusinessKey(ServerUtils.getServerKey(session.getAddress(), session.getPort()));
    }
    @Override
    public void onDestroy(IoSession session) {
        log.info("----连接断开-----IP={},PORT={}", session.getAddress(), session.getPort());
    }
}
fzzy-igdss-io/src/main/java/com/fzzy/igds/quantity/util/ServerUtils.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
package com.fzzy.igds.quantity.util;
import com.alibaba.fastjson.JSON;
import com.fzzy.igds.constant.RedisConst;
import com.fzzy.igds.quantity.dto.IoMessage;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
/**
 * @Description
 * @Author CZT
 * @Date 2026/01/08 16:36
 */
@Slf4j
public class ServerUtils {
    public static final String VERSION_1 = "v1.0";
    public static final String SIGN_DEFAULT = "0000";
    public static final String CHARSET = "UTF-8";
    public static final String MSG_BEGIN = "<BHZN>";
    public static final String MSG_END = "<END>";
    //功能码
    public static final String FUNCTION_1001 = "1001";// åŸºç¡€å‚数配置
    public static final String FUNCTION_2001 = "2001";// å¼€å§‹æ£€æµ‹
    public static final String FUNCTION_2002 = "2002";// åœæ­¢æ£€æµ‹
    public static final String FUNCTION_2003 = "2003";// è¿›åº¦æŸ¥è¯¢
    public static final String FUNCTION_2004 = "2004";// ç»“果上报
    public static final String FUNCTION_2005 = "2005";// åæ ‡æå–
    public static final String FUNCTION_2006 = "2006";// è¿œç¨‹æŠ“拍
    public static final String FUNCTION_2007 = "2007";// å¿ƒè·³ç»´æŒ
    public static final String FUNCTION_1002 = "1002";// æ—¶é—´åŒæ­¥
    public static final String FUNCTION_1003 = "1003";// è®¾å¤‡ç™»é™†
    //响应码
    public static String RESP_0 = "0";//    æˆåŠŸ
    public static String RESP_1 = "1";//    å‘½ä»¤æ ¼å¼é”™è¯¯
    public static String RESP_2 = "2";//    å‘½ä»¤æ•°æ®æ£€éªŒå¼‚常
    public static String RESP_3 = "3";//    å‘送超时错误
    public static String RESP_4 = "4";//    ç»ˆç«¯è®¾å¤‡ä¸åœ¨çº¿
    public static String RESP_5 = "5";//    ç»ˆç«¯è®¾å¤‡æ‰§è¡Œä¸­
    public static String RESP_6 = "6";//    ç»ˆç«¯è®¾å¤‡æŠ“拍失败
    public static String RESP_9 = "9";//    å…¶å®ƒé”™è¯¯
    /**
     * ç”ŸæˆTCP连接的KEY
     *
     * @param ip
     * @param port
     * @return
     */
    public static String getServerKey(String ip, Integer port) {
        return ip + ":" + port;
    }
    /**
     * @param message
     * @return
     */
    public static IoMessage buildMessage(String message) throws Exception {
        IoMessage ioMessage = JSON.parseObject(message, IoMessage.class);
        return ioMessage;
    }
    public static String buildRequestKey(String companyId, String sn) {
        return RedisConst.buildKey(companyId, sn);
    }
    public static String createOrderId() {
        return RandomUtils.nextInt(1000, 9999) + "";
    }
}
fzzy-igdss-web/src/main/java/com/fzzy/Application.java
@@ -11,9 +11,7 @@
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportResource;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -25,7 +23,6 @@
@EnableRedisHttpSession
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@ComponentScan(basePackages = {"com.fzzy", "com.ruoyi", "com.ld"})
@MapperScan("com.fzzy.*.mapper")
@EntityScan(basePackages = {"com.fzzy.*.*.domain"})
public class Application {
fzzy-igdss-web/src/main/java/com/fzzy/security/SecurityController.java
@@ -9,6 +9,7 @@
import com.fzzy.igds.data.PageResponse;
import com.fzzy.igds.data.PatrolSuperData;
import com.fzzy.igds.domain.*;
import com.fzzy.igds.response.BaseResponse;
import com.fzzy.igds.utils.ContextUtil;
import com.fzzy.igds.utils.SystemUtil;
import com.fzzy.common.manager.CommonManager;
@@ -277,7 +278,30 @@
        return secManager.getQuantityFiles(param);
    }
    /**
     * æ•°é‡ç›‘测-开始检测
     *
     * @param param
     * @return
     */
    @RequestMapping("/check-single")
    @ResponseBody
    public BaseResponse checkSingle(@RequestBody IgdsBaseParam param) {
        return secManager.checkSingle(param);
    }
    /**
     * æ•°é‡ç›‘测-停止检测
     *
     * @param param
     * @return
     */
    @RequestMapping("/check-stop")
    @ResponseBody
    public BaseResponse checkStop(@RequestBody IgdsBaseParam param) {
        return secManager.checkStop(param);
    }
    /*------------------巡更轨迹页面------------------*/
    /**
fzzy-igdss-web/src/main/java/com/fzzy/security/manager/SecManager.java
@@ -4,15 +4,22 @@
import com.fzzy.igds.camera.ApiCameraManager;
import com.fzzy.igds.camera.data.ApiCameraData;
import com.fzzy.igds.camera.data.ApiCameraResp;
import com.fzzy.igds.constant.OrderRespEnum;
import com.fzzy.igds.constant.RespCodeEnum;
import com.fzzy.igds.data.*;
import com.fzzy.igds.domain.*;
import com.fzzy.igds.io.manager.QuantityRemoteManager;
import com.fzzy.igds.io.service.RemoteQuantityService;
import com.fzzy.igds.request.QuantityRequest;
import com.fzzy.igds.response.BaseResponse;
import com.fzzy.igds.service.*;
import com.fzzy.igds.utils.ContextUtil;
import com.fzzy.igds.utils.DateUtil;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@@ -32,6 +39,8 @@
    @Resource
    private CommonManager commonManager;
    @Resource
    private QuantityRemoteManager remoteManager;
    @Resource
    private SecCameraService secCameraService;
    @Resource
@@ -316,4 +325,82 @@
        return new PageResponse<>(RespCodeEnum.CODE_0000.getCode(), "执行成功!!", fileList);
    }
    /**
     * å•仓检测
     *
     * @param param
     * @return
     */
    public BaseResponse checkSingle(IgdsBaseParam param) {
        if (null == param || StringUtils.isBlank(param.getDepotId())) {
            return new BaseResponse(RespCodeEnum.CODE_1007.getCode(), RespCodeEnum.CODE_1007.getMsg());
        }
        if (StringUtils.isBlank(param.getCompanyId())) {
            param.setCompanyId(ContextUtil.getCompanyId());
        }
        QuantityConf conf = quantityService.getCacheQuantityConf(param.getCompanyId(), param.getDepotId());
        if (conf == null) {
            return new BaseResponse(RespCodeEnum.CODE_1007.getCode(), RespCodeEnum.CODE_1007.getMsg());
        }
        RemoteQuantityService remoteQuantityService = remoteManager.getRemoteQuantityService(conf.getProtocol());
        if (null == remoteQuantityService) {
            return new BaseResponse(OrderRespEnum.ORDER_ERROR.getCode(),
                    "系统没有" + conf.getProtocol() + "的协议实现,执行被拒绝!");
        }
        QuantityRequest request = new QuantityRequest();
        BeanUtils.copyProperties(conf, request);
        request.setDepotId(conf.getDepotId());
        request.setYtIp(conf.getYtIp());
        request.setCompanyId(conf.getCompanyId());
        request.setDeptId(conf.getDeptId());
        request.setSn(conf.getSn());
        request.setLength(conf.getLength());
        request.setBatchId(conf.getDepotId() + "_" + DateFormatUtils.format(new Date(), "yyyyMMddHHmm"));
        return remoteQuantityService.checkStart(request);
    }
    /**
     * åœæ­¢æ£€æµ‹
     * @param param
     * @return
     */
    public BaseResponse checkStop(IgdsBaseParam param) {
        if (param == null || StringUtils.isEmpty(param.getDepotId())) {
            return new BaseResponse(RespCodeEnum.CODE_1007.getCode(), RespCodeEnum.CODE_1007.getMsg());
        }
        if (StringUtils.isEmpty(param.getCompanyId())) {
            param.setCompanyId(ContextUtil.getCompanyId());
        }
        QuantityConf conf = quantityService.getCacheQuantityConf(param.getCompanyId(), param.getDepotId());
        if (conf == null) {
            return new BaseResponse(RespCodeEnum.CODE_1007.getCode(), RespCodeEnum.CODE_1007.getMsg());
        }
        RemoteQuantityService remoteQuantityService = remoteManager.getRemoteQuantityService(conf.getProtocol());
        if (null == remoteQuantityService) {
            return new BaseResponse(OrderRespEnum.ORDER_ERROR.getCode(),
                    "系统没有" + conf.getProtocol() + "的协议实现,执行被拒绝!");
        }
        QuantityRequest request = new QuantityRequest();
        BeanUtils.copyProperties(conf, request);
        request.setCompanyId(conf.getCompanyId());
        request.setYtIp(conf.getYtIp());
        request.setSn(conf.getSn());
        request.setDeptId(conf.getDeptId());
        request.setDepotId(conf.getDepotId());
        return remoteQuantityService.checkStop(request);
    }
}
fzzy-igdss-web/src/main/resources/static/security/quantity.js
@@ -143,7 +143,6 @@
    }
}
/**
 * è¯·æ±‚图表信息
 */
@@ -317,6 +316,68 @@
    $("#divPlugin2").html(html);
}
/**
 * å¯åŠ¨å¼€å§‹æ£€æµ‹
 */
function checkStart() {
    if (!curCamera) {
        shoTips("请先选择设备!");
        return;
    }
    layer.msg("开始执行……");
    var data = {
        'depotId': curCamera.depotId
    };
    $.ajax({
        type: "POST",
        url: "/security/check-single",
        dataType: "json",
        contentType: "application/json;charset=UTF-8",
        data: JSON.stringify(data),
        success: function (result) {
            if (result.code == "ORDER_SUCCESS") {
                shoTips("命令发生成功,请等待终端返回结果……");
            } else {
                shoTips("命令发送失败:" + result.msg);
            }
        },
        error: function () {
            shoTips("检测出现异常,执行失败!");
        }
    });
}
/**
 * åœæ­¢æ£€æµ‹
 */
function checkStop() {
    if (!curCamera) {
        shoTips("请先选择仓库!");
        return;
    }
    layer.msg("开始执行……");
    var data = {
        'depotId': curCamera.depotId
    };
    $.ajax({
        type: "POST",
        url: "/security/check-stop",
        dataType: "json",
        contentType: "application/json;charset=UTF-8",
        data: JSON.stringify(data),
        success: function (result) {
            if (result.code == "ORDER_SUCCESS") {
                shoTips("命令发生成功……");
            } else {
                shoTips("命令发送失败:" + result.msg);
            }
        },
        error: function () {
            shoTips("检测出现异常,执行失败!");
        }
    });
}
// åˆå§‹åŒ–ECharts温度走势图
function initEcharts(names, data) {
    // åˆå§‹åŒ–ECharts温度走势图
@@ -389,4 +450,11 @@
    window.addEventListener('resize', function () {
        temperatureChart.resize();
    });
}
function shoTips(msg) {
    layer.msg(msg,
        {time: 3000, shift: 5, offset: "rb"},
        function () {
        });
}
fzzy-igdss-web/src/main/resources/templates/security/quantity.html
@@ -68,28 +68,34 @@
                    <!-- ç®€åŒ–的视频控制工具栏-->
                    <div style="margin-top: 15px; text-align: center; background-color: #f5f5f5; padding: 10px; border-radius: 4px;">
                        <button class="layui-btn layui-btn-default layui-btn-sm">
                           ä¸Šç§» <i class="layui-icon layui-icon-up"></i>
                        <button class="layui-btn layui-btn-default layui-btn-sm" onmousedown="ptzControl(1);"
                                onmouseup="moveStop();">
                            ä¸Šç§» <i class="layui-icon layui-icon-up"></i>
                        </button>
                        <button class="layui-btn layui-btn-default layui-btn-sm">
                           ä¸‹ç§» <i class="layui-icon layui-icon-down"></i>
                        <button class="layui-btn layui-btn-default layui-btn-sm" onmousedown="ptzControl(2);"
                                onmouseup="moveStop();">
                            ä¸‹ç§» <i class="layui-icon layui-icon-down"></i>
                        </button>
                        <button class="layui-btn layui-btn-default layui-btn-sm">
                           å·¦ç§» <i class="layui-icon layui-icon-left"></i>
                        <button class="layui-btn layui-btn-default layui-btn-sm" onmousedown="ptzControl(3);"
                                onmouseup="moveStop();">
                            å·¦ç§» <i class="layui-icon layui-icon-left"></i>
                        </button>
                        <button class="layui-btn layui-btn-default layui-btn-sm">
                           å³ç§» <i class="layui-icon layui-icon-right"></i>
                        <button class="layui-btn layui-btn-default layui-btn-sm" onmousedown="ptzControl(4);"
                                onmouseup="moveStop();">
                            å³ç§» <i class="layui-icon layui-icon-right"></i>
                        </button>
                        <button class="layui-btn layui-btn-default layui-btn-sm">
                           åŠ å€ <i class="layui-icon layui-icon-addition"></i>
                        <button class="layui-btn layui-btn-default layui-btn-sm" onmousedown="ptzControl(10);"
                                onmouseup="zoomStop();">
                            å˜ç„¦å¤§ <i class="layui-icon layui-icon-addition"></i>
                        </button>
                        <button class="layui-btn layui-btn-default layui-btn-sm">
                           å‡å€ <i class="layui-icon layui-icon-subtraction"></i>
                        <button class="layui-btn layui-btn-default layui-btn-sm" onmousedown="ptzControl(9);"
                                onmouseup="zoomStop();">
                            å˜ç„¦å° <i class="layui-icon layui-icon-subtraction"></i>
                        </button>
                        <button class="layui-btn layui-btn-default layui-btn-sm">
                        <button class="layui-btn layui-btn-default layui-btn-sm" onclick="checkStart()">
                            å¼€å§‹æ£€æµ‹ <i class="layui-icon layui-icon-subtraction"></i>
                        </button>
                        <button class="layui-btn layui-btn-default layui-btn-sm">
                        <button class="layui-btn layui-btn-default layui-btn-sm" onclick="checkStop()">
                            åœæ­¢æ£€æµ‹ <i class="layui-icon layui-icon-subtraction"></i>
                        </button>
                    </div>
@@ -255,4 +261,5 @@
<script th:src="@{/ajax/libs/layui/layui.js}"></script>
<script th:src="@{/js/plugins/echarts/echarts.min-4.7.js}"></script>
<script th:src="@{/security/quantity.js}"></script>
<script th:src="@{/security/video-control.js}"></script>
</html>