239 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import dayjs from "./moment";
 | |
| 
 | |
| 
 | |
| const PARAMS = {
 | |
|   /* 省,直辖市代码表 */
 | |
|   provinceAndCitys: {
 | |
|     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: '国外'
 | |
|   },
 | |
| 
 | |
|   /* 每位加权因子 */
 | |
|   powers: [
 | |
|     '7',
 | |
|     '9',
 | |
|     '10',
 | |
|     '5',
 | |
|     '8',
 | |
|     '4',
 | |
|     '2',
 | |
|     '1',
 | |
|     '6',
 | |
|     '3',
 | |
|     '7',
 | |
|     '9',
 | |
|     '10',
 | |
|     '5',
 | |
|     '8',
 | |
|     '4',
 | |
|     '2'
 | |
|   ],
 | |
| 
 | |
|   /* 第18位校检码 */
 | |
|   parityBit: ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'],
 | |
| 
 | |
|   /* 性别 */
 | |
|   genders: {1: '男', 0: '女'},
 | |
| }
 | |
| 
 | |
| const Check = {
 | |
|   /* 校验地址码 */
 | |
|   checkAddressCode(addressCode) {
 | |
|     const check = /^[1-9]\d{5}$/.test(addressCode)
 | |
|     if (!check) return false
 | |
|     return !!PARAMS.provinceAndCitys[parseInt(addressCode.substring(0, 2))]
 | |
|   },
 | |
|   /* 校验日期码 */
 | |
|   checkBirthDayCode(birDayCode) {
 | |
|     const check = /^[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))$/.test(
 | |
|         birDayCode
 | |
|     )
 | |
|     if (!check) return false
 | |
|     const yyyy = parseInt(birDayCode.substring(0, 4), 10)
 | |
|     const mm = parseInt(birDayCode.substring(4, 6), 10)
 | |
|     const dd = parseInt(birDayCode.substring(6), 10)
 | |
|     const xdata = new Date(yyyy, mm - 1, dd)
 | |
|     if (xdata > new Date()) {
 | |
|       return false // 生日不能大于当前日期
 | |
|     } else {
 | |
|       return (
 | |
|           xdata.getFullYear() == yyyy &&
 | |
|           xdata.getMonth() == mm - 1 &&
 | |
|           xdata.getDate() == dd
 | |
|       )
 | |
|     }
 | |
|   },
 | |
|   /* 验证校检码 */
 | |
|   checkParityBit(idCardNo) {
 | |
|     const parityBit = idCardNo.charAt(17).toUpperCase()
 | |
|     return this.getParityBit(idCardNo) == parityBit
 | |
|   },
 | |
| // 校验15位的身份证号码
 | |
|   check15IdCardNo(idCardNo) {
 | |
|     // 15位身份证号码的基本校验
 | |
|     let check = /^[1-9]\d{7}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}$/.test(
 | |
|         idCardNo
 | |
|     )
 | |
|     if (!check) return false
 | |
|     // 校验地址码
 | |
|     const addressCode = idCardNo.substring(0, 6)
 | |
|     check = this.checkAddressCode(addressCode)
 | |
|     if (!check) return false
 | |
|     const birDayCode = '19' + idCardNo.substring(6, 12)
 | |
|     // 校验日期码
 | |
|     return this.checkBirthDayCode(birDayCode)
 | |
|   },
 | |
| 
 | |
| // 校验18位的身份证号码
 | |
|   check18IdCardNo(idCardNo) {
 | |
|     // 18位身份证号码的基本格式校验
 | |
|     let check = /^[1-9]\d{5}[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}(\d|x|X)$/.test(
 | |
|         idCardNo
 | |
|     )
 | |
|     if (!check) return false
 | |
|     // 校验地址码
 | |
|     const addressCode = idCardNo.substring(0, 6)
 | |
|     check = this.checkAddressCode(addressCode)
 | |
|     if (!check) return false
 | |
|     // 校验日期码
 | |
|     const birDayCode = idCardNo.substring(6, 14)
 | |
|     check = this.checkBirthDayCode(birDayCode)
 | |
|     if (!check) return false
 | |
|     // 验证校检码
 | |
|     return this.checkParityBit(idCardNo)
 | |
|   },
 | |
