修正ts类型

This commit is contained in:
Zy
2026-05-13 15:28:25 +08:00
parent 1b738c0f4d
commit a1750bc67b
114 changed files with 2346 additions and 613 deletions

View File

@@ -64,3 +64,153 @@ export type RegType = keyof typeof reg;
export function validator(value: string | number, regType: RegType): boolean {
return reg[regType].test(String(value));
}
/**
* 车牌验证工具类
* 支持传统燃油、新能源、军警、武警、使馆、临时、港澳等全量车牌
*/
export class LicensePlateValidator {
/**
* 省份简称正则片段
*/
private static readonly PROVINCE = '[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼]';
/**
* 使领馆前缀
*/
private static readonly EMBASSY_PREFIX = '[使领]';
/**
* 验证传统燃油车牌 (蓝牌/黄牌)
* 格式: 省份 + 字母 + 5位字符
* 示例: 京A·12345, 粤B·88888
*/
static isTraditionalPlate(plate: string): boolean {
// 包含普通民用以及使领馆非新能源部分(如果使领馆归为此类,通常使领馆有单独规则,这里仅指普通民用)
// 注意:使领馆车牌通常格式特殊,见 isEmbassyPlate
const reg = new RegExp(`^${this.PROVINCE}[A-HJ-NP-Z][A-HJ-NP-Z0-9]{5}$`);
return reg.test(plate.toUpperCase());
}
/**
* 验证新能源车牌 (绿牌)
* 小型: 省份 + 字母 + D/F + 4位数字/字母 或 省份 + 字母 + 5位数字/字母 + D/F
* 大型: 省份 + 字母 + 5位数字/字母 + D/F (通常最后一位是D/F)
* 示例: 京AD12345, 京A12345D, 沪AF12345
*/
static isNewEnergyPlate(plate: string): boolean {
// 小型新能源第2位或第7位是D/F
// 大型新能源最后一位是D/F (且总长8位)
// 综合正则:
// 1. [省份][A-HJ-NP-Z][D-F][0-9A-HJ-NP-Z]{4} (小型D/F在第2位)
// 2. [省份][A-HJ-NP-Z][0-9A-HJ-NP-Z]{4}[D-F] (小型/大型D/F在最后)
// 3. [省份][A-HJ-NP-Z][0-9A-HJ-NP-Z][D-F][0-9A-HJ-NP-Z]{3} (较少见但某些早期试点或特殊编排可能存在标准通常只认1和2)
// 更严谨的标准新能源正则 (GA 804-2018):
// 小型: [省份][A-HJ-NP-Z][D-F][0-9A-HJ-NP-Z]{4} | [省份][A-HJ-NP-Z][0-9A-HJ-NP-Z]{4}[D-F]
// 大型: [省份][A-HJ-NP-Z][0-9A-HJ-NP-Z]{5}[D-F] (其实包含在上面第二种情况的子集里只要保证总长8位)
const reg = new RegExp(`^${this.PROVINCE}[A-HJ-NP-Z](?:[D-F][0-9A-HJ-NP-Z]{4}|[0-9A-HJ-NP-Z]{5}[D-F])$`);
return reg.test(plate.toUpperCase());
}
/**
* 验证警车车牌
* 格式: 省份 + 字母 + 4位数字 + 警
* 示例: 京A·1234警
*/
static isPolicePlate(plate: string): boolean {
const reg = new RegExp(`^${this.PROVINCE}[A-HJ-NP-Z][0-9]{4}警$`);
return reg.test(plate.toUpperCase());
}
/**
* 验证教练车牌
* 格式: 省份 + 字母 + 4位数字 + 学
* 示例: 京A·1234学
*/
static isCoachPlate(plate: string): boolean {
const reg = new RegExp(`^${this.PROVINCE}[A-HJ-NP-Z][0-9]{4}学$`);
return reg.test(plate.toUpperCase());
}
/**
* 验证武警车牌 (2013式)
* 格式: WJ + 省份/部门简称 + 5位字符
* 示例: WJ·京12345, WJ·12345X, WJ·B12345
* 注意WJ后紧跟的可能是省份简称或部门字母
*/
static isArmedPolicePlate(plate: string): boolean {
// WJ + (省份简称 | 部门字母) + 5位字符
// 部门字母包括: 内边消水电林通海等,这里简化处理,允许字母或省份
const reg = /^WJ(?:[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼]|[A-Z])[0-9A-HJ-NP-Z]{5}$/;
return reg.test(plate.toUpperCase());
}
/**
* 验证军队车牌 (2012式)
* 格式: 军种字母 + · + 5位字符 (实际输入常不带点)
* 军种: V(军委), K(空军), H(海军), B(北京军区), S(沈阳), L(兰州), J(济南), N(南京), G(广州), C(成都) 等
* 示例: V·12345, K·A1234
*/
static isMilitaryPlate(plate: string): boolean {
// 简化版首字母为大写排除I,O后跟5位字符
// 更严谨应限制首字母为特定军种代号,但考虑到军改变化,此处做通用校验
// 2012式军牌格式XY·12345 (X为军种/大区Y为单位)
// 常见前缀: V, K, H, B, S, L, J, N, G, C, M, P, O, A, E 等
const reg = /^[VKBHSLJNGCMPEOA][A-HJ-NP-Z0-9][0-9A-HJ-NP-Z]{4}$/;
return reg.test(plate.toUpperCase());
}
/**
* 验证使馆/领馆车牌
* 格式: 使/领 + 3位数字 + 3位数字 (共6位数字或 使·123456)
* 示例: 使·123456, 领·123456
*/
static isEmbassyPlate(plate: string): boolean {
const reg = /^[使领][0-9]{6}$/;
return reg.test(plate);
}
/**
* 验证港澳入出境车 (粤Z牌)
* 格式: 粤Z + 4位字符 + 港/澳
* 示例: 粤Z·1234港, 粤Z·1234澳
*/
static isHKMacauPlate(plate: string): boolean {
const reg = /^粤Z[A-HJ-NP-Z0-9]{4}[港澳]$/;
return reg.test(plate.toUpperCase());
}
/**
* 验证临时车牌
* 格式: 省份 + 字母 + 5位字符 + 临 / 超
* 示例: 京A·12345临, 沪B·12345超
*/
static isTemporaryPlate(plate: string): boolean {
const reg = new RegExp(`^${this.PROVINCE}[A-HJ-NP-Z][0-9A-HJ-NP-Z]{5}[临超]$`);
return reg.test(plate.toUpperCase());
}
/**
* 验证所有合法车牌(全量)
* @param plate 车牌号码
*/
static isValidPlate(plate: string): boolean {
if (!plate || typeof plate !== 'string') return false;
const upperPlate = plate.toUpperCase().replace(/[·\s-]/g, ''); // 去除分隔符和空格
return (
this.isTraditionalPlate(upperPlate) ||
this.isNewEnergyPlate(upperPlate) ||
this.isPolicePlate(upperPlate) ||
this.isCoachPlate(upperPlate) ||
this.isArmedPolicePlate(upperPlate) ||
this.isMilitaryPlate(upperPlate) ||
this.isEmbassyPlate(upperPlate) ||
this.isHKMacauPlate(upperPlate) ||
this.isTemporaryPlate(upperPlate)
);
}
}