【Vue】可编辑表格与三级联动下拉

需求是给员工分配岗位,设计上是一人多岗的存在...

单位 —— 部门 —— 岗位 这样的层级

功能效果:

因为员工可以在不同的单位下任职岗位,所以这个每一个岗位都是一个独立

查询单位列表是固定的,但是每个单位下的部门不是固定的,每个单位下的部门下的岗位也是不一样的

每一行的下拉列表都是独立维护的

 

这种表格是和表单在一起的,所以存储逻辑是,直接清空以前的记录,根据提交的这份重新写库保存

 

可编辑表格的校验还是可以通过Form表单校验,TableData放在form表单对象里面

校验的prop属性是关联TableData的下标元素属性这样实现的,rules校验对象也是单独设置

注意下拉列表引用的集合都是下标元素里的(如果不是这样的联动列表,可以共用...)

<template>
  <div>
    <el-form :ref="formRef" :model="form" :rules="rules" label-width="135px" :inline="true" label-position="top" size="small">
      <div class="location2">
        <span style="font-weight: bolder">{{ form.emName + ' ' + form.emPhone }}</span>
        <span>
          <svg-icon icon-class="tj-icon" class="tj-icon" style="margin-right: 10px" @click="newEditRow" />
          <svg-icon icon-class="sc-icon" class="tj-icon" @click="deleteEditRow" />
        </span>
      </div>

      <div>
        <el-table :ref="editableTableRef" v-loading="loading" size="small" stripe highlight-current-row :data="form.tableData" :row-class-name="rowClassName" :row-style="rowStyle" @row-click="rowClick" @selection-change="handleSelectionChange">
          <el-table-column align="center" type="index" width="50px" label="序号" />
          <el-table-column prop="sysArCoId" min-width="160px" align="left" label="所属公司">
            <template slot-scope="sc">
              <el-form-item size="mini" :prop=" `tableData.${sc.$index}.sysArCoId` " :rules="rules.sysArCoId" :style="inputStyle">
                <el-select v-model="sc.row.sysArCoId" :style="inputStyle" clearable placeholder="请选择" @change="selectCorpChange(sc.$index, sc.row)">
                  <el-option v-for="item in sc.row.corpList" :key="item.id" :label="item.coName" :value="item.id" />
                </el-select>
              </el-form-item>
            </template>
          </el-table-column>
          <el-table-column prop="sysArDeId" min-width="160px" align="left" label="所属部门">
            <template slot-scope="sc">
              <el-form-item size="mini" :prop=" `tableData.${sc.$index}.sysArDeId` " :rules="rules.sysArDeId" :style="inputStyle">
                <el-select v-model="sc.row.sysArDeId" :style="inputStyle" clearable placeholder="请先选择所属公司" @change="selectDeptChange(sc.$index, sc.row)">
                  <el-option v-for="item in sc.row.deptList" :key="item.sysArDeId" :label="item.deName" :value="item.sysArDeId" />
                </el-select>
              </el-form-item>
            </template>
          </el-table-column>
          <el-table-column prop="poName" min-width="160px" align="left" label="岗位名称">
            <template slot-scope="sc">
              <el-form-item size="mini" :prop=" `tableData.${sc.$index}.sysArPoId` " :rules="rules.sysArPoId" :style="inputStyle">
                <el-select v-model="sc.row.sysArPoId" :style="inputStyle" clearable placeholder="请先选择所属部门">
                  <el-option v-for="item in sc.row.postList" :key="item.id" :label="item.poName" :value="item.id" />
                </el-select>
              </el-form-item>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </el-form>

    <div class="drawer-bottom-bar">
      <el-button type="primary" @click="submit">确定</el-button>
      <el-button @click="closeEditDialog">取消</el-button>
    </div>
  </div>
</template>

  

Data属性和Prop属性:

查询这个列表的接口还是需要的,直接用翻页接口,就不要翻页组件,size变量直接写死999,足够展示了

单位列表是共用的,加载一次就可以给每一行用

  props: {
    form: {
      type: Object,
      required: true,
      default() {
        return {
          tableData: []
        }
      }
    }
  },
  data() {
    return {
      /* 列表变量 */
      loading: false,
      page: {
        current: 0,
        size: 999,
        total: 0
      },

      /* 表单变量 */
      formRef: 'currentRowRefKey',
      editableTableRef: 'editableTableRefKey',
      rules: {
        sysArCoId: [
          { required: true, message: '请选择所属公司', trigger: 'change' }
        ],
        sysArDeId: [
          { required: true, message: '请选择所属部门', trigger: 'change' }
        ],
        sysArPoId: [
          { required: true, message: '请选择岗位名称', trigger: 'change' }
        ]
      },
      commonStyle: { width: '47%' },
      inputStyle: { width: '100%' },
      isUpdate: false,
      selectionRow: [],
      corpList: []
    }
  }

  

Method方法区内容:

一、解决新增操作时的问题

1、newEditRow 创建一条新行时,直接push这个行对象,这里初始化关联的员工ID和单位列表

2、deleteEditRow 删除编辑行,(用Splice方法跟据选中的下标来删除即可)这里用的是非复选框实现的选中方式 参考文章:http://www.javashuo.com/article/p-fbtbpqzn-bc.html

3、selectCorpChange 监听单位下拉事件,清空所有下级列表和选中的值,根据单位ID重新加载部门列表

4、selectDeptChange 监听部门下拉事件,同理

二、解决回显和编辑操作的问题

