#实践案例#苍穹外设对接原创
金蝶云社区-城主
城主
20人赞赏了该文章 1036次浏览 未经作者许可,禁止转载编辑于2023年02月08日 09:45:24

一、业务背景概述

在使用云苍穹平台的时候,会存在使用外设的需求。比如在信息采集的界面,通过第三方的读卡器读取采集信息,如身份证,社保卡,健康码等等。由于云苍穹是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端外设对接。

赞 20