【el-cascader 级联选择器】懒加载 - 适用新增、编辑表单(编辑表单有初始数据)

目录

  • 代码
  • 效果

代码

constant/formList.js

export const operationFormDesc = (_this) => {
  return {
    rule: {
      type: 'cascader',
      label: '违规情况',
      layout: 12,
      required: true,
      attrs: {
        'collapse-tags': true,
        props: {
          lazy: true,
          // multiple: true,
          /** ** 【主要代码】懒加载 ****/
          lazyLoad: (node, resolve) => {
            /**
             * 【懒加载 - 当前应用场景】
             *    当前表单项支持新增、修改, "违规情况" 是一个级联选择器
             *    级联选择器(懒加载):
             *      1. 一级列表(level: 0):规则大类(从字典获取)
             *      2. 二级列表(level: 1):规则子类(根据一级列表当前值调用接口获取)
             *
             * 【新增 - 懒加载】
             *    二级列表的数据根据接口获取
             *
             * 【编辑 - 懒加载 】
             *    1. 首先获取详情数据回显:回显数据时,由于懒加载,当前二级列表是没有数据,所以需要根据一级列表当前值调用接口获取二级列表数据(如果一级数据有值,就会自动根据当前一级数据调用接口获取对应的二级数据列表 ----- 【注意】前提是先有的一级数据(初始数据),再有的一级列表,才会自动获取二级数据);
             *    2. form 表单详情接口调用完之后,获取到初始数据,然后渲染级联选择器一级数据 → 懒加载自动调用获取二级数据列表接口;
             *    3. 但是不知道为啥会调用两次二级数据接口,所以 用 ruleFirstClickList 将已经调用过二级数据列表的一级数据存起来,判断一下,如果当前一级数据已经调用过二级数据列表,resolve 返回空数组。
             *
             */
            const { level, data } = node
            if (level === 0) {
              /**
               * 获取规则大类(一级列表)
               * 取字典数据
               */
              const nodes = (_this.$common.getDic('rule_first') || []).map((item) => {
                return {
                  value: item.value,
                  label: item.label,
                  leaf: false
                }
              })

              /**
               * 【弹框 - 编辑场景】
               *    - 侦听 isGetDetailEnd 是否结束(即:详情接口是否调用完成 - 获取到初始数据)
               *    - 结束后再 resolve 返回字典列表数据 nodes
               */
              if (_this.dialogType === 'edit') {
                const timer = setInterval(() => {
                  if (_this.isGetDetailEnd) {
                    // 根据 isGetDetailEnd 判断详情接口是否调用完成
                    resolve(nodes)
                    clearInterval(timer)
                  }
                }, 100)
                return
              }
              
              /**
               * 【弹框 - 非编辑场景 - 即新增场景】
               *    - 直接返回字典列表数据 nodes
               */
              resolve(nodes)
            } else if (level === 1) {
             /**
              * 【获取二级列表数据】
              *    - 调用接口
              */
              getRuleSecondList(data.value).then((res) => {
                _this.$common.CheckCode(res, null, () => {
                  const nodes =
                    res.data?.map((item) => {
                      return {
                        value: item.dmbh,
                        label: item.dmmc,
                        leaf: true
                      }
                    }) || []
                  _this.ruleSecondOptions && _this.ruleSecondOptions.push(...nodes) // 将二级数据列表推入二级数据列表数组中,便于翻译(当行代码与当前文章无关,可不看)

	             /**
	              * 【弹框 - 编辑场景】
	              *    - 已经加载过二级数据的一级数据,resolve 返回空数组
	              */
                  resolve(
                    _this.dialogType === 'edit' && _this.ruleFirstClickList.includes(data.value)
                      ? []
                      : nodes // 其他情况 resolve 接口返回数据
                  )

                  /**
	              * 【弹框 - 编辑场景】
	              *    - 将已经加载过二级数据的一级数据 push 到 ruleFirstClickList 数组中
	              */
                  if (_this.dialogType === 'edit') {
                    _this.ruleFirstClickList.push(data.value)
                  }
                })
              })
            } else {
              resolve([])
            }
          }
        }
      }
    }
  }
}

index.vue


