如何记录验证element后台管理系统中表单(表格?)的修改痕迹

流过昼夜 提交于 2020-04-13 17:57:23

【今日推荐】:为什么一到面试就懵逼!>>>

如何记录验证element后台管理系统中表单(表格?)的修改痕迹

大家好我是极速网吧的黒网吧天才少年,主要打1号位,这篇文章记录一下工作中遇到的一个比较有意思的需求,防止下次开发的时候忘记,同时希望大佬们给点建议

最近接了个需求,要求我写一个表格,这个表格用户可以自由增加删除行以及修改行内的数据,输入的内容有一定的验证要求,同时记录下用户的操作,在上传数据的时候提示用户进行了哪些操作。如图:

后端返回以及要求数据结构:

const tableList = [{
  section_name: "老八",
  section_id:1
  grade_list: ["臭豆腐", "俘虏", "臭撸虾", "嘎嘣脆嗲", "胡罗贝", "柠檬"]
}]
复制代码

这是表格中的内容,为数组对象,其中我们要记录修改痕迹的grade_list是不带id标识的,最终要求返回的数据也跟这个一致。

分析思路

记录修改痕迹,我们只需要在进入弹窗的时候记录一份原始数据,然后再比对原始数据以及提交时候的数据即可。

this.myTable = row.grade_list.map((key,index) => ({
	id:index,
    section_name:row.section_name,
    grade_name:key
}))
this.originTable = JSON.parse(JSON.stringify(this.myTable))
复制代码

第一步:验证重复

当有重复项的时候直接阻止进入下一步,同时在表格中弹窗提示重复,样式怎么写呢?直接去element源码把el-form的验证样式复制过来即可

<!-- html内容 -->
<el-table
  border
  :data="myTable"
>
  <el-table-column type="index" label="序号"></el-table-column>
  <el-table-column prop="section_name" label="姓名"></el-table-column>
  <el-table-column label="最爱的食物">
    <template slot-scope="{ row,$index }">
      <div class="el-form-item" :class="{
          'is-error': errorObj.hasOwnProperty($index)
        }">
        <div class="el-form-item__content">
          <el-input v-model="row.grade_name" maxlength="10"></el-input>
          <transition name="el-zoom-in-top">
            <div
              v-if="errorObj.hasOwnProperty($index)"
              class="el-form-item__error"
            >
              {{errorObj[$index]}}
            </div>
          </transition>
        </div>
      </div>
    </template>
  </el-table-column>
  <el-table-column label="操作">
    <template slot-scope="{ row,$index }">
      <el-button @click="delClass(row,$index)">删除</el-button>
    </template>
  </el-table-column>
</el-table>
<!-- js内容 -->
<script>
 需要的data:
 data(){
     return{
        myTable:[],
        originTable:[],
        tempRow:{},
        //验证类
        validateState:'error',
        errorObj:{},
     }
 }
 绑定在保存按钮点击事件上的方法:
 putGrades(){
     ...
	//去空
	this.myTable = this.myTable.filter(key=> key.grade_name.trim() !== '')
	// 验证重复,new一个名字为键序号数组为值的map,序号的length大于1的时候说明有重复
	let map = new Map()
	this.errorObj = {}
	this.myTable.forEach((key,index)=>{
    //遇到重复的名字,重新把名字对应的序号
  	if(map.has(key.grade_name)){
    	let oldVal = map.get(key.grade_name)
    	map.set(key.grade_name,[...oldVal,index])
    	return
  	}
  	map.set(key.grade_name,[index])
	})
	map.forEach((value)=>{
  	if(value.length > 1){
    	value.forEach(key=> { 
      	//存入重复项以及验证错误的原因
      	this.$set(this.errorObj,key,'老八不喜欢重复的食物!')
    	})
  	}
	})
	//有重复阻止发送请求
	if(Object.keys(this.errorObj).length !== 0) return
    ...
 }
</script>
复制代码

因为错误信息errorObj因为不确定有多少项,所以没法在data中直接写上让vue动态绑定,所以在方法中用了vue.set的方法手动来动态绑定,通过数组中的index来保证与原数组一一对应的关系。通过这个思路,我可以通过写其他的方法来验证其他不同的规则,比如是否含有字母、手机号规则等,只需要遍历数组一次,将不符合规则的index以及错误信息存入errorObj即可。

第二步:记录修改痕迹

记录修改痕迹,需要先区别新增项与原始数组中的项,我在原始数组的每一项中都添加一个id,id的值跟index一致,新增项中则没有id。这样就能将新增与原有区分开来,如此只需两步就可以记录下修改痕迹了。

ps:“新”代表要提交的数组,“旧”代表我们拷贝的那份数组

1:判断新旧是否有重名,有重名的先直接去掉,属于不变的组

2.1:判断新旧中有id的名字是否一致,不一致的部分去掉,属于修改组

2.2:判断新旧带id的数量是否一致,新中少了的部分去掉,为删除组,剩下的都是新增组

...
//第1步,判断新旧是否有重名,有重名的先直接去掉,属于不变的组
let originMap = new Map()
this.originTable.forEach(key =>{
	originMap.set(key.grade_name,key.id)
})
let tempNew = this.myTable.filter((key) => {
  if(originMap.has(key.grade_name)) {
    originMap.delete(key.grade_name)
    return false
  }
  return true
})
//如果全部重名即没有修改,直接返回
if(tempNew.length === 0) return
//第2.1步,判断有id的名字是否一致,不一致属于修改组
//第2.2步,判断新旧带id的数量是否一致,origin少了的部分为删除组
//第3步,剩下的都是新增组
//反转originMap中键值对
let idMap = new Map()
originMap.forEach((value,key)=>{
  idMap.set(value,key)
})
let edited = new Map()
let noIDGrade = []
tempNew.forEach(key=>{
  if(key.id !== undefined) {
    edited.set(idMap.get(key.id),key.grade_name)
    idMap.delete(key.id)
  }else{
    noIDGrade.push(key.grade_name)
  }
})
const h = this.$createElement;
let renderEdit = []
let renderAdd = []
let renderDel = []
edited.forEach((value,key)=>{
  renderEdit.push(h('p',`${key}修改为${value}`))
})
noIDGrade.forEach((value)=>{
  renderDel.push(h('p',`新增:${value}`))
})
idMap.forEach((value)=>{
  renderAdd.push(h('p',`已删除:${value}`))
})
//判断修改组、新增组、删除组是否为空,为空的话阻止上传
if(renderEdit.length === 0 && renderAdd.length === 0 && renderDel.length === 0) return
this.$msgbox({
  title: "修改确认",
  message: h("div", null, [
    h( 
      "p",renderEdit
    ),
    h(
      "p",renderAdd
    ),
    h(
      "p",renderDel
    ),
  ]),
  showCancelButton: true,
  showClose: false,
  confirmButtonText: "确认",
  cancelButtonText: "取消"
})
...
复制代码

因为修改组必须以键值对的形式出现,即xxx修改为xxx,所以修改组我用map记录,删除组跟新增组都直接存名字的值。最后效果:

总结&求助

感觉自己写的这个东西很垃圾,遍历了很多次,用了许多额外的空间,创造了一堆数组跟map,特别是反转map键值对显得特别蠢,有没有其他思路或者写法上可以更简洁,恳请大神们给个提示,在掘金搜了一下没看到有写校验表单的相关内容。

完整的项目地址:github.com/Eating-Eati…

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!