移除多个文件中的console.log调试语句 添加search-tag.css和search-tag.less中的set-hint-box样式 新增recommend.js推荐功能模块 优化ajaxGet调用和用户信息处理逻辑
261 lines
21 KiB
JavaScript
261 lines
21 KiB
JavaScript
// 1. 创建组件模板和样式(内置到 JS 中,无需外部 HTML/Template)
|
||
const template = document.createElement("template");
|
||
template.innerHTML = `<style> .flexflex { display: flex; } .flexcenter { display: flex; justify-content: center; align-items: center; } .flexjcenter { display: flex; justify-content: center; } .flexacenter { display: flex; align-items: center; } .flex1 { flex: 1; } .flexcolumn { display: flex; flex-direction: column; } .one-line-display { word-break: keep-all; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .two-line-display { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; text-overflow: ellipsis; } .coins-area { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 10004; display: none; } .coins-area * { box-sizing: border-box; } .coins-area a { text-decoration: none; } .coins-area .coins-box { width: 624px; background-color: #ffffff; border: 1px solid #e9eef2; border-radius: 11px; flex-direction: column; padding: 40px 30px 35px; position: relative; display: none; max-width: calc(100vw - 10px); } .coins-area .coins-box .fork { width: 12px; height: 12px; position: absolute; top: 20px; right: 20px; cursor: pointer; } .coins-area .coins-box .coins-head { margin-bottom: 32px; } .coins-area .coins-box .coins-head .icon { width: 50px; height: 60px; margin-right: 16px; } .coins-area .coins-box .coins-head .text { font-family: "PingFangSC-Regular", "PingFang SC", sans-serif; font-weight: 400; color: #7f7f7f; font-size: 14px; } .coins-area .coins-box .coins-head .text .sum { font-family: "PingFangSC-Semibold", "PingFang SC Semibold", "PingFang SC", sans-serif; font-weight: 650; font-size: 18px; color: #000000; margin: 0 5px; } .coins-area .coins-box .coins-input { width: 333px; height: 36px; background-color: #ffffff; border: 1px solid #d7d7d7; border-radius: 8px; overflow: hidden; margin-bottom: 31px; } .coins-area .coins-box .coins-input .input { height: 100%; border: none; outline: none; font-size: 14px; padding: 0 10px; } .coins-area .coins-box .coins-input .btn { width: 84px; height: 100%; line-height: 36px; text-align: center; background-color: #50e3c2; cursor: pointer; } .coins-area .coins-box .coins-info { color: #555555; font-size: 14px; margin-bottom: 43px; } .coins-area .coins-box .coins-info .icon { width: 16px; height: 16px; margin-right: 6px; } .coins-area .coins-box .coins-info .sum { font-family: "PingFangSC-Semibold", "PingFang SC Semibold", "PingFang SC", sans-serif; font-weight: 650; color: #000000; margin: 0 5px; } .coins-area .coins-box .coins-info .strategy { margin-left: 5px; color: #026277; cursor: pointer; text-decoration: none; } .coins-area .coins-box .coins-list-area { max-height: 347px; background-color: #fbfbfb; border-radius: 16px; width: 100%; /* padding: 20px 20px 0; */ flex-direction: column; } .coins-area .coins-box .coins-list-area .coins-total { color: #7f7f7f; font-size: 14px; margin: 20px 20px 0; } .coins-area .coins-box .coins-list-area .coins-total .sum { font-family: "PingFangSC-Semibold", "PingFang SC Semibold", "PingFang SC", sans-serif; font-weight: 650; color: #000000; margin: 0 5px; } .coins-area .coins-box .coins-list-area .list { overflow: auto; margin: 0 20px; } .coins-area .coins-box .coins-list-area .list .item { height: 65px; padding: 0 35px; } .coins-area .coins-box .coins-list-area .list .item:not(:last-child) { border-bottom: 1px solid #f2f2f2; } .coins-area .coins-box .coins-list-area .list .item .serial { font-family: "Arial-BoldMT", "Arial Bold", "Arial", sans-serif; font-weight: 700; font-style: normal; color: #ffb600; margin-right: 114px; } .coins-area .coins-box .coins-list-area .list .item .user { color: #555555; font-size: 13px; cursor: pointer; } .coins-area .coins-box .coins-list-area .list .item .user .avatar { width: 32px; height: 32px; margin-right: 10px; border-radius: 50%; } .coins-area .coins-box .coins-list-area .list .item .amount { color: #000000; font-size: 16px; } .coins-area .coins-box .coins-list-area .list .item .amount .text { font-size: 13px; margin-left: 2px; } .unlock-insertcoins-box { width: 520px; border: 1px solid #e5e5e5; background-color: #fff; border-radius: 11px; flex-direction: column; display: flex; -webkit-box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.21); box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.21); display: none; } .unlock-insertcoins-box .unlock-insertcoins-close { width: 16px; height: 16px; padding: 10px; align-self: self-end; box-sizing: content-box; cursor: pointer; } .unlock-insertcoins-box .unlock-insertcoins-head { font-size: 14px; color: #555555; margin: 10px auto 35px; } .unlock-insertcoins-box .unlock-insertcoins-head .bi-icon { width: 40px; height: 48px; } .unlock-insertcoins-box .unlock-insertcoins-btn { width: 175px; height: 43px; border-radius: 45px; background-color: #50e3c2; cursor: pointer; } .unlock-insertcoins-box .in-all { color: #555555; font-size: 13px; margin-top: 17px; margin-bottom: 54px; } .unlock-insertcoins-box .in-all span { font-weight: 650; } .no-jituobi-pop-box { width: 520px; flex-direction: column; border: 1px solid #e5e5e5; background-color: #fff; border-radius: 11px; display: flex; -webkit-box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.21); box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.21); padding-bottom: 55px; display: none; } .no-jituobi-pop-box .no-jituobi-close { width: 16px; height: 16px; padding: 10px; align-self: flex-end; cursor: pointer; box-sizing: content-box; } .no-jituobi-pop-box .no-jituobi-head { font-size: 16px; color: #333; margin: 23px auto 42px; } .no-jituobi-pop-box .no-jituobi-head .bi-icon { width: 50px; height: 60px; } .no-jituobi-pop-box .strategy-btn { width: 198px; height: 43px; color: #000; font-size: 16px; border-radius: 100px; margin: 0 auto; cursor: pointer; } .no-jituobi-pop-box .strategy-btn .strategy-icon { width: 16px; height: 16px; margin-left: 8px; } .greenBj { background-color: #50e3c2; border-color: #50e3c2 !important; }</style> <div class="coins-area flexcenter"> <div class="coins-box flexcenter"> <img class="fork closeCoinBox" src="https://app.gter.net/image/gter/commonCom/bi/img/fork-icon.png" /> <div class="coins-head flexacenter"> <img class="icon" src="https://app.gter.net/image/gter/commonCom/bi/img/bi.png" /> <div class="text flexacenter"> 该<span class="pagetpyeText"></span>已获得 <div class="sum"></div> 个寄托币 </div> </div> <div class="coins-input flexacenter"> <input class="input flex1" type="number" placeholder="输入投币数" /> <div class="btn coinSubmit">投币</div> </div> <div class="coins-info flexacenter"> <img class="icon" src="https://app.gter.net/image/gter/commonCom/bi/img/bi-black-icon.png" /> 你当前共有 <div class="sum"></div> 寄托币 <a class="strategy" target="_blank" href="">[挣币攻略]</a> </div> <div class="coins-list-area flexflex"></div> </div> <!-- <div class="unlock-insertcoins-box flexcenter" v-if="coinMybalance >= defaultcoinnum"> --> <div class="unlock-insertcoins-box flexcenter"> <img class="unlock-insertcoins-close closeCoinBox" src="https://app.gter.net/image/gter/commonCom/bi/img/fork-icon.png" /> <div class="unlock-insertcoins-head flexacenter"> <img class="bi-icon" src="https://app.gter.net/image/gter/commonCom/bi/img/bi.png" style="margin-right: 11px;" /> 作者设置了阅读限制,解锁所有内容仅需 <span style="font-size: 20px;font-weight: 650;margin: 0 4px;" class="coinNum"></span> 寄托币 </div> <div class="unlock-insertcoins-btn flexcenter">投币解锁</div> <div class="in-all">你共有 <span class="balance"></span> 寄托币</div> </div> <!-- <div class="no-jituobi-pop-box" v-else-if="coinMybalance <= 0 || coinMybalance < defaultcoinnum"> --> <div class="no-jituobi-pop-box"> <img class="no-jituobi-close closeCoinBox" src="https://app.gter.net/image/gter/commonCom/bi/img/fork-icon.png" /> <div class="no-jituobi-head flexacenter"> <img class="bi-icon" src="https://app.gter.net/image/gter/commonCom/bi/img/bi.png" style="margin-right: 12px;"> <span style="margin-top: 10px;">你的寄托币不够,快去发帖挣币吧</span> </div> <a href="https://bbs.gter.net/thread-2543548-1-1.html" target="_blank"> <div class="strategy-btn greenBj flexcenter"> 攒币指南 <img class="strategy-icon" src="https://app.gter.net/image/gter/commonCom/bi/img/u1045.svg" /> </div> </a> </div></div>`;
|
||
|
||
// 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 = `<div class="coins-total flexacenter">共<div class="sum">${coinNubmer}</div>人参与投币:</div>`;
|
||
|
||
const coinList = data.data;
|
||
let list = coinList
|
||
.map((item) => {
|
||
return `<div class="item flexacenter" =>
|
||
<div class="serial">${item.rank}</div>
|
||
<a class="user flex1 flexacenter" href="https://f.gter.net/u/${item.user.uniqid}" target="_blank">
|
||
<img class="avatar" src="${item.user.avatar}" alt="" />
|
||
<div class="username one-line-display flex1">${item.user.nickname || "匿名用户"}</div>
|
||
</a>
|
||
<div class="amount flexacenter">
|
||
${item.coins}
|
||
<div class="text">币</div>
|
||
</div>
|
||
</div>`;
|
||
})
|
||
.join("");
|
||
list = `<div class="list flex1">${list}</div>`;
|
||
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;
|