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 } } }