当前位置:   article > 正文

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

vue el-table 合并单元格
1、需求

        1)、按后台返回的数据进行合并单元格;

        2)、点击新增,表格里面内容新增一行新的数据到最下方,并且序号加一;

        3)、批量删除,勾选复选框点击删除,删除所勾选的数据,并且序号重新排序;

        4)、勾选复选框,点击复制,复制所选的数据到列表最下方,并且序号重新排序;

        5)、表格里面也有新增和删除功能,删除是删除当前行,新增是新增到当前行的下面,并且前面列动态合并,序号也重新排序;

2、效果图

3、功能图片

        1)、新增

 

        2)、删除

 

        3)、复制

 

        4)、table表格里的删除新增

 

4、代码

         1)、HTML结构

        注:N20是我们公司自己封装的组件,但是底层还是elementUI,结构并不是很重要,主要是结构上的:span-method="objectSpanMethod"方法。

  1. <template>
  2. <div style="position: static !important;" >
  3. <N20-expandable-pane title="风险场景规则" class="risk_scenario_form_class">
  4. <template slot="tips">
  5. <el-button type="primary" size="mini" @click="handleClick('add')">新增</el-button>
  6. <el-button size="mini" plain @click="handleClick('copy')">复制</el-button>
  7. <el-button type="danger" size="mini" plain @click="handleClick('delete')">删除</el-button>
  8. </template>
  9. <el-form :model="formTableData" ref="formTableData" >
  10. <N20-table :showSetsize="true" :data="formTableData.tableData" :columns="columns" @select="handleTableSelection" @select-all="handleTableSelectionAll" :span-method="objectSpanMethod" border>
  11. <el-table-column label="指标模型名称" slot="name" align="center" width="248" :render-header="addRedStar" >
  12. <template slot-scope="scope">
  13. <el-form-item :rules="[ { required: true, message: '', trigger: 'change' } ]" :prop="'tableData.' + scope.$index + '.name'">
  14. <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"/>
  15. </el-form-item>
  16. </template>
  17. </el-table-column>
  18. <el-table-column label="风险管控类型" slot="fxgklx" align="center" width="248" :render-header="addRedStar">
  19. <template slot-scope="scope">
  20. <el-form-item :rules="[ { required: true, message: '', trigger: 'change' } ]" :prop="'tableData.' + scope.$index + '.fxgklx'">
  21. <el-select style="width:224px" v-model="scope.row.fxgklx" clearable>
  22. <el-option v-for="item in fxgklxOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
  23. </el-select>
  24. </el-form-item>
  25. </template>
  26. </el-table-column>
  27. <el-table-column label="触发数据/业务类型" slot="ywlx" align="center" width="248" :render-header="addRedStar">
  28. <template slot-scope="scope">
  29. <el-form-item :rules="[ { required: true, message: '', trigger: 'change' } ]" :prop="'tableData.' + scope.$index + '.ywlx'">
  30. <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"/>
  31. </el-form-item>
  32. </template>
  33. </el-table-column>
  34. <el-table-column label="频率" slot="pl" align="center" width="116" :render-header="addRedStar">
  35. <template slot-scope="scope">
  36. <el-form-item :rules="[ { required: true, message: '', trigger: 'change' } ]" :prop="'tableData.' + scope.$index + '.pl'">
  37. <el-select style="width:100px" v-model="scope.row.pl" clearable>
  38. <el-option v-for="item in fxgklxOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
  39. </el-select>
  40. </el-form-item>
  41. </template>
  42. </el-table-column>
  43. <el-table-column label="适用单位设置" slot="sydwsz" align="center" width="118" >
  44. <template slot-scope="scope">
  45. <el-form-item>
  46. <el-button type="text" @click="handleSetting(scope.row)">设置</el-button>
  47. </el-form-item>
  48. </template>
  49. </el-table-column>
  50. <el-table-column slot="yz" align="center" width="400">
  51. <template slot="header">
  52. <span><span style="color:red;margin-right: 4px">*</span>阈值</span><i class="n20-icon-xinxitishi" style="margin-left: 4px" v-title="'实际场景规则无对比阈值的,此项可空,比例类型阈值需转换成小数类型数值项输入'" />
  53. </template>
  54. <template slot-scope="scope">
  55. <el-form-item :rules="[ { required: true, message: '', trigger: 'change' } ]" :prop="'tableData.' + scope.$index + '.yz'">
  56. <el-select style="width:100px;margin-right:4px" v-model="scope.row.yz" clearable>
  57. <el-option v-for="item in fxgklxOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
  58. </el-select>
  59. <el-input style="width:224px;margin-right:4px" v-model="scope.row.yz" clearable/>
  60. <el-button icon="n20-icon-xinzeng" type="text" @click="handleTableAdd(scope.row,scope.$index)"></el-button>
  61. <el-button icon="n20-icon-a-shanchuxuanzhong" type="text" @click="handleTableDel(scope.row,scope.$index)"></el-button>
  62. </el-form-item>
  63. </template>
  64. </el-table-column>
  65. <el-table-column label="风险等级" slot="fxdj" align="center" width="118" :render-header="addRedStar">
  66. <template slot-scope="scope">
  67. <el-form-item :rules="[ { required: true, message: '', trigger: 'change' } ]" :prop="'tableData.' + scope.$index + '.fxdj'">
  68. <el-select style="width:100px" v-model="scope.row.fxdj" clearable>
  69. <el-option v-for="item in fxgklxOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
  70. </el-select>
  71. </el-form-item>
  72. </template>
  73. </el-table-column>
  74. <el-table-column label="风险事件设置" slot="fxsjsz" align="center" width="118" >
  75. <template slot-scope="scope">
  76. <el-form-item>
  77. <el-button type="text" @click="handleSetting(scope.row)">设置</el-button>
  78. </el-form-item>
  79. </template>
  80. </el-table-column>
  81. </N20-table>
  82. </el-form>
  83. </N20-expandable-pane>
  84. <div class="operate-box" style="right:6px;width: calc(100% - 12px);left: 6px;">
  85. <el-button @click="handleConfirm('saveAndStart')" type="primary">保存启用</el-button>
  86. <el-button plain @click="handleConfirm('save')" >保存</el-button>
  87. </div>
  88. </div>
  89. </template>

        2)、JS代码

  1. export default {
  2. name: 'dispositionAdd',//风险场景配置 新增
  3. data () {
  4. return {
  5. isIndexShow: false,
  6. indexRecordData: {},
  7. indexNum:0,
  8. formData: {
  9. yjfxcj: null,//一级风险场景
  10. ywcjbh:null,//业务场景编号
  11. ywcjmc:null,//业务场景名称
  12. gzmc:null,//规则名称
  13. gzlx:null,//规则类型
  14. ywcjms:null,//业务场景描述
  15. },
  16. formUnitData: {
  17. hyfl:null,//行业分类
  18. dwmc:null,//单位名称
  19. dwbh: null,//单位编号
  20. current: 1,
  21. size: 100,
  22. total: 0,
  23. },
  24. flag:false,
  25. rules: {
  26. yjfxcj: [
  27. { required: true, message: '请输入', trigger: 'blur' }
  28. ],
  29. ywcjbh: [
  30. { required: true, message: '请输入', trigger: 'blur' }
  31. ],
  32. ywcjmc: [
  33. { required: true, message: '请输入', trigger: 'blur' }
  34. ],
  35. gzmc: [
  36. { required: true, message: '请输入', trigger: 'blur' }
  37. ],
  38. },
  39. formTableData: {
  40. tableData: [
  41. { name: '上下游单位同名', type: '指标', fxgklx: '事前预测', ywlx: '',index:'1' },
  42. { name: '上下游单位同名', type: '指标', fxgklx: '事前预测', ywlx: '',index:'1' },
  43. { name: '上下游单位同名', type: '指标', fxgklx: '事前预测', ywlx: '',index:'1' },
  44. { name: '同名双向结算', type: '指标', fxgklx: '事后预警', ywlx: '', index: '2' },
  45. { name: '贸易合同异常模型', type: '评价模型', fxgklx: '事后预警', ywlx:'',index:'3' },
  46. { name: '反洗钱模型', type: '计算模型', fxgklx: '事后预警', ywlx:'',index:'4' },
  47. ]
  48. },
  49. fxgklxOptions: [],
  50. rowSpanArr: [],
  51. columns: [
  52. { type: 'selection', align: 'center', width: '46' },
  53. { prop: 'index', label:'序号', align: 'center', width: '80' },
  54. { label: '指标模型名称', align: 'center', slotName: 'name' },
  55. { label: '类型', align: 'center', prop: 'type' },
  56. { label: '风险管控类型', align: 'center', slotName: 'fxgklx' },
  57. { label: '触发数据/业务类型', align: 'center', slotName: 'ywlx' },
  58. { label: '频率', align: 'center', slotName: 'pl' },
  59. { label: '适用单位设置', align: 'center', slotName: 'sydwsz' },
  60. { label: '阈值', align: 'center', slotName: 'yz' },
  61. { label: '风险等级', align: 'center', slotName: 'fxdj' },
  62. { label: '风险事件设置', align: 'center', slotName: 'fxsjsz' },
  63. ],
  64. sltList: [],//table 复选框 选择集合
  65. }
  66. },
  67. created() {
  68. // 模拟 处理table数据 收集要合并的数据
  69. this.handleTableData(this.formTableData.tableData)
  70. },
  71. methods: {
  72. // 保存 和 保存启用
  73. handleConfirm (type) {
  74. console.log('formTableData',this.formTableData)
  75. if (this.handleValidate()) {
  76. switch (type) {
  77. case 'saveAndStart':
  78. break;
  79. default:
  80. break;
  81. }
  82. }
  83. },
  84. // 校验所有表单
  85. handleValidate () {
  86. let flag = false
  87. let validateList = ['formTableData','formRef']
  88. validateList.map(item=>{
  89. this.$refs[item].validate((valid) => {
  90. if (valid) {
  91. flag = true
  92. } else {
  93. flag = false
  94. }
  95. })
  96. })
  97. return flag
  98. },
  99. // table 新增
  100. handleTableAdd (row,index) {
  101. let tableData = JSON.parse(JSON.stringify(this.formTableData.tableData))
  102. tableData.splice(index,0,row)
  103. console.log('tableData----新增---->>>',tableData)
  104. this.$set(this.formTableData, 'tableData', tableData)
  105. // 处理table数据 收集要合并的数据
  106. this.handleTableData(this.formTableData.tableData)
  107. },
  108. // table 删除
  109. handleTableDel (row, index) {
  110. console.log('table---删除单个--->>>',row, index)
  111. let tableData = JSON.parse(JSON.stringify(this.formTableData.tableData))
  112. if (Array.isArray(tableData) && tableData.length && tableData.indexOf(row)) {
  113. tableData.splice(index, 1);
  114. let tableDataOther = JSON.parse(JSON.stringify(tableData))
  115. this.handleSetArray(tableDataOther).map((item, index) => {
  116. let num = index + 1
  117. tableData.map(ele => {
  118. if (item.index == ele.index) {
  119. ele.index = num
  120. }
  121. })
  122. })
  123. this.$set(this.formTableData, 'tableData', tableData)
  124. // 处理table数据 收集要合并的数据
  125. this.handleTableData(this.formTableData.tableData)
  126. }
  127. },
  128. // 新增 复制 删除
  129. handleClick (type) {
  130. // tableData table的数据源
  131. let tableData = JSON.parse(JSON.stringify(this.formTableData.tableData))
  132. // 复选之后数组收集
  133. let sltList = JSON.parse(JSON.stringify(this.sltList))
  134. if (type == 'add') {
  135. // 新增
  136. let num = this.handleSetArray(tableData).length
  137. let tableDataItem = { name: '', type: '', fxgklx: '', ywlx: '',index:num+1 }
  138. this.formTableData.tableData.push(tableDataItem)
  139. } else if(type == 'copy'){
  140. // 复制
  141. if (!sltList.length) this.$message.info('请选择数据')
  142. // this.flag为true则是全选 为false则为不全选,因为点击复制之后 复选框全部清除勾选,所以点击全选之后再点击单选,flag还是为true,则走的还是全选的逻辑,所以得重置为false
  143. this.flag = false
  144. // sltListOther 作用是 对比去重之后的数据 给index赋值
  145. let sltListOther = JSON.parse(JSON.stringify(this.sltList))
  146. // 收集 去重之后的table的长度,用于复制的序列号的使用
  147. let num = this.handleSetArray(tableData).length
  148. // 去重复选框勾选的集合
  149. sltList = this.handleSetArray(sltList)
  150. console.log('复制---sltList--->>>', sltList)
  151. sltList.map(item => {
  152. num++
  153. sltListOther.map((ele=>{
  154. if (item.index == ele.index) {
  155. ele.index = num
  156. }
  157. }))
  158. })
  159. console.log('复制---sltListOther--->>>', sltListOther)
  160. // 合并table和复选框选择的数据 最后赋值给tableData
  161. let copyArr = this.formTableData.tableData.concat(sltListOther)
  162. console.log('复制---copyArr--->>>',copyArr)
  163. this.formTableData.tableData = copyArr
  164. } else {
  165. // 删除
  166. if (sltList.length) {
  167. sltList.map(item => {
  168. tableData.map((ele,index) => {
  169. if (item.index == ele.index) {
  170. tableData.splice(index, 1);
  171. }
  172. })
  173. })
  174. console.log('删除---tableData--->>>',tableData)
  175. let tableDataOther = JSON.parse(JSON.stringify(tableData))
  176. console.log('删除---tableDataOther--->>>',tableDataOther)
  177. this.handleSetArray(tableData).map((item, index) => {
  178. let num = index + 1
  179. tableDataOther.map(ele => {
  180. if (item.index == ele.index) {
  181. ele.index = num
  182. }
  183. })
  184. })
  185. this.$set(this.formTableData,'tableData',tableDataOther)
  186. console.log('删除--->>>',this.formTableData.tableData)
  187. } else {
  188. this.$message.info('请选择数据')
  189. }
  190. }
  191. // 处理table数据 收集要合并的数据
  192. this.handleTableData(this.formTableData.tableData)
  193. this.sltList = []
  194. },
  195. // 根据index去重
  196. handleSetArray (arr = []) {
  197. if (Array.isArray(arr)) {
  198. for (let i = 0; i < arr.length; i++) {
  199. for (let j = i + 1; j < arr.length; j++) {
  200. if (arr[i].index == arr[j].index) {
  201. arr.splice(j, 1);
  202. j--
  203. }
  204. }
  205. }
  206. return arr
  207. } else {
  208. return []
  209. }
  210. },
  211. // @select="handleTableSelection" table的单选事件
  212. handleTableSelection(val,row){
  213. // table的数据源
  214. let tableData = [...this.formTableData.tableData]
  215. // 点击table复选框 收集 数据源
  216. let sltList = [...this.sltList]
  217. // flag为true的时候代表的是全选 为false则代表不全选
  218. // 全选--勾选or不勾选逻辑
  219. if(this.flag){
  220. // isSelect为true代表全选之后点击取消
  221. // isSelect为false代表全选之后点击取消然后又点勾选
  222. let isSelect = sltList.length && sltList.indexOf(row) > -1
  223. // 收集第一次勾选取消之后 收集原来勾选的数据
  224. let sltListCheck = []
  225. if(isSelect){
  226. tableData.forEach(item=>{
  227. if(item.index != row.index){
  228. sltListCheck.push(item)
  229. }
  230. })
  231. this.sltList = sltListCheck
  232. }else{
  233. // 当再次勾选的时候 在原有的sltList集合 push新的勾选数据
  234. tableData.forEach(item=>{
  235. if(item.index == row.index){
  236. this.sltList.push(item)
  237. }
  238. })
  239. }
  240. console.log('全选--勾选or不勾选逻辑-->>',this.sltList)
  241. }else{
  242. // 不全选--勾选or不勾选逻辑
  243. let checkList = []
  244. if (tableData.length && val.length) {
  245. // tableData为table数据数组
  246. // val为复选框选择之后的数组
  247. // 两个数组相互比较 如果index相同 则收集到checkList数组里面
  248. tableData.forEach(item => {
  249. val.forEach(ele => {
  250. if (item.index == ele.index) {
  251. checkList.push(item)
  252. }
  253. })
  254. })
  255. }
  256. this.sltList = checkList
  257. console.log('不全选--勾选or不勾选--sltList-->>>',this.sltList)
  258. }
  259. },
  260. // @select-all="handleTableSelectionAll" table的全选事件
  261. handleTableSelectionAll(sltList){
  262. if (sltList.length) {
  263. // flag为true的时候代表的是全选 为false则代表不全选
  264. // sltList 为点击table复选框 收集 数据源
  265. this.flag = true
  266. this.sltList = this.formTableData.tableData
  267. }else{
  268. this.flag = false
  269. this.sltList = []
  270. }
  271. console.log('handleTableSelectionAll',this.sltList)
  272. },
  273. // 单位选择 确认
  274. handleConfirmIndex (val) {
  275. console.log('单位选择 确认', val)
  276. let tableData = [ ...this.formTableData.tableData ]
  277. let indexRecordData = this.indexRecordData
  278. tableData.forEach((item,index) => {
  279. if (item.index == indexRecordData.index) {
  280. tableData[index].name = val.name
  281. }
  282. })
  283. this.$set( this.formTableData,'tableData',tableData)
  284. this.isIndexShow = false
  285. },
  286. // 单位选择 取消
  287. handleCloseUnit () {
  288. this.isIndexShow = false
  289. },
  290. // 设置
  291. handleSetting (row) {
  292. },
  293. // 处理table数据 收集要合并的数据
  294. handleTableData (tableData = []) {
  295. let rowSpanArr = []
  296. let position = 0
  297. if (!!tableData && Array.isArray(tableData)) {
  298. tableData.map((item, index) => {
  299. if (index == 0) {
  300. rowSpanArr.push(1)
  301. position = 0
  302. } else {
  303. if (item.index == tableData[index - 1].index) {
  304. rowSpanArr[position] += 1
  305. rowSpanArr.push(0)
  306. } else {
  307. rowSpanArr.push(1)
  308. position = index
  309. }
  310. }
  311. })
  312. }
  313. this.rowSpanArr = rowSpanArr
  314. },
  315. // table合并单元格
  316. objectSpanMethod ({ row, column, rowIndex, columnIndex }) {
  317. if (columnIndex != 8 && columnIndex != 9 && columnIndex != 10) {
  318. let rowspan = this.rowSpanArr[rowIndex]
  319. return {
  320. rowspan: rowspan,
  321. colspan: 1
  322. };
  323. }
  324. },
  325. // 选择指标模型 并带出数据 和 下标
  326. // index 下标 indicator带出的数据
  327. chooseIndicator (index, indicator) {
  328. this.isIndexShow = true
  329. this.indexRecordData = indicator
  330. this.indexNum = index
  331. },
  332. // 处理table 星号 变红
  333. addRedStar(h, { column }) {
  334. return [
  335. h("span", { style: "color: red" }, "*"),
  336. h("span", " " + column.label),
  337. ];
  338. },
  339. },
  340. }
  341. </script>

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/965230
推荐阅读
相关标签
  

闽ICP备14008679号