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

浙公网安备 33010602011771号