Commit e099bdc042d190ff5e3fc14fb2949b5b6e4089ac

Authored by ww
1 parent c174e0ab

fix: DEFECT-1339转换脚本新增messageType参数

@@ -8,6 +8,31 @@ export enum StatusEnum { @@ -8,6 +8,31 @@ export enum StatusEnum {
8 DISABLE = 0, 8 DISABLE = 0,
9 } 9 }
10 10
  11 +export enum ScriptMessageTypeEnum {
  12 + 'Post attributes' = 'POST_ATTRIBUTES',
  13 + 'Post telemetry' = 'POST_TELEMETRY',
  14 + 'RPC Request from Device' = 'RPC_REQUEST_FROM_DEVICE',
  15 + 'RPC Request to Device' = 'RPC_REQUEST_TO_DEVICE',
  16 + 'Activity Event' = 'ACTIVITY_EVENT',
  17 + 'Inactivity Event' = 'INACTIVITY_EVENT',
  18 + 'Connect Event' = 'CONNECT_EVENT',
  19 + 'Disconnect Event' = 'DISCONNECT_EVENT',
  20 + 'Entity Created' = 'ENTITY_CREATED',
  21 + 'Entity Updated' = 'ENTITY_UPDATED',
  22 + 'Entity Deleted' = 'ENTITY_DELETED',
  23 + 'Entity Assigned' = 'ENTITY_ASSIGNED',
  24 + 'Entity Unassigned' = 'ENTITY_UNASSIGNED',
  25 + 'Attributes Updated' = 'ATTRIBUTES_UPDATED',
  26 + 'Attributes Deleted' = 'ATTRIBUTES_DELETED',
  27 + 'Timeseries Updated' = 'TIMESERIES_UPDATED',
  28 + 'Timeseries Deleted' = 'TIMESERIES_DELETED',
  29 + 'RPC Queued' = 'RPC_QUEUED',
  30 + 'RPC Delivered' = 'RPC_DELIVERED',
  31 + 'RPC Successful' = 'RPC_SUCCESSFUL',
  32 + 'RPC Timeout' = 'RPC_TIMEOUT',
  33 + 'RPC Failed' = 'RPC_FAILED',
  34 +}
  35 +
