Ant design combined with es7 syntax

a-table

 <a-table
          :columns="columns"
          :dataSource="rows"
          :pagination="pagination"
          rowKey="id"
          @change="getList"
          :scroll="{ x: '100%' }"
          :loading="loading"
          size="middle"
        >
          <template #name="record">
            {<!-- -->{ record.name }}
          </template>
          <template #action="record">
              <a-dropdown>
              <a class="ant-dropdown-link">
                More
                <a-icon type="down" />
              </a>
              <template #overlay>
                <a-menu @click="menuHandler($event, record)">
                  <a-menu-item key="auth" v-if="record.isCanSetUser">
                    Authorize other users
                  </a-menu-item>
                  <a-menu-item key="detail">
                    details
                  </a-menu-item>
                  <a-menu-item key="update">
                    edit
                  </a-menu-item>
                  <a-menu-item v-if="record.id !== 1" key="delete">
                    delete
                  </a-menu-item>
                  <a-menu-item key="copy">
                    copy
                  </a-menu-item>
                  <a-menu-item key="ping" v-if="record.status === 1">
                    ping
                  </a-menu-item>
                  <a-menu-item key="connect" v-if="record.status === 1">
                    test connection
                  </a-menu-item>
                  <a-menu-item
                    key="bindKey"
                    v-if="
                      record.authType === MACHINE_AUTH_TYPE.SECRET_KEY.value
                    "
                  >
                    bind key
                  </a-menu-item>
                  <!-- <a-menu-item key="openEnv">
                    <a @click="$router.push(`/machine/env/${record.id}`)"
                      >environment variables</a
                    >
                  </a-menu-item> -->
                  <a-menu-item key="openMonitor">
                    <a
                      @click="
                        $router.push(`/machine/monitor/metrics/${record.id}`)
                      "
                      >Machine Monitoring</a
                    >
                  </a-menu-item>
                </a-menu>
              </template>
            </a-dropdown>
          </template>
        </a-table>

const columns = [

{

title: “Serial Number”,

key: “seq”,

width: 65,

align: “center”,

customRender: (text, record, index) => `${index + 1}`

},

{

title: “Machine Information”,

key: “name”,

ellipsis: true,

scopedSlots: { customRender: “info” }

},

{

title: “Operation”,

key: “operation”,

fixed: “right”,

align: “center”,

width: 240,

scopedSlots: { customRender: “action” }

}

];

in the action bar corresponding to the

menuHandler({ key }, record) {

const handler = moreMenuHandler[key];

handler & amp; & amp; handler. call(this, record);

},

const moreMenuHandler = {

detail(record) {

this.$refs.detailModal.open(record.id);

},

update(record) {

this.$router.push(`/machine/update/${record.id}`);

},

delete(record) {

this.$confirm({

title: “Confirm Deletion”,

content: “Do you want to delete the current machine? All data associated with the machine will be deleted!”,

okText: “Confirm”,

okType: “danger”,

cancelText: “Cancel”,

onOk: () => {

this.$api

.deleteMachine({

idList: [record.id]

})

.then(() => {

this.$message.success(“Delete successfully”);

this. getList({});

});

}

});

},

copy(record) {

this.$confirm({

title: “Confirm Copy”,

content: `Do you want to copy machine ${record.name}?`,

okText: “Copy”,

cancelText: “Cancel”,

onOk: () => {

this.$api

.copyMachine({

id: record.id

})

.then(() => {

this.$message.success(“Copy successfully”);

this. getList();

});

}

});

},

bindKey(record) {

this.$refs.keyBindModal.open(record.id, record.keyId, record.name);

}

};

Form with checkmarks

computed: {

rowSelection() {

return {

selectedRowKeys: this. selectedRowKeys,

onChange: e => {

this.selectedRowKeys = e;

},

getCheckboxProps: record => ({

props: {

disabled: record.id === 1

}

})

};

}

},

Form tree (expand/collapse)

<a-table
          v-if="rows. length"
          :columns="columns"
          :data-source="rows"
          :pagination="false"
          rowKey="id" :defaultExpandAllRows="defaultExpandAllRows"
          :key="defaultExpandAllRows ? rows.length : 0"
          @change="getList"
          :scoll="{ x: '100%' }"
          :loading="loading"
          size="middle"
          childrenColumnName="childs"
        >
1. The reason for using v-if is to initialize and assign true to defaultExpandAllRows, which does not work;
2. Dynamically click the button to expand/collapse the tree, switching defaultExpandAllRows does not work; (the document states that it only takes effect at initialization); asynchronous loading and resetting rows does not work either;
3. Solution: Change the length of the list data through the value of defaultExpandAllRows; you can expand and collapse
4. childrenColumnName customizes the sub-array identified by the tree;

