Commit cea7fdf23a38e81c2e96acf3f188d1d7f4e70e35

Authored by xp.Huang
1 parent 7ddce7c2

Merge branch 'ft' into 'main_dev'

fix: 修复Teambition上的问题

See merge request yunteng/thingskit-front!533

(cherry picked from commit 6fee6dcc13983532958543c85383139aad19fdce)

c62f9e54 pref:优化测试接口表格,只有一项时,清除对应项
85cc1230 fix:DEFECT-1122 分页接口测试错误提示,修复post传参问题
e2c049f2 fix:DEFECT-1112 提示输入参数值 表格选择是否必须为是,则对应测试接口参数若为空则增加提示
f8d25bcd fix:DEFECT-1112 提示输入参数值 表格选择是否必须为是,则对应测试接口参数若为空则增加提示
eaaa19ee pref:调整脚本管理 转换函数
dda4b267 fix:DEFECT-1078 修复暗黑模式场景联动白框问题
b8876e1a fix:DEFECT-1079 修复暗黑模式转换脚本白框问题
1 1 <template>
2   - <div :class="prefixCls">
  2 + <div
  3 + :class="prefixCls"
  4 + :style="{ backgroundColor: modeSwitch === 'dark' ? '#1f1f1f' : 'rgb(242, 242, 242)' }"
  5 + >
3 6 <CollapseHeader
4 7 v-bind="$props"
5 8 :prefixCls="prefixCls"
... ... @@ -29,7 +32,7 @@
29 32 </template>
30 33 <script lang="ts" setup>
31 34 import type { PropType } from 'vue';
32   - import { ref } from 'vue';
  35 + import { ref, computed } from 'vue';
33 36 // component
34 37 import { Skeleton } from 'ant-design-vue';
35 38 import { CollapseTransition } from '/@/components/Transition';
... ... @@ -38,6 +41,7 @@
38 41 // hook
39 42 import { useTimeoutFn } from '/@/hooks/core/useTimeout';
40 43 import { useDesign } from '/@/hooks/web/useDesign';
  44 + import { useAppStore } from '/@/store/modules/app';
41 45
42 46 const props = defineProps({
43 47 isClose: { type: Boolean, default: true },
... ... @@ -64,6 +68,11 @@
64 68 */
65 69 lazyTime: { type: Number, default: 0 },
66 70 });
  71 +
  72 + const userStore = useAppStore();
  73 +
  74 + const modeSwitch = computed((): string => userStore.getDarkMode);
  75 +
67 76 const emit = defineEmits(['expand', 'change', 'hchange']);
68 77
69 78 const show = ref(true);
... ... @@ -92,7 +101,7 @@
92 101 @prefix-cls: ~'@{namespace}-collapse-container';
93 102
94 103 .@{prefix-cls} {
95   - background-color: @component-background;
  104 + // background-color: @component-background;
96 105 border-radius: 2px;
97 106 transition: all 0.3s ease-in-out;
98 107
... ...
... ... @@ -18,6 +18,7 @@
18 18 placeholder="请选择"
19 19 :options="selectOptions"
20 20 @change="handleChange"
  21 + @dropdownVisibleChange="hanldeDropdownVisibleChange"
21 22 allowClear
22 23 />
23 24 </td>
... ... @@ -111,16 +112,20 @@
111 112
112 113 // 减少
113 114 const remove = (item, index: number) => {
114   - if (tableArray.content.length !== 1) {
  115 + if (tableArray.content.length > 1) {
115 116 selectOptions.value.forEach((ele) => {
116 117 if (ele.value == item.key) {
117 118 ele.disabled = false;
118 119 }
119 120 });
120 121 tableArray.content.splice(index, 1);
  122 + } else {
  123 + resetValue();
121 124 }
122 125 };
123 126
  127 + const hanldeDropdownVisibleChange = () => handleChange();
  128 +
124 129 //Select互斥
125 130 const handleChange = () => {
126 131 selectOptions.value.forEach((ele) => {
... ... @@ -132,7 +137,7 @@
132 137 element.value = '';
133 138 element.editDisabled = true;
134 139 }
135   - if (element.key === ele.value && element.key !== 'scope' && element.key !== 'fixed_date') {
  140 + if (element.key === ele.value && element.key !== 'scope') {
136 141 ele.disabled = true;
137 142 }
138 143 });
... ...
... ... @@ -18,6 +18,7 @@
18 18 placeholder="请选择"
19 19 :options="selectOptions"
20 20 @change="handleChange"
  21 + @dropdownVisibleChange="hanldeDropdownVisibleChange"
21 22 allowClear
22 23 />
23 24 </td>
... ... @@ -111,13 +112,15 @@
111 112
112 113 // 减少
113 114 const remove = (item, index: number) => {
114   - if (tableArray.content.length !== 1) {
  115 + if (tableArray.content.length > 1) {
115 116 selectOptions.value.forEach((ele) => {
116 117 if (ele.value == item.key) {
117 118 ele.disabled = false;
118 119 }
119 120 });
120 121 tableArray.content.splice(index, 1);
  122 + } else {
  123 + resetValue();
121 124 }
122 125 };
123 126
... ... @@ -132,13 +135,15 @@
132 135 element.value = '';
133 136 element.editDisabled = true;
134 137 }
135   - if (element.key === ele.value && element.key !== 'scope' && element.key !== 'fixed_date') {
  138 + if (element.key === ele.value && element.key !== 'scope') {
136 139 ele.disabled = true;
137 140 }
138 141 });
139 142 });
140 143 };
141 144
  145 + const hanldeDropdownVisibleChange = () => handleChange();
  146 +
142 147 //获取数据
143 148 const getValue = () => {
144 149 const assemblyData = tableArray.content.map((it) => {
... ...
... ... @@ -31,6 +31,7 @@
31 31 import moment from 'moment';
32 32 import { useUtils } from '../../../hooks/useUtils';
33 33 import JsonEditor from '../../SimpleRequest/components/jsonEditor.vue';
  34 + import { useMessage } from '/@/hooks/web/useMessage';
34 35
35 36 const emits = defineEmits(['testBodyInterface']);
36 37
... ... @@ -40,6 +41,8 @@
40 41 },
41 42 });
42 43
  44 + const { createMessage } = useMessage();
  45 +
