411 lines
13 KiB
JavaScript
411 lines
13 KiB
JavaScript
const dlOpenApiDomain = `https://dl-open.${strCodeCcDl}.net/p`
|
||
const getChannelStatisticalcode = `https://hyapi.${strCodeCcHy}.net/api/channel/statisticalcode`
|
||
/*
|
||
* 渠道推广统计
|
||
* channelPromotionStatistics
|
||
* 第一种:落地页携带渠道编码。比如我们的站点是 a.com`, 代理商渠道页面就是 `a.com?channel=code01 。
|
||
用户打开这个链接时,前端需要检查当前网址是否存在channel参数,
|
||
如果有,需要将该参数记录到本地cookie。这个参数在注册的时候,需要携带传送到后台。
|
||
以及,访问其他所有页面,都需要调取代理商推广分析平台的open pv记录接口
|
||
第二种:渠道配置的是 来源域名,这里假设是 x.com 。
|
||
我们的站点是 a.com`,用户从 `x.com 跳转到 a.com 我们的站点。
|
||
前端需要检查是否存在来源域名,且来源域名和当前域名不一致的时候,
|
||
需要将来源域名记录到本地cookie.这个参数在注册的时候,
|
||
需要携带传送到后台。以及,访问其他所有页面,
|
||
都需要调取代理商推广分析平台的open pv记录接口。
|
||
*/
|
||
const channelPv = {
|
||
|
||
apiurl: dlOpenApiDomain, //正式服
|
||
//apiurl : , // 测试服
|
||
|
||
StorageKeyChannelcode: EncAndDec.encryptData('dlfx_channelcode'), // 代理分析-渠道编码
|
||
|
||
StorageKeySourceDomain: EncAndDec.encryptData('dlfx_sourceDomain'),// 代理分析-来源域名
|
||
|
||
StorageKeyMuReferrerId: EncAndDec.encryptData('dlfx_muReferrerId'),// 代理分析-推广人id
|
||
|
||
StorageKeySourceUrl: EncAndDec.encryptData('dlfx_sourceUrl'),// 代理分析-来源地址
|
||
|
||
//初始化
|
||
init() {
|
||
//渠道编码
|
||
let channelCode = this.getQueryVariable('qd')
|
||
if(channelCode) {
|
||
localStorage.setItem(channelPv.StorageKeyChannelcode, channelCode)
|
||
}
|
||
//推广
|
||
let muReferrerId = this.getQueryVariable('mu_referrer_id')
|
||
if(muReferrerId) {
|
||
localStorage.setItem(channelPv.StorageKeyMuReferrerId, muReferrerId)
|
||
}
|
||
|
||
//来源域名
|
||
let sourceUrl = document.referrer;
|
||
let sourceDomain = sourceUrl.split('/')[2];
|
||
let currnetDomain = location.href.split('/')[2];
|
||
if(sourceDomain && sourceDomain != currnetDomain) {
|
||
localStorage.setItem(channelPv.StorageKeySourceDomain, sourceDomain)
|
||
localStorage.setItem(channelPv.StorageKeySourceUrl, sourceUrl)
|
||
}
|
||
|
||
//调用pv统计
|
||
let channelCode_getItem = localStorage.getItem(channelPv.StorageKeyChannelcode)
|
||
let sourceDomain_getItem = localStorage.getItem(channelPv.StorageKeySourceDomain)
|
||
let sourceUrl_getItem = localStorage.getItem(channelPv.StorageKeySourceUrl)
|
||
|
||
if(this.getQueryVariable('outlog')) {
|
||
console.log(document.referrer)
|
||
console.log(channelCode)
|
||
console.log(sourceDomain)
|
||
console.log(currnetDomain)
|
||
console.log(channelCode_getItem)
|
||
console.log(sourceDomain_getItem)
|
||
}
|
||
|
||
if(channelCode_getItem || sourceDomain_getItem) {
|
||
let data = {
|
||
'ac_code': channelCode_getItem,
|
||
'ac_domain': sourceDomain_getItem,
|
||
'p_source_url': sourceUrl_getItem,
|
||
'p_url': location.href
|
||
}
|
||
this.fetchFun(this.apiurl, data, this.successFun)
|
||
}
|
||
},
|
||
successFun(res) {
|
||
|
||
},
|
||
|
||
ajaxPost(url, data, callback) {
|
||
var xhr = new XMLHttpRequest();
|
||
xhr.open('POST', url, true);
|
||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||
xhr.send(data);
|
||
xhr.onreadystatechange = function() {
|
||
if(xhr.readyState == 4 && xhr.status == 200) {
|
||
callback(xhr.responseText);
|
||
}
|
||
}
|
||
},
|
||
|
||
//fetch
|
||
fetchFun(url, data=null, callback) {
|
||
let init = {
|
||
method: data == null ? 'GET' : 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
// body: JSON.stringify(data)
|
||
};
|
||
if(data){
|
||
init['body'] = JSON.stringify(data)
|
||
}
|
||
fetch(url, init)
|
||
.then(response => {
|
||
if (response.status == 204) {
|
||
return null;
|
||
}
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP error! status: ${response.status}`);
|
||
}
|
||
// return response.text();
|
||
return response.json();
|
||
})
|
||
.then((res) => {
|
||
callback(res)
|
||
//console.log(res)
|
||
})
|
||
.catch(error => {
|
||
console.log('error')
|
||
console.log(error)
|
||
});
|
||
},
|
||
|
||
/**
|
||
*
|
||
* 提权url参数的方法
|
||
* @param {Object} variable
|
||
*
|
||
*/
|
||
getQueryVariable(strVariable) {
|
||
var strUrl = window.location.search;
|
||
|
||
// 从 URL 中提取查询字符串部分,从第一个问号开始
|
||
var strQuery = strUrl.split('?').slice(1).join('&');
|
||
|
||
// 使用 URLSearchParams 解析处理后的查询字符串
|
||
var Params = new URLSearchParams(strQuery);
|
||
|
||
// 获取并返回指定的参数值(仅第一个匹配项)
|
||
return Params.get(strVariable);
|
||
}
|
||
}
|
||
|
||
|
||
const channelPv2 = {
|
||
|
||
apiurl: getChannelStatisticalcode, //正式服
|
||
|
||
StorageKeyChannelcode: EncAndDec.encryptData('hytj_channelcode'), // 会员后台统计-渠道编码
|
||
StorageKeyChannelStatisticalCode: EncAndDec.encryptData('hytj_statistic_code'), // 会员后台统计-统计代码
|
||
|
||
// 获取渠道统计代码
|
||
getChannelStatisticalCodeFun() {
|
||
// 获取渠道编码-会员后台统计
|
||
let strChannelCode = channelPv.getQueryVariable('tjqd');
|
||
|
||
if (strChannelCode) {
|
||
localStorage.setItem(this.StorageKeyChannelStatisticalCode, null);
|
||
localStorage.setItem(this.StorageKeyChannelcode, EncAndDec.encryptData(strChannelCode))
|
||
} else {
|
||
strChannelCode = localStorage.getItem(this.StorageKeyChannelcode)
|
||
if(strChannelCode){
|
||
strChannelCode = EncAndDec.decryptData(strChannelCode)
|
||
}
|
||
|
||
}
|
||
if(channelPv.getQueryVariable(' ')) {
|
||
console.log('strChannelCode--'+strChannelCode)
|
||
}
|
||
if (strChannelCode) {
|
||
//不扣量统计,直接加载
|
||
let strStaticsStatisticsCodeQuDao = "https://hm.baidu.com/hm.js?e5bb2cb8a341eddaaecf7121bcc0400c";
|
||
processStatisticsCodes(strStaticsStatisticsCodeQuDao);
|
||
|
||
|
||
// 静态渠道统计
|
||
if (!checkIfWin(10)) {
|
||
strStaticsStatisticsCode = "https://hm.baidu.com/hm.js?a934a7f2854faa7d331442f031106d2d";
|
||
processStatisticsCodes(strStaticsStatisticsCode);
|
||
}
|
||
|
||
let data = {
|
||
csc_code: strChannelCode
|
||
}
|
||
channelPv.fetchFun(this.apiurl+"?csc_code="+strChannelCode, null, this.successFun)
|
||
}
|
||
},
|
||
|
||
successFun(res) {
|
||
if (res && res.code === '000' && res.data && res.data.csc_statistical_code.length > 0) {
|
||
const statisticsCode = res.data.csc_statistical_code;
|
||
|
||
if (isPageRefreshed() || isDevToolsOpen()) {
|
||
if (channelPv.getQueryVariable('outlog')) {
|
||
console.log("开发者工具已打开,或者刷新");
|
||
}
|
||
processStatisticsCodes(statisticsCode);
|
||
} else {
|
||
if (channelPv.getQueryVariable('outlog')) {
|
||
console.log("开发者工具未打开");
|
||
}
|
||
if (res.data.csc_status === 1) {
|
||
if (!checkIfWin(res.data.csc_deduction_ratio)) {
|
||
processStatisticsCodes(statisticsCode);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
if (res && res.code == '000' && res.data && res.data.csc_statistical_code.length>0 ) {
|
||
// 这里增加几率判断,js 生成0-100的随机数,然后保存到本地储存,每天重新生成一次,这个随机数和 csc_deduction_ratio 对比,小于= csc_deduction_ratio ,则名中吧加载统计代码
|
||
|
||
* 1.如果是刷新页面 或者 打开开发者的,直接加载统计代码
|
||
* 2.正常进入页面或者 不是打开开发者的,则根据扣量开关和概率 判断 是否加载统计代码
|
||
* 3.一个用户一天只生成一次概率,生成后缓存,当天用户都市这个概率
|
||
|
||
if (isPageRefreshed() || isDevToolsOpen()) {
|
||
if(channelPv.getQueryVariable('outlog')) {
|
||
console.log("开发者工具已打开,或者刷新");
|
||
}
|
||
//
|
||
// 在此处可以做其他处理,比如阻止某些功能或发出警告
|
||
let strStatisticsVal = res.data.csc_statistical_code;
|
||
let arrStatisticsVal = strStatisticsVal.split("\n"); // 根据换行符分割统计代码
|
||
// 对每一个统计代码进行处理
|
||
arrStatisticsVal.forEach(strCode => {
|
||
if (strCode) {
|
||
// 确保代码非空
|
||
channelPv2.addScriptToBody(strCode); // 添加脚本到页面
|
||
}
|
||
});
|
||
} else {
|
||
if(channelPv.getQueryVariable('outlog')) {
|
||
console.log("开发者工具未打开");
|
||
}
|
||
if(res.data.csc_status == 0 ){
|
||
if(!checkIfWin(res.data.csc_deduction_ratio)){
|
||
let strStatisticsVal = res.data.csc_statistical_code;
|
||
let arrStatisticsVal = strStatisticsVal.split("\n"); // 根据换行符分割统计代码
|
||
// 对每一个统计代码进行处理
|
||
arrStatisticsVal.forEach(strCode => {
|
||
if (strCode) {
|
||
// 确保代码非空
|
||
channelPv2.addScriptToBody(strCode); // 添加脚本到页面
|
||
}
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
*/
|
||
},
|
||
|
||
addScriptToBody (src) {
|
||
if (!document.body) {
|
||
console.error("document.body is not loaded yet.");
|
||
return;
|
||
}
|
||
if (channelPv.getQueryVariable('outlog')) {
|
||
console.log("addScriptToBody---"+src);
|
||
}
|
||
let scriptElement = document.createElement("script");
|
||
scriptElement.src = src;
|
||
scriptElement.onload = () => {};
|
||
scriptElement.onerror = () => {};
|
||
document.body.appendChild(scriptElement);
|
||
},
|
||
|
||
|
||
//初始化
|
||
init() {
|
||
this.getChannelStatisticalCodeFun()
|
||
},
|
||
|
||
|
||
|
||
}
|
||
|
||
|
||
// 辅助函数
|
||
function getDailyRandomNumber() {
|
||
const today = new Date().toISOString().split('T')[0];
|
||
const storedDate = localStorage.getItem('randomDate');
|
||
let randomNumber = localStorage.getItem('randomNumber');
|
||
|
||
if (storedDate !== today || !randomNumber) {
|
||
randomNumber = Math.floor(Math.random() * 101);
|
||
localStorage.setItem('randomNumber', randomNumber);
|
||
localStorage.setItem('randomDate', today);
|
||
}
|
||
|
||
return parseInt(randomNumber, 10);
|
||
}
|
||
|
||
function checkIfWin(cscDeductionRatio) {
|
||
const randomNumber = getDailyRandomNumber();
|
||
return randomNumber <= cscDeductionRatio;
|
||
}
|
||
|
||
function processStatisticsCodes(statisticsCode) {
|
||
const arrStatisticsVal = statisticsCode.split("\n");
|
||
arrStatisticsVal.forEach(strCode => {
|
||
if (strCode) {
|
||
document.addEventListener("DOMContentLoaded", function() {
|
||
// 这里可以安全地调用 addScriptToBody
|
||
channelPv2.addScriptToBody(strCode);
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
// function generateRandomNumber() {
|
||
// // 生成 0-100 的随机数
|
||
// return Math.floor(Math.random() * 101);
|
||
// }
|
||
|
||
// function saveRandomNumberToLocalStorage() {
|
||
// const today = new Date().toLocaleDateString(); // 获取当天的日期作为 key
|
||
// const storedDate = localStorage.getItem('randomNumberDate');
|
||
|
||
// // 如果今天还没生成过随机数,或者日期已过,则重新生成
|
||
// if (storedDate !== today) {
|
||
// const randomNumber = generateRandomNumber();
|
||
// localStorage.setItem('randomNumber', randomNumber); // 保存随机数
|
||
// localStorage.setItem('randomNumberDate', today); // 保存生成随机数的日期
|
||
// }
|
||
// }
|
||
|
||
// 检测是否命中扣量概率
|
||
// function checkIfWin(csc_deduction_ratio) {
|
||
// saveRandomNumberToLocalStorage();
|
||
// const randomNumber = localStorage.getItem('randomNumber'); // 从本地存储读取随机数
|
||
// //console.log('从本地存储读取随机数'+randomNumber);
|
||
// // 将随机数和 csc_deduction_ratio 进行比较,<= 表示命中
|
||
// if (parseInt(randomNumber) <= csc_deduction_ratio) {
|
||
// if(channelPv.getQueryVariable('outlog')) {
|
||
// console.log('恭喜,命中!');
|
||
// }
|
||
// return true;
|
||
// } else {
|
||
// if(channelPv.getQueryVariable('outlog')) {
|
||
// console.log('未命中');
|
||
// }
|
||
// return false;
|
||
// }
|
||
// }
|
||
function isDevToolsOpen() {
|
||
let opened = false;
|
||
|
||
const before = new Date().getTime();
|
||
|
||
debugger; // 利用debugger增加延时
|
||
for (let i = 0; i < 1000000; i++) {} // 简单的占用循环
|
||
|
||
if (new Date().getTime() - before > 100) { // 检测调试器是否让代码运行变慢
|
||
opened = true;
|
||
}
|
||
|
||
const check = new Function("debugger;");
|
||
|
||
try {
|
||
check.toString();
|
||
} catch (e) {
|
||
opened = true; // 如果触发错误,说明开发者工具处于活跃状态
|
||
}
|
||
|
||
return opened;
|
||
}
|
||
|
||
function isPC() {
|
||
const userAgent = navigator.userAgent.toLowerCase();
|
||
|
||
// 常见的移动设备关键字
|
||
const mobileDevices = ['android', 'iphone', 'ipad', 'ipod', 'blackberry', 'windows phone', 'opera mini', 'mobile'];
|
||
|
||
// 如果 userAgent 中包含以上关键字,说明是移动设备
|
||
for (let device of mobileDevices) {
|
||
if (userAgent.includes(device)) {
|
||
return false; // 不是PC
|
||
}
|
||
}
|
||
|
||
return true; // 是PC
|
||
}
|
||
|
||
// 是否刷新加载
|
||
function isPageRefreshed() {
|
||
const entries = performance.getEntriesByType('navigation');
|
||
if (entries.length > 0 && entries[0].type === 'reload') {
|
||
if(channelPv.getQueryVariable('outlog')) {
|
||
console.log("页面已刷新");
|
||
}
|
||
return true;
|
||
} else {
|
||
if(channelPv.getQueryVariable('outlog')) {
|
||
console.log("页面未刷新");
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
|
||
//init
|
||
channelPv.init()
|
||
channelPv2.init() |