增加adjust web sdk
All checks were successful
site-dist-deploy / build-and-deploy (push) Successful in 1m36s
All checks were successful
site-dist-deploy / build-and-deploy (push) Successful in 1m36s
This commit is contained in:
parent
681ad15228
commit
d629b360a0
@ -10,6 +10,7 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@adjustcom/adjust-web-sdk": "^5.8.2",
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.18",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
|||||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@ -8,6 +8,9 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@adjustcom/adjust-web-sdk':
|
||||||
|
specifier: ^5.8.2
|
||||||
|
version: 5.8.2
|
||||||
'@tailwindcss/vite':
|
'@tailwindcss/vite':
|
||||||
specifier: ^4.1.18
|
specifier: ^4.1.18
|
||||||
version: 4.1.18(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2))
|
version: 4.1.18(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2))
|
||||||
@ -72,6 +75,9 @@ importers:
|
|||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
'@adjustcom/adjust-web-sdk@5.8.2':
|
||||||
|
resolution: {integrity: sha512-6ov2EKKuPQi7i+0CdtsGZ7REIE8jRlg++muAjqpR4ySLjOXTgxVSmWjsTBohxnTVDDL2OGEMfXFUG6ZIhyvl9Q==}
|
||||||
|
|
||||||
'@babel/helper-string-parser@7.27.1':
|
'@babel/helper-string-parser@7.27.1':
|
||||||
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
|
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
@ -85,6 +91,10 @@ packages:
|
|||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
'@babel/runtime@7.29.2':
|
||||||
|
resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@babel/types@7.28.6':
|
'@babel/types@7.28.6':
|
||||||
resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==}
|
resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
@ -1094,6 +1104,10 @@ packages:
|
|||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
|
'@adjustcom/adjust-web-sdk@5.8.2':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.29.2
|
||||||
|
|
||||||
'@babel/helper-string-parser@7.27.1': {}
|
'@babel/helper-string-parser@7.27.1': {}
|
||||||
|
|
||||||
'@babel/helper-validator-identifier@7.28.5': {}
|
'@babel/helper-validator-identifier@7.28.5': {}
|
||||||
@ -1102,6 +1116,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@babel/types': 7.28.6
|
'@babel/types': 7.28.6
|
||||||
|
|
||||||
|
'@babel/runtime@7.29.2': {}
|
||||||
|
|
||||||
'@babel/types@7.28.6':
|
'@babel/types@7.28.6':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/helper-string-parser': 7.27.1
|
'@babel/helper-string-parser': 7.27.1
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import './styles/index.css'
|
import './styles/index.css'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import '@/utils/openinstall.ts'
|
import '@/utils/openinstall'
|
||||||
|
import '@/utils/adjust'
|
||||||
|
|
||||||
createApp(App).mount('#app')
|
createApp(App).mount('#app')
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
:aria-label="mainButton.label"
|
:aria-label="mainButton.label"
|
||||||
class="flex h-full w-full items-center justify-center transition-transform hover:brightness-110 active:scale-95"
|
class="flex h-full w-full items-center justify-center transition-transform hover:brightness-110 active:scale-95"
|
||||||
|
@click.prevent="handleDownload(mainButton)"
|
||||||
>
|
>
|
||||||
<component :is="mainButton.mainIcon" class="h-auto w-full text-black transition-transform" />
|
<component :is="mainButton.mainIcon" class="h-auto w-full text-black transition-transform" />
|
||||||
</a>
|
</a>
|
||||||
@ -16,6 +17,7 @@
|
|||||||
:id="mainButton?.id"
|
:id="mainButton?.id"
|
||||||
:aria-label="mainButton?.label"
|
:aria-label="mainButton?.label"
|
||||||
class="flex h-full w-full cursor-pointer items-center justify-center transition-transform hover:brightness-110 active:scale-95"
|
class="flex h-full w-full cursor-pointer items-center justify-center transition-transform hover:brightness-110 active:scale-95"
|
||||||
|
@click="handleDownload(mainButton)"
|
||||||
>
|
>
|
||||||
<component :is="mainButton?.mainIcon" class="h-auto w-full text-black transition-transform" />
|
<component :is="mainButton?.mainIcon" class="h-auto w-full text-black transition-transform" />
|
||||||
</div>
|
</div>
|
||||||
@ -35,6 +37,7 @@
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
:aria-label="item.label"
|
:aria-label="item.label"
|
||||||
class="transition-transform hover:brightness-110 active:scale-95"
|
class="transition-transform hover:brightness-110 active:scale-95"
|
||||||
|
@click.prevent="handleDownload(item)"
|
||||||
>
|
>
|
||||||
<component :is="item.secondaryIcon" class="h-[24px] md:h-[34px] text-white" />
|
<component :is="item.secondaryIcon" class="h-[24px] md:h-[34px] text-white" />
|
||||||
</a>
|
</a>
|
||||||
@ -43,6 +46,7 @@
|
|||||||
:id="item.id"
|
:id="item.id"
|
||||||
:aria-label="item.label"
|
:aria-label="item.label"
|
||||||
class="cursor-pointer transition-transform hover:brightness-110 active:scale-95"
|
class="cursor-pointer transition-transform hover:brightness-110 active:scale-95"
|
||||||
|
@click="handleDownload(item)"
|
||||||
>
|
>
|
||||||
<component :is="item.secondaryIcon" class="h-[24px] md:h-[34px] text-white" />
|
<component :is="item.secondaryIcon" class="h-[24px] md:h-[34px] text-white" />
|
||||||
</div>
|
</div>
|
||||||
@ -64,10 +68,9 @@ import AndroidIcon from './AndroidIcon.svg?component'
|
|||||||
|
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
import {computed, ref, onMounted} from "vue";
|
import {computed, ref, onMounted} from "vue";
|
||||||
import {getAllQueryString} from "@/utils/url-utils";
|
import {getAllQueryString} from "../../../utils/url-utils";
|
||||||
|
import AdjustUtil from "../../../utils/adjust";
|
||||||
|
|
||||||
const downLoadWin = ref('')
|
|
||||||
const downLoadMac = ref('')
|
|
||||||
const currentPlatform = ref('win')
|
const currentPlatform = ref('win')
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -100,30 +103,38 @@ onMounted(() => {
|
|||||||
console.log('Detected Platform:', currentPlatform.value);
|
console.log('Detected Platform:', currentPlatform.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
// request.get('/api/v1/common/client/download', {
|
const handleDownload = (item: any) => {
|
||||||
// invite_code: getAllQueryString('ic'),
|
console.log('Downloading:', item.label, item.link);
|
||||||
// platform: 'mac',
|
// 记录点击事件(通过 key 自动映射令牌)
|
||||||
// }).then((res: any) => {
|
AdjustUtil.trackEvent(item.key);
|
||||||
// downLoadMac.value = res.url
|
|
||||||
// })
|
|
||||||
|
|
||||||
request.get('/api/v1/common/client/download', {
|
if (item.key === 'win') {
|
||||||
invite_code: getAllQueryString('ic'),
|
// Windows 平台:点击时请求下载地址
|
||||||
platform: 'windows',
|
request.get('/api/v1/common/client/download', {
|
||||||
}).then((res: any) => {
|
invite_code: getAllQueryString('ic'),
|
||||||
downLoadWin.value = res.url
|
platform: 'windows',
|
||||||
})
|
}).then((res: any) => {
|
||||||
|
if (res.url) {
|
||||||
|
window.open(res.url, '_blank');
|
||||||
|
}
|
||||||
|
}).catch((err: any) => {
|
||||||
|
console.error('Failed to fetch windows download link:', err);
|
||||||
|
});
|
||||||
|
} else if (item.link) {
|
||||||
|
// 其他平台:直接打开链接
|
||||||
|
window.open(item.link, '_blank');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const allDownloadOptions = computed(() => {
|
const allDownloadOptions = computed(() => {
|
||||||
const ic = getAllQueryString('ic')
|
|
||||||
const androidLink = currentPlatform.value === 'android'
|
const androidLink = currentPlatform.value === 'android'
|
||||||
? `https://hifastvpn.go.link?adj_t=1xf6e7ru&inviteCode=${ic}`
|
? AdjustUtil.getDecoratedLink()
|
||||||
: 'https://api.hifast.biz/v1/common/client/download/file/Hi%E5%BF%ABVPN-android-1.0.0.apk'
|
: 'https://api.hifast.biz/v1/common/client/download/file/Hi%E5%BF%ABVPN-android-1.0.0.apk'
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{ key: 'win', mainIcon: Icon1, secondaryIcon: WinIcon, link: downLoadWin.value, label: 'Windows', id: 'downloadButton_win' },
|
{ key: 'win', mainIcon: Icon1, secondaryIcon: WinIcon, link: '', label: 'Windows', id: 'downloadButton_win' },
|
||||||
{ key: 'mac', mainIcon: Icon3, secondaryIcon: MacIcon, label: 'macOS', link: `https://hifastvpn.go.link?adj_t=1xf6e7ru&inviteCode=${ic}` },
|
{ key: 'mac', mainIcon: Icon3, secondaryIcon: MacIcon, label: 'macOS', link: AdjustUtil.getDecoratedLink() },
|
||||||
{ key: 'ios', mainIcon: Icon2, secondaryIcon: AppleIcon, label: 'iOS', link: `https://hifastvpn.go.link?adj_t=1xf6e7ru&inviteCode=${ic}` },
|
{ key: 'ios', mainIcon: Icon2, secondaryIcon: AppleIcon, label: 'iOS', link: AdjustUtil.getDecoratedLink() },
|
||||||
{ key: 'android', mainIcon: Icon4, secondaryIcon: AndroidIcon, label: 'Android', link: androidLink },
|
{ key: 'android', mainIcon: Icon4, secondaryIcon: AndroidIcon, label: 'Android', link: androidLink },
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
98
src/utils/adjust.ts
Normal file
98
src/utils/adjust.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import Adjust from '@adjustcom/adjust-web-sdk'
|
||||||
|
import { getAllQueryString } from '@/utils/url-utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjust Web SDK 工具类
|
||||||
|
* 用于初始化 SDK 及管理全局参数
|
||||||
|
*/
|
||||||
|
class AdjustUtil {
|
||||||
|
private static instance: AdjustUtil
|
||||||
|
private isInitialized: boolean = false
|
||||||
|
private appToken: string = 'vnxcjw75xyww'
|
||||||
|
private environment: 'production' | 'sandbox' = 'production'
|
||||||
|
|
||||||
|
// Adjust 事件令牌映射表(请在此处替换为真实的 6 位令牌)
|
||||||
|
public static readonly EVENT_TOKENS = {
|
||||||
|
win: 'c6rntd',
|
||||||
|
mac: 'c6rntd',
|
||||||
|
ios: 'c6rntd',
|
||||||
|
android: 'c6rntd',
|
||||||
|
}
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getInstance(): AdjustUtil {
|
||||||
|
if (!AdjustUtil.instance) {
|
||||||
|
AdjustUtil.instance = new AdjustUtil()
|
||||||
|
}
|
||||||
|
return AdjustUtil.instance
|
||||||
|
}
|
||||||
|
|
||||||
|
private init() {
|
||||||
|
try {
|
||||||
|
if (!this.isInitialized) {
|
||||||
|
Adjust.initSdk({
|
||||||
|
appToken: this.appToken,
|
||||||
|
environment: this.environment,
|
||||||
|
logLevel: 'verbose'
|
||||||
|
})
|
||||||
|
|
||||||
|
this.isInitialized = true
|
||||||
|
console.log('Adjust SDK Initialized (NPM)')
|
||||||
|
|
||||||
|
// 获取并设置 inviteCode 作为全局参数
|
||||||
|
const ic = getAllQueryString('ic')
|
||||||
|
if (ic) {
|
||||||
|
Adjust.addGlobalCallbackParameters([
|
||||||
|
{ key: 'inviteCode', value: ic }
|
||||||
|
])
|
||||||
|
console.log('Adjust Global Parameter Set: inviteCode =', ic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Adjust SDK Initialization Error:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取装饰后的 Adjust 链接(透传当前页面所有 URL 参数)
|
||||||
|
* @param baseUrl 基础 Adjust 链接,默认为 'https://hifastvpn.go.link'
|
||||||
|
* @param defaultAdjT 默认的 adj_t 值,默认为 '1xf6e7ru'
|
||||||
|
*/
|
||||||
|
public getDecoratedLink(baseUrl: string = 'https://hifastvpn.go.link', defaultAdjT: string = '1xf6e7ru'): string {
|
||||||
|
const currentParams = new URLSearchParams(window.location.search || window.location.hash.split('?')[1] || '')
|
||||||
|
const baseParams = new URLSearchParams()
|
||||||
|
|
||||||
|
// 设置默认 adj_t
|
||||||
|
baseParams.set('adj_t', defaultAdjT)
|
||||||
|
|
||||||
|
// 将当前页面的参数合并进来(当前页面的参数优先级更高,可覆盖默认的 adj_t)
|
||||||
|
currentParams.forEach((value, key) => {
|
||||||
|
if (key === 'ic') {
|
||||||
|
// 特殊处理:URL 上的 ic 映射为 Adjust 链接上的 inviteCode
|
||||||
|
baseParams.set('inviteCode', value)
|
||||||
|
} else {
|
||||||
|
baseParams.set(key, value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const finalQuery = baseParams.toString()
|
||||||
|
return `${baseUrl}${baseUrl.includes('?') ? '&' : '?'}${finalQuery}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录自定义事件
|
||||||
|
* @param eventNameOrToken 事件名称(win/ios等)或 Adjust Event Token(6位令牌)
|
||||||
|
*/
|
||||||
|
public trackEvent(eventNameOrToken: string) {
|
||||||
|
if (this.isInitialized) {
|
||||||
|
// 优先从映射表中查找令牌,找不到则视为直接传入的令牌
|
||||||
|
const token = (AdjustUtil.EVENT_TOKENS as any)[eventNameOrToken] || eventNameOrToken
|
||||||
|
Adjust.trackEvent({ eventToken: token })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdjustUtil.getInstance()
|
||||||
@ -10,7 +10,11 @@
|
|||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"erasableSyntaxOnly": true,
|
"erasableSyntaxOnly": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noUncheckedSideEffectImports": true
|
"noUncheckedSideEffectImports": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user