全网唯一正确身份证和社统一社会信用代码自定义表单校验器(身份证校验和社统一社会信用代码校验)

话不多说,直入正题: 

1、工具类: 

import * as moment from 'moment';
import {isUndefined} from 'util';
import {AbstractControl, ValidatorFn} from '@angular/forms';

/**
 * Created by yanchao lcj on 2020/06/28.
 */
export class StringUtils {

    constructor() {
    }

    /**
     * 判断是空字符串?
     * @param str
     */
    static isBlank(str: string) {
        return isUndefined(str) || str === null || '' === str.trim();
    }

    /**
     * 去空格
     * @param str 处理字符串
     * @return 结果字符串
     */
    static trim(str: string) {
        return str.replace('\n', '').replace(' ', '').trim();
    }

    /**
     * 判断不是空字符串?
     * @param str
     */
    static isNotBlank(str: string) {
        return !this.isBlank(str);
    }

    /**
     * 判断是空?
     * @param o
     */
    static isEmpty(o) {
        return o === null || o === 'null' || o === undefined || o === 'undefined' || o === '';
    }

    /**
     * 判断不是空?
     * @param o
     */
    static isNotEmpty(o) {
        return !this.isEmpty(o);
    }

    /**
     * 校验身份证的
     * @param code
     */
    public static identityCodeValid(code): ProcessResult {      
        // 判断是否为空 长度是否合法
        if (this.isBlank(code) || code.length !== 18) {
            return new ProcessResult(false, '身份证长度不够');
        }
        code = this.trim(code);
        // 身份证号格式错误
        if (!code || !/^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(code)) {
            return new ProcessResult(false, '身份证不合法');
        }
        // 省份对应的省编码
        const city = {
            11: '北京', 12: '天津', 13: '河北', 14: '山西', 15: '内蒙古', 21: '辽宁', 22: '吉林', 23: '黑龙江', 31: '上海',
            32: '江苏', 33: '浙江', 34: '安徽', 35: '福建', 36: '江西', 37: '山东', 41: '河南', 42: '湖北', 43: '湖南',
            44: '广东', 45: '广西', 46: '海南', 50: '重庆', 51: '四川', 52: '贵州', 53: '云南', 54: '西藏', 61: '陕西',
            62: '甘肃', 63: '青海', 64: '宁夏', 65: '新疆', 71: '台湾', 81: '香港', 82: '澳门', 91: '国外'
        };
        if (!city[code.substr(0, 2)]) {
            // 地址编码错误
            return new ProcessResult(false, '身份证前2为输入有误');
        } else {
            // 18位身份证需要验证最后一位校验位
            code = code.split('');
            // 身份证最后一位
            const lastOneCode = code[17];
            // 加权因子 ∑(ai×Wi)(mod 11)
            const factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
            // 校验位
            const parity = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
            let sum = 0;
            let ai = 0;
            let wi = 0;
            // 取前17位,(每一位数字 * 每一位数字在加权因子数组的对应的数字) 之和
            for (let i = 0; i < 17; i++) {
                ai = code[i];
                wi = factor[i];
                sum += ai * wi;
            }
            // 算出来的和 mod 11 得到 最后一位,再把传进来的身份证的最后一位和算出来的最后一位对比
            return new ProcessResult(parity[sum % 11] === lastOneCode, '身份证不合法');
        }
    }

    /**
     * 身份证自定义校验器
     */
    public static idCardNoValidator(): ValidatorFn {
        return (control: AbstractControl): { [key: string]: any } | null => {
            const processResult = this.identityCodeValid(control.value);
            return processResult.isSuccess() ? null : {idCardError: {value: control.value, message: processResult.errorMessage}};
        };
    }

    /**
     * 统一社会信用代码自定义校验器
     */
    public static unifiedCreditCodeValidator(): ValidatorFn {
        return (control: AbstractControl): { [key: string]: any } | null => {
            const processResult = this.checkUnifiedCreditCode(control.value);
            return processResult.isSuccess() ? null : {unifiedCreditCodeError: {value: control.value, message: processResult.errorMessage}};
        };
    }

