107 lines
3.2 KiB
TypeScript
107 lines
3.2 KiB
TypeScript
// 资产类型数字代码映射(纯数字编码)
|
||
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)
|
||
}
|
||
|