Commit 3d8dc5f6 by 吴斌

update:完成规则脚本对Lua的支持。

parent 4d6bcd58
...@@ -1173,6 +1173,30 @@ ...@@ -1173,6 +1173,30 @@
"reusify": "^1.0.4" "reusify": "^1.0.4"
} }
}, },
"fengari": {
"version": "0.1.4",
"resolved": "https://registry.npmmirror.com/fengari/-/fengari-0.1.4.tgz",
"integrity": "sha512-6ujqUuiIYmcgkGz8MGAdERU57EIluGGPSUgGPTsco657EHa+srq0S3/YUl/r9kx1+D+d4rGfYObd+m8K22gB1g==",
"requires": {
"readline-sync": "^1.4.9",
"sprintf-js": "^1.1.1",
"tmp": "^0.0.33"
}
},
"fengari-interop": {
"version": "0.1.3",
"resolved": "https://registry.npmmirror.com/fengari-interop/-/fengari-interop-0.1.3.tgz",
"integrity": "sha512-EtZ+oTu3kEwVJnoymFPBVLIbQcCoy9uWCVnMA6h3M/RqHkUBsLYp29+RRHf9rKr6GwjubWREU1O7RretFIXjHw=="
},
"fengari-web": {
"version": "0.1.4",
"resolved": "https://registry.npmmirror.com/fengari-web/-/fengari-web-0.1.4.tgz",
"integrity": "sha512-f+W/Csx9VNyKttxYjZnk6290+Pcs7w7noDVhkuPEt0e51GWoD32vSNHFXhZYzTe8Ni/bhbk5VocNV1RBIgO5iA==",
"requires": {
"fengari": "^0.1.4",
"fengari-interop": "^0.1"
}
},
"fill-range": { "fill-range": {
"version": "7.0.1", "version": "7.0.1",
"resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz", "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz",
...@@ -1647,6 +1671,11 @@ ...@@ -1647,6 +1671,11 @@
"mimic-fn": "^2.1.0" "mimic-fn": "^2.1.0"
} }
}, },
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g=="
},
"p-limit": { "p-limit": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz", "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz",
...@@ -1824,6 +1853,11 @@ ...@@ -1824,6 +1853,11 @@
"picomatch": "^2.2.1" "picomatch": "^2.2.1"
} }
}, },
"readline-sync": {
"version": "1.4.10",
"resolved": "https://registry.npmmirror.com/readline-sync/-/readline-sync-1.4.10.tgz",
"integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw=="
},
"regenerator-runtime": { "regenerator-runtime": {
"version": "0.14.0", "version": "0.14.0",
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
...@@ -1915,6 +1949,11 @@ ...@@ -1915,6 +1949,11 @@
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz", "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
}, },
"sprintf-js": {
"version": "1.1.3",
"resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.1.3.tgz",
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
},
"strip-final-newline": { "strip-final-newline": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
...@@ -1995,6 +2034,14 @@ ...@@ -1995,6 +2034,14 @@
"resolved": "https://registry.npmmirror.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz", "resolved": "https://registry.npmmirror.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
}, },
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmmirror.com/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"requires": {
"os-tmpdir": "~1.0.2"
}
},
"to-regex-range": { "to-regex-range": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz",
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
"@element-plus/icons-vue": "^2.1.0", "@element-plus/icons-vue": "^2.1.0",
"@types/node": "^20.6.0", "@types/node": "^20.6.0",
"element-plus": "^2.3.12", "element-plus": "^2.3.12",
"fengari": "^0.1.4",
"fengari-web": "^0.1.4",
"gojs": "^2.1.48", "gojs": "^2.1.48",
"mathjs": "^12.0.0", "mathjs": "^12.0.0",
"vue": "^3.3.4", "vue": "^3.3.4",
......
...@@ -203,6 +203,7 @@ ...@@ -203,6 +203,7 @@
<div> <div>
<el-button type="primary" @click="addRuleParam">添加参数</el-button> <el-button type="primary" @click="addRuleParam">添加参数</el-button>
<div v-for="(input,index) in ruleDialog.data.inputs" class="flex mt-2 space-x-1"> <div v-for="(input,index) in ruleDialog.data.inputs" class="flex mt-2 space-x-1">
<div class="font-bold mr-2">{{index}}</div>
<el-select v-model="input['key']" class="flex-1"> <el-select v-model="input['key']" class="flex-1">
<el-option <el-option
v-for="device in deviceMap" v-for="device in deviceMap"
...@@ -269,7 +270,6 @@ import { ...@@ -269,7 +270,6 @@ import {
} from "./kit/core/Analyse.ts"; } from "./kit/core/Analyse.ts";
import {addRule, deleteRuleById, rules, runAllEnableRule, testRuleById, updateRule} from "./kit/rule/Rule"; import {addRule, deleteRuleById, rules, runAllEnableRule, testRuleById, updateRule} from "./kit/rule/Rule";
import {diagramModelData} from "./kit/ModelData.ts"; import {diagramModelData} from "./kit/ModelData.ts";
import {convertSVGToGeometry} from "./kit/core/SVG2Geometry.ts";
// 变量定义 // 变量定义
// region // region
// 图表配置 // 图表配置
...@@ -341,6 +341,7 @@ const ruleDialog = ref<Record<string, any>>({ ...@@ -341,6 +341,7 @@ const ruleDialog = ref<Record<string, any>>({
type:"add", type:"add",
data:{ data:{
name: "", name: "",
description:"",
inputs:[], inputs:[],
func:"", func:"",
} }
...@@ -538,7 +539,8 @@ function listenDiagram(){ ...@@ -538,7 +539,8 @@ function listenDiagram(){
}); });
myDiagram.addModelChangedListener(function(e:any){ myDiagram.addModelChangedListener(function(e:any){
if (e.isTransactionFinished) { if (e.isTransactionFinished) {
runAllEnableRule(getDiagramMapData(myDiagram)) deviceMap.value = getDiagramMapData(myDiagram)
runAllEnableRule(deviceMap.value)
} }
}) })
} }
...@@ -868,9 +870,9 @@ function confirmAddRule(){ ...@@ -868,9 +870,9 @@ function confirmAddRule(){
return return
} }
if(ruleDialog.value.type === 'add'){ if(ruleDialog.value.type === 'add'){
addRule(ruleData.name, ruleData.inputs, ruleData.func) addRule(ruleData.name, ruleData.description, ruleData.inputs, ruleData.func)
}else if(ruleDialog.value.type === 'update'){ }else if(ruleDialog.value.type === 'update'){
updateRule(ruleData.id, ruleData.name, ruleData.inputs, ruleData.func) updateRule(ruleData.id, ruleData.name, ruleData.description, ruleData.inputs, ruleData.func)
} }
ruleDialog.value.visible = false ruleDialog.value.visible = false
......
...@@ -7787,6 +7787,45 @@ export const diagramModelData = { ...@@ -7787,6 +7787,45 @@ export const diagramModelData = {
] ]
}, },
ruleData:[ ruleData:[
// {
// "id": "ffdb88cf1809049819226d3e617a1fbd4",
// "type": "js",
// "name": "1",
// "inputs": [
// {
// "key": -1,
// "valueKey": "name",
// "testData": ""
// },
// {
// "key": -2,
// "valueKey": "name",
// "testData": ""
// }
// ],
// "description": "1",
// "func": "return data[0]",
// "enable": false
// },
{
"id": "f3b59c21947034e6f81506812ccbaa2a8",
"type": "lua",
"name": "2",
"inputs": [
{
"key": -1,
"valueKey": "name",
"testData": ""
},
{
"key": -2,
"valueKey": "name",
"testData": ""
}
],
"description": "2",
"func": "return data[1]",
"enable": true
}
] ]
} }
import {uuid} from "vue3-uuid"; import {uuid} from "vue3-uuid";
import * as fengari from 'fengari-web';
export class RuleScriptType {
static Lua = 'lua'
static JS = 'js'
}
export var rules :Record<string, any>[]= [] /**
* {
* id: string // 规则id 也是函数名
* type: string // 规则语法类型 例如:lua,js等 暂定为只有lua
* inputs:[
* key: 对应设备的唯一id,
* valueKey: "name", 指定设备下的属性key,
* testData: 测试数据
* ] 输入的参数列表
* func: string // 规则函数
* enable: boolean // 是否启用
* name: string // 规则名称
* description: string // 规则描述
* actions: [
* type: 通知的类型 例如:success,info,warning,error
* content: string, 通知的内容
* ] // 规则动作 根据用户填写的规则的返回值来确定触发的效果
* }
*/
export var rules: Record<string, any>[] = []
/** /**
* 添加规则 * 添加规则
* @param name 规则名称 * @param name 规则名称
* @param inputs 输入参数 [{key:-1 ,valueKey:'thick',testData:""}] key表示节点在diagram中的唯一id,valueKey表示节点的属性key * @param description 规则描述
* @param inputs 输入参数
* @param func 规则函数 * @param func 规则函数
* @param actions 规则动作
*/ */
export function addRule(name:string, inputs:any[], func:Function){ export function addRule(name: string, description: string, inputs: any[], func: Function, actions:any[]=[]) {
const ruleId = 'f' + uuid.v4().split('-').join('')
rules.push({ rules.push({
id: uuid.v4(), id: ruleId,
name: name, name: name,
inputs: inputs, inputs: inputs,
description: description,
func: func, func: func,
enable:false, enable: false,
type: RuleScriptType.Lua, // 暂定为只有lua
actions: actions
}) })
} }
...@@ -22,14 +54,16 @@ export function addRule(name:string, inputs:any[], func:Function){ ...@@ -22,14 +54,16 @@ export function addRule(name:string, inputs:any[], func:Function){
* 更新规则 * 更新规则
* @param id 规则id * @param id 规则id
* @param name 规则名称 * @param name 规则名称
* @param description 规则描述
* @param inputs 输入参数 * @param inputs 输入参数
* @param func 规则函数 * @param func 规则函数
*/ */
export function updateRule(id:string, name:string, inputs:[], func:Function){ export function updateRule(id: string, name: string, description: string, inputs: [], func: Function) {
let ruleIndex = rules.findIndex((item:any) => item.id == id) let ruleIndex = rules.findIndex((item: any) => item.id == id)
if (ruleIndex !== -1){ if (ruleIndex !== -1) {
rules[ruleIndex].name = name rules[ruleIndex].name = name
rules[ruleIndex].inputs = inputs rules[ruleIndex].inputs = inputs
rules[ruleIndex].description = description
rules[ruleIndex].func = func rules[ruleIndex].func = func
} }
} }
...@@ -38,8 +72,8 @@ export function updateRule(id:string, name:string, inputs:[], func:Function){ ...@@ -38,8 +72,8 @@ export function updateRule(id:string, name:string, inputs:[], func:Function){
* 删除规则 * 删除规则
* @param id * @param id
*/ */
export function deleteRuleById(id:string){ export function deleteRuleById(id: string) {
rules.splice(rules.findIndex((item:any) => item.id == id), 1) rules.splice(rules.findIndex((item: any) => item.id == id), 1)
} }
...@@ -48,20 +82,26 @@ export function deleteRuleById(id:string){ ...@@ -48,20 +82,26 @@ export function deleteRuleById(id:string){
* @param rule 规则 * @param rule 规则
* @param deviceMap 设备数据 * @param deviceMap 设备数据
*/ */
export function runRule(rule:any, deviceMap:Record<string, any>){ export function runRule(rule: any, deviceMap: Record<string, any>) {
let inputData = [] let inputData = []
let runFunc = null let result = null
if (rule){ if (rule) {
for (let input of rule.inputs){ for (let input of rule.inputs) {
inputData.push(deviceMap[input.key][input.valueKey]) inputData.push(deviceMap[input.key][input.valueKey])
} }
runFunc = new Function( "return " + rule.func) switch (rule['type']) {
try { case RuleScriptType.Lua:
runFunc()(...inputData) result = runLua(rule, inputData)
}catch (e){ break
alert(e) case RuleScriptType.JS:
result = runJS(rule, inputData)
break
default:
alert('no such rule type' + rule['type'])
} }
} }
console.log('run rule result:', result)
return result
} }
...@@ -69,9 +109,9 @@ export function runRule(rule:any, deviceMap:Record<string, any>){ ...@@ -69,9 +109,9 @@ export function runRule(rule:any, deviceMap:Record<string, any>){
* 函数“runAllEnableRule”在给定的设备映射上运行所有启用的规则。 * 函数“runAllEnableRule”在给定的设备映射上运行所有启用的规则。
* @param deviceMap - 将设备名称映射到其相应信息或数据的记录对象。 * @param deviceMap - 将设备名称映射到其相应信息或数据的记录对象。
*/ */
export function runAllEnableRule(deviceMap:Record<string, any>){ export function runAllEnableRule(deviceMap: Record<string, any>) {
rules.forEach((item:any) => { rules.forEach((item: any) => {
if(item['enable'].toString() === 'true') { if (item['enable'].toString() === 'true') {
runRule(item, deviceMap) runRule(item, deviceMap)
} }
}) })
...@@ -82,8 +122,8 @@ export function runAllEnableRule(deviceMap:Record<string, any>){ ...@@ -82,8 +122,8 @@ export function runAllEnableRule(deviceMap:Record<string, any>){
* @param {string} id - “id”参数是一个字符串,表示规则的唯一标识符。它用于在“rules”数组中查找规则。 * @param {string} id - “id”参数是一个字符串,表示规则的唯一标识符。它用于在“rules”数组中查找规则。
* @param deviceMap - “deviceMap”参数是一个记录对象,它将设备名称映射到其相应的信息或状态。它用于提供运行规则所需的数据。 * @param deviceMap - “deviceMap”参数是一个记录对象,它将设备名称映射到其相应的信息或状态。它用于提供运行规则所需的数据。
*/ */
export function runRuleById(id:string, deviceMap:Record<string, any>){ export function runRuleById(id: string, deviceMap: Record<string, any>) {
let rule = rules.find((item:any) => item.id == id) let rule = rules.find((item: any) => item.id == id)
runRule(rule, deviceMap) runRule(rule, deviceMap)
} }
...@@ -91,17 +131,17 @@ export function runRuleById(id:string, deviceMap:Record<string, any>){ ...@@ -91,17 +131,17 @@ export function runRuleById(id:string, deviceMap:Record<string, any>){
* 函数“testRule”将规则对象作为输入,从规则中提取测试数据,从规则的函数字符串创建一个新函数,然后使用测试数据作为参数执行该函数。 * 函数“testRule”将规则对象作为输入,从规则中提取测试数据,从规则的函数字符串创建一个新函数,然后使用测试数据作为参数执行该函数。
* @param {any} rule - “rule”参数是包含有关特定规则的信息的对象。 * @param {any} rule - “rule”参数是包含有关特定规则的信息的对象。
*/ */
export function testRule(rule:any){ export function testRule(rule: any) {
let inputData = [] let inputData = []
let runFunc = null let runFunc = null
if (rule){ if (rule) {
for (let input of rule.inputs){ for (let input of rule.inputs) {
inputData.push(input['testData']) inputData.push(input['testData'])
} }
runFunc = new Function( "return " + rule.func) runFunc = new Function("return " + rule.func)
try { try {
runFunc()(...inputData) runFunc()(...inputData)
}catch (e){ } catch (e) {
alert(e) alert(e)
} }
} }
...@@ -111,7 +151,39 @@ export function testRule(rule:any){ ...@@ -111,7 +151,39 @@ export function testRule(rule:any){
* 函数“testRuleById”通过 ID 查找规则,然后测试该规则。 * 函数“testRuleById”通过 ID 查找规则,然后测试该规则。
* @param {string} id - “id”参数是一个字符串,表示规则的唯一标识符。 * @param {string} id - “id”参数是一个字符串,表示规则的唯一标识符。
*/ */
export function testRuleById(id:string){ export function testRuleById(id: string) {
let rule = rules.find((item:any) => item.id == id) let rule = rules.find((item: any) => item.id == id)
testRule(rule) testRule(rule)
} }
export function runJS(rule: any, inputData: any) {
const funcBody = "(data)=>{ "+ rule['func']+"}"
const runFunc = new Function("return " + funcBody)
try {
return runFunc()(inputData)
} catch (e) {
alert(e)
}
}
export function runLua(rule: any, inputData: any) {
try {
// 创建Lua状态
let codestring = `
return function (data)
${rule['func']}
end
`
let luaFunction = fengari.load(codestring)
let result = luaFunction().call(inputData);
return result
} catch (e) {
alert(e)
}
}
...@@ -3,4 +3,5 @@ declare module '*.vue' { ...@@ -3,4 +3,5 @@ declare module '*.vue' {
import { ComponentOptions } from 'vue' import { ComponentOptions } from 'vue'
const componentOptions: ComponentOptions const componentOptions: ComponentOptions
export default componentOptions export default componentOptions
} }
\ No newline at end of file declare module 'fengari-web';
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment