shop-code.ts 1.3 KB

12345678910111213141516171819202122232425262728
  1. import dayjs from "dayjs";
  2. /**
  3. * 门店编号(third_shop_id)自动生成 —— 汇安融门店创建表单用。
  4. *
  5. * 形状:`SP` + `yyyyMMddHHmmss` + 16 位随机,共 32 字符,正好吃满
  6. * `third_shop_id` 的 varchar(32)。改成自动生成是因为运营手填这个编号的代价不对称:
  7. * 撞号 ⇒ 上游按「重复提交」拒绝建店;填错一个字符 ⇒ 上游没有更新接口,事后补不上。
  8. *
  9. * 两个刻意的选择:
  10. * - 字母表去掉 0/1/I/O(连同数字段共 32 个字符):编号要能在电话/微信里念得出来,
  11. * 去掉易混字符,一个歧义就少一类抄错。
  12. * - 32 是 2 的幂 ⇒ 取随机字节的低 5 位做下标是无偏的(256 % 32 == 0),无需拒绝采样。
  13. * 随机源必须是 crypto.getRandomValues:这个编号在上游是**幂等键**,撞号等于
  14. * 整笔建店被拒,Math.random 的碰撞概率和可预测性都不能接受。
  15. */
  16. const ALPHABET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
  17. export function generateShopCode(now: Date = new Date()): string {
  18. const stamp = dayjs(now).format("YYYYMMDDHHmmss");
  19. const bytes = new Uint8Array(16);
  20. crypto.getRandomValues(bytes);
  21. let rand = "";
  22. for (const b of bytes) {
  23. rand += ALPHABET[b & 31];
  24. }
  25. return `SP${stamp}${rand}`;
  26. }