TestScript.vue 8.81 KB
<template>
  <div>
    <PageWrapper title="测试脚本功能" class="pl-4 pr-4 pt-4" :contentStyle="{ display: 'none' }" />
    <div class="h-full flex p-4">
      <div class="flex flex-col w-1/2">
        <div class="flex-1 mr-4 mb-4">
          <Card :bodyStyle="cardStyle">
            <template #title>
              <div class="w-3/4 flex">
                <span class="mr-2">消息类型</span>
                <Select
                  v-model:value="messageType"
                  class="flex-1 mr-2"
                  :options="getScriptMessageTypeOptions"
                  placeholder="请选择消息类型"
                />
              </div>
              <div>消息</div>
            </template>
            <template #extra>
              <div>
                <Tag color="blue">Message</Tag>
                <a-button @click="handleFormatJson" size="small">格式化</a-button>
                <a-button @click="handleMiniJson" size="small" class="ml-2">收起</a-button>
              </div>
            </template>
            <div ref="jsoneditorRef" style="height: 100%"></div>
          </Card>
        </div>
        <div class="flex-1 mr-4">
          <Card title="转换函数" :bodyStyle="cardStyle">
            <template #extra>
              <Tag color="blue">Transform Function</Tag>
              <a-button @click="handleFormatJScript" size="small">格式化</a-button>

              <Tooltip title="帮助文档" @click="openModal">
                <QuestionCircleOutlined class="ml-2" style="font-size: 1rem" />
              </Tooltip>
            </template>
            <div class="ml-8">function Transform(msg, metadata, msgType) {</div>
            <div ref="aceRef" style="height: calc(100% - 44px)"></div>
            <div class="ml-7">}</div>
          </Card>
        </div>
      </div>
      <div class="flex flex-col w-1/2">
        <div class="flex-1 mb-4">
          <Card title="元数据" :bodyStyle="cardStyle">
            <template #extra>
              <Tag color="blue">Meta Data</Tag>
            </template>
            <Description @register="registerDesc" />
          </Card>
        </div>
        <div class="flex-1">
          <Card title="输出" :bodyStyle="cardStyle">
            <template #extra>
              <Tag color="blue">Output</Tag>
              <a-button @click="handleFormatOutPutJson" size="small">格式化</a-button>
              <a-button @click="handleCompactJson" size="small" class="ml-2">收起</a-button>
            </template>
            <div class="ml-8 opacity-0">site</div>
            <div ref="outputRef" style="height: calc(100% - 44px)"></div>
            <div class="ml-7 opacity-0">site</div>
          </Card>
        </div>
      </div>
    </div>
    <div class="flex justify-between pl-4 pr-4">
      <div>
        <a-button class="" type="primary" @click="handleTestFunc"> 测试</a-button>
      </div>
      <div>
        <a-button class="ml-4" @click="handleCancel"> 取消</a-button>
        <a-button class="ml-4" type="primary" @click="handleOk"> 保存</a-button>
      </div>
    </div>
    <BasicModal
      @register="registerModal"
      title="转换消息功能"
      :footer="null"
      width="800px"
      centered
      v-bind="$attrs"
    >
      <h2> function Transform(msg,metadata): {msg: object, metadata: object, msgType: string} </h2>
      <li> 将输入消息、元数据转换为输出消息的 JavaScript 函数 </li>
      <h2>参数:</h2>
      <ul>
        <li>msg: {[key: string]: any} - 是消息有效负载键/值对象。</li>
        <li>metadata: {[key: string]: string} - 是消息元数据键/值映射, 其中键和值都是字符串。</li>
        <li>msgType: string - 是包含消息类型的字符串。有关常用值, 请参见MessageType enum。</li>
      </ul>
      <h2>返回值:</h2>
      <ul>
        <li>
          { msg?: {[key: string]: any}, metadata?: {[key: string]: string}, msgType?: string }
        </li>
        <li> 结果对象中的所有字段都是可选的,如果未指定,将从原始消息中获取。 </li>
      </ul>
    </BasicModal>
  </div>
