const signTemplate = document.createElement("template"); signTemplate.innerHTML = `
0
寄托币
签到规则
随机奖励
+{{ reward }}
额外奖励
+{{ extra_reward }}
`; class SignInBox extends HTMLElement { static get observedAttributes() { return ["integral", "signnum", "signreward", "todaycount"]; } constructor() { super(); this.attachShadow({ mode: "open" }); this.shadowRoot.appendChild(signTemplate.content.cloneNode(true)); this.totalDaysInMonth = 0; this.currentDay = 0; this.list = []; this.showPage = 1; this.listEl = this.shadowRoot.querySelector(".signInBox-mask .signInBox-content .sign-in-list"); this.listNoEl = this.shadowRoot.querySelector(".signInBox-mask .signInBox-content .discuss-list-no"); this.moreEl = this.shadowRoot.querySelector(".signInBox-mask .signInBox-content .sign-in-more"); this.finishEl = this.shadowRoot.querySelector(".signInBox-mask .signInBox-content .sign-in-finish"); this.bindUI(); this.computeMonth(); // this.init(); // this.getList(); this.headerCross = this.shadowRoot.querySelector(".signInBox-mask .signInBox .header-cross"); this.headerCross.addEventListener("click", () => { document.body.style.overflow = ""; document.body.style.paddingRight = ""; this.shadowRoot.querySelector(".signInBox-mask").style.display = "none"; }); window.signInComponent = this; } connectedCallback() {} attributeChangedCallback(name, oldVal, newVal) { const el = this.shadowRoot.querySelector(`[data-field="${name}"]`); if (el) el.textContent = newVal || "0"; } renderList(list, type = "push") { let itemAll = ``; list.forEach((item) => { itemAll += `
${item.rank || ""}
`; }); if (type == "push") { this.listEl.innerHTML += itemAll; } else if (type == "unshift") { this.listEl.innerHTML = itemAll + this.listEl.innerHTML; } this.listEl.style.display = "block"; setTimeout(() => { const itemArr = this.listEl.querySelectorAll(".sign-in-item"); if (this.list.length > itemArr.length) { this.moreEl.style.display = "flex"; this.finishEl.style.display = "none"; } else { this.moreEl.style.display = "none"; this.finishEl.style.display = "flex"; } }, 0); } bindUI() { const ruleBtn = this.shadowRoot.querySelector(".bi-rule"); const ruleBox = this.shadowRoot.querySelector(".outer-ring"); ruleBtn.addEventListener("click", () => (ruleBox.hidden = !ruleBox.hidden)); const ruleClose = this.shadowRoot.querySelector(".rule-close"); ruleClose.addEventListener("click", () => (ruleBox.hidden = true)); const signBtn = this.shadowRoot.querySelector('[data-action="sign"]'); if (signBtn) signBtn.addEventListener("click", () => this.postSign()); } pad(n) { return String(n).padStart(2, "0"); } computeMonth() { const firstDayOfMonth = new Date(); firstDayOfMonth.setDate(1); const dayOfWeek = firstDayOfMonth.getDay(); this.dayOfWeek = dayOfWeek; // Store for renderCalendar const items = []; for (let i = 0; i < dayOfWeek; i++) { items.push(`
`); } const box = this.shadowRoot.querySelector('[data-list="calendar"]'); box.innerHTML = items.join(""); const currentDate = new Date(); const currentMonth = currentDate.getMonth() + 1; const currentYear = currentDate.getFullYear(); this.currentDay = currentDate.getDate(); this.totalDaysInMonth = new Date(currentYear, currentMonth, 0).getDate(); } init() { const mask = this.shadowRoot.querySelector(".signInBox-mask"); mask.style.display = "none"; this.fetchGet("https://api.gter.net/v2/api/forum/getSignInfo").then((res) => { if (res.code != 200) return; mask.style.display = "flex"; const data = res.data || {}; this.setField("integral", Number(data.integral) || 0); this.setField("signnum", data.signnum || 0); this.setField("signreward", data.signreward || 0); this.issign = data.issign; if (data.issign == 1) { const signBtn = this.shadowRoot.querySelector('[data-action="sign"]'); signBtn.textContent = "今天已签到,明天记得来哦~"; signBtn.classList.add("already"); } // Determine today logic before rendering calendar this.renderCalendar(data.list || {}); if (data.signnum >= 25) this.shadowRoot.querySelector(".diligent").hidden = false; const tipsBox = this.shadowRoot.querySelector('[data-list="tips"]'); const tips = data.tips || []; tipsBox.innerHTML = tips .map( (t, i) => `
${t}
` ) .join(""); this.isInit = true; this.getList(); }); } setField(name, value) { const el = this.shadowRoot.querySelector(`[data-field="${name}"]`); if (el) el.textContent = value; } renderCalendar(list) { const box = this.shadowRoot.querySelector('[data-list="calendar"]'); // Calculate today's row index const todayIndex = this.dayOfWeek + this.currentDay - 1; const todayRow = Math.floor(todayIndex / 7); // Determine visible rows for mobile const visibleRows = new Set(); if (todayRow > 0) { visibleRows.add(todayRow); visibleRows.add(todayRow - 1); } else { visibleRows.add(0); visibleRows.add(1); } const items = []; // Add placeholders for (let i = 0; i < this.dayOfWeek; i++) { const row = 0; // Placeholders always in row 0 (since dayOfWeek < 7) const showMobile = visibleRows.has(row) ? "show-mobile" : ""; items.push(`
`); } for (let i = 1; i <= this.totalDaysInMonth; i++) { let type = 0; let name = ""; const key = this.pad(i); if (list[key]) { type = 2; name = `+${list[key]}`; } else if (this.currentDay > i) type = 1; else if (this.currentDay == i) type = 3; if (!name) name = this.currentDay == i ? "今" : i; const cls = { 1: "formerly", 2: "already", 3: "today" }[type] || ""; const index = this.dayOfWeek + i - 1; const row = Math.floor(index / 7); const showMobile = visibleRows.has(row) ? "show-mobile" : ""; items.push(`
${name}
`); } box.innerHTML = items.join(""); } getList() { this.fetchGet("https://api.gter.net/v2/api/forum/getSignRankList").then((res) => { if (res.code != 200) return; const data = res.data || {}; this.list = data.list || []; let showList = this.list.slice(0, 10) || []; if (!Array.isArray(data.my)) { showList.unshift(data.my); } if (showList.length > 0) this.renderList(showList); this.setField("todaycount", data.todaycount || 0); if (this.list.length > showList.length) { this.moreEl.style.display = "flex"; this.finishEl.style.display = "none"; this.moreEl.onclick = () => this.moreList(); } else if (this.list.length == 0) { this.listNoEl.style.display = "flex"; this.finishEl.style.display = "none"; } else { this.moreEl.style.display = "none"; this.finishEl.style.display = "flex"; } }); } moreList() { const showList = this.list.slice(this.showPage * 20 - 10, this.showPage * 20 + 10); this.showPage += 1; this.renderList(showList); } postSign() { console.log('document.querySelector(".sign-in")', document.querySelector(".sign-in")); if (this.issign == 1) { creationAlertBox("error", "今天已签到,明天记得来哦~"); return; } const user = window.userInfoWin; if (!user || (user?.uin <= 0 && user?.uid <= 0)) { creationAlertBox("error", "没有绑定寄托账号"); showWindow("login", "https://passport.gter.net/login/ajax", "get", -1, { cover: true }); return; } this.fetchPost("https://api.gter.net/v2/api/forum/sign").then((res) => { if (res.code != 200) { creationAlertBox("error", res.message); return; } const data = res.data || {}; const rewardT = data.extra_reward * 1 + data.reward * 1 || 0; this.setField("integral", (Number(this.shadowRoot.querySelector('[data-field="integral"]').textContent) || 0) + rewardT); this.setField("signnum", (Number(this.shadowRoot.querySelector('[data-field="signnum"]').textContent) || 0) + 1); this.setField("signreward", (Number(this.shadowRoot.querySelector('[data-field="signreward"]').textContent) || 0) + rewardT); const myItem = { avatar: user.avatar || "", uniqid: user.uniqid || "", nickname: user.nickname || "匿名用户", rank: data.rank || 1, reward: rewardT, timestamp: this.currentDateTime() }; this.renderList([myItem], "unshift"); this.cutSucceed(data.reward, data.extra_reward); localStorage.setItem("signInState", this.currentDate()); const todayItem = this.shadowRoot.querySelector(".calendar-item.today"); todayItem.classList.remove("today"); todayItem.classList.add("already"); todayItem.innerHTML = `+${rewardT}`; this.issign = 1; const signBtn = this.shadowRoot.querySelector('[data-action="sign"]'); signBtn.textContent = "今天已签到,明天记得来哦~"; signBtn.classList.add("already"); const sign = document.querySelector(".sign-in"); sign.classList.add("sign-in-already"); sign.classList.remove("sign-in-no"); }); } cutSucceed(reward, extra_reward) { const mask = this.shadowRoot.querySelector(".succeed-mask"); if (!mask) return; mask.style.display = "flex"; if (reward > 0) { const rewardEl = mask.querySelector(".reward"); rewardEl.querySelector(".succeed-award-value").textContent = `+${reward}`; rewardEl.style.display = "flex"; } if (extra_reward > 0) { const extra_rewardEl = mask.querySelector(".extra_reward"); extra_rewardEl.querySelector(".succeed-award-value").textContent = `+${extra_reward}`; extra_rewardEl.style.display = "flex"; } setTimeout(() => (mask.style.display = "none"), 1800); } currentDate() { const now = new Date(); return `${now.getFullYear()}-${this.pad(now.getMonth() + 1)}-${this.pad(now.getDate())}`; } currentDateTime() { const d = new Date(); return `${d.getFullYear()}-${this.pad(d.getMonth() + 1)}-${this.pad(d.getDate())} ${this.pad(d.getHours())}:${this.pad(d.getMinutes())}:${this.pad(d.getSeconds())}`; } 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; } fetchPost(url, data = {}) { return new Promise((resolve) => { if (data) data["v"] = this.getScriptParameter("v") || "v2"; const 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) { resolve(xhr.response); } }; xhr.send(JSON.stringify(data)); }); } fetchGet(url) { return new Promise((resolve) => { 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; try { response = JSON.parse(response); } catch {} 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(); }); } open() { const scrollWidth = window.innerWidth - document.documentElement.clientWidth; document.body.style.overflow = "hidden"; document.body.style.paddingRight = `${scrollWidth}px`; if (this.isInit) this.shadowRoot.querySelector(".signInBox-mask").style.display = "flex"; else { this.init(); } } // 静态方法,用于在外部调用组件初始化 type normal 展示正常的投币和列表 unlock 解锁插入币弹窗 或者 币不足 static initComponent() { if (window.signInComponent) { window.signInComponent.open(); return true; } const el = document.createElement("sign-in-box"); document.body.appendChild(el); window.signInComponent = el; el.open(); return true; } } if (!customElements.get("sign-in-box")) customElements.define("sign-in-box", SignInBox); window.SignInComponent = SignInBox;