refactor: 重构slideshow-box组件,移除帖子标签 fix: 修复item-bottom组件中QR码加载状态显示问题 style: 调整多个页面的CSS样式,包括字体大小和间距 perf: 优化save.js文件同步逻辑,支持更多模板格式 docs: 更新组件文档和注释 chore: 添加bi组件相关文件并配置监听同步 test: 更新测试用例以适应组件变更
208 lines
14 KiB
JavaScript
208 lines
14 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: 2; display: none; } .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; } .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; }</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"> 该帖子已获得 <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>`;
|
||
|
||
// 2. 定义组件类
|
||
class BiCard extends HTMLElement {
|
||
constructor() {
|
||
super();
|
||
|
||
this.coins = 0;
|
||
this.token = "";
|
||
this.pagetpye = "";
|
||
|
||
// 创建 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.querySelector(".coins-area .closeCoinBox");
|
||
|
||
this.coinSubmitEl.addEventListener("click", () => this.coinSubmit());
|
||
this.closeCoinBoxEl.addEventListener("click", () => this.closeCoinBox());
|
||
|
||
this.input = this.shadowRoot.querySelector(".coins-input .input");
|
||
|
||
this.coinListAreaEl = this.shadowRoot.querySelector(".coins-list-area");
|
||
|
||
this.defaultcoinnum = 0;
|
||
// 将实例存储到全局变量中,以便外部调用
|
||
window.biComponent = this;
|
||
}
|
||
|
||
// 监听的属性列表
|
||
static get observedAttributes() {
|
||
return ["coins", "token", "pagetpye"];
|
||
}
|
||
|
||
// 属性变化回调
|
||
attributeChangedCallback(attrName, oldVal, newVal) {
|
||
this[attrName] = newVal; // 同步属性值到变量
|
||
}
|
||
|
||
init() {
|
||
this.getCoinConfig();
|
||
if (!this.coinListAreaEl.querySelector(".list")) this.getCoinRankList();
|
||
}
|
||
|
||
getCoinConfig() {
|
||
this.$ajaxget(`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 = strategy;
|
||
this.mybalanceEl.textContent = mybalance;
|
||
this.coinsEl.textContent = this.coins;
|
||
this.defaultcoinnum = defaultcoinnum;
|
||
|
||
this.coinsAreaEl.style.display = "flex";
|
||
});
|
||
}
|
||
|
||
getCoinRankList() {
|
||
this.$ajaxget(`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://bbs.gter.net/home.php?mod=space&uin=${item.user.uin}" 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;
|
||
this.$ajax(`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;
|
||
|
||
this.mybalanceEl.textContent = Number(this.mybalanceEl.textContent) - num || 0;
|
||
this.input.value = "";
|
||
const coins = data.coins;
|
||
this.coinsEl.textContent = coins || 0;
|
||
|
||
if (this.pagetpye == "forum") document.querySelector(".action-bar-item.coins .text").textContent = coins || 0;
|
||
|
||
this.getCoinRankList();
|
||
});
|
||
}
|
||
|
||
closeCoinBox() {
|
||
this.coinsAreaEl.style.display = "none";
|
||
}
|
||
|
||
// 静态方法,用于在外部调用组件初始化
|
||
static initComponent() {
|
||
if (window.biComponent) {
|
||
window.biComponent.init();
|
||
return true;
|
||
}
|
||
console.warn("bi组件尚未加载或挂载");
|
||
return false;
|
||
}
|
||
|
||
// 生命周期:组件挂载
|
||
connectedCallback() {}
|
||
|
||
// 生命周期:组件卸载
|
||
disconnectedCallback() {
|
||
console.log(`用户卡片 ${this.getAttribute("username")} 已卸载`);
|
||
}
|
||
|
||
$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. 注册组件(确保只注册一次)
|
||
if (!customElements.get("bi-card")) customElements.define("bi-card", BiCard);
|
||
|
||
// 4. 导出组件类,以便在外部直接调用
|
||
window.BiComponent = BiCard;
|