    /**
     * 统一社会信用代码校验
     * @param uniCode
     */
    public static checkUnifiedCreditCode(uniCode: string): ProcessResult {      
        // 假如不是18位,错误
        if (!uniCode || uniCode.length !== 18) {
            return new ProcessResult(false, '统一社会信用代码长度不合法');
        }
        uniCode = this.trim(uniCode);
        // 统一社会信用代码由18位阿拉伯数字或英文大写字母表示(不包括I,O,Z,S,V以防止和阿拉伯字母混淆)-->V:???关我毛事?
        const upUniCode = uniCode.toUpperCase();
        if (upUniCode.indexOf('I') !== -1 || upUniCode.indexOf('O') !== -1 || upUniCode.indexOf('Z') !== -1 || upUniCode.indexOf('S') !== -1 || upUniCode.indexOf('V') !== -1) {
            return new ProcessResult(false, '统一社会信用代码不能含有(I,O,Z,S,V)');
        }
        // (组织机构代码)校验
        const orgCheckCode = [
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
            'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
            'U', 'V', 'W', 'X', 'Y', 'Z'
        ];
        // 组织机构代码加权因子
        const orgWeight = [3, 7, 9, 10, 5, 8, 4, 2];
        const orgCode = uniCode.substr(8, 9);
        let sumOrg = 0;
        // 去前8位数 每一位数对应在orgWeight数组的下标 * 对应的加权因子 之和
        for (let i = 0; i < 8; i++) {
            const tmpAttr = orgCode[i] as any;
            const tmpCode = orgCheckCode.indexOf(tmpAttr);
            const tmpWeight = orgWeight[i];
            sumOrg += (tmpCode * tmpWeight);
        }
        // 再用11 - 算出的合数 mod 11
        const modOrg = 11 - sumOrg % 11;
        // 再用算出来的数字转换成最后一位的数字 拿到最后一个字符
        const modOrgLast = (modOrg === 10) ? 'X' : ((modOrg === 11) ? '0' : ('' + modOrg));
        // 对比算出来的最后一位是否等于给我的组织机构代码的最后一位
        if (modOrgLast !== orgCode[8]) {
            return new ProcessResult(false, '统一社会信用代码中的组织机构代码不合法');
        }
        // 最后一位的校验 (A=10, B=11,以此类推)
        const uniCheckCode = [
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q',
            'R', 'T', 'U', 'W', 'X', 'Y'
        ];
        // 统一社会信用代码加权因子
        const uniCodeWeight = [1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28];
        let sumUniCode = 0;
        // 去前17位数 每一位数对应在uniCheckCode数组的下标 * 对应的加权因子 之和
        for (let i = 0; i < 17; i++) {
            const tmpAttr = uniCode[i] as any;
            const tmpCode = uniCheckCode.indexOf(tmpAttr);
            const tmpWeight = uniCodeWeight[i];
            sumUniCode += (tmpCode * tmpWeight);
        }
        // 再用31 - 算出的合数 mod 31
        const modOrgUni = 31 - sumUniCode % 31;
        // 在uniCheckCode数组找出对应的字符就是最后一位
        const modOrgUniLast = uniCheckCode[modOrgUni % 31];
        // 对比算出来的最后一位是否等于给我的信用代码的最后一位
        return new ProcessResult(modOrgUniLast + '' === uniCode[17] + '', '统一社会信用代码不合法');
    }

    /**
     * 根据身份证号码获取生日年龄性别
     */
    public static getIdCardInformation(idCardNo): IdCardInformation {
        const processResult = this.identityCodeValid(idCardNo);
        if (processResult.isFailure()) {
            return new IdCardInformation(undefined, undefined, undefined);
        }
        // 区分二代身份证
        const mark = idCardNo.length > 15;
        // 获取身份证上的出生日期
        const birthday = moment(idCardNo.substring(6, mark ? 14 : 11), 'YYYYMMDD').toDate();
        // 算出年龄
        const age = new Date().getFullYear() - birthday.getFullYear();
        // 得出年龄
        const gender = !(Number(idCardNo.charAt(mark ? 16 : 14)) % 2 === 0);
        // 返回身份证信息
        return new IdCardInformation(birthday, age, gender);
    }
}

/**
 * 身份证信息
 */
class IdCardInformation {

    /**
     * 出生日期
     */
    birthday: Date;

    /**
     * 年龄
     */
    age: number;

    /**
     * 性别
     */
    gender: boolean;

    constructor(birthday: Date, age: number, gender: boolean) {
        this.birthday = birthday;
        this.age = age;
        this.gender = gender;
    }
}

/**
 * 处理结果
 */
class ProcessResult {

    /**
     * 成功?
     */
    success: boolean;

    /**
     * 错误信息
     */
    errorMessage: string;

    constructor(success: boolean, errorMessage: string) {
        this.success = success;
        this.errorMessage = errorMessage;
    }

    /**
     * 是成功的?
     */
    isSuccess() {
        return this.success;
    }

    /**
     * 是失败的?
     */
    isFailure() {
        return !this.success;
    }
}

2、表单对象 :

this.formGroup = this.fb.group({
    // 证件号码
    idCard: [null, [Validators.required, StringUtils.idCardNoValidator()]]
});

 3、页面用管道显示错误信息:

<nz-form-item>
    <nz-form-label [nzSm]="4" [nzXs]="12" nzRequired>证件号码</nz-form-label>
        <nz-form-control [nzValidateStatus]="formGroup.get('idCard')"
                             nzHasFeedback [nzErrorTip]="formGroup.get('idCard').errors | errorMessage"
                             [nzSm]="7" [nzXs]="12">
            <input nz-input formControlName="idCard" placeholder="请输入证件号码"/>
    </nz-form-control>
</nz-form-item>

4、管道的类:

import {Pipe, PipeTransform} from '@angular/core';
import {ValidationErrors} from '@angular/forms';

@Pipe({
    name: 'errorMessage'
})
export class ErrorMessagePipe implements PipeTransform {

    constructor() {
    }

    errors: ValidationErrors;

    formatError(key) {
        switch (key) {
            case 'required':
                return '必填项';
            case 'idCardError':
                return this.errors[key].message;
            case 'unifiedCreditCodeError':
                return this.errors[key].message;
            default:
                return '';
        }
    }

    transform(errors: ValidationErrors): any {
        this.errors = errors;
        // tslint:disable-next-line:forin
        for (const key in errors) {
            return this.formatError(key);
        }
    }

}

效果:

 

 

5、校验身份证获取身份证信息:

const value = "身份证号码";

// 获取身份证里面的信息如:出生日期 年龄 性别  当然还可以获得出生地,这里我没实现
const idCardInformation = StringUtils.getIdCardInformation(value);

// 身份证校验
const success = StringUtils.identityCodeValid(value).isSuccess();

// 统一社会信用代码校验
const success1 = StringUtils.checkUnifiedCreditCode(‘****’).isSuccess();

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值