43 46 const showTestEditCell = ref(false);
44 47
45 48 const excuteData = ref({});
... ... @@ -63,13 +66,12 @@
63 66 const getValue = async () => {
64 67 await nextTick();
65 68 await nextTick(() => {
66   - console.log(props.data?.list);
67 69 if (props.data?.type === 'x-www-form-urlencoded' || props.data?.type === 'form-data') {
68 70 const getSingleKey = props.data?.list;
69   - const getMuteKey = props.data?.list?.filter((it: any) => it.key.split(',').length > 1);
  71 + const getMuteKey = props.data?.list?.filter((it: any) => it.key?.split(',').length > 1);
70 72 const getMuteKeys = getMultipleKeys(getMuteKey);
71 73 const mergeKeys = [...getSingleKey, ...getMuteKeys]?.filter(
72   - (it: any) => it.key.split(',').length === 1
  74 + (it: any) => it.key?.split(',').length === 1
73 75 );
74 76 testEditCellTableRef.value?.setTableArray(mergeKeys);
75 77 } else if (props.data?.type === 'json') {
... ... @@ -111,6 +113,7 @@
111 113 return {
112 114 key,
113 115 value,
  116 + required: it.required,
114 117 };
115 118 });
116 119 };
... ... @@ -120,6 +123,11 @@
120 123 let params: any = {};
121 124 if (props.data?.type === 'x-www-form-urlencoded' || props.data?.type === 'form-data') {
122 125 const getTable = getTestTableKeyValue();
  126 + const hasRequired = getTable?.some((it) => it.required === true && !it.value);
  127 + if (hasRequired) {
  128 + createMessage.error('选择项为必须的,参数不能为空');
  129 + throw new Error('选择项为必须的,参数不能为空');
  130 + }
123 131 getTable?.map((it) => (params[it.key!] = it.value!));
124 132 } else if (props.data?.type === 'json') {
125 133 params = jsonEditorRef.value?.getJsonValue();
... ...
... ... @@ -228,6 +228,7 @@
228 228 };
229 229
230 230 const getAttributeOptions = async (params) => {
  231 + console.log(params);
231 232 const res = await getDeviceAttributes(params);
232 233 if (Object.keys(res).length === 0) return (attributeOptions.value.length = 0);
233 234 attributeOptions.value = res?.map((item) => ({ label: item.name, value: item.identifier }));
... ... @@ -243,7 +244,9 @@
243 244 if (f.key === 'organizationId') organizationId = f.value;
244 245 if (f.key === 'entityId') f.value = null;
245 246 });
246   - getAttributeOptions({ deviceProfileId: e.value });
  247 + if (e.value) {
  248 + getAttributeOptions({ deviceProfileId: e.value });
  249 + }
247 250 if (organizationId !== '') {
248 251 getEntityOptions(organizationId, e.value);
249 252 }
... ... @@ -261,6 +264,9 @@
261 264 </script>
262 265
263 266 <style scoped lang="less">
  267 + :deep(.ant-select-selector) {
  268 + max-width: 16vw;
  269 + }
264 270 @table-color: #e5e7eb;
265 271
266 272 .table-border-color {
... ...
... ... @@ -36,7 +36,7 @@
36 36 import { JWT_TOKEN_KEY } from '/@/enums/cacheEnum';
37 37 import { getAuthCache } from '/@/utils/auth';
38 38 import { useMessage } from '/@/hooks/web/useMessage';
39   - // import { useGlobSetting } from '/@/hooks/setting';
  39 + import { useUtils } from '../../../hooks/useUtils';
40 40
41 41 const emits = defineEmits(['emitExcute']);
42 42
... ... @@ -56,8 +56,6 @@
56 56
57 57 const socketUrls = ref('');
58 58
59   - // const { socketUrl } = useGlobSetting();
60   -
61 59 const socketMessage: any = reactive({
62 60 server: ``,
63 61 sendValue: {
... ... @@ -152,7 +150,7 @@
152 150 apiUrl,
153 151 headers = {},
154 152 params = {},
155   - body,
  153 + body = {},
156 154 joinPrefix = false
157 155 ) => {
158 156 switch (apiType) {
... ... @@ -165,8 +163,9 @@
165 163 }
166 164 );
167 165 case 'POST':
  166 + const { convertObj } = useUtils();
168 167 return await otherHttp.post(
169   - { url: apiUrl, data: body, headers, params },
  168 + { url: `${apiUrl}?${convertObj(params)}`, data: body, headers },
170 169 {
171 170 apiUrl: '',
172 171 joinPrefix,
... ...
... ... @@ -20,6 +20,7 @@
20 20 import { ref, nextTick } from 'vue';
21 21 import { Button } from 'ant-design-vue';
22 22 import TestHeaderEditCellTable from './testEditHeaderCellTable.vue';
  23 + import { useMessage } from '/@/hooks/web/useMessage';
23 24
24 25 const emits = defineEmits(['testHeaderInterface']);
25 26
... ... @@ -29,6 +30,8 @@
29 30 },
30 31 });
31 32
  33 + const { createMessage } = useMessage();
  34 +
32 35 const showTestEditCell = ref(false);
33 36
34 37 const excuteData = ref({});
... ... @@ -59,6 +62,11 @@
59 62 //获取数据
60 63 const getTestValue = () => {
61 64 const getTable = getTestTableKeyValue();
  65 + const hasRequired = getTable?.some((it) => it.required === true && !it.value);
  66 + if (hasRequired) {
  67 + createMessage.error('选择项为必须的,参数不能为空');
  68 + throw new Error('选择项为必须的,参数不能为空');
  69 + }
62 70 const params: any = {};
63 71 getTable?.map((it: any) => (params[it.key!] = it.value!));
64 72 excuteData.value = {
... ...
... ... @@ -22,6 +22,7 @@
22 22 import TestParamsCellTable from './testEditParamsCellTable.vue';
23 23 import moment from 'moment';
24 24 import { useUtils } from '../../../hooks/useUtils';
  25 + import { useMessage } from '/@/hooks/web/useMessage';
25 26
26 27 const emits = defineEmits(['testParamsInterface']);
27 28
... ... @@ -31,6 +32,8 @@
31 32 },
32 33 });
33 34
  35 + const { createMessage } = useMessage();
  36 +
34 37 const showTestEditCell = ref(false);
35 38
36 39 const excuteData = ref({});
... ... @@ -92,6 +95,7 @@
92 95 return {
93 96 key,
94 97 value,
  98 + required: it.required,
95 99 };
96 100 });
97 101 };
... ... @@ -99,6 +103,11 @@
99 103 //获取数据
100 104 const getTestValue = () => {
101 105 const getTable = getTestTableKeyValue();
  106 + const hasRequired = getTable?.some((it) => it.required === true && !it.value);
  107 + if (hasRequired) {
  108 + createMessage.error('选择项为必须的,参数不能为空');
  109 + throw new Error('选择项为必须的,参数不能为空');
  110 + }
102 111 const params: any = {};
103 112 getTable?.map((it) => (params[it.key!] = it.value!));
104 113 if (params['keys']) {
... ...
... ... @@ -235,7 +235,9 @@
235 235 if (f.key === 'organizationId') organizationId = f.value;
236 236 if (f.key === 'entityId') f.value = null;
237 237 });
238   - getAttributeOptions({ deviceProfileId: e.value });
  238 + if (e.value) {
  239 + getAttributeOptions({ deviceProfileId: e.value });
  240 + }