11 export const columns: BasicColumn[] = [ 36 export const columns: BasicColumn[] = [
12 { 37 {
13 title: '名称', 38 title: '名称',
1 -<template>  
2 - <div>  
3 - <BasicDrawer  
4 - v-bind="$attrs"  
5 - :title="getTitle"  
6 - @register="register"  
7 - width="500px"  
8 - @ok="handleSubmit"  
9 - showFooter  
10 - >  
11 - <BasicForm @register="registerForm">  
12 - <template #function>  
13 - <Card title="转换函数" :bodyStyle="{ padding: 0, height: '280px' }">  
14 - <template #extra>  
15 - <Tag color="blue">Transform Function</Tag>  
16 - <a-button @click="handleFormat" size="small">格式化</a-button>  
17 - </template>  
18 - <div class="ml-8">function Transform(msg, metadata) {</div>  
19 - <div ref="aceRef" class="overflow-hidden"></div>  
20 - <div class="ml-7">}</div>  
21 - </Card>  
22 - <a-button type="primary" class="mt-4" @click="testTransformFunc">测试转换功能</a-button>  
23 - </template>  
24 - </BasicForm>  
25 - </BasicDrawer>  
26 - </div>  
27 -</template>  
28 -  
29 -<script lang="ts" setup>  
30 - import { ref, computed, unref } from 'vue';  
31 - import { useDrawerInner, BasicDrawer } from '/@/components/Drawer/index';  
32 - import { useForm, BasicForm } from '/@/components/Form/index';  
33 - import { formSchema } from '../config/config.data';  
34 - import { Card, Tag } from 'ant-design-vue';  
35 - import { createOrEditTransformScriptApi } from '/@/api/device/TransformScriptApi';  
36 - import { useMessage } from '/@/hooks/web/useMessage';  
37 - import ace from 'ace-builds';  
38 - import 'ace-builds/src-noconflict/theme-chrome'; // 默认设置的主题  
39 - import 'ace-builds/src-noconflict/theme-terminal'; // 默认设置的主题  
40 - import 'ace-builds/src-noconflict/mode-javascript'; // 默认设置的语言模式  
41 - import { beautify } from 'ace-builds/src-noconflict/ext-beautify.js';  
42 - import { useAppStore } from '/@/store/modules/app';  
43 -  
44 - const emit = defineEmits(['register', 'isStatus', 'success']);  
45 - const userStore = useAppStore();  
46 - const getAceClass = computed((): string => userStore.getDarkMode);  
47 - const isUpdate: any = ref(false);  
48 - const isView = ref(true);  
49 - const aceEditor = ref();  
50 - const aceRef = ref();  
51 - const getTitle = computed(() => (isUpdate.value ? '编辑转换脚本' : '新增转换脚本'));  
52 - const editId = ref('');  
53 - const [register, { setDrawerProps, closeDrawer }] = useDrawerInner((data) => {  
54 - resetFields();  
55 - setDrawerProps({ confirmLoading: false });  
56 - isUpdate.value = data.isUpdate;  
57 - initEditor(data.record?.configuration.jsScript);  
58 - switch (isUpdate.value) {  
59 - case 'view':  
60 - isView.value = false;  
61 - setDrawerProps({  
62 - showFooter: unref(isView),  
63 - title: '查看转换脚本',  
64 - loading: false,  
65 - });  
66 - editId.value = data.record.id;  
67 - setFieldsValue(data.record);  
68 - break;  
69 - case true:  
70 - isView.value = true;  
71 - setDrawerProps({  
72 - showFooter: unref(isView),  
73 - title: '编辑转换脚本',  
74 - loading: false,  
75 - });  
76 - editId.value = data.record.id;  
77 - setFieldsValue(data.record);  
78 - break;  
79 - case false:  
80 - isView.value = true;  
81 - setDrawerProps({  
82 - showFooter: unref(isView),  
83 - title: '新增转换脚本',  
84 - loading: false,  
85 - });  
86 - break;  
87 - }  
88 - });  
89 - const [registerForm, { validate, setFieldsValue, resetFields }] = useForm({  
90 - showActionButtonGroup: false,  
91 - colProps: { span: 24 },  
92 - schemas: formSchema,  
93 - });  
94 -  
95 - // 初始化编辑器  
96 - const initEditor = (jsScript?: string) => {  
97 - aceEditor.value = ace.edit(aceRef.value, {  
98 - maxLines: 12, // 最大行数,超过会自动出现滚动条  
99 - minLines: 12, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小  
100 - fontSize: 14, // 编辑器内字体大小  
101 - theme: 'ace/theme/chrome', // 默认设置的主题  
102 - mode: 'ace/mode/javascript', // 默认设置的语言模式  
103 - tabSize: 2, // 制表符设置为 4 个空格大小  
104 - });  
105 -  
106 - aceEditor.value.setOptions({  
107 - enableBasicAutocompletion: true,  
108 - enableLiveAutocompletion: true,  
109 - theme: getAceClass.value === 'dark' ? 'ace/theme/terminal' : 'ace/theme/chrome',  
110 - });  
111 - aceEditor.value.setValue(jsScript ?? 'return {msg: msg, metadata: metadata};');  
112 - beautify(aceEditor.value.session);  
113 - };  
114 -  
115 - const testTransformFunc = () => {  
116 - closeDrawer();  
117 - const jsCode = aceEditor.value.getValue();  
118 - emit('isStatus', { status: 1, jsCode });  
119 - };  
120 - const handleSubmit = async () => {  
121 - const editIdPost = isUpdate.value ? { id: editId.value } : {};  
122 - try {  
123 - setDrawerProps({ confirmLoading: true });  
124 - const fieldsValue = await validate();  
125 - if (!fieldsValue) return;  
126 - await createOrEditTransformScriptApi({  
127 - configuration: {  
128 - jsScript: aceEditor.value.getValue(),  
129 - },  
130 - type: 'org.thingsboard.rule.engine.transform.TbTransformMsgNode',  
131 - ...fieldsValue,  
132 - ...editIdPost,  
133 - });  
134 - closeDrawer();  
135 - emit('success');  
136 - const { createMessage } = useMessage();  
137 - createMessage.success('保存成功');  
138 - } catch (e) {  
139 - } finally {  
140 - setTimeout(() => {  
141 - setDrawerProps({ confirmLoading: false });  
142 - }, 300);  
143 - }  
144 - };  
145 - const handleFormat = () => {  
146 - beautify(aceEditor.value.session);  
147 - };  
148 - defineExpose({ aceEditor });  
149 -</script> 1 +<template>
  2 + <div>
  3 + <BasicDrawer
  4 + v-bind="$attrs"
  5 + :title="getTitle"
  6 + @register="register"
  7 + width="500px"
  8 + @ok="handleSubmit"
  9 + showFooter
  10 + >
  11 + <BasicForm @register="registerForm">
  12 + <template #function>
  13 + <Card title="转换函数" :bodyStyle="{ padding: 0, height: '280px' }">
  14 + <template #extra>
  15 + <Tag color="blue">Transform Function</Tag>
  16 + <a-button @click="handleFormat" size="small">格式化</a-button>
  17 + </template>
  18 + <div class="ml-8">function Transform(msg, metadata, msgType) {</div>
  19 + <div ref="aceRef" class="overflow-hidden"></div>
  20 + <div class="ml-7">}</div>
  21 + </Card>
  22 + <a-button type="primary" class="mt-4" @click="testTransformFunc">测试转换功能</a-button>
  23 + </template>
  24 + </BasicForm>
  25 + </BasicDrawer>
  26 + </div>
  27 +</template>
  28 +
  29 +<script lang="ts" setup>
  30 + import { ref, computed, unref } from 'vue';
  31 + import { useDrawerInner, BasicDrawer } from '/@/components/Drawer/index';
  32 + import { useForm, BasicForm } from '/@/components/Form/index';
  33 + import { formSchema } from '../config/config.data';
  34 + import { Card, Tag } from 'ant-design-vue';
  35 + import { createOrEditTransformScriptApi } from '/@/api/device/TransformScriptApi';
  36 + import { useMessage } from '/@/hooks/web/useMessage';
  37 + import ace from 'ace-builds';
  38 + import 'ace-builds/src-noconflict/theme-chrome'; // 默认设置的主题
  39 + import 'ace-builds/src-noconflict/theme-terminal'; // 默认设置的主题
  40 + import 'ace-builds/src-noconflict/mode-javascript'; // 默认设置的语言模式
  41 + import { beautify } from 'ace-builds/src-noconflict/ext-beautify.js';
  42 + import { useAppStore } from '/@/store/modules/app';
  43 +
  44 + const emit = defineEmits(['register', 'isStatus', 'success']);
  45 + const userStore = useAppStore();
  46 + const getAceClass = computed((): string => userStore.getDarkMode);
  47 + const isUpdate: any = ref(false);
  48 + const isView = ref(true);
  49 + const aceEditor = ref();
  50 + const aceRef = ref();
  51 + const getTitle = computed(() => (isUpdate.value ? '编辑转换脚本' : '新增转换脚本'));
  52 + const editId = ref('');
  53 + const [register, { setDrawerProps, closeDrawer }] = useDrawerInner((data) => {
  54 + resetFields();
  55 + setDrawerProps({ confirmLoading: false });
  56 + isUpdate.value = data.isUpdate;
  57 + initEditor(data.record?.configuration.jsScript);
  58 + switch (isUpdate.value) {
  59 + case 'view':
  60 + isView.value = false;
  61 + setDrawerProps({
  62 + showFooter: unref(isView),
  63 + title: '查看转换脚本',
  64 + loading: false,
  65 + });
  66 + editId.value = data.record.id;
  67 + setFieldsValue(data.record);
  68 + break;
  69 + case true:
  70 + isView.value = true;
  71 + setDrawerProps({
  72 + showFooter: unref(isView),
  73 + title: '编辑转换脚本',
  74 + loading: false,
  75 + });
  76 + editId.value = data.record.id;
  77 + setFieldsValue(data.record);
  78 + break;
  79 + case false:
  80 + isView.value = true;
  81 + setDrawerProps({
  82 + showFooter: unref(isView),
  83 + title: '新增转换脚本',
  84 + loading: false,
  85 + });
  86 + break;
  87 + }
  88 + });
  89 + const [registerForm, { validate, setFieldsValue, resetFields }] = useForm({
  90 + showActionButtonGroup: false,
  91 + colProps: { span: 24 },
  92 + schemas: formSchema,
  93 + });
  94 +
  95 + // 初始化编辑器
  96 + const initEditor = (jsScript?: string) => {
  97 + aceEditor.value = ace.edit(aceRef.value, {
  98 + maxLines: 12, // 最大行数,超过会自动出现滚动条
  99 + minLines: 12, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
  100 + fontSize: 14, // 编辑器内字体大小
  101 + theme: 'ace/theme/chrome', // 默认设置的主题
  102 + mode: 'ace/mode/javascript', // 默认设置的语言模式
  103 + tabSize: 2, // 制表符设置为 4 个空格大小
  104 + });
  105 +
  106 + aceEditor.value.setOptions({
  107 + enableBasicAutocompletion: true,
  108 + enableLiveAutocompletion: true,
  109 + theme: getAceClass.value === 'dark' ? 'ace/theme/terminal' : 'ace/theme/chrome',
  110 + });
  111 + aceEditor.value.setValue(
  112 + jsScript ?? 'return {msg: msg, metadata: metadata, msgType: msgType};'
  113 + );
  114 + beautify(aceEditor.value.session);
  115 + };
  116 +
  117 + const testTransformFunc = () => {
  118 + closeDrawer();
  119 + const jsCode = aceEditor.value.getValue();
  120 + emit('isStatus', { status: 1, jsCode });
  121 + };
  122 + const handleSubmit = async () => {
  123 + const editIdPost = isUpdate.value ? { id: editId.value } : {};
  124 + try {
  125 + setDrawerProps({ confirmLoading: true });
  126 + const fieldsValue = await validate();
  127 + if (!fieldsValue) return;
  128 + await createOrEditTransformScriptApi({
  129 + configuration: {
  130 + jsScript: aceEditor.value.getValue(),
  131 + },
  132 + type: 'org.thingsboard.rule.engine.transform.TbTransformMsgNode',
  133 + ...fieldsValue,
  134 + ...editIdPost,
  135 + });
  136 + closeDrawer();
  137 + emit('success');
  138 + const { createMessage } = useMessage();
  139 + createMessage.success('保存成功');
  140 + } catch (e) {
  141 + } finally {
  142 + setTimeout(() => {
  143 + setDrawerProps({ confirmLoading: false });
  144 + }, 300);
  145 + }
  146 + };
  147 + const handleFormat = () => {
  148 + beautify(aceEditor.value.session);
  149 + };
  150 + defineExpose({ aceEditor });
  151 +</script>
@@ -4,11 +4,25 @@ @@ -4,11 +4,25 @@
4 <div class="h-full flex p-4"> 4 <div class="h-full flex p-4">
5 <div class="flex flex-col w-1/2"> 5 <div class="flex flex-col w-1/2">
6 <div class="flex-1 mr-4 mb-4"> 6 <div class="flex-1 mr-4 mb-4">
7 - <Card title="消息" :bodyStyle="cardStyle"> 7 + <Card :bodyStyle="cardStyle">
  8 + <template #title>
  9 + <div class="w-3/4 flex">
  10 + <span class="mr-2">消息类型</span>
  11 + <Select
  12 + v-model:value="messageType"
  13 + class="flex-1 mr-2"
  14 + :options="getScriptMessageTypeOptions"
  15 + placeholder="请选择消息类型"
  16 + />
  17 + </div>
  18 + <div>消息</div>
  19 + </template>
8 <template #extra> 20 <template #extra>
9 - <Tag color="blue">Message</Tag>  
10 - <a-button @click="handleFormatJson" size="small">格式化</a-button>  
11 - <a-button @click="handleMiniJson" size="small" class="ml-2">收起</a-button> 21 + <div>
  22 + <Tag color="blue">Message</Tag>
  23 + <a-button @click="handleFormatJson" size="small">格式化</a-button>
  24 + <a-button @click="handleMiniJson" size="small" class="ml-2">收起</a-button>
  25 + </div>
12 </template> 26 </template>
13 <div ref="jsoneditorRef" style="height: 100%"></div> 27 <div ref="jsoneditorRef" style="height: 100%"></div>
14 </Card> 28 </Card>
@@ -23,7 +37,7 @@ @@ -23,7 +37,7 @@
23 <QuestionCircleOutlined class="ml-2" style="font-size: 1rem" /> 37 <QuestionCircleOutlined class="ml-2" style="font-size: 1rem" />
24 </Tooltip> 38 </Tooltip>
25 </template> 39 </template>
26 - <div class="ml-8">function Transform(msg, metadata) {</div> 40 + <div class="ml-8">function Transform(msg, metadata, msgType) {</div>
27 <div ref="aceRef" style="height: calc(100% - 44px)"></div> 41 <div ref="aceRef" style="height: calc(100% - 44px)"></div>
28 <div class="ml-7">}</div> 42 <div class="ml-7">}</div>
29 </Card> 43 </Card>
@@ -69,24 +83,27 @@ @@ -69,24 +83,27 @@
69 centered 83 centered
70 v-bind="$attrs" 84 v-bind="$attrs"
71 > 85 >
72 - <h2> function Transform(msg,metadata): {msg: object, metadata: object} </h2> 86 + <h2> function Transform(msg,metadata): {msg: object, metadata: object, msgType: string} </h2>
73 <li> 将输入消息、元数据转换为输出消息的 JavaScript 函数 </li> 87 <li> 将输入消息、元数据转换为输出消息的 JavaScript 函数 </li>
74 <h2>参数:</h2> 88 <h2>参数:</h2>
75 <ul> 89 <ul>
76 <li>msg: {[key: string]: any} - 是消息有效负载键/值对象。</li> 90 <li>msg: {[key: string]: any} - 是消息有效负载键/值对象。</li>
77 - <li>metadata: {[key: string]: string} - 是消息元数据键/值映射,其中键和值都是字符串。</li> 91 + <li>metadata: {[key: string]: string} - 是消息元数据键/值映射, 其中键和值都是字符串。</li>
  92 + <li>msgType: string - 是包含消息类型的字符串。有关常用值, 请参见MessageType enum。</li>
78 </ul> 93 </ul>
79 <h2>返回值:</h2> 94 <h2>返回值:</h2>
80 <ul> 95 <ul>
81 - <li> { msg?: {[key: string]: any}, metadata?: {[key: string]: string} } </li> 96 + <li>
  97 + { msg?: {[key: string]: any}, metadata?: {[key: string]: string}, msgType?: string }
  98 + </li>
82 <li> 结果对象中的所有字段都是可选的,如果未指定,将从原始消息中获取。 </li> 99 <li> 结果对象中的所有字段都是可选的,如果未指定,将从原始消息中获取。 </li>
83 </ul> 100 </ul>
84 </BasicModal> 101 </BasicModal>
85 </div> 102 </div>
86 </template> 103 </template>
87 <script lang="ts" setup> 104 <script lang="ts" setup>
88 - import { ref, onMounted, defineComponent } from 'vue';  
89 - import { Card, Tag, Tooltip } from 'ant-design-vue'; 105 + import { ref, onMounted, defineComponent, computed, unref } from 'vue';
  106 + import { Card, Tag, Tooltip, Select } from 'ant-design-vue';
90 import { PageWrapper } from '/@/components/Page'; 107 import { PageWrapper } from '/@/components/Page';
91 import { Description, DescItem, useDescription } from '/@/components/Description/index'; 108 import { Description, DescItem, useDescription } from '/@/components/Description/index';
92 import { useMessage } from '/@/hooks/web/useMessage'; 109 import { useMessage } from '/@/hooks/web/useMessage';
@@ -100,6 +117,7 @@ @@ -100,6 +117,7 @@
100 import 'ace-builds/src-noconflict/mode-javascript'; // 默认设置的语言模式 117 import 'ace-builds/src-noconflict/mode-javascript'; // 默认设置的语言模式
101 import 'ace-builds/src-noconflict/ext-language_tools.js'; //语言提示 118 import 'ace-builds/src-noconflict/ext-language_tools.js'; //语言提示
102 import { beautify } from 'ace-builds/src-noconflict/ext-beautify.js'; //格式化 119 import { beautify } from 'ace-builds/src-noconflict/ext-beautify.js'; //格式化
  120 + import { ScriptMessageTypeEnum } from '../config/config.data';
103 // !!!important 重要,配置ace编辑器的错误提示,基础路径。否则会加载不到相关web Worker,就没有syntax validation提示 121 // !!!important 重要,配置ace编辑器的错误提示,基础路径。否则会加载不到相关web Worker,就没有syntax validation提示
104 ace.config.set('basePath', 'https://cdn.jsdelivr.net/npm/ace-builds@1.4.14/src-noconflict/'); 122 ace.config.set('basePath', 'https://cdn.jsdelivr.net/npm/ace-builds@1.4.14/src-noconflict/');
105 defineComponent({ 123 defineComponent({
@@ -120,6 +138,15 @@ @@ -120,6 +138,15 @@
120 const aceEditor = ref(); 138 const aceEditor = ref();
121 const aceRef = ref(); 139 const aceRef = ref();
122 const emit = defineEmits(['isStatus']); 140 const emit = defineEmits(['isStatus']);
  141 +
  142 + const messageType = ref(ScriptMessageTypeEnum['Post telemetry']);
  143 + const getScriptMessageTypeOptions = computed(() =>
  144 + Object.keys(ScriptMessageTypeEnum).map((item) => ({
  145 + label: item,
  146 + value: ScriptMessageTypeEnum[item],
  147 + }))
  148 + );
  149 +
123 function initEditor() { 150 function initEditor() {
124 let options = { 151 let options = {
125 mode: 'code', 152 mode: 'code',
@@ -200,7 +227,12 @@ @@ -200,7 +227,12 @@
200 const metadata = mataData; 227 const metadata = mataData;
201 const jsCode = aceEditor.value.getValue(); 228 const jsCode = aceEditor.value.getValue();
202 // 执行动态Javascript脚本 229 // 执行动态Javascript脚本
203 - let result = Function('msg', 'metadata', jsCode)(msg, metadata); 230 + let result = Function(
  231 + 'msg',
  232 + 'metadata',
  233 + 'msgType',
  234 + jsCode
  235 + )(msg, metadata, unref(messageType));
204 // 设置输出值 236 // 设置输出值
205 outputEditor.value.set(result); 237 outputEditor.value.set(result);
206 } catch (e) { 238 } catch (e) {