【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() } }) }