ConverScript.vue 9.81 KB
<template>
  <div>
    <a-form
      ref="formRef"
      :model="scriptForm"
      name="basic"
      :label-col="{ span: 4 }"
      :wrapper-col="{ span: 16 }"
      autocomplete="off"
    >
      <a-form-item
        :label="ifAdd ? '名称' : '输入参数(params)'"
        :name="ifAdd ? 'name' : 'params'"
        :rules="[{ required: true, message: ifAdd ? '请输入脚本名称' : '请输入参数' }]"
      >
        <a-input
          v-if="ifAdd"
          :maxlength="36"
          @change="handleInputChange"
          v-model:value="scriptForm.name"
          placeholder="请输入脚本名称"
        />
        <a-input
          @change="handleInputChange"
          v-else
          v-model:value="scriptForm.params"
          placeholder="请输入参数"
        />
      </a-form-item>
      <a-form-item
        label="上报数据类型"
        name="dataType"
        :rules="[{ required: false, message: '请选择上报数据类型' }]"
      >
        <a-space direction="vertical">
          <a-radio-group v-model:value="scriptForm.dataType" :options="typeOptions" />
        </a-space>
      </a-form-item>
      <a-form-item
        label="脚本类型"
        name="scriptType"
        :rules="[{ required: true, message: '请选择脚本类型' }]"
      >
        <a-space direction="vertical">
          <a-radio-group
            @change="handleScriptType"
            v-model:value="scriptForm.scriptType"
            :options="scriptTypeOptions"
          />
        </a-space>
      </a-form-item>
      <a-form-item
        label="保存原始数据"
        name="saveOriginalData"
        :rules="[{ required: true, message: '请选择保存原始数据' }]"
      >
        <a-space direction="vertical">
          <a-radio-group v-model:value="scriptForm.saveOriginalData" :options="originalOptions" />
        </a-space>
      </a-form-item>
      <a-form-item label="脚本内容" :name="ifAdd ? 'convertJs' : 'script'">
        <Card title="脚本内容" :bodyStyle="{ padding: 0, height: '280px' }">
          <template #extra>
            <a-button @click="handleFormat" size="small">格式化</a-button>
            <Tooltip :title="defaultTitle" class="ml-2">
              <QuestionCircleOutlined style="font-size: 1rem" />
            </Tooltip>
          </template>
          {{ getAceClass }}
          <div ref="aceRef" class="overflow-hidden"></div>
        </Card>
        <Button @click="handleCopy" class="mt-4">
          <template #icon>
            <CopyOutlined />
          </template>
          copy
        </Button>
      </a-form-item>
      <a-form-item
        :label="ifAdd ? '备注' : '输出参数(output)'"
        :name="ifAdd ? 'description' : 'output'"
      >
        <a-textarea
          :rows="3"
          v-if="ifAdd"
          v-model:value="scriptForm.description"
          placeholder="请输入备注"
          :maxlength="255"
        />
        <a-textarea
          :rows="3"
          v-else
          v-model:value="scriptForm.output"
          placeholder="输出参数为服务端返回的内容"
          :maxlength="255"
        />
      </a-form-item>
    </a-form>
  </div>
