ConverScriptForm.vue 10 KB
<template>
  <div>
    <a-form
      ref="formRef"
      :model="scriptForm"
      name="basic"
      :label-col="{ span: 4 }"
      :wrapper-col="{ span: 16 }"
    >
      <a-form-item
        :label="isNotTest ? '名称' : '输入参数(params)'"
        :name="isNotTest ? 'name' : 'params'"
        :rules="[{ required: true, message: isNotTest ? '请输入脚本名称' : '请输入参数' }]"
      >
        <a-input-group compact>
          <a-input
            style="width: calc(100% - 200px)"
            v-if="isNotTest"
            :maxlength="36"
            @change="handleInputChange"
            v-model:value="scriptForm.name"
            placeholder="请输入脚本名称"
          />
          <a-input
            @change="handleInputChange"
            v-else
            v-model:value="scriptForm.params"
            placeholder="请输入参数"
          />
          <a-button
            @click="
              handleInnerTestClick(BusinessConvertScriptTextEnum.BUSINESS_TEST_TEXT, 'innerTest')
            "
            v-show="isNotTest && !isView"
            type="primary"
          >
            测试
          </a-button>
        </a-input-group>
      </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="isNotTest ? 'convertJs' : 'script'">
        <Card title="编写脚本内容" :bodyStyle="{ padding: 0 }">
          <template #extra>
            <Button
              v-show="isNotTest && !isView"
              @click="onHandleTestExample(true, scriptForm.scriptType)"
              class="button-text"
              type="primary"
            >
              直连/子设备用例</Button
            >
            <Button
              class="ml-2 button-text"
              v-show="isNotTest && !isView"
              @click="onHandleTestExample(false, scriptForm.scriptType)"
              type="primary"
            >
              网关用例</Button
            >
            <a-button @click="handleFormat" size="small">格式化</a-button>
            <Tooltip
              v-if="scriptForm.scriptType !== ScriptTypeEnum.TRANSPORT_TCP_UP"
              :title="defaultAuthTitle"
              class="ml-2"
            >
              <QuestionCircleOutlined />
            </Tooltip>
            <Tooltip v-else :title="defaultUpTitle" class="ml-2">
              <QuestionCircleOutlined />
            </Tooltip>
          </template>
          <div ref="aceRef"></div>
        </Card>
        <Button @click="handleCopy" class="mt-4">
          <template #icon>
            <CopyOutlined />
          </template>
          copy
        </Button>
      </a-form-item>
      <a-form-item
        :label="isNotTest ? '备注' : '输出参数(output)'"
        :name="isNotTest ? 'description' : 'output'"
      >
        <a-textarea
          :rows="3"
          v-if="isNotTest"
          v-model:value="scriptForm.description"
          placeholder="请输入备注"
          :maxlength="255"
        />
        <a-textarea
          :rows="5"
          v-else
          v-model:value="scriptForm.output"
          placeholder="输出参数为服务端返回的内容"
        />
      </a-form-item>
    </a-form>
    <ConverScriptModal @register="registerModal" />
  </div>
