睿能科技
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

400 lines
14 KiB

//#region \0vite/modulepreload-polyfill.js
(function polyfill() {
const relList = document.createElement("link").relList;
if (relList && relList.supports && relList.supports("modulepreload")) return;
for (const link of document.querySelectorAll("link[rel=\"modulepreload\"]")) processPreload(link);
new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.type !== "childList") continue;
for (const node of mutation.addedNodes) if (node.tagName === "LINK" && node.rel === "modulepreload") processPreload(node);
}
}).observe(document, {
childList: true,
subtree: true
});
function getFetchOpts(link) {
const fetchOpts = {};
if (link.integrity) fetchOpts.integrity = link.integrity;
if (link.referrerPolicy) fetchOpts.referrerPolicy = link.referrerPolicy;
if (link.crossOrigin === "use-credentials") fetchOpts.credentials = "include";
else if (link.crossOrigin === "anonymous") fetchOpts.credentials = "omit";
else fetchOpts.credentials = "same-origin";
return fetchOpts;
}
function processPreload(link) {
if (link.ep) return;
link.ep = true;
const fetchOpts = getFetchOpts(link);
fetch(link.href, fetchOpts);
}
})();
//#endregion
//#region js/common.js
const UI_I18N = {
zh: {
"video.play": "视频播放",
"filter.by_product": "按产品筛选",
"about.expand_more": "展开更多",
"about.collapse": "收起",
"brand.short": "睿能科技",
"stock.delay_note": "截止 {time}*报价有十五分钟或以上延迟。",
"contact.name_required": "请输入姓名",
"contact.phone_required": "请输入手机号",
"contact.company_required": "请输入公司名称",
"contact.email_required": "请输入邮箱",
"contact.submitting": "提交中...",
"contact.submit": "提交",
"contact.success": "提交成功,我们会尽快与您联系!",
"contact.fail": "提交失败,请稍后重试",
"contact.network_error": "网络错误,请稍后重试",
"earth.hq_fuzhou_html": "全球总部<br>福州"
},
en: {
"video.play": "Video",
"filter.by_product": "Filter by product",
"about.expand_more": "Show more",
"about.collapse": "Show less",
"brand.short": "RAYNEN",
"stock.delay_note": "As of {time}* Quotes delayed by 15 minutes or more.",
"contact.name_required": "Please enter your name",
"contact.phone_required": "Please enter your phone number",
"contact.company_required": "Please enter your company name",
"contact.email_required": "Please enter your email",
"contact.submitting": "Submitting...",
"contact.submit": "Submit",
"contact.success": "Submitted successfully. We will contact you soon.",
"contact.fail": "Submission failed. Please try again later.",
"contact.network_error": "Network error. Please try again later.",
"earth.hq_fuzhou_html": "Global HQ<br>Fuzhou"
}
};
function getUiLang() {
const fromHeader = document.querySelector(".site-header__lang")?.getAttribute("data-lang-current");
if (fromHeader === "en" || fromHeader === "zh") return fromHeader;
const seg = location.pathname.replace(/^\//, "").split("/")[0] || "";
return seg === "en" ? "en" : "zh";
}
function t(key, vars) {
const lang = getUiLang();
const table = UI_I18N[lang] || UI_I18N.zh;
let str = table[key] ?? UI_I18N.zh[key] ?? key;
if (vars && typeof vars === "object") {
Object.keys(vars).forEach((k) => {
str = str.replace(new RegExp(`\\{${k}\\}`, "g"), String(vars[k]));
});
}
return str;
}
window.getUiLang = getUiLang;
window.t = t;
$(function() {
AOS.init({ duration: 800 });
const lenis = new Lenis();
window.lenis = lenis;
gsap.registerPlugin(ScrollTrigger, Observer);
lenis.on("scroll", ScrollTrigger.update);
gsap.ticker.add((time) => {
lenis.raf(time * 1e3);
});
gsap.ticker.lagSmoothing(0);
const $header = $(".site-header");
const $mask = $(".mask");
const $targets = $("[data-header-dark]");
const updateHeader = () => {
if (!$header.length) return;
const headerRect = $header[0].getBoundingClientRect();
let shouldDark = false;
const probeX = Math.max(0, Math.min(window.innerWidth - 1, window.innerWidth / 2));
const probeY = Math.max(0, Math.min(window.innerHeight - 1, headerRect.bottom + 2));
if (document.elementFromPoint(probeX, probeY)?.closest("[data-header-dark]")) shouldDark = true;
else $targets.each(function() {
const rect = this.getBoundingClientRect();
if (rect.top <= headerRect.bottom && rect.bottom > headerRect.top) {
shouldDark = true;
return false;
}
});
$header.toggleClass("dark", shouldDark || $header.hasClass("is-mega-open"));
const isScrolled = window.scrollY > 50;
$header.toggleClass("is-scrolled", isScrolled);
$mask.toggleClass("is-scrolled", isScrolled);
};
lenis.on("scroll", updateHeader);
ScrollTrigger.addEventListener("refresh", updateHeader);
updateHeader();
const maskEl = document.querySelector(".mask");
const maskContentEl = document.querySelector(".mask-content");
function setMaskOpenUi(isOpen) {
$("body").toggleClass("is-mask-open", isOpen);
}
$(".site-header__extra-btn.toggle").on("click", function() {
if (!maskEl || !maskContentEl) return;
const nodes = maskContentEl.querySelectorAll(".mask-nav__link");
$(maskEl).addClass("show mask--nav-motion");
$("body").css("overflow", "hidden");
setMaskOpenUi(true);
gsap.killTweensOf(nodes);
gsap.from(nodes, {
opacity: 0,
y: 10,
stagger: .04,
delay: .2,
overwrite: "auto",
onComplete: function() {
maskEl.classList.remove("mask--nav-motion");
gsap.set(nodes, { clearProps: "all" });
}
});
});
$(".mask-header__icon-btn--close").on("click", function() {
if (!maskEl || !maskContentEl) return;
gsap.killTweensOf(maskContentEl.querySelectorAll("ul li a"));
$(maskEl).removeClass("show mask--nav-motion");
$("body").css("overflow", "auto");
setMaskOpenUi(false);
});
$(".mask-nav__toggle").on("click", function() {
const $item = $(this).closest(".mask-nav__item--expandable, .mask-nav__subitem--expandable");
const isExpanded = $item.attr("data-expanded") === "true";
$item.attr("data-expanded", String(!isExpanded));
$(this).attr("aria-expanded", String(!isExpanded));
});
// nav-mega 子组:标题 / 箭头均可展开收起(同组互斥)
$(document).on("click", ".nav-mega__subgroup-title, .nav-mega__subgroup-toggle", function() {
const $subgroup = $(this).closest(".nav-mega__subgroup");
const $siblings = $subgroup.siblings(".nav-mega__subgroup");
const isExpanded = !$subgroup.hasClass("is-expanded");
$siblings.removeClass("is-expanded").find(".nav-mega__subgroup-toggle").attr("aria-expanded", false);
$subgroup.toggleClass("is-expanded", isExpanded);
$subgroup.find(".nav-mega__subgroup-toggle").attr("aria-expanded", isExpanded);
});
// 语言切换:默认语言无前缀,其它语言用 /{lang}/ 前缀(与 getLang 一致)
(function initLangSwitch() {
const ALLOWED = ["zh", "tc", "en", "ja", "de", "fa", "id", "th", "ru"];
const defaultLang =
document.querySelector(".site-header__lang")?.getAttribute("data-lang-default") || "zh";
const getPathLang = () => {
const seg = location.pathname.replace(/^\//, "").split("/")[0] || "";
return ALLOWED.includes(seg) ? seg : defaultLang;
};
const buildLangUrl = (targetLang) => {
const parts = location.pathname.replace(/^\//, "").split("/").filter(Boolean);
if (parts.length && ALLOWED.includes(parts[0])) parts.shift();
const rest = parts.join("/");
let path;
if (!targetLang || targetLang === defaultLang) {
path = rest ? `/${rest}` : "/";
} else {
path = rest ? `/${targetLang}/${rest}` : `/${targetLang}/`;
}
return path + location.search + location.hash;
};
const goLang = (targetLang) => {
if (!targetLang) return;
const cur = getPathLang();
const uiCur = cur === "en" ? "en" : "zh";
if (targetLang === uiCur || targetLang === cur) return;
location.href = buildLangUrl(targetLang);
};
const syncActive = () => {
const uiLang = getPathLang() === "en" ? "en" : "zh";
$(".site-header__lang [data-lang]").removeClass("site-header__lang-active");
$(`.site-header__lang [data-lang="${uiLang}"]`).addClass("site-header__lang-active");
};
$(document).on("click", ".site-header__lang [data-lang]", function(e) {
e.preventDefault();
e.stopPropagation();
goLang(this.getAttribute("data-lang"));
});
$(document).on("click", ".site-header__lang", function(e) {
if ($(e.target).closest("[data-lang]").length) return;
goLang(getPathLang() === "en" ? "zh" : "en");
});
$(document).on("click", ".site-header__extra-btn.lang, .mask-header__icon-btn.lang", function(e) {
e.preventDefault();
goLang(getPathLang() === "en" ? "zh" : "en");
});
syncActive();
})();
// $(".section-contact-form").on("submit", function(e) {
// e.preventDefault();
// const $form = $(this);
// const $name = $form.find("[name=\"name\"]");
// const $phone = $form.find("[name=\"phone\"]");
// const name = $.trim($name.val());
// const phone = $.trim($phone.val());
// const agreed = $form.find("[name=\"agree\"]").is(":checked");
// if (!name) {
// alert("请输入姓名");
// $name.focus();
// return;
// }
// if (!phone) {
// alert("请输入联系方式");
// $phone.focus();
// return;
// }
// if (!agreed) {
// alert("请阅读并同意隐私政策");
// return;
// }
// alert("提交成功,我们将尽快与您联系");
// $form[0].reset();
// });
$("#nav-mega-product").on("mouseenter", "[data-mega-cat]", function() {
const $mega = $("#nav-mega-product");
const cat = $(this).attr("data-mega-cat");
$mega.find("[data-mega-cat]").removeClass("is-active");
$(this).addClass("is-active");
$mega.find("[data-mega-panel]").each(function() {
const match = this.dataset.megaPanel === cat;
this.hidden = !match;
this.classList.toggle("is-active", match);
});
});
// Lenis.stop() 会加 .lenis-stopped { overflow: clip },经典滚动条(如360)消失后
// fixed 头部会变宽;内容区通常不变。只补偿头部,不给 html/body 加 padding。
function getScrollbarWidth() {
return Math.max(0, window.innerWidth - document.documentElement.clientWidth);
}
function lockPageScroll() {
const root = document.documentElement;
if (root.classList.contains("is-scroll-locked")) return;
const sbw = getScrollbarWidth();
root.style.setProperty("--scroll-lock-compensation", `${sbw}px`);
root.classList.add("is-scroll-locked");
lenis.stop();
// 若 CSS 已保住滚动条,则清零补偿,避免头部被多余收窄
requestAnimationFrame(() => {
if (getScrollbarWidth() > 0) {
root.style.setProperty("--scroll-lock-compensation", "0px");
}
});
}
function unlockPageScroll() {
const root = document.documentElement;
if (!root.classList.contains("is-scroll-locked")) return;
root.classList.remove("is-scroll-locked");
root.style.removeProperty("--scroll-lock-compensation");
lenis.start();
}
$(".nav-mega").attr("data-lenis-prevent", "");
$(".site-header__nav-item--mega").on("mouseenter", function() {
if ($("body").hasClass("is-mask-open")) return;
lockPageScroll();
}).on("mouseleave", function() {
if ($("body").hasClass("is-mask-open")) return;
unlockPageScroll();
});
// 股票行情局部刷新(页脚 + 投资者关系页),不整页 reload
(function initStockQuoteRefresh() {
const INTERVAL = 60 * 1000;
let timer = null;
const setText = (el, text) => {
if (el) el.textContent = text;
};
const setColor = (el, color) => {
if (!el) return;
if (color) el.style.color = color;
else el.style.removeProperty("color");
};
const applyQuote = (data) => {
if (!data) return;
const color = data.color || "";
const changeText = `${data.change || "--"}\u00a0\u00a0${data.changePercent || "--"}`;
document.querySelectorAll("[data-stock-quote]").forEach((root) => {
const priceEl = root.querySelector('[data-stock="price"]');
const unitEl = root.querySelector('[data-stock="unit"]');
const changeEl = root.querySelector('[data-stock="change"]');
setText(priceEl, data.price ?? "--");
setText(changeEl, changeText);
setColor(priceEl, color);
setColor(unitEl, color);
setColor(changeEl, color);
});
setText(document.querySelector('[data-stock="high"]'), data.high ?? "--");
setText(document.querySelector('[data-stock="low"]'), data.low ?? "--");
setText(document.querySelector('[data-stock="volume"]'), data.volume ?? "--");
setText(document.querySelector('[data-stock="amount"]'), data.amount ?? "--");
const timeEl = document.querySelector('[data-stock="time"]');
if (timeEl && data.updateTime) {
timeEl.textContent = t("stock.delay_note", { time: data.updateTime });
}
const chartEl = document.querySelector('#stock-chart, [data-stock="chart"]');
if (chartEl) {
const code =
document.querySelector("[data-stock-quote]")?.getAttribute("data-stock-code") ||
data.code ||
"603933";
const market = String(code).charAt(0) === "6" ? "sh" : "sz";
const raw = String(data.chart || `https://image.sinajs.cn/newchart/min/n/${market}${code}.gif`);
const base = raw.split("?")[0];
chartEl.setAttribute("src", `${base}?t=${Date.now()}`);
}
};
const fetchQuote = () => {
const code =
document.querySelector("[data-stock-quote]")?.getAttribute("data-stock-code") || "603933";
return fetch(`/stock/quote?code=${encodeURIComponent(code)}`, {
credentials: "same-origin",
headers: { Accept: "application/json" }
})
.then((res) => (res.ok ? res.json() : null))
.then((json) => {
if (!json || (json.code !== 0 && json.code !== 200)) return;
applyQuote(json.data || json);
})
.catch(() => {});
};
const start = () => {
if (timer) return;
timer = setInterval(fetchQuote, INTERVAL);
};
const stop = () => {
if (!timer) return;
clearInterval(timer);
timer = null;
};
if (!document.querySelector("[data-stock-quote], [data-stock='chart'], #stock-chart")) return;
fetchQuote();
start();
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
stop();
} else {
fetchQuote();
start();
}
});
})();
});
//#endregion