launchScene.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /**
  2. * 太阳码 / 扫码进入参数解析(冷启动 onLoad + 热启动 App.onShow 共用)
  3. */
  4. /** 微信「扫小程序码 / 长按识别 / 相册选取」等进入场景值 */
  5. export const SCAN_ENTRY_SCENES = [1011, 1012, 1013, 1047, 1048, 1049]
  6. /**
  7. * 解析 scene 字符串为键值对,如 s=123&a=456&id=789
  8. */
  9. export function parseSceneString(sceneRaw) {
  10. if (!sceneRaw) {
  11. return {}
  12. }
  13. const scene = decodeURIComponent(String(sceneRaw))
  14. const params = {}
  15. scene.split('&').forEach((pair) => {
  16. if (!pair) {
  17. return
  18. }
  19. const eq = pair.indexOf('=')
  20. if (eq === -1) {
  21. params[pair] = ''
  22. return
  23. }
  24. const key = pair.slice(0, eq)
  25. const val = pair.slice(eq + 1)
  26. if (key) {
  27. params[key] = val != null ? decodeURI(val) : ''
  28. }
  29. })
  30. return params
  31. }
  32. /**
  33. * 将 scene 内字段展开为页面 query(account / hdId / id 等)
  34. */
  35. export function sceneParamsToQuery(sceneParams, baseQuery) {
  36. const q = Object.assign({}, baseQuery || {})
  37. if (sceneParams.s) {
  38. q.account = sceneParams.s
  39. }
  40. if (sceneParams.a) {
  41. if (!q.account) {
  42. q.account = sceneParams.a
  43. }
  44. q.staffId = sceneParams.a
  45. }
  46. if (sceneParams.id) {
  47. q.id = sceneParams.id
  48. }
  49. if (sceneParams.hdId) {
  50. q.hdId = sceneParams.hdId
  51. }
  52. delete q.scene
  53. return q
  54. }
  55. /**
  56. * 合并 onLoad 的 option:scene 展开 + 普通二维码 q 参数
  57. */
  58. export function applyLaunchQuery(option) {
  59. const merged = Object.assign({}, option || {})
  60. if (merged.scene) {
  61. const sceneParams = parseSceneString(merged.scene)
  62. Object.assign(merged, sceneParamsToQuery(sceneParams, merged))
  63. delete merged.scene
  64. }
  65. if (merged.q) {
  66. const currentUrl = decodeURIComponent(String(merged.q))
  67. const marker = 'account='
  68. const idx = currentUrl.lastIndexOf(marker)
  69. if (idx >= 0) {
  70. let account = currentUrl.substring(idx + marker.length)
  71. const amp = account.indexOf('&')
  72. if (amp >= 0) {
  73. account = account.substring(0, amp)
  74. }
  75. merged.account = account
  76. }
  77. }
  78. return merged
  79. }
  80. /**
  81. * 拼 reLaunch 地址
  82. */
  83. export function buildLaunchUrl(path, query) {
  84. const normalizedPath = path && path.indexOf('/') === 0 ? path : '/' + (path || '')
  85. const parts = []
  86. const q = query || {}
  87. Object.keys(q).forEach((key) => {
  88. const val = q[key]
  89. if (val !== undefined && val !== null && val !== '') {
  90. parts.push(key + '=' + encodeURIComponent(val))
  91. }
  92. })
  93. return parts.length ? normalizedPath + '?' + parts.join('&') : normalizedPath
  94. }
  95. /**
  96. * 写入 account / hdId / currentQuery(与原 globalMixins 一致)
  97. */
  98. export function persistLaunchStorage(option) {
  99. if (option.account) {
  100. uni.setStorageSync('account', option.account)
  101. } else {
  102. uni.setStorageSync('account', 0)
  103. }
  104. if (option.hdId) {
  105. uni.setStorageSync('hdId', option.hdId)
  106. } else {
  107. uni.setStorageSync('hdId', 0)
  108. }
  109. uni.setStorageSync('currentQuery', JSON.stringify(option))
  110. }
  111. /** 分享邀请人 customId 的 storage key(按门店隔离) */
  112. export function getShareInviterStorageKey(account) {
  113. const shopId = account || uni.getStorageSync('account') || ''
  114. return shopId ? 'shareInviter_' + shopId : ''
  115. }
  116. /**
  117. * 缓存分享链接中的邀请人 xhCustom.id,供注册后拉新绑定
  118. */
  119. export function persistShareInviter(option) {
  120. const inviterCustomId = option && option.inviterCustomId ? Number(option.inviterCustomId) : 0
  121. const account = option && option.account ? option.account : uni.getStorageSync('account')
  122. const key = getShareInviterStorageKey(account)
  123. if (!key || inviterCustomId <= 0) {
  124. return
  125. }
  126. uni.setStorageSync(key, inviterCustomId)
  127. }
  128. /** 读取当前门店缓存的邀请人 ID */
  129. export function getShareInviterCustomId(account) {
  130. const key = getShareInviterStorageKey(account)
  131. if (!key) {
  132. return 0
  133. }
  134. const val = uni.getStorageSync(key)
  135. return val ? Number(val) : 0
  136. }
  137. /** 绑定成功后清除邀请人缓存 */
  138. export function clearShareInviter(account) {
  139. const key = getShareInviterStorageKey(account)
  140. if (key) {
  141. uni.removeStorageSync(key)
  142. }
  143. }
  144. /**
  145. * 热启动:根据 getEnterOptionsSync 判断是否需要 reLaunch 到展开 query 的目标页
  146. * @returns {boolean} 是否已触发 reLaunch
  147. */
  148. export function tryReLaunchFromScanEnter(globalData) {
  149. if (!uni.getEnterOptionsSync) {
  150. return false
  151. }
  152. const enter = uni.getEnterOptionsSync()
  153. if (!enter || !enter.query || !enter.query.scene) {
  154. return false
  155. }
  156. const launchKey = (enter.path || '') + '|' + enter.query.scene
  157. const sceneCode = Number(enter.scene)
  158. const isScanEntry = SCAN_ENTRY_SCENES.indexOf(sceneCode) >= 0
  159. if (!isScanEntry && globalData.lastLaunchKey === launchKey) {
  160. return false
  161. }
  162. const sceneParams = parseSceneString(enter.query.scene)
  163. const expandedQuery = sceneParamsToQuery(sceneParams, Object.assign({}, enter.query))
  164. const targetUrl = buildLaunchUrl(enter.path, expandedQuery)
  165. const targetRoute = (enter.path || '').replace(/^\//, '')
  166. const pages = getCurrentPages()
  167. const current = pages.length ? pages[pages.length - 1] : null
  168. if (current) {
  169. const curRoute = current.route || ''
  170. const curOpts = current.options || {}
  171. // 已在目标页且参数已展开(无 scene),无需重复 reLaunch
  172. if (curRoute === targetRoute && !curOpts.scene && (curOpts.account || curOpts.id || curOpts.hdId)) {
  173. globalData.lastLaunchKey = launchKey
  174. return false
  175. }
  176. }
  177. globalData.lastLaunchKey = launchKey
  178. uni.reLaunch({ url: targetUrl })
  179. return true
  180. }