移除多个文件中的console.log调试语句 添加search-tag.css和search-tag.less中的set-hint-box样式 新增recommend.js推荐功能模块 优化ajaxGet调用和用户信息处理逻辑
274 lines
14 KiB
JavaScript
274 lines
14 KiB
JavaScript
// 1. 创建组件模板和样式(内置到 JS 中,无需外部 HTML/Template)
|
||
const template = document.createElement("template");
|
||
template.innerHTML = `<div class="head-top flexacenter"> <a href="/" class="flexacenter" target="_blank"> <img class="logo" src="https://oss.gter.net/logo" alt="" /> </a> <div class="flex1"></div> <div class="input-box flexacenter" :class="{'pitch': searchInputState}"> <div class="placeholder" v-if="!searchInputState && !input"> <div class="placeholder-box" :style="{transform: 'translateY(-' + currentIndex * 36 + 'px)', transition: 'transform .3s ease'}"> <div class="item one-line-display" v-for="(item,index) in hotSearchWords" :key="index">大家都在搜:{{ item.keyword }}</div> <div class="item one-line-display" v-for="(item,index) in hotSearchWords.slice(0, 2)" :key="'copy-' + index">大家都在搜:{{ item.keyword }}</div> </div> </div> <input class="input flex1" type="text" @keyup.enter="searchEvent()" v-model="input" @focus="searchInputFocus" @blur="searchInputBlur" maxlength="140" /> <img class="icon" src="/img/search-icon.svg" @click="searchEvent()" /> <div class="search-box-history" v-if="searchHistoryShowState"> <div class="search-box-history-title">历史搜索</div> <div class="search-box-history-list"> <div class="search-box-history-item one-line-display" v-for="(item,index) in historySearchList " :key="index" @click="searchEvent(item)">{{ item }}</div> </div> </div> </div> <div class="post-list flexacenter" v-if="page == 'details'"><a href="/publish" target="_blank" style="margin-right: 10px"> <img class="post-item" src="/img/post-thread.png" /> </a> <a href="https://offer.gter.net/post" target="_blank" style="margin-right: 10px"> <img class="post-item" src="/img/post-offer.png" /> </a> <a href="https://offer.gter.net/post/summary" target="_blank" style="margin-right: 10px"> <img class="post-item" src="/img/post-summary.png" /> </a> <a href="https://interviewexperience.gter.net/publish" target="_blank" style="margin-right: 10px"> <img class="post-item" src="/img/post-mj.png" /> </a> <a href="https://vote.gter.net/publish" target="_blank" style="margin-right: 10px"> <img class="post-item" src="/img/post-vote.png" /> </a> </div> <template v-else> <div class="sign-in flexacenter" :class="{'sign-in-already': state == 1, 'sign-in-no': state == 0}" @click="signIn()" v-cloak> <div class="sign-in-no-box"> <img class="sign-in-bj" src="/img/sign-in-bj.svg" /> <img class="coin-bj" src="/img/coin-bj.svg" /> <img class="coin-icon" src="/img/coin-icon.png" /> <span class="text flex1">签到领寄托币</span> <div class="sign-go flexcenter"> <img class="sign-go-bj" src="/img/sign-go.svg" /> GO </div> <img class="petal1" src="/img/petal1.png" /> <img class="petal2" src="/img/petal2.png" /> <img class="petal3" src="/img/petal3.png" /> </div> <div class="sign-in-already-box"> <img class="sign-icon" src="/img/sign-icon.png" /> <span>已签到,明天再来</span> </div> </div> </template></div> `;
|
||
|
||
// 2. 定义组件类
|
||
class HeadTopWeb extends HTMLElement {
|
||
constructor() {
|
||
super();
|
||
}
|
||
|
||
// 监听的属性列表
|
||
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.headTopWebComponent) {
|
||
window.headTopWebComponent.init(type);
|
||
return true;
|
||
}
|
||
console.warn("head-top-web组件尚未加载或挂载");
|
||
return false;
|
||
}
|
||
|
||
// 生命周期:组件挂载
|
||
connectedCallback() {
|
||
if (this._mounted) return;
|
||
this.innerHTML = "";
|
||
this.appendChild(template.content.cloneNode(true));
|
||
this.coins = this.getAttribute("coins") || this.coins || "";
|
||
this.token = this.getAttribute("token") || this.token || "";
|
||
this.pagetpye = this.getAttribute("pagetpye") || this.pagetpye || "";
|
||
this.displaytips = this.getAttribute("displaytips") || this.displaytips || "";
|
||
this.input = this.querySelector(".input") || this.input;
|
||
window.headTopWebComponent = this;
|
||
this._mounted = true;
|
||
}
|
||
|
||
// 生命周期:组件卸载
|
||
disconnectedCallback() {
|
||
console.log(`用户卡片 ${this.getAttribute("username")} 已卸载`);
|
||
}
|
||
|
||
fetchData(url, data) {
|
||
return new Promise((resolve, reject) => {
|
||
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);
|
||
}
|
||
};
|
||
|
||
xhr.send(JSON.stringify(data));
|
||
});
|
||
}
|
||
|
||
fetchGetData(url) {
|
||
return new Promise((resolve, reject) => {
|
||
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));
|
||
}
|
||
};
|
||
|
||
xhr.send();
|
||
});
|
||
}
|
||
|
||
$ajax(url) {
|
||
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||
return new Promise(function (resolve, reject) {
|
||
axios
|
||
.post(url, data, {
|
||
emulateJSON: true,
|
||
withCredentials: true,
|
||
})
|
||
.then(function (res) {
|
||
var data = typeof res.data == "string" ? JSON.parse(res.data) : res.data;
|
||
|
||
if (data.code == 401) {
|
||
// 需要登录
|
||
showWindow("login", "https://passport.gter.net/login/ajax", "get", -1, {
|
||
cover: true,
|
||
});
|
||
reject();
|
||
}
|
||
resolve(data);
|
||
})
|
||
.catch((err) => {
|
||
if (err.response.status == 401)
|
||
showWindow("login", "https://passport.gter.net/login/ajax", "get", -1, {
|
||
cover: true,
|
||
});
|
||
});
|
||
});
|
||
}
|
||
|
||
$ajaxget(url) {
|
||
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||
return new Promise(function (resolve, reject) {
|
||
axios
|
||
.get(
|
||
url,
|
||
{},
|
||
{
|
||
emulateJSON: true,
|
||
withCredentials: true,
|
||
}
|
||
)
|
||
.then(function (res) {
|
||
var data = typeof res.data == "string" ? JSON.parse(res.data) : res.data;
|
||
if (data.code == 401) {
|
||
// 需要登录
|
||
showWindow("login", "https://passport.gter.net/login/ajax", "get", -1, {
|
||
cover: true,
|
||
});
|
||
reject();
|
||
}
|
||
resolve(data);
|
||
})
|
||
.catch((error) => {
|
||
reject(error);
|
||
});
|
||
});
|
||
}
|
||
}
|
||
|
||
// 3. 注册组件(确保只注册一次) head-top-web
|
||
if (!customElements.get("head-top-web")) customElements.define("head-top-web", HeadTopWeb);
|
||
|
||
// 4. 导出组件类,以便在外部直接调用
|
||
window.HeadTopWebComponent = HeadTopWeb;
|