“Free and open source” drag and drop form customization of the background management system of the crudapi zero code development platform, a front-end spa project based on Vue and Quasar (16)

Time:2022-6-5

Drag and drop form customization of front-end spa project based on Vue and Quasar (16)

review

Pass the previous articleDynamic form of front-end spa project practice based on Vue and Quasar (V)It realizes the dynamic form design function in metadata, supports common data types and indexes, and then realizes the crud addition, deletion, modification and query function of dynamic forms. All form pages are in the default style. This article mainly introduces the drag and drop form customization function, which can customize the form entry and editing pages by dragging to meet the personalized needs.

brief introduction

For each field in the metadata table, you can determine whether to display or hide it by dragging, and then you can configure the display width. Finally, it is saved to the background database in JSON format. When running, it dynamically renders the input and edit form form page according to the configuration. It can be customized for different devices (computers, tablets, mobile phones).

UI interface


Page construction


Runtime

code

explain

It adopts the open source framework vuesortable, implements sorting based on Vue, and supports drag and drop. Page construction is divided into three parts: left, middle and right. The left is the candidate field, the middle is the field to be displayed, and the right can set some properties for each field, such as width.

data sheet

Create a form tableformbuilder to store page construction JSON data, including type, device device, content body and other fields. Make full use of the crudapi function, and the API part is implemented in zero code.


tableFormBuilder

Core code

Page construction
<draggable
  class="dragArea list-group row"
  :list="selectedList"
  group="people"
  @change="log"
>
  <div class="list-group-item q-pa-md" 
    v-for="formElement in selectedList"
    :key="formElement.columnId"
    :class="formElement | classFormat(currentElement)"
    @click="selectForEdit(formElement)"
  > 
    <div>
      <div 
        v-bind:class="{ 'required': !formElement.column.nullable}">
        {{formElement.column.caption}}:
      </div>
      <q-input v-if="isStringType(formElement)"
        readonly
        :placeholder="formElement.column.description"
        :type="formElement.isPwd ? 'password' : 'text'"
        v-model="formElement.column.value" >
        <template v-slot:append v-if="!formElement.isText" >
          <q-icon
            :name="formElement.isPwd ? 'visibility_off' : 'visibility'"
            class="cursor-pointer"
            @click="formElement.isPwd = !formElement.isPwd"
          />
        </template>
      </q-input>

      <q-editor readonly v-else-if="isTextType(formElement)"
        v-model="textValue"
        :placeholder="formElement.column.description" >
      </q-editor>

      <q-input v-else-if="isDateTimeType(formElement)" readonly>
        <template v-slot:prepend>
          <q-icon name="event" class="cursor-pointer">
            <q-popup-proxy ref="qDateProxy" transition-show="scale" transition-hide="scale">
              <q-date
              mask="YYYY-MM-DD HH:mm:ss"
              @input="hideRefPopProxyAction('qDateProxy')" />
            </q-popup-proxy>
          </q-icon>
        </template>

        <template v-slot:append>
          <q-icon name="access_time" class="cursor-pointer">
            <q-popup-proxy ref="qTimeProxy" transition-show="scale" transition-hide="scale">
              <q-time mask="YYYY-MM-DD HH:mm:ss"
              format24h with-seconds
              @input="hideRefPopProxyAction('qTimeProxy')" />
            </q-popup-proxy>
          </q-icon>
        </template>
      </q-input>

      <q-input v-else-if="isDateType(formElement)" readonly>
        <template v-slot:append>
          <q-icon name="event" class="cursor-pointer">
            <q-popup-proxy ref="qDateProxy" transition-show="scale" transition-hide="scale">
              <q-date
              mask="YYYY-MM-DD"
              @input="hideRefPopProxyAction('qDateProxy')" />
            </q-popup-proxy>
          </q-icon>
        </template>
      </q-input>

      <q-input v-else-if="isTimeType(formElement)" readonly>
        <template v-slot:append>
          <q-icon name="access_time" class="cursor-pointer">
            <q-popup-proxy ref="qTimeProxy" transition-show="scale" transition-hide="scale">
              <q-time  mask="HH:mm:ss"
              format24h with-seconds
              @input="hideRefPopProxyAction('qTimeProxy')" />
            </q-popup-proxy>
          </q-icon>
        </template>
      </q-input>

      <q-toggle v-else-if="isBoolType(formElement)" readonly
        v-model="formElement.column.value">
      </q-toggle>

      <q-input readonly
        v-else-if="isNumberType(formElement)"
        :placeholder="formElement.column.description"
        type="number"
        v-model="formElement.column.value" >
      </q-input>

      <CFile v-else-if="isAttachmentType(formElement)"
        v-model="formElement.column.value" >
      </CFile>

      <q-input v-else
        readonly
        :placeholder="formElement.column.description"
        :type="formElement.isPwd ? 'password' : 'text'"
        v-model="formElement.column.value" >
        <template v-slot:append v-if="!formElement.isText" >
          <q-icon
            :name="formElement.isPwd ? 'visibility_off' : 'visibility'"
            class="cursor-pointer"
            @click="formElement.isPwd = !formElement.isPwd"
          />
        </template>
      </q-input>
    </div>
    <div class="row reverse editable-element-action-buttons">
      <div class="justify-end q-pt-xs">
        <q-btn 
          @click="deleteElement(formElement)"
          v-if="isSelectedForEdit(formElement)" 
          class="editable-element-button" 
          color="red" 
          icon="delete" 
          round unelevated  size="xs">
          <q-tooltip> remove </q-tooltip>
        </q-btn>
      </div>
    </div>
  </div>