</template>
<script setup lang="ts">
  import { ref, unref, reactive, onMounted, toRefs, nextTick, computed } from 'vue';
  import ace from 'ace-builds';
  import { Card, Button, Tooltip } from 'ant-design-vue';
  import 'ace-builds/src-noconflict/theme-chrome'; // 默认设置的主题
  import 'ace-builds/src-noconflict/theme-terminal'; // 默认设置的主题
  import 'ace-builds/src-noconflict/mode-javascript'; // 默认设置的语言模式
  import { beautify } from 'ace-builds/src-noconflict/ext-beautify.js';
  import { CopyOutlined } from '@ant-design/icons-vue';
  import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { findDictItemByCode } from '/@/api/system/dict';
  import { QuestionCircleOutlined } from '@ant-design/icons-vue';
  import { defaultTitle, defaultScriptTypeContent } from './config.data';
  import { useAppStore } from '/@/store/modules/app';

  defineEmits(['register']);
  const props = defineProps({
    ifAdd: { type: Boolean, default: true },
  });

  const scriptForm = reactive({
    name: '',
    description: '',
    convertJs: '',
    script: '',
    params: '',
    output: '',
    dataType: 'HEX',
    scriptType: 'TRANSPORT_TCP_UP',
    saveOriginalData: 'true',
  });

  const reportTypeOptions = reactive({
    typeOptions: [],
    originalOptions: [],
    scriptTypeOptions: [],
  });

  const { originalOptions, typeOptions, scriptTypeOptions } = toRefs(reportTypeOptions);

  const { createMessage } = useMessage();

  const { clipboardRef, copiedRef } = useCopyToClipboard();

  const aceEditor = ref();

  const aceRef = ref();

  const userStore = useAppStore();

  const getAceClass = computed((): string => userStore.getDarkMode);

  const setDefaultRadio = (p1, p2, p3) => {
    scriptForm.dataType = p1;
    scriptForm.saveOriginalData = p2;
    scriptForm.scriptType = p3;
  };

  const getDictValue = async (dict_type) => {
    const res = await findDictItemByCode({
      dictCode: dict_type,
    });
    return res.map((m) => {
      return { label: m.itemText, value: m.itemValue };
    });
  };

  onMounted(async () => {
    reportTypeOptions.typeOptions = (await getDictValue('report_data_type')) as never as any;
    reportTypeOptions.originalOptions = (await getDictValue('original_data')) as never as any;
    reportTypeOptions.scriptTypeOptions = (await getDictValue('script_type')) as never as any;
  });

  // 初始化编辑器
  const initEditor = () => {
    aceEditor.value = ace.edit(aceRef.value, {
      maxLines: 12, // 最大行数,超过会自动出现滚动条
      minLines: 12, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
      fontSize: 14, // 编辑器内字体大小
      theme: 'ace/theme/chrome', // 默认设置的主题
      mode: 'ace/mode/javascript', // 默认设置的语言模式
      tabSize: 2, // 制表符设置为 4 个空格大小
    });

    aceEditor.value.setOptions({
      enableBasicAutocompletion: true,
      enableLiveAutocompletion: true,
      theme: getAceClass.value === 'dark' ? 'ace/theme/terminal' : 'ace/theme/chrome',
    });
    aceEditor.value.setValue('');
    beautify(aceEditor.value.session);
    switchScriptTypeGetContent('TRANSPORT_TCP_UP');
  };

  const handleScriptType = ({ target }) => {
    const { value } = target;
    switchScriptTypeGetContent(value);
  };

  const switchScriptTypeGetContent = (type) => {
    if (type === 'TRANSPORT_TCP_DOWN')
      Reflect.set(
        defaultScriptTypeContent,
        'TRANSPORT_TCP_DOWN',
        `out.datas = "${scriptForm.params}";out.deviceName = "sensor";`
      );
    aceEditor.value.setValue(defaultScriptTypeContent[type]);
  };

  const handleCopy = () => {
    const valueRef = aceEditor.value.getValue();
    const value = unref(valueRef);
    if (!value) {
      createMessage.warning('请输入要拷贝的内容!');
      return;
    }
    clipboardRef.value = value;
    if (unref(copiedRef)) {
      createMessage.success('复制成功!');
    }
  };

  const formRef = ref();

  const getFormData = async () => {
    const value = await formRef.value.validateFields();
    if (props.ifAdd) {
      scriptForm.convertJs = aceEditor.value.getValue();
      if (scriptForm.convertJs == '') {
        createMessage.error('请编写脚本内容');
        throw '请编写脚本内容';
      }
    } else {
      scriptForm.script = aceEditor.value.getValue();
      if (scriptForm.script == '') {
        createMessage.error('请编写脚本内容');
        throw '请编写脚本内容';
      }
    }
    if (!value) return;
    if (scriptForm.params) {
      const trimParams = scriptForm.params.replace(/\s*/g, '');
      Reflect.set(value, 'params', trimParams);
    }
    if (scriptForm.convertJs.length > 1000) {
      createMessage.error('脚本内容长度不能大于1000');
      throw '脚本内容长度不能大于1000';
    }
    return {
      ...value,
      ...{ convertJs: props.ifAdd ? scriptForm.convertJs : null },
      ...{ script: !props.ifAdd ? scriptForm.script : null },
      ...{ saveOriginalData: scriptForm.saveOriginalData === 'false' ? false : true },
    };
  };

  const handleInputChange = (e) => {
    const trimParams = e.target.value.replace(/\s*/g, '');
    Reflect.set(scriptForm, 'params', trimParams);
    if (scriptForm.scriptType === 'TRANSPORT_TCP_DOWN') {
      aceEditor.value.setValue(`out.datas = "${scriptForm.params}";out.deviceName = "sensor";`);
    }
  };

  const setFormData = (v) => {
    if (v) {
      for (let i in scriptForm) {
        Reflect.set(scriptForm, i, v[i]);
      }
      nextTick(() => {
        setTimeout(() => {
          scriptForm.saveOriginalData = v.saveOriginalData === false ? 'false' : 'true';
          scriptForm.dataType = v.dataType;
        }, 10);
      });
      aceEditor.value.setValue(v.convertJs);
      handleFormat();
    }
  };

  const setScriptContentData = (v) => {
    aceEditor.value.setValue(v);
    handleFormat();
  };

  const resetFormData = () => {
    for (let i in scriptForm) {
      Reflect.set(scriptForm, i, '');
    }
  };

  const setScriptOutputData = (v) => {
    scriptForm.output = v;
  };

  const handleFormat = () => beautify(aceEditor.value.session);

  defineExpose({
    initEditor,
    getFormData,
    resetFormData,
    setFormData,
    setScriptContentData,
    setScriptOutputData,
    setDefaultRadio,
  });
</script>
<style lang="less" scoped>
  @import url('./ConverScriptModal.less');
</style>