zcloud-gbs-primeport-react/src/utils/index.js

273 lines
6.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { useEffect, useRef, useState } from "react";
/**
* 校验中国大陆18位身份证号
* 包含地址码、年份(18/19/20开头)、月份、日期、顺序码和校验位
* @param {string} idCard
* @returns {boolean}
*/
export function isValidChineseIdCard(idCard) {
if (!idCard || typeof idCard !== "string") {
return false;
}
const value = idCard.trim();
if (!isValidChineseIdCardFormat(value)) {
return false;
}
const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
const checkCodeMap = ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"];
const sum = value
.substring(0, 17)
.split("")
.reduce((total, num, index) => total + Number(num) * weights[index], 0);
return checkCodeMap[sum % 11] === value[17].toUpperCase();
}
export function isValidChineseIdCardFormat(idCard) {
if (!idCard || typeof idCard !== "string") {
return false;
}
const value = idCard.trim();
const pattern = /^[1-9][0-9]{5}(18|19|20)[0-9]{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])[0-9]{3}[0-9Xx]$/;
if (!pattern.test(value)) {
return false;
}
const year = Number.parseInt(value.substring(6, 10), 10);
const month = Number.parseInt(value.substring(10, 12), 10);
const day = Number.parseInt(value.substring(12, 14), 10);
const date = new Date(year, month - 1, day);
return (
date.getFullYear() === year
&& date.getMonth() === month - 1
&& date.getDate() === day
);
}
export function getChineseIdCardInputErrorMessage(idCard) {
if (!idCard || typeof idCard !== "string") {
return "";
}
const value = idCard.trim();
if (!/^[0-9Xx]*$/.test(value)) {
return "身份证号只能输入数字或X";
}
if (value.length > 18) {
return "身份证号长度不能超过18位";
}
if (value.length < 18) {
return "";
}
if (!isValidChineseIdCardFormat(value)) {
return "请输入正确的18位身份证号";
}
return "";
}
export function getChineseIdCardFullErrorMessage(idCard) {
const inputErrorMessage = getChineseIdCardInputErrorMessage(idCard);
if (inputErrorMessage) {
return inputErrorMessage;
}
if (!idCard || typeof idCard !== "string") {
return "";
}
const value = idCard.trim();
if (value.length < 18) {
return "";
}
if (!isValidChineseIdCard(value)) {
return "身份证校验位不正确";
}
return "";
}
/**
* 根据身份证号计算年龄
* @param {string} idCard - 18位身份证号码
* @returns {number | null} 年龄(整数),无效身份证返回 null
*/
export function getAgeByIdCard(idCard) {
// 非空 & 类型校验
if (!idCard || typeof idCard !== "string") {
return null;
}
// 只处理18位身份证
const id = idCard.trim();
if (id.length !== 18) {
return null;
}
// 提取出生年月日第7~14位索引6~13
const birthStr = id.substring(6, 14); // 如 "19900101"
const year = Number.parseInt(birthStr.substring(0, 4), 10);
const month = Number.parseInt(birthStr.substring(4, 6), 10);
const day = Number.parseInt(birthStr.substring(6, 8), 10);
// 简单校验日期合法性(可选增强)
if (
year < 1900
|| year > new Date().getFullYear()
|| month < 1
|| month > 12
|| day < 1
|| day > 31
) {
return null;
}
// 构造出生日期
const birthDate = new Date(year, month - 1, day); // 月份从0开始
const today = new Date();
// 计算年龄
let age = today.getFullYear() - birthDate.getFullYear();
const monthDiff = today.getMonth() - birthDate.getMonth();
const dayDiff = today.getDate() - birthDate.getDate();
// 如果还没过生日减1岁
if (monthDiff < 0 || (monthDiff === 0 && dayDiff < 0)) {
age -= 1;
}
return age >= 0 ? age : null; // 年龄不能为负
}
/**
* 从18位身份证号中提取出生年月日
* @param {string} idCard - 身份证号码
* @returns {{ year: number; month: number; day: number } | null} 出生年月日对象,无效则返回 null
*/
export function getBirthDateFromIdCard(idCard) {
if (!idCard || typeof idCard !== "string") {
return null;
}
const id = idCard.trim();
if (id.length !== 18) {
return null; // 仅支持18位身份证
}
// 提取第7~14位YYYYMMDD
const birthStr = id.substring(6, 14); // 如 "19900307"
const year = Number.parseInt(birthStr.substring(0, 4), 10);
const month = Number.parseInt(birthStr.substring(4, 6), 10);
const day = Number.parseInt(birthStr.substring(6, 8), 10);
// 简单合法性校验
const currentYear = new Date().getFullYear();
if (
year < 1900
|| year > currentYear + 1 // 允许未来1年录入误差
|| month < 1
|| month > 12
|| day < 1
|| day > 31
) {
return null;
}
return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
}
export function useDebounce(value, delay = 500) {
const [debouncedValue, setDebouncedValue] = useState(value);
const timerRef = useRef(null);
useEffect(() => {
// 清除上一次的定时器
if (timerRef.current) {
clearTimeout(timerRef.current);
}
// 设置新的定时器
timerRef.current = setTimeout(() => {
setDebouncedValue(value);
}, delay);
// 组件卸载或 delay/value 变化时清理
return () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
};
}, [value, delay]);
return debouncedValue;
}
// 手机号脱敏
export function maskPhone(phone) {
if (!phone)
return "";
const str = String(phone).replace(/\s+/g, ""); // 去除空格
if (!/^1[3-9]\d{9}$/.test(str)) {
return phone; // 非标准手机号,原样返回
}
return `${str.substring(0, 3)}****${str.substring(7)}`;
}
// 身份证号脱敏
export function maskIdCard(idCard) {
if (!idCard)
return "";
// 转为字符串并去除空格
const str = String(idCard).replace(/\s+/g, "");
// 判断是否为 18 位身份证(支持末尾 X/x
if (!/^\d{17}[\dX]$/i.test(str)) {
return idCard; // 非标准身份证,原样返回
}
return `${str.substring(0, 6)}********${str.substring(14)}`;
}
// 属地
export const getAreaNamePath = (item) => {
const names = [
item.provinceName,
item.cityName,
item.countryName,
item.streetName,
item.villageName,
].filter(name => name != null && name !== "");
return names.join("/");
};
// 行业类型
export const getCorpTypeNamePath = (item) => {
const names = [
item.corpTypeName,
item.corpType2Name,
item.corpType3Name,
item.corpType4Name,
].filter(name => name != null && name !== "");
return names.join("/");
};
// 身份证解码
export const UseDecodeIdCard = (userIdCard) => {
if (!userIdCard)
return userIdCard;
try {
const decoded = atob(userIdCard);
if (/^\d{17}[\dX]$/.test(decoded)) {
return decoded;
}
}
catch {
console.warn("Not a valid Base64 string, keep as is:", userIdCard);
}
return userIdCard; // fallback
};