首页 > 其他分享 >el-form封装

el-form封装

时间:2024-09-24 14:13:29浏览次数:11  
标签:el 封装 && form formData item formView key

<template>
  <el-form
    ref="elform"
    :model="formData"
    :inline="inline"
    :label-width="formLabelWidth"
    :size="size"
    v-bind="$attrs"
    :rules="rules"
    v-on="$listeners"
    @submit.native.prevent
  >
    <!-- {{ notebookAndModuleInfo }} -->
    <!-- {{ formWidth }} -->
    <!-- {{ autoLayout }}
    {{ isAutoComputedColumns }}
    {{ Object.keys(formView).length }}
    {{ columns }}
    {{ itemcolumns }} -->
    <!-- {{ checkboxMultiple }} -->
    <!-- {{ formView }} -->
    <!-- {{ formData }} -->
    <!-- {{ rules }} -->
    <!-- {{ proxyMethods }} -->
    <!-- {{ tableRowIndex }} -->
    <!-- {{ groupCodeOptions }} -->
    <draggable
      :group="dragGroup"
      animation="300"
      :scroll="true"
      @end="dragEnd"
      ghostClass="ghost"
      :disabled="!draggable"
      :class="[layoutClass, hiddenLabelClass, labelPosition ? `el-form--label-${labelPosition}` : '', dragFormClass]"
      :style="styleObj"
    >
      <!-- :label="item.itemlabel" -->
      <template v-for="(item, key) in formView">
        <el-form-item
          v-if="
            item.showInEditForm ||
            (typeof item.hidden === 'function'
              ? !item.hidden({
                  item,
                  formView,
                  formData,
                  editTableRowIndex,
                  tableRowIndex
                })
              : !item.hidden &&
                !hiddenKeys.includes(item.prop || key) &&
                !hiddenTypes.includes(item.itemtype) &&
                item?.itemAttr != 'hidden')
          "
          v-show="(item.showInEditForm || item.show) ?? true"
          :key="item.key || key"
          :prop="item.prop || key"
          :show-message="item.showMessage"
          :item-key="key"
          :label-width="item.labelWidth"
          :label="$t(item.itemlabel) || item.itemlabel"
          :readonly="item.readonly"
          :class="[
            {
              selectedFormItem: selectedKey === key,
              hiddenLabelClass: item.hiddenLabel,
              itemIsDisabled:
                typeof item.itemDisabled === 'function'
                  ? item.itemDisabled({
                      item,
                      formView,
                      formData,
                      editTableRowIndex,
                      tableRowIndex
                    })
                  : item.itemDisabled,
              contentOverHidden: ['Table'].includes(item.itemtype) ? true : false
            },
            item.itemClassName
          ]"
          @click.native.stop="
            handleClickFormItem({
              key,
              item,
              formView,
              formData,
              editTableRowIndex,
              tableRowIndex
            })
          "
          :style="[setStyle(item, key), item.itemStyle]"
        >
          <!-- TODO注意key和prop,要考虑具体绑定的值和验证的值在一些场景是否会区分 -->

          <!--TODO需要插件语法支持,默认为 :clearable="item.clearable ?? true" -->
          <!-- <template slot="label" v-if="!item.hiddenLabel">
            {{ item.itemlabel }}
          </template> -->
          <template #label v-if="item.customFormLabel">
            <div>
              <span>{{ item.itemlabel }}</span>
              <el-tooltip :content="item.formLabelContent" placement="top">
                <i class="el-icon-question" style="color: #e6a23c; margin-left: 2px" v-if="item.formLabelContent"></i>
              </el-tooltip>
            </div>
          </template>
          <span slot="label" v-if="item.clickable">
            <span :class="item.clickable ? 'clickable' : ''">{{ $t(item.i18nkey || item.itemlabel) || ' ' }}</span>
          </span>
          <!-- ReadonlyInput类型仅仅用来展示,需要配合bindkey一起使用 -->
          <el-input
            v-if="item.itemtype === 'ReadonlyInput'"
            v-model="formData[item.bindkey]"
            v-bind="item"
            v-on="item"
            :placeholder="$t(item.placeholder || `${$t('请输入')} ${$t(item.label || item.itemlabel || '')}`)"
            :title="formData[item.bindkey] ?? ''"
          >
          </el-input>
          <el-input
            v-else-if="item.itemtype === 'Input'"
            :maxlength="item.verify && !item?.needMaxLength ? false : item.maxlength || 255"
            :show-word-limit="item.showWordLimit === false || !item.maxlength ? false : true"
            ref="formInput"
            :id="item?.ref || 'formInput'"
            v-model="formData[key]"
            v-bind="item"
            v-on="item"
            v-verify="item.verify"
            :clearable="item.clearable ?? true"
            :readonly="item?.readonly || item?.isReadonlyInputView"
            @clear="handleClear"
            @click.native="clickHandler(key, item)"
            @keyup.enter.native="keyupEnterHandler(key, item)"
            :placeholder="
              $t(
                item.placeholder ||
                  `${showPlaceholderPrefix ? $t('请输入') : ''} ${$t(item.label || item.itemlabel || '')}`
              )
            "
            :title="item.itemlabel && !item.itemlabel.includes('密码') && formData[key] ? formData[key] : ''"
            :class="item.showWordLimit === false || !item.maxlength ? '' : 'showWordLimitInput'"
          >
            <component :is="item.prefix" slot="prefix" v-if="item.prefix"></component>
            <component :is="item.suffix" slot="suffix" v-if="item.suffix"></component>
            <component
              :is="item.prepend"
              slot="prepend"
              v-if="item.prepend"
              v-bind="item.prependAttrs"
              v-on="item.prependListeners"
            ></component>
            <component :is="item.append" slot="append" v-if="item.append"></component>
            <template v-if="item.child">
              {{ typeof item.child === 'function' ? item.child({ key, formData, itemConfig: item }) : item.child }}
            </template>
            <template slot="append" v-if="item.appendTemplate">
              {{
                typeof item.appendTemplate === 'function'
                  ? item.appendTemplate({ key, formData, itemConfig: item })
                  : item.appendTemplate
              }}
            </template>
          </el-input>
          <el-input
            v-else-if="item.itemtype === 'Password'"
            v-model="formData[key]"
            type="password"
            autocomplete="new-password"
            :maxlength="item.verify ? false : item.maxlength || 255"
            :show-word-limit="item.showWordLimit === false || !item.maxlength ? false : true"
            :placeholder="$t(item.placeholder || `${$t('请输入')} ${$t(item.label || item.itemlabel || '')}`)"
          >
            <!--            <i style="cursor: pointer; line-height: 30px" slot="suffix" :class="iconClass" @click="showPwd(key)"></i>-->
          </el-input>
          <toggle-password v-else-if="item.itemtype === 'TogglePassword'" v-model="formData[key]" v-bind="item">
          </toggle-password>
          <el-button
            v-else-if="item.itemtype === 'Button'"
            v-bind="item"
            :menuCode="item.menuCode"
            :disabled="
              typeof item.disabled === 'function'
                ? item.disabled({
                    item,
                    formView,
                    formData,
                    editTableRowIndex,
                    tableRowIndex
                  })
                : item.disabled
            "
            @click="item.click({ key, tableRowIndex, tableColIndex, formData })"
          >
            {{
              typeof item.buttonText === 'function'
                ? item.buttonText({ key, tableRowIndex, tableColIndex, formData })
                : $t(item.buttonText)
            }}
          </el-button>
          <template v-else-if="item.itemtype === 'NativeFile'">
            <!-- <input type="file" @change="item.change && item.change($event)" class="nativeFile" /> -->
            <input
              ref="nativeFile"
              type="file"
              id="nativeFile"
              style="display: none"
              @change="nativeFileChange(item, $event)"
            />
            <input ref="nativeFileName" id="nativeFileName" readonly />
            <input
              type="button"
              :value="$t('选择文件')"
              style="border-radius: 2px; padding: 0 4px; margin-left: 6px"
              @click="nativeFileClick"
            />
          </template>

          <template v-else-if="item.itemtype === 'Autocomplete'">
            <el-autocomplete
              v-bind="item"
              v-on="item"
              v-model="formData[key]"
              :title="formData[key]"
              @select="changeAutoComplete()"
            >
              <template slot-scope="{ item }">
                <span>{{ item.label || item.value }}</span>
              </template>
            </el-autocomplete>
          </template>
          <template v-else-if="item.itemtype === 'CustomAutocomplete'">
            <customAutocomplete
              :formData="formData"
              :itemkey="key"
              :formItem="item"
              v-model="formData[key]"
              :title="formData[key]"
            >
            </customAutocomplete>
          </template>

          <el-input
            v-else-if="item.itemtype === 'SelectInput'"
            v-model="formData[key]"
            v-bind="item"
            v-on="item"
            v-verify="item.verify"
            clearable
            @clear="handleClear"
            :placeholder="$t(item.placeholder || `${$t('请输入')} ${$t(item.label || item.itemlabel || '')}`)"
            :title="formData[key]"
          >
            <!-- ReadonlyInput类型仅仅用来展示,需要配合bindkey一起使用 -->
            <template v-if="item.selectConfig.itemtype === 'ReadonlyInput'">
              <span :slot="item.selectConfig.slot || 'append'">{{ formData[item.selectConfig.bindkey] }}</span>
            </template>
            <template v-else>
              <el-select
                v-if="item.selectConfig"
                v-model="formData[item.selectConfig.prop]"
                :slot="item.selectConfig.slot || 'append'"
                :style="[{ minWidth: '80px' }, item.selectConfig.itemStyle]"
                :placeholder="$t('请选择')"
                v-bind="item.selectConfig"
                @clear="handleClear(item, key)"
                @change="handleChangeSelectInput(item.selectConfig, item.selectConfig.prop)"
              >
                <el-option
                  v-for="(selitem, index) in item.selectConfig.groupCode
                    ? groupCodeOptions[item.selectConfig.groupCode]
                    : item.selectConfig.options"
                  :key="index"
                  :label="selitem.label"
                  :value="selitem[item.selectConfig.bindValueField || 'value' || 'label']"
                  :disabled="selitem.disabled"
                  @click.native="handleSelect(selitem, key, item)"
                ></el-option>
              </el-select>
            </template>
          </el-input>

          <template v-else-if="item.itemtype === 'Select'">
            <div
              v-if="item.multiple"
              v-selectloadmore="item.infiniteScrollMethods ? item.infiniteScrollMethods : ''"
              style="width: 100%; display: grid"
            >
              <el-select
                v-model="checkboxMultiple[key]"
                v-bind="item"
                v-on="item"
                :collapse-tags="item.collapseTags ? true : false"
                ref="SelectMultiple"
                :placeholder="$t(item.placeholder || `${$t('请选择')} ${$t(item.label || item.itemlabel || '')}`)"
                :clearable="item.clearable ?? true"
                :filterable="item.filterable ?? true"
                :title="renderTitle('select', { key, item })"
                @clear="handleClear(item, key)"
              >
                <li
                  class="el-select-dropdown__item"
                  :class="{
                    selected: selmultiAll(key, 2),
                    optionBtnType: item.optionBtnType
                  }"
                  style="user-select: none"
                  v-if="item.multiple"
                  @click="selmultiAll(key, 1, item, item.groupCode ? groupCodeOptions[item.groupCode] : item.options)"
                >
                  <span>{{ selmultiAll(key, 2) ? $t('全不选') : $t('全选') }}</span>
                </li>
                <template v-if="item.slotTitle">
                  <li v-html="item.slotTitle" class="el-select-dropdown__item" style="user-select: none"></li>
                </template>
                <el-option
                  v-for="(selitem, index) in item.groupCode ? groupCodeOptions[item.groupCode] : item.options"
                  :key="selitem.value + index"
                  :label="selitem.label"
                  :value="selitem[item.bindValueField || 'value' || 'label']"
                  :disabled="selitem.disabled ?? (selitem.optionDisabled && selitem.optionDisabled(selitem))"
                  @click.native="
                    selectOptionsRow(
                      key,
                      selitem,
                      item,
                      item.groupCode ? groupCodeOptions[item.groupCode] : item.options
                    )
                  "
                >
                  <div v-if="item.slotHtml" v-html="item.slotHtml(selitem)"></div>
                </el-option>
              </el-select>
            </div>

            <div
              v-else
              v-selectloadmore="item.infiniteScrollMethods ? item.infiniteScrollMethods : ''"
              style="width: 100%; display: grid"
            >
              <el-select
                @focus="handleFocus(item, key)"
                :ref="'selectSingle' + key"
                v-model="formData[key]"
                v-bind="item"
                v-on="item"
                :placeholder="$t(item.placeholder || `${$t('请选择')} ${$t(item.label || item.itemlabel || '')}`)"
                :clearable="item.clearable ?? true"
                :filterable="item.filterable ?? true"
                :title="renderTitle('select', { key, item })"
                @clear="handleClear(item, key)"
                :bindKey="key"
                @filter-change="handleFilterChange"
                @visible-change="item.shouldInput ? selectFocus(key) : item.visibleChange"
              >
                <template v-if="item.slotTitle">
                  <li v-html="item.slotTitle" class="el-select-dropdown__item" style="user-select: none"></li>
                </template>
                <template v-if="item.customOption">
                  <li
                    :style="item.customOption.style || ''"
                    @click="item.customOption.click && item.customOption.click($refs['selectSingle' + key][0])"
                  >
                    <span> {{ item.customOption.label }} </span>
                  </li>
                  <el-option
                    v-if="
                      typeof item.options === 'function'
                        ? item.options(key, formData, formView) && item.options(key, formData, formView).length === 0
                        : item.options && item.options.length === 0
                    "
                    style="height: 0"
                    :value="''"
                    @click.native="selectOptionsRow(key, selitem, item)"
                  ></el-option>
                </template>

                <el-option
                  v-for="(selitem, index) in typeof item.options === 'function'
                    ? item.options(key, formData, formView)
                    : item.groupCode
                    ? groupCodeOptions[item.groupCode]
                    : item.options"
                  :key="key + index"
                  :optionData="selitem"
                  :filterVal="selectFilterObj[key]"
                  :customFilterMethod="item.customFilterMethod"
                  :label="selitem[item.bindLabelField || 'label' || 'value']"
                  :value="selitem[item.bindValueField || 'value' || 'label']"
                  :disabled="selitem.disabled"
                  @click.native="selectOptionsRow(key, selitem, item)"
                >
                  <span v-if="selitem.html" v-html="selitem.html"></span>
                  <div v-if="item.slotHtml" v-html="item.slotHtml(selitem)"></div>
                </el-option>
              </el-select>
            </div>
          </template>

          <!-- todo支持多选和下拉多选返回的值的类型,数组或者逗号隔开的字符串 -->
          <template v-else-if="item.itemtype === 'Checkbox'">
            <span
              v-if="item?.class === 'custom_check_box' || item?.class === 'custom_label'"
              :style="{ 'font-size': '12px', color: formData[key] ? 'red' : '' }"
              >{{ formData[key] ? $t('是') : $t('否') }}</span
            >
            <el-checkbox
              v-else
              v-model="formData[key]"
              v-bind="item"
              v-on="item"
              :title="formData[key]"
              :disabled="
                typeof item.disabled === 'function'
                  ? item.disabled({
                      item,
                      formView,
                      formData,
                      editTableRowIndex,
                      tableRowIndex
                    })
                  : item.disabled
              "
            >
              {{ item.label }}
            </el-checkbox>
          </template>
          <el-checkbox-group
            v-else-if="item.itemtype === 'CheckboxGroup'"
            v-model="checkboxMultiple[key]"
            v-bind="item"
            v-on="item"
            :title="formData[key]"
          >
            <template v-if="checkboxMultiple[key]">
              <el-checkbox
                v-for="(checkitem, checkboxindex) in item.options"
                :label="checkitem.value"
                :disabled="checkitem.disabled"
                :key="checkboxindex"
              >
                {{ checkitem.label }}
              </el-checkbox>
            </template>
          </el-checkbox-group>

          <el-radio-group
            v-else-if="item.itemtype === 'Radio'"
            v-model="formData[key]"
            v-bind="item"
            v-on="item"
            :title="formData[key]"
          >
            <el-radio
              v-for="(radioItem, index) in getSelectOptions(item, item.params)"
              :label="radioItem.value"
              :key="index"
            >
              {{ $t(radioItem.label) }}
            </el-radio>
          </el-radio-group>

          <el-switch
            v-else-if="item.itemtype === 'Switch'"
            v-model="formData[key]"
            v-bind="item"
            style="width: min-content"
            v-on="item"
            :title="formData[key]"
          ></el-switch>

          <el-date-picker
            v-else-if="item.itemtype === 'DatePicker'"
            :type="item.type || 'date'"
            :value-format="item.format || 'yyyy-MM-dd'"
            :placeholder="$t(item.placeholder) || $t('请选择日期')"
            :start-placeholder="$t('开始日期')"
            :end-placeholder="$t('结束日期')"
            v-model="formData[key]"
            v-bind="item"
            v-on="item"
            :title="formData[key]"
            :picker-options="item.pickerOptions ?? datePickerOptions"
            @clear="handleClear"
          ></el-date-picker>

          <el-date-picker
            v-else-if="item.itemtype === 'DateTimePicker'"
            :type="item.type || 'datetime'"
            :value-format="item.format || 'yyyy-MM-dd'"
            :placeholder="item.placeholder || $t('请选择日期')"
            v-model="formData[key]"
            v-bind="item"
            v-on="item"
            :title="formData[key]"
            :picker-options="item.pickerOptions ?? datePickerOptions"
            @clear="handleClear"
          ></el-date-picker>

          <el-time-picker
            v-else-if="item.itemtype === 'TimePicker'"
            :placeholder="item.placeholder || $t('请选择时间')"
            :value-format="item.format || 'HH:mm:ss'"
            v-model="formData[key]"
            v-bind="item"
            v-on="item"
            :title="formData[key]"
            @clear="handleClear"
          ></el-time-picker>

          <el-button-group v-else-if="item.itemtype === 'ButtonGroup'">
            <el-button
              v-for="(buttonItem, buttonIndex) in item.options"
              @click="formData[key] = buttonItem.value"
              :type="formData[key] == buttonItem.value ? item.checkedType || 'primary' : buttonItem.type"
              :key="buttonIndex"
              :title="formData[key]"
            >
              {{ buttonItem.label }}
            </el-button>
          </el-button-group>

          <el-dropdown v-else-if="item.itemtype === 'Dropdown'" v-bind="item" v-on="item">
            <span class="el-dropdown-link"> {{ item.text }}<i class="el-icon-arrow-down el-icon--right"></i> </span>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item v-for="dropdownItem in item.options" :key="dropdownItem.label || dropdownItem.value">
                {{ dropdownItem.label || dropdownItem.value }}
              </el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>

          <el-input
            v-else-if="item.itemtype === 'Textarea'"
            type="textarea"
            show-word-limit
            :rows="item.rows || 3"
            v-model="formData[key]"
            v-bind="item"
            v-on="item"
            :title="formData[key]"
            :placeholder="$t(item.placeholder || `${$t('请输入')} ${$t(item.label || item.itemlabel || '')}`)"
          />

          <el-input-number
            v-else-if="item.itemtype === 'InputNumber' && !item.isNativeAction"
            v-model="formData[key]"
            v-bind="item"
            v-on="item"
            :title="formData[key]"
            @clear="handleClear"
            :max="item.max || 1000000000"
          ></el-input-number>
          <el-input-number
            v-else-if="item.itemtype === 'InputNumber' && item.isNativeAction"
            v-model="formData[key]"
            v-bind="item"
            :title="formData[key]"
            @input.native="item.input"
            :max="item.max || 1000000000"
            @clear="handleClear"
          ></el-input-number>

          <el-divider v-else-if="item.itemtype === 'Divider'" v-bind="item"
            ><span v-html="item.content"></span
          ></el-divider>

          <selectTree
            v-else-if="item.itemtype === 'SelectTree'"
            v-bind="item"
            v-on="item"
            :formData="formData"
            v-model="formData[key]"
            :data="item.groupCode ? getSelectOptions(item) : item.data"
          ></selectTree>
          <el-color-picker
            v-else-if="item.itemtype === 'ColorPicker'"
            v-bind="item"
            v-on="item"
            v-model="formData[key]"
          ></el-color-picker>
          <!-- <el-upload v-else-if="item.itemtype === 'Upload'" class="my-el-upload" v-bind="item" v-on="item">
            <span style="cursor:pointer" class="el-icon-upload2"></span>
            <div slot="tip" class="el-upload__tip" v-if="item.tip">{{ item.tip }}</div>
          </el-upload> -->
          <custom-file
            v-else-if="item.itemtype === 'CustomFile'"
            v-bind="item"
            v-on="item"
            v-model="formData[key]"
          ></custom-file>

          <upload-file
            v-else-if="item.itemtype === 'UploadFile'"
            v-bind="item"
            v-on="item"
            v-model="formData[key]"
          ></upload-file>

          <page-select
            v-else-if="item.itemtype === 'PageSelect'"
            style="width: 100%"
            v-bind="item"
            v-on="item"
            :modelval.sync="formData[key]"
            :formData="formData"
          ></page-select>

          <mingdu-form
            v-else-if="item.itemtype === 'SlotForm'"
            class="slotform"
            :form-data="item.formData ? formData[item.formData] : formData"
            :form-view="item.formView"
            v-bind="item.slotFormConfig"
            ref="SlotForm"
          ></mingdu-form>

          <template v-else-if="item.itemtype === 'Table'">
            <mingdu-table v-bind="item" :data="formData[key]" v-on="item" :ref="key + 'Mdtable'"></mingdu-table>
          </template>
          <!-- 配置选项 -->
          <template v-else-if="item.itemtype === 'ConfigOptions'">
            <config-options v-model="formData[key]"></config-options>
          </template>
          <template v-else-if="item.itemtype === 'TableConfigOptions'">
            <table-config-options v-model="formData[key]"></table-config-options>
          </template>
          <template v-else-if="item.itemtype === 'CustomElement'">
            <slot
              v-if="item.slotName"
              :name="item.slotName"
              :form-item="item"
              :form-data="formData"
              :prop-name="key"
            ></slot>
            <div
              v-else-if="item.html"
              v-html="
                typeof item.html === 'function'
                  ? item.html({
                      formItem: item,
                      formView,
                      formData,
                      propName: key
                    })
                  : item.html
              "
            ></div>
            <component
              :formItem="item"
              :formView="formView"
              :formData="formData"
              :propName="key"
              v-on="item.emitMethods"
              v-bind="item"
              :is="item.component"
              v-else-if="item.component"
            ></component>
            <component
              :scope="{ formItem: item, formView, formData, propName: key }"
              v-bind="item"
              :is="
                typeof item.render === 'function'
                  ? handleRendel(item.render, {
                      formItem: item,
                      formView,
                      formData,
                      propName: key
                    })
                  : item.render
              "
              v-else-if="item.render"
            ></component>
          </template>
          <el-input
            class="dialogSelect"
            v-else-if="item.itemtype === 'DialogSelect'"
            v-model="formData[`${key}_label`]"
            v-bind="item"
            v-on="item"
            @focus="openSelectDialog(item, key)"
            @input="inputDialogSelect($event, item, key)"
            id="dialogSelectInput"
            :placeholder="$t(item.placeholder || `${$t('请选择')} ${$t(item.label || item.itemlabel || '')}`)"
          >
            <el-button
              slot="append"
              icon="el-icon-circle-close"
              v-if="!item.required"
              @click="dialogSelectClear(item, key)"
            ></el-button>
            <el-button
              slot="append"
              icon="el-icon-folder-opened"
              v-if="item.shouldInput"
              @click="openSelectDialog(item, key, 'click')"
            ></el-button>
          </el-input>
          <!-- 仅显示文本 -->
          <span v-else-if="item.itemtype === 'Text'" :class="item.class || ''">{{
            item.formatter && typeof item.formatter === 'function'
              ? item.formatter(formData[key], {
                  formItem: item,
                  formView,
                  formData,
                  propName: key
                })
              : formData[key]
          }}</span>
          <span v-else>{{ formData[key] }}</span>
          <el-button
            v-if="selectedKey === key"
            @click.stop="deleteSelectedKeyEvent(key)"
            class="deleteSelectedKey"
            type="danger"
            icon="el-icon-delete"
          ></el-button>
        </el-form-item>
      </template>
      <slot name="rightContent"></slot>
      <!-- <el-button type="primary" style="width: 100px" v-if="formKey" @click="$saveFormView(formView, formKey)"
        >保存表单配置</el-button
      > -->
    </draggable>
    <!-- 选择用户 -->
    <SelectUser
      ref="refSelectUser"
      :defaultCheckedList="defaultCheckedUserList"
      @on-select="handleSelectUser"
    ></SelectUser>
    <!--    库位选择-->
    <location-select ref="locationSelect" @locationInfo="getLocationInfo"></location-select>
  </el-form>
