1、需求
1)、按后台返回的数据进行合并单元格;
2)、点击新增,表格里面内容新增一行新的数据到最下方,并且序号加一;
3)、批量删除,勾选复选框点击删除,删除所勾选的数据,并且序号重新排序;
4)、勾选复选框,点击复制,复制所选的数据到列表最下方,并且序号重新排序;
5)、表格里面也有新增和删除功能,删除是删除当前行,新增是新增到当前行的下面,并且前面列动态合并,序号也重新排序;
2、效果图
3、功能图片
1)、新增
2)、删除
3)、复制
4)、table表格里的删除新增
4、代码
1)、HTML结构
注:N20是我们公司自己封装的组件,但是底层还是elementUI,结构并不是很重要,主要是结构上的:span-method="objectSpanMethod"方法。
<template> <div style="position: static !important;" > <N20-expandable-pane title="风险场景规则" class="risk_scenario_form_class"> <template slot="tips"> <el-button type="primary" size="mini" @click="handleClick('add')">新增</el-button> <el-button size="mini" plain @click="handleClick('copy')">复制</el-button> <el-button type="danger" size="mini" plain @click="handleClick('delete')">删除</el-button> </template> <el-form :model="formTableData" ref="formTableData" > <N20-table :showSetsize="true" :data="formTableData.tableData" :columns="columns" @select="handleTableSelection" @select-all="handleTableSelectionAll" :span-method="objectSpanMethod" border> <el-table-column label="指标模型名称" slot="name" align="center" width="248" :render-header="addRedStar" > <template slot-scope="scope"> <el-form-item :rules="[ { required: true, message: '', trigger: 'change' } ]" :prop="'tableData.' + scope.$index + '.name'"> <N20-input-search class="defind-input-width" v-model="scope.row.name" readonly @click.native="chooseIndicator(scope.$index,scope.row)" :is-clearable="true" v-title="scope.row.name"/> </el-form-item> </template> </el-table-column> <el-table-column label="风险管控类型" slot="fxgklx" align="center" width="248" :render-header="addRedStar"> <template slot-scope="scope"> <el-form-item :rules="[ { required: true, message: '', trigger: 'change' } ]" :prop="'tableData.' + scope.$index + '.fxgklx'"> <el-select style="width:224px" v-model="scope.row.fxgklx" clearable> <el-option v-for="item in fxgklxOptions" :key="item.value" :label="item.label" :value="item.value"></el-option> </el-select> </el-form-item> </template> </el-table-column> <el-table-column label="触发数据/业务类型" slot="ywlx" align="center" width="248" :render-header="addRedStar"> <template slot-scope="scope"> <el-form-item :rules="[ { required: true, message: '', trigger: 'change' } ]" :prop="'tableData.' + scope.$index + '.ywlx'"> <N20-input-search class="defind-input-width" v-model="scope.row.ywlx" readonly @click.native="chooseIndicator(scope.$index,scope.row)" :is-clearable="true" v-title="scope.row.ywlx"/> </el-form-item> </template> </el-table-column> <el-table-column label="频率" slot="pl" align="center" width="116" :render-header="addRedStar"> <template slot-scope="scope"> <el-form-item :rules="[ { required: true, message: '', trigger: 'change' } ]" :prop="'tableData.' + scope.$index + '.pl'"> <el-select style="width:100px" v-model="scope.row.pl" clearable> <el-option v-for="item in fxgklxOptions" :key="item.value" :label="item.label" :value="item.value"></el-option> </el-select> </el-form-item> </template> </el-table-column> <el-table-column label="适用单位设置" slot="sydwsz" align="center" width="118" > <template slot-scope="scope"> <el-form-item> <el-button type="text" @click="handleSetting(scope.row)">设置</el-button> </el-form-item> </template> </el-table-column> <el-table-column slot="yz" align="center" width="400"> <template slot="header"> <span><span style="color:red;margin-right: 4px">*</span>阈值</span><i class="n20-icon-xinxitishi" style="margin-left: 4px" v-title="'实际场景规则无对比阈值的,此项可空,比例类型阈值需转换成小数类型数值项输入'" /> </template> <template slot-scope="scope"> <el-form-item :rules="[ { required: true, message: '', trigger: 'change' } ]" :prop="'tableData.' + scope.$index + '.yz'"> <el-select style="width:100px;margin-right:4px" v-model="scope.row.yz" clearable> <el-option v-for="item in fxgklxOptions" :key="item.value" :label="item.label" :value="item.value"></el-option> </el-select> <el-input style="width:224px;margin-right:4px" v-model="scope.row.yz" clearable/> <el-button icon="n20-icon-xinzeng" type="text" @click="handleTableAdd(scope.row,scope.$index)"></el-button> <el-button icon="n20-icon-a-shanchuxuanzhong" type="text" @click="handleTableDel(scope.row,scope.$index)"></el-button> </el-form-item> </template> </el-table-column> <el-table-column label="风险等级" slot="fxdj" align="center" width="118" :render-header="addRedStar"> <template slot-scope="scope"> <el-form-item :rules="[ { required: true, message: '', trigger: 'change' } ]" :prop="'tableData.' + scope.$index + '.fxdj'"> <el-select style="width:100px" v-model="scope.row.fxdj" clearable> <el-option v-for="item in fxgklxOptions" :key="item.value" :label="item.label" :value="item.value"></el-option> </el-select> </el-form-item> </template> </el-table-column> <el-table-column label="风险事件设置" slot="fxsjsz" align="center" width="118" > <template slot-scope="scope"> <el-form-item> <el-button type="text" @click="handleSetting(scope.row)">设置</el-button> </el-form-item> </template> </el-table-column> </N20-table> </el-form> </N20-expandable-pane> <div class="operate-box" style="right:6px;width: calc(100% - 12px);left: 6px;"> <el-button @click="handleConfirm('saveAndStart')" type="primary">保存启用</el-button> <el-button plain @click="handleConfirm('save')" >保存</el-button> </div> </div> </template>
复制
2)、JS代码
export default { name: 'dispositionAdd',//风险场景配置 新增 data () { return { isIndexShow: false, indexRecordData: {}, indexNum:0, formData: { yjfxcj: null,//一级风险场景 ywcjbh:null,//业务场景编号 ywcjmc:null,//业务场景名称 gzmc:null,//规则名称 gzlx:null,//规则类型 ywcjms:null,//业务场景描述 }, formUnitData: { hyfl:null,//行业分类 dwmc:null,//单位名称 dwbh: null,//单位编号 current: 1, size: 100, total: 0, }, flag:false, rules: { yjfxcj: [ { required: true, message: '请输入', trigger: 'blur' } ], ywcjbh: [ { required: true, message: '请输入', trigger: 'blur' } ], ywcjmc: [ { required: true, message: '请输入', trigger: 'blur' } ], gzmc: [ { required: true, message: '请输入', trigger: 'blur' } ], }, formTableData: { tableData: [ { name: '上下游单位同名', type: '指标', fxgklx: '事前预测', ywlx: '',index:'1' }, { name: '上下游单位同名', type: '指标', fxgklx: '事前预测', ywlx: '',index:'1' }, { name: '上下游单位同名', type: '指标', fxgklx: '事前预测', ywlx: '',index:'1' }, { name: '同名双向结算', type: '指标', fxgklx: '事后预警', ywlx: '', index: '2' }, { name: '贸易合同异常模型', type: '评价模型', fxgklx: '事后预警', ywlx:'',index:'3' }, { name: '反洗钱模型', type: '计算模型', fxgklx: '事后预警', ywlx:'',index:'4' }, ] }, fxgklxOptions: [], rowSpanArr: [], columns: [ { type: 'selection', align: 'center', width: '46' }, { prop: 'index', label:'序号', align: 'center', width: '80' }, { label: '指标模型名称', align: 'center', slotName: 'name' }, { label: '类型', align: 'center', prop: 'type' }, { label: '风险管控类型', align: 'center', slotName: 'fxgklx' }, { label: '触发数据/业务类型', align: 'center', slotName: 'ywlx' }, { label: '频率', align: 'center', slotName: 'pl' }, { label: '适用单位设置', align: 'center', slotName: 'sydwsz' }, { label: '阈值', align: 'center', slotName: 'yz' }, { label: '风险等级', align: 'center', slotName: 'fxdj' }, { label: '风险事件设置', align: 'center', slotName: 'fxsjsz' }, ], sltList: [],//table 复选框 选择集合 } }, created() { // 模拟 处理table数据 收集要合并的数据 this.handleTableData(this.formTableData.tableData) }, methods: { // 保存 和 保存启用 handleConfirm (type) { console.log('formTableData',this.formTableData) if (this.handleValidate()) { switch (type) { case 'saveAndStart': break; default: break; } } }, // 校验所有表单 handleValidate () { let flag = false let validateList = ['formTableData','formRef'] validateList.map(item=>{ this.$refs[item].validate((valid) => { if (valid) { flag = true } else { flag = false } }) }) return flag }, // table 新增 handleTableAdd (row,index) { let tableData = JSON.parse(JSON.stringify(this.formTableData.tableData)) tableData.splice(index,0,row) console.log('tableData----新增---->>>',tableData) this.$set(this.formTableData, 'tableData', tableData) // 处理table数据 收集要合并的数据 this.handleTableData(this.formTableData.tableData) }, // table 删除 handleTableDel (row, index) { console.log('table---删除单个--->>>',row, index) let tableData = JSON.parse(JSON.stringify(this.formTableData.tableData)) if (Array.isArray(tableData) && tableData.length && tableData.indexOf(row)) { tableData.splice(index, 1); let tableDataOther = JSON.parse(JSON.stringify(tableData)) this.handleSetArray(tableDataOther).map((item, index) => { let num = index + 1 tableData.map(ele => { if (item.index == ele.index) { ele.index = num } }) }) this.$set(this.formTableData, 'tableData', tableData) // 处理table数据 收集要合并的数据 this.handleTableData(this.formTableData.tableData) } }, // 新增 复制 删除 handleClick (type) { // tableData table的数据源 let tableData = JSON.parse(JSON.stringify(this.formTableData.tableData)) // 复选之后数组收集 let sltList = JSON.parse(JSON.stringify(this.sltList)) if (type == 'add') { // 新增 let num = this.handleSetArray(tableData).length let tableDataItem = { name: '', type: '', fxgklx: '', ywlx: '',index:num+1 } this.formTableData.tableData.push(tableDataItem) } else if(type == 'copy'){ // 复制 if (!sltList.length) this.$message.info('请选择数据') // this.flag为true则是全选 为false则为不全选,因为点击复制之后 复选框全部清除勾选,所以点击全选之后再点击单选,flag还是为true,则走的还是全选的逻辑,所以得重置为false this.flag = false // sltListOther 作用是 对比去重之后的数据 给index赋值 let sltListOther = JSON.parse(JSON.stringify(this.sltList)) // 收集 去重之后的table的长度,用于复制的序列号的使用 let num = this.handleSetArray(tableData).length // 去重复选框勾选的集合 sltList = this.handleSetArray(sltList) console.log('复制---sltList--->>>', sltList) sltList.map(item => { num++ sltListOther.map((ele=>{ if (item.index == ele.index) { ele.index = num } })) }) console.log('复制---sltListOther--->>>', sltListOther) // 合并table和复选框选择的数据 最后赋值给tableData let copyArr = this.formTableData.tableData.concat(sltListOther) console.log('复制---copyArr--->>>',copyArr) this.formTableData.tableData = copyArr } else { // 删除 if (sltList.length) { sltList.map(item => { tableData.map((ele,index) => { if (item.index == ele.index) { tableData.splice(index, 1); } }) }) console.log('删除---tableData--->>>',tableData) let tableDataOther = JSON.parse(JSON.stringify(tableData)) console.log('删除---tableDataOther--->>>',tableDataOther) this.handleSetArray(tableData).map((item, index) => { let num = index + 1 tableDataOther.map(ele => { if (item.index == ele.index) { ele.index = num } }) }) this.$set(this.formTableData,'tableData',tableDataOther) console.log('删除--->>>',this.formTableData.tableData) } else { this.$message.info('请选择数据') } } // 处理table数据 收集要合并的数据 this.handleTableData(this.formTableData.tableData) this.sltList = [] }, // 根据index去重 handleSetArray (arr = []) { if (Array.isArray(arr)) { for (let i = 0; i < arr.length; i++) { for (let j = i + 1; j < arr.length; j++) { if (arr[i].index == arr[j].index) { arr.splice(j, 1); j-- } } } return arr } else { return [] } }, // @select="handleTableSelection" table的单选事件 handleTableSelection(val,row){ // table的数据源 let tableData = [...this.formTableData.tableData] // 点击table复选框 收集 数据源 let sltList = [...this.sltList] // flag为true的时候代表的是全选 为false则代表不全选 // 全选--勾选or不勾选逻辑 if(this.flag){ // isSelect为true代表全选之后点击取消 // isSelect为false代表全选之后点击取消然后又点勾选 let isSelect = sltList.length && sltList.indexOf(row) > -1 // 收集第一次勾选取消之后 收集原来勾选的数据 let sltListCheck = [] if(isSelect){ tableData.forEach(item=>{ if(item.index != row.index){ sltListCheck.push(item) } }) this.sltList = sltListCheck }else{ // 当再次勾选的时候 在原有的sltList集合 push新的勾选数据 tableData.forEach(item=>{ if(item.index == row.index){ this.sltList.push(item) } }) } console.log('全选--勾选or不勾选逻辑-->>',this.sltList) }else{ // 不全选--勾选or不勾选逻辑 let checkList = [] if (tableData.length && val.length) { // tableData为table数据数组 // val为复选框选择之后的数组 // 两个数组相互比较 如果index相同 则收集到checkList数组里面 tableData.forEach(item => { val.forEach(ele => { if (item.index == ele.index) { checkList.push(item) } }) }) } this.sltList = checkList console.log('不全选--勾选or不勾选--sltList-->>>',this.sltList) } }, // @select-all="handleTableSelectionAll" table的全选事件 handleTableSelectionAll(sltList){ if (sltList.length) { // flag为true的时候代表的是全选 为false则代表不全选 // sltList 为点击table复选框 收集 数据源 this.flag = true this.sltList = this.formTableData.tableData }else{ this.flag = false this.sltList = [] } console.log('handleTableSelectionAll',this.sltList) }, // 单位选择 确认 handleConfirmIndex (val) { console.log('单位选择 确认', val) let tableData = [ ...this.formTableData.tableData ] let indexRecordData = this.indexRecordData tableData.forEach((item,index) => { if (item.index == indexRecordData.index) { tableData[index].name = val.name } }) this.$set( this.formTableData,'tableData',tableData) this.isIndexShow = false }, // 单位选择 取消 handleCloseUnit () { this.isIndexShow = false }, // 设置 handleSetting (row) { }, // 处理table数据 收集要合并的数据 handleTableData (tableData = []) { let rowSpanArr = [] let position = 0 if (!!tableData && Array.isArray(tableData)) { tableData.map((item, index) => { if (index == 0) { rowSpanArr.push(1) position = 0 } else { if (item.index == tableData[index - 1].index) { rowSpanArr[position] += 1 rowSpanArr.push(0) } else { rowSpanArr.push(1) position = index } } }) } this.rowSpanArr = rowSpanArr }, // table合并单元格 objectSpanMethod ({ row, column, rowIndex, columnIndex }) { if (columnIndex != 8 && columnIndex != 9 && columnIndex != 10) { let rowspan = this.rowSpanArr[rowIndex] return { rowspan: rowspan, colspan: 1 }; } }, // 选择指标模型 并带出数据 和 下标 // index 下标 indicator带出的数据 chooseIndicator (index, indicator) { this.isIndexShow = true this.indexRecordData = indicator this.indexNum = index }, // 处理table 星号 变红 addRedStar(h, { column }) { return [ h("span", { style: "color: red" }, "*"), h("span", " " + column.label), ]; }, }, } </script>
复制