#
Junjie
2024-06-22 4e6d844962ae71bfa593de96e68bae5628ad5ffa
#
5个文件已修改
4个文件已添加
543 ■■■■■ 已修改文件
zy-asrs-flow/src/pages/device/conveyor/index.jsx 242 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/device/conveyor/index.less 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/deviceConfig/basConveyorSta/components/edit.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/deviceConfig/basConveyorSta/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/controller/BasConveyorController.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/domain/param/ConveyorOperatorParam.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/entity/BasConveyorSta.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/model/protocol/StaProtocol.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/ws/ConveyorWebSocket.java 171 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/device/conveyor/index.jsx
New file
@@ -0,0 +1,242 @@
import React, { useEffect, useRef, useState } from "react";
import { getToken } from '@/utils/token-util'
import Http from '@/utils/http';
import { Badge, Button, Descriptions, Drawer, Input, Card, Select, message } from 'antd';
import {
    PageContainer,
} from '@ant-design/pro-components';
import './index.less'
import { WEBSOCKET_BASE_URL } from '@/config/setting';
const Main = () => {
    const [deviceInfos, setDeviceInfos] = useState([]);
    const [ws, setWs] = useState(null);
    const [openOpera, setOpenOpera] = useState(false);
    const [currentData, setCurrentData] = useState(null);
    const [taskNo, setTaskNo] = useState(null);
    const [staNo, setStaNo] = useState(null);
    useEffect(() => {
        console.log('yes');
        connect();
        return () => {
            if (ws) {
                ws.close();
            }
        }
    }, [])
    useEffect(() => {
        console.log('yes');
        if (ws) {
            ws.onopen = function () {
                console.log("open");
                sendWs(JSON.stringify({
                    "url": "login",
                    "data": {
                        "token": getToken()
                    }
                }))
            }
            ws.onmessage = function (e) {
                const result = JSON.parse(e.data);
                if (result.url == "login") {
                    setInterval(function () {
                        getDeviceInfo();
                    }, 1000)
                } else if (result.url == "/conveyor/list") {
                    const data = JSON.parse(result.data);
                    setDeviceInfos(data);
                }
            }
            ws.onclose = function (e) {
                console.log("close");
                reconnect();
            }
            ws.onerror = function (e) {
                console.log(e);
            }
        }
    }, [ws]);
    const connect = () => {
        var newWs = new WebSocket(WEBSOCKET_BASE_URL + "/ws/conveyor/websocket");
        setWs(newWs);
    }
    const reconnect = () => {
        setTimeout(() => {
            console.log('WebSocketClient: Attempting to reconnect...');
            connect();
        }, 3000);
    }
    const sendWs = (message) => {
        if (ws.readyState == WebSocket.OPEN) {
            ws.send(message)
        }
    }
    const getDeviceInfo = () => {
        sendWs(JSON.stringify({
            "url": "/conveyor/list",
            "data": {}
        }))
    }
    const showOpera = (data) => {
        setOpenOpera(true);
        setCurrentData(data);
        setTaskNo(data.taskNo);
        setStaNo(data.staNo);
    };
    const closeOpera = () => {
        setOpenOpera(false);
    };
    const taskNoChange = (e) => {
        setTaskNo(e.target.value)
    }
    const staNoChange = (e) => {
        setStaNo(e.target.value)
    }
    const conveyorOperator = async (type) => {
        try {
            const resp = await Http.doPost('api/basConveyor/operator/sta', {
                conveyorNo: currentData.conveyorNo,
                siteNo: currentData.siteNo,
                taskMode: type,
                taskNo: taskNo,
                staNo: staNo
            });
            if (resp.code === 200) {
                message.success("请求成功");
                return true;
            } else {
                message.warning(resp.msg);
                return false;
            }
        } catch (error) {
            message.warning("请求失败");
            return false;
        }
    }
    let codeContent = (<PageContainer
        header={{
            breadcrumb: {},
        }}
    >
        <div style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'space-around' }}>
            {deviceInfos.map(item => {
                if (item == null) {
                    return;
                }
                let tmpTitle = item.siteNo + "站"
                let tmpData = [
                    {
                        key: '1',
                        label: '任务号',
                        children: item.taskNo,
                    },
                    {
                        key: '2',
                        label: '自动',
                        children: item.autoing,
                    },
                    {
                        key: '3',
                        label: '有物',
                        children: item.loading,
                    },
                    {
                        key: '4',
                        label: '可入',
                        children: item.inEnable,
                    },
                    {
                        key: '5',
                        label: '可出',
                        children: item.outEnable,
                    },
                    {
                        key: '6',
                        label: '能入',
                        children: item.canining,
                    },
                    {
                        key: '7',
                        label: '能出',
                        children: item.canouting,
                    },
                    {
                        key: '8',
                        label: '高低类型',
                        children: item.locType1$,
                    },
                    {
                        key: '9',
                        label: '宽窄类型',
                        children: item.locType2$,
                    },
                    {
                        key: '10',
                        label: '轻重类型',
                        children: item.locType3$,
                    },
                    {
                        key: '11',
                        label: '工作模式',
                        children: item.workMode$,
                    },
                    {
                        key: '12',
                        label: '目标站',
                        children: item.staNo,
                    },
                ];
                return <div key={item.id} style={{ width: '45%', marginBottom: '30px' }}>
                    <div style={{ marginBottom: '10px' }}>
                        <span style={{ marginRight: '10px' }}>{tmpTitle}</span>
                        <Button type="primary" onClick={() => showOpera(item)}>操作</Button>
                    </div>
                    <Descriptions size="small" bordered items={tmpData} />
                </div>
            })}
        </div>
    </PageContainer>);
    if (currentData) {
        codeContent = (
            <>
                {codeContent}
                <Drawer title="操作面板" onClose={closeOpera} open={openOpera}>
                    <h2 style={{ marginBottom: '15px' }}>{currentData.siteNo}站</h2>
                    <div style={{ marginBottom: '15px' }}>
                        <Card title="相关指令" style={{ width: 300 }}>
                            <div className="commandItem">
                                <Input value={taskNo} addonBefore="工作号" onChange={taskNoChange} />
                                <Input value={staNo} addonBefore="目标站" onChange={staNoChange} />
                                <Button type="primary" onClick={() => conveyorOperator('taskNoAndStaNo')}>保存</Button>
                            </div>
                        </Card>
                    </div>
                </Drawer>
            </>
        )
    }
    return (codeContent);
}
export default Main;
zy-asrs-flow/src/pages/device/conveyor/index.less
New file
@@ -0,0 +1,15 @@
.commandItem {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
}
.commandItem > Button {
    width: 120px;
    margin-bottom: 10px;
}
.commandItem > div {
    width: 120px;
    margin-bottom: 10px;
}
zy-asrs-flow/src/pages/deviceConfig/basConveyorSta/components/edit.jsx
@@ -223,6 +223,13 @@
                            colProps={{ md: 12, xl: 12 }}
                        />
                    </ProForm.Group>
                    <ProForm.Group>
                        <ProFormText
                            name="staNo"
                            label="目标站"
                            colProps={{ md: 12, xl: 12 }}
                        />
                    </ProForm.Group>
                </ProForm>
            </Modal>
