zoukankan      html  css  js  c++  java
  • handsontable在线编辑excel扩展功能-踩坑篇

    简述

    先说一下背景,之所以封装handsontable插件,是因为公司要实现在线编辑导入excel文件的功能,然后我就找到了这个功能强大的插件handsontable。

    具体功能

    除了handsontable的功能外,还包括:

    1、每一行数据统计错误数,重复数

    2、每一列标记重复项,错误项

    3、定位功能,当数据过多出现滚动条时,点击上一条/下一条按钮,定位到当前标记项。

    4、表头标注每一列数据的校验规则。

    5、当数据被编辑后,立即重新校验,并标记重复项、错误项

    6、配置isValidate,true则本地校验,false则不校验
    (css样式有待改进,后面会更新)

    2018/3/30日,修复所有bug,

    1、根绝插件局部渲染的特性,将每行的第一列的标注完成局部渲染,以及错误点定位,也根据局部渲染的特性,先滚动到指定行,再进行标记。

    2、另外,修复时间控件在最前/后一列/行的情况下,会被遮挡的问题,修改了源码,根据当前单元格的位置来计算时间控件展示的位置。

    3、修改源码,将时间控件的英文改为中文。(后面会附上源码修改部分)

    2018/4/3日,修改保存错误定位的数据结构,并标记每一个td的row,col位置,保证做到,定位错误点100%准确

    /*
     * author Happy Guo 
     * date 2018-03-15
     */
    'use strict';
    define(["jquery","Handsontable"], function ($,Handsontable) {
     var HandsontableExtend = function(opt) {
       this.opt = $.extend(true, {}, opt);
       this.element = document.querySelector(this.opt.el);
       this.header = Object.keys(this.opt.dataObj.headMap);
       this.allErrorNum = [];//记录每一行的错误数
       this.table = null;
       this.errorRow = 0;//统计有几行是有错误的
       this.errorPosition = {
         index:0,
         row: 0,
         col: 0
       };//记录当前被标注的错误位置
       this.firstError = {
        isExist :false,
        row:0,
        col:0
       }
       this.isPosition = false;
       this.position = null;
       //如果没有数据,默认给出一行空行
       if(this.opt.dataObj.dataMap.length===0){
        var obj = {};
         this.header.map(function(item,index){
           obj[item] = {
             value:'',
             errorType:''
           }
         });
        this.opt.dataObj.dataMap.push(obj)
      }
     }
      HandsontableExtend.prototype = {
        constructor: HandsontableExtend,
       // extraType: ["CODE_TYPE","Date"], //不需要校验的类型
        typeMap:{'STRING':'文本','INTEGER':'整型','DOUBLE':'小数','DATE':'日期','CODE_TYPE':'枚举类型','BOOLEAN':'布尔','TIME':'小时分钟'},
        dateFormat:['yyyy-MM-dd','yyyy/MM/dd','yyyy.MM.dd'],
        timePattern:/^([0-1]{1}d|2[0-3]):([0-5]d)$/,
        /*@method 整合table的列的配置项
         */
        setColumn: function() {
          var list = [];
          for (var i = 0; i < this.header.length; i++) {
            var obj = {
              data: this.header[i] + ".value",
               150,
              height: 60
            };
            var typeData = this.opt.dataObj.headMap[this.header[i]];
            if (typeData.type === "CODE_TYPE") {
              obj.type = "dropdown";
              obj.source = this.getCodeValueList(typeData.codeValueList);
            }
            if (typeData.type === "BOOLEAN") {
              obj.type = "dropdown";
              obj.source = ['是','否'];
            }
            if(typeData.type === 'TIME'){
              obj.type = "time";
              obj.dateFormat = "h:mm";
            }
            if (typeData.type === "DATE") {
              obj.type = "date";
              obj.dateFormat = "YYYY-MM-DD";
              obj.datePickerConfig={
                firstDay: 1,
                yearRange:100,
                showWeekNumber: true,
                minDate: new Date('1900-01-01')
              }
            }
            list.push(obj);
          }
          return list;
          this.opt.set.columns = list;
        },
        setCell:function(){
          var list = [];
          var that = this;
          this.opt.dataObj.dataMap.map(function(item,index){
            Object.keys(item).forEach(function(key){
              if(item[key].originalValue){
                list.push({
                  row:index,
                  col:that.header.indexOf(key),
                  comment:{
                    value:item[key].originalValue
                  }
                })
              }
            })
          });
          return list;
        },
        getCodeValueList:function(list){
          var newList = [];
          if(list instanceof Array){
            list.map(function(item,index){
              newList.push(item.displayName);
            });
            return newList;
          }else{
            return [];
          }
        },
        /*@method 初始化table的配置,以及事件监听
         */
        init: function() {
          var that = this;
          this.opt.set = $.extend(true,
            {
              data: that.opt.dataObj.dataMap,
              comments:true,
              columns: this.setColumn(),
              cells: function(row, col, prop) {
                //单元格渲染
                this.renderer = function(instance,td,row,col,prop,value,cellProperties) {
                  Handsontable.renderers.TextRenderer.apply(this, arguments);
                  var obj = that.opt.dataObj.dataMap[row][that.header[col]];
                  $(td).attr({row:row,col:col});
                  if (typeof obj["errorType"] !== "undefined") {
                    if (obj["errorType"] === "repeat") {
                      $(td).attr({ repeat: true });
                    } else if (obj["errorType"] === "error") {
                      $(td).attr({ error: true });
                    }
                  } else {
                    $(td).css({
                      border: "1px solid #ccc",
                      color: "#999",
                      "white-space": "normal",
                      "word-break": "break-all"
                    });
                  }
                  if(obj.originalValue){
                    $(td).css({
                      'background-color':'#F1F9FF'
                    })
                  }
                };
              },
              cell:that.setCell(),
              stretchH: "all",
               "100%",
              autoWrapRow: true,
              autoRowSize: true,
              autoColumnSize: true,
              height: "600",
              maxRows: 1000,
              manualRowResize: false,
              manualColumnResize: false,
              // beforeKeyDown : function(e) {
              //     // 禁止选中列后delete键和回退键清空整列数据
              //     if (e.keyCode === 8 || e.keyCode == 46) {
              //         Handsontable.Dom.stopImmediatePropagation(e);
              //     }
              // },
              manualRowMove: true,
              manualColumnMove: true,
              contextMenu: true,
              filters: true,
              dropdownMenu: true
            },
            this.opt.set
          );
          this.opt.set.rowHeaders = function(index) {
            var repeatNum = 0;
            var errorNum =  0;
            if(that.allErrorNum[index] instanceof Array){
              for(var j=0;j<that.allErrorNum[index].length;j++){
                if(that.allErrorNum[index][j].type==='error'){
                  errorNum+=1;
                }else{
                  repeatNum+=1;
                }
              }
            }
            var html = "<span class='error-th' style='display:"+((that.allErrorNum[index]&&that.allErrorNum[index].length>0)?"block":"none")+"'></span>";
            html +=
              " <span class='error-content'>重复:" + repeatNum +
              ",错误:" + errorNum + "</span>";
            html += "<span id='column_name' style='padding-right:6px;'>" + (index + 1) + "</span>";
            return html;
          };
          this.opt.set.colHeaders = function(index) {
            var desc = that.header[index]+"规则:";
            var map = that.opt.dataObj.headMap[that.header[index]];
            if(map.minLength&&map.maxLength){
              desc=desc+'长度:'+map.minLength+'-'+map.maxLength;
            }else if(map.length){
              desc=desc+'长度:'+map.length
            }
            if(map.type){
              desc=desc+',类型:'+that.typeMap[map.type]
            }
            if(map.required){
              desc=desc+',必填'
            }
            if(map.unique){
              desc=desc+',不能重复'
            }
            var html = "<span class='remark-th'></span>";
            html += " <span class='remark-content'>"+desc+"</span>";
            if(map.required){
              html += "<span id='column_name' style='color:#ED5565'>" + that.header[index] + "</span>";
            }else{
              html += "<span id='column_name'>" + that.header[index] + "</span>";
            }
            return html;
          };
          this.table = new Handsontable(this.element, this.opt.set);
          this.table.updateSettings({
            contextMenu: {
              callback: function(key, options) {
                if (key === "about") {
                  setTimeout(function() {
                    // timeout is used to make sure the menu collapsed before alert is shown
                    alert(
                      "This is a context menu with default and custom options mixed"
                    );
                  }, 100);
                }
              },
              items: {
                row_above: {
                  name: "向上插入一行",
                  disabled: function() {
                    return that.table.getSelected()[0] === 0;
                  }
                },
                remove_row: {
                  name: "删除选中行",
                  disabled: function() {
                    // if first row, disable this option
                    return that.table.getSelected()[0] === 0;
                  }
                }
              }
            }
          });
          window.onresize = this.opt.isValidate
            ? function() {
                that.render.call(that);
              }
            : null;
          this.table.addHook("afterChange", function() {
            that.opt.isValidate && that.render.call(that);
          });
          this.table.addHook("afterRemoveRow", function() {
            that.opt.isValidate && that.render.call(that);
          });
          var topValue = 0,leftValue = 0;
          var interval = null;
          $(this.opt.el + " .wtHolder")[0].onscroll = function() {
            if (interval == null) {
              interval = setInterval(isFinishScroll, 1000);
            }
          };
          function isFinishScroll() {
            // 判断此刻到顶部的距离是否和1秒前的距离相等
            if ($(that.opt.el + " .wtHolder")[0].scrollLeft === leftValue && $(that.opt.el + " .wtHolder")[0].scrollTop === topValue) {
              clearInterval(interval);
              interval = null;
              that.validate();
              that.renderError(); 
              that.remarkShow();//渲染表头、列头标注
              if(that.position){
                $("td[row='"+that.errorPosition.row+"'][col='"+that.errorPosition.col+"']").attr('current');
              }
            } else {
              topValue = $(that.opt.el + " .wtHolder")[0].scrollTop;
              leftValue = $(that.opt.el + " .wtHolder")[0].scrollLeft;
            }
          }
          this.render();
          return this;
        },
        /*@method 渲染整个table数据
         */
        render: function() {
          var table = this.table;
          this.validate.call(this); //初始化,先验证,并标记重复项
          table.render(); //并渲染在行首部
          this.renderError();
          this.remarkShow();//渲染表头、列头标注
          $(".htInvalid").removeClass('htInvalid');
          $("td[current]").removeAttr('current');
        },
        /*@method 渲染出表头和列头的标注信息
         */
        remarkShow:function(){
          $(".remark-th").hover(function(){
            var top = $(this).closest('th').offset().top;
            var left = $(this).closest('th').offset().left;
            $(this).next().css({'top':top,"left":left})
          });
          $(".error-th").hover(function(){
            var top = $(this).closest('th').offset().top;
            var left = $(this).closest('th').offset().left+10;
            $(this).next().css({'top':top,"left":left})
          })
        },
        /*@method 渲染出重复、错误的单元格
         */
        renderError: function() {
          var that = this;
           var rowHeaderTr = $(".ht_clone_left .htCore").eq(0).find("tbody").find("tr");
           var tr = $(this.opt.el + " .htCore").eq(0).find("tbody").find("tr");
          //渲染错误项(只渲染当前可视区域的),
          //此处天坑,行头是单独的table,之前滚动后渲染位置错误。
          for (var i = 0; i < tr.length; i++) {
            var rowNum =  $(tr[i]).find("th #column_name").text();
            rowNum = parseInt(rowNum) - 1;
            //统计每一行错误项、重复项,如果列数过多,则列会渲染不完全,所以不能用选择器查出准确数据,只能使用统计出的数据
            var repeatNum = 0;
            var errorNum =  0;
            if(that.allErrorNum[rowNum] instanceof Array){
              for(var j=0;j<this.allErrorNum[rowNum].length;j++){
                if(this.allErrorNum[rowNum][j].type==='error'){
                  errorNum+=1;
                }else{
                  repeatNum+=1;
                }
              }
            }
            var errorTH = $(rowHeaderTr[i]).find("th .error-th").eq(0);
            if(repeatNum+errorNum>0){
              errorTH.css({'display':'block'});
              var top = errorTH.offset().top;
              var left = errorTH.offset().left+10;
              errorTH.next().css({'top':top,"left":left})
              errorTH.next().text('重复:'+repeatNum+',错误:'+errorNum);
            }else{
              errorTH.css({'display':'none'});
            }
            $(tr[i]).find("th .error-th,th .error-content").remove();//将另一处被渲染的行标注删除,防止误导
          }
          this.remarkShow();
        },
        /*@method 验证
         */
        validate: function() {
          var table = this.table;
          var that = this;
          this.allErrorNum = [];//初始化统计错误array
          this.firstError = {
            isExist :false,
            row:0,
            col:0
           };//初始化,第一个错误位置改为不存在
          var cellLength = table.getDataAtRow(0).length;
          var errorRows = [];
          for (var i = 0; i < cellLength; i++) {
            var cellData = table.getDataAtCol(i);
           // var newArr = [];
            cellData.map(function(item, index, arr) {
              var NewCell;
              var validateRule = that.opt.dataObj.headMap[that.header[i]];
              var dataMap = that.opt.dataObj.dataMap[index][that.header[i]];
              //if (newArr.indexOf(index) === -1) {
                //如果被重复项最后一个索引已有渲染标志,则不删除渲染标志。
                NewCell = table.getCell(index, i);
                $(NewCell).removeAttr("error");
                $(NewCell).removeAttr("repeat");
                dataMap["errorType"] = "";
              //}
              if (validateRule.required && !item) {
                dataMap["errorType"] = "error";
                $(NewCell).attr("error", true);
                that.setAllErrorNum.call(that,index,i,"error");
                errorRows.indexOf(index)===-1 && errorRows.push(index);
                return;
              }
              if(item){
                if (validateRule.type &&
                  validateRule.type === "CODE_TYPE") {
                  var list = that.getCodeValueList(validateRule.codeValueList);
                  if(list.indexOf(item)===-1){
                    dataMap["errorType"] = "error";
                    $(NewCell).attr("error", true);
                    that.setAllErrorNum.call(that,index,i,"error");
                    errorRows.indexOf(index)===-1 && errorRows.push(index);
                    return;
                  }
                }
                if(validateRule.type && validateRule.type === "BOOLEAN"){
                  if(['是','否'].indexOf(item)===-1){
                    dataMap["errorType"] = "error";
                    $(NewCell).attr("error", true);
                    that.setAllErrorNum.call(that,index,i,"error");
                    errorRows.indexOf(index)===-1 && errorRows.push(index);
                    return;
                  }
                }
                if (
                  validateRule.type &&
                  validateRule.type === "DATE"
                ) {
                  var result = false;
                  that.dateFormat.map(function(format,index){
                    if(new Date(item).format(format)===item){
                      result = true;
                    }
                  })
                  if(!result){
                    dataMap["errorType"] = "error";
                    $(NewCell).attr("error", true);
                    that.setAllErrorNum.call(that,index,i,"error");
                    errorRows.indexOf(index)===-1 && errorRows.push(index);
                    return;
                  }
                }
                if(validateRule.type &&
                  validateRule.type === "TIME" && !that.timePattern.test(item)){
                  dataMap["errorType"] = "error";
                  $(NewCell).attr("error", true);
                  that.setAllErrorNum.call(that,index,i,"error");
                  errorRows.indexOf(index)===-1 && errorRows.push(index);
                  return;
                }
                if(validateRule.type &&
                  validateRule.type === "INTEGER" && parseInt(item)!=item){
                    dataMap["errorType"] = "error";
                    $(NewCell).attr("error", true);
                    that.setAllErrorNum.call(that,index,i,"error");
                    errorRows.indexOf(index)===-1 && errorRows.push(index);
                    return;
                }
                if(validateRule.type &&
                  validateRule.type === "DOUBLE" && parseFloat(item)!=item){
                  dataMap["errorType"] = "error";
                  $(NewCell).attr("error", true);
                  that.setAllErrorNum.call(that,index,i,"error");
                  errorRows.indexOf(index)===-1 && errorRows.push(index);
                  return;
                }
                if (parseInt(validateRule.minLength) && item.length < parseInt(validateRule.minLength)) {
                  dataMap["errorType"] = "error";
                  $(NewCell).attr("error", true);
                  that.setAllErrorNum.call(that,index,i,"error");
                  errorRows.indexOf(index)===-1 && errorRows.push(index);
                  return;
                }
                if (parseInt(validateRule.maxLength) && item.length > parseInt(validateRule.maxLength)) {
                  dataMap["errorType"] = "error";
                  $(NewCell).attr("error", true);
                  that.setAllErrorNum.call(that,index,i,"error");
                  errorRows.indexOf(index)===-1 && errorRows.push(index);
                  return;
                }
                if ((!validateRule.maxLength && !validateRule.minLength&& validateRule.length) && item.length !== validateRule.length) {
                  dataMap["errorType"] = "error";
                  $(NewCell).attr("error", true);
                  that.setAllErrorNum.call(that,index,i,"error");
                  errorRows.indexOf(index)===-1 && errorRows.push(index);
                  return;
                }
                if (validateRule.regexp) {
                  var pattern = new RegExp(validateRule.regexp);
                  if(!pattern.test(item)){
                    dataMap["errorType"] = "error";
                    $(NewCell).attr("error", true);
                    that.setAllErrorNum.call(that,index,i,"error");
                    errorRows.indexOf(index)===-1 && errorRows.push(index);
                    return;
                  }
                }
                if (validateRule.unique && that.getRepeatNum(arr,item,index)) {
                  $(NewCell).attr("repeat", true);
                  dataMap["errorType"] = "repeat";
                  that.setAllErrorNum.call(that,index,i,"repeat");
                  errorRows.indexOf(index)===-1 && errorRows.push(index);
                }
              }
            });
          }
          $(".htInvalid").removeClass('htInvalid');
          this.errorRow = errorRows.length;
        },
        /*@method 辅助方法,获取table中第一个错误点的位置
         */
        setAllErrorNum:function(x,y,type){
          if(!this.firstError.isExist||this.firstError.row>x){
            this.firstError = {
              isExist:true,
              row:x,
              col:y
            };
          }
          if(!this.allErrorNum[x]){
           this.allErrorNum[x] = [];
          } 
          this.allErrorNum[x].push({
            type:type,
            row:x,
            col:y
          });
          //如果在已经定位的情况下,又修改了其他单元格到处出现新的数据,那么此处的错误定位要重新定位
          if(x === this.errorPosition.row && y === this.errorPosition.col){
            this.errorPosition.index = this.allErrorNum[x].length-1;
          }
        },
        /*@method 辅助方法,判断数组中某一个值是否有重复项
         */
        getRepeatNum:function(arr,val,i){
          var result = false;
          arr.map(function(item,index,array){
            if(item===val && index!==i){
              result = true;
            }
          })
          return result;
        },
        /*@method 下一个错误调用方法
         */
        nextError: function() {
          if (this.position) {
            $("td[current]").removeAttr("current");
            this.position = "next";
            this.nextErrorPostion();
            this.isPosition = true;
            this.scrollToError();
          }
        },
        /*@method 上一个错误调用方法
         */
        prevError: function() {
          if (this.position) {
            $("td[current]").removeAttr("current");
            this.position = "prev";
            this.prevErrorPosition();
            this.isPosition = true;
            this.scrollToError();
          }
        },
        /*@method 计算出下一个错误单元格的位置
         */
        nextErrorPostion: function() {
          var length = this.allErrorNum[this.errorPosition.row].length;
          if (this.errorPosition.index < length - 1) {
            this.errorPosition.index += 1;
            this.errorPosition.col = this.allErrorNum[this.errorPosition.row][this.errorPosition.index].col;
          } else {
            var maxLength = this.allErrorNum.length;
            for (var i = this.errorPosition.row + 1; i < maxLength; i++) {
              if (this.allErrorNum[i] instanceof Array &&this.allErrorNum[i].length>0) {
                this.errorPosition = {
                  index:0,
                  row: i,
                  col: this.allErrorNum[i][0].col
                };
                return;
              }
            }
            if (i === maxLength && (this.errorPosition.index === this.allErrorNum[i-1].length-1)) {
              this.errorPosition = {
                index:0,
                row: this.firstError.row,
                col: this.firstError.col
              };
            }
          }
        },
        /*@method 计算出上一个错误单元格的位置
         */
        prevErrorPosition: function() {
          var length = this.allErrorNum[this.errorPosition.row].length;
          if (this.errorPosition.index > 0) {
            this.errorPosition.index -= 1;
            this.errorPosition.col = this.allErrorNum[this.errorPosition.row][this.errorPosition.index].col;
          } else {
            for (var i = this.errorPosition.row - 1; i >= 0; i--) {
              if (this.allErrorNum[i] instanceof Array &&this.allErrorNum[i].length>0) {
                var len = this.allErrorNum[i].length-1;
                this.errorPosition = {
                  index:this.allErrorNum[i].length-1,
                  row: i,
                  col: this.allErrorNum[i][len].col
                };
                return;
              }
            }
          }
        },
        /*@method 滚动到errorPosition记录的位置
         */
        scrollToError: function() {
          var that = this;
          var tr = $(that.opt.el + " .htCore tbody").find("th #column_name:contains('"+(that.errorPosition.row+1)+"')").closest('tr');
          var lastTd = (tr.length>0)?tr.find("td[col='"+this.errorPosition.col+"']"):'';
          //滚动到对应行的位置,并且插件会自动渲染出新的可视区域,此时再找出定位的单元格,并标记
          $(this.opt.el + " .wtHolder").animate({ scrollTop: (this.errorPosition.row-5)*28 }, 300);
          lastTd = tr.find("td[col='"+that.errorPosition.col+"']");
          $(this.opt.el + " .wtHolder").animate({ scrollLeft: (this.errorPosition.col-1)*150 }, 300);
          setTimeout(function(){
          //此处因为是定时器,所以要注意tr和ladtTd会在定时器回掉函数开始执行时消失,所以要在定时器中重新定义,或者使用闭包
            var tr = $(that.opt.el + " .htCore tbody").find("th #column_name:contains('"+(that.errorPosition.row+1)+"')").closest('tr');
            lastTd = tr.find("td[col='"+that.errorPosition.col+"']");
            $(lastTd).attr("current",true);
            that.isPosition = false;
          },600)
        },
        /*@method 标记当前错误点
         */
        currentError: function(){
          if(!this.position){
            this.errorPosition.row = this.firstError.row;
            this.errorPosition.col = this.firstError.col;
          }
          this.isPosition = true;
          this.position = "current";
          this.scrollToError();
        },
        /*@method 获取有多少条记录是有错误的、正确的 
         *@return array [总记录数,错误数,正确数]
         */
        getErrorNum:function(){
          var total = this.opt.dataObj.dataMap.length;
          return [total,this.errorRow,total-this.errorRow];
        },
        /*@method 获取到编辑后的table数据
         */
        getData: function() {
          return this.opt.dataObj;
        }
      };
      $.fn.HandsontableExtend = function (opts) {
       var hand = new HandsontableExtend(opts);
       return hand.init(window);
      };
    })
    //修改源码部分:
    //第36508行,function showDatepicker(event)的部分,228,258分别为时间控件的高和宽
          if(this.TD.offsetTop+228>holder.offsetHeight){
            this.datePickerStyle.top = window.pageYOffset + offset.top - 228 + 'px';
          }else{
            this.datePickerStyle.top = window.pageYOffset + offset.top + (0, _element.outerHeight)(this.TD)  + 'px';
          }
          if(this.TD.offsetLeft+258>holder.offsetWidth){
            this.datePickerStyle.left = window.pageXOffset + offset.left - (0, _element.outerWidth)(this.TD) + 'px';
          }else{
            this.datePickerStyle.left = window.pageXOffset + offset.left + 'px';
          }
          //this.datePickerStyle.top = window.pageYOffset + offset.top + (0, _element.outerHeight)(this.TD) + 'px';
          //this.datePickerStyle.left = window.pageXOffset + offset.left + 'px';
    //i18n,json对象改为
    i18n:{
                previousMonth : '上一月',
                nextMonth     : '下一月',
                months        : ['一月','二月','三月','四月','五月','六月','七月','八月','九月','十月','十一月','十二月'],
                weekdays      : ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'],
                weekdaysShort : ['周日','周一','周二','周三','周四','周五','周六']
            }

     调用方法:

    
    
    var handTableExtend = $("#hot").HandsontableExtend({
    el:'#hot',
    dataObj:$scope.dataObject,
    isValidate:true,
    set:{
    height: 500
    }
    })
    //dataObject接受的数据结构
    dataObject = {
                    headMap:{
                        '姓名':{
                            isRequired:true,
                            type:'string',
                            minLength:2,
                            maxlength:20,
                            isUnique:false
                        },
                        '性别':{
                            isRequired:false,
                            type:'string',
                            isUnique:false
                        },
                        '身份证号':{
                            isRequired:true,
                            type:'string',
                            minLength:9,
                            maxlength:20,
                            isUnique:true,
                            regexp:/^[1-9][0-9]{5}(19|20)[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|31)|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}([0-9]|x|X)$/
                        },
                        '联系电话':{
                            isRequired:true,
                            type:'string',
                            //length:11,
                            isUnique:true
                        },
                        '地址':{
                            isRequired:false,
                            type:'string',
                            maxLength:50,
                            isUnique:false
                        },
                        '职位':{
                            isRequired:false,
                            type:'string',
                            isUnique:false
                        },
                        '部门':{
                            isRequired:false,
                            type:'code_type',
                            enumData:['it部','hr部','后勤部','销售部'],
                            isUnique:false
                        },
                        '入职日期':{
                            isRequired:false,
                            type:'date',
                            isUnique:false
                        }
                    },
                    dataMap:[
                        {
                            '姓名':{
                                value:'张三',
                                errorType:''
                            },
                            '性别':{
                                value:'男',
                                errorType:''
                            },
                            '身份证号':{
                                value:'',
                                errorType:''
                            },
                            '联系电话':{
                                value:'18817802351',
                                errorType:'repeat'
                            },
                            '地址':{
                                value:'上海浦东',
                                errorType:''
                            },
                            '职位':{
                                value:'it',
                                errorType:''
                            },
                            '部门':{
                                value:'it部',
                                errorType:''
                            },
                            '入职日期':{
                                value:'it部',
                                errorType:''
                            }
                        },{
                            '姓名':{value:'李四1',
                            errorType:''},
                            '性别':{value:'女',
                            errorType:''},
                            '身份证号':{value:'111222',
                            errorType:''},
                            '联系电话':{value:'18817802351',
                            errorType:''},
                            '地址':{value:'上海浦东',
                            errorType:''},
                            '职位':{value:'it',
                            errorType:''},
                            '部门':{value:'it部',
                            errorType:''},
                            '入职日期':{value:'it部',
                            errorType:''}
                        },{
                            '姓名':{value:'李四1',
                            errorType:''},
                            '性别':{value:'女',
                            errorType:''},
                            '身份证号':{value:'111222',
                            errorType:''},
                            '联系电话':{value:'18817802351',
                            errorType:''},
                            '地址':{value:'上海浦东',
                            errorType:''},
                            '职位':{value:'it',
                            errorType:''},
                            '部门':{value:'it部',
                            errorType:''},
                            '入职日期':{value:'it部',
                            errorType:''}
                        }
                    ]
                }; 

    页面html代码

    <div ng-controller="SurveyHandsontable">
        <button id="prev" ng-click="prevError()">></button>
        <button id="next" ng-click="nextError()"><</button>
        <div id="hot"></div>
        <button ng-click="getData()">点击</button>
    </div>
  • 相关阅读:
    更改THttpClientSocket连接超时时间
    咏南跨平台中间件REST API
    INDY10 BASE64编码
    HTTP协议之multipart/form-data
    WWF3动态修改工作流<第九篇>
    WWF3自定义活动<第八篇>
    WWF3追踪功能<WWF第六篇>
    WWF3状态机工作流<WWF第七篇>
    WWF3的持续化<第五篇>
    WWF3事务和异常处理类型活动<第四篇>
  • 原文地址:https://www.cnblogs.com/HappyYawen/p/8574376.html
Copyright © 2011-2022 走看看