</template>
<script setup lang="ts">
  import { ref, unref, reactive, onMounted, toRefs, 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 { useClipboard } from '@vueuse/core';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { findDictItemByCode } from '/@/api/system/dict';
  import { QuestionCircleOutlined } from '@ant-design/icons-vue';
  import {
    defaultAuthTitle,
    defaultUpTitle,
    defaultScriptTypeContent,
    defaultTestUpExample,
    defaultTestAuthExample,
    defaultTestSubGatewayUpExample,
    ScriptTypeEnum,
    aceEditorAttribtes,
    aceEditorOptions,
  } from '../config';
  import { useAppStore } from '/@/store/modules/app';
  import { ConverScriptModal } from './index';
  import { useModal } from '/@/components/Modal';
  import { useHooks } from '../hooks/index.hooks';
  import { BusinessConvertScriptTextEnum } from '../config';

  defineEmits(['register']);

  const props = defineProps({
    isNotTest: { type: Boolean, default: true },
    isView: { type: Boolean, default: false },
  });

  const { validateContentError } = useHooks();

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

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

  const { scriptTypeOptions } = toRefs(reportTypeOptions);

  const { createMessage } = useMessage();

  const { copied, copy } = useClipboard({ legacy: true });

  const aceEditor = ref();

  const aceRef = ref();

  const userStore = useAppStore();

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

  const setDefaultRadio = (defaultRadio) => {
    scriptForm.scriptType = defaultRadio;
  };

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

  const getScriptType = async () => {
    reportTypeOptions.scriptTypeOptions = (await getDictValue('script_type')) as any;
  };

  onMounted(() => {
    getScriptType();
    initEditor();
  });

  // 初始化Ace编辑器
  const initEditor = () => {
    aceEditor.value = ace.edit(aceRef.value, aceEditorAttribtes);
    aceEditor.value.setOptions({
      ...aceEditorOptions,
      theme: getAceClass.value === 'dark' ? 'ace/theme/terminal' : 'ace/theme/chrome',
    });
    aceEditor.value.setValue('');
    beautify(aceEditor.value.session);
    switchScriptTypeGetContent(ScriptTypeEnum.TRANSPORT_TCP_UP);
  };

  const handleScriptType = ({ target }) => {
    const { value } = target;
    scriptForm.scriptType = value;
    //业务 编辑不允许切换
    if (convertJsContent.value) return;
    switchScriptTypeGetContent(value);
  };

  const switchScriptTypeGetContent = (type) => {
    aceEditor.value.setValue(defaultScriptTypeContent[type]);
  };

  const onHandleTestExample = (status, example) => {
    if (status && example === ScriptTypeEnum.TRANSPORT_TCP_UP) {
      aceEditor.value?.setValue(defaultTestSubGatewayUpExample);
    } else {
      example === ScriptTypeEnum.TRANSPORT_TCP_UP
        ? aceEditor.value?.setValue(defaultTestUpExample)
        : aceEditor.value?.setValue(defaultTestAuthExample);
    }
    handleFormat();
  };

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

  const formRef = ref();

  const getFormData = async () => {
    const value = await formRef.value.validateFields();
    if (props.isNotTest) {
      scriptForm.convertJs = aceEditor.value.getValue();
      if (scriptForm.convertJs == '') return validateContentError();
    } else {
      scriptForm.script = aceEditor.value.getValue();
      if (scriptForm.script == '') return validateContentError();
    }
    if (!value) return;
    if (scriptForm.params) removeTrim(true, scriptForm.params);
    return {
      ...value,
      ...{ convertJs: props.isNotTest ? scriptForm.convertJs : null },
      ...{ script: !props.isNotTest ? scriptForm.script : null },
    };
  };

  const removeTrim = (status, e) => {
    //去除空格
    const value = status ? e : e.target.value;
    const trimParams = value.replace(/\s*/g, '');
    Reflect.set(scriptForm, 'params', trimParams);
  };

  const handleInputChange = (e) => removeTrim(false, e);

  const convertJsContent = ref('');

  const setFormData = (v) => {
    if (!v) return;
    for (let i in scriptForm) {
      Reflect.set(scriptForm, i, v[i]);
    }
    aceEditor.value.setValue(v.convertJs);
    convertJsContent.value = v.convertJs;
    handleFormat();
  };

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

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

  const handleFormat = () => {
    let oldValue = aceEditor.value?.getValue() || '';
    oldValue = oldValue.replaceAll(/;(\n+)?/g, ';\n');
    aceEditor.value?.setValue(oldValue);
    beautify(aceEditor.value.session);
  };

  const [registerModal, { openModal }] = useModal();

  const handleInnerTestClick = (text, innerTest) => {
    const getTestContent = aceEditor.value?.getValue();
    const modalParams = {
      innerTest,
      text,
      record: {
        convertJs: getTestContent,
        scriptType: scriptForm.scriptType,
      },
    };
    openModal(true, modalParams);
  };

  const setDisableRadio = (value) => {
    reportTypeOptions.scriptTypeOptions.forEach((item: any) => {
      if (item.value === value) item.disabled = false;
      else item.disabled = true;
    });
  };

  defineExpose({
    getFormData,
    resetFormData,
    setFormData,
    setScriptOutputData,
    setDefaultRadio,
    setDisableRadio,
  });
</script>
<style lang="less" scoped>
  .button-text {
    position: relative;
    top: -4rem;
    right: -6.6rem;
  }
</style>