<template>
<el-form
ref="lineEditForm"
:rules="tableFormRules"
:model="tableFormData"
v-bind="{
'inline-message': true,
'validate-on-rule-change': false,
'label-width': '0px',
...(formOptions || {}),
}"
>
<div class="lineEditForm">
<el-table :data="tableData || []" v-bind="{ border: false, ...(tableOptions || {}) }">
<el-table-column
v-for="e in tableColumns || []"
:key="e.props"
:prop="e.props"
v-bind="{ ...(e.tableColumnOptions || {}) }"
>
<template slot="header">
<slot :name="`${e.prop}_header`" />
</template>
<template slot-scope="scope">
<el-form-item :prop="`${e.prop}-${scope.$index}`" v-bind="{ ...(e.formItemOptions || {}) }">
<slot :name="e.prop" :rowData="scope.row" :rowIndex="scope.$index"/>
</el-form-item>
</template>
</el-table-column>
<el-table-column
v-if="!operationOptions.hiddenOptionColumn"
v-bind="{
prop: 'operation',
align: 'center',
width: '150px',
label: $t('common_components_ui.components.lineEditTable.operation'),
...(operationOptions.operationColumnOptions || {}),
}"
>
<template slot-scope="scope">
<!--自定义分摊:操作(删除)-->
<el-popover
v-show="!(operationOptions.hiddenDelete || []).includes(scope.$index)"
:ref="`lineEditFormPopover-${scope.$index}`"
placement="top"
>
<p>{{ $t('common_components_ui.components.lineEditTable.confirmTips') }}</p>
<div class="popover-btn">
<el-button @click="$refs[`lineEditFormPopover-${scope.$index}`].doClose()">
{{ $t('common_components_ui.components.lineEditTable.cancel') }}
</el-button>
<el-button type="primary" @click="deleteLineEdit(scope.$index)">
{{ $t('common_components_ui.components.lineEditTable.confirm') }}
</el-button>
</div>
<el-button slot="reference" type="text">
{{ $t('common_components_ui.components.lineEditTable.delete') }}
</el-button>
</el-popover>
</template>
</el-table-column>
</el-table>
</div>
<el-row v-show="!operationOptions.hiddenAdd" type="flex" justify="center" style="margin-top: 16px">
<el-button type="text" class="ad-btn" icon="el-icon-plus" @click="addLineEdit">
{{ $t('common_components_ui.components.lineEditTable.add') }}
</el-button>
</el-row>
</el-form>
</template>
<script>
export default {
name: 'MkLineEditTable',
props: {
// 行编辑列表数据 (必填)
tableData: {
type: Array,
default() {
return []
},
},
/**
* 行编辑列配置想,按从左到右顺序来 (必填)
* [{
* prop: '', // 该列关键字和tableData中数据一一对应,必填
* initValue: '', // 该列初始值 新增一行时会用到初始值,必填
* rules: {
* trigger: '', // 校验触发类型 可选值 'change' || 'blur'
* validator: (rule, value, callback, rowData, rowIndex) => {
* // 校验逻辑 前三个入参值和el-form的validator函数一致,后两个参数为当前行数据 和 当前行index
* }
* },
* tableColumnOptions: {}, // 表格该列自定义属性,支持el-table-column的所有入参都支持
* formItemOptions: {} // 该列form项的自定义属性,支持el-form-item的所有入参都支持
* }]
*/
tableColumns: {
type: Array,
default() {
return []
},
},
// form表单自定义参数,支持el-form所有参数
formOptions: {
type: Object,
default() {
return {}
},
},
// table表格自定义参数,支持el-table所有参数
tableOptions: {
type: Object,
default() {
return {}
},
},
/**
* 操作按钮属性
* hiddenOptionColumn 是否隐藏操作列,默认false
* hiddenDelete 数组 存 不展示删除按钮的行数下标
* hiddenAdd 是否隐藏添加按钮,默认false
* operationColumnOptions 操作列自定义属性,支持el-table-column的所有入参都支持
*/
operationOptions: {
type: Object,
default() {
return {
hiddenOptionColumn: false,
hiddenDelete: [],
hiddenAdd: false,
operationColumnOptions: {},
}
},
},
},
data() {
return {}
},
computed: {
/**
* 通过table数组数据形成Form表单所需对象
*/
tableFormData() {
const tableFormData = {}
this.tableData.forEach((data, index) => {
this.tableColumns.forEach((options) => {
tableFormData[`${options.prop}-${index}`] = data[options.prop]
})
})
return tableFormData
},
/**
* 通过table数组数据形成Form表单所需校验规则
*/
tableFormRules() {
const tableFormRules = {}
this.tableData.forEach((data, index) => {
this.tableColumns.forEach((options) => {
if (options.rules) {
tableFormRules[`${options.prop}-${index}`] = {
trigger: options.rules.trigger,
validator: (rule, value, callback) => {
options.rules.validator(rule, value, callback, this.tableData[index], index)
},
}
}
})
})
return tableFormRules
},
},
methods: {
/**
* @method deleteLineEdit 删除一行
*/
deleteLineEdit(index) {
this.$refs[`lineEditFormPopover-${index}`].doClose()
this.tableData.splice(index, 1)
this.$emit('update:tableData', this.tableData)
},
/**
* @method addLineEdit 添加一行
*/
addLineEdit() {
const tableDataItem = {}
this.tableColumns.forEach((options) => {
tableDataItem[options.prop] = options.initValue
})
this.tableData.push(tableDataItem)
this.$emit('update:tableData', this.tableData)
},
/**
* @method formValidate form表单校验
* @return Promise
*/
formValidate() {
return new Promise((resolve, reject) => {
this.$refs.lineEditForm.validate((valid) => {
resolve(valid)
})
})
},
/**
* @method formResetFields 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
*/
formResetFields() {
this.$refs.lineEditForm.validateField()
},
/**
* @method formValidateField 对部分表单字段进行校验的方法
* @param val 表单项的 prop 属性或者 prop 组成的数组
* @param callback 校验完后的回调函数 Function(errorMessage: string)
*/
formValidateField(val, callback) {
this.$refs.lineEditForm.validateField(val, callback)
},
/**
* @method formClearValidate 移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果
* @param val 表单项的 prop 属性或者 prop 组成的数组
*/
formClearValidate(val) {
this.$refs.lineEditForm.clearValidate(val)
},
},
}
</script>
<style lang="scss" scoped>
.popover-btn {
text-align: right;
margin-top: 16px;
}
.header-label:before {
content: '*';
color: #ea3447;
margin-right: 4px;
}
.ad-btn {
width: 100%;
border: 1px dashed rgba(0, 0, 0, 0.1) !important;
color: rgba(0, 0, 0, 0.45) !important;
font-size: 15px;
}
.lineEditForm ::v-deep .el-table__empty-block {
height: 80px !important;
}
</style>
使用场景:动态编辑行