239 241 if (organizationId !== '') {
240 242 getEntityOptions(organizationId, e.value);
241 243 }
... ...
... ... @@ -5,9 +5,14 @@ export const useUtils = () => {
5 5 list?.forEach((it) => {
6 6 const keys = it.key.split(',');
7 7 const temp = keys.map((item) => {
8   - const obj: { key: string; value: string } = { key: '', value: '' };
  8 + const obj: { key: string; value: string; required: boolean } = {
  9 + key: '',
  10 + value: '',
  11 + required: false,
  12 + };
9 13 obj.key = item;
10 14 obj.value = item === 'scope' ? it.value : '';
  15 + obj.required = it.required;
11 16 return obj;
12 17 });
13 18 temps = temp;
... ... @@ -36,5 +41,20 @@ export const useUtils = () => {
36 41 type: '0',
37 42 },
38 43 };
39   - return { getMultipleKeys, pushObj, resetReqHttpType, resetUpdateSchema };
  44 + //对象转get params参数
  45 + const convertObj = (data: object) => {
  46 + const _result: any = [];
  47 + for (const key in data) {
  48 + const value = data[key];
  49 + if (value.constructor == Array) {
  50 + value.forEach(function (_value) {
  51 + _result.push(key + '=' + _value);
  52 + });
  53 + } else {
  54 + _result.push(key + '=' + value);
  55 + }
  56 + }
  57 + return _result.join('&');
  58 + };
  59 + return { getMultipleKeys, pushObj, resetReqHttpType, resetUpdateSchema, convertObj };
40 60 };
... ...
1 1 <template>
2 2 <div>
3   - <CollapseContainer style="background-color: #f2f2f2" :title="`${title} ${index + 1}`">
  3 + <CollapseContainer :title="`${title} ${index + 1}`">
4 4 <template #action>
5 5 <div class="flex">
6 6 <div class="flex">
... ...
1 1 <template>
2   - <CollapseContainer style="background-color: #f2f2f2" :title="`执行动作 ${actionIndex + 1}`">
  2 + <CollapseContainer :title="`执行动作 ${actionIndex + 1}`">
3 3 <template #action>
4 4 <Tooltip title="移除" v-if="actionData.length > 1">
5 5 <Icon
... ...
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/mode-javascript'; // 默认设置的语言模式
40   - import { beautify } from 'ace-builds/src-noconflict/ext-beautify.js';
41   -
42   - const emit = defineEmits(['register', 'isStatus', 'success']);
43   - const isUpdate: any = ref(false);
44   - const isView = ref(true);
45   - const aceEditor = ref();
46   - const aceRef = ref();
47   - const getTitle = computed(() => (isUpdate.value ? '编辑转换脚本' : '新增转换脚本'));
48   - const editId = ref('');
49   - const [register, { setDrawerProps, closeDrawer }] = useDrawerInner((data) => {
50   - resetFields();
51   - setDrawerProps({ confirmLoading: false });
52   - isUpdate.value = data.isUpdate;
53   - initEditor(data.record?.configuration.jsScript);
54   - switch (isUpdate.value) {
55   - case 'view':
56   - isView.value = false;
57   - setDrawerProps({
58   - showFooter: unref(isView),
59   - title: '查看转换脚本',
60   - loading: false,
61   - });
62   - editId.value = data.record.id;
63   - setFieldsValue(data.record);
64   - break;
65   - case true:
66   - isView.value = true;
67   - setDrawerProps({
68   - showFooter: unref(isView),
69   - title: '编辑转换脚本',
70   - loading: false,
71   - });
72   - editId.value = data.record.id;
73   - setFieldsValue(data.record);
74   - break;
75   - case false:
76   - isView.value = true;
77   - setDrawerProps({
78   - showFooter: unref(isView),
79   - title: '新增转换脚本',
80   - loading: false,
81   - });
82   - break;
83   - }
84   - });
85   - const [registerForm, { validate, setFieldsValue, resetFields }] = useForm({
86   - showActionButtonGroup: false,
87   - colProps: { span: 24 },
88   - schemas: formSchema,
89   - });
90   -
91   - // 初始化编辑器
92   - const initEditor = (jsScript?: string) => {
93   - aceEditor.value = ace.edit(aceRef.value, {
94   - maxLines: 12, // 最大行数,超过会自动出现滚动条
95   - minLines: 12, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
96   - fontSize: 14, // 编辑器内字体大小
97   - theme: 'ace/theme/chrome', // 默认设置的主题
98   - mode: 'ace/mode/javascript', // 默认设置的语言模式
99   - tabSize: 2, // 制表符设置为 4 个空格大小
100   - });
101   -
102   - aceEditor.value.setOptions({
103   - enableBasicAutocompletion: true,
104   - enableLiveAutocompletion: true,
105   - });
106   - aceEditor.value.setValue(jsScript ?? 'return {msg: msg, metadata: metadata};');
107   - beautify(aceEditor.value.session);
108   - };
109   -
110   - const testTransformFunc = () => {
111   - closeDrawer();
112   - const jsCode = aceEditor.value.getValue();
113   - emit('isStatus', { status: 1, jsCode });
114   - };
115   - const handleSubmit = async () => {
116   - const editIdPost = isUpdate.value ? { id: editId.value } : {};
117   - try {
118   - setDrawerProps({ confirmLoading: true });
119   - const fieldsValue = await validate();
120   - if (!fieldsValue) return;
121   - await createOrEditTransformScriptApi({
122   - configuration: {
123   - jsScript: aceEditor.value.getValue(),
124   - },
125   - type: 'org.thingsboard.rule.engine.transform.TbTransformMsgNode',
126   - ...fieldsValue,
127   - ...editIdPost,
128   - });
129   - closeDrawer();
130   - emit('success');
131   - const { createMessage } = useMessage();
132   - createMessage.success('保存成功');
133   - } catch (e) {
134   - } finally {
135   - setTimeout(() => {
136   - setDrawerProps({ confirmLoading: false });
137   - }, 300);
138   - }
139   - };
140   - const handleFormat = () => {
141   - beautify(aceEditor.value.session);
142   - };
143   - defineExpose({ aceEditor });
144   -</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) {</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   - <a-form
4   - ref="formRef"
5   - :model="scriptForm"
6   - name="basic"
7   - :label-col="{ span: 4 }"
8   - :wrapper-col="{ span: 16 }"
9   - autocomplete="off"
10   - >
11   - <a-form-item
12   - :label="ifAdd ? '名称' : '输入参数(params)'"
13   - :name="ifAdd ? 'name' : 'params'"
14   - :rules="[{ required: true, message: ifAdd ? '请输入脚本名称' : '请输入参数' }]"
15   - >
16   - <a-input
17   - v-if="ifAdd"
18   - :maxlength="36"
19   - v-model:value="scriptForm.name"
20   - placeholder="请输入脚本名称"
21   - />
22   - <a-input
23   - @change="handleInputChange"
24   - v-else
25   - v-model:value="scriptForm.params"
26   - placeholder="请输入参数"
27   - />
28   - </a-form-item>
29   - <a-form-item
30   - label="上报数据类型"
31   - name="dataType"
32   - :rules="[{ required: true, message: '请选择上报数据类型' }]"
33   - >
34   - <a-space direction="vertical">
35   - <a-radio-group v-model:value="scriptForm.dataType" :options="typeOptions" />
36   - </a-space>
37   - </a-form-item>
38   - <a-form-item
39   - label="保存原始数据"
40   - name="saveOriginalData"
41   - :rules="[{ required: true, message: '请选择保存原始数据' }]"
42   - >
43   - <a-space direction="vertical">
44   - <a-radio-group v-model:value="scriptForm.saveOriginalData" :options="originalOptions" />
45   - </a-space>
46   - </a-form-item>
47   - <a-form-item label="脚本内容" :name="ifAdd ? 'convertJs' : 'script'">
48   - <Card title="脚本内容" :bodyStyle="{ padding: 0, height: '280px' }">
49   - <template #extra>
50   - <a-button @click="handleFormat" size="small">格式化</a-button>
51   - <Tooltip :title="defaultTitle" class="ml-2">
52   - <QuestionCircleOutlined style="font-size: 1rem" />
53   - </Tooltip>
54   - </template>
55   - <div ref="aceRef" class="overflow-hidden"></div>
56   - </Card>
57   - <Button @click="handleCopy" class="mt-4">
58   - <template #icon>
59   - <CopyOutlined />
60   - </template>
61   - copy
62   - </Button>
63   - </a-form-item>
64   - <a-form-item
65   - :label="ifAdd ? '备注' : '输出参数(output)'"
66   - :name="ifAdd ? 'description' : 'output'"
67   - >
68   - <a-textarea
69   - :rows="3"
70   - v-if="ifAdd"
71   - v-model:value="scriptForm.description"
72   - placeholder="请输入备注"
73   - :maxlength="255"
74   - />
75   - <a-textarea
76   - :rows="3"
77   - v-else
78   - v-model:value="scriptForm.output"
79   - placeholder="输出参数为服务端返回的内容"
80   - :maxlength="255"
81   - />
82   - </a-form-item>
83   - </a-form>
84   - </div>
85   -</template>
86   -<script setup lang="ts">
87   - import { ref, unref, reactive, onMounted, toRefs, nextTick } from 'vue';
88   - import ace from 'ace-builds';
89   - import { Card, Button, Tooltip } from 'ant-design-vue';
90   - import 'ace-builds/src-noconflict/theme-chrome'; // 默认设置的主题
91   - import 'ace-builds/src-noconflict/mode-javascript'; // 默认设置的语言模式
92   - import { beautify } from 'ace-builds/src-noconflict/ext-beautify.js';
93   - import { CopyOutlined } from '@ant-design/icons-vue';
94   - import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
95   - import { useMessage } from '/@/hooks/web/useMessage';
96   - import { findDictItemByCode } from '/@/api/system/dict';
97   - import { QuestionCircleOutlined } from '@ant-design/icons-vue';
98   - import { defaultTitle } from './config.data';
99   -
100   - defineEmits(['register']);
101   - const props = defineProps({
102   - ifAdd: { type: Boolean, default: true },
103   - });
104   - const scriptForm = reactive({
105   - name: '',
106   - description: '',
107   - convertJs: '',
108   - script: '',
109   - params: '',
110   - output: '',
111   - dataType: 'HEX',
112   - saveOriginalData: 'true',
113   - });
114   - const reportTypeOptions = reactive({
115   - typeOptions: [],
116   - originalOptions: [],
117   - });
118   - const { originalOptions, typeOptions } = toRefs(reportTypeOptions);
119   - const { createMessage } = useMessage();
120   - const { clipboardRef, copiedRef } = useCopyToClipboard();
121   - const aceEditor = ref();
122   - const aceRef = ref();
123   - const setDefaultRadio = (p1, p2) => {
124   - scriptForm.dataType = p1;
125   - scriptForm.saveOriginalData = p2;
126   - };
127   - onMounted(async () => {
128   - const res: any = await findDictItemByCode({
129   - dictCode: 'report_data_type',
130   - });
131   - const resOriginal: any = await findDictItemByCode({
132   - dictCode: 'original_data',
133   - });
134   - reportTypeOptions.typeOptions = res.map((m) => {
135   - return { label: m.itemText, value: m.itemValue };
136   - });
137   - reportTypeOptions.originalOptions = resOriginal.map((m) => {
138   - return { label: m.itemText, value: m.itemValue };
139   - });
140   - });
141   - // 初始化编辑器
142   - const initEditor = () => {
143   - aceEditor.value = ace.edit(aceRef.value, {
144   - maxLines: 12, // 最大行数,超过会自动出现滚动条
145   - minLines: 12, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
146   - fontSize: 14, // 编辑器内字体大小
147   - theme: 'ace/theme/chrome', // 默认设置的主题
148   - mode: 'ace/mode/javascript', // 默认设置的语言模式
149   - tabSize: 2, // 制表符设置为 4 个空格大小
150   - });
151   -
152   - aceEditor.value.setOptions({
153   - enableBasicAutocompletion: true,
154   - enableLiveAutocompletion: true,
155   - });
156   - aceEditor.value.setValue('');
157   - beautify(aceEditor.value.session);
158   - // scriptForm.convertJs = aceEditor.value.getValue();
159   - };
160   - const handleCopy = () => {
161   - const valueRef = aceEditor.value.getValue();
162   - const value = unref(valueRef);
163   - if (!value) {
164   - createMessage.warning('请输入要拷贝的内容!');
165   - return;
166   - }
167   - clipboardRef.value = value;
168   - if (unref(copiedRef)) {
169   - createMessage.success('复制成功!');
170   - }
171   - };
172   - const formRef = ref();
173   - const getFormData = async () => {
174   - const value = await formRef.value.validateFields();
175   - if (props.ifAdd) {
176   - scriptForm.convertJs = aceEditor.value.getValue();
177   - if (scriptForm.convertJs == '') {
178   - createMessage.error('请编写脚本内容');
179   - throw '请编写脚本内容';
180   - }
181   - } else {
182   - scriptForm.script = aceEditor.value.getValue();
183   - if (scriptForm.script == '') {
184   - createMessage.error('请编写脚本内容');
185   - throw '请编写脚本内容';
186   - }
187   - }
188   - if (!value) return;
189   - if (scriptForm.params) {
190   - const trimParams = scriptForm.params.replace(/\s*/g, '');
191   - Reflect.set(value, 'params', trimParams);
192   - }
193   - if (scriptForm.convertJs.length > 1000) {
194   - createMessage.error('脚本内容长度不能大于1000');
195   - throw '脚本内容长度不能大于1000';
196   - }
197   - return {
198   - ...value,
199   - ...{ convertJs: props.ifAdd ? scriptForm.convertJs : null },
200   - ...{ script: !props.ifAdd ? scriptForm.script : null },
201   - ...{ saveOriginalData: scriptForm.saveOriginalData === 'false' ? false : true },
202   - };
203   - };
204   - const handleInputChange = (e) => {
205   - const trimParams = e.target.value.replace(/\s*/g, '');
206   - Reflect.set(scriptForm, 'params', trimParams);
207   - };
208   - const setFormData = (v) => {
209   - if (v) {
210   - for (let i in scriptForm) {
211   - Reflect.set(scriptForm, i, v[i]);
212   - }
213   - nextTick(() => {
214   - setTimeout(() => {
215   - scriptForm.saveOriginalData = v.saveOriginalData === false ? 'false' : 'true';
216   - scriptForm.dataType = v.dataType;
217   - }, 10);
218   - });
219   - aceEditor.value.setValue(v.convertJs);
220   - handleFormat();
221   - }
222   - };
223   - const setScriptContentData = (v) => {
224   - aceEditor.value.setValue(v);
225   - handleFormat();
226   - };
227   - const resetFormData = () => {
228   - for (let i in scriptForm) {
229   - Reflect.set(scriptForm, i, '');
230   - }
231   - };
232   - const setScriptOutputData = (v) => {
233   - scriptForm.output = v;
234   - };
235   - const handleFormat = () => beautify(aceEditor.value.session);
236   -
237   - defineExpose({
238   - initEditor,
239   - getFormData,
240   - resetFormData,
241   - setFormData,
242   - setScriptContentData,
243   - setScriptOutputData,
244   - setDefaultRadio,
245   - });
246   -</script>
247   -<style lang="less" scoped>
248   - @import url('./ConverScriptModal.less');
249   -</style>
  1 +<template>
  2 + <div>
  3 + <a-form
  4 + ref="formRef"
  5 + :model="scriptForm"
  6 + name="basic"
  7 + :label-col="{ span: 4 }"
  8 + :wrapper-col="{ span: 16 }"
  9 + autocomplete="off"
  10 + >
  11 + <a-form-item
  12 + :label="ifAdd ? '名称' : '输入参数(params)'"
  13 + :name="ifAdd ? 'name' : 'params'"
  14 + :rules="[{ required: true, message: ifAdd ? '请输入脚本名称' : '请输入参数' }]"
  15 + >
  16 + <a-input
  17 + v-if="ifAdd"
  18 + :maxlength="36"
  19 + @change="handleInputChange"
  20 + v-model:value="scriptForm.name"
  21 + placeholder="请输入脚本名称"
  22 + />
  23 + <a-input
  24 + @change="handleInputChange"
  25 + v-else
  26 + v-model:value="scriptForm.params"
  27 + placeholder="请输入参数"
  28 + />
  29 + </a-form-item>
  30 + <a-form-item
  31 + label="上报数据类型"
  32 + name="dataType"
  33 + :rules="[{ required: false, message: '请选择上报数据类型' }]"
  34 + >
  35 + <a-space direction="vertical">
  36 + <a-radio-group v-model:value="scriptForm.dataType" :options="typeOptions" />
  37 + </a-space>
  38 + </a-form-item>
  39 + <a-form-item
  40 + label="脚本类型"
  41 + name="scriptType"
  42 + :rules="[{ required: true, message: '请选择脚本类型' }]"
  43 + >
  44 + <a-space direction="vertical">
  45 + <a-radio-group
  46 + @change="handleScriptType"
  47 + v-model:value="scriptForm.scriptType"
  48 + :options="scriptTypeOptions"
  49 + />
  50 + </a-space>
  51 + </a-form-item>
  52 + <a-form-item
  53 + label="保存原始数据"
  54 + name="saveOriginalData"
  55 + :rules="[{ required: true, message: '请选择保存原始数据' }]"
  56 + >
  57 + <a-space direction="vertical">
  58 + <a-radio-group v-model:value="scriptForm.saveOriginalData" :options="originalOptions" />
  59 + </a-space>
  60 + </a-form-item>
  61 + <a-form-item label="脚本内容" :name="ifAdd ? 'convertJs' : 'script'">
  62 + <Card title="脚本内容" :bodyStyle="{ padding: 0, height: '280px' }">
  63 + <template #extra>
  64 + <a-button @click="handleFormat" size="small">格式化</a-button>
  65 + <Tooltip :title="defaultTitle" class="ml-2">
  66 + <QuestionCircleOutlined style="font-size: 1rem" />
  67 + </Tooltip>
  68 + </template>
  69 + {{ getAceClass }}
  70 + <div ref="aceRef" class="overflow-hidden"></div>
  71 + </Card>
  72 + <Button @click="handleCopy" class="mt-4">
  73 + <template #icon>
  74 + <CopyOutlined />
  75 + </template>
  76 + copy
  77 + </Button>
  78 + </a-form-item>
  79 + <a-form-item
  80 + :label="ifAdd ? '备注' : '输出参数(output)'"
  81 + :name="ifAdd ? 'description' : 'output'"
  82 + >
  83 + <a-textarea
  84 + :rows="3"
  85 + v-if="ifAdd"
  86 + v-model:value="scriptForm.description"
  87 + placeholder="请输入备注"
  88 + :maxlength="255"
  89 + />
  90 + <a-textarea
  91 + :rows="3"
  92 + v-else
  93 + v-model:value="scriptForm.output"
  94 + placeholder="输出参数为服务端返回的内容"
  95 + :maxlength="255"
  96 + />
  97 + </a-form-item>
  98 + </a-form>
  99 + </div>
  100 +</template>
  101 +<script setup lang="ts">
  102 + import { ref, unref, reactive, onMounted, toRefs, nextTick, computed } from 'vue';
  103 + import ace from 'ace-builds';
  104 + import { Card, Button, Tooltip } from 'ant-design-vue';
  105 + import 'ace-builds/src-noconflict/theme-chrome'; // 默认设置的主题
  106 + import 'ace-builds/src-noconflict/theme-terminal'; // 默认设置的主题
  107 + import 'ace-builds/src-noconflict/mode-javascript'; // 默认设置的语言模式
  108 + import { beautify } from 'ace-builds/src-noconflict/ext-beautify.js';
  109 + import { CopyOutlined } from '@ant-design/icons-vue';
  110 + import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
  111 + import { useMessage } from '/@/hooks/web/useMessage';
  112 + import { findDictItemByCode } from '/@/api/system/dict';
  113 + import { QuestionCircleOutlined } from '@ant-design/icons-vue';
  114 + import { defaultTitle, defaultScriptTypeContent } from './config.data';
  115 + import { useAppStore } from '/@/store/modules/app';
  116 +
  117 + defineEmits(['register']);
  118 + const props = defineProps({
  119 + ifAdd: { type: Boolean, default: true },
  120 + });
  121 +
  122 + const scriptForm = reactive({
  123 + name: '',
  124 + description: '',
  125 + convertJs: '',
  126 + script: '',
  127 + params: '',
  128 + output: '',
  129 + dataType: 'HEX',
  130 + scriptType: 'TRANSPORT_TCP_UP',
  131 + saveOriginalData: 'true',
  132 + });
  133 +
  134 + const reportTypeOptions = reactive({
  135 + typeOptions: [],
  136 + originalOptions: [],
  137 + scriptTypeOptions: [],
  138 + });
  139 +
  140 + const { originalOptions, typeOptions, scriptTypeOptions } = toRefs(reportTypeOptions);
  141 +
  142 + const { createMessage } = useMessage();
  143 +
  144 + const { clipboardRef, copiedRef } = useCopyToClipboard();
  145 +
  146 + const aceEditor = ref();
  147 +
  148 + const aceRef = ref();
  149 +
  150 + const userStore = useAppStore();
  151 +
  152 + const getAceClass = computed((): string => userStore.getDarkMode);
  153 +
  154 + const setDefaultRadio = (p1, p2, p3) => {
  155 + scriptForm.dataType = p1;
  156 + scriptForm.saveOriginalData = p2;
  157 + scriptForm.scriptType = p3;
  158 + };
  159 +
  160 + const getDictValue = async (dict_type) => {
  161 + const res = await findDictItemByCode({
  162 + dictCode: dict_type,
  163 + });
  164 + return res.map((m) => {
  165 + return { label: m.itemText, value: m.itemValue };
  166 + });
  167 + };
  168 +
  169 + onMounted(async () => {
  170 + reportTypeOptions.typeOptions = (await getDictValue('report_data_type')) as never as any;
  171 + reportTypeOptions.originalOptions = (await getDictValue('original_data')) as never as any;
  172 + reportTypeOptions.scriptTypeOptions = (await getDictValue('script_type')) as never as any;
  173 + });
  174 +
  175 + // 初始化编辑器
  176 + const initEditor = () => {
  177 + aceEditor.value = ace.edit(aceRef.value, {
  178 + maxLines: 12, // 最大行数,超过会自动出现滚动条
  179 + minLines: 12, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
  180 + fontSize: 14, // 编辑器内字体大小
  181 + theme: 'ace/theme/chrome', // 默认设置的主题
  182 + mode: 'ace/mode/javascript', // 默认设置的语言模式
  183 + tabSize: 2, // 制表符设置为 4 个空格大小
  184 + });
  185 +
  186 + aceEditor.value.setOptions({
  187 + enableBasicAutocompletion: true,
  188 + enableLiveAutocompletion: true,
  189 + theme: getAceClass.value === 'dark' ? 'ace/theme/terminal' : 'ace/theme/chrome',
  190 + });
  191 + aceEditor.value.setValue('');
  192 + beautify(aceEditor.value.session);
  193 + switchScriptTypeGetContent('TRANSPORT_TCP_UP');
  194 + };
  195 +
  196 + const handleScriptType = ({ target }) => {
  197 + const { value } = target;
  198 + switchScriptTypeGetContent(value);
  199 + };
  200 +
  201 + const switchScriptTypeGetContent = (type) => {
  202 + if (type === 'TRANSPORT_TCP_DOWN')
  203 + Reflect.set(
  204 + defaultScriptTypeContent,
  205 + 'TRANSPORT_TCP_DOWN',
  206 + `out.datas = "${scriptForm.params}";out.deviceName = "sensor";`
  207 + );
  208 + aceEditor.value.setValue(defaultScriptTypeContent[type]);
  209 + };
  210 +
  211 + const handleCopy = () => {
  212 + const valueRef = aceEditor.value.getValue();
  213 + const value = unref(valueRef);
  214 + if (!value) {
  215 + createMessage.warning('请输入要拷贝的内容!');
  216 + return;
  217 + }
  218 + clipboardRef.value = value;
  219 + if (unref(copiedRef)) {
  220 + createMessage.success('复制成功!');
  221 + }
  222 + };
  223 +
  224 + const formRef = ref();
  225 +
  226 + const getFormData = async () => {
  227 + const value = await formRef.value.validateFields();
  228 + if (props.ifAdd) {
  229 + scriptForm.convertJs = aceEditor.value.getValue();
  230 + if (scriptForm.convertJs == '') {
  231 + createMessage.error('请编写脚本内容');
  232 + throw '请编写脚本内容';
  233 + }
  234 + } else {
  235 + scriptForm.script = aceEditor.value.getValue();
  236 + if (scriptForm.script == '') {
  237 + createMessage.error('请编写脚本内容');
  238 + throw '请编写脚本内容';
  239 + }
  240 + }
  241 + if (!value) return;
  242 + if (scriptForm.params) {
  243 + const trimParams = scriptForm.params.replace(/\s*/g, '');
  244 + Reflect.set(value, 'params', trimParams);
  245 + }
  246 + if (scriptForm.convertJs.length > 1000) {
  247 + createMessage.error('脚本内容长度不能大于1000');
  248 + throw '脚本内容长度不能大于1000';
  249 + }
  250 + return {
  251 + ...value,
  252 + ...{ convertJs: props.ifAdd ? scriptForm.convertJs : null },
  253 + ...{ script: !props.ifAdd ? scriptForm.script : null },
  254 + ...{ saveOriginalData: scriptForm.saveOriginalData === 'false' ? false : true },
  255 + };
  256 + };
  257 +
  258 + const handleInputChange = (e) => {
  259 + const trimParams = e.target.value.replace(/\s*/g, '');
  260 + Reflect.set(scriptForm, 'params', trimParams);
  261 + if (scriptForm.scriptType === 'TRANSPORT_TCP_DOWN') {
  262 + aceEditor.value.setValue(`out.datas = "${scriptForm.params}";out.deviceName = "sensor";`);
  263 + }
  264 + };
  265 +
  266 + const setFormData = (v) => {
  267 + if (v) {
  268 + for (let i in scriptForm) {
  269 + Reflect.set(scriptForm, i, v[i]);
  270 + }
  271 + nextTick(() => {
  272 + setTimeout(() => {
  273 + scriptForm.saveOriginalData = v.saveOriginalData === false ? 'false' : 'true';
  274 + scriptForm.dataType = v.dataType;
  275 + }, 10);
  276 + });
  277 + aceEditor.value.setValue(v.convertJs);
  278 + handleFormat();
  279 + }
  280 + };
  281 +
  282 + const setScriptContentData = (v) => {
  283 + aceEditor.value.setValue(v);
  284 + handleFormat();
  285 + };
  286 +
  287 + const resetFormData = () => {
  288 + for (let i in scriptForm) {
  289 + Reflect.set(scriptForm, i, '');
  290 + }
  291 + };
  292 +
  293 + const setScriptOutputData = (v) => {
  294 + scriptForm.output = v;
  295 + };
  296 +
  297 + const handleFormat = () => beautify(aceEditor.value.session);
  298 +
  299 + defineExpose({
  300 + initEditor,
  301 + getFormData,
  302 + resetFormData,
  303 + setFormData,
  304 + setScriptContentData,
  305 + setScriptOutputData,
  306 + setDefaultRadio,
  307 + });
  308 +</script>
  309 +<style lang="less" scoped>
  310 + @import url('./ConverScriptModal.less');
  311 +</style>
... ...
1   -<template>
2   - <div>
3   - <BasicModal
4   - destroyOnClose
5   - v-bind="$attrs"
6   - width="60rem"
7   - @register="register"
8   - :title="getTitle"
9   - :minHeight="500"
10   - @cancel="handleCancel"
11   - @ok="handleSubmit"
12   - >
13   - <ConverScript :ifAdd="isTest ? false : true" ref="converScriptRef" />
14   - </BasicModal>
15   - </div>
16   -</template>
17   -<script setup lang="ts">
18   - import { ref, computed, unref, reactive } from 'vue';
19   - import { BasicModal, useModalInner } from '/@/components/Modal';
20   - import ConverScript from './ConverScript.vue';
21   - import {
22   - createOrEditScriptManage,
23   - getScriptManageDetail,
24   - testScriptManage,
25   - } from '/@/api/scriptmanage/scriptManager';
26   - import { useMessage } from '/@/hooks/web/useMessage';
27   -
28   - const emits = defineEmits(['success', 'register']);
29   - const { createMessage } = useMessage();
30   - const converScriptRef = ref<InstanceType<typeof ConverScript>>();
31   - const getTitle = computed(() => (isUpdate.value ? '编辑转换脚本' : '新增转换脚本'));
32   - const isUpdate = ref(false);
33   - const isViewDetail = ref('');
34   - const isTest = ref(false);
35   - const isText = ref('');
36   - const isTitle = ref('');
37   - const editData = reactive({
38   - data: {},
39   - });
40   - const [register, { setModalProps, closeModal }] = useModalInner(async (data) => {
41   - setModalProps({ loading: true });
42   - handleCancel(false);
43   - isUpdate.value = data.isUpdate;
44   - isViewDetail.value = data.isView;
45   - isTest.value = data.isTest;
46   - isText.value = data.isText;
47   - isTitle.value = data.isTitle;
48   - editData.data = data.record;
49   - setModalProps({ loading: false });
50   - converScriptRef.value?.initEditor();
51   - if (!unref(isViewDetail)) {
52   - const title =
53   - unref(isTitle) == 'edit'
54   - ? '编辑转换脚本'
55   - : unref(isTitle) == 'add'
56   - ? '新增转换脚本'
57   - : '测试转换脚本';
58   - const okText = isText.value == 'test' ? '测试' : '确定';
59   - if (unref(isTitle) == 'add') {
60   - converScriptRef.value?.setDefaultRadio('HEX', 'true');
61   - }
62   - if (unref(isTitle) == 'edit') {
63   - converScriptRef.value?.setFormData(data.record);
64   - }
65   - if (unref(isTitle) == 'test') {
66   - if (data.record) {
67   - const res = await getScriptManageDetail(data.record);
68   - converScriptRef.value?.setFormData(res);
69   - } else {
70   - converScriptRef.value?.setDefaultRadio('HEX', 'true');
71   - }
72   - }
73   - setModalProps({ title, showOkBtn: true, showCancelBtn: true, okText });
74   - if (!unref(isUpdate)) {
75   - }
76   - } else {
77   - setModalProps({ showOkBtn: false, showCancelBtn: false, title: '查看转换脚本' });
78   - const res = await getScriptManageDetail(data.record.id);
79   - converScriptRef.value?.setFormData(res || {});
80   - }
81   - });
82   -
83   - const handleSubmit = async () => {
84   - setModalProps({ confirmLoading: true });
85   - try {
86   - const val = await converScriptRef.value?.getFormData();
87   - const tempObj = {
88   - ...editData.data,
89   - ...val,
90   - };
91   - const res: any =
92   - isText.value == 'test'
93   - ? await testScriptManage(val)
94   - : await createOrEditScriptManage(tempObj);
95   - createMessage.success(
96   - unref(isTitle) == 'edit'
97   - ? '编辑转换脚本成功'
98   - : unref(isTitle) == 'add'
99   - ? '新增转换脚本成功'
100   - : '测试转换脚本成功'
101   - );
102   - if (unref(isTitle) == 'add' || unref(isTitle) == 'edit') {
103   - setTimeout(() => {
104   - closeModal();
105   - }, 10);
106   - emits('success', {
107   - res,
108   - text: isText.value,
109   - });
110   - } else {
111   - if (res) {
112   - converScriptRef.value?.setScriptOutputData(res?.output || res?.error);
113   - }
114   - }
115   - } finally {
116   - setModalProps({ confirmLoading: false });
117   - }
118   - };
119   - const handleCancel = (flag) => {
120   - if (flag) {
121   - closeModal();
122   - }
123   - converScriptRef.value?.resetFormData();
124   - };
125   -</script>
126   -<style lang="less" scoped>
127   - @import url('./ConverScriptModal.less');
128   -</style>
  1 +<template>
  2 + <div>
  3 + <BasicModal
  4 + destroyOnClose
  5 + v-bind="$attrs"
  6 + width="60rem"
  7 + @register="register"
  8 + :title="getTitle"
  9 + :minHeight="500"
  10 + @cancel="handleCancel"
  11 + @ok="handleSubmit"
  12 + >
  13 + <ConverScript :ifAdd="isTest ? false : true" ref="converScriptRef" />
  14 + </BasicModal>
  15 + </div>
  16 +</template>
  17 +<script setup lang="ts">
  18 + import { ref, computed, unref, reactive } from 'vue';
  19 + import { BasicModal, useModalInner } from '/@/components/Modal';
  20 + import ConverScript from './ConverScript.vue';
  21 + import {
  22 + createOrEditScriptManage,
  23 + getScriptManageDetail,
  24 + testScriptManage,
  25 + } from '/@/api/scriptmanage/scriptManager';
  26 + import { useMessage } from '/@/hooks/web/useMessage';
  27 +
  28 + const emits = defineEmits(['success', 'register']);
  29 + const { createMessage } = useMessage();
  30 + const converScriptRef = ref<InstanceType<typeof ConverScript>>();
  31 + const getTitle = computed(() => (isUpdate.value ? '编辑转换脚本' : '新增转换脚本'));
  32 + const isUpdate = ref(false);
  33 + const isViewDetail = ref('');
  34 + const isTest = ref(false);
  35 + const isText = ref('');
  36 + const isTitle = ref('');
  37 + const editData = reactive({
  38 + data: {},
  39 + });
  40 + const [register, { setModalProps, closeModal }] = useModalInner(async (data) => {
  41 + setModalProps({ loading: true });
  42 + handleCancel(false);
  43 + isUpdate.value = data.isUpdate;
  44 + isViewDetail.value = data.isView;
  45 + isTest.value = data.isTest;
  46 + isText.value = data.isText;
  47 + isTitle.value = data.isTitle;
  48 + editData.data = data.record;
  49 + setModalProps({ loading: false });
  50 + converScriptRef.value?.initEditor();
  51 + if (!unref(isViewDetail)) {
  52 + const title =
  53 + unref(isTitle) == 'edit'
  54 + ? '编辑转换脚本'
  55 + : unref(isTitle) == 'add'
  56 + ? '新增转换脚本'
  57 + : '测试转换脚本';
  58 + const okText = isText.value == 'test' ? '测试' : '确定';
  59 + if (unref(isTitle) == 'add') {
  60 + converScriptRef.value?.setDefaultRadio('HEX', 'true', 'TRANSPORT_TCP_UP');
  61 + }
  62 + if (unref(isTitle) == 'edit') {
  63 + converScriptRef.value?.setFormData(data.record);
  64 + }
  65 + if (unref(isTitle) == 'test') {
  66 + if (data.record) {
  67 + const res = await getScriptManageDetail(data.record);
  68 + converScriptRef.value?.setFormData(res);
  69 + } else {
  70 + converScriptRef.value?.setDefaultRadio('HEX', 'true', 'TRANSPORT_TCP_UP');
  71 + }
  72 + }
  73 + setModalProps({ title, showOkBtn: true, showCancelBtn: true, okText });
  74 + if (!unref(isUpdate)) {
  75 + }
  76 + } else {
  77 + setModalProps({ showOkBtn: false, showCancelBtn: false, title: '查看转换脚本' });
  78 + const res = await getScriptManageDetail(data.record.id);
  79 + converScriptRef.value?.setFormData(res || {});
  80 + }
  81 + });
  82 +
  83 + const handleSubmit = async () => {
  84 + setModalProps({ confirmLoading: true });
  85 + try {
  86 + const val = await converScriptRef.value?.getFormData();
  87 + const tempObj = {
  88 + ...editData.data,
  89 + ...val,
  90 + };
  91 + const res: any =
  92 + isText.value == 'test'
  93 + ? await testScriptManage(val)
  94 + : await createOrEditScriptManage(tempObj);
  95 + createMessage.success(
  96 + unref(isTitle) == 'edit'
  97 + ? '编辑转换脚本成功'
  98 + : unref(isTitle) == 'add'
  99 + ? '新增转换脚本成功'
  100 + : '测试转换脚本成功'
  101 + );
  102 + if (unref(isTitle) == 'add' || unref(isTitle) == 'edit') {
  103 + setTimeout(() => {
  104 + closeModal();
  105 + }, 10);
  106 + emits('success', {
  107 + res,
  108 + text: isText.value,
  109 + });
  110 + } else {
  111 + if (res) {
  112 + converScriptRef.value?.setScriptOutputData(res?.output || res?.error);
  113 + }
  114 + }
  115 + } finally {
  116 + setModalProps({ confirmLoading: false });
  117 + }
  118 + };
  119 + const handleCancel = (flag) => {
  120 + if (flag) {
  121 + closeModal();
  122 + }
  123 + converScriptRef.value?.resetFormData();
  124 + };
  125 +</script>
  126 +<style lang="less" scoped>
  127 + @import url('./ConverScriptModal.less');
  128 +</style>
... ...
1   -import { BasicColumn, FormSchema } from '/@/components/Table';
2   -import moment from 'moment';
3   -import { h } from 'vue';
4   -
5   -// 表格配置
6   -export const columns: BasicColumn[] = [
7   - {
8   - title: '脚本名称',
9   - dataIndex: 'name',
10   - width: 80,
11   - },
12   - {
13   - title: '脚本状态',
14   - dataIndex: 'status',
15   - width: 120,
16   - slots: { customRender: 'status' },
17   - },
18   - {
19   - title: '脚本内容',
20   - dataIndex: 'convertJs',
21   - width: 120,
22   - slots: { customRender: 'convertJs' },
23   - },
24   - {
25   - title: '备注',
26   - dataIndex: 'description',
27   - width: 120,
28   - },
29   - {
30   - title: '创建时间',
31   - dataIndex: 'createTime',
32   - width: 180,
33   - },
34   -];
35   -
36   -// 查询配置
37   -export const searchFormSchema: FormSchema[] = [
38   - {
39   - field: 'name',
40   - label: '脚本名称',
41   - component: 'Input',
42   - colProps: { span: 6 },
43   - componentProps: {
44   - maxLength: 36,
45   - placeholder: '请输入配置名称',
46   - },
47   - },
48   - {
49   - field: 'sendTime',
50   - label: '创建时间',
51   - component: 'RangePicker',
52   - componentProps: {
53   - showTime: {
54   - defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')],
55   - },
56   - },
57   - colProps: { span: 6 },
58   - },
59   -];
60   -
61   -export const defaultTitle = h('div', { style: 'background:#404040' }, [
62   - h('h3', { style: 'color:white' }, '示例'),
63   - h('h3', { style: 'color:white' }, '输入参数:'),
64   - h('h3', { style: 'color:white' }, '0103040150008D3BBB'),
65   - h('h3', { style: 'color:white' }, [
66   - h('h3', { style: 'color:white' }, '脚本内容:'),
67   - h(
68   - 'h3',
69   - { style: 'color:white' },
70   - "out.humidity = (parseInt('0x'+params.substr(6, 4))*0.1).toFixed(2);"
71   - ),
72   - h(
73   - 'h3',
74   - { style: 'color:white' },
75   - "out.temperature = (parseInt('0x'+params.substr(10, 4))*0.1).toFixed(2);"
76   - ),
77   - h('h3', { style: 'color:white' }, '输出参数:'),
78   - h('h3', { style: 'color:white' }, "{'humidity':'33.60','temperature':'14.10'}"),
79   - ]),
80   -]);
  1 +import { BasicColumn, FormSchema } from '/@/components/Table';
  2 +import moment from 'moment';
  3 +import { h } from 'vue';
  4 +
  5 +// 表格配置
  6 +export const columns: BasicColumn[] = [
  7 + {
  8 + title: '脚本名称',
  9 + dataIndex: 'name',
  10 + width: 80,
  11 + },
  12 + {
  13 + title: '脚本状态',
  14 + dataIndex: 'status',
  15 + width: 120,
  16 + slots: { customRender: 'status' },
  17 + },
  18 + {
  19 + title: '脚本内容',
  20 + dataIndex: 'convertJs',
  21 + width: 120,
  22 + slots: { customRender: 'convertJs' },
  23 + },
  24 + {
  25 + title: '备注',
  26 + dataIndex: 'description',
  27 + width: 120,
  28 + },
  29 + {
  30 + title: '创建时间',
  31 + dataIndex: 'createTime',
  32 + width: 180,
  33 + },
  34 +];
  35 +
  36 +// 查询配置
  37 +export const searchFormSchema: FormSchema[] = [
  38 + {
  39 + field: 'name',
  40 + label: '脚本名称',
  41 + component: 'Input',
  42 + colProps: { span: 6 },
  43 + componentProps: {
  44 + maxLength: 36,
  45 + placeholder: '请输入配置名称',
  46 + },
  47 + },
  48 + {
  49 + field: 'sendTime',
  50 + label: '创建时间',
  51 + component: 'RangePicker',
  52 + componentProps: {
  53 + showTime: {
  54 + defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')],
  55 + },
  56 + },
  57 + colProps: { span: 6 },
  58 + },
  59 +];
  60 +
  61 +export const defaultTitle = h('div', { style: 'background:#404040' }, [
  62 + h('h3', { style: 'color:white' }, '示例'),
  63 + h('h3', { style: 'color:white' }, '输入参数:'),
  64 + h('h3', { style: 'color:white' }, '0103040150008D3BBB'),
  65 + h('h3', { style: 'color:white' }, [
  66 + h('h3', { style: 'color:white' }, '脚本内容:'),
  67 + h(
  68 + 'h3',
  69 + { style: 'color:white' },
  70 + "out.humidity = (parseInt('0x'+params.substr(6, 4))*0.1).toFixed(2);"
  71 + ),
  72 + h(
  73 + 'h3',
  74 + { style: 'color:white' },
  75 + "out.temperature = (parseInt('0x'+params.substr(10, 4))*0.1).toFixed(2);"
  76 + ),
  77 + h('h3', { style: 'color:white' }, '输出参数:'),
  78 + h('h3', { style: 'color:white' }, "{'humidity':'33.60','temperature':'14.10'}"),
  79 + ]),
  80 +]);
  81 +
  82 +export const defaultScriptTypeContent = {
  83 + TRANSPORT_TCP_UP:
  84 + 'var attrData = {};var teleData = {};teleData.source= params;out.datas = teleData;out.telemetry =true;out.ackMsg = params;out.deviceName = "sensor";out.ts = Date.now();',
  85 + TRANSPORT_TCP_DOWN: 'out.datas = "";out.deviceName = "sensor";',
  86 + TRANSPORT_TCP_AUTH: 'out.password = params;out.success = params;',
  87 +};
... ...