couponNormalize.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /**
  2. * 将 getUserCouponList 等接口返回的单条优惠券规范为前端统一结构(与券包页一致)
  3. * @param {object} raw 接口原始项
  4. * @param {number} [tabStatus=0] 列表 Tab 状态(券包页传入 currentTab)
  5. */
  6. export function normalizeUserCouponListItem(raw, tabStatus = 0) {
  7. if (!raw || typeof raw !== 'object') return null;
  8. const couponType = Number(raw.couponType) ?? 1;
  9. const nominalValue = Number(raw.nominalValue ?? raw.amount ?? 0) || 0;
  10. const discountRate = ((Number(raw.discountRate ?? 0) || 0) / 10) || 0;
  11. const minAmount = Number(raw.minimumSpendingAmount ?? raw.minAmount ?? 0) || 0;
  12. let amount = nominalValue;
  13. let amountUnit = '元';
  14. let conditionText = minAmount > 0 ? `满${minAmount}可用` : '无门槛';
  15. if (couponType === 2 && discountRate > 0) {
  16. amount = discountRate;
  17. amountUnit = '折';
  18. conditionText = minAmount > 0 ? `满${minAmount}可用` : '无门槛';
  19. }
  20. const expirationTime =
  21. raw.expirationTime ?? raw.endGetDate ?? raw.expireDate ?? '';
  22. const longTermValid = Number(raw.longTermValid) === 1 ? 1 : 0;
  23. // id 用于列表选中态与 :key,必须为「用户持有实例」唯一键;勿把模板 couponId 放首位,否则多张相同活动券会 id 重复、出现多选假象
  24. const listId =
  25. raw.userCouponId ??
  26. raw.user_coupon_id ??
  27. raw.memberCouponId ??
  28. raw.receiveRecordId ??
  29. raw.receiveId ??
  30. raw.id ??
  31. raw.couponId ??
  32. '';
  33. return {
  34. id: listId,
  35. /** 券模板/业务侧 couponId,与 id(用户券实例)区分,支付等场景按需选用 */
  36. couponId: raw.couponId ?? raw.coupon_id ?? '',
  37. amount,
  38. amountUnit,
  39. minAmount,
  40. name: raw.name ?? raw.title ?? raw.couponName ?? '',
  41. expirationTime,
  42. expireDate: expirationTime,
  43. longTermValid,
  44. status: tabStatus,
  45. couponType,
  46. nominalValue,
  47. discountRate,
  48. conditionText,
  49. specifiedDay: raw.specifiedDay ?? raw.validDays ?? '',
  50. supplementaryInstruction: raw.supplementaryInstruction ?? raw.description ?? '',
  51. qrCodeUrl: raw.qrCodeUrl ?? raw.qrcodeUrl ?? raw.qrUrl ?? '',
  52. verificationCode:
  53. raw.verificationCode ?? raw.verifyCode ?? raw.couponCode ?? raw.pickUpCode ?? '',
  54. /** 接口原始门槛;与 minAmount 并存,供 getCouponMinSpendThreshold 优先解析(0 表示无门槛) */
  55. minimumSpendingAmount:
  56. raw.minimumSpendingAmount !== undefined && raw.minimumSpendingAmount !== null
  57. ? Number(raw.minimumSpendingAmount)
  58. : undefined
  59. };
  60. }
  61. /**
  62. * 优惠券使用门槛金额(元)。
  63. * 优先 minimumSpendingAmount:显式为 0 视为无门槛(可选);字段未给出时用 minAmount。
  64. * @param {object} coupon 原始项或 normalizeUserCouponListItem 结果
  65. */
  66. export function getCouponMinSpendThreshold(coupon) {
  67. if (!coupon || typeof coupon !== 'object') return 0;
  68. const raw = coupon.minimumSpendingAmount;
  69. const explicit = raw !== undefined && raw !== null && raw !== '';
  70. if (explicit) {
  71. const v = Number(raw);
  72. return Number.isFinite(v) && v > 0 ? v : 0;
  73. }
  74. const fb = Number(coupon.minAmount ?? 0);
  75. return Number.isFinite(fb) && fb > 0 ? fb : 0;
  76. }
  77. /** 解析 getUserCouponList 分页响应(数组或 { records/list, total }) */
  78. export function parseCouponListPage(res) {
  79. if (res == null) return { list: [], total: 0 };
  80. if (Array.isArray(res)) return { list: res, total: 0 };
  81. const data = res.data !== undefined && res.data !== null && !Array.isArray(res) ? res.data : res;
  82. if (Array.isArray(data)) return { list: data, total: 0 };
  83. if (data && typeof data === 'object') {
  84. const list =
  85. data.records ??
  86. data.list ??
  87. data.rows ??
  88. data.items ??
  89. (Array.isArray(data.data) ? data.data : []);
  90. const total =
  91. Number(data.total ?? data.totalCount ?? data.totalElements ?? data.count ?? res.total ?? res.totalCount ?? 0) ||
  92. 0;
  93. return { list: Array.isArray(list) ? list : [], total };
  94. }
  95. return { list: [], total: 0 };
  96. }
  97. /** 分页追加时按 id 去重 */
  98. export function mergeCouponListById(existing, incoming) {
  99. const seen = new Set((existing ?? []).map((c) => String(c?.id ?? '')));
  100. const out = [...(existing ?? [])];
  101. for (const item of incoming ?? []) {
  102. const id = String(item?.id ?? '');
  103. if (id && !seen.has(id)) {
  104. seen.add(id);
  105. out.push(item);
  106. } else if (!id) {
  107. out.push(item);
  108. }
  109. }
  110. return out;
  111. }