|   /* 计算校检码 */
 | |
|   getParityBit(idCardNo) {
 | |
|     const id17 = idCardNo.substring(0, 17)
 | |
|     /* 加权 */
 | |
|     let power = 0
 | |
|     for (let i = 0; i < 17; i++) {
 | |
|       power += parseInt(id17.charAt(i), 10) * parseInt(PARAMS.powers[i])
 | |
|     }
 | |
|     /* 取模 */
 | |
|     const mod = power % 11
 | |
|     return PARAMS.parityBit[mod]
 | |
|   }
 | |
| }
 | |
| 
 | |
| export default class Identity {
 | |
|   constructor(code) {
 | |
|     this.code = this.getId18(code)
 | |
|     this.init()
 | |
|   }
 | |
| 
 | |
|   init() {
 | |
|     const {code} = this
 | |
|     if (!!code) {
 | |
|       this.hideCode = Identity.hideId(code)
 | |
|       this.getIdCardInfo(code)
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   static hideId(code) {
 | |
|     return code?.replace(/^(\d{10})\d{4}(.{4}$)/g, `$1${Array(5).join('*')}$2`)
 | |
|   }
 | |
| 
 | |
|   getId18(code) {
 | |
|     if (code.length == 15) {
 | |
|       const id17 = code.substring(0, 6) + '19' + code.substring(6)
 | |
|       const parityBit = Check.getParityBit(id17)
 | |
|       return id17 + parityBit
 | |
|     } else if (code.length == 18) {
 | |
|       return code
 | |
|     } else {
 | |
|       return null
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   getIdCardInfo(idCardNo) {
 | |
|     this.birthday = Identity.getBirthday(idCardNo)
 | |
|     this.sex = Identity.getSex(idCardNo)
 | |
|     this.gender = PARAMS.genders[this.sex]
 | |
|     this.age = Identity.getAge(idCardNo)
 | |
|     this.areaId = Identity.getArea(idCardNo)
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 获取性别
 | |
|    * @param code
 | |
|    * @returns {string}
 | |
|    */
 | |
|   static getSex(code) {
 | |
|     return (Number(code.substring(16, 17)) % 2).toString()
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 获取年龄
 | |
|    * @param code
 | |
|    * @returns {number}
 | |
|    */
 | |
|   static getAge(code) {
 | |
|     const birthday = dayjs(code.substring(6, 14), 'YYYYMMDD')
 | |
|     return Math.ceil(dayjs.duration(dayjs().unix() - dayjs(birthday).unix(), 's').asYears())
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 获取地区编码
 | |
|    * @param code
 | |
|    */
 | |
|   static getArea(code) {
 | |
|     return code.substring(0, 6) + new Array(7).join(0)
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 获取生日
 | |
|    */
 | |
|   static getBirthday(code) {
 | |
|     return dayjs(code.substring(6, 14), 'YYYYMMDD').format("YYYY-MM-DD").replace('Invalid Date', '')
 | |
|   }
 | |
| 
 | |
|   /* 校验15位或18位的身份证号码 */
 | |
|   static check(idCardNo) {
 | |
|     // 15位和18位身份证号码的基本校验
 | |
|     const check = /^\d{15}|(\d{17}(\d|x|X))$/.test(idCardNo)
 | |
|     if (!check) return false
 | |
|     // 判断长度为15位或18位
 | |
|     if (idCardNo.length == 15) {
 | |
|       return Check.check15IdCardNo(idCardNo)
 | |
|     } else if (idCardNo.length == 18) {
 | |
|       return Check.check18IdCardNo(idCardNo)
 | |
|     } else {
 | |
|       return false
 | |
|     }
 | |
|   }
 | |
| }
 |