flat: bug修复
This commit is contained in:
227
utils/IDCardParser.js
Normal file
227
utils/IDCardParser.js
Normal file
@@ -0,0 +1,227 @@
|
||||
// 使用示例:
|
||||
// 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;
|
||||
Reference in New Issue
Block a user