From 003b5992a51c0922e5cb020e4bc13cbdf3313e20 Mon Sep 17 00:00:00 2001 From: "DESKTOP-RQ919RC\\Pc" <1300399510@qq.com> Date: Fri, 5 Dec 2025 19:07:33 +0800 Subject: [PATCH] =?UTF-8?q?refactor(components):=20=E4=BD=BF=E7=94=A8defin?= =?UTF-8?q?eAsyncComponent=E4=BC=98=E5=8C=96=E5=BC=82=E6=AD=A5=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix(public.js): 添加getScriptParameter函数并处理请求参数 style(index.html): 移除多余空行和注释 perf(bi.js): 移除冗余ajax方法并优化请求参数处理 docs(sign-in.txt): 调整样式和响应式布局 --- component/bi/bi.js | 71 +- component/head-top/head-top.js | 1 + component/item-bottom/item-bottom.js | 232 +- component/item-forum/item-forum.js | 10 +- component/item-head/item-head.js | 5 +- component/item-mj/item-mj.js | 10 +- component/item-offer/item-offer.js | 6 +- component/item-summary/item-summary.js | 6 +- component/item-tenement/item-tenement.js | 6 +- component/item-vote/item-vote.js | 6 +- component/latest-list/latest-list.js | 5 - component/sign-in/sign-in.js | 63 +- component/sign-in/sign-in.txt | 461 +++- css/public.css | 118 -- css/public.less | 122 -- details.html | 9 +- index.html | 3 - js/details.js | 2455 +++++++++++----------- js/public.js | 15 + 19 files changed, 1899 insertions(+), 1705 deletions(-) diff --git a/component/bi/bi.js b/component/bi/bi.js index a6e5584..bd5f3b5 100644 --- a/component/bi/bi.js +++ b/component/bi/bi.js @@ -194,8 +194,18 @@ class BiCard extends HTMLElement { 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; @@ -218,6 +228,9 @@ class BiCard extends HTMLElement { 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; @@ -234,64 +247,6 @@ class BiCard extends HTMLElement { 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. 注册组件(确保只注册一次) diff --git a/component/head-top/head-top.js b/component/head-top/head-top.js index 2b8e757..aa4217a 100644 --- a/component/head-top/head-top.js +++ b/component/head-top/head-top.js @@ -19,6 +19,7 @@ export const headTop = defineComponent({ let isPaused = ref(false); // 是否暂停轮播 onMounted(() => { + console.log("getScriptParameter", getScriptParameter("v")); getHistorySearch(); // 写一个函数 ,判断本地缓存有没有 wConfig 并判断 是否过一天 如果过了一天 则更新 wConfig checkWConfig(); diff --git a/component/item-bottom/item-bottom.js b/component/item-bottom/item-bottom.js index 6a62ece..b24cdec 100644 --- a/component/item-bottom/item-bottom.js +++ b/component/item-bottom/item-bottom.js @@ -1,151 +1,151 @@ // my-component.js // 引入全局 Vue 对象(因在 HTML 中通过 script 引入,Vue 已挂载到 window) -const { defineComponent, ref, inject } = Vue; +const { defineComponent, ref, inject, defineAsyncComponent } = Vue; -const { like } = await import(withVer("../like/like.js")); +const like = defineAsyncComponent(() => import(withVer("../like/like.js")).then(m => m.like)); // 定义组件(直接使用模板) export const itemBottom = defineComponent({ name: "item-bottom", - props: { - itemdata: { - type: Object, - default: () => {}, + props: { + itemdata: { + type: Object, + default: () => {}, + }, }, - }, - setup(props) { - let item = ref({ ...props.itemdata }); + setup(props) { + let item = ref({ ...props.itemdata }); - let isLogin = inject("isLogin"); - let userInfoWin = inject("userInfoWin"); - let realname = inject("realname"); - let goLogin = inject("goLogin"); - let openAttest = inject("openAttest"); + let isLogin = inject("isLogin"); + let userInfoWin = inject("userInfoWin"); + let realname = inject("realname"); + let goLogin = inject("goLogin"); + let openAttest = inject("openAttest"); - let isLikeGif = ref(false); + let isLikeGif = ref(false); - let cancelOperate = inject("cancelOperate"); + let cancelOperate = inject("cancelOperate"); - const likeClick = () => { - if (realname.value == 0 && userInfoWin.value?.uin > 0) { - openAttest(); - return; - } + const likeClick = () => { + if (realname.value == 0 && userInfoWin.value?.uin > 0) { + openAttest(); + return; + } - if (!isLogin.value) { - goLogin(); - return; - } + if (!isLogin.value) { + goLogin(); + return; + } - const token = item.value.token || ""; + const token = item.value.token || ""; - if (["offer", "offer_summary", "interviewexperience"].includes(item.value["type"]) && item.value["is_like"]) { - creationAlertBox("error", "不可取消点赞"); - return; - } + if (["offer", "offer_summary", "interviewexperience"].includes(item.value["type"]) && item.value["is_like"]) { + creationAlertBox("error", "不可取消点赞"); + return; + } - ajax(`/v2/api/forum/postTopicLike`, { - token, - }) - .then((res) => { - if (res.code != 200) { - creationAlertBox("error", res.message); - return; - } - - let data = res.data; - creationAlertBox("success", res.message); - - item.value["is_like"] = data.status; - item.value["likes"] = data.likes; - - if (data.status) { - isLikeGif.value = true; - setTimeout(() => (isLikeGif.value = false), 2000); - } - - if (data.status == 0) cancelOperate("like", token); - - // wx.hideLoading(); + ajax(`/v2/api/forum/postTopicLike`, { + token, }) - .catch(() => {}); - }; + .then((res) => { + if (res.code != 200) { + creationAlertBox("error", res.message); + return; + } - const collectClick = () => { - if (!isLogin.value) { - goLogin(); - return; - } + let data = res.data; + creationAlertBox("success", res.message); - const token = item.value.token || ""; + item.value["is_like"] = data.status; + item.value["likes"] = data.likes; - ajax(`/v2/api/forum/postTopicCollect`, { - token, - }) - .then((res) => { - if (res.code != 200) { - creationAlertBox("error", res.message); - return; - } + if (data.status) { + isLikeGif.value = true; + setTimeout(() => (isLikeGif.value = false), 2000); + } + + if (data.status == 0) cancelOperate("like", token); + + // wx.hideLoading(); + }) + .catch(() => {}); + }; + + const collectClick = () => { + if (!isLogin.value) { + goLogin(); + return; + } + + const token = item.value.token || ""; + + ajax(`/v2/api/forum/postTopicCollect`, { + token, + }) + .then((res) => { + if (res.code != 200) { + creationAlertBox("error", res.message); + return; + } + const data = res.data || {}; + + item.value["is_collect"] = data.status; + item.value["collections"] = data.collections; + creationAlertBox("success", res.message); + // 调用父组件的方法 + if (data.status == 0) cancelOperate("collection", token); + }) + .catch((err) => { + if (err?.code == 401) goLogin(); + }); + }; + + const copyLinkClick = () => { + copyForumUid(`${location.origin}/details/${item.value.uniqid}`); + }; + + let QRcode = ref(""); + const showQRcode = () => { + if (QRcode.value) return; + // return + ajaxGet(`/v2/api/forum/getQrcode?token=${item.value.token}`).then((res) => { + if (res.code != 200) return; const data = res.data || {}; - - item.value["is_collect"] = data.status; - item.value["collections"] = data.collections; - creationAlertBox("success", res.message); - // 调用父组件的方法 - if (data.status == 0) cancelOperate("collection", token); - }) - .catch((err) => { - if (err?.code == 401) goLogin(); + QRcode.value = data.url || ""; }); - }; + }; - const copyLinkClick = () => { - copyForumUid(`${location.origin}/details/${item.value.uniqid}`); - }; + let isright = ref(false); - let QRcode = ref(""); - const showQRcode = () => { - if (QRcode.value) return; - // return - ajaxGet(`/v2/api/forum/getQrcode?token=${item.value.token}`).then((res) => { - if (res.code != 200) return; - const data = res.data || {}; - QRcode.value = data.url || ""; - }); - }; + const share = () => { + const token = item.value.token || ""; + ajax(`/v2/api/forum/postTopicShare`, { token }); - let isright = ref(false); + if (!shareBoxRef.value) return; - const share = () => { - const token = item.value.token || ""; - ajax(`/v2/api/forum/postTopicShare`, { token }); + // 1. 获取元素相对于可视窗口的位置信息 + const rect = shareBoxRef.value.getBoundingClientRect(); - if (!shareBoxRef.value) return + // 2. 获取可视窗口宽度(不包含滚动条,更准确) + const clientWidth = document.documentElement.clientWidth; - // 1. 获取元素相对于可视窗口的位置信息 - const rect = shareBoxRef.value.getBoundingClientRect(); + // 3. 计算距离:可视窗口宽度 - 元素右边缘到左边缘的距离 + const distance = clientWidth - rect.right; + console.log("distance", distance); - // 2. 获取可视窗口宽度(不包含滚动条,更准确) - const clientWidth = document.documentElement.clientWidth; + if (distance < 140) isright.value = true; + else isright.value = false; + }; - // 3. 计算距离:可视窗口宽度 - 元素右边缘到左边缘的距离 - const distance = clientWidth - rect.right; - console.log('distance', distance); + const shareBoxRef = ref(null); - if (distance < 140) isright.value = true; - else isright.value = false; - }; + return { isright, shareBoxRef, share, QRcode, showQRcode, copyLinkClick, collectClick, item, likeClick, isLogin, isLikeGif }; + }, - const shareBoxRef = ref(null); + components: { + like, + }, - return { isright, shareBoxRef, share, QRcode, showQRcode, copyLinkClick, collectClick, item, likeClick, isLogin, isLikeGif }; - }, - - components: { - like, - }, - - template: `
{{ item?.commentreviews?.content || "[图]" }}
{{ item.likes || "赞" }}
{{ item.collections || "收藏" }}
{{ item.comments || "讨论" }}
{{ item.coins || "投币" }}
{{ item.shares || '转发'}}
`, + template: `
{{ item?.commentreviews?.content || "[图]" }}
{{ item.likes || "赞" }}
{{ item.collections || "收藏" }}
{{ item.comments || "讨论" }}
{{ item.coins || "投币" }}
{{ item.shares || '转发'}}
`, }); diff --git a/component/item-forum/item-forum.js b/component/item-forum/item-forum.js index 7cbdad4..1e9324d 100644 --- a/component/item-forum/item-forum.js +++ b/component/item-forum/item-forum.js @@ -1,9 +1,11 @@ // my-component.js // 引入全局 Vue 对象(因在 HTML 中通过 script 引入,Vue 已挂载到 window) -const { defineComponent, ref } = Vue; +const { defineComponent, ref, defineAsyncComponent } = Vue; +const itemBottom = defineAsyncComponent(() => import(withVer("../item-bottom/item-bottom.js")).then((m) => m.itemBottom)); +const itemHead = defineAsyncComponent(() => import(withVer("../item-head/item-head.js")).then((m) => m.itemHead)); -const { itemBottom } = await import(withVer("../item-bottom/item-bottom.js")); -const { itemHead } = await import(withVer("../item-head/item-head.js")); +// const { itemBottom } = await import(withVer("../item-bottom/item-bottom.js")); +// const { itemHead } = await import(withVer("../item-head/item-head.js")); // 定义组件(直接使用模板) export const itemForum = defineComponent({ @@ -27,7 +29,7 @@ export const itemForum = defineComponent({ let item = ref({ ...res }); - item.value['url'] = '/details/' + item.value.uniqid; + item.value["url"] = "/details/" + item.value.uniqid; return { item }; }, diff --git a/component/item-head/item-head.js b/component/item-head/item-head.js index c92a109..9f532af 100644 --- a/component/item-head/item-head.js +++ b/component/item-head/item-head.js @@ -1,8 +1,9 @@ // my-component.js // 引入全局 Vue 对象(因在 HTML 中通过 script 引入,Vue 已挂载到 window) -const { defineComponent, ref, provide, onMounted, inject } = Vue; +const { defineComponent, ref, provide, onMounted, inject, defineAsyncComponent } = Vue; -const { report } = await import(withVer("../report/report.js")); +// const { report } = await import(withVer("../report/report.js")); +const report = defineAsyncComponent(() => import(withVer("../report/report.js")).then((m) => m.report)); // 定义组件(直接使用模板) export const itemHead = defineComponent({ diff --git a/component/item-mj/item-mj.js b/component/item-mj/item-mj.js index 9641d6c..99d0363 100644 --- a/component/item-mj/item-mj.js +++ b/component/item-mj/item-mj.js @@ -1,9 +1,11 @@ // my-component.js // 引入全局 Vue 对象(因在 HTML 中通过 script 引入,Vue 已挂载到 window) -const { defineComponent, ref } = Vue; +const { defineComponent, ref, defineAsyncComponent } = Vue; -const { itemBottom } = await import(withVer("../item-bottom/item-bottom.js")); -const { itemHead } = await import(withVer("../item-head/item-head.js")); +// const { itemBottom } = await import(withVer("../item-bottom/item-bottom.js")); +// const { itemHead } = await import(withVer("../item-head/item-head.js")); +const itemHead = defineAsyncComponent(() => import(withVer("../item-head/item-head.js")).then((m) => m.itemHead)); +const itemBottom = defineAsyncComponent(() => import(withVer("../item-bottom/item-bottom.js")).then((m) => m.itemHead)); // 定义组件(直接使用模板) export const itemMj = defineComponent({ @@ -21,7 +23,7 @@ export const itemMj = defineComponent({ setup(props) { let item = ref({ ...props.itemdata }); - item.value['url'] = '/details/' + item.value.uniqid; + item.value["url"] = "/details/" + item.value.uniqid; return { item }; }, diff --git a/component/item-offer/item-offer.js b/component/item-offer/item-offer.js index eb9c9e2..3004c4a 100644 --- a/component/item-offer/item-offer.js +++ b/component/item-offer/item-offer.js @@ -1,9 +1,9 @@ // my-component.js // 引入全局 Vue 对象(因在 HTML 中通过 script 引入,Vue 已挂载到 window) -const { defineComponent, ref, provide } = Vue; +const { defineComponent, ref, provide, defineAsyncComponent } = Vue; -const { itemBottom } = await import(withVer("../item-bottom/item-bottom.js")); -const { itemHead } = await import(withVer("../item-head/item-head.js")); +const itemBottom = defineAsyncComponent(() => import(withVer("../item-bottom/item-bottom.js")).then((m) => m.itemBottom)); +const itemHead = defineAsyncComponent(() => import(withVer("../item-head/item-head.js")).then((m) => m.itemHead)); // 定义组件(直接使用模板) export const itemOffer = defineComponent({ diff --git a/component/item-summary/item-summary.js b/component/item-summary/item-summary.js index b00601c..3c6e37e 100644 --- a/component/item-summary/item-summary.js +++ b/component/item-summary/item-summary.js @@ -1,9 +1,9 @@ // my-component.js // 引入全局 Vue 对象(因在 HTML 中通过 script 引入,Vue 已挂载到 window) -const { defineComponent, ref } = Vue; +const { defineComponent, ref, defineAsyncComponent } = Vue; -const { itemBottom } = await import(withVer("../item-bottom/item-bottom.js")); -const { itemHead } = await import(withVer("../item-head/item-head.js")); +const itemBottom = defineAsyncComponent(() => import(withVer("../item-bottom/item-bottom.js")).then((m) => m.itemBottom)); +const itemHead = defineAsyncComponent(() => import(withVer("../item-head/item-head.js")).then((m) => m.itemHead)); // 定义组件(直接使用模板) export const itemSummary = defineComponent({ diff --git a/component/item-tenement/item-tenement.js b/component/item-tenement/item-tenement.js index 5bc0fc9..21818d3 100644 --- a/component/item-tenement/item-tenement.js +++ b/component/item-tenement/item-tenement.js @@ -1,9 +1,9 @@ // my-component.js // 引入全局 Vue 对象(因在 HTML 中通过 script 引入,Vue 已挂载到 window) -const { defineComponent, ref } = Vue; +const { defineComponent, ref, defineAsyncComponent } = Vue; -const { itemBottom } = await import(withVer("../item-bottom/item-bottom.js")); -const { itemHead } = await import(withVer("../item-head/item-head.js")); +const itemBottom = defineAsyncComponent(() => import(withVer("../item-bottom/item-bottom.js")).then((m) => m.itemBottom)); +const itemHead = defineAsyncComponent(() => import(withVer("../item-head/item-head.js")).then((m) => m.itemHead)); // 定义组件(直接使用模板) export const itemTenement = defineComponent({ diff --git a/component/item-vote/item-vote.js b/component/item-vote/item-vote.js index d7af95c..91aa4b0 100644 --- a/component/item-vote/item-vote.js +++ b/component/item-vote/item-vote.js @@ -1,9 +1,9 @@ // my-component.js // 引入全局 Vue 对象(因在 HTML 中通过 script 引入,Vue 已挂载到 window) -const { defineComponent, ref } = Vue; +const { defineComponent, ref, defineAsyncComponent } = Vue; -const { itemBottom } = await import(withVer("../item-bottom/item-bottom.js")); -const { itemHead } = await import(withVer("../item-head/item-head.js")); +const itemBottom = defineAsyncComponent(() => import(withVer("../item-bottom/item-bottom.js")).then((m) => m.itemBottom)); +const itemHead = defineAsyncComponent(() => import(withVer("../item-head/item-head.js")).then((m) => m.itemHead)); // 定义组件(直接使用模板) export const itemVote = defineComponent({ diff --git a/component/latest-list/latest-list.js b/component/latest-list/latest-list.js index 56a79d3..44b348a 100644 --- a/component/latest-list/latest-list.js +++ b/component/latest-list/latest-list.js @@ -2,9 +2,6 @@ // 引入全局 Vue 对象(因在 HTML 中通过 script 引入,Vue 已挂载到 window) const { defineComponent, ref, onMounted, nextTick } = Vue; -const { itemBottom } = await import(withVer("../item-bottom/item-bottom.js")); -const { itemHead } = await import(withVer("../item-head/item-head.js")); - // 定义组件(直接使用模板) export const latestList = defineComponent({ name: "latestList", @@ -85,8 +82,6 @@ export const latestList = defineComponent({ }, components: { - itemBottom, - itemHead, }, template: `
最新
精华阅读
最新
精华
`, diff --git a/component/sign-in/sign-in.js b/component/sign-in/sign-in.js index 3bb65d8..92bd744 100644 --- a/component/sign-in/sign-in.js +++ b/component/sign-in/sign-in.js @@ -1,5 +1,5 @@ const signTemplate = document.createElement("template"); -signTemplate.innerHTML = `
0
寄托币
签到规则
随机奖励
+{{ reward }}
额外奖励
+{{ extra_reward }}
`; +signTemplate.innerHTML = `
0
寄托币
签到规则
随机奖励
+{{ reward }}
额外奖励
+{{ extra_reward }}
`; class SignInBox extends HTMLElement { static get observedAttributes() { @@ -30,7 +30,8 @@ class SignInBox extends HTMLElement { this.headerCross = this.shadowRoot.querySelector(".signInBox-mask .signInBox .header-cross"); this.headerCross.addEventListener("click", () => { - // document.body.style.overflow = "auto"; + document.body.style.overflow = ""; + document.body.style.paddingRight = ""; this.shadowRoot.querySelector(".signInBox-mask").style.display = "none"; }); @@ -97,9 +98,11 @@ class SignInBox extends HTMLElement { 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(`
`); + items.push(`
`); } const box = this.shadowRoot.querySelector('[data-list="calendar"]'); box.innerHTML = items.join(""); @@ -121,7 +124,6 @@ class SignInBox extends HTMLElement { mask.style.display = "flex"; const data = res.data || {}; - this.renderCalendar(data.list || {}); this.setField("integral", Number(data.integral) || 0); this.setField("signnum", data.signnum || 0); this.setField("signreward", data.signreward || 0); @@ -131,6 +133,9 @@ class SignInBox extends HTMLElement { 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"]'); @@ -160,7 +165,30 @@ class SignInBox extends HTMLElement { 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 = ""; @@ -172,9 +200,14 @@ class SignInBox extends HTMLElement { else if (this.currentDay == i) type = 3; if (!name) name = this.currentDay == i ? "今" : i; const cls = { 1: "formerly", 2: "already", 3: "today" }[type] || ""; - items.push(`
${name}
`); + + 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(""); + box.innerHTML = items.join(""); } getList() { @@ -287,8 +320,19 @@ class SignInBox extends HTMLElement { 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; @@ -306,6 +350,9 @@ class SignInBox extends HTMLElement { 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); @@ -327,7 +374,9 @@ class SignInBox extends HTMLElement { } open() { - // document.body.style.overflow = "hidden"; + 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(); diff --git a/component/sign-in/sign-in.txt b/component/sign-in/sign-in.txt index 66e74e9..4a93a5d 100644 --- a/component/sign-in/sign-in.txt +++ b/component/sign-in/sign-in.txt @@ -51,14 +51,14 @@ .signInBox-mask a { text-decoration: none; - color: unset; + color: unset; } .signInBox-mask .signInBox { - width: min(1060px, 95vw); + width: 1060px; background-color: #fff; border-radius: 20px; - position: relative; + position: relative; filter: drop-shadow(0 -5px 0 #f7c308); } @@ -97,19 +97,21 @@ .signInBox-mask .signInBox .signInBox-content { align-items: flex-start; - height: auto; - gap: 16px; - flex-wrap: wrap; + height: 595px; } .signInBox-mask .signInBox .signInBox-content .left-box { - flex: 1 1 520px; - max-width: 560px; + width: 50%; + max-width: 538px; padding: 20px 30px 40px; border-right: 1px dotted #d7d7d7; + display: flex; + flex-direction: column; + align-items: center; } .signInBox-mask .signInBox .signInBox-content .left-box .content-header { + width: 100%; font-size: 15px; color: #555555; line-height: 40px; @@ -144,19 +146,19 @@ cursor: pointer; } - .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring { + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring { position: absolute; - left: calc(100% + 31px); - top: -21px; + left: 0; + top: 0; z-index: 1; - width: 522px; - height: 596px; + width: 100%; + height: 100%; background-color: #fdda55; padding: 20px; - border-radius: 0 0 20px 0; + border-radius: 20px; } - .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring::after { + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring::after { content: ""; position: absolute; top: 26px; @@ -171,7 +173,7 @@ border-right-color: #fdda55; } - .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box { + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring .rule-box { background-color: #fff; -moz-box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.07058824); -webkit-box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.07058824); @@ -182,7 +184,7 @@ padding-bottom: 62px; } - .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box .rule-header { + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring .rule-box .rule-header { font-weight: 650; font-size: 24px; color: #ab8705; @@ -194,7 +196,7 @@ margin-bottom: 14px; } - .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box .rule-header::after { + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring .rule-box .rule-header::after { content: ""; display: block; position: absolute; @@ -208,12 +210,12 @@ z-index: -1; } - .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box .rule-list { + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring .rule-box .rule-list { flex-direction: column; margin: 0 23px; } - .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box .rule-list .rule-item .rule-item-icon { + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring .rule-box .rule-list .rule-item .rule-item-icon { width: 52px; height: 52px; background-color: #f6f6f6; @@ -225,23 +227,23 @@ margin-right: 30px; } - .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box .rule-list .rule-item .rule-item-img { + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring .rule-box .rule-list .rule-item .rule-item-img { width: 30px; height: 36px; } - .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box .rule-list .rule-item .rule-item-text { + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring .rule-box .rule-list .rule-item .rule-item-text { color: #333; line-height: 28px; font-size: 16px; padding: 40px 0; } - .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box .rule-list .rule-item:not(:last-of-type) .rule-item-text { + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring .rule-box .rule-list .rule-item:not(:last-of-type) .rule-item-text { border-bottom: 1px dotted #ebebeb; } - .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box .rule-close { + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring .rule-box .rule-close { font-family: "PingFangSC-Regular", "PingFang SC", sans-serif; font-weight: 400; font-style: normal; @@ -256,7 +258,9 @@ .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box { width: 100%; - height: auto; + max-width: 477px; + min-width: min-content; + height: 479px; background-color: #fbfbfb; border-radius: 12px; flex-direction: column; @@ -281,15 +285,17 @@ .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .calendar { margin: 0 0 14px; display: grid; - grid-template-columns: repeat(7, minmax(32px, 1fr)); - column-gap: 12px; - row-gap: 10px; + grid-template-columns: repeat(7, minmax(40px, 1fr)); + justify-items: center; + gap: 10px; + width: 100%; } .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .calendar .calendar-item { - width: 100%; - aspect-ratio: 1 / 1; + width: 40px; + height: 40px; border-radius: 50%; + margin-bottom: 10px; font-size: 17px; color: #aaaaaa; position: relative; @@ -329,7 +335,7 @@ } .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .sign-in-btn { - min-height: 48px; + height: 48px; border-radius: 219px; background-color: #f7c308; color: #fff; @@ -351,29 +357,16 @@ color: #555555; font-size: 15px; flex-direction: column; - flex: 1 1 420px; - min-height: 320px; - height: auto; - overflow: auto; + height: inherit; + position: relative; + overflow: hidden; } - - @media (max-width: 768px) { - .signInBox-mask .signInBox { - width: 95vw; - } - .signInBox-mask .signInBox .signInBox-content { + + .signInBox-mask .signInBox .signInBox-content .sign-in-box .sign-in-scroll-wrapper { + overflow: auto; + flex: 1; + display: flex; flex-direction: column; - gap: 12px; - } - .signInBox-mask .signInBox .signInBox-content .left-box { - max-width: 100%; - border-right: none; - border-bottom: 1px dotted #d7d7d7; - } - .signInBox-mask .signInBox .signInBox-content .sign-in-box { - margin: 0; - border-radius: 12px; - } } .signInBox-mask .signInBox .signInBox-content .sign-in-box .sign-in-header { @@ -657,6 +650,333 @@ display: none; } } + @media screen and (max-width: 1200px) { + .signInBox-mask .signInBox { + width: 95%; + max-width: 1060px; + } + } + + @media screen and (max-width: 768px) { + .signInBox-mask { + align-items: flex-end; /* Align box to bottom */ + } + + .signInBox-mask .signInBox { + width: 100%; /* Full width */ + max-width: none; /* Remove max width */ + height: 90vh; + border-radius: 20px 20px 0 0; /* Rounded top corners only */ + margin: 0; /* No margins */ + display: flex; + flex-direction: column; + /* overflow-y: hidden; */ /* Container fixed, inner scrolls */ + } + + .signInBox-mask .signInBox .signInBox-head { + flex-shrink: 0; + } + + .signInBox-mask .signInBox .signInBox-content { + flex-direction: column; + height: 0; /* Allow growing */ + flex: 1; + align-items: stretch; + } + + .signInBox-mask .signInBox .signInBox-content .left-box { + width: 100%; + height: auto; /* Let it grow */ + flex: 0 0 auto; /* Don't shrink below content */ + border-right: none; + border-bottom: 1px dotted #d7d7d7; + padding: 15px 20px; /* Restore comfortable padding */ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + overflow: visible; /* Default overflow */ + max-width: inherit; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .content-header { + width: 100%; + justify-content: center; + flex-shrink: 0; + margin-bottom: 16px; /* Restore margin */ + transform: none; /* Restore size */ + } + + .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring { + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + width: 90%; + height: auto; + max-height: 80vh; + border-radius: 20px; + background-color: rgba(253, 218, 85, 0.95); + position: fixed; + z-index: 10010; + overflow: hidden; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring::after { + display: none; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box { + padding-bottom: 30px; + height: auto; + max-height: 100%; + display: flex; + flex-direction: column; + overflow: hidden; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box .rule-list { + overflow-y: auto; + flex: 1; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box .rule-header { + font-size: 20px; + padding-top: 25px; + margin-bottom: 10px; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box .rule-header::after { + width: 100px; + height: 18px; + bottom: -2px; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box .rule-list .rule-item .rule-item-icon { + width: 42px; + height: 42px; + margin-right: 15px; + border-radius: 12px; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box .rule-list .rule-item .rule-item-img { + width: 24px; + height: 28px; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .content-header .outer-ring .rule-box .rule-list .rule-item .rule-item-text { + font-size: 14px; + line-height: 24px; + padding: 20px 0; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box { + max-width: 100%; + height: auto; + padding: 0; /* Remove all padding */ + padding: 10px 0; /* Add vertical margin */ + flex-shrink: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .sign-in-text { + margin-bottom: 15px; /* Restore margin */ + font-size: 14px; /* Restore font size */ + line-height: 28px; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .calendar { + display: grid; + grid-template-columns: repeat(7, 1fr); /* Force 7 columns */ + gap: 1.5%; /* Relative gap */ + width: 100%; /* Full width */ + max-width: none; /* Remove limit */ + justify-items: center; /* Center items in their cells */ + margin-bottom: 15px; /* Restore margin */ + } + + .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .calendar .calendar-item { + width: 100%; /* Fill grid cell */ + max-width: 40px; /* Limit max size to original desktop size */ + aspect-ratio: 1; /* Keep square */ + height: auto; /* Auto height based on width */ + line-height: normal; /* Reset line-height */ + display: flex; /* Use flex for centering content */ + align-items: center; + justify-content: center; + font-size: min(14px, 3vw); /* Fluid font size */ + margin: 0; /* Grid handles spacing */ + border-width: 1px; /* Default border width */ + } + + .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .sign-in-btn { + height: 40px; /* Reduced height */ + font-size: 16px; /* Adjusted font size */ + width: auto; /* Restore width */ + min-width: auto; + padding: 0 30px; /* Add padding for auto width */ + } + + /* Adjust border width for 'today' item to be relative if possible, but px is usually safer for borders. + We can use thin/medium or keep 1px as it's already quite thin. + Let's keep 1px but ensure box-sizing handles it well. */ + + .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .calendar .calendar-item.today { + border-width: 1px; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .calendar .calendar-item.already .yellow-tick { + width: 30%; /* Relative tick size */ + height: 30%; + top: -5%; + right: -5%; + } + + /* Remove previous margin overrides as grid handles it */ + .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .calendar .calendar-item:not(:nth-child(7n)) { + margin-right: 0; + } + + /* List Styling Adjustments */ + .signInBox-mask .signInBox .signInBox-content .sign-in-box { + width: 100%; + height: auto; /* Auto height */ + flex: 1; /* Take remaining height */ + margin: 0; + padding: 0 20px; + display: flex; + flex-direction: column; + /* overflow: hidden; */ + } + + .signInBox-mask .signInBox .signInBox-content .sign-in-box .sign-in-header { + padding: 15px 10px; /* Compact header */ + font-size: 13px; + } + + .signInBox-mask .signInBox .signInBox-content .sign-in-box .sign-in-list .sign-in-item { + padding: 8px 0 0 10px; /* Compact item padding */ + } + + .signInBox-mask .signInBox .signInBox-content .sign-in-box .sign-in-list .sign-in-item .sign-in-index { + font-size: 13px; + width: 30px; + } + + .signInBox-mask .signInBox .signInBox-content .sign-in-box .sign-in-list .sign-in-item .sign-in-value { + width: 32px; + height: 32px; + font-size: 14px; + margin-right: 10px; + } + + .signInBox-mask .signInBox .signInBox-content .sign-in-box .sign-in-list .sign-in-item .sign-in-info .sign-in-name { + font-size: 13px; + } + + .signInBox-mask .signInBox .signInBox-content .sign-in-box .sign-in-list .sign-in-item .sign-in-info .sign-in-time { + font-size: 12px; + } + } + + @media screen and (max-width: 480px) { + .signInBox-mask .signInBox .signInBox-head .header-bi { + width: 60px; + height: 72px; + top: -45px; + } + + .signInBox-mask .signInBox .signInBox-head .header-halo { + width: 120px; + height: 115px; + top: -65px; + } + + .signInBox-mask .signInBox .signInBox-content .left-box { + padding: 15px; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .content-header .bi-value { + font-size: 24px; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box { + padding: 20px 5px; /* Very tight padding for mobile */ + } + + .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .calendar { + display: grid; + grid-template-columns: repeat(7, 1fr); + gap: 1.5%; /* Relative gap */ + justify-items: center; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .calendar .calendar-item { + width: 100%; + max-width: none; /* Fully fluid */ + aspect-ratio: 1; + height: auto; + font-size: 4vw; /* Large relative font for mobile */ + margin: 0; + /* display: none; Remove hide default */ + border-width: 1px; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .calendar .calendar-item.already .yellow-tick { + width: 35%; /* Larger relative tick for mobile */ + height: 35%; + } + + /* .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .calendar .calendar-item.show-mobile { + display: flex; + } Remove show logic */ + + /* Override any previous margin settings */ + .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .calendar .calendar-item:not(:nth-child(7n)) { + margin-right: 0; + } + + .signInBox-mask .signInBox .signInBox-content .left-box .calendar-box .sign-in-btn { + height: 36px; + font-size: 15px; + margin-top: 10px; + } + + /* Adjust Success Modal for mobile */ + .signInBox-mask .succeed-mask .succeed-box { + transform: scale(0.9); + } + + /* Further compact list for mobile */ + .signInBox-mask .signInBox .signInBox-content .sign-in-box .sign-in-list .sign-in-item .sign-in-value { + width: 28px; + height: 28px; + font-size: 13px; + } + + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring .rule-box .rule-header { + font-size: 18px; + } + + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring .rule-box .rule-list .rule-item .rule-item-icon { + width: 36px; + height: 36px; + margin-right: 10px; + } + + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring .rule-box .rule-list .rule-item .rule-item-img { + width: 20px; + height: 24px; + } + + .signInBox-mask .signInBox .signInBox-content .sign-in-box .outer-ring .rule-box .rule-list .rule-item .rule-item-text { + font-size: 13px; + padding: 15px 0; + } + }
@@ -672,14 +992,6 @@
0
寄托币
签到规则
-
@@ -694,16 +1006,27 @@
-
@@ -736,4 +1059,4 @@
- + \ No newline at end of file diff --git a/css/public.css b/css/public.css index fe8396f..bbd2496 100644 --- a/css/public.css +++ b/css/public.css @@ -2093,124 +2093,6 @@ td { margin: 0 auto; box-sizing: content-box; } -@media (max-width: 1200px) { - .head-pop .head-more-pop { - width: 80vw; - } - .head-pop .head-more-pop .head-more-userinfo { - margin-left: 20px; - padding-right: 20px; - } - .head-pop .head-more-pop .tab-list { - padding-right: 20px; - margin-left: 20px; - } - .head-pop .head-more-pop .tab-list .tab-item { - height: 50px; - padding-left: 20px; - font-size: 14px; - } - .head-pop .head-more-pop .head-more-post { - margin: 40px 0 90px; - } - .head-pop .head-more-pop .cross-icon { - left: calc(50% + 40px); - } -} -@media (max-width: 768px) { - .head-pop .head-more-pop { - width: 100vw; - height: 100vh; - } - .head-pop .head-more-pop .head-more-userinfo { - margin-left: 16px; - padding-right: 16px; - } - .head-pop .head-more-pop .head-more-userinfo .head-more-right { - width: auto; - height: auto; - } - .head-pop .head-more-pop .tab-list { - padding-right: 16px; - margin-left: 16px; - } - .head-pop .head-more-pop .tab-list .tab-item { - height: 46px; - padding-left: 16px; - font-size: 13px; - } - .head-pop .head-more-pop .head-more-post { - margin: 36px 0 80px; - font-size: 16px; - } - .head-pop .head-more-pop .head-more-post .head-more-post-icon { - width: 18px; - height: 18px; - margin-right: 6px; - } - .head-pop .head-more-pop .cross-icon { - left: 50%; - transform: translateX(-50%); - bottom: 15px; - } -} -@media (max-width: 480px) { - .head-pop .head-more-pop .head-more-userinfo { - margin-left: 12px; - padding-right: 12px; - } - .head-pop .head-more-pop .head-more-userinfo .head-more-left .head-more-userinfo-avatar { - width: 36px; - height: 36px; - margin-right: 8px; - } - .head-pop .head-more-pop .head-more-userinfo .head-more-left .head-more-userinfo-username { - font-size: 12px; - } - .head-pop .head-more-pop .head-more-userinfo .head-more-right .information-box { - width: 14px; - height: 14px; - } - .head-pop .head-more-pop .head-more-userinfo .head-more-right .information-box .information-icon { - width: 14px; - height: 14px; - } - .head-pop .head-more-pop .head-more-userinfo .head-more-right .loginBtn { - width: 72px; - height: 28px; - font-size: 12px; - } - .head-pop .head-more-pop .tab-list { - padding-right: 12px; - margin-left: 12px; - } - .head-pop .head-more-pop .tab-list .tab-item { - height: 42px; - padding-left: 14px; - font-size: 12px; - } - .head-pop .head-more-pop .head-more-post { - margin: 24px 0 60px; - font-size: 14px; - } - .head-pop .head-more-pop .head-more-post .head-more-post-icon { - width: 16px; - height: 16px; - margin-right: 6px; - } - .head-pop .head-more-pop .head-more-post .head-more-post-icon .head-more-post-img { - width: 8px; - height: 8px; - } - .head-pop .head-more-pop .cross-icon { - width: 10px; - height: 10px; - padding: 12px; - bottom: 12px; - left: 50%; - transform: translateX(-50%); - } -} @media screen and (max-width: 1200px) { header.page-header { min-width: auto !important; diff --git a/css/public.less b/css/public.less index ca29050..a941fb6 100644 --- a/css/public.less +++ b/css/public.less @@ -2508,128 +2508,6 @@ td { margin: 0 auto; box-sizing: content-box; } - - // 响应式断点:1200 / 768 / 480 - @media (max-width: 1200px) { - width: 80vw; - .head-more-userinfo { - margin-left: 20px; - padding-right: 20px; - } - .tab-list { - padding-right: 20px; - margin-left: 20px; - .tab-item { - height: 50px; - padding-left: 20px; - font-size: 14px; - } - } - .head-more-post { - margin: 40px 0 90px; - } - .cross-icon { - left: calc(50% + 40px); - } - } - - @media (max-width: 768px) { - width: 100vw; - height: 100vh; - .head-more-userinfo { - margin-left: 16px; - padding-right: 16px; - .head-more-right { - width: auto; - height: auto; - } - } - .tab-list { - padding-right: 16px; - margin-left: 16px; - .tab-item { - height: 46px; - padding-left: 16px; - font-size: 13px; - } - } - .head-more-post { - margin: 36px 0 80px; - font-size: 16px; - .head-more-post-icon { - width: 18px; - height: 18px; - margin-right: 6px; - } - } - .cross-icon { - left: 50%; - transform: translateX(-50%); - bottom: 15px; - } - } - - @media (max-width: 480px) { - .head-more-userinfo { - margin-left: 12px; - padding-right: 12px; - .head-more-left { - .head-more-userinfo-avatar { - width: 36px; - height: 36px; - margin-right: 8px; - } - .head-more-userinfo-username { - font-size: 12px; - } - } - .head-more-right { - .information-box { - width: 14px; - height: 14px; - .information-icon { - width: 14px; - height: 14px; - } - } - .loginBtn { - width: 72px; - height: 28px; - font-size: 12px; - } - } - } - .tab-list { - padding-right: 12px; - margin-left: 12px; - .tab-item { - height: 42px; - padding-left: 14px; - font-size: 12px; - } - } - .head-more-post { - margin: 24px 0 60px; - font-size: 14px; - .head-more-post-icon { - width: 16px; - height: 16px; - margin-right: 6px; - .head-more-post-img { - width: 8px; - height: 8px; - } - } - } - .cross-icon { - width: 10px; - height: 10px; - padding: 12px; - bottom: 12px; - left: 50%; - transform: translateX(-50%); - } - } } } diff --git a/details.html b/details.html index a7495b3..66aa9ff 100644 --- a/details.html +++ b/details.html @@ -29,6 +29,7 @@ - \ No newline at end of file diff --git a/js/details.js b/js/details.js index d57333f..e95d862 100644 --- a/js/details.js +++ b/js/details.js @@ -1,1254 +1,1347 @@ -const { createApp, ref, onMounted, nextTick, onUnmounted, computed, watch, provide } = Vue; +const { createApp, ref, onMounted, nextTick, onUnmounted, computed, watch, provide, defineAsyncComponent } = Vue; +(async function () { + const { itemForum } = await import(withVer("../component/item-forum/item-forum.js")); + const { itemOffer } = await import(withVer("../component/item-offer/item-offer.js")); + const { itemSummary } = await import(withVer("../component/item-summary/item-summary.js")); + const { itemVote } = await import(withVer("../component/item-vote/item-vote.js")); + const { itemMj } = await import(withVer("../component/item-mj/item-mj.js")); + const { itemTenement } = await import(withVer("../component/item-tenement/item-tenement.js")); -const { itemForum } = await import(withVer("../component/item-forum/item-forum.js")); -const { itemOffer } = await import(withVer("../component/item-offer/item-offer.js")); -const { itemSummary } = await import(withVer("../component/item-summary/item-summary.js")); -const { itemVote } = await import(withVer("../component/item-vote/item-vote.js")); -const { itemMj } = await import(withVer("../component/item-mj/item-mj.js")); -const { itemTenement } = await import(withVer("../component/item-tenement/item-tenement.js")); -const { latestList } = await import(withVer("../component/latest-list/latest-list.js")); -const { slideshowBox } = await import(withVer("../component/slideshow-box/slideshow-box.js")); -const { like } = await import(withVer("../component/like/like.js")); -const { report } = await import(withVer("../component/report/report.js")); -const { headTop } = await import(withVer("../component/head-top/head-top.js")); + // const itemForum = defineAsyncComponent(() => import(withVer("../component/item-forum/item-forum.js")).then(m => m.itemForum)); + // const itemOffer = defineAsyncComponent(() => import(withVer("../component/item-offer/item-offer.js")).then(m => m.itemOffer)); + // const itemSummary = defineAsyncComponent(() => import(withVer("../component/item-summary/item-summary.js")).then(m => m.itemSummary)); + // const itemVote = defineAsyncComponent(() => import(withVer("../component/item-vote/item-vote.js")).then(m => m.itemVote)); + // const itemMj = defineAsyncComponent(() => import(withVer("../component/item-mj/item-mj.js")).then(m => m.itemMj)); + // const itemTenement = defineAsyncComponent(() => import(withVer("../component/item-tenement/item-tenement.js")).then(m => m.itemTenement)); + // const latestList = defineAsyncComponent(() => import(withVer("../component/latest-list/latest-list.js")).then(m => m.latestList)); + // const slideshowBox = defineAsyncComponent(() => import(withVer("../component/slideshow-box/slideshow-box.js")).then(m => m.slideshowBox)); + // const like = defineAsyncComponent(() => import(withVer("../component/like/like.js")).then(m => m.like)); + // const report = defineAsyncComponent(() => import(withVer("../component/report/report.js")).then(m => m.report)); + // const headTop = defineAsyncComponent(() => import(withVer("../component/head-top/head-top.js")).then(m => m.headTop)); -const appSectionIndex = createApp({ - setup() { - onMounted(() => { - getUserInfoWin(); - }); + // 判断 ismobile 为 true 是 不加载 latestList 和 slideshowBox + // if (!window.isMobile) { + // const { latestList } = await import(withVer("../component/latest-list/latest-list.js")); + // const { slideshowBox } = await import(withVer("../component/slideshow-box/slideshow-box.js")); + // } + let latestList, slideshowBox; + if (!window.isMobile) { + ({ latestList } = await import(withVer("../component/latest-list/latest-list.js"))); + ({ slideshowBox } = await import(withVer("../component/slideshow-box/slideshow-box.js"))); + } else { + latestList = { name: "latestList", template: "
" }; + slideshowBox = { name: "slideshowBox", template: "
" }; + } + // const { latestList } = await import(withVer("../component/latest-list/latest-list.js")); + // const { slideshowBox } = await import(withVer("../component/slideshow-box/slideshow-box.js")); + const { like } = await import(withVer("../component/like/like.js")); + const { report } = await import(withVer("../component/report/report.js")); + const { headTop } = await import(withVer("../component/head-top/head-top.js")); - let isLogin = ref(false); - let realname = ref(0); // 是否已经实名 - let userInfoWin = ref({}); + const appSectionIndex = createApp({ + setup() { + onMounted(() => { + getUserInfoWin(); - let permissions = ref([]); - - const getUserInfoWin = () => { - const checkUser = () => { - const user = window.userInfoWin; - if (!user) return; - document.removeEventListener("getUser", checkUser); - realname.value = user.realname; - userInfoWin.value = user; - if (user?.uin > 0 || user?.uid > 0) isLogin.value = true; - permissions.value = user?.authority || []; - ismanager.value = permissions.value.indexOf("topic:manager") >= 0; - }; - document.addEventListener("getUser", checkUser); - }; - - const openAttest = () => { - const handleAttestClose = () => { - document.removeEventListener("closeAttest", handleAttestClose); - realname.value = window.userInfoWin?.realname || 0; - }; - // 启动认证流程时添加监听 - document.addEventListener("closeAttest", handleAttestClose); - loadAttest(2); - }; - - // 跳转登录 - const goLogin = () => { - if (typeof window === "undefined") return; - if (window["userInfoWin"] && Object.keys(window["userInfoWin"]).length !== 0) { - if (window["userInfoWin"]["uid"]) isLogin.value = true; - else ajax_login(); - } else ajax_login(); - }; - - provide("isLogin", isLogin); - provide("userInfoWin", userInfoWin); - provide("realname", realname); - provide("openAttest", openAttest); - provide("goLogin", goLogin); - - let authorInfo = ref({}); - let info = ref({}); - let ismyself = ref(false); - - let timestamp = ref(""); - let updatedTime = ref(""); - let token = ""; - let tokentoken = ref(""); - let uniqid = ""; - - let sectionn = ref([]); - let tags = ref([]); - - let uniqidRef = ref(null); - - onMounted(() => { - const preLoader = document.getElementById("pre-loader"); - if (preLoader) preLoader.style.display = "none"; - - uniqid = uniqidRef.value.innerText; - - init(); - - window.addEventListener("scroll", handleScroll); - - checkWConfig(); - }); - - const checkWConfig = () => { - const wConfig = JSON.parse(localStorage.getItem("wConfig")) || {}; - if (wConfig.time) { - const time = new Date(wConfig.time); - const now = new Date(); - if (now - time > 24 * 60 * 60 * 1000) getWConfig(); - else { - const config = wConfig.config || {}; - maxPicture.value = config.topic_image_count; - } - } else { - getWConfig(); - } - }; - - const getWConfig = () => { - ajaxGet("/v2/api/config/website").then((res) => { - if (res.code == 200) { - let data = res["data"] || {}; - const config = data.config || {}; - maxPicture.value = config.topic_image_count; - - data.time = new Date().toISOString(); - localStorage.setItem("wConfig", JSON.stringify(data)); - } - }); - }; - - const init = () => { - ajaxGet(`/v2/api/forum/getTopicDetails?uniqid=${uniqid}`).then((res) => { - if (res.code != 200) { - creationAlertBox("error", res.message || "主题不存在"); - // setTimeout(() => redirectToExternalWebsite(`/`), 3000); - return; - } - const data = res.data; - - let targetInfo = data.info; - - if (!targetInfo.hidden) targetInfo.hidden = 0; - - // 替换换行 - targetInfo.content = targetInfo.content?.replace(/\n/g, "
") || ""; - - if (!targetInfo.content) { - targetInfo.content = targetInfo.title; - targetInfo.title = ""; - } - - authorInfo.value = Array.isArray(data.authorInfo) ? null : data.authorInfo; - ismyself.value = data.ismyself || false; - - const sectionNameSet = new Set(targetInfo.sectionn.map((item) => item.name)); - const newTag = targetInfo.tags.filter((tagName) => !sectionNameSet.has(tagName)); - - sectionn.value = targetInfo.sectionn; - tags.value = newTag; - - timestamp.value = strtimeago(targetInfo.release_at, 4); - updatedTime.value = targetInfo.updated_at ? strtimeago(targetInfo.updated_at, 4) : null; - - if (targetInfo.content) targetInfo.content = restoreHtml(targetInfo.content, targetInfo.attachments); - - info.value = targetInfo; - - token = data.token; - tokentoken.value = data.token; - - if (info.value["anonymous"] == 0) getAuthorInfo(); - - isLogin.value = data.islogin; - - if (isLogin.value) getTopicOperation(); - - getRelatedTopics(); - getComment(); - getQrcode(); - }); - }; - - const restoreHtml = (formattedText, attachments, type) => { - const imageList = attachments?.images || []; - const filesList = attachments?.files || []; - const videosList = attachments?.videos || []; - - let html = formattedText; - - html = html.replaceAll("", "[b]"); - html = html.replaceAll("", "[/b]"); - - // 1. 还原换行符为
标签 - html = html.replace(/\n/g, "
"); - - // 2. 还原块级标签的换行标记 - html = html.replace(/
/g, "
"); - html = html.replace(/<\/div>
/g, "
"); - - // 3. 还原标签标记为span.blue - html = html.replace(/\[tag\]([^[]+)\[\/tag\]/gi, '#$1 '); - - // 4. 还原粗体标记为h2标签 - html = html.replace(/\[b\]([\s\S]*?)\[\/b\]/gi, "

$1

"); - - // 5. 还原【新增图片格式】[img=width,height]aid[/img] 或 [img]aid[/img] - html = html.replace(/\[img(?:=([0-9]+(?:\.[0-9]+)?)(?:,([0-9]+(?:\.[0-9]+)?))?)?\](\d+)\[\/img\]/gi, (match, width, height, aid) => { - const image = imageList.find((img) => String(img.aid) === String(aid)); // 统一字符串比较,避免类型问题 - if (!image) return match; - - // 从列表中移除已匹配的图片(避免重复使用) - const index = imageList.findIndex((img) => String(img.aid) === String(aid)); - if (index > -1) imageList.splice(index, 1); - - // 拼接img标签(带宽高样式,宽高为0则不设置) - let style = ""; - const w = width ? Number(width) : 0; - const h = height ? Number(height) : 0; - if (w > 0 && h > 0) style = `style="width: ${w}px; height: ${h}px;"`; - else if (w > 0) style = `style="width: ${w}px;"`; - - return ``; - }); - - console.log(html); - - // 5. 统一在单次遍历中按出现顺序替换 attach/attachimg - const byAid = new Map(); - imageList.forEach((e) => byAid.set(Number(e.aid), { type: "image", ...e })); - filesList.forEach((e) => byAid.set(Number(e.aid), { type: "file", ...e })); - videosList.forEach((e) => byAid.set(Number(e.aid), { type: "video", ...e })); - - html = html.replace(/\[(attachimg|attach)\](\d+)\[\/\1\]/gi, (match, tag, aidStr) => { - const aid = Number(aidStr); - const item = byAid.get(aid); - if (!item) return match; - byAid.delete(aid); - if (item.type === "image") { - return `
`; - } - if (item.type === "file") { - return `
${item.filename}【点击下载附件】
`; - } - return `
`; - }); - - // 6. 还原填充标签 - html = html.replace(/([^<]+<\/span>)\s+/gi, '$1 '); - - // 7. 清理多余的
标签 - // html = html.replace(/

/g, "
"); - - if (type != "comment") { - byAid.forEach((item, aid) => { - if (item.type === "image") html += `
`; - else if (item.type === "file") html += `
${item.name || item.filename}【点击下载附件】

`; - else html += `
`; + const preLoader = document.getElementById("pre-loader"); + if (preLoader) preLoader.style.display = "none"; + document.querySelectorAll(".vuehide").forEach((item) => { + item.style.display = "none"; }); - } - - return html; - }; - - let QRcode = ref(""); - const getQrcode = () => { - ajaxGet(`/v2/api/forum/getQrcode?token=${token}`).then((res) => { - if (res.code != 200) return; - const data = res.data || []; - QRcode.value = data.url || ""; - }); - }; - - let count = ref(0); - let medal = ref([]); - const getAuthorInfo = () => { - ajaxGet(`/v2/api/forum/getSpaceDetail?uid=${authorInfo.value.uid || 0}&uin=${authorInfo.value.uin || 0}`).then((res) => { - const data = res.data; - const countList = data.count || []; - count.value = countList.reduce((sum, item) => { - const currentCount = Number(item.count) || 0; - return sum + currentCount; - }, 0); - - medal.value = data.medal || []; - authorInfo.value = data.info; - getCreationList(data.token); - }); - }; - - let recentlyList = ref([]); - const getCreationList = (token) => { - ajaxGet(`/v2/api/forum/getSpaceTopicList?token=${token}&simple=1`).then((res) => { - const data = res.data; - recentlyList.value = data.data || []; - recentlyList.value = recentlyList.value.slice(0, 8); - }); - }; - - let islike = ref(0); - let iscollect = ref(0); - - const getTopicOperation = () => { - ajax(`/v2/api/forum/getTopicOperation`, { - token, - actions: ["like", "collection"], - }) - .then((res) => { - const data = res.data; - const like = data.like; - const collection = data.collection; - - islike.value = like.status; - iscollect.value = collection.status; - }) - .catch((err) => { - console.log("err", err); - }); - }; - - let isLikeGif = ref(false); - - const likeClick = () => { - if (realname.value == 0 && userInfoWin.value?.uin > 0) { - openAttest(); - return; - } - - if (!isLogin.value) { - goLogin(); - return; - } - - ajax(`/v2/api/forum/postTopicLike`, { - token, - }).then((res) => { - if (res.code != 200) { - creationAlertBox("error", res.message); - return; - } - const data = res.data; - islike.value = data.status; - info.value.likes = data.likes; - - if (data.status) { - isLikeGif.value = true; - setTimeout(() => (isLikeGif.value = false), 2000); - } - }); - }; - - const collectClick = () => { - ajax(`/v2/api/forum/postTopicCollect`, { - token, - }).then((res) => { - if (res.code != 200) { - creationAlertBox("error", res.message); - return; - } - const data = res.data; - iscollect.value = data.status; - info.value.collections = data.collections; - }); - }; - - let strategy = ref(""); - let mybalance = ref(0); - let defaultcoinnum = 0; - - const getCoinConfig = () => { - if (!isLogin.value) { - goLogin(); - return; - } - - ajaxGet(`/v2/api/forum/getCoinConfig`).then((res) => { - const data = res.data; - strategy.value = data.config.strategy.url || 0; - mybalance.value = data.mybalance || 0; - defaultcoinnum = data.defaultcoinnum || 0; - - // openCoinBox(); - }); - }; - - let coinsState = ref(false); - const openCoinBox = () => { - BiComponent.initComponent(); - - // getCoinConfig(); - // coinsState.value = true; - // document.body.style.overflow = "hidden"; - // if (!coinListRequest) getCoinRankList(); - }; - - const closeCoinBox = () => { - coinsState.value = false; - document.body.style.overflow = "auto"; - }; - - let coinAmount = ref(""); - - const coinSubmit = () => { - const num = Number(coinAmount.value || defaultcoinnum) || 0; - ajax(`/v2/api/forum/postTopicCoin`, { - 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; - - mybalance.value = mybalance.value - num || 0; - coinAmount.value = ""; - info.value.coins = data.coins || 0; - - coinNubmer.value = 0; - coinList.value = []; - getCoinRankList(); - }) - .finally(() => { - // wx.hideLoading(); - }); - }; - - let coinNubmer = ref(0); - let coinList = ref([]); - let coinListRequest = false; // 控制请求次数 - const getCoinRankList = () => { - ajaxGet(`/v2/api/forum/getCoinRankList?token=${token}&limit=1000`).then((res) => { - const data = res.data; - coinNubmer.value = data.nubmer; - coinList.value = data.data; - coinListRequest = true; - }); - }; - - let relatedList = ref([]); - let relatedTime = ref(""); - const getRelatedTopics = () => { - ajaxGet(`/v2/api/forum/getRelatedTopics?uniqid=${uniqid}&limit=8`).then((res) => { - const data = res.data; - relatedTime.value = data.updated_at || ""; - relatedList.value = data.list || []; - }); - }; - - let alreadyCommentIdList = []; - let commentPage = ref(1); - let isgetCommentSate = false; - let commentList = ref([]); - let commentTotalCount = ref(0); - - const getComment = () => { - if (commentPage.value == 0 || isgetCommentSate || !token) return; - isgetCommentSate = true; - ajaxGet(`/v2/api/forum/getCommentList?token=${token}&page=${commentPage.value}&limit=20`) - .then((res) => { - if (res.code != 200) { - creationAlertBox("error", res.message || ""); - return; - } - let data = res.data; - - data.data.forEach((element, index) => { - element.timestamp = strtimeago(element.created_at, 4); - element["picture"] = []; - element["isReplyBoxShow"] = 0; - - if (element["content"]) element["content"] = restoreHtml(element["content"], element.attachments, "comment"); - - if (element.child.length > 0) { - element.child.forEach((el) => { - el["picture"] = []; - el.timestamp = strtimeago(el.created_at, 4); - el["isReplyBoxShow"] = 0; - - if (el["content"]) el["content"] = restoreHtml(el["content"], el.attachments, "comment"); - }); - } - }); - - // if (commentPage.value > 1) { - // for (let index = 0; index < data.data.length; index++) { - // if (alreadyCommentIdList.includes(data.data[index].id)) { - // data.data.splice(index, 1); - // index--; - // } - // } - // } - - commentList.value = commentList.value.concat(data.data); - commentTotalCount.value = data.commentcount; - commentPage.value = data.count > commentList.value.length ? commentPage.value + 1 : 0; - }) - .finally(() => { - isgetCommentSate = false; - }); - }; - - let picture = ref([]); - - const openUserInfo = (index, i) => { - if (i != undefined && (commentList.value[index].child[i].user["uin"] > 0 || commentList.value[index].child[i].user["uid"] > 0)) commentList.value[index].child[i]["avatarState"] = true; - if (i == undefined && index != undefined && (commentList.value[index].user["uin"] > 0 || commentList.value[index].user["uid"] > 0)) commentList.value[index]["avatarState"] = true; - }; - - const closeUserInfo = (index, i) => { - if (i != undefined) commentList.value[index].child[i]["avatarState"] = false; - else if (index != undefined) commentList.value[index]["avatarState"] = false; - }; - - let isReplyBoxShow = ref(true); - - // 打开 回答-评论 的子评论 - const openAnswerCommentsChild = (index, i) => { - if (realname.value == 0 && userInfoWin.value?.uin > 0) { - openAttest(); - return; - } - - if (!isLogin.value) { - goLogin(); - return; - } - - closeAnswerCommentsChild(); - - if (i == null) commentList.value[index]["childState"] = true; - else commentList.value[index].child[i]["childState"] = true; - - isReplyBoxShow.value = false; - }; - - // 关闭 回答-评论 的子评论 - const closeAnswerCommentsChild = () => { - commentList.value.forEach((ele) => { - ele["childState"] = false; - ele["commentInput"] = ""; // 删除原本输入值 - if (ele["child"] && ele["child"].length != 0) { - ele["child"].forEach((el) => { - el["childState"] = false; - el["commentInput"] = ""; - }); - } }); - isReplyBoxShow.value = true; - }; + let isLogin = ref(false); + let realname = ref(0); // 是否已经实名 + let userInfoWin = ref({}); - const handleAnswerText = (e) => { - if (e.target.tagName === "IMG") { - // 检查点击的图片是否被a标签包裹 - const anchorTag = e.target.closest("a"); + let permissions = ref([]); - // 如果被a标签包裹,则不执行图片预览,让链接正常跳转 - if (anchorTag) { - return; - } - - // 否则,执行图片预览 - var src = e.target.getAttribute("src"); - previewImage.initComponent(src); - } - }; - - // 回答-评论 点赞 - const operateAnswerCommentsLike = (token, index, i) => { - if (realname.value == 0 && userInfoWin.value?.uin > 0) { - openAttest(); - return; - } - - if (!isLogin.value) { - goLogin(); - return; - } - - ajax("/v2/api/forum/likeComment", { - token, - }).then((res) => { - if (res.code != 200) { - creationAlertBox("error", res.message || "操作成功"); - return; - } - let data = res.data; - - if (i != undefined) { - commentList.value[index].child[i]["islike"] = data["status"]; - commentList.value[index].child[i]["likenum"] = data["count"]; - } else { - commentList.value[index]["islike"] = data["status"]; - commentList.value[index]["likenum"] = data["count"]; - } - - creationAlertBox("success", res.message || "操作成功"); - - if (data["status"]) { - isLikeGif.value = true; - setTimeout(() => (isLikeGif.value = false), 2000); - } - }); - }; - - let emojiState = ref(false); - let emojiMaskState = ref(false); - let inputTextarea = ref(""); - - // 打开 Emoji - const openEmoji = (event, index, i) => { - if (!isLogin.value) { - goLogin(); - return; - } - - if (i != undefined) commentList.value[index].child[i]["emojiState"] = true; - else if (index != undefined) commentList.value[index]["emojiState"] = true; - else { - closeEmoji(); - closeAnswerCommentsChild(); - emojiState.value = true; - } - - emojiMaskState.value = true; - - let emojiBottomDistance = 0; - const doc = document.documentElement; - try { - const targetEl = (event && (event.currentTarget || event.target)) || null; - const rect = targetEl && targetEl.getBoundingClientRect ? targetEl.getBoundingClientRect() : null; - if (rect) { - const elementBottomDocY = rect.bottom + window.scrollY; - emojiBottomDistance = Math.max(doc.scrollHeight - elementBottomDocY, 0); - } else { - const pageY = event && (event.pageY != null ? event.pageY : event.clientY != null ? event.clientY + window.scrollY : 0); - emojiBottomDistance = Math.max(doc.scrollHeight - pageY, 0); - } - - const itemEl = targetEl && targetEl.closest ? targetEl.closest(".item") : null; - - const boxEl = itemEl ? itemEl.querySelector(".emoji-box") : null; - if (boxEl) { - if (emojiBottomDistance < 500) boxEl.classList.add("top"); - else boxEl.classList.remove("top"); - } - } catch (e) {} - }; - - // 关闭 Emoji - const closeEmoji = (index, i) => { - commentList.value.forEach((ele) => { - ele["emojiState"] = false; - if (ele["child"] && ele["child"].length != 0) { - ele["child"].forEach((el) => { - el["emojiState"] = false; - }); - } - }); - - emojiState.value = false; - emojiMaskState.value = false; - editEmojiState.value = false; - }; - - const TAHomePage = (token) => goHomePage(token); - const sendMessage = (token) => goSendMessage(token); - - let emojiData = ref(["😀", "😁", "😆", "😅", "😂", "😉", "😍", "🥰", "😘", "🤥", "😪", "😵‍💫", "🤓", "🥺", "😋", "😜", "🤪", "😎", "🤩", "🥳", "😔", "🙁", "😭", "😡", "😳", "🤗", "🤔", "🤭", "🤫", "😯", "😵", "🙄", "🥴", "🤢", "🤑", "🤠", "👌", "✌️", "🤟", "🤘", "🤙", "👍", "👎", "✊", "👏", "🤝", "🙏", "💪", "❎️", "✳️", "✴️", "❇️", "#️⃣", "*️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣", "🔟", "🆗", "🈶", "🉐", "🉑", "🌹", "🥀", "🌸", "🌺", "🌷", "🌲", "☘️", "🍀", "🍁", "🌙", "⭐", "🌍", "☀️", "⭐️", "🌟", "☁️", "🌈", "☂️", "❄️", "☃️", "☄️", "🔥", "💧", "🍎", "🍐", "🍊", "🍉", "🍓", "🍑", "🍔", "🍟", "🍕", "🥪", "🍜", "🍡", "🍨", "🍦", "🎂", "🍰", "🍭", "🍿", "🍩", "🧃", "🍹", "🍒", "🥝", "🥒", "🥦", "🥨", "🌭", "🥘", "🍱", "🍢", "🥮", "🍩", "🍪", "🧁", "🍵", "🍶", "🍻", "🥂", "🧋", "🎉", "🎁", "🧧", "🎃", "🎄", "🧨", "✨️", "🎈", "🎊", "🎋", "🎍", "🎀", "🎖️", "🏆️", "🏅", "💌", "📬", "🚗", "🚕", "🚲", "🛵", "🚀", "🚁", "⛵", "🚢", "🔮", "🧸", "🀄️"]); - - const handleEditFile = () => { - editEmojiState.value = false; - judgeLogin(); - }; - - // 选择 Emoji - const selectEmoji = (key, index, i) => { - closeEmoji(); - if (i != undefined) { - if (!commentList.value[index]["child"][i]["commentInput"]) commentList.value[index]["child"][i]["commentInput"] = ""; - commentList.value[index]["child"][i]["commentInput"] += key; - } else if (index != undefined) { - if (!commentList.value[index]["commentInput"]) commentList.value[index]["commentInput"] = ""; - commentList.value[index]["commentInput"] += key; - } else inputTextarea.value += key; - }; - - const judgeLogin = () => { - if (!isLogin.value) goLogin(); - }; - - let maxPicture = ref(10); - - const handleFileUpload = (event, index, i) => { - closeEmoji(); - const file = event.target.files[0]; // 获取选择的文件 - - if (!file) return; - - if (file.size > maxSize) { - creationAlertBox("error", "文件大小不能超过 20MB"); - return; - } - - let target = []; - if (editCommentState.value) target = editPicture.value; - else { - if (i != undefined) target = commentList.value[index].child[i]["picture"]; - else if (index != undefined) target = commentList.value[index]["picture"]; - else target = picture.value; - } - - if (target.length >= maxPicture.value) { - creationAlertBox("error", `最多只能上传 ${maxPicture.value} 张图片`); - return; - } - - const reader = new FileReader(); - reader.onload = (e) => { - const base64 = e.target.result; - uploadImg(file).then((res) => { - const obj = { - aid: res.aid || "", - url: res.url || "", - }; - - target.push(obj); - - if (editCommentState.value) editPicture.value = target; - else { - if (i != undefined) commentList.value[index].child[i]["picture"] = target; - else if (index != undefined) commentList.value[index]["picture"] = target; - else picture.value = target; - } - creationAlertBox("success", "上传成功"); - }); - }; - reader.readAsDataURL(file); - }; - - let uploadConfig = null; - const maxSize = 20 * 1024 * 1024; // 20MB - - // 上传图片 获取图片url - const uploadImg = (file) => { - return new Promise((resolve, reject) => { - const upload = () => { - let config = uploadConfig; - - const formData = new FormData(); - formData.append(config.requestName, file); // 文件数据 - formData.append("name", file.name); // 文件名 - formData.append("type", "image"); // 文件名 - formData.append("data", config.params.data); // 文件名 - - ajax(config.url, formData).then((res) => { - if (res.code != 200) { - creationAlertBox("error", "上传失败"); - return; - } - let data = res.data; - resolve(data); - }); + const getUserInfoWin = () => { + const checkUser = () => { + const user = window.userInfoWin; + if (!user) return; + document.removeEventListener("getUser", checkUser); + realname.value = user.realname; + userInfoWin.value = user; + if (user?.uin > 0 || user?.uid > 0) isLogin.value = true; + permissions.value = user?.authority || []; + ismanager.value = permissions.value.indexOf("topic:manager") >= 0; }; - - if (uploadConfig) upload(); - else getUploadConfig().then(() => upload()); - }); - }; - - const getUploadConfig = () => { - return new Promise((resolve, reject) => { - ajaxGet("/v2/api/config/upload?type=comment").then((res) => { - let data = res.data; - uploadConfig = data; - resolve(); - }); - }); - }; - - // 删除上传的图片 - const closeFileUpload = (aid, index, i) => { - let target = []; - - if (i != undefined) target = [...commentList.value[index].child[i]["picture"]]; - else if (index != undefined) target = [...commentList.value[index]["picture"]]; - else target = [...picture.value]; - - let sub = target.findIndex((item) => item.aid == aid); - if (sub != -1) target.splice(sub, 1); - if (i != undefined) commentList.value[index].child[i]["picture"] = target; - else if (index != undefined) commentList.value[index]["picture"] = target; - else picture.value = target; - }; - - const closePictureUpload = (index) => picture.value.splice(index, 1); - - // 提交回答-评论 - const submitAnswerComments = (index, i) => { - if (realname.value == 0 && userInfoWin.value?.uin > 0) { - openAttest(); - return; - } - - if (!isLogin.value) { - goLogin(); - return; - } - - let content = ""; - let parentid = null; - // let token = this.token; - let image = []; - - if (i != null) { - content = commentList.value[index]["child"][i]["commentInput"]; - parentid = commentList.value[index]["child"][i]["id"]; - image = [...commentList.value[index]["child"][i]["picture"]]; - } else if (index != null) { - content = commentList.value[index]["commentInput"]; - parentid = commentList.value[index]["id"]; - image = [...commentList.value[index]["picture"]]; - } else { - content = inputTextarea.value; - image = [...picture.value]; - } - - // this.detailLoading = true; - - const attachments = { - images: image, + document.addEventListener("getUser", checkUser); }; - ajax("/v2/api/forum/postComment", { - content, - token, - attachments, - replyid: parentid, - }) - .then((res) => { - if (res.code != 200) { - creationAlertBox("error", res.message || "操作成功"); - return; - } - let data = res.data; - - const timestamp = strtimeago(new Date()); - - if (i != null) { - let targetData = { - id: data["commentid"], - content, - isauthor: 1, - islike: 0, - likenum: 0, - reply: { - nickname: commentList.value[index]["child"][i]["nickname"], - }, - ...data, - attachments, - picture: [], - timestamp, - user: { ...userInfoWin.value }, - }; - - commentList.value[index]["child"].push(targetData); - commentList.value[index]["childnum"]++; - } else if (index != null) { - let targetData = { - id: data["commentid"], - content, - isauthor: 1, - islike: 0, - likenum: 0, - reply: [], - ...data, - attachments, - picture: [], - timestamp, - user: { ...userInfoWin.value }, - }; - commentList.value[index]["child"].unshift(targetData); - commentList.value[index]["childnum"]++; - } else { - let targetData = { - id: data["commentid"], - content, - isauthor: 1, - islike: 0, - likenum: 0, - ...data, - child: [], - attachments, - picture: [], - timestamp, - user: { ...userInfoWin.value }, - }; - commentList.value.unshift(targetData); - inputTextarea.value = ""; - picture.value = []; - } - - commentTotalCount.value = data.count || 0; - - // if (!inputTextarea.value) { - // const textarea = this.$refs["input-textarea"] - // textarea.style.height = "80px" - // } - - closeAnswerCommentsChild(); - creationAlertBox("success", res.message || "操作成功"); - }) - .finally(() => { - // this.detailLoading = false; - }); - }; - - let editCommentState = ref(false); - let editToken = ref(""); - let editPicture = ref([]); - let editInput = ref(""); - let editEmojiState = ref(false); - - const openEdit = (token, index, i) => { - const list = JSON.parse(JSON.stringify(commentList.value)); - let target = {}; - if (i != null) target = list[index]["child"][i]; - else target = list[index]; - - editToken.value = target.token || ""; - editInput.value = target.content || ""; - editPicture.value = target.attachments?.images || []; - - editCommentState.value = true; - }; - - const closeEdit = () => { - editPicture.value = {}; - editToken.value = ""; - editInput.value = ""; - editCommentState.value = false; - }; - - // 打开 Emoji - const openEditEmoji = (index, i) => { - if (!isLogin.value) { - goLogin(); - return; - } - editEmojiState.value = true; - }; - - const closeEditEmoji = () => { - editEmojiState.value = false; - }; - - const selectEditEmoji = (key) => { - closeEmoji(); - editInput.value += key; - }; - - const postEditComment = () => { - if (!isLogin.value) { - goLogin(); - return; - } - - const image = editPicture.value; - const attachments = { - images: image, + const openAttest = () => { + const handleAttestClose = () => { + document.removeEventListener("closeAttest", handleAttestClose); + realname.value = window.userInfoWin?.realname || 0; + }; + // 启动认证流程时添加监听 + document.addEventListener("closeAttest", handleAttestClose); + loadAttest(2); }; - ajax("/v2/api/forum/postCommentEdit", { - content: editInput.value, - token: editToken.value, - attachments, - }).then((res) => { - if (res.code != 200) { - creationAlertBox("error", res.message || "操作失败"); - return; - } - commentList.value.forEach((element) => { - if (element.token == editToken.value) { - element["content"] = editInput.value; - element["attachments"] = attachments; - } - element.child && - element.child.forEach((ele) => { - if (ele.token == editToken.value) { - ele["content"] = editInput.value; - ele["attachments"] = attachments; - } - }); - }); + // 跳转登录 + const goLogin = () => { + if (typeof window === "undefined") return; + if (window["userInfoWin"] && Object.keys(window["userInfoWin"]).length !== 0) { + if (window["userInfoWin"]["uid"]) isLogin.value = true; + else ajax_login(); + } else ajax_login(); + }; - editPicture.value = []; - editToken.value = ""; - editCommentState.value = false; - editEmojiState.value = false; - creationAlertBox("success", res.message || "操作成功"); + provide("isLogin", isLogin); + provide("userInfoWin", userInfoWin); + provide("realname", realname); + provide("openAttest", openAttest); + provide("goLogin", goLogin); + + let authorInfo = ref({}); + let info = ref({}); + let ismyself = ref(false); + + let timestamp = ref(""); + let updatedTime = ref(""); + let token = ""; + let tokentoken = ref(""); + let uniqid = ""; + + let sectionn = ref([]); + let tags = ref([]); + + let uniqidRef = ref(null); + + onMounted(() => { + uniqid = uniqidRef.value.innerText; + + init(); + + window.addEventListener("scroll", handleScroll); + + checkWConfig(); }); - }; - const closeEditFileUpload = (aid) => { - let target = [...editPicture.value]; - let sub = target.findIndex((item) => item.aid == aid); - if (sub != -1) target.splice(sub, 1); - editPicture.value = target; - }; - - const handleInputPaste = (event, index, ii) => { - const items = event.clipboardData.items; // 获取粘贴的内容 - - for (let i = 0; i < items.length; i++) { - const item = items[i]; - if (item.type.startsWith("image/")) { - event.preventDefault(); - const file = item.getAsFile(); // 获取文件 - - if (file.size > maxSize) { - creationAlertBox("error", "文件大小不能超过 20MB"); - return; - } - - let target = []; - if (editCommentState.value) target = editPicture.value; + const checkWConfig = () => { + const wConfig = JSON.parse(localStorage.getItem("wConfig")) || {}; + if (wConfig.time) { + const time = new Date(wConfig.time); + const now = new Date(); + if (now - time > 24 * 60 * 60 * 1000) getWConfig(); else { - if (ii != undefined) target = commentList.value[index].child[ii]["picture"]; - else if (index != undefined) target = commentList.value[index]["picture"]; - else target = picture.value; + const config = wConfig.config || {}; + maxPicture.value = config.topic_image_count; } + } else { + getWConfig(); + } + }; - if (target.length >= maxPicture.value) { - creationAlertBox("error", `最多只能上传 ${maxPicture.value} 张图片`); + const getWConfig = () => { + ajaxGet("/v2/api/config/website").then((res) => { + if (res.code == 200) { + let data = res["data"] || {}; + const config = data.config || {}; + maxPicture.value = config.topic_image_count; + + data.time = new Date().toISOString(); + localStorage.setItem("wConfig", JSON.stringify(data)); + } + }); + }; + + const init = () => { + ajaxGet(`/v2/api/forum/getTopicDetails?uniqid=${uniqid}`).then((res) => { + if (res.code != 200) { + creationAlertBox("error", res.message || "主题不存在"); + // setTimeout(() => redirectToExternalWebsite(`/`), 3000); return; } + const data = res.data; - const reader = new FileReader(); - reader.onload = (e) => { - const base64 = e.target.result; + let targetInfo = data.info; - uploadImg(file).then((res) => { - const obj = { - aid: res.aid || "", - url: res.url || "", - }; + if (!targetInfo.hidden) targetInfo.hidden = 0; - target.push(obj); + // 替换换行 + targetInfo.content = targetInfo.content?.replace(/\n/g, "
") || ""; - if (editCommentState.value) editPicture.value = target; - else { - if (ii != undefined) commentList.value[index].child[ii]["picture"] = target; - else if (index != undefined) commentList.value[index]["picture"] = target; - else picture.value = target; - } - creationAlertBox("success", "上传成功"); - }); - }; - reader.readAsDataURL(file); - } - } - }; + if (!targetInfo.content) { + targetInfo.content = targetInfo.title; + targetInfo.title = ""; + } - const alsoCommentsData = (index, i) => { - if (!isLogin.value) { - goLogin(); - return; - } + authorInfo.value = Array.isArray(data.authorInfo) ? null : data.authorInfo; + ismyself.value = data.ismyself || false; - const parentid = commentList.value[index]["id"]; + const sectionNameSet = new Set(targetInfo.sectionn.map((item) => item.name)); + const newTag = targetInfo.tags.filter((tagName) => !sectionNameSet.has(tagName)); - ajax("/v2/api/forum/childrenList", { - token, - parentid, - limit: 2000, - page: 1, - childlimit: 3, - }).then((res) => { - if (res.code != 200) { - creationAlertBox("error", res.message || "操作成功"); - return; - } - let data = res.data; + sectionn.value = targetInfo.sectionn; + tags.value = newTag; - data.data.forEach((element, index) => { - element.timestamp = strtimeago(element.created_at, 4); - element["isReplyBoxShow"] = 0; - element["picture"] = []; - if (element["content"]) element["content"] = restoreHtml(element["content"], element.attachments, "comment"); + timestamp.value = strtimeago(targetInfo.release_at, 4); + updatedTime.value = targetInfo.updated_at ? strtimeago(targetInfo.updated_at, 4) : null; + + if (targetInfo.content) targetInfo.content = restoreHtml(targetInfo.content, targetInfo.attachments); + + info.value = targetInfo; + + token = data.token; + tokentoken.value = data.token; + + if (info.value["anonymous"] == 0) getAuthorInfo(); + + isLogin.value = data.islogin; + + if (isLogin.value) getTopicOperation(); + + getRelatedTopics(); + getComment(); + getQrcode(); + }); + }; + + const restoreHtml = (formattedText, attachments, type) => { + let imageList = attachments?.images || []; + if (imageList && typeof imageList === "object" && !Array.isArray(imageList)) imageList = Object.values(imageList); + + let filesList = attachments?.files || []; + if (filesList && typeof filesList === "object" && !Array.isArray(filesList)) filesList = Object.values(filesList); + + let videosList = attachments?.videos || []; + if (videosList && typeof videosList === "object" && !Array.isArray(videosList)) videosList = Object.values(videosList); + + // const filesList = attachments?.files || []; + // const videosList = attachments?.videos || []; + + let html = formattedText; + + html = html.replaceAll("", "[b]"); + html = html.replaceAll("", "[/b]"); + + // 1. 还原换行符为
标签 + html = html.replace(/\n/g, "
"); + + // 2. 还原块级标签的换行标记 + html = html.replace(/
/g, "
"); + html = html.replace(/<\/div>
/g, "
"); + + // 3. 还原标签标记为span.blue + html = html.replace(/\[tag\]([^[]+)\[\/tag\]/gi, '#$1 '); + + // 4. 还原粗体标记为h2标签 + html = html.replace(/\[b\]([\s\S]*?)\[\/b\]/gi, "

$1

"); + + // 5. 还原【新增图片格式】[img=width,height]aid[/img] 或 [img]aid[/img] + html = html.replace(/\[img(?:=([0-9]+(?:\.[0-9]+)?)(?:,([0-9]+(?:\.[0-9]+)?))?)?\](\d+)\[\/img\]/gi, (match, width, height, aid) => { + const image = imageList.find((img) => String(img.aid) === String(aid)); // 统一字符串比较,避免类型问题 + if (!image) return match; + + // 从列表中移除已匹配的图片(避免重复使用) + const index = imageList.findIndex((img) => String(img.aid) === String(aid)); + if (index > -1) imageList.splice(index, 1); + + // 拼接img标签(带宽高样式,宽高为0则不设置) + let style = ""; + const w = width ? Number(width) : 0; + const h = height ? Number(height) : 0; + if (w > 0 && h > 0) style = `style="width: ${w}px; height: ${h}px;"`; + else if (w > 0) style = `style="width: ${w}px;"`; + + return ``; }); - let merged = [...commentList.value[index]["child"], ...data.data.filter((item2) => !commentList.value[index]["child"].find((item1) => item1.id == item2.id))]; + console.log(html); - commentList.value[index]["child"] = merged; - }); - }; + // 5. 统一在单次遍历中按出现顺序替换 attach/attachimg + const byAid = new Map(); + imageList.forEach((e) => byAid.set(Number(e.aid), { type: "image", ...e })); + filesList.forEach((e) => byAid.set(Number(e.aid), { type: "file", ...e })); + videosList.forEach((e) => byAid.set(Number(e.aid), { type: "video", ...e })); - // 自动输入框增高 - const autoResize = (e) => { - e.target.style.height = "auto"; // 重置高度 - e.target.style.height = `${e.target.scrollHeight}px`; // 设置为内容高度 - }; + html = html.replace(/\[(attachimg|attach)\](\d+)\[\/\1\]/gi, (match, tag, aidStr) => { + const aid = Number(aidStr); + const item = byAid.get(aid); + if (!item) return match; + byAid.delete(aid); + if (item.type === "image") { + return `
`; + } + if (item.type === "file") { + return `
${item.filename}【点击下载附件】
`; + } + return `
`; + }); - let commemtDelete = {}; - // 点击删除 - const commentDelete = (token, index, i) => { - const post = () => { - ajax("/v2/api/forum/deleteComment", { + // 6. 还原填充标签 + html = html.replace(/([^<]+<\/span>)\s+/gi, '$1 '); + + // 7. 清理多余的
标签 + // html = html.replace(/

/g, "
"); + + if (type != "comment") { + byAid.forEach((item, aid) => { + if (item.type === "image") html += `
`; + else if (item.type === "file") html += `
${item.name || item.filename}【点击下载附件】

`; + else html += `
`; + }); + } + + return html; + }; + + let QRcode = ref(""); + const getQrcode = () => { + ajaxGet(`/v2/api/forum/getQrcode?token=${token}`).then((res) => { + if (res.code != 200) return; + const data = res.data || []; + QRcode.value = data.url || ""; + }); + }; + + let count = ref(0); + let medal = ref([]); + const getAuthorInfo = () => { + ajaxGet(`/v2/api/forum/getSpaceDetail?uid=${authorInfo.value.uid || 0}&uin=${authorInfo.value.uin || 0}`).then((res) => { + const data = res.data; + const countList = data.count || []; + count.value = countList.reduce((sum, item) => { + const currentCount = Number(item.count) || 0; + return sum + currentCount; + }, 0); + + medal.value = data.medal || []; + authorInfo.value = data.info; + getCreationList(data.token); + }); + }; + + let recentlyList = ref([]); + const getCreationList = (token) => { + ajaxGet(`/v2/api/forum/getSpaceTopicList?token=${token}&simple=1`).then((res) => { + const data = res.data; + recentlyList.value = data.data || []; + recentlyList.value = recentlyList.value.slice(0, 8); + }); + }; + + let islike = ref(0); + let iscollect = ref(0); + + const getTopicOperation = () => { + ajax(`/v2/api/forum/getTopicOperation`, { + token, + actions: ["like", "collection"], + }) + .then((res) => { + const data = res.data; + const like = data.like; + const collection = data.collection; + + islike.value = like.status; + iscollect.value = collection.status; + }) + .catch((err) => { + console.log("err", err); + }); + }; + + let isLikeGif = ref(false); + + const likeClick = () => { + if (realname.value == 0 && userInfoWin.value?.uin > 0) { + openAttest(); + return; + } + + if (!isLogin.value) { + goLogin(); + return; + } + + ajax(`/v2/api/forum/postTopicLike`, { token, }).then((res) => { if (res.code != 200) { creationAlertBox("error", res.message); return; } + const data = res.data; + islike.value = data.status; + info.value.likes = data.likes; - if (i >= 0) { - commentList.value[index].child.splice(i, 1); - commentList.value[index].childnum -= 1; - } else { - commentList.value.splice(index, 1); + if (data.status) { + isLikeGif.value = true; + setTimeout(() => (isLikeGif.value = false), 2000); + } + }); + }; + + const collectClick = () => { + ajax(`/v2/api/forum/postTopicCollect`, { + token, + }).then((res) => { + if (res.code != 200) { + creationAlertBox("error", res.message); + return; + } + const data = res.data; + iscollect.value = data.status; + info.value.collections = data.collections; + }); + }; + + let strategy = ref(""); + let mybalance = ref(0); + let defaultcoinnum = 0; + + const getCoinConfig = () => { + if (!isLogin.value) { + goLogin(); + return; + } + + ajaxGet(`/v2/api/forum/getCoinConfig`).then((res) => { + const data = res.data; + strategy.value = data.config.strategy.url || 0; + mybalance.value = data.mybalance || 0; + defaultcoinnum = data.defaultcoinnum || 0; + + // openCoinBox(); + }); + }; + + let coinsState = ref(false); + const openCoinBox = () => { + BiComponent.initComponent(); + + // getCoinConfig(); + // coinsState.value = true; + // document.body.style.overflow = "hidden"; + // if (!coinListRequest) getCoinRankList(); + }; + + const closeCoinBox = () => { + coinsState.value = false; + document.body.style.overflow = "auto"; + }; + + let coinAmount = ref(""); + + const coinSubmit = () => { + const num = Number(coinAmount.value || defaultcoinnum) || 0; + ajax(`/v2/api/forum/postTopicCoin`, { + 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; + + mybalance.value = mybalance.value - num || 0; + coinAmount.value = ""; + info.value.coins = data.coins || 0; + + coinNubmer.value = 0; + coinList.value = []; + getCoinRankList(); + }) + .finally(() => { + // wx.hideLoading(); + }); + }; + + let coinNubmer = ref(0); + let coinList = ref([]); + let coinListRequest = false; // 控制请求次数 + const getCoinRankList = () => { + ajaxGet(`/v2/api/forum/getCoinRankList?token=${token}&limit=1000`).then((res) => { + const data = res.data; + coinNubmer.value = data.nubmer; + coinList.value = data.data; + coinListRequest = true; + }); + }; + + let relatedList = ref([]); + let relatedTime = ref(""); + const getRelatedTopics = () => { + ajaxGet(`/v2/api/forum/getRelatedTopics?uniqid=${uniqid}&limit=8`).then((res) => { + const data = res.data; + relatedTime.value = data.updated_at || ""; + relatedList.value = data.list || []; + }); + }; + + let alreadyCommentIdList = []; + let commentPage = ref(1); + let isgetCommentSate = false; + let commentList = ref([]); + let commentTotalCount = ref(0); + + const getComment = () => { + if (commentPage.value == 0 || isgetCommentSate || !token) return; + isgetCommentSate = true; + ajaxGet(`/v2/api/forum/getCommentList?token=${token}&page=${commentPage.value}&limit=20`) + .then((res) => { + if (res.code != 200) { + creationAlertBox("error", res.message || ""); + return; + } + let data = res.data; + + data.data.forEach((element, index) => { + element.timestamp = strtimeago(element.created_at, 4); + element["picture"] = []; + element["isReplyBoxShow"] = 0; + + if (element["content"]) element["content"] = restoreHtml(element["content"], element.attachments, "comment"); + + if (element.child.length > 0) { + element.child.forEach((el) => { + el["picture"] = []; + el.timestamp = strtimeago(el.created_at, 4); + el["isReplyBoxShow"] = 0; + + if (el["content"]) el["content"] = restoreHtml(el["content"], el.attachments, "comment"); + }); + } + }); + + // if (commentPage.value > 1) { + // for (let index = 0; index < data.data.length; index++) { + // if (alreadyCommentIdList.includes(data.data[index].id)) { + // data.data.splice(index, 1); + // index--; + // } + // } + // } + + commentList.value = commentList.value.concat(data.data); + commentTotalCount.value = data.commentcount; + commentPage.value = data.count > commentList.value.length ? commentPage.value + 1 : 0; + }) + .finally(() => { + isgetCommentSate = false; + }); + }; + + let picture = ref([]); + + const openUserInfo = (index, i) => { + if (i != undefined && (commentList.value[index].child[i].user["uin"] > 0 || commentList.value[index].child[i].user["uid"] > 0)) commentList.value[index].child[i]["avatarState"] = true; + if (i == undefined && index != undefined && (commentList.value[index].user["uin"] > 0 || commentList.value[index].user["uid"] > 0)) commentList.value[index]["avatarState"] = true; + }; + + const closeUserInfo = (index, i) => { + if (i != undefined) commentList.value[index].child[i]["avatarState"] = false; + else if (index != undefined) commentList.value[index]["avatarState"] = false; + }; + + let isReplyBoxShow = ref(true); + + // 打开 回答-评论 的子评论 + const openAnswerCommentsChild = (index, i) => { + if (realname.value == 0 && userInfoWin.value?.uin > 0) { + openAttest(); + return; + } + + if (!isLogin.value) { + goLogin(); + return; + } + + closeAnswerCommentsChild(); + + if (i == null) commentList.value[index]["childState"] = true; + else commentList.value[index].child[i]["childState"] = true; + + isReplyBoxShow.value = false; + }; + + // 关闭 回答-评论 的子评论 + const closeAnswerCommentsChild = () => { + commentList.value.forEach((ele) => { + ele["childState"] = false; + ele["commentInput"] = ""; // 删除原本输入值 + if (ele["child"] && ele["child"].length != 0) { + ele["child"].forEach((el) => { + el["childState"] = false; + el["commentInput"] = ""; + }); + } + }); + + isReplyBoxShow.value = true; + }; + + const handleAnswerText = (e) => { + if (e.target.tagName === "IMG") { + // 检查点击的图片是否被a标签包裹 + const anchorTag = e.target.closest("a"); + + // 如果被a标签包裹,则不执行图片预览,让链接正常跳转 + if (anchorTag) { + return; } - commentTotalCount.value -= 1; + // 否则,执行图片预览 + var src = e.target.getAttribute("src"); + previewImage.initComponent(src); + } + }; + // 回答-评论 点赞 + const operateAnswerCommentsLike = (token, index, i) => { + if (realname.value == 0 && userInfoWin.value?.uin > 0) { + openAttest(); + return; + } + + if (!isLogin.value) { + goLogin(); + return; + } + + ajax("/v2/api/forum/likeComment", { + token, + }).then((res) => { + if (res.code != 200) { + creationAlertBox("error", res.message || "操作成功"); + return; + } + let data = res.data; + + if (i != undefined) { + commentList.value[index].child[i]["islike"] = data["status"]; + commentList.value[index].child[i]["likenum"] = data["count"]; + } else { + commentList.value[index]["islike"] = data["status"]; + commentList.value[index]["likenum"] = data["count"]; + } + + creationAlertBox("success", res.message || "操作成功"); + + if (data["status"]) { + isLikeGif.value = true; + setTimeout(() => (isLikeGif.value = false), 2000); + } + }); + }; + + let emojiState = ref(false); + let emojiMaskState = ref(false); + let inputTextarea = ref(""); + const inputTextareaRef = ref(null); + + // 打开 Emoji + const openEmoji = (event, index, i) => { + if (!isLogin.value) { + goLogin(); + return; + } + + if (i != undefined) commentList.value[index].child[i]["emojiState"] = true; + else if (index != undefined) commentList.value[index]["emojiState"] = true; + else { + closeEmoji(); + closeAnswerCommentsChild(); + emojiState.value = true; + } + + emojiMaskState.value = true; + + let emojiBottomDistance = 0; + const doc = document.documentElement; + try { + const targetEl = (event && (event.currentTarget || event.target)) || null; + const rect = targetEl && targetEl.getBoundingClientRect ? targetEl.getBoundingClientRect() : null; + if (rect) { + const elementBottomDocY = rect.bottom + window.scrollY; + emojiBottomDistance = Math.max(doc.scrollHeight - elementBottomDocY, 0); + } else { + const pageY = event && (event.pageY != null ? event.pageY : event.clientY != null ? event.clientY + window.scrollY : 0); + emojiBottomDistance = Math.max(doc.scrollHeight - pageY, 0); + } + + const itemEl = targetEl && targetEl.closest ? targetEl.closest(".item") : null; + + const boxEl = itemEl ? itemEl.querySelector(".emoji-box") : null; + if (boxEl) { + if (emojiBottomDistance < 500) boxEl.classList.add("top"); + else boxEl.classList.remove("top"); + } + } catch (e) {} + }; + + // 关闭 Emoji + const closeEmoji = (index, i) => { + commentList.value.forEach((ele) => { + ele["emojiState"] = false; + if (ele["child"] && ele["child"].length != 0) { + ele["child"].forEach((el) => { + el["emojiState"] = false; + }); + } + }); + + emojiState.value = false; + emojiMaskState.value = false; + editEmojiState.value = false; + }; + + const TAHomePage = (token) => goHomePage(token); + const sendMessage = (token) => goSendMessage(token); + + let emojiData = ref(["😀", "😁", "😆", "😅", "😂", "😉", "😍", "🥰", "😘", "🤥", "😪", "😵‍💫", "🤓", "🥺", "😋", "😜", "🤪", "😎", "🤩", "🥳", "😔", "🙁", "😭", "😡", "😳", "🤗", "🤔", "🤭", "🤫", "😯", "😵", "🙄", "🥴", "🤢", "🤑", "🤠", "👌", "✌️", "🤟", "🤘", "🤙", "👍", "👎", "✊", "👏", "🤝", "🙏", "💪", "❎️", "✳️", "✴️", "❇️", "#️⃣", "*️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣", "🔟", "🆗", "🈶", "🉐", "🉑", "🌹", "🥀", "🌸", "🌺", "🌷", "🌲", "☘️", "🍀", "🍁", "🌙", "⭐", "🌍", "☀️", "⭐️", "🌟", "☁️", "🌈", "☂️", "❄️", "☃️", "☄️", "🔥", "💧", "🍎", "🍐", "🍊", "🍉", "🍓", "🍑", "🍔", "🍟", "🍕", "🥪", "🍜", "🍡", "🍨", "🍦", "🎂", "🍰", "🍭", "🍿", "🍩", "🧃", "🍹", "🍒", "🥝", "🥒", "🥦", "🥨", "🌭", "🥘", "🍱", "🍢", "🥮", "🍩", "🍪", "🧁", "🍵", "🍶", "🍻", "🥂", "🧋", "🎉", "🎁", "🧧", "🎃", "🎄", "🧨", "✨️", "🎈", "🎊", "🎋", "🎍", "🎀", "🎖️", "🏆️", "🏅", "💌", "📬", "🚗", "🚕", "🚲", "🛵", "🚀", "🚁", "⛵", "🚢", "🔮", "🧸", "🀄️"]); + + const handleEditFile = () => { + editEmojiState.value = false; + judgeLogin(); + }; + + // 选择 Emoji + const selectEmoji = (key, index, i) => { + closeEmoji(); + if (i != undefined) { + if (!commentList.value[index]["child"][i]["commentInput"]) commentList.value[index]["child"][i]["commentInput"] = ""; + + const id = commentList.value[index]["child"][i]?.id; + const textarea = document.querySelector(`.input-textarea-${id}`); + + if (textarea) { + const currentValue = textarea.value; + const startPos = textarea.selectionStart || 0; + const endPos = textarea.selectionEnd || 0; + const newValue = currentValue.substring(0, startPos) + key + currentValue.substring(endPos); + + commentList.value[index]["child"][i]["commentInput"] = newValue; + + nextTick(() => { + textarea.focus(); + textarea.selectionStart = textarea.selectionEnd = startPos + key.length; + }); + } else commentList.value[index]["child"][i]["commentInput"] += key; + } else if (index != undefined) { + if (!commentList.value[index]["commentInput"]) commentList.value[index]["commentInput"] = ""; + + const id = commentList.value[index]?.id; + const textarea = document.querySelector(`.input-textarea-${id}`); + + if (textarea) { + const currentValue = textarea.value; + const startPos = textarea.selectionStart || 0; + const endPos = textarea.selectionEnd || 0; + const newValue = currentValue.substring(0, startPos) + key + currentValue.substring(endPos); + + commentList.value[index]["commentInput"] = newValue; + + nextTick(() => { + textarea.focus(); + textarea.selectionStart = textarea.selectionEnd = startPos + key.length; + }); + } else commentList.value[index]["commentInput"] += key; + } else { + const textarea = inputTextareaRef.value; + if (!textarea) return; + + const currentValue = textarea.value; + const startPos = textarea.selectionStart || 0; + const endPos = textarea.selectionEnd || 0; + + const newValue = currentValue.substring(0, startPos) + key + currentValue.substring(endPos); + + inputTextarea.value = newValue; + + nextTick(() => { + textarea.focus(); + textarea.selectionStart = textarea.selectionEnd = startPos + key.length; + }); + } + }; + + const judgeLogin = () => { + if (!isLogin.value) goLogin(); + }; + + let maxPicture = ref(10); + + const handleFileUpload = (event, index, i) => { + closeEmoji(); + const file = event.target.files[0]; // 获取选择的文件 + + if (!file) return; + + if (file.size > maxSize) { + creationAlertBox("error", "文件大小不能超过 20MB"); + return; + } + + let target = []; + if (editCommentState.value) target = editPicture.value; + else { + if (i != undefined) target = commentList.value[index].child[i]["picture"]; + else if (index != undefined) target = commentList.value[index]["picture"]; + else target = picture.value; + } + + if (target.length >= maxPicture.value) { + creationAlertBox("error", `最多只能上传 ${maxPicture.value} 张图片`); + return; + } + + const reader = new FileReader(); + reader.onload = (e) => { + const base64 = e.target.result; + uploadImg(file).then((res) => { + const obj = { + aid: res.aid || "", + url: res.url || "", + }; + + target.push(obj); + + if (editCommentState.value) editPicture.value = target; + else { + if (i != undefined) commentList.value[index].child[i]["picture"] = target; + else if (index != undefined) commentList.value[index]["picture"] = target; + else picture.value = target; + } + creationAlertBox("success", "上传成功"); + }); + }; + reader.readAsDataURL(file); + }; + + let uploadConfig = null; + const maxSize = 20 * 1024 * 1024; // 20MB + + // 上传图片 获取图片url + const uploadImg = (file) => { + return new Promise((resolve, reject) => { + const upload = () => { + let config = uploadConfig; + + const formData = new FormData(); + formData.append(config.requestName, file); // 文件数据 + formData.append("name", file.name); // 文件名 + formData.append("type", "image"); // 文件名 + formData.append("data", config.params.data); // 文件名 + + ajax(config.url, formData).then((res) => { + if (res.code != 200) { + creationAlertBox("error", "上传失败"); + return; + } + let data = res.data; + resolve(data); + }); + }; + + if (uploadConfig) upload(); + else getUploadConfig().then(() => upload()); + }); + }; + + const getUploadConfig = () => { + return new Promise((resolve, reject) => { + ajaxGet("/v2/api/config/upload?type=comment").then((res) => { + let data = res.data; + uploadConfig = data; + resolve(); + }); + }); + }; + + // 删除上传的图片 + const closeFileUpload = (aid, index, i) => { + let target = []; + + if (i != undefined) target = [...commentList.value[index].child[i]["picture"]]; + else if (index != undefined) target = [...commentList.value[index]["picture"]]; + else target = [...picture.value]; + + let sub = target.findIndex((item) => item.aid == aid); + if (sub != -1) target.splice(sub, 1); + if (i != undefined) commentList.value[index].child[i]["picture"] = target; + else if (index != undefined) commentList.value[index]["picture"] = target; + else picture.value = target; + }; + + const closePictureUpload = (index) => picture.value.splice(index, 1); + + // 提交回答-评论 + const submitAnswerComments = (index, i) => { + if (realname.value == 0 && userInfoWin.value?.uin > 0) { + openAttest(); + return; + } + + if (!isLogin.value) { + goLogin(); + return; + } + + let content = ""; + let parentid = null; + // let token = this.token; + let image = []; + + if (i != null) { + content = commentList.value[index]["child"][i]["commentInput"]; + parentid = commentList.value[index]["child"][i]["id"]; + image = [...commentList.value[index]["child"][i]["picture"]]; + } else if (index != null) { + content = commentList.value[index]["commentInput"]; + parentid = commentList.value[index]["id"]; + image = [...commentList.value[index]["picture"]]; + } else { + content = inputTextarea.value; + image = [...picture.value]; + } + + // this.detailLoading = true; + + const attachments = { + images: image, + }; + + ajax("/v2/api/forum/postComment", { + content, + token, + attachments, + replyid: parentid, + }) + .then((res) => { + if (res.code != 200) { + creationAlertBox("error", res.message || "操作成功"); + return; + } + let data = res.data; + + const timestamp = strtimeago(new Date()); + + if (i != null) { + let targetData = { + id: data["commentid"], + content, + isauthor: 1, + islike: 0, + likenum: 0, + reply: { + nickname: commentList.value[index]["child"][i]["nickname"], + }, + ...data, + attachments, + picture: [], + timestamp, + user: { ...userInfoWin.value }, + }; + + commentList.value[index]["child"].push(targetData); + commentList.value[index]["childnum"]++; + } else if (index != null) { + let targetData = { + id: data["commentid"], + content, + isauthor: 1, + islike: 0, + likenum: 0, + reply: [], + ...data, + attachments, + picture: [], + timestamp, + user: { ...userInfoWin.value }, + }; + commentList.value[index]["child"].unshift(targetData); + commentList.value[index]["childnum"]++; + } else { + let targetData = { + id: data["commentid"], + content, + isauthor: 1, + islike: 0, + likenum: 0, + ...data, + child: [], + attachments, + picture: [], + timestamp, + user: { ...userInfoWin.value }, + }; + commentList.value.unshift(targetData); + inputTextarea.value = ""; + picture.value = []; + } + + commentTotalCount.value = data.count || 0; + + // if (!inputTextarea.value) { + // const textarea = this.$refs["input-textarea"] + // textarea.style.height = "80px" + // } + + closeAnswerCommentsChild(); + creationAlertBox("success", res.message || "操作成功"); + }) + .finally(() => { + // this.detailLoading = false; + }); + }; + + let editCommentState = ref(false); + let editToken = ref(""); + let editPicture = ref([]); + let editInput = ref(""); + let editEmojiState = ref(false); + + const openEdit = (token, index, i) => { + const list = JSON.parse(JSON.stringify(commentList.value)); + let target = {}; + if (i != null) target = list[index]["child"][i]; + else target = list[index]; + + editToken.value = target.token || ""; + editInput.value = target.content || ""; + editPicture.value = target.attachments?.images || []; + + editCommentState.value = true; + + nextTick(() => { + console.log('editInputRef.value',editInputRef.value); + editInputRef.value.style.height = "auto"; // 重置高度 + editInputRef.value.style.height = `${editInputRef.value.scrollHeight}px`; // 设置为内容高度 + }); + }; + + const closeEdit = () => { + editPicture.value = {}; + editToken.value = ""; + editInput.value = ""; + editCommentState.value = false; + }; + + // 打开 Emoji + const openEditEmoji = (index, i) => { + if (!isLogin.value) { + goLogin(); + return; + } + editEmojiState.value = true; + }; + + const closeEditEmoji = () => { + editEmojiState.value = false; + }; + + const selectEditEmoji = (key) => { + closeEmoji(); + editInput.value += key; + }; + + const postEditComment = () => { + if (!isLogin.value) { + goLogin(); + return; + } + + const image = editPicture.value; + const attachments = { + images: image, + }; + ajax("/v2/api/forum/postCommentEdit", { + content: editInput.value, + token: editToken.value, + attachments, + }).then((res) => { + if (res.code != 200) { + creationAlertBox("error", res.message || "操作失败"); + return; + } + + commentList.value.forEach((element) => { + if (element.token == editToken.value) { + element["content"] = editInput.value; + element["attachments"] = attachments; + } + element.child && + element.child.forEach((ele) => { + if (ele.token == editToken.value) { + ele["content"] = editInput.value; + ele["attachments"] = attachments; + } + }); + }); + + editPicture.value = []; + editToken.value = ""; + editCommentState.value = false; + editEmojiState.value = false; creationAlertBox("success", res.message || "操作成功"); }); }; - const isConfirmed = confirm(`确定要删除讨论吗?`); - if (isConfirmed) post(); - }; + const closeEditFileUpload = (aid) => { + let target = [...editPicture.value]; + let sub = target.findIndex((item) => item.aid == aid); + if (sub != -1) target.splice(sub, 1); + editPicture.value = target; + }; - const openDiscuss = () => { - let dom = document.querySelector(".answer-discuss"); - if (!dom) return; - const rect = dom.getBoundingClientRect(); - const scrollPosition = window.pageYOffset + rect.top - 50; - window.scrollTo({ - top: scrollPosition, - behavior: "smooth", - }); - }; + const handleInputPaste = (event, index, ii) => { + const items = event.clipboardData.items; // 获取粘贴的内容 - let show = ref(false); - let ismanager = ref(false); - const cutShow = () => { - show.value = !show.value; // 修改为切换显示状态 - }; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + if (item.type.startsWith("image/")) { + event.preventDefault(); + const file = item.getAsFile(); // 获取文件 - let reportState = ref(false); - let reportToken = ref(""); - provide("reportState", reportState); + if (file.size > maxSize) { + creationAlertBox("error", "文件大小不能超过 20MB"); + return; + } - // 举报 - const report = (token) => { - cutShow(); - reportState.value = true; - reportToken.value = token; - }; + let target = []; + if (editCommentState.value) target = editPicture.value; + else { + if (ii != undefined) target = commentList.value[index].child[ii]["picture"]; + else if (index != undefined) target = commentList.value[index]["picture"]; + else target = picture.value; + } - // 隐藏 - const hide = () => { - const target = info.value; - managerHide(token, target.hidden, "thread").then((value) => { - target.hidden = value; - info.value = target; + if (target.length >= maxPicture.value) { + creationAlertBox("error", `最多只能上传 ${maxPicture.value} 张图片`); + return; + } + + const reader = new FileReader(); + reader.onload = (e) => { + const base64 = e.target.result; + + uploadImg(file).then((res) => { + const obj = { + aid: res.aid || "", + url: res.url || "", + }; + + target.push(obj); + + if (editCommentState.value) editPicture.value = target; + else { + if (ii != undefined) commentList.value[index].child[ii]["picture"] = target; + else if (index != undefined) commentList.value[index]["picture"] = target; + else picture.value = target; + } + creationAlertBox("success", "上传成功"); + }); + }; + reader.readAsDataURL(file); + } + } + }; + + const alsoCommentsData = (index, i) => { + if (!isLogin.value) { + goLogin(); + return; + } + + const parentid = commentList.value[index]["id"]; + + ajax("/v2/api/forum/childrenList", { + token, + parentid, + limit: 2000, + page: 1, + childlimit: 3, + }).then((res) => { + if (res.code != 200) { + creationAlertBox("error", res.message || "操作成功"); + return; + } + let data = res.data; + + data.data.forEach((element, index) => { + element.timestamp = strtimeago(element.created_at, 4); + element["isReplyBoxShow"] = 0; + element["picture"] = []; + if (element["content"]) element["content"] = restoreHtml(element["content"], element.attachments, "comment"); + }); + + let merged = [...commentList.value[index]["child"], ...data.data.filter((item2) => !commentList.value[index]["child"].find((item1) => item1.id == item2.id))]; + + commentList.value[index]["child"] = merged; + }); + }; + + // 自动输入框增高 + const autoResize = (e) => { + e.target.style.height = "auto"; // 重置高度 + e.target.style.height = `${e.target.scrollHeight}px`; // 设置为内容高度 + }; + + let commemtDelete = {}; + // 点击删除 + const commentDelete = (token, index, i) => { + const post = () => { + ajax("/v2/api/forum/deleteComment", { + token, + }).then((res) => { + if (res.code != 200) { + creationAlertBox("error", res.message); + return; + } + + if (i >= 0) { + commentList.value[index].child.splice(i, 1); + commentList.value[index].childnum -= 1; + } else { + commentList.value.splice(index, 1); + } + + commentTotalCount.value -= 1; + + creationAlertBox("success", res.message || "操作成功"); + }); + }; + + const isConfirmed = confirm(`确定要删除讨论吗?`); + if (isConfirmed) post(); + }; + + const openDiscuss = () => { + let dom = document.querySelector(".answer-discuss"); + if (!dom) return; + const rect = dom.getBoundingClientRect(); + const scrollPosition = window.pageYOffset + rect.top - 50; + window.scrollTo({ + top: scrollPosition, + behavior: "smooth", + }); + }; + + let show = ref(false); + let ismanager = ref(false); + const cutShow = () => { + show.value = !show.value; // 修改为切换显示状态 + }; + + let reportState = ref(false); + let reportToken = ref(""); + provide("reportState", reportState); + + // 举报 + const report = (token) => { cutShow(); - }); - }; + reportState.value = true; + reportToken.value = token; + }; - // 推荐 - const recommend = () => { - const target = info.value; - managerRecommend(token, target.recommend).then((value) => { - target.recommend = value; - info.value = target; - cutShow(); - }); - }; + // 隐藏 + const hide = () => { + const target = info.value; + managerHide(token, target.hidden, "thread").then((value) => { + target.hidden = value; + info.value = target; + cutShow(); + }); + }; - // 精华 - const essence = () => { - const target = info.value; - managerEssence(token, target.best).then((value) => { - target.best = value; - info.value = target; - cutShow(); - }); - }; + // 推荐 + const recommend = () => { + const target = info.value; + managerRecommend(token, target.recommend).then((value) => { + target.recommend = value; + info.value = target; + cutShow(); + }); + }; - const copyLinkClick = () => { - copyForumUid(location.href); - }; + // 精华 + const essence = () => { + const target = info.value; + managerEssence(token, target.best).then((value) => { + target.best = value; + info.value = target; + cutShow(); + }); + }; - const goPersonalHomepage = (token) => { - if (!token) return; - redirectToExternalWebsite(`/u/${token}`); - }; + const copyLinkClick = () => { + copyForumUid(location.href); + }; - let searchInput = ref(""); - let defaultSearchText = ref("屯特"); - const goSearch = () => { - const searchText = searchInput.value || defaultSearchText.value; - redirectToExternalWebsite("/search/" + searchText); - }; + const goPersonalHomepage = (token) => { + if (!token) return; + redirectToExternalWebsite(`/u/${token}`); + }; - const edit = () => { - redirectToExternalWebsite(`/publish?uniqid=${info.value.uniqid}`); - }; + let searchInput = ref(""); + let defaultSearchText = ref("屯特"); + const goSearch = () => { + const searchText = searchInput.value || defaultSearchText.value; + redirectToExternalWebsite("/search/" + searchText); + }; - let pitchInputState = ref(false); + const edit = () => { + redirectToExternalWebsite(`/publish?uniqid=${info.value.uniqid}`); + }; - const sidebarFixed = ref(false); + let pitchInputState = ref(false); - const handleScroll = () => { - matterHeight.value = -(matterRef.value.offsetHeight - window.innerHeight); - sidebarHeight.value = -(sidebarRef.value.offsetHeight - window.innerHeight); - if (matterHeight.value > 0) matterHeight.value = 12; - if (sidebarHeight.value > 0) sidebarHeight.value = 12; + const sidebarFixed = ref(false); - const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; - const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight; - const clientHeight = window.innerHeight; + const handleScroll = () => { + matterHeight.value = -(matterRef.value.offsetHeight - window.innerHeight); + sidebarHeight.value = -(sidebarRef.value.offsetHeight - window.innerHeight); + if (matterHeight.value > 0) matterHeight.value = 12; + if (sidebarHeight.value > 0) sidebarHeight.value = 12; - // 列表下 滑动到底部 获取新数据 - if (scrollTop + clientHeight >= scrollHeight - 200) getComment(); - }; + const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; + const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight; + const clientHeight = window.innerHeight; - const matterRef = ref(null); - const sidebarRef = ref(null); + // 列表下 滑动到底部 获取新数据 + if (scrollTop + clientHeight >= scrollHeight - 200) getComment(); + }; - const deleteItem = () => { - managerDelete(token) - .then(() => redirectToExternalWebsite("/", "_self")) - .finally(() => cutShow()); - }; + const matterRef = ref(null); + const sidebarRef = ref(null); - let sidebarHeight = ref(0); - let matterHeight = ref(0); + const deleteItem = () => { + managerDelete(token) + .then(() => redirectToExternalWebsite("/", "_self")) + .finally(() => cutShow()); + }; - const share = () => { - ajax(`/v2/api/forum/postTopicShare`, { token }); - }; + let sidebarHeight = ref(0); + let matterHeight = ref(0); - return { uniqidRef, share, reportToken, isReplyBoxShow, matterHeight, sidebarHeight, deleteItem, maxPicture, sidebarFixed, matterRef, sidebarRef, pitchInputState, ismyself, edit, searchInput, defaultSearchText, goSearch, goPersonalHomepage, QRcode, alsoCommentsData, copyLinkClick, reportState, tokentoken, essence, recommend, hide, report, cutShow, ismanager, show, openDiscuss, commentDelete, handleInputPaste, autoResize, editCommentState, selectEditEmoji, closeEditEmoji, openEditEmoji, closeEdit, openEdit, closeEditFileUpload, postEditComment, submitAnswerComments, closePictureUpload, closeFileUpload, picture, editToken, editPicture, editInput, editEmojiState, handleFileUpload, inputTextarea, judgeLogin, handleEditFile, selectEmoji, emojiData, emojiMaskState, emojiState, closeEmoji, openEmoji, closeAnswerCommentsChild, openAnswerCommentsChild, handleAnswerText, sendMessage, TAHomePage, operateAnswerCommentsLike, closeUserInfo, openUserInfo, permissions, commentList, commentPage, commentTotalCount, picture, userInfoWin, relatedList, relatedTime, coinNubmer, coinList, coinAmount, coinSubmit, strategy, mybalance, coinsState, openCoinBox, closeCoinBox, isLikeGif, likeClick, collectClick, islike, iscollect, recentlyList, medal, count, sectionn, tags, authorInfo, info, timestamp, updatedTime }; - }, -}); + const share = () => { + ajax(`/v2/api/forum/postTopicShare`, { token }); + }; -appSectionIndex.component("itemForum", itemForum); -appSectionIndex.component("itemOffer", itemOffer); -appSectionIndex.component("itemSummary", itemSummary); -appSectionIndex.component("itemVote", itemVote); -appSectionIndex.component("itemMj", itemMj); -appSectionIndex.component("itemTenement", itemTenement); -appSectionIndex.component("latestList", latestList); -appSectionIndex.component("slideshowBox", slideshowBox); -appSectionIndex.component("like", like); -appSectionIndex.component("report", report); -appSectionIndex.component("headTop", headTop); + return { inputTextareaRef, uniqidRef, share, reportToken, isReplyBoxShow, matterHeight, sidebarHeight, deleteItem, maxPicture, sidebarFixed, matterRef, sidebarRef, pitchInputState, ismyself, edit, searchInput, defaultSearchText, goSearch, goPersonalHomepage, QRcode, alsoCommentsData, copyLinkClick, reportState, tokentoken, essence, recommend, hide, report, cutShow, ismanager, show, openDiscuss, commentDelete, handleInputPaste, autoResize, editCommentState, selectEditEmoji, closeEditEmoji, openEditEmoji, closeEdit, openEdit, closeEditFileUpload, postEditComment, submitAnswerComments, closePictureUpload, closeFileUpload, picture, editToken, editPicture, editInput, editEmojiState, handleFileUpload, inputTextarea, judgeLogin, handleEditFile, selectEmoji, emojiData, emojiMaskState, emojiState, closeEmoji, openEmoji, closeAnswerCommentsChild, openAnswerCommentsChild, handleAnswerText, sendMessage, TAHomePage, operateAnswerCommentsLike, closeUserInfo, openUserInfo, permissions, commentList, commentPage, commentTotalCount, picture, userInfoWin, relatedList, relatedTime, coinNubmer, coinList, coinAmount, coinSubmit, strategy, mybalance, coinsState, openCoinBox, closeCoinBox, isLikeGif, likeClick, collectClick, islike, iscollect, recentlyList, medal, count, sectionn, tags, authorInfo, info, timestamp, updatedTime }; + }, + }); -appSectionIndex.mount("#details"); + appSectionIndex.component("itemForum", itemForum); + appSectionIndex.component("itemOffer", itemOffer); + appSectionIndex.component("itemSummary", itemSummary); + appSectionIndex.component("itemVote", itemVote); + appSectionIndex.component("itemMj", itemMj); + appSectionIndex.component("itemTenement", itemTenement); + appSectionIndex.component("latestList", latestList); + appSectionIndex.component("slideshowBox", slideshowBox); + appSectionIndex.component("like", like); + appSectionIndex.component("report", report); + appSectionIndex.component("headTop", headTop); + + appSectionIndex.mount("#details"); +})(); diff --git a/js/public.js b/js/public.js index 03d2c76..39e8a6c 100644 --- a/js/public.js +++ b/js/public.js @@ -4,12 +4,22 @@ axios.defaults.emulateJSON = true; const withVer = (p) => `${p}?v=${window.__ASSET_VERSION__}`; +const 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; +}; + // 导出ajax函数 const ajax = (url, data) => { axios.defaults.withCredentials = true; axios.defaults.emulateJSON = true; url = url.indexOf("https://") > -1 ? url : forumBaseURL + url; + if (data) data["v"] = getScriptParameter("v") || "v2"; return new Promise(function (resolve, reject) { if (location.hostname == "127.0.0.1") axios.defaults.headers.common["Authorization"] = "n1pstcsmw6m6bcx49z705xhvduqviw29"; @@ -41,6 +51,7 @@ const ajaxdelete = (url, data) => { url = url.indexOf("https://") > -1 ? url : forumBaseURL + url; return new Promise(function (resolve, reject) { + if (data) data["v"] = getScriptParameter("v") || "v2"; axios .delete(url, { emulateJSON: true, @@ -70,6 +81,10 @@ const ajaxGet = (url) => { axios.defaults.emulateJSON = true; url = url.indexOf("https://") > -1 ? url : forumBaseURL + url; + + const paramSymbol = url.includes("?") ? "&" : "?"; + url = `${url}${paramSymbol}v=${getScriptParameter("v") || "v2" }`; + return new Promise(function (resolve, reject) { if (location.hostname == "127.0.0.1") axios.defaults.headers.common["Authorization"] = "n1pstcsmw6m6bcx49z705xhvduqviw29";