10分钟,创建你的第一个点线面低代码应用
1. 效果预览
这个例子包括,串口的打开和发送,包括字符串的发送和hex 的发送。最终效果如图。
点线面低代码应用下载
GitHub 下载地址 https://github.com/dotLinePlane-com/dotlineplane/releases
通过百度网盘分享的文件:dotLinePlaneV2.1.0.7z 链接:https://pan.baidu.com/s/1XUl32fFD3ssZoPMqC4NmQw?pwd=qn0d 提取码:qn0d
2. 具体步骤
创建一个应用主要有四个步骤,包括:拖拽组件、设置组件属性、编写js脚本和设置组件事件与脚本关联。
2.1 拖拽组件
界面的右边选择拖拽到画布中。
使用的组件有 dropdown (端口和波特率)、按钮(打开和发送)、复选框(Hex 发送)、文本输入框(发送区)和 多行文本输入框(接收区和log)
2.2 设置组件属性
这里主要设置组件的名称属性,其他的有程序设置。
端口----》dropdownPort
波特率----》dropdownBaud
复选框----》HexSendCheckbox
发送区----》send
接收区----》recivedData
log----》log
2.3 添加 js 脚本
***添加 init 脚本时,注意需要在Settings 中打开 在应用程序加载时运行此查询
init
//init 脚本
// 获取串口列表
const ports = await serialAPI.getSerialPorts();
console.log("v port :", ports);
// 格式化串口数据
let formattedPorts = ports.map(port => ({
disable: false,
visible: true,
value: port.path,
label: port.friendlyName || port.path,
}));
console.log("port:", formattedPorts);
// 获取 defaultPortsValue, portsLabel 和 portsValue
const defaultPortsValue = formattedPorts.length > 0 ? formattedPorts[0].value : null;
const portsLabel = formattedPorts.map(port => port.label);
const portsValue = formattedPorts.map(port => port.value);
const portsSelect = {
defaultPortsValue,
portsLabel,
portsValue,
};
const baudsValue = [9600, 115200];
const baudsLabel = ["9600", "115200"];
const defaultBaudsValue = baudsValue[0];
const baudsSelect = {
defaultBaudsValue,
baudsValue,
baudsLabel,
};
// 更新 formattedPorts 对象结构
const formattedPortsObject = {
portsSelect,
baudsSelect,
};
console.log("formattedPortsObject:", formattedPortsObject);
// 设置页面变量
await actions.setPageVariable('ports', formattedPortsObject);
await actions.setPageVariable('serialRx', '');
await actions.setPageVariable('isOpen', false);
// 定义处理串口数据的函数
const handleSerialData = async (path, data) => {
if (path === page.variables.usedPort) {
const receiveTime = Date.now();
console.log(`[${new Date(receiveTime).toISOString()}] Received data:`, data);
await actions.setPageVariable('serialRx', data);
}
};
// 初始化串口连接
const initializeSerialConnection = async () => {
if (page.variables.isOpen) {
// 设置使用的串口
await actions.setPageVariable('usedPort', components.dropdownPort.value);
serialAPI.onSerialData(components.dropdownPort.value, handleSerialData);
} else {
await actions.setPageVariable('usedPort', '');
// serialAPI.offSerialData(portRef.current, handleSerialData);
}
};
// 在页面加载时执行初始化
await initializeSerialConnection();
// 返回格式化后的串口对象
return formattedPortsObject;
openPort
//openPort
function mergeUint8Arrays(arrays) {
console.log(`Received data:`, arrays);
if (arrays instanceof Uint8Array) {
arrays = [arrays];
}
if (!Array.isArray(arrays)) {
console.error("Input is not an array.");
return null;
}
// 确保数组中的每个元素都是 Uint8Array
for (let i = 0; i < arrays.length; i++) {
if (!(arrays[i] instanceof Uint8Array)) {
console.error(`Element at index ${i} is not a Uint8Array.`);
return null;
}
}
// 计算总长度
const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
// 创建新的 Uint8Array
const mergedArray = new Uint8Array(totalLength);
// 复制数据
let offset = 0;
arrays.forEach(arr => {
mergedArray.set(arr, offset);
offset += arr.length;
});
return mergedArray;
}
const handleSerialData = async (path, data) => {
if (path === page.variables.usedPort) {
const receiveTime = Date.now();
console.log(`[${new Date(receiveTime).toISOString()}] Received data:`, data);
const mergeData = mergeUint8Arrays(data);
const decoder = new TextDecoder('utf-8');
const stringData = decoder.decode(mergeData);
console.log("serialRx:",stringData);
await actions.setPageVariable('serialRx', stringData);
}
};
if (!page.variables.isOpen) {
// Open the serial port
const config = {
path:components.dropdownPort.value,
baudRate: parseInt(components.dropdownBaud.value, 10),
dataBits:8,
parity:'none',
stopBits:1,
// dataBits: parseInt(components.dropdownBits.value, 10),
// parity: components.dropdownCrc.value === 'NONE' ? 'none' : components.dropdownCrc.value.toLowerCase(),
// stopBits: parseInt(components.dropdownStop.value, 10),
};
try {
const result = await serialAPI.openSerialPort(config);
console.log(result);
await actions.setPageVariable('usedPort', components.dropdownPort.value);
serialAPI.onSerialData(components.dropdownPort.value, handleSerialData);
await actions.setPageVariable('isOpen', true);
components.openButton.setText("关闭");
} catch (error) {
console.error('Failed to open serial port:', error);
}
} else {
// Close the serial port
try {
await serialAPI.closeSerialPort(page.variables.usedPort);
serialAPI.offSerialData(page.variables.usedPort, handleSerialData);
await actions.setPageVariable('isOpen', false);
components.openButton.setText("打开");
} catch (error) {
console.error('Failed to close serial port:', error);
await actions.setPageVariable('isOpen', false);
components.openButton.setText("打开");
if(page.variables.usedPort){
serialAPI.offSerialData(page.variables.usedPort, handleSerialData);
}
}
}
return 0;
sendData
//sendData
function hexStringToUint8Array(hexString) {
// 确保字符串长度为偶数
if (hexString.length % 2 !== 0) {
return null;
}
// 创建一个 Uint8Array,长度为字符串长度的一半
const length = hexString.length / 2;
const uint8Array = new Uint8Array(length);
// 遍历字符串,每两个字符解析为一个字节
for (let i = 0; i < length; i++) {
const byteHex = hexString.substr(i * 2, 2); // 提取两个字符
uint8Array[i] = parseInt(byteHex, 16); // 将 16 进制字符串解析为数字
}
return uint8Array;
}
if(page.variables.isOpen){
if(!components.HexSendCheckbox.value){
serialAPI.writeSerialPort(page.variables.usedPort,components.sendData.value);
}else{
const hexSend = hexStringToUint8Array(components.sendData.value);
if(hexSend){
serialAPI.writeSerialPort(page.variables.usedPort,hexSend);
// actions.showAlert("info:"+ "发送成功"); // 使用 ToolJet 的 toast 组件
actions.setVariable("infoMessage", "发送成功");
// queries.log.run()
await actions.runQuery('log',{message: "发送成功"});
}
}
}
log
//log
// 更新 log 内容
components.log.setText(components.log.value + variables.infoMessage + "\r\n");
// 获取 TextArea 元素
// 获取外层 div 元素
const textareaWrapper = document.getElementById(components.log.id);
// 从外层 div 中找到 textarea 元素
const textareaElement = textareaWrapper ? textareaWrapper.querySelector("textarea") : null;
// 检查是否成功获取 textarea
if (textareaElement) {
// 滚动到 textarea 的底部
textareaElement.scrollTop = textareaElement.scrollHeight;
}
2.4 组件事件与js脚本进行关联
3. 结束
更多的细节需要你自己的探索,那就开始你的点线面低代码的探索之旅吧!
有问题可以私信我,也可以在应用程序中找到联系方式,单独交流。