<template>
  <el-dialog
    :title="title"
    :visible.sync="dialogVisible"
    width="60%"
    top="8vh"
    :before-close="handleClose"
    :close-on-click-modal="dialogType === 'detail'"
  >
    <ele-form
      ref="submitRef"
      inline
      form-btn-size="mini"
      :disabled="dialogType === 'detail'"
      :form-data="formData"
      :form-desc="formDesc"
      :is-show-back-btn="false"
    />

    <span v-if="dialogType !== 'detail'" slot="footer" class="dialog-footer">
      <el-button type="primary" size="mini" @click="submitHandler"> 提交 el-button>
      <el-button size="mini" @click="handleClose">关闭el-button>
    span>
  el-dialog>
template>

<script>
import { mapGetters } from 'vuex'
import _ from 'lodash.clonedeep'
import { addScore, editScore, getScore } from '@/api/twelve-points'
import { operationFormDesc } from '../constant/formList'

export default {
  name: 'OperationDialog',
  components: {},

  props: {},

  data() {
    return {
      dialogVisible: false,
      dialogType: '',
      rowData: {},
      formData: {
        rule: []
      },
      detailInfo: {},
      ruleSecondOptions: [],
      ruleFirstClickList: [],
      isGetDetailEnd: false,
      editFirst: false,
      editRuleFirst: false
    }
  },

  computed: {
    ...mapGetters(['glbmOptions', 'sysConfigData']),
    title() {
      const obj = {
        add: '新增记分',
        edit: '修改记分',
        detail: '记分详情'
      }
      return obj[this.dialogType]
    },
    formDesc() {
      return this.dialogVisible ? operationFormDesc(this) : {}
    },
    submitAx() {
      const obj = {
        add: addScore,
        edit: editScore
      }
      return obj[this.dialogType]
    }
  },

  watch: {
    dialogVisible() {
      this.$refs.submitRef &&
        this.$refs.submitRef.$refs.form &&
        this.$refs.submitRef.$refs.form.clearValidate()
    }
  },

  created() {},

  methods: {
    open(type, rowData = {}) {
      this.rowData = _(rowData)
      this.dialogType = type
      if (type !== 'add') {
        this.getDetail(rowData.jfbh)
      }
      this.dialogVisible = true
    },
    getDetail(jfbh) {
      getScore(jfbh)
        .then((res) => {
          this.$common.CheckCode(res, null, () => {
            this.detailInfo = res.data || {}
            const { data = {} } = res
            this.editFirst = true
            for (const key in this.formDesc) {
              if (key === 'sjfssjStr') {
                this.$set(this.formData, key, data['sjfssj'])
              } else if (['rule'].includes(key)) {
                const arr = [data.ruleFirst, data.ruleSecond]
                this.$set(this.formData, 'rule', arr)
              } else {
                this.$set(this.formData, key, data[key])
              }
            }

            this.editFirst = false
            this.editRuleFirst = true
          })
        })
        .finally(() => {
          this.isGetDetailEnd = true
        })
    },

    submitHandler() {
      this.$refs.submitRef.validate().then((valid) => {
        this.$confirm('确认提交记分?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        })
          .then(() => {
            const { jfdwView, jfrView, ...params } = this.formData
            const { jfbh, jfdw, jfr } = this.detailInfo

            if (this.dialogType === 'edit') {
              params.jfbh = jfbh
              params.jfdw = jfdw
              params.jfr = jfr
            }

            this.submitAx(params).then((res) => {
              this.$common.CheckCode(res, '提交成功', () => {
                this.$emit('update')
                this.handleClose()
              })
            })
          })
          .catch(() => {
            this.$message('取消提交')
          })
      })
    },
    handleClose() {
      this.rowData = {}

      this.ruleSecondOptions = []
      this.ruleFirstClickList = []
      this.isGetDetailEnd = false

      this.editFirst = false
      this.editRuleFirst = false

      for (const key in this.formData) {
        if (this.formData[key] && this.formData[key].constructor === Array) {
          this.formData[key] = []
        } else if (this.formData[key] && this.formData[key].constructor === Object) {
          this.formData[key] = {}
        } else {
          this.formData[key] = ''
        }
      }
      this.dialogVisible = false
    }
  }
}
script>

<style lang='scss' scoped>
@import '@/styles/dialog-scss.scss';
style>

效果

你可能感兴趣的:(elementUI,vue,代码记录,vue.js,javascript,前端)