#实践案例#苍穹外设对接原创
金蝶云社区-城主
城主
21人赞赏了该文章 1,383次浏览 未经作者许可,禁止转载编辑于2023年02月08日 09:45:24
summary-icon摘要由AI智能服务提供

在使用云苍穹平台的B/S架构中,由于平台不提供外设对接方案,开发人员不能直接通过修改代码实现与外设如读卡器的对接。为解决这一问题,采用了一种通过JS(前端)、插件(后端)、WebService(本地)交互的方式。具体实现中,用户发起指令后,通过插件向JS传递指令,JS调用WebService调用外设并获取结果,然后将结果返回给JS,再由插件对结果进行处理。实现步骤包括JS端功能实现与控件上传、单据端拖放自定义控件、单据插件编写代码以发送和监听消息,以及本地WebService端用C#控制台实现接收指令并调用外设。通过这种方式,成功实现了云苍穹平台与外设的对接。

一、业务背景概述

在使用云苍穹平台的时候,会存在使用外设的需求。比如在信息采集的界面,通过第三方的读卡器读取采集信息,如身份证,社保卡,健康码等等。由于云苍穹是B/S架构,并且不提供外设相关的解决方案,开发人员并不能直接修改代码来实现与外设的对接。在此之前,我们预研了browser-serialport,也没办法实现我们web端读取外设信息的需求。


二、解决方案

因此需要通过曲线救国的方式来完成。这里用到的是js(前端)——插件(后端)——WebService(本地)交互的实现方法。


三、实现思路

用户发起指令——插件向JS传递指令——JS接收到指令,调用WebService——WebService调用外设,获得结果,然后返回给JS——JS接收到结果,传递给插件——插件对结果作相关处理。

image.png

四、具体实现步骤

1、JS端实现相关功能,打包成控件方案并上传。

js相关代码:

export default {
        data() {
            return {
                path:"ws://127.0.0.1:8181",//ws服务地址
                ws: {}
            };
        },
        watch: {
            data: function (newValue, oldValue) {
                //监听插件传过来的ws调用指令,然后给ws传递信息调用读卡
                console.log('ws调用');
                this.ws.send(newValue);
            },
        },
        props: {
            data: {//接收苍穹插件传入的数据
                type: String
            },
            model:{
                type: Object
            },
            invoke:{
                type: Function
            }
        },
        methods:{
            //init函数可在页面加载的时候就进行初始化或者根据自己的业务需求在需要打开通讯的时候在进行初始化
            init() {
            // 实例化socket,这里的实例化直接赋值给this.ws是为了后面可以在其它的函数中也能调用websocket方法,例如:this.ws.close(); 完成通信后关闭WebSocket连接
            this.ws = new WebSocket(this.path)
                     
            console.log("ws初始化");
            //监听是否连接成功
            this.ws.onopen = ()=> {
                console.log('ws连接状态:' +this.ws.readyState);
                //连接成功则发送一个数据
                this.ws.send('连接成功');
                }
             
            //接听服务器发回的信息并处理展示
            this.ws.onmessage = (data)=> {
                console.log('接收到来自服务器的消息:');
                console.log(data);
                console.log('返回的数据传给插件');      
                //data是ws的一个信息返回对象,读卡的信息保存在里面的data字段中,因此返回的是data.data,其余不必要的信息就不用返回了
                //返回方法名readcardevent跟插件端统一,不是固定名称
                this.invoke('readcardevent',data.data); 
                }
             
            //监听连接关闭事件
            this.ws.onclose = ()=>{
                //监听整个过程中websocket的状态
                console.log('ws连接状态:' + this.ws.readyState);
                }
             
            //监听并处理error事件。。。
            this.ws.onerror = function(error) {
                console.log(error);
                }
            }      
        },
        mounted(){
            //开启ws连接
            this.init();
        },
    }


2、在单据端,拖一个自定义控件,规范命名标识,然后选择第1步的控件方案;


image.png


3、在单据插件编写代码:


java插件发送消息至JS


// 获取控件
CustomControl customcontrol = this.getView().getControl("kdy_custom_read_card");
// 通过setData给自定义控件传输数据,前端就能通过props.data获取数据
customcontrol.setData("readCardPlease" + System.currentTimeMillis());


java插件监听JS返回的结果


@Override
public void customEvent(CustomEventArgs e) {
    IFormPlugin.super.customEvent(e);
 
    // 前端通过model.invoke定义的事件名
    String eventName = e.getEventName();
    // 拿到读卡数据
    String cardData = e.getEventArgs();
    if (eventName.isEmpty() || cardData.isEmpty()) {
        return;
    }
    if (eventName.toLowerCase(Locale.ROOT).equals("readcardevent")) {
        JSONObject obj = JSON.parseObject(cardData);
        // 姓名
        this.getModel().setValue("kdy_name", obj.getString("Name"));
        // 性别
        this.getModel().setItemValueByNumber("kdy_gender", obj.getString("Sex").contains("男") ? "1" : "2");
        // 证件号码
        this.getModel().setValue("kdy_id_number", obj.getString("CardId"));
        // 出生日期
        this.getModel().setValue("kdy_birthdate", obj.getDate("Birthday"));
    }
}


4、本地WebService端,用C#控制台实现


从NUGet获取Fleck

image.png

接收到JS发过来的指令后,开始调用外设


C#控制台监听指令并读卡


static void Main(string[] args)
{
    FleckLog.Level = LogLevel.Debug;
    var allSockets = new List<IWebSocketConnection>();
    var server = new WebSocketServer("ws://127.0.0.1:8181");
    server.RestartAfterListenError = true;
    server.Start(socket =>
    {
        socket.OnOpen = () =>
        {
            Console.WriteLine("Open!");
            allSockets.Add(socket);
        };
        socket.OnClose = () =>
        {
            Console.WriteLine("Close!");
            allSockets.Remove(socket);
            server.Dispose();
        };
        socket.OnMessage = message =>
        {
            Console.WriteLine(message);
            // TODO 处理逻辑
            // 单向返回
            //socket.Send("Echo: " + message);
            // 分发
            //allSockets.ToList().ForEach(s => s.Send("Echo: " + message));
 
            // 调用读卡器
            if (message.StartsWith("readCardPlease"))
            {
                // 读卡
                var card = CVRReadIDCard.ReadIDCard();
                var result = JsonConvert.SerializeObject(card);
 
                // 返回数据给JS
                socket.Send(result);
            }
        };
    });
  
    var input = Console.ReadLine();
}


五、方案的可推广价值

本方案基于真实业务场景,适用于所有pc端外设对接。

图标赞 21
21人点赞
还没有人点赞,快来当第一个点赞的人吧!
图标打赏
0人打赏
还没有人打赏,快来当第一个打赏的人吧!