Files
qingdao-employment-service/utils/IDCardParser.js

227 lines
6.8 KiB
JavaScript
Raw Normal View History

2025-12-25 12:52:54 +08:00
// 使用示例:
// import IDCardParser from '@/utils/IDCardParser';
// const handleCheck = (idStr) => {
// const parser = new IDCardParser(idStr);
// const result = parser.getInfo();
// if(result.valid) {
// // 填充表单
// console.log(result.age, result.gender);
// } else {
// alert(result.message);
// }
// }
class IDCardParser {
constructor(idNumber) {
this.idNumber = idNumber ? idNumber.trim().toUpperCase() : "";
this.provinceMap = {
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: "澳门特别行政区"
};
// 初始化验证结果
const validation = this._validate();
this.isValid = validation.isValid;
this.errorMsg = validation.msg;
// 如果合法,预先解析数据
if (this.isValid) {
this._parseData();
}
}
/**
* 核心校验逻辑
*/
_validate() {
// 1. 基础正则 (18位末位数字或X)
if (!/^\d{17}[\d|X]$/.test(this.idNumber)) {
return {
isValid: false,
msg: "格式错误必须是18位末位为数字或X"
};
}
// 2. 省份校验
const provinceCode = parseInt(this.idNumber.substring(0, 2));
if (!this.provinceMap[provinceCode]) {
return {
isValid: false,
msg: "省份代码错误"
};
}
// 3. 日期合法性严格校验
const year = parseInt(this.idNumber.substring(6, 10));
const month = parseInt(this.idNumber.substring(10, 12));
const day = parseInt(this.idNumber.substring(12, 14));
const date = new Date(year, month - 1, day);
// JS Date会自动纠错(例如2月30会变成3月),所以必须反向比对
if (
date.getFullYear() !== year ||
date.getMonth() + 1 !== month ||
date.getDate() !== day
) {
return {
isValid: false,
msg: "出生日期无效"
};
}
// 检查年份范围可选例如限制在1900年以后
if (year < 1900 || date > new Date()) {
return {
isValid: false,
msg: "出生日期不在合理范围内"
};
}
// 4. 校验码计算 (ISO 7064:1983.MOD 11-2)
if (!this._checkSum()) {
return {
isValid: false,
msg: "校验码错误(身份证可能无效)"
};
}
return {
isValid: true,
msg: "验证通过"
};
}
/**
* 校验码算法
*/
_checkSum() {
const factors = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
const checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
let sum = 0;
for (let i = 0; i < 17; i++) {
sum += parseInt(this.idNumber[i]) * factors[i];
}
const mod = sum % 11;
return checkCodes[mod] === this.idNumber[17];
}
/**
* 解析内部数据
*/
_parseData() {
const year = parseInt(this.idNumber.substring(6, 10));
const month = parseInt(this.idNumber.substring(10, 12));
const day = parseInt(this.idNumber.substring(12, 14));
this.birthDate = new Date(year, month - 1, day);
this.province = this.provinceMap[parseInt(this.idNumber.substring(0, 2))];
// 性别第17位奇数男偶数女
const genderCode = parseInt(this.idNumber.substring(16, 17));
this.gender = genderCode % 2 !== 0 ? "男" : "女";
}
/**
* 获取所有信息
*/
getInfo() {
if (!this.isValid) {
return {
valid: false,
message: this.errorMsg
};
}
return {
valid: true,
idNumber: this.idNumber,
province: this.province,
birthday: this._formatDate(this.birthDate),
gender: this.gender,
age: this._calculateAge(),
zodiac: this._getZodiac(), // 生肖
constellation: this._getConstellation() // 星座
};
}
_formatDate(date) {
const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, '0');
const d = String(date.getDate()).padStart(2, '0');
return `${y}-${m}-${d}`;
}
_calculateAge() {
const today = new Date();
let age = today.getFullYear() - this.birthDate.getFullYear();
const m = today.getMonth() - this.birthDate.getMonth();
// 如果没过生日年龄减1
if (m < 0 || (m === 0 && today.getDate() < this.birthDate.getDate())) {
age--;
}
return age;
}
_getZodiac() {
// 猴鸡狗猪鼠牛虎兔龙蛇马羊 (对应余数 0-11)
const zodiacs = "猴鸡狗猪鼠牛虎兔龙蛇马羊";
return zodiacs.charAt(this.birthDate.getFullYear() % 12);
}
_getConstellation() {
const month = this.birthDate.getMonth() + 1;
const day = this.birthDate.getDate();
// 星座分割日
const dates = [20, 19, 21, 20, 21, 22, 23, 23, 23, 24, 23, 22];
const constellations = [
"摩羯座", "水瓶座", "双鱼座", "白羊座", "金牛座", "双子座",
"巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "摩羯座"
];
if (day < dates[month - 1]) {
return constellations[month - 1];
} else {
return constellations[month];
}
}
}
export default IDCardParser;