</template>
<script>
import { formItemRules } from './js/form-rules.js'
import mixin from '../mixins/commonUi.js'
import draggable from 'vuedraggable'
import ConfigOptions from './basicComponent/config-options.vue'
import TableConfigOptions from './basicComponent/table-config-options.vue'
import { cloneDeep } from 'lodash'
import selectTree from './basicComponent/selectTree'
import CustomFile from '@/components/customFileUpload/index.vue'
import uploadFile from '@/components/uploadFile'
import PageSelect from './basicComponent/pageSelect.vue'
import customAutocomplete from './basicComponent/myCustomAutocomplete.vue'
import togglePassword from './basicComponent/myPassword.vue'
// import { createRulesBasicPage } from '@/util/validate';
import { optionsConfigs } from '@/common/getBasicDate.js'
import { nanoid } from 'nanoid'
import i18n from '@/lang'
import { mapGetters } from 'vuex'

function validateEmpty(message = '') {
  return function (rule, value, callback) {
    // console.log('validate Empty= >', value)
    typeof value === 'string' && value !== '' && value.trim() === ''
      ? callback(message || i18n.t('请勿全部输入空格'))
      : callback()
  }
}

const validatorRange = function ({ type = 'text', min = 0, max = 0, data = {}, required = false }) {
  const { itemtype, value, options } = data

  // 判断表单项是否必填
  if (required === false && (value === '' || value === undefined)) {
    return { success: true }
  }

  if (itemtype === 'Select') {
    // const option = (options ?? []).find((item) => item.value === value)
    // const len = `${option?.label ?? ''}`.length
    // if (len < min || len > max) {
    //   const message = `请选择长度【${min}~${max}】的数据`
    //   return { success: false, message }
    // } else {
    //   return { success: true }
    // }
    return { success: true }
  } else if (itemtype === 'Input' || itemtype === 'SelectInput') {
    if (type === 'text') {
      const len = `${value ?? ''}`.length
      if (len >= min && len <= max) {
        return { success: true }
      } else {
        const message = `请输入长度【${min}~${max}】的字符`
        return { success: false, message }
      }
    } else if (type === 'number') {
      const nValue = Number(value)
      if (isNaN(nValue)) {
        return { success: false, message: i18n.t('请输入正确的数字') }
      } else if (value !== '' && value !== '0' && /^[0]+$/.test(nValue)) {
        return { success: false, message: i18n.t('请勿输入全为0的数字') }
      } else if (nValue >= min && nValue <= max) {
        return { success: true }
      } else {
        const message = i18n.t('请输入范围【{0}~{1}】的{2}', [min, max, '数字'])
        return { success: false, message }
      }
    }
  } else {
    return { success: true }
  }
}