</draggable>

Implemented by draggable tag

Runtime rendering
<div v-if="selectedList.length > 0" class="row">
  <div class="list-group-item q-pa-md" 
    v-for="formElement in selectedList"
    :key="formElement.columnId"
    :class="formElement | classFormat">
    <div>
      <div 
        v-bind:class="{ 'required': !formElement.column.nullable}">
        {{formElement.column.caption}}:
      </div>

      <div class="row items-baseline content-center"
        style="border-bottom: 1px solid rgba(0,0,0,0.12)" 
        v-if="formElement.column.relationTableName">
        <div class="col-11">
          <span>{{ formElement.column.value | relationDataFormat(formElement.column) }}</span>
        </div>
        <div class="col-1">
          <q-btn round dense flat icon="zoom_in" 
          @click="openDialogClickAction(formElement.column)" />
        </div>
      </div>

      <q-input v-else-if="isStringType(formElement.column.dataType)"
        v-model="formElement.column.value"
        :placeholder="formElement.column.description"
        :type="formElement.isPwd ? 'password' : 'text'" >
        <template v-slot:append v-if="!formElement.isText" >
          <q-icon
            :name="formElement.isPwd ? 'visibility_off' : 'visibility'"
            class="cursor-pointer"
            @click="formElement.isPwd = !formElement.isPwd"
          />
        </template>
      </q-input>

      <q-editor  v-else-if="isTextType(formElement.column.dataType)"
        v-model="formElement.column.value"
        :placeholder="formElement.column.description" >
      </q-editor>

      <q-input v-else-if="isDateTimeType(formElement.column.dataType)"
        v-model="formElement.column.value" >
        <template v-slot:prepend>
          <q-icon name="event" class="cursor-pointer">
            <q-popup-proxy ref="qDateProxy" transition-show="scale" transition-hide="scale">
              <q-date v-model="formElement.column.value"
              mask="YYYY-MM-DD HH:mm:ss"
              @input="hideRefPopProxyAction('qDateProxy')" />
            </q-popup-proxy>
          </q-icon>
        </template>

        <template v-slot:append>
          <q-icon name="access_time" class="cursor-pointer">
            <q-popup-proxy ref="qTimeProxy" transition-show="scale" transition-hide="scale">
              <q-time  v-model="formElement.column.value"
              mask="YYYY-MM-DD HH:mm:ss"
              format24h with-seconds
              @input="hideRefPopProxyAction('qTimeProxy')" />
            </q-popup-proxy>
          </q-icon>
        </template>
      </q-input>

       <q-input v-else-if="isDateType(formElement.column.dataType)" 
        v-model="formElement.column.value">
        <template v-slot:append>
          <q-icon name="event" class="cursor-pointer">
            <q-popup-proxy ref="qDateProxy" transition-show="scale" transition-hide="scale">
              <q-date  v-model="formElement.column.value"
              mask="YYYY-MM-DD"
              @input="hideRefPopProxyAction('qDateProxy')" />
            </q-popup-proxy>
          </q-icon>
        </template>
      </q-input>

      <q-input v-else-if="isTimeType(formElement.column.dataType)"
       v-model="formElement.column.value" >
        <template v-slot:append>
          <q-icon name="access_time" class="cursor-pointer">
            <q-popup-proxy ref="qTimeProxy" transition-show="scale" transition-hide="scale">
              <q-time   v-model="formElement.column.value" 
              mask="HH:mm:ss"
              format24h with-seconds
              @input="hideRefPopProxyAction('qTimeProxy')" />
            </q-popup-proxy>
          </q-icon>
        </template>
      </q-input>

      <q-toggle v-else-if="isBoolType(formElement.column.dataType)"
       v-model="formElement.column.value" >
      </q-toggle>

      <q-input 
        v-else-if="isNumberType(formElement.column.dataType)"
        v-model="formElement.column.value"
        :placeholder="formElement.column.description"
        type="number">
      </q-input>

      <CFile v-else-if="isAttachmentType(formElement.column.dataType)"
       v-model="formElement.column.value"
       @input="(data)=>{
        formElement.column.value = data.url;
       }"></CFile>

      <q-input v-else
        v-model="formElement.column.value"
        :placeholder="formElement.column.description"
        :type="formElement.isPwd ? 'password' : 'text'" >
        <template v-slot:append v-if="!formElement.isText" >
          <q-icon
            :name="formElement.isPwd ? 'visibility_off' : 'visibility'"
            class="cursor-pointer"
            @click="formElement.isPwd = !formElement.isPwd"
          />
        </template>
      </q-input>
    </div>
  </div>