</template>
<script lang="ts" setup>
  import { ref, onMounted, defineComponent, computed, unref } from 'vue';
  import { Card, Tag, Tooltip, Select } from 'ant-design-vue';
  import { PageWrapper } from '/@/components/Page';
  import { Description, DescItem, useDescription } from '/@/components/Description/index';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { QuestionCircleOutlined } from '@ant-design/icons-vue';
  import { BasicModal, useModal } from '/@/components/Modal/index';

  import jsoneditor from 'jsoneditor';
  import 'jsoneditor/dist/jsoneditor.min.css';
  import ace from 'ace-builds';
  import 'ace-builds/src-noconflict/theme-chrome'; // 默认设置的主题
  import 'ace-builds/src-noconflict/mode-javascript'; // 默认设置的语言模式
  import 'ace-builds/src-noconflict/ext-language_tools.js'; //语言提示
  import { beautify } from 'ace-builds/src-noconflict/ext-beautify.js'; //格式化
  import { ScriptMessageTypeEnum } from '../config/config.data';
  // !!!important 重要,配置ace编辑器的错误提示,基础路径。否则会加载不到相关web Worker,就没有syntax validation提示
  ace.config.set('basePath', 'https://cdn.jsdelivr.net/npm/ace-builds@1.4.14/src-noconflict/');
  defineComponent({
    Tooltip,
  });

  const jsonValue = ref({
    temperature: 22.4,
    humidity: 78,
  });
  const cardStyle = { padding: 0, height: '280px' };

  // json 以及初始化JSON
  const jsoneditorRef = ref();
  const JsonEditor = ref();
  const outputRef = ref();
  const outputEditor = ref();
  const aceEditor = ref();
  const aceRef = ref();
  const emit = defineEmits(['isStatus']);

  const messageType = ref(ScriptMessageTypeEnum['Post telemetry']);
  const getScriptMessageTypeOptions = computed(() =>
    Object.keys(ScriptMessageTypeEnum).map((item) => ({
      label: item,
      value: ScriptMessageTypeEnum[item],
    }))
  );

  function initEditor() {
    let options = {
      mode: 'code',
      mainMenuBar: false,
      statusBar: false,
      onError: function (err) {
        alert('EF1 ->' + err.toString());
      },
    };
    let editor = new jsoneditor(jsoneditorRef.value, options);
    editor.set(jsonValue.value);
    JsonEditor.value = editor;
    let outEditor = new jsoneditor(outputRef.value, options);
    outEditor.set(true);
    outputEditor.value = outEditor;

    aceEditor.value = ace.edit(aceRef.value, {
      maxLines: 12, // 最大行数,超过会自动出现滚动条
      minLines: 12, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
      fontSize: 14, // 编辑器内字体大小
      theme: 'ace/theme/chrome', // 默认设置的主题
      mode: 'ace/mode/javascript', // 默认设置的语言模式
      tabSize: 2, // 制表符设置为 2 个空格大小
      enableBasicAutocompletion: true, //补全
      enableLiveAutocompletion: true, //
    });
  }
  const mataData: any = {
    deviceName: 'Test Device',
    deviceType: 'default',
    ts: Date.now(),
  };
  const schema: DescItem[] = [
    {
      field: 'deviceName',
      label: 'deviceName',
    },
    {
      field: 'deviceType',
      label: 'deviceType',
    },
    {
      field: 'ts',
      label: 'ts',
    },
  ];
  const [registerDesc] = useDescription({
    column: 1,
    data: mataData,
    schema,
  });
  // 格式化json
  const handleFormatJson = () => {
    JsonEditor.value.repair();
    JsonEditor.value.format();
  };
  // 迷你json
  const handleMiniJson = () => {
    JsonEditor.value.repair();
    JsonEditor.value.compact();
  };
  // format json
  const handleFormatOutPutJson = () => {
    outputEditor.value.repair();
    outputEditor.value.format();
  };
  // 迷你json
  const handleCompactJson = () => {
    outputEditor.value.repair();
    outputEditor.value.compact();
  };

  // 测试
  const handleTestFunc = async () => {
    // 收集3方数据
    try {
      const msg = JsonEditor.value.get();
      const metadata = mataData;
      const jsCode = aceEditor.value.getValue();
      // 执行动态Javascript脚本
      let result = Function(
        'msg',
        'metadata',
        'msgType',
        jsCode
      )(msg, metadata, unref(messageType));
      // 设置输出值
      outputEditor.value.set(result);
    } catch (e) {
      console.error(e);
      const { createMessage } = useMessage();
      createMessage.error(e.toString());
    }
  };
  const [registerModal, { openModal }] = useModal();
  const handleCancel = () => {
    emit('isStatus', { status: 0, emitType: 'cancel' });
  };
  const handleOk = () => {
    emit('isStatus', { status: 0, emitType: 'ok' });
  };
  const handleFormatJScript = () => {
    beautify(aceEditor.value.session);
  };
  onMounted(() => {
    initEditor();
  });
  defineExpose({ aceEditor });
</script>

<style scope>
  .jsoneditor {
    border: none;
  }
</style>