a-form

Combined with es7 syntax sugar v-decorator

<template>
  <a-modal
    v-model="visible"
    :title="title"
    :width="650"
    :okButtonProps="{ props: { disabled: loading } }"
    :maskClosable="false"
    :destroyOnClose="true"
    @ok="check"
    @cancel="close"
  >
    <a-spin :spinning="loading">
      <a-form :form="form" v-bind="layout">
        <a-form-item
          label="upper menu"
          v-show="form.getFieldValue('powerType') == '1'"
        >
          <a-tree-select
            v-decorator="[
              decorators. parentId,
              {
                initialValue: 0,
                rules: [
                  {
                    required:
                      form.getFieldValue('powerType') == '1' ? true : false,
                    message: 'Please select the upper menu'
                  }
                ]
              }
            ]"
            class="machine-input"
            tree-data-simple-mode
            style="width: 100%"
            :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
            :tree-data="treeList"
            placeholder="Please select the parent menu"
            :replaceFields="replaceFields"
            allowClear
            @select="onSelect"
          />
        </a-form-item>
        <a-form-item label="menu type">
          <a-radio-group
            name="radioGroup"
            :disabled="!!this.id"
            v-decorator="decorators.powerType"
          >
            <a-radio value="0">Directory</a-radio>
            <a-radio value="1">Menu</a-radio>
          </a-radio-group>
        </a-form-item>
        <a-form-item
          :label="
            form.getFieldValue('powerType') == '0' ? 'directory name' : 'menu name'
          "
          has Feedback
          name="name"
        >
          <a-input
            v-decorator="decorators.name"
            :placeholder="
              `Please enter ${
                form.getFieldValue('powerType') == '0' ? 'directory' : 'menu'
              }name`
            "
            showCount
            allowClear
          />
        </a-form-item>
        <a-form-item label="Sort">
          <a-input-number
            style="width:100%"
            id="inputNumber"
            :placeholder="
              `Please specify ${
                form.getFieldValue('powerType') == '0' ? 'directory' : 'menu'
              }location`
            "
            v-decorator="decorators.order"
            :max="1000"
          />
          <!-- <p>The larger the value, the higher the display order</p> -->
        </a-form-item>
        <a-form-item
          :label="
            form.getFieldValue('powerType') == '0' ? 'directory address' : 'menu address'
          "
          has Feedback
        >
          <a-input
            v-decorator="[
              decorators.path,
              {
                rules: [
                  {
                    required:
                      form.getFieldValue('powerType') == '1' ? true : false,
                    message: `Please enter ${
                      form.getFieldValue('powerType') == '0' ? 'directory' : 'menu'
                    }Address`
                  },
                  {
                    max: 100,
                    message: 'The length cannot be greater than 100 characters'
                  }
                ]
              }
            ]"
            :placeholder="
              `Please enter ${
                form.getFieldValue('powerType') == '0' ? 'directory' : 'menu'
              }Address`
            "
            allowClear
          />
          <p>Access routing address, such as: `/user`</p>
        </a-form-item>
        <a-form-item
          label="Redirect address"
          v-if="isTwoMenu & amp; & amp; form.getFieldValue('powerType') == '0'"
        >
          <a-input
            v-decorator="decorators. redirect"
            placeholder="Please enter redirect address"
            allowClear
          />
          <p>Breadcrumb redirect routing address, such as: `/test/user`</p>
        </a-form-item>
        <a-form-item label="Component path">
          <a-input
            v-decorator="[
              decorators.component,
              {
                initialValue:
                  form.getFieldValue('powerType') == '0' ? 'Layout' : ''
              }
            ]"
            placeholder="Please enter the component path"
            allowClear
          />
          <p v-if="form.getFieldValue('powerType') == '1'">
            The component path to access, such as: `system/user/index`, default in the `views` directory
          </p>
        </a-form-item>
      </a-form>
    </a-spin>
  </a-modal>
</template>

<script>
import { pick } from "lodash";
import { md5 } from "@/lib/utils";
import { ROLE_TYPE } from "@/lib/enum";

const layout = {
  labelCol: { span: 5 },
  wrapperCol: { span: 17 }
};
function getDecorators() {
  return {
    powerType: [
      "powerType",
      {
        initialValue: "0"
      }
    ],
    name: [
      "name",
      {
        rules: [
          {
            required: true,
            message: "Please enter a name"
          },
          {
            max: 32,
            message: "The length of the user name cannot be greater than 32 characters"
          }
        ]
      }
    ],
    path: ["path"],
    order: ["order"],
    parentId: ["parentId"],
    redirect: ["redirect"],
    component: ["component"]
  };
}

