GuDingZiChan/backend/src/utils/equipmentCode.ts
2026-03-10 16:19:47 +08:00

107 lines
3.2 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.

// 资产类型数字代码映射(纯数字编码)
const EQUIPMENT_TYPE_NUMBERS: Record<string, number> = {
'相机': 1,
'镜头': 2,
'三脚架': 3,
'闪光灯': 4,
'摄影配饰品': 5
}
/**
* 生成资产编码(纯数字格式)
* 格式: {类型数字}{地址ID(4位)}{序号(5位)}
* 例如: 1000100001 (类型1,地址1,序号00001)
* 如果没有地址,地址ID为0000
*
* 确保唯一性:
* 1. 查找该类型和地址的最大序号,避免并发问题
* 2. 检查生成的编码是否已存在,如果存在则递增序号重试
* 3. 最多重试10次,防止无限循环
*/
export const generateEquipmentCode = async (
equipmentType: string,
prisma: any,
storageLocationId?: number | null
): Promise<string> => {
const typeNumber = EQUIPMENT_TYPE_NUMBERS[equipmentType] || 0
// 获取地址ID,如果没有地址则为0
const locationId = storageLocationId || 0
// 格式前缀:{类型数字}{地址ID(4位)}
const typeCode = String(typeNumber)
const locationCode = String(locationId).padStart(4, '0')
const prefix = `${typeCode}${locationCode}`
// 查找该类型和地址的所有资产,提取最大序号
// 使用这种方式比count更安全,可以处理并发情况
const existingEquipment = await prisma.equipment.findMany({
where: {
equipment_type: equipmentType,
storage_location_id: storageLocationId || null,
equipment_code: {
startsWith: prefix
}
},
select: {
equipment_code: true
},
orderBy: {
equipment_code: 'desc'
},
take: 1 // 只取最大的一条
})
// 计算起始序号
let startSequence = 1
if (existingEquipment.length > 0) {
// 从最大编码中提取序号
const maxCode = existingEquipment[0].equipment_code
if (maxCode.startsWith(prefix)) {
const sequencePart = maxCode.substring(prefix.length)
const maxSequence = parseInt(sequencePart, 10)
if (!isNaN(maxSequence)) {
startSequence = maxSequence + 1
}
}
}
// 检查序号是否溢出(5位数字最大99999)
if (startSequence > 99999) {
throw new Error(`资产编码序号已溢出,该类型和地址的资产数量已超过99999`)
}
// 生成编码并检查唯一性,最多重试10次
const maxRetries = 10
for (let attempt = 0; attempt < maxRetries; attempt++) {
const sequence = String(startSequence + attempt).padStart(5, '0')
const code = `${prefix}${sequence}`
// 检查编码是否已存在
const existing = await prisma.equipment.findUnique({
where: { equipment_code: code }
})
if (!existing) {
// 编码唯一,返回
return code
}
// 如果编码已存在,继续尝试下一个序号
console.warn(`资产编码 ${code} 已存在,尝试下一个序号`)
}
// 如果重试10次后仍然冲突,抛出错误
throw new Error(`无法生成唯一的资产编码,已重试${maxRetries}次`)
}
/**
* 验证资产编码格式(纯数字)
*/
export const validateEquipmentCode = (code: string): boolean => {
// 纯数字格式,长度10位:{类型1位}{地址4位}{序号5位}
const pattern = /^\d{10}$/
return pattern.test(code)
}