</div>

Determine whether there is a customized page. If there is dynamic rendering, otherwise, the default page layout is used.

example

Take the product as an example. After the entry page is configured, the original default entry page is replaced by a new page. The new form page is consistent with the previously configured form page. The function is not affected and data can be entered normally.

Summary

In this paper, the form customization function is realized by dragging and dropping. It is very convenient to use. The form entry and editing pages are customized with zero code, which meets the personalized needs. The whole process does not need to write code.

Introduction to crudapi

Crudapi is a combination of crud+api, which means adding, deleting, modifying and querying interfaces. It is a zero code configurable product. Using crudapi can bid farewell to the tedious addition, deletion, modification and query of code, so that you can focus more on business, save a lot of costs, and improve work efficiency. The goal of crudapi is to make it easier to process data, and everyone can use it for free! No programming is required. The crud is automatically generated through configuration. The addition, deletion, modification and query restful API provides background UI management business data. Based on the mainstream open source framework, it has independent intellectual property rights and supports secondary development.

Demo demo

Crudapi is a product level zero code platform, which is different from the automatic code generator. It does not need to generate business codes such as controller, service, repository and entity. It can be used when the program is running. The real 0 code can cover the basic business independent crud restful API.

Official website address:https://crudapi.cn
Test address:https://demo.crudapi.cn/crudapi/login

Source code address attached

GitHub address

https://github.com/crudapi/crudapi-admin-web

Gitee address

https://gitee.com/crudapi/crudapi-admin-web

Due to network reasons, GitHub may be slow. Just visit gitee and update the code synchronously.