Files
shanxia2.0/web-admin/src/utils/pl-paste-recognize.ts
T
2026-08-19 22:20:42 +08:00

174 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 三方车辆/人员客户文本粘贴解析
* 标准格式见 `PL_PASTE_SAMPLE_TEXT`。
*/
/**
* 粘贴识别输入框预填示例(格式与解析规则一致,敏感字段已脱敏,供用户对照改写)
* 姓名保留姓、手机保留前 3 后 4、身份证保留前 6 后 4、车牌保留省份简称后打码
*/
export const PL_PASTE_SAMPLE_TEXT = [
'车牌:皖******皖******挂',
'核载:34 吨',
'驾驶员:张**',
'身份证号:340000********0000',
'手机号:138****0000',
'押运员:李**',
'身份证号:340000********0000',
'电话:139****0000'
].join('\n')
export interface PlPastePersonnelDraft {
personnelName: string
phoneNo?: string
idCardNo?: string
personnelType: 'driver' | 'escort'
}
export interface PlPasteVehicleDraft {
licensePlate: string
trailerNo?: string
loadCapacity?: number
}
export interface PlPasteRecognizeResult {
vehicle?: PlPasteVehicleDraft
driver?: PlPastePersonnelDraft
escort?: PlPastePersonnelDraft
warnings: string[]
}
/** 普通蓝牌 7 位、挂车带「挂」、新能源约 8 位;每次新建避免 lastIndex 残留 */
function plateTokenRe() {
return /[\u4e00-\u9fa5][A-HJ-NP-Z][A-HJ-NP-Z0-9]{4,6}挂?/gi
}
const PLATE_LINE_LABEL = /^(?:车牌号|车牌|主车号|主车|号牌)[::]\s*/i
const TRAILER_LINE_LABEL = /^(?:挂车号|挂车)[::]\s*/i
const ID_CARD_LINE = /^(?:身份证号码|身份证号|身份证|证件号)[::]?\s*([0-9Xx]{15,18})$/
function extractPlates(text: string): string[] {
const compact = text.replace(/\s+/g, '').toUpperCase()
const found = compact.match(plateTokenRe()) || []
return found
}
function remainderAfterPlates(text: string, plates: string[]): string {
let rest = text.replace(/\s+/g, '').toUpperCase()
for (const plate of plates) {
rest = rest.replace(plate.toUpperCase(), '')
}
return rest.replace(/[,,、;;\-_//]/g, '')
}
function applyPlatesToVehicle(
vehicle: PlPasteVehicleDraft | undefined,
plates: string[]
): PlPasteVehicleDraft {
const next = vehicle || { licensePlate: '' }
if (plates[0] && !next.licensePlate) {
next.licensePlate = plates[0]
}
if (plates[1] && !next.trailerNo) {
next.trailerNo = plates[1]
} else if (plates.length === 1 && plates[0].endsWith('挂') && next.licensePlate && !next.trailerNo) {
next.trailerNo = plates[0]
if (next.licensePlate === plates[0]) {
next.licensePlate = ''
}
}
return next
}
export function parsePlCustomerVehicleText(raw: string): PlPasteRecognizeResult {
const warnings: string[] = []
const lines = raw
.split(/\r?\n/)
.map(l => l.trim())
.filter(Boolean)
let vehicle: PlPasteVehicleDraft | undefined
let driver: PlPastePersonnelDraft | undefined
let escort: PlPastePersonnelDraft | undefined
let section: 'none' | 'driver' | 'escort' = 'none'
for (const line of lines) {
if (TRAILER_LINE_LABEL.test(line)) {
const plates = extractPlates(line.replace(TRAILER_LINE_LABEL, ''))
if (plates.length) {
if (!vehicle) vehicle = { licensePlate: '' }
vehicle.trailerNo = plates[0]
continue
}
}
const plateLabeled = PLATE_LINE_LABEL.test(line)
const plateSource = plateLabeled ? line.replace(PLATE_LINE_LABEL, '') : line
const plates = extractPlates(plateSource)
if (plates.length && (plateLabeled || !remainderAfterPlates(plateSource, plates))) {
vehicle = applyPlatesToVehicle(vehicle, plates)
continue
}
const load = line.match(/核载[::]?\s*([\d.]+)\s*吨?/)
if (load) {
if (!vehicle) {
vehicle = { licensePlate: '' }
}
vehicle.loadCapacity = Number(load[1])
continue
}
if (/^驾驶员[::]/.test(line)) {
section = 'driver'
driver = {
personnelName: line.replace(/^驾驶员[::]\s*/, '').trim(),
personnelType: 'driver'
}
continue
}
if (/^押运员[::]/.test(line)) {
section = 'escort'
escort = {
personnelName: line.replace(/^押运员[::]\s*/, '').trim(),
personnelType: 'escort'
}
continue
}
const phone = line.match(/^(?:手机号|电话)[::]?\s*(\d{11})$/)
if (phone) {
if (section === 'driver' && driver) {
driver.phoneNo = phone[1]
continue
}
if (section === 'escort' && escort) {
escort.phoneNo = phone[1]
continue
}
}
const idCard = line.match(ID_CARD_LINE)
if (idCard) {
const no = idCard[1].toUpperCase()
if (section === 'driver' && driver) {
driver.idCardNo = no
continue
}
if (section === 'escort' && escort) {
escort.idCardNo = no
continue
}
}
warnings.push(`未识别行:${line}`)
}
if (vehicle && !vehicle.licensePlate.trim()) {
warnings.push('未识别到主车车牌')
}
return { vehicle, driver, escort, warnings }
}