// 雪花 ID 53-bit 压缩版 (JS Number 安全) // 移植自 hwt-code (IdGenerator.java) - 与后端 com.ruoyi.common.utils.id.IdGenerator 完全一致 // 53-bit 容量: 2^53-1 = 9007199254740991, JS Number max safe = 2^53-1 // // 算法: // timestamp 40 bits (per 10ms, 2300+ 年可用) // machineId 5 bits (0~31) // sequence 8 bits (0~255, 每 10ms 重置) // // 注意: JS bit-shift 对 32-bit 安全, 53-bit 不会溢出 (32-bit long 范围更大) const MACHINE_BIT = 5 const SEQUENCE_BIT = 8 const MAX_MACHINE_NUM = -1 ^ (-1 << MACHINE_BIT) // 31 const MAX_SEQUENCE = -1 ^ (-1 << SEQUENCE_BIT) // 255 const MACHINE_LEFT = SEQUENCE_BIT const TIMESTMP_LEFT = MACHINE_BIT + SEQUENCE_BIT let machineId = 0 let sequence = 0 let lastStmp = -1 function initDefaultInstance(id) { machineId = id sequence = 0 lastStmp = -1 } function getTimestamp() { return Math.floor(Date.now() / 10) // per 10ms (与后端一致) } function getNextTimestamp() { let mill = getTimestamp() while (mill <= lastStmp) mill = getTimestamp() return mill } function nextId() { let currStmp = getTimestamp() if (currStmp < lastStmp) throw new Error('Clock moved backwards. Refusing to generate id') if (currStmp === lastStmp) { sequence = (sequence + 1) & MAX_SEQUENCE if (sequence === 0) currStmp = getNextTimestamp() } else { sequence = 0 } lastStmp = currStmp // JS Number 53-bit 安全 return Number(BigInt(currStmp) << BigInt(TIMESTMP_LEFT) | BigInt(machineId) << BigInt(MACHINE_LEFT) | BigInt(sequence)) } function generateId() { return nextId() } function parseIdTimestamp(id) { return new Date(Number(BigInt(id) >> BigInt(TIMESTMP_LEFT)) * 10) } export default { initDefaultInstance, generateId, parseIdTimestamp, }