// 1. 创建组件模板和样式(内置到 JS 中,无需外部 HTML/Template) const template = document.createElement("template"); template.innerHTML = `
已获得
个寄托币
投币
你当前共有
寄托币 [挣币攻略]
作者设置了阅读限制,解锁所有内容仅需 寄托币
投币解锁
你共有 寄托币
你的寄托币不够,快去发帖挣币吧
攒币指南
`; // 2. 定义组件类 class BiCard extends HTMLElement { constructor() { super(); this.coins = 0; this.token = ""; this.pagetpye = ""; this.displaytips = ""; // 创建 Shadow DOM 并挂载模板 this.attachShadow({ mode: "open" }); this.shadowRoot.appendChild(template.content.cloneNode(true)); this.strategyEl = this.shadowRoot.querySelector(".coins-info .strategy"); this.mybalanceEl = this.shadowRoot.querySelector(".coins-info .sum"); this.coinsAreaEl = this.shadowRoot.querySelector(".coins-area"); this.coinsEl = this.shadowRoot.querySelector(".coins-area .coins-head .sum"); this.coinSubmitEl = this.shadowRoot.querySelector(".coins-input .coinSubmit"); this.closeCoinBoxEl = this.shadowRoot.querySelectorAll(".coins-area .closeCoinBox"); this.closeCoinBoxEl.forEach((item) => { item.addEventListener("click", () => this.closeCoinBox()); }); this.coinSubmitEl.addEventListener("click", () => this.coinSubmit()); this.input = this.shadowRoot.querySelector(".coins-input .input"); this.coinListAreaEl = this.shadowRoot.querySelector(".coins-list-area"); this.defaultcoinnum = 0; // 将实例存储到全局变量中,以便外部调用 window.biComponent = this; this.pagetpyeText = this.shadowRoot.querySelector(".pagetpyeText"); this.coinsBoxEl = this.shadowRoot.querySelector(".coins-box"); // 解锁插入币弹窗 this.coinsUnlock = this.shadowRoot.querySelector(".unlock-insertcoins-box"); this.coinsNoBi = this.shadowRoot.querySelector(".no-jituobi-pop-box"); } // 监听的属性列表 static get observedAttributes() { return ["coins", "token", "pagetpye", "displaytips"]; } // 属性变化回调 attributeChangedCallback(attrName, oldVal, newVal) { this[attrName] = newVal; // 同步属性值到变量 } init(type) { this.fetchGetData(`https://api.gter.net/v2/api/forum/getCoinConfig`).then((res) => { const data = res.data; const strategy = data.config.strategy.url || 0; const mybalance = data.mybalance || 0; const defaultcoinnum = data.defaultcoinnum || 0; // 替换策略链接 this.strategyEl.href = "https://bbs.gter.net/account.php?a=credit&op=rule"; this.mybalanceEl.textContent = mybalance; this.coinsEl.textContent = this.coins; this.defaultcoinnum = defaultcoinnum; this.input.placeholder = `输入投币数,默认${defaultcoinnum}个币`; this.coinsAreaEl.style.display = "flex"; if (type == "unlock") { if (mybalance >= defaultcoinnum) { this.coinsBoxEl.style.display = "none"; this.coinsNoBi.style.display = "none"; this.coinsUnlock.style.display = "flex"; this.coinsUnlock.querySelector(".coinNum").textContent = defaultcoinnum; this.coinsUnlock.querySelector(".balance").textContent = mybalance; this.coinsUnlock.querySelector(".unlock-insertcoins-btn").addEventListener("click", () => this.coinSubmit(type)); } else { this.coinsBoxEl.style.display = "none"; this.coinsUnlock.style.display = "none"; this.coinsNoBi.style.display = "flex"; } } else { this.coinsUnlock.style.display = "none"; this.coinsNoBi.style.display = "none"; this.coinsBoxEl.style.display = "flex"; } }); if (!this.coinListAreaEl.querySelector(".list")) this.getCoinRankList(); const obj = { offer: "Offer", summary: "总结", mj: "面经", thread: "帖子", vote: "投票", }; this.pagetpyeText.textContent = obj[this.pagetpye]; } getCoinRankList() { this.fetchGetData(`https://api.gter.net/v2/api/forum/getCoinRankList?token=${this.token}&limit=1000`).then((res) => { const data = res.data; this.coinListAreaEl.innerHTML = ""; const coinNubmer = data.nubmer; if (coinNubmer == 0) return; const total = `
${coinNubmer}
人参与投币:
`; const coinList = data.data; let list = coinList .map((item) => { return `
${item.rank}
${item.user.nickname || "匿名用户"}
${item.coins}
`; }) .join(""); list = `
${list}
`; const listHTML = total + list; this.coinListAreaEl.innerHTML = listHTML; }); } coinSubmit() { const num = Number(this.input.value || this.defaultcoinnum) || 0; if (num <= 0) { creationAlertBox("error", "投币数量必须大于0"); return; } this.fetchData(`https://api.gter.net/v2/api/forum/postTopicCoin`, { token: this.token, num, }).then((res) => { if (res.code == 200) creationAlertBox("success", res.message); else creationAlertBox("error", res.message); if (res.code != 200) return; let data = res.data; if (this.displaytips == "coindisplayuser") { setTimeout(() => window.location.reload(), 1000); return; } this.mybalanceEl.textContent = Number(this.mybalanceEl.textContent) - num || 0; this.input.value = ""; const coins = data.coins; this.coinsEl.textContent = coins || 0; if (this.pagetpye == "thread") document.querySelector(".action-bar-item.coins .text").textContent = coins || 0; if (this.pagetpye == "vote") document.querySelector(".coinText").textContent = coins || 0; if (this.pagetpye == "mj") document.querySelector(".coinText").textContent = coins || 0; if (this.pagetpye == "offer") document.querySelector(".broadside-text.cursorpointer.coinText").textContent = (coins || 0) + " 寄托币"; if (this.pagetpye == "summary") document.querySelector(".broadside-text.cursorpointer.coinText").textContent = (coins || 0) + " 寄托币"; this.getCoinRankList(); }); } closeCoinBox() { this.coinsAreaEl.style.display = "none"; } // 静态方法,用于在外部调用组件初始化 type normal 展示正常的投币和列表 unlock 解锁插入币弹窗 或者 币不足 static initComponent(type = "normal") { if (window.biComponent) { window.biComponent.init(type); return true; } console.warn("bi组件尚未加载或挂载"); return false; } // 生命周期:组件挂载 connectedCallback() {} // 生命周期:组件卸载 disconnectedCallback() { console.log(`用户卡片 ${this.getAttribute("username")} 已卸载`); } getScriptParameter(paramName) { const currentScript = document.currentScript; if (currentScript && currentScript.src) { const url = new URL(currentScript.src, window.location.origin); return url.searchParams.get(paramName); } return null; } fetchData(url, data) { return new Promise((resolve, reject) => { if (data) data["v"] = this.getScriptParameter("v") || "v2"; var xhr = new XMLHttpRequest(); xhr.responseType = "json"; xhr.withCredentials = true; xhr.open("POST", url, true); xhr.setRequestHeader("Content-Type", "application/json"); if (["127.0.0.1", "localhost", "192.168.18.219"].includes(location.hostname)) xhr.setRequestHeader("Authorization", "3b01343c65e3b2fa3ce32ae26feb3a9b"); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { let response = xhr.response; resolve(response); } else if (xhr.status === 401) { if (typeof ajax_login === "function") ajax_login(); else window.open("https://passport.gter.net/?referer=" + escape(location.href), "_self"); } }; xhr.send(JSON.stringify(data)); }); } fetchGetData(url) { return new Promise((resolve, reject) => { const paramSymbol = url.includes("?") ? "&" : "?"; url = `${url}${paramSymbol}v=${this.getScriptParameter("v") || "v2"}`; const xhr = new XMLHttpRequest(); xhr.withCredentials = true; xhr.open("GET", url, true); if (["127.0.0.1", "localhost", "192.168.18.219"].includes(location.hostname)) xhr.setRequestHeader("Authorization", "3b01343c65e3b2fa3ce32ae26feb3a9b"); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { let response = xhr.response; resolve(JSON.parse(response)); } else if (xhr.status === 401) { if (typeof ajax_login === "function") ajax_login(); else window.open("https://passport.gter.net/?referer=" + escape(location.href), "_self"); } }; xhr.send(); }); } } // 3. 注册组件(确保只注册一次) if (!customElements.get("bi-card")) customElements.define("bi-card", BiCard); // 4. 导出组件类,以便在外部直接调用 window.BiComponent = BiCard;