zy-asrs-flow/src/pages/deviceConfig/basConveyorSta/index.jsx
@@ -407,6 +407,19 @@
                setSearchParam={setSearchParam}
            />,
        },
        {
            title: '目标站',
            dataIndex: 'staNo',
            valueType: 'text',
            hidden: false,
            width: 140,
            filterDropdown: (props) => <TextFilter
                name='staNo'
                {...props}
                actionRef={actionRef}
                setSearchParam={setSearchParam}
            />,
        },
        {
            title: '操作',
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/controller/BasConveyorController.java
@@ -8,19 +8,35 @@
import com.zy.asrs.wcs.common.domain.BaseParam;
import com.zy.asrs.wcs.common.domain.KeyValVo;
import com.zy.asrs.wcs.common.domain.PageParam;
import com.zy.asrs.wcs.core.domain.param.ConveyorOperatorParam;
import com.zy.asrs.wcs.core.domain.param.ShuttleOperatorParam;
import com.zy.asrs.wcs.core.entity.BasConveyor;
import com.zy.asrs.wcs.core.entity.Motion;
import com.zy.asrs.wcs.core.entity.Task;
import com.zy.asrs.wcs.core.entity.TaskCtg;
import com.zy.asrs.wcs.core.model.enums.DeviceCtgType;
import com.zy.asrs.wcs.core.model.enums.TaskCtgType;
import com.zy.asrs.wcs.core.model.enums.TaskStsType;
import com.zy.asrs.wcs.core.service.BasConveyorService;
import com.zy.asrs.wcs.core.utils.Utils;
import com.zy.asrs.wcs.rcs.News;
import com.zy.asrs.wcs.rcs.cache.SlaveConnection;
import com.zy.asrs.wcs.rcs.entity.Device;
import com.zy.asrs.wcs.rcs.model.enums.LiftProtocolStatusType;
import com.zy.asrs.wcs.rcs.model.enums.SlaveType;
import com.zy.asrs.wcs.rcs.service.DeviceService;
import com.zy.asrs.wcs.rcs.thread.DevpThread;
import com.zy.asrs.wcs.rcs.thread.LiftThread;
import com.zy.asrs.wcs.rcs.thread.ShuttleThread;
import com.zy.asrs.wcs.system.controller.BaseController;
import com.zy.asrs.wcs.utils.ExcelUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.*;
@RestController
@RequestMapping("/api")
@@ -28,6 +44,8 @@
    @Autowired
    private BasConveyorService basConveyorService;
    @Autowired
    private DeviceService deviceService;
    @PreAuthorize("hasAuthority('core:basConveyor:list')")
    @PostMapping("/basConveyor/page")
@@ -99,4 +117,43 @@
        ExcelUtil.build(ExcelUtil.create(basConveyorService.list(), BasConveyor.class), response);
    }
    //手动操作
    @PreAuthorize("hasAuthority('core:basConveyor:operator')")
    @PostMapping("/basConveyor/operator/sta")
    @Transactional
    public synchronized R conveyorOperator(@RequestBody ConveyorOperatorParam param) {
        if (Cools.isEmpty(param.getConveyorNo(), param.getTaskMode())) {
            return R.error("参数为空");
        }
        Integer conveyorNo = param.getConveyorNo();
        Device device = deviceService.getOne(new LambdaQueryWrapper<Device>()
                .eq(Device::getDeviceType, DeviceCtgType.CONVEYOR.val())
                .eq(Device::getStatus, 1)
                .eq(Device::getDeviceNo, conveyorNo));
        if (device == null) {
            return R.error("设备不存在");
        }
        DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Conveyor, device.getId().intValue());
        if (devpThread == null) {
            return R.error("设备离线");
        }
        if (param.getTaskMode().equals("taskNoAndStaNo")) {
            //写入工作号和目标站
            if (Cools.isEmpty(param.getSiteNo())) {
                return R.error("站点不存在");
            }
            boolean result = devpThread.writeWorkSta(param.getSiteNo(), Short.parseShort(param.getTaskNo()), param.getStaNo().shortValue());
            if (!result) {
                return R.error("保存失败");
            }
            return R.ok("保存成功");
        }
        return R.ok();
    }
}
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/domain/param/ConveyorOperatorParam.java
New file
@@ -0,0 +1,23 @@
package com.zy.asrs.wcs.core.domain.param;
import lombok.Data;
@Data
public class ConveyorOperatorParam {
    // 输送线号
    private Integer conveyorNo;
    // 站点号
    private Integer siteNo;
    // 命令类型
    private String taskMode;
    // 工作号
    private String taskNo;
    // 目标站
    private Integer staNo;
}
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/entity/BasConveyorSta.java
@@ -179,6 +179,12 @@
    @ApiModelProperty(value= "工作模式")
    private Integer workMode;
    /**
     * 目标站
     */
    @ApiModelProperty(value= "目标站")
    private Integer staNo;
    public BasConveyorSta() {}
    public BasConveyorSta(Long conveyorId,Integer conveyorNo,Long updateBy,Long createBy,Date createTime,Date updateTime,String memo,Integer deleted,Long hostId,Integer siteNo,String inEnable,String outEnable,String autoing,String loading,String canining,String canouting,Integer locType1,Integer locType2,Integer locType3,String locNo,String qrCodeValue) {
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/model/protocol/StaProtocol.java
@@ -92,6 +92,7 @@
        station.setInEnable(inEnable?"Y":"N");
        station.setOutEnable(outEnable?"Y":"N");
        station.setWorkMode(workMode);
        station.setStaNo((int) staNo);
        station.setLocType1(0);  // 高低类型{0:未知,1:低库位,2:高库位}
        station.setLocType2(0);  // 宽窄类型{0:未知,1:窄库位,2:宽库位}
        station.setLocType3(0);  // 轻重类型{0:未知,1:轻库位,2:重库位}
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/ws/ConveyorWebSocket.java
New file
@@ -0,0 +1,171 @@
package com.zy.asrs.wcs.rcs.ws;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zy.asrs.framework.common.R;
import com.zy.asrs.framework.common.SpringUtils;
import com.zy.asrs.wcs.common.config.ConfigProperties;
import com.zy.asrs.wcs.common.security.JwtSubject;
import com.zy.asrs.wcs.core.entity.BasConveyorSta;
import com.zy.asrs.wcs.core.service.BasConveyorStaService;
import com.zy.asrs.wcs.rcs.ws.model.WebSocketMessage;
import com.zy.asrs.wcs.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
@Component
@Slf4j
@Service
@ServerEndpoint("/ws/conveyor/websocket")
@Data
public class ConveyorWebSocket {
    //客户端在线人数
    private static int onlineClient = 0;
    //客户端池
    private static CopyOnWriteArraySet<ConveyorWebSocket> webSocketServers = new CopyOnWriteArraySet<>();
    private Session session;
    private String username;
    private Long hostId;
    //管道ID
    private String sessionId;
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        this.sessionId = session.getId();
        //将websocket对象进行保存
        webSocketServers.add(this);
        //添加在线人数
        addOnlineClient();
        log.info("有新窗口开始监听:" + session.getId() + ",当前在线人数为:" + getOnlineClient());
    }
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketServers.remove(this);  //从set中删除
        subOnlineClient();           //在线数减1
        log.info("关闭的连接:" + sessionId);
        log.info("有一连接关闭!当前在线人数为" + getOnlineClient());
    }
    /**
     * 收到客户端消息后调用的方法
     * @ Param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        BasConveyorStaService basConveyorStaService = SpringUtils.getBean(BasConveyorStaService.class);
        WebSocketMessage socketMessage = JSON.parseObject(message, WebSocketMessage.class);
        if (socketMessage.getUrl().equals("login")) {
            try {
                // 解析token
                ConfigProperties configProperties = SpringUtils.getBean(ConfigProperties.class);
                JSONObject data = JSON.parseObject(socketMessage.getData());
                Claims claims = JwtUtil.parseToken(data.getString("token"), configProperties.getTokenKey());
                JwtSubject jwtSubject = JwtUtil.getJwtSubject(claims);
                this.username = jwtSubject.getUsername();
                this.hostId = jwtSubject.getHostId();
                socketMessage.setData(JSON.toJSONString(R.ok("auth success")));
            } catch (Exception e) {
                e.printStackTrace();
                socketMessage.setData(JSON.toJSONString(R.error("auth fail")));
            }
            this.sendMessage(JSON.toJSONString(socketMessage));
        } else if (socketMessage.getUrl().equals("/conveyor/list")) {
            if (this.hostId != null) {
                // 根据输送线plc遍历
                List<BasConveyorSta> list = basConveyorStaService.list();
                socketMessage.setData(JSON.toJSONString(list));
                this.sendMessage(JSON.toJSONString(socketMessage));
            }
        }
//        log.info("收到来自连接:" + sessionId + "的信息:" + message);
    }
    /**
     * @ Param session
     * @ Param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }
    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }
    /**
     * 服务器主动推送给指定用户
     */
    public void sendMessage(String message, String account) throws IOException {
        for (ConveyorWebSocket item : webSocketServers) {
            item.sendMessage(message);
        }
    }
    public void sendMessage(String message, int userId) throws IOException {
        for (ConveyorWebSocket item : webSocketServers) {
            item.sendMessage(message);
        }
    }
    /**
     * 服务器主动推送给指定用户
     */
    public static boolean sendMessageGlobal(String message, String account) throws IOException {
        boolean tag = false;
        for (ConveyorWebSocket item : webSocketServers) {
            tag = true;
            item.sendMessage(message);
        }
        return tag;
    }
    public static boolean sendMessageGlobal(String message, int userId) throws IOException {
        boolean tag = false;
        for (ConveyorWebSocket item : webSocketServers) {
            tag = true;
            item.sendMessage(message);
        }
        return tag;
    }
    public static synchronized int getOnlineClient() {
        return onlineClient;
    }
    public static synchronized void addOnlineClient() {
        ConveyorWebSocket.onlineClient++;
    }
    public static synchronized void subOnlineClient() {
        if (ConveyorWebSocket.onlineClient > 0) {
            ConveyorWebSocket.onlineClient--;
        }
    }
}