Vue+elementUI的el-table组件,合并单元格,勾选之后,复制、新增、删除、批量复制、批量删除功能

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>

 

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值