Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

88 linhas
2.5 KiB

  1. const INVITE_MAX_AGE = 30 * 24 * 3600
  2. function normalizeInviteCode(value) {
  3. const text = Array.isArray(value) ? value[0] : value
  4. const code = String(text || '').trim()
  5. return /^[a-zA-Z0-9_-]{1,64}$/.test(code) ? code : ''
  6. }
  7. function parseInviteScene(value) {
  8. if (!value) return ''
  9. let text = String(Array.isArray(value) ? value[0] : value)
  10. try {
  11. text = decodeURIComponent(text)
  12. } catch {
  13. // 保留原始 scene,交给后续格式校验。
  14. }
  15. const match = text.match(/(?:^|[&?])i=([^&]+)/) || text.match(/(?:^|[&?])i_([^&]+)/)
  16. if (match) return normalizeInviteCode(match[1])
  17. if (text.startsWith('i_')) return normalizeInviteCode(text.slice(2))
  18. return ''
  19. }
  20. export function useInvite() {
  21. const inviteCode = useCookie('invite_code', {
  22. maxAge: INVITE_MAX_AGE,
  23. path: '/',
  24. sameSite: 'lax',
  25. })
  26. const source = useCookie('source', {
  27. maxAge: INVITE_MAX_AGE,
  28. path: '/',
  29. sameSite: 'lax',
  30. })
  31. const runtimeConfig = useRuntimeConfig()
  32. const requestUrl = useRequestURL()
  33. function captureInvite(query = {}) {
  34. const token = useCookie('token', { path: '/' })
  35. const code = normalizeInviteCode(query.invite_code)
  36. || normalizeInviteCode(query.invite_open_id)
  37. || parseInviteScene(query.scene)
  38. // 已登录用户不会再触发注册奖励,避免在共享设备上污染下一位登录用户。
  39. if (code && !token.value) inviteCode.value = code
  40. const sourceValue = String(Array.isArray(query.source) ? query.source[0] : query.source || '').trim()
  41. if (sourceValue && sourceValue.length <= 50) source.value = sourceValue
  42. return code
  43. }
  44. function withInvite(params = {}) {
  45. const code = normalizeInviteCode(inviteCode.value)
  46. return code ? { ...params, invite_open_id: code } : { ...params }
  47. }
  48. function clearInvite() {
  49. inviteCode.value = null
  50. }
  51. function buildInvitePath(code) {
  52. const normalized = normalizeInviteCode(code)
  53. if (!normalized) return '/invite/landing'
  54. const query = new URLSearchParams({
  55. invite_code: normalized,
  56. source: 'pc_invite',
  57. })
  58. return `/invite/landing?${query.toString()}`
  59. }
  60. function buildInviteUrl(code) {
  61. const configuredOrigin = String(runtimeConfig.public.siteUrl || '').replace(/\/+$/, '')
  62. const origin = configuredOrigin || requestUrl.origin
  63. return `${origin}${buildInvitePath(code)}`
  64. }
  65. return {
  66. inviteCode,
  67. source,
  68. captureInvite,
  69. withInvite,
  70. clearInvite,
  71. buildInvitePath,
  72. buildInviteUrl,
  73. normalizeInviteCode,
  74. }
  75. }