export default {
  name: "AddMenuModal",
  props: {
    treeList: {
      required: true,
      default: () => {}
    }
  },
  data: function() {
    return {
      ROLE_TYPE,
      id: null,
      visible: false,
      title: null,
      loading: false,
      record: null,
      layout,
      decorators: getDecorators. call(this),
      form: this. $form. createForm(this),
      isRoot: false,
      isTwoMenu: false,
      replaceFields: {
        children: "children",
        title: "name",
        key: "id",
        value: "id"
      }
    };
  },
  watch: {},
  mounted() {},
  methods: {
    add() {
      this.title = "New menu";
      this.initRecord({});
    },
    update(id) {
      this.title = "Modify menu";
      this.$api.getMenuDetail({ id }).then(({ data }) => {
        this.initRecord(data);
      });
    },
    addChildren(id) {
      this.title = "New menu";
      this.$api.getMenuDetail({ id }).then(({ data }) => {
        this.initRecord(data, "son");
      });
    },
    onSelect(value, node, extray) {
      console.log(extray.selectedNodes[0].data.props);
      let extraNode = extray.selectedNodes[0].data.props;
      this. treeHandleSelect(extraNode);
    },
    treeHandleSelect(node) {
      if (node.component == "Layout") {
        this.isTwoMenu = true;
      } else {
        this.isTwoMenu = false;
      }
      // if (node.id == "0" || node.id == undefined) {
      // this.isRoot = false;
      // this.isTwoMenu = false;
      // } else {
      // this.isRoot = true;
      // }
      //
      this. $nextTick(() => {
        this.form.setFieldsValue({
          parentId: node.id
        });
      });
    },
    async initRecord(row, val) {
      this.form.resetFields();
      this.visible = true;
      this.id = row.id;
      await this. treeHandleSelect(row);
      this. record = pick(
        Object. assign({}, row),
        "powerType",
        "name",
        "order",
        "path",
        "parentId",
        "component",
        "redirect"
      );
      if (val) {
        this.record = pick(Object.assign({}, row), "id");
      }
      this. $nextTick(() => {
        this.form.setFieldsValue(this.record);
      });
    },
    check() {
      this.loading = true;
      this.form.validateFields((err, values) => {
        if (err) {
          this.loading = false;
          return;
        }
        this. submit(values);
      });
    },
    async submit(values) {
      let res;
      try {
        if (!this.id) {
          // Add to
          let obj = {
            name: values.name,
            powerType: values. powerType,
            order: values.order || "",
            parentId: values.powerType == "0" ? 0 : values.parentId,
            path: values.path || "",
            component: values.component || "",
            redirect: values.redirect || ""
          };
          // console. log(obj);
          // values.password = md5(values.password);
          res = await this. $api. addMenu(obj);
        } else {
          // Revise
          res = await this. $api. updateMenu({
            ...values,
            id: this.id
          });
        }
        if (!this.id) {
          this.$message.success("Added successfully");
          this.$emit("added", res.data);
          this.$root.updateFlag = true;
        } else {
          this.$message.success("Modified successfully");
          this.$emit("updated", res.data);
          this.$root.updateFlag = true;
        }
        this. close();
      } catch (e) {
        this.$root.updateFlag = false;
        // ignore
      }
      this.loading = false;
    },
    close() {
      this.visible = false;
      this.loading = false;
    }
  }
};
</script>

<style scoped>
p {
  padding: 0;
  margin: 0;
  line-height: 12px;
  font-size: 12px;
  color: #cacdd4;
}
</style>
  1. When setting values for the form form, you cannot assign values directly, you need to combine

    this.form.setFieldsValue({ username: ‘set value’ })

  2. When the judgment condition is false, the dom will not render (use v-show instead, and combine this.$nextTick(() => { when assigning values)
    this.form.setFieldsValue({
    id: node.id
    });
    });
    //In order not to appear warning as follows
    It should be noted that the domain data declared by v-decorator must be used on the form (it can not be displayed on the page when used), otherwise an error will be reported
  3. Search bar menu binding, use: model form, using v-model will report an error
  4. Combined with the scene of a-radio, the corresponding form items and verification rules are different under different values; it is realized by inline
  5. When using an item in the form as an explicit or implicit condition; get it in the form of form.getFieldValue(‘powerType’);
  6. When using a-radio, an initial value is usually given; re-initialize the implementation of initialValue at the same level as the verification rule in the getDecorators() method of the form;
  7. The form item declared by v-decorator in the form must be used in the form (v-show=’false’); otherwise, an alarm will be generated when clicking OK

