新老外国人永久居留证转换JS函数

589 阅读2分钟

随着2023年12月初新版外国人永久居留证的发布,其证件信息进行了不少更新。新版证件号码跟二代身份证一样,为18位数字了,固定以9开头,跟老版外国人证号码并不能直接进行转换,但可通过读取证件芯片信息进行转换。本文将提供新版外国人永久居留证证件号码JS函数,实现新版外国人证件号码转换为旧版号码


/**
 * 新老外国人永久居留证证件号码转换
 * 通常是通过读取新版外国人证,通过里面芯片信息才能转换得到旧版外国人证
 * @param newCardNo 新版外国人证号码
 * @param newCardNation 新版外国人证民族,其实是国籍代码
 * @param newCardRelatedItem 新版外国人证读卡芯片里的relatedItem信息
 * @example 
 * ```js
 * foreignCardFromNewToOld('932586198001010029', 'PAK', '010') // -> 'PAK320180010103'
 * ```
 */
export function foreignCardFromNewToOld(
  newCardNo: string = '',
  newCardNation: string = '',
  newCardRelatedItem: string = ''
): string {
  if (!newCardNo || !newCardNation || !newCardRelatedItem) {
    return '';
  }

  // 旧版外国人证前14位
  const strOldCardNo14Chars: string = [
    // 第1-3位,国籍
    newCardNation,
    // 第4-5位,首次申领地所属省行政区数字代码
    newCardNo.slice(1, 3),
    // 第6-7位,首次申领地所属市行政区数字代码
    newCardRelatedItem.slice(0, 2),
    // 第8-13位,6位的出生日期
    newCardNo.slice(8, 14),
    // 第14位,顺序吗
    newCardRelatedItem.slice(2, 3),
  ].join('');

  const resultDigit = calculateCheckDigitOldForeignCard(strOldCardNo14Chars);
  if (!resultDigit.success) {
    return '';
  }
  const strOldCardNoLastChar: string = resultDigit.result.toString();
  return strOldCardNo14Chars + strOldCardNoLastChar;
}

/**
 * 计算旧版外国人永居证的第15位校验位
 * @param id 旧版外国人永居证的前14位
 * @example
 * ```javascript
 * calculateCheckDigitOldForeignCard('PAK32018108031') // -> 2
 * ```
 */
export function calculateCheckDigitOldForeignCard(id: string): {
  success: boolean;
  result?: number;
  errorMsg?: string;
} {
  if (id?.length !== 14) {
    return { success: false, errorMsg: '计算校验外国人永居证第15位号段时,输入的证号长度应为14位。' };
  }
  if (!/[a-z]{3}[0-9]{11}/i.test(id)) {
    return { success: false, errorMsg: '非有效输入,前3位必须为字母,后面为数字。' };
  }

  let sum = 0;
  const weight = [7, 3, 1];
  for (let i = 0; i < 14; i++) {
    const char = id[i];
    let charValue;
    if (i < 3) {
      // Convert latin letters to number according to the mapping
      charValue = char.charCodeAt(0) - 'A'.charCodeAt(0) + 10;
    } else {
      charValue = Number(char);
    }
    sum += charValue * weight[i % 3];
  }
  // Use the remainder of the sum / 10 as the check digit
  return { success: true, result: sum % 10 };
}