query 在加载列表的时候,同步阻塞执行加载方法把对应的列表放到行中

这里要注意的问题就是 异步执行顺序,一定要先等待单位列表加载完了,才能加载整个岗位的查询

  methods: {
    newEditRow() {
      const row = {
        sysArEmId: this.form.id,
        sysArCoId: '',
        sysArPoId: '',
        sysArDeId: '',
        corpList: [... this.corpList],
        deptList: [],
        postList: []
      }
      this.form.tableData.push(row)
    },
    deleteEditRow() {
      const selectedLength = this.selectionRow.length
      const totalLength = this.form.tableData.length
      if (totalLength === 0) return this.$message.error('没有编辑行了')
      if (selectedLength > 0) {
        for (let i = selectedLength - 1; i >= 0; i--) {
          this.form.tableData.splice(this.selectionRow[i].rowIndex, 1)
        }
      } else {
        const lastOne = totalLength - 1
        this.form.tableData.splice(lastOne, 1)
      }
      this.$refs[this.editableTableRef].clearSelection()
      this.selectionRow = []
    },
    selectCorpChange(rowIdx, row) {
      this.form.tableData[rowIdx].sysArDeId = ''
      this.form.tableData[rowIdx].sysArPoId = ''
      if (!row.sysArCoId) {
        this.form.tableData[rowIdx].deptList = []
        this.form.tableData[rowIdx].postList = []
      }
      this.loadDeptList(row.sysArCoId, rowIdx)
    },
    selectDeptChange(rowIdx, row) {
      this.form.tableData[rowIdx].sysArPoId = ''
      if (!row.sysArDeId) this.form.tableData[rowIdx].postList = []
      this.loadPostList(row.sysArDeId, rowIdx)
    },
    async initialCorpList() {
      const param = {}
      const { data: res } = await getCompanyList(param)
      this.corpList = res
    },
    async loadDeptList(val, rowIdx) {
      const param = { sysArCoId: val }
      const { data: res } = await getAllocatedDepartmentList(param)
      this.form.tableData[rowIdx].deptList = res
    },
    async loadPostList(val, rowIdx) {
      const param = { sysArDeId: val }
      const { data: res } = await getSysArPostList(param)
      this.form.tableData[rowIdx].postList = res
    },
    handleSizeChange(pageSize) {
      this.page.size = pageSize
      this.query()
    },
    handleCurrentChange(pageIndex) {
      this.page.current = pageIndex
      this.query()
    },
    searchPage() {
      this.page.current = 0
      this.page.total = 0
      this.query()
    },
    async query() {
      this.loading = true
      const param = {
        sysArEmId: this.form.id,
        page: this.page
      }
      const { data: res, total } = await getEmployeePositionPage(param)
      for (let i = 0; i < res.length; i++) {
        res[i].corpList = [... this.corpList]
        const { data: deptList } = await getAllocatedDepartmentList({ sysArCoId: res[i].sysArCoId })
        res[i].deptList = deptList
        const { data: postList } = await getSysArPostList({ sysArDeId: res[i].sysArDeId })
        res[i].postList = postList
      }
      this.form.tableData = res
      this.page.total = total
      this.loading = false
    },
    closeEditDialog() {
      this.$parent.$parent.closePostAssignDialog()
    },
    submit() {
      this.$refs[this.formRef].validate(async valid => {
        if (!valid) return
        this.form.empoList = this.form.tableData
        await assignEmployeePosition(this.form)
        this.$message.success('分配任岗成功')
      })
    }
  }

 

Created的执行:

  created() {
    this.initialCorpList().then(() => { this.searchPage() })
  }

  

 

多个表格,拆分校验的问题:

例如下图这样,存在明细表和行程信息表,可以在一个实例的表单对象上面写

如果表格已经是拆分成其他组件来写的话,再花时间合并到一个文件中就很费劲

 

 

把可编辑表格按组件引入进来

key用来刷新组件

ref用来获取组件的属性

keyId是传递外键

 

在提交表单的时候,可以拆分两个Promise对象进行处理

执行每个表单的校验,通过则resolve,反之reject

在最后放入All方法按顺序执行,只有都通过校验,才会进入then方法执行提交

不要忘记把可编辑表格的数据放入提交的表单中

所以,后面存在若干个表格,依次类推实现

    submit() {
      const part1Validate = new Promise((resolve, reject) => {
        this.$refs[this.formRef].validate(async valid => {
          if (valid) resolve()
          else reject()
        })
      })

      const part2Validate = new Promise((resolve, reject) => {
        const formTable = this.$refs['detailList'].$refs['currentRowRefKey']
        formTable.validate(valid => {
          if (valid) resolve()
          else reject()
        })
      })

      Promise.all([part1Validate, part2Validate]).then(async() => {
        this.form.detailList = this.$refs['detailList'].form.tableData
        if (this.isUpdate) {
          await updateFinSpApply(this.form)
          this.$message.success('更新成功')
          this.$parent.$parent.searchPage()
        } else {
          const { data: res } = await addFinSpApply(this.form)
          this.isUpdate = !!res
          if (this.isUpdate) {
            this.form.id = res.id
            this.freshFlag = new Date().getTime() /* 刷新子组件的key属性,让子组件重新加载 */
            this.$message.success('新增成功')
          }
          this.$parent.$parent.searchPage()
        }
      })
    }

  

 

posted @ 2022-11-05 17:30  emdzz  阅读(1371)  评论(0编辑  收藏  举报