a-tree-select

v-decorator=”[
decorators. parentId,
{
initialValue: 0,
rules: [
{
required:
form.getFieldValue(‘menuType’) == ‘1’ ? true : false,
message: ‘Please select the upper menu’
}
]
}
]”
class=”machine-input”
tree-data-simple-mode
style=”width: 100%”
:dropdown-style=”{ maxHeight: ‘400px’, overflow: ‘auto’ }”
:tree-data=”treeList”
placeholder=”Please select the parent menu”
:replaceFields=”replaceFields”
allowClear
@select=”onSelect”
/>
1. replaceFields: {
children: “childs”,
title: “menuName”,
key: “id”,
value: “id”
}
Each must declare;
2. Since the id is used as the node identifier, the selected node can only get the node id
onSelect(value, node, extray) {
//Select all props of the node itself console.log(extray.selectedNodes[0].data.props);
let extraNode = extray.selectedNodes[0].data.props;
this. treeHandleSelect(extraNode);
},

Online editor for sql statement input

Plugin: vue2-ace-editor

Component Packaging

<template>
  <ace ref="editor"
       :value="value"
       :lang="lang"
       :width="width === 0 ? '100%' : width"
       :height="height === 0 ? '100%' : height"
       :theme="theme"
       :options="options"
       @init="initEditor"
       v-bind="config">
  </ace>
</template>

<script>

import ace from 'vue2-ace-editor'

export default {
  name: 'Editor',
  components: {
    ace
  },
  props: {
    value: {
      type: String,
      default: ''
    },
    width: {
      type: Number,
      default: 0
    },
    height: {
      type: Number,
      default: 0
    },
    readOnly: {
      type: Boolean,
      default: false
    },
    theme: {
      type: String,
      default: 'iplastic'
    },
    lang: {
      type: String,
      default: 'sh'
    },
    config: {
      type: Object,
      default: () => {
        return {
          enableLiveAutocompletion: true,
          fontSize: 16
        }
      }
    }
  },
  computed: {
    options() {
      return {
        enableBasicAutocompletion: true,
        enableSnippets: true,
        showPrintMargin: false,
        fontSize: this.config.fontSize,
        enableLiveAutocompletion: this.config.enableLiveAutocompletion,
        readOnly: this.readOnly
      }
    }
  },
  methods: {
    initEditor(editor) {
      require('brace/ext/language_tools')
      // language setting
      require('brace/mode/sh')
      require('brace/mode/json')
      require('brace/mode/xml')
      require('brace/mode/yaml')
      require('brace/mode/properties')
      require('brace/snippets/sh')
      require('brace/snippets/json')
      require('brace/snippets/xml')
      require('brace/snippets/yaml')
      require('brace/snippets/properties')
      // set the theme
      // light iplastic sqlserver tomorrow xcode
      // dark dracula gruvbox idle_fingers merbivore terminal tomorrow_night_bright
      require('brace/theme/iplastic')
      // listen for changes in value
      editor.getSession().on('change', () => {
        this.$emit('change', editor.getValue())
      })
    },
    getValue() {
      return this. $refs. editor. editor. getValue()
    },
    setValue(value) {
      this.$refs.editor.editor.session.setValue(value)
    },
    clear() {
      this.$refs.editor.editor.session.setValue('')
    }
  }
}
</script>

<style scoped>

</style>

Component Reference – Implementation Preview

<template>
  <a-modal v-model="visible"
           :width="650"
           :footer="null"
           :destroyOnClose="true"
           @close="close">
    <!-- editor -->
    <Editor v-bind="editorConfig" :value="value" :height="350" :readOnly="true"/>
    <!-- Title -->
    <template #title>
      <span>{<!-- -->{ title }}</span>
      <a @click="$copy(value)" title="Copy">
        <a-icon class="copy-icon-right" type="copy"/>
      </a>
    </template>
  </a-modal>
</template>

<script>
import Editor from '@/components/editor/Editor'

export default {
  name: 'EditorPreview',
  components: {
    Editor
  },
  props: {
    editorConfig: {
      type: Object,
      default: () => {
        return {}
      }
    },
    title: {
      type: String,
      default: 'Preview'
    }
  },
  data() {
    return {
      visible: false,
      value: null
    }
  },
  methods: {
    preview(value) {
      this.visible = true
      this.value = value
    },
    close() {
      this.visible = false
      this. value = null
    }
  }
}
</script>

<style scoped>

</style>

When used in the form, give the initial value undefined