тууралуу...">
,需要通过父级DOM结构来判断
*/
var trackActionPhone = function (node) {
var nodeInnerText = node.innerText || '';
if (!limitRegLength(nodeInnerText)) return;
var nodeText = trimText(nodeInnerText);
if (nodeText.length < 5 || nodeText.length > 20) return false;
var type =
arguments.length > 1 && arguments[1] !== undefined
? arguments[1]
: 'click';
var str = trimText(node.href || node.innerHTML || '');
if (phoneReg.test(str) && numUseReg.test(str)) {
_paq.push(['trackEvent', type, 'phone', nodeText]);
return true;
}
/** 排查父级嵌套非标签场景,并且对dom的正则校验做一个性能兜底,通过控制innerText的长度,来确保正则的性能 */
var fatherText = trimText(node.parentNode.innerText || '');
if (fatherText.length < 5 || fatherText.length > 20) return false;
var fatherDom = trimText(node.parentNode.innerHTML || '');
if (phoneReg.test(fatherDom) && numUseReg.test(fatherDom)) {
_paq.push(['trackEvent', type, 'phone', nodeText]);
return true;
}
return false;
};
window.addEventListener('click', function (e) {
var node = e.target;
/** 社媒点击 */
var appName = '';
var getAppAriaLabel =
node.ariaLabel || node.parentNode.ariaLabel || '';
if (mediaList.includes(getAppAriaLabel.toLowerCase())) {
appName = getAppAriaLabel;
}
if (
!appName &&
node.nodeName &&
node.nodeName.toLowerCase() === 'a'
) {
appName = getMediaName(node.href) || getMediaName(node.alt);
}
if (
!appName &&
node.nodeName &&
node.nodeName.toLowerCase() === 'img'
) {
appName = getMediaName(node.alt) || getMediaName(node.src);
}
if (
!appName &&
node.nodeName &&
node.nodeName.toLowerCase() === 'i'
) {
appName = getMediaName(node.className);
}
if (appName) {
_paq.push(['trackEvent', 'click', 'contactApp', appName]);
return;
}
/** 联系方式点击 */
if (trackActionPhone(node, 'click')) return;
if (node.nodeName && node.nodeName.toLowerCase() === 'a') {
var val = node.href;
if (!limitRegLength(val)) return;
if (emailReg.test(val)) {
_paq.push(['trackEvent', 'click', 'email', val]);
return;
}
}
if (node.nodeName && node.nodeName.toLowerCase() === 'i') {
var val = node.className;
var content = node.parentNode.href || '';
if (val.includes('email')) {
_paq.push(['trackEvent', 'click', 'email', content]);
return;
}
}
var nodeChildList = node.childNodes;
for (var i = 0; i < nodeChildList.length; i++) {
if (nodeChildList[i].nodeType !== 3) continue;
var val = nodeChildList[i].textContent.replace(/\s?:?/g, '');
if (!limitRegLength(val)) continue;
if (emailReg.test(val)) {
_paq.push(['trackEvent', 'click', 'email', val]);
return;
}
}
trackNumberData(node);
});
window.addEventListener('copy', function (e) {
if (trackActionPhone(e.target, 'copy')) return;
var text = e.target.textContent;
if (!text) return;
var val = text.replace(/\s:?/g, '');
if (!limitRegLength(val)) return;
if (emailReg.test(val)) {
_paq.push(['trackEvent', 'copy', 'email', val]);
return;
}
trackNumberData(e.target);
});
}
trackContactInit();
/**
* 基于custom_inquiry_form.js 以及 form.js 对于询盘表单提交的实现,来反推询盘表单的input标签触发,用来收集意向客户
* 1. 缓存的KEY:TRACK_INPUT_ID_MTM_00;
* 2. 缓存策略 - lockTrackInput:单个页面内,10分钟内,不重复上报
*/
function trackActionInput() {
const CACHE_KEY = 'TRACK_INPUT_ID_MTM_00';
const pathName = window.location.hostname + window.location.pathname;
var lockTrackInput = function () {
try {
const lastCacheData = localStorage.getItem(CACHE_KEY);
if (!lastCacheData) return false;
const cacheData = JSON.parse(lastCacheData);
const cacheTime = cacheData[pathName];
if (!cacheTime) return false;
return Date.now() - cacheTime < 1000 * 60 * 10; // 10分钟内,不重复上报
} catch (error) {
console.error('lockTrackInput Error', error);
return false;
}
};
var setInputTrackId = function () {
try {
const curCacheData = localStorage.getItem(CACHE_KEY);
if (curCacheData) {
const cacheData = JSON.parse(curCacheData);
cacheData[pathName] = Date.now();
localStorage.setItem(CACHE_KEY, JSON.stringify(cacheData));
return;
}
const cacheData = {
[pathName]: Date.now(),
};
localStorage.setItem(CACHE_KEY, JSON.stringify(cacheData));
} catch (error) {
console.error('setInputTrackId Error', error);
}
};
var getInputDom = function (initDom) {
var ele = initDom;
while (ele) {
/**
* isWebSiteForm 是站点的表单
* isChatWindowForm 是聊天窗口的表单
*/
/** 旧模板表单 */
var isWebSiteForm = !!(
/crm-form/i.test(ele.className) && ele.querySelector('form')
);
/** 1:新模板自定义表单、2:Get a Quote 弹框表单 */
var isWebSiteFormNew = !!(
/inquiry/i.test(ele.className) && ele.querySelector('form')
);
if (isWebSiteForm || isWebSiteFormNew) {
_paq.push(['trackEvent', 'formInquiry', 'formInput', 'page']);
setInputTrackId();
return;
}
/** Mkt会话触达-聊天弹框的表单输入: MKT由于是iframe嵌入,所以MKT的上报,会单独写到MKT-form代码上 */
var isInquiryChatForm = !!(
/comp-form/i.test(ele.className) && ele.querySelector('form')
);
if (isInquiryChatForm) {
_paq.push(['trackEvent', 'formInquiry', 'formInput', 'chat']);
setInputTrackId();
return;
}
/** 向上查找父节点 */
ele = ele.parentNode;
}
};
function initInputListener() {
var inputUseDebounce = function (fn, delay) {
var timer = null;
var that = this;
return function () {
var args = Array.prototype.slice.call(arguments);
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(that, args);
}, delay);
};
};
var optimizeGetInputDom = inputUseDebounce(getInputDom, 300);
window.addEventListener('input', function (e) {
/** 如果已经上报过,则不再上报 */
if (lockTrackInput()) return;
optimizeGetInputDom(e.target);
});
}
try {
initInputListener();
} catch (error) {
console.log('initInputListener Error', error);
}
}
trackActionInput();
}
/** 第三方消息上报:目前主要是针对全点托管会话;在msgCollect/index.js中调试,访问test.html */
function thirdMsgCollect() {
/** 先检测是否是stayReal托管:如果stayReal脚本都没有,那么说明当前站点未开启stayReal会话托管 */
const scriptList = Array.prototype.slice.call(
document.querySelectorAll('script'),
);
const checkStayReal = () =>
!!scriptList.find((s) => s.src.includes('stayreal.xiaoman.cn'));
if (!checkStayReal()) return;
/** 缓存当前消息队列的最后一条消息id */
const CACHE_KEY = 'CACHE_KEY_MONITOR';
const setCache = (msgIndex) => {
/** 对缓存KEY进行base64转码处理 */
const cacheMsgIndex = btoa(msgIndex);
localStorage.setItem(CACHE_KEY, cacheMsgIndex);
};
const getCache = () => {
const cacheMsgIndex = localStorage.getItem(CACHE_KEY);
if (cacheMsgIndex) return Number(atob(cacheMsgIndex));
return -1;
};
/** 拉取最新msg列表 */
const pullMsgList = () => {
const msgEleList = Array.prototype.slice.call(
document.querySelectorAll('#chat-list li'),
);
const msgIds = [];
const msgMap = msgEleList.reduce((acc, item) => {
const sendTime = item
.querySelector('.message-data-time')
.textContent.trim();
const sendContent = item.querySelector('.message').textContent.trim();
/** msg带有class:other-message的是访客消息,my-message的是客服消息 */
const isOtherMessage = item
.querySelector('.message')
.classList.contains('other-message');
const msgId = item.querySelector('.message').getAttribute('id');
const msgItemData = {
msgId,
user: isOtherMessage ? 'visitor' : 'official',
time: sendTime,
content: sendContent,
};
msgIds.push(msgId);
acc[msgId] = msgItemData;
return acc;
}, {});
return {
ids: msgIds,
dataMap: msgMap,
};
};
/** 加密并上传消息数据 */
let ENCRYPT_KEY = 'de29f1aab63ab033';
let ENCRYPT_IV = 'b8d2badf875e76ac';
const baseUrl = 'https://cms.xiaoman.cn';
// var getEncryptConfig = function () {
// const url = baseUrl + '/shop-api/innerApi/getKeyIv'
// $.get(
// url,
// function (result) {
// console.log('result', result)
// if (Number(result.code) === 0 && result.data.key && result.data.iv) {
// ENCRYPT_KEY = result.data.key
// ENCRYPT_IV = result.data.iv
// uploadMsgData()
// } else {
// /** 如果获取失败,则重试 */
// setTimeout(() => {
// getEncryptConfig()
// }, 1000)
// }
// },
// 'json'
// )
// }
// getEncryptConfig()
const encryptMsg = function (msgData) {
const enc = new TextEncoder();
// 转字节
const keyBytes = enc.encode(ENCRYPT_KEY);
const ivBytes = enc.encode(ENCRYPT_IV);
const plainBytes = enc.encode(msgData);
// 导入密钥并加密
return crypto.subtle
.importKey('raw', keyBytes, { name: 'AES-CBC' }, false, ['encrypt'])
.then(function (cryptoKey) {
return crypto.subtle.encrypt(
{ name: 'AES-CBC', iv: ivBytes },
cryptoKey,
plainBytes,
);
})
.then(function (encryptedBuffer) {
// 转 base64 返回
return btoa(
String.fromCharCode(...new Uint8Array(encryptedBuffer)),
);
})
.catch((err) => {
return Promise.reject(err);
});
};
let uploadFlag = false;
const uploadMsgData = function () {
if (uploadFlag) return;
uploadFlag = true;
const { ids, dataMap } = pullMsgList();
let cacheMsgIndex = getCache();
const msgLen = ids.length;
if (!msgLen) {
// 消息DOM未挂载 || 消息DOM已挂载,但是消息列表为空
uploadFlag = false;
return;
}
if (msgLen - 1 < cacheMsgIndex) {
/** 针对站点挂后台一段时间,消息列表会自动塞入重复消息,导致消息有重复,刷新后又重置回正常消息列表,所以这里需要更新锚点下标 */
cacheMsgIndex = msgLen - 1;
setCache(cacheMsgIndex);
uploadFlag = false;
return;
}
if (msgLen - 1 === cacheMsgIndex) {
// 缓存的最后一次发送的消息ID是最后一条(说明当前消息均已经上报),则不跳过本地上报
uploadFlag = false;
return;
}
const currentMsgIds = ids.slice(cacheMsgIndex + 1, msgLen);
const currentMsgData = currentMsgIds.map((id) => dataMap[id]);
const mtmId = window.matomo_site_id_cookie_key || ''; // 获取mtm会话id
const msgBody = {
mtmId,
curl: window.location.href,
msgList: currentMsgData,
};
const msgBodyStr = JSON.stringify(msgBody);
encryptMsg(msgBodyStr)
.then(function (encryptedMsg) {
console.log('encryptedMsg:', encryptedMsg, msgBodyStr);
const url = baseUrl + '/shop-api/External/ListenSiteActiveStatus';
$.ajax({
type: 'POST',
url,
data: JSON.stringify({ d_v: encryptedMsg }),
contentType: 'application/json',
success: function (result) {
if (Number(result.code) === 0) {
// 更新消息队列
setCache(msgLen - 1);
}
uploadFlag = false;
},
error: function (err) {
console.error(err, '请求异常');
uploadFlag = false;
},
});
})
.catch((err) => {
console.error(err, '数据加密失败');
uploadFlag = false;
});
};
/** 监控chat-list的DOM变更 */
const initChatListObserver = () => {
// 需要监听的 DOM 节点
const target = document.getElementById('chat-list');
if (!target) return;
// 回调函数
const callback = function (mutationsList, observer) {
for (const mutation of mutationsList) {
console.log('mutation', mutation);
if (mutation.type === 'childList') {
uploadMsgData();
}
}
};
// 配置
const config = {
childList: true, // 监听子节点的增删
subtree: true, // 是否也监听后代节点
};
// 创建 observer
const observer = new MutationObserver(callback);
// 开始监听
observer.observe(target, config);
};
let testCount = 30;
let itv = null;
const checkChatDom = () => !!document.querySelector('#vc-model');
const initTalkCheck = () => {
itv = setTimeout(() => {
console.log('checkChatDom', checkChatDom(), testCount);
if (!checkChatDom() && testCount > 0) {
testCount--;
initTalkCheck();
return;
}
clearTimeout(itv);
uploadMsgData();
initChatListObserver();
}, 1500);
};
initTalkCheck();
}
try {
gtmTrack();
thirdMsgCollect();
console.log('inserted gtm code');
} catch (error) {
console.error('gtmTrack Error', error);
}
});
})();
Сиздин транспорттук каражатыңыздын чалбыр кылымдар , алар катуу, прочный жана бюджеттүү болушу керек. Бул жерде биз, YAOLILAI компаниясы, ишке ашып, чыгабыз. Биз жакшы баалар менен сатууга болот чыбыктардын чоң тандоосун сунуштайбыз. Сиз ремонттоо бекетин жабдып жатсаңыз же жеке транспортту жаңыртып жатсаңыз, бизде сизге керек нерселер бар! Биздин болот чыбыктарыбыз эң жогорку сапатка тиешелүү, нарыкка жаңы сапат деңгээлин алып келет. YAOLILAI компаниясында сапат биринчи орунда. Биздин жогорку сапаттагы алмаштыруу үчүн аркандарыбыз эң жакшы мейкиндиктерден жасалган. Бул аркандар жолдон тыс катуу шарттарга чыдап, төрт тегермегиңизди жолдо эң жакшы колдоо көрсөтүү үчүн долбоорлоштурулган. Кыйын көчөлөрдө же толкундуу трассаларда болуп калышыңыздан тышкары, биздин аркандар ишти аткара алар. Бизде бардык талаптарыңызга туура келген өлчөмдөрүбүз жана стилдеримиз бар. Автомобилдик дүкөнүңүз бар болсо, сапатты төмөндөтпөстөн чыгымдарды кыскартуунун маанисин түшүнөсүз. YAOLILAI производствосу сапаттуу болот жана баасы төмөн болгон болот. Биздин дисктерди тандаганда, арзан баада жаңы запастар ала аласыз. Дисктерибиз чоң прочностько ээ болгондуктан узак мөөнөттө колдонуп, узак мөөнөттө акча токтой аласыз. Техникалык мүнөздөмөлөрү, орундоштуруу жана сапатына 30 күндүк акча кайтарып берүү кепилдиги. Жогорку сапаттагы болот дисктер менен жолдо жакшыраак сезимге жана жөнтөлүшкө ээ болуңуз. Эң керек учурда дисктин бүгүлүшү же сызылып кетиши - бул эч нерседен жаман. Бирок YAOLILAI OEM болот дисктери менен мындай көйгөй башыңызга келбейт. Биздин дисктерибиз өнөр жайда эң жогорку стандарт боюнча циклдүү сындан өткөрүлөт жана туруктуулугу жогорку, анан сиз стабилдуулук менен жана ишенчи менен узак мезгил жүрө аласыз. Биздин дисктердин ушул далилдүүлүгү автофана жана професионалдар бул өнүмгө ишенүүнүн себеби. Опциялар дүйнөсүндө көзгө түшүү катуу. Бул жерде YAOLILAI компаниясынын OEM болот чыбыктарынын премиум линиясы колдонгон. Биздин өзүбүздүн дизайныбыз бар жана жогорку сапат! Биздин чыбыктарыбыз аркылуу башкалардын колунда жок уникалдуу нерсе сунуштоо мүмкүнчүлүгүңүз бар. Биз клиенттер үчүн компетенттүү, ишти сүйгөн жана заботтуу кызматкерлерди түзүп алдык. Алгачкы сатып алуу консультациясы болсун же сатып алгандан кийинки OEM болоттун тегереги болсун, биз сизге тез жана профессионалдык кызмат көрсөтөбүз, андагы кайсы бир кабыл алынбаган кынтыгыңыз болбойт. Баштапкы материалдарды тандоодо биз сапат боюнча катуу стандарттарга үнөмдүүлүк менен ылайыкташып, өндүрүштүн ар бир этапын баалап отуробуз. Ар бир болоттун тегереги анын жогорку күчүн, төзүмдүүлүгүн жана OEM болоттун тегереги өлчөмдөрүн камсыз кылуу үчүн көп сандагы текшерүү процедураларынан өтөт, андагы сизге жогорку сапаттагы кепилдик берилет. oEM болоттун тегереги ар бир клиенттин талаптары өзгөчөлүгүн түшүнөт жана биз ар түрлүү персоналдаштырылган кызматтарды сунуштайбыз. Биз стиле, дизайнга жана талаптарга дал келген тегерек түзүп бере алабыз. Биздин изилдөө жана өнүктүрүү тобу оем болгон болоттун тегерчектери менен кызыктырылган жана алар даими түрдө жаңы технологияларды, материалдарды жана дизайндарды изилдеп жатат. Биз өнөрпаздыкта рыноктун талаптарына жана тенденцияларына ылдам реакция беребиз жана сиздерге эң инновациялык болоттун тегерчектери менен камсыз кылабыз, бул продукттар сиздердин талаптарыңызга туура келет.Егер сиз мушкиелер турундагы мeseлeлерди кoрcош болсоңуз, менге тиешеме тилебиз!
oEM болот коробкасы
Жогорку сапаттагы OEM болот доңдондорду албеткичтен тийишүү баалар менен өзүңүздүн запасыңызды жаңыртыңыз.

Биздин OEM болот доңдондорубуз менен жогорку өнүмдүүлүк жана ишенчтүүлүктү байкоңүз.

Биздин эксклюзивдүү OEM болот доңдондор коллециябыз менен башкалардан айырмаланыңыз.

OEM болот доңдондор боюнча бардык зарылдыктарыңыз үчүн өнөр жүрүштүн лидери болгон жеткизүүчүнү тандоо.
Why choose YAOLILAI oEM болот коробкасы?
Профессиялык клиенттик кызмат:
Таттелүү сапкасы:
Жеке жана тамырланган кызмат:
Инновациялык R&D команда:
Керегиз кызматтаалуу нерсе таба албыйсыз бе?
Эмне жакында суроо кылыңыз
Коюнда көпүрөө products уучун консультанттарымыздын байланышыңыз.Байланышуу