export default {
  inheritAttrs: false,
  name: 'MdForm',
  mixins: [mixin],
  components: {
    draggable,
    ConfigOptions,
    TableConfigOptions,
    selectTree,
    CustomFile,
    PageSelect,
    uploadFile,
    customAutocomplete,
    SelectUser: () => import('@/components/selectUser'),
    locationSelect: () => import('@/components/locationSelect'),
    togglePassword
  },
  props: {
    /**
     * 表单绑定的值
     *@param {paraName}
     */
    formData: {
      type: Object,
      default: () => ({})
    },
    // 用于查询条件时,去掉值为undefined null 和空字符串的数据
    searchData: {
      type: Object,
      default: () => ({})
    },
    // 表单是否可拖动
    draggable: {
      type: Boolean,
      default: false
    },
    // 拖动时的group名
    dragGroup: {
      type: String,
      default: ''
    },
    formKey: {
      type: String,
      default: ''
    },
    isUpdateCustomLabel: {
      type: Boolean,
      default: true
    },
    formView: {
      type: Object,
      default: () => ({})
    },
    inline: {
      type: Boolean,
      default: false
    },
    size: {
      type: String,
      default: 'small'
    },
    // label的宽度
    labelWidth: {
      type: [String, Number],
      default: '104px'
    },
    layoutClass: {
      // 可维护多种备选布局方式
      type: String,
      default: 'default-layout'
    },
    labelPosition: {
      // left right top
      type: String,
      default: 'right'
    },
    formColumns: {
      // 默认共12列,
      type: Number,
      default: 12
    },
    columns: {
      // 默认每个表单组件所占的列数,
      type: Number,
      default: 12
    },
    updateClearValidate: {
      // 默认更新view会校验表单
      type: Boolean,
      default: true
    },
    isAutoComputedColumns: {
      // 是否自动计算columns
      type: Boolean,
      default: true
    },
    // 是否自适应布局
    autoLayout: {
      type: Boolean,
      default: false
    },
    formItemMinWidth: {
      // form-item的最小宽度
      type: Number,
      default: 0
    },
    selectedKey: {
      type: [Number, String],
      default: ''
    },
    // 设置表单可拖动时的样式名
    dragFormClass: {
      type: String,
      default: ''
    },
    // 隐藏表单的所有label
    hiddenLabel: {
      type: Boolean,
      default: false
    },
    // 隐藏某些 form-item
    hiddenKeys: {
      type: Array,
      default: () => []
    },
    // 隐藏某些类型的表单
    hiddenTypes: {
      type: Array,

      default: () => []
    },
    // 列间距
    columnGap: {
      type: [Number, String],
      default: 6
    },
    // 行间距
    rowGap: {
      type: [Number, String],
      default: 16
    },
    editTableRowIndex: {
      // 当用于表格中的单元格的表单的时候的编辑行的索引
      type: [Number, String],
      default: -1
    },
    tableRowIndex: {
      // 当用于表格中的单元格的表单的时候的行索引
      type: [Number, String],
      default: -1
    },
    tableColIndex: {
      // 当用于表格中的单元格的表单的时候的行索引
      type: [Number, String],
      default: -1
    },
    editFormType: {
      // left right top
      type: Number,
      default: 1
    },
    showPlaceholderPrefix: {
      //placeholder前缀
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      refsName: 'elform',
      proxyMethodsArr: ['validate', 'validateField', 'resetFields', 'clearValidate'],
      checkboxMultiple: {}, // 代理多选框组数据
      formWidth: null,
      rules: {},
      formDataBackup: {},
      focusElement: null,
      selectAuto: true,
      selectOptions: {}, // 记录选择框的选项的行数据
      groupCodeOptions: {}, // 存储groupCode对应的options选项,可以直接通过groupCodeOptions['groupCode']渠道缓存的选项值
      selectFilterObj: {},
      datePickerOptions: {
        disabledDate(time) {
          return (
            time.getTime() <= new Date('1900-01-01 00:00:00').getTime() ||
            time.getTime() >= new Date('2073-12-30 23:59:59').getTime()
          )
        }
      },
      defaultCheckedUserList: [], // 已选择的用户
      currentFocusData: {} //记住当前操作数据
    }
  },
  inject: {
    notebookAndModuleInfo: {
      default: {}
    }
  },
  watch: {
    autoLayout: {
      handler(val) {
        // window.removeEventListener('resize', this.onResize)
        // console.log('%c 第372行', 'color:red;font-size:2em')
        // console.log(val)

        if (val) {
          // this.$nextTick(() => {
          // window.addEventListener('resize', this.onResize)
          // this.onResize()
          // })
        }
      },
      immediate: true
    }
  },
  created() {
    // this.rewriteEventMethods()
  },
  beforeMount() {
    this.initConfig()
  },
  mounted() {
    // console.log('%c 第839行 mounted', 'color:red;font-size:2em')
    // console.log(this.formView)
    this.$watch(
      () => {
        return this.formView
      },
      async () => {
        if (!this.formView) {
          return
        }
        console.log('表单json变化')
        await this.queryGroupCodeOptions().then(async (res) => {
          this.initFormItemConfig()
          this.initConfig()
          await this.rewriteEventMethods()
        })
      },
      { deep: true, immediate: true }
    )
    this.$watch(
      () => {
        return this.formData
      },
      (val) => {
        let changeField = null
        let searchData = {}
        Object.keys(this.formData).forEach((i) => {
          let v = this.formData[i]
          if (
            this.formView &&
            this.formView[i] &&
            (this.formView[i].type === 'Number' || this.formView[i].verify === 'integer')
          ) {
            const nVal = isNaN(Number(v)) || Number(v) === 0 ? '' : Number(v)
            this.$set(this.formData, i, nVal)
          }
          if (this.formView && this.formView[i]) {
            // console.log('2222', this.editFormType)
            //修改的时候调接口查询对应中文名
            if (
              this.formView[i].itemtype === 'DialogSelect' &&
              (this.formView[i].dialogType === 'selectUser' || this.formView[i].dialogType === 'selectLocation') &&
              this.editFormType == 2 &&
              !this.formView[i].shouldInput
            ) {
              if (this.formData.hasOwnProperty(i)) {
                if (!isNaN(this.formData[i])) {
                  //数字类型 为userid
                  this.$request.getUserInfoListById([this.formData[i]]).then((res) => {
                    let data = res?.data
                    this.$set(this.formData, i + '_label', data[this.formData[i]])
                  })
                } else {
                  if (this.formView[i].dialogType === 'selectLocation') {
                    this.$set(
                      this.formData,
                      i + '_label',
                      this.formData[this.formView[i]['linkSetField']] ||
                        this.formData[this.formView[i]['labelShowField']] ||
                        this.formData[i]
                    )
                  } else {
                    this.$set(this.formData, i + '_label', this.formData[i])
                  }
                }
              }
            }
          }
          if (v !== undefined && v !== null && v !== '' && !(Array.isArray(v) && v.length === 0)) {
            searchData[i] = v
          }
          if ((v || this.formDataBackup[i]) && JSON.stringify(v) !== JSON.stringify(this.formDataBackup[i])) {
            changeField = i
          }
        })
        this.$emit('update:searchData', searchData)
        // 不用失焦而是立即执行的input类型
        let inputTypes = ['Radio']
        if (
          document.activeElement &&
          document.activeElement !== document.body &&
          !this.focusElement &&
          !inputTypes.includes(this.formView[changeField]?.itemtype)
        ) {
          if (this.$refs.elform.$el.contains(document.activeElement)) {
            this.focusElement = document.activeElement
            this.focusElement.addEventListener('blur', this.elementBlur) // 只能监听部分类型的失去焦点事件,一些类型的数据改变应当立即抛出时间
          }
        } else {
          let types = ['Switch', 'DatePicker', 'DateTimePicker'].concat(inputTypes)

          if (changeField && types.includes(this.formView[changeField]?.itemtype)) {
            this.elementBlur()
          }
        }
        this.formDataBackup = cloneDeep(val)
        // if (this.notebookAndModuleInfo?.formUsedToExperimentNotebook) {
        // 	// 当表单用于实验记录页面的时候,监听数据变化,在离开实验记录页面的时候保存数据
        // 	this.$store.commit('record/SET_VALUECHANGE', true)
        // }
      },
      { deep: true, immediate: true }
    )

    if (this.autoLayout) {
      window.addEventListener('resize', this.onResize)
      this.onResize()
    }
    if (this.draggable) {
      document.addEventListener('click', this.documentClick)
    }
  },
  directives: {
    selectloadmore: {
      bind(el, binding) {
        if (binding.value) {
          const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
          SELECTWRAP_DOM.addEventListener('scroll', function () {
            const CONDITION = this.scrollHeight - this.scrollTop <= this.clientHeight
            if (CONDITION) {
              binding.value()
            }
          })
        }
      }
    }
  },
  methods: {
    findForm(el) {
      if (el.parentNode.tagName === 'FORM') {
        return el.parentNode
      } else {
        return this.findForm(el.parentNode)
      }
    },
    initConfig() {
      try {
        if (!this.isUpdateCustomLabel) {
          return
        }
        // console.log('formKey', this.formKey)
        let tarConfig = (this.sysFormConfig || {})[this.formKey] // 获取当前模块配置

        console.log('tarConfig', tarConfig)
        if (tarConfig) {
          for (let key in this.formView) {
            let configView = tarConfig[key]
            if (!configView) continue
            if (configView.itemCustomLabel) {
              this.formView[key].itemlabel = configView.itemCustomLabel
            }
            if (configView.itemAttr === 'required') {
              this.$set(this.formView[key], 'required', true)
            }
            if (configView.itemAttr === 'disabled') {
              this.formView[key].disabled = true
            }
            if (configView.itemAttr === 'readonly') {
              this.formView[key].readonly = true
            }
            if (configView.itemAttr === 'hidden') {
              this.formView[key].show = false
            }
            if (configView.itemAttr === 'normal') {
              this.$set(this.formView[key], 'required', false)
            }
            if (configView?.itemAttr != 'hidden') {
              if (this.formView[key].hasOwnProperty('itemAttr')) {
                delete this.formView[key].itemAttr
              }
              // this.$set(this.formView[key], 'itemAttr', '')
            }
          }
        }
      } catch {}
    },
    nativeFileClick() {
      this.$refs.nativeFile[0].click()
    },
    nativeFileChange(item, e) {
      this.$refs.nativeFileName[0].value = e.target.files[0].name
      item.change && item.change(e)
    },
    inputDialogSelect(e, item, key) {
      if (item.dialogType === 'selectUser') {
        this.$set(this.formData, key, e)
      }
    },
    openSelectDialog(data, key, type = 'focus') {
      this.currentFocusData = Object.assign({}, data, { key: key }) //记住当前操作数据
      if (data.dialogType === 'selectUser') {
        //选择用户组件
        if (type === 'focus' && data.shouldInput) return
        let dataList = Number(this.formData[key]) ? [Number(this.formData[key])].map((item) => ({ userId: item })) : []
        this.defaultCheckedUserList = this.formData.hasOwnProperty(key) ? dataList : []
        console.log('this.defaultCheckedUserList', this.defaultCheckedUserList)
        this.$refs.refSelectUser.show()
        //手动失焦,为了解决键盘输入还是会输入值在输入框中
        if (type === 'focus') {
          let formInput = document.getElementById('dialogSelectInput')
          formInput && formInput.blur()
        }
      } else if (data.dialogType === 'selectLocation') {
        if (type === 'focus' && data.shouldInput) return
        this.$refs.locationSelect.show()
      }
    },
    dialogSelectClear(data, key) {
      this.currentFocusData = Object.assign({}, data, { key: key }) //记住当前操作数据
      const item = this.currentFocusData
      if (data.dialogType === 'selectUser' || data.dialogType === 'selectLocation') {
        this.$set(this.formData, key, '')
        this.$set(this.formData, `${key}_label`, '')
        if (item.linkSetField) {
          // 需要关联的设置的值
          if (typeof item.linkSetField === 'string') {
            this.$set(this.formData, item.linkSetField, '')
          }
          if (typeof item.linkSetField === 'object') {
            // console.log('%c 第1228行', 'color: red; font-size: 2em')
            // console.log(item)
            this.$set(this.formData, item.linkSetField.setField, '')
          }

          if (Array.isArray(item.linkSetField)) {
            item.linkSetField.forEach((oItem) => {
              this.$set(this.formData, oItem.setField, '')
            })
          }
        }
        //选择用户组件
        item.change && item.change('')
        console.log('formData', this.formData)
      }
    },
    handleSelectUser(user = {}) {
      const item = this.currentFocusData
      let row = {
        label: user.userName,
        value: user.id,
        account: user.account,
        userCode: user.userCode,
        info: user
      }
      let value = row[item['bindValueField'] || 'value' || 'label']
      let key = item.key
      this.$set(this.formData, key, value)
      console.log('row, ', row)
      this.$set(this.formData, `${key}_label`, row.label)
      console.log('formDatahandleSelectUser', this.formData)
      if (item.linkSetField) {
        // 需要关联的设置的值
        if (typeof item.linkSetField === 'string') {
          this.$set(this.formData, item.linkSetField, row[item.linkSetFieldBindKey] || row.label)
        }
        if (typeof item.linkSetField === 'object') {
          // console.log('%c 第1228行', 'color: red; font-size: 2em')
          // console.log(item)
          this.$set(this.formData, item.linkSetField.setField, row[item.linkSetField.bindField] || row.label)
        }

        if (Array.isArray(item.linkSetField)) {
          item.linkSetField.forEach((oItem) => {
            this.$set(this.formData, oItem.setField, row[oItem.bindField])
          })
        }
      }
      item.afterSelect &&
        item.afterSelect({
          value: this.formData[key],
          key,
          formView: this.formView,
          formData: this.formData,
          selectOption: row
        })
    },
    getLocationInfo(data) {
      if (!data) return
      // console.log('getLocationInfo-data---------', data)
      const item = this.currentFocusData
      let row = {
        label: data.name,
        showName: data.name,
        value: data.id,
        info: data
      }
      let value = row[item['bindValueField'] || 'value' || 'label']
      // console.log('item', item, row, value)
      let key = item.key
      this.$set(this.formData, key, value)
      this.$set(this.formData, `${key}_label`, row.label)
      if (item.linkSetField) {
        // 需要关联的设置的值
        if (typeof item.linkSetField === 'string') {
          this.$set(this.formData, item.linkSetField, row.label)
        }
        if (typeof item.linkSetField === 'object') {
          // console.log('%c 第1228行', 'color: red; font-size: 2em')
          // console.log(item)
          this.$set(this.formData, item.linkSetField.setField, row[item.linkSetField.bindField] || row.label)
        }

        if (Array.isArray(item.linkSetField)) {
          item.linkSetField.forEach((oItem) => {
            this.$set(this.formData, oItem.setField, row[oItem.bindField])
          })
        }
      }
      if (item.recordSelectedRowInfo) {
        this.$set(this.formData, item.recordSelectedRowInfo, row)
      }
      item.afterSelect &&
        item.afterSelect({
          value: this.formData[key],
          key,
          formView: this.formView,
          formData: this.formData,
          selectOption: row
        })
    },
    renderTitle(type = '', data = {}) {
      // console.log('render title =>', type, data)
      let title = ''
      if (type === 'select') {
        const { key, item } = data
        const array = (item.groupCode ? this.groupCodeOptions[item.groupCode] : item.options) ?? []
        const options = typeof item.options === 'function' ? item.options(key, this.formData, this.formView) : array

        if (Array.isArray(options)) {
          const value = this.formData[key]
          const values = Array.isArray(value) ? value : [value]
          const matched = options.filter((e) => values.includes(e.value))
          title = matched.map((e) => e?.label ?? '').join('、')
        }
      }

      return title
    },
    handleFilterChange(filter, key) {
      this.$set(this.selectFilterObj, key, filter)
    },
    /**
     * formItem 点击时触发
     * @param { String } key formItem对应的key值
     * @param { Object } item formItem对应的项目
     * @param { Object } formView formView数据
     * @param { Object } formData formData数据
     */
    handleClickFormItem({ key, item, formView, formData }) {
      // console.log(key, item, formView, formData)
      this.draggable ? this.updateSelectedKey(key) : null

      if (item.clickable) {
        this.$emit('itemClick', { key, item, formView, formData })
      }
    },
    changeAutoComplete() {
      // console.log('changeAutoComplete')
      // 选中后让输入框失焦,不然下拉的数据可能还在
      document.body.click()
    },
    clickHandler(key, item) {
      typeof item.click === 'function' && item.click(key, item)
    },
    keyupEnterHandler(key, item) {
      typeof item.enterSearch === 'function' && item.enterSearch(item)

      this.$emit('enter', { key, itemData: item })
    },
    keydownHandler(e, key, item) {
      if (item.type === 'number') {
        let keyCode = e.keyCode
        if (keyCode === 69) {
          //数字类型输入框禁止输入e
          e.returnValue = false
          return false
        }
        return true
      }
    },
    handleClear(item, key) {
      console.log('

标签:el,封装,&&,form,formData,item,formView,key
From: https://www.cnblogs.com/yibottlec/p/18429037

相关文章

  • 基于RHEL 9 搭建 KVM 虚拟化环境
    一、准备工作1.检查硬件虚拟化支持KVM要求处理器支持硬件虚拟化技术:IntelVT-x(虚拟化技术扩展)或AMD-V(虚拟化技术扩展)。检查方法:使用以下命令检查CPU是否支持虚拟化:egrep'(vmx|svm)'/proc/cpuinfo输出含有vmx的为Intel处理器支持虚拟化输出含有svm的为A......
  • 【工具】Java Excel转图片
    【工具】JavaExcel转图片packagecom.yj.luban.modules.office.excel;importorg.apache.poi.ss.usermodel.*;importorg.apache.poi.xssf.usermodel.XSSFWorkbook;importjavax.imageio.ImageIO;importjava.awt.Color;importjava.awt.Font;importjava.awt.*;importj......
  • 回归预测 | Matlab实现SSA-HKELM麻雀算法优化混合核极限学习机多变量回归预测
    回归预测|Matlab实现SSA-HKELM麻雀算法优化混合核极限学习机多变量回归预测目录回归预测|Matlab实现SSA-HKELM麻雀算法优化混合核极限学习机多变量回归预测效果一览基本介绍程序设计参考资料效果一览基本介绍1.Matlab实现SSA-HKELM麻雀算法优化混合核极限学习机多变量回归预......
  • 创新首发!LightGBM+BO-Transformer-GRU多变量回归交通流量预测(Matlab)
    创新首发!秋日私语!LightGBM+BO-Transformer-GRU多变量回归交通流量预测(Matlab)目录创新首发!秋日私语!LightGBM+BO-Transformer-GRU多变量回归交通流量预测(Matlab)效果一览基本介绍程序设计参考资料效果一览基本介绍1.Matlab实现LightGBM+BO-Transformer-GRU多变量回归预测,LightGB......
  • 论文速递 | 基于MIC-ICEEMD-RIME-DHKELM的碳排放预测模型研究
    目录参考文献内容介绍作者擅长碳排放预测模型参考文献内容介绍本文提出了一种基于最大信息系数(MIC)特征提取、改进互补集合经验模态分解(ICEEMD)、雾凇优化算法(RIME)与深度混合核极限学习机(DHKELM)的建筑业碳排放量预测模型。首先,根据IPCC计算方法,从直接和间接两个方面测算1992-202......
  • 2024年JCR一区极光优化算法+分解对比!VMD-PLO-Transformer-BiLSTM多变量时间序列光伏功
    中秋献礼!2024年中科院一区极光优化算法+分解对比!VMD-PLO-Transformer-LSTM多变量时间序列光伏功率预测目录中秋献礼!2024年中科院一区极光优化算法+分解对比!VMD-PLO-Transformer-LSTM多变量时间序列光伏功率预测效果一览基本介绍程序设计参考资料效果一览基本介绍1.中秋献礼!2024年......
  • DsExcel,GcExcel .NET 7.2.2 Crack
    DsExcel,GcExcel.NET 高速C#.NETExcel电子表格API库Excel文档解决方案(DsExcel,以前称为GcExcel).NET版本允许您使用此快速电子表格API在C#.NET6+、.NETCore、.NETFramework和Xamarin跨平台应用程序中以编程方式创建、编辑、导入和导出Excel电子表格。......
  • 父子Shell你了解多少?一起解读吧
    一.source和点、bash\sh、./script区别1.source和点,执行脚本,只在当前shell环境中执行生效2.指定bash\sh解释器运行脚本,是开启subshell,开启子shell运行脚本 命令3../script,都会指定shebang,通过解释器运行,也是开启subshell运行命令 二.父Shell的概念pstree|--s......
  • Anaconda创建虚拟环境失败Malformed version string ‘~‘: invalid character(s)
     notepad%USERPROFILE%\.condarccondacreate-npy38python=3.8TRANSLATEwithxEnglishArabicHebrewPolishBulgarianHindiPortugueseCatalanHmongDawRomanianChineseSimplifiedHungarianRussianChineseTraditionalIndonesian......
  • DATA1002 / 1902 - Informatics: Data and Computation
    DATA1002/1902-Informatics:DataandComputation2024Sem2GroupProjectStage2THEPROJECTWORKFORSTAGE2:Task            Description           Group/individual            Details1 ......