diff --git a/component/preview-image/preview.js b/component/preview-image/preview.js new file mode 100644 index 0000000..60aed55 --- /dev/null +++ b/component/preview-image/preview.js @@ -0,0 +1,99 @@ +class PreviewImage extends HTMLElement { + static get observedAttributes() { return ["src", "alt"]; } + constructor(){ + super(); + this._src = this.getAttribute("src") || ""; + this._alt = this.getAttribute("alt") || ""; + this.attachShadow({ mode: "open" }); + const root = document.createElement("div"); + root.className = "root"; + const img = document.createElement("img"); + root.appendChild(img); + this.shadowRoot.append(style, root); + this._img = img; + this._render(); + this._img.addEventListener("click", (e)=>{ e.stopPropagation(); this.init(this._src); }); + // 保存一个全局实例(与 bi.js 风格一致,便于外部静态调用) + window.previewImageComponent = this; + } + attributeChangedCallback(name, oldVal, newVal){ + if(name === "src") this._src = newVal || ""; + if(name === "alt") this._alt = newVal || ""; + this._render(); + } + _render(){ + if(this._img){ this._img.src = this._src; this._img.alt = this._alt; } + } + init(src){ PreviewImage.open(src || this._src); } + static open(src){ + if(!src) return; + const mask = document.createElement("div"); + const box = document.createElement("div"); + const img = document.createElement("img"); + + mask.style.width = "100%"; + mask.style.height = "100%"; + mask.style.maxWidth = "none"; + mask.style.maxHeight = "none"; + mask.style.border = "none"; + mask.style.position = "fixed"; + mask.style.top = "0"; + mask.style.left = "0"; + mask.style.backgroundColor = "rgba(255, 255, 255, 0.8)"; + mask.style.zIndex = "10002"; + mask.style.display = "flex"; + mask.style.alignItems = "center"; + mask.style.justifyContent = "center"; + + // box.className = "detail-image flexcenter"; + box.style.width = "80vw"; + box.style.height = "80vh"; + box.style.borderRadius = "8px"; + box.style.backgroundColor = "rgba(17, 17, 17, 0.9)"; + box.style.overflow = "hidden"; + box.style.display = "flex"; + box.style.alignItems = "center"; + box.style.justifyContent = "center"; + box.style.position = "relative"; + + // img.className = "detail-img"; + img.style.maxWidth = "100%"; + img.style.maxHeight = "100%"; + img.src = src; + box.appendChild(img); + mask.appendChild(box); + let scale = 1, tx = 0, ty = 0, dragging = false, sx = 0, sy = 0; + const apply = () => { img.style.transform = `translate(${tx}px, ${ty}px) scale(${scale})`; img.style.cursor = dragging ? "grabbing" : "grab"; }; + const onWheel = (ev) => { ev.preventDefault(); const step = 0.1; scale += (ev.deltaY > 0 ? -step : step); if (scale < 0.1) scale = 0.1; if (scale > 5) scale = 5; apply(); }; + const onDown = (ev) => { ev.preventDefault(); dragging = true; sx = ev.clientX; sy = ev.clientY; apply(); }; + const onMove = (ev) => { if (!dragging) return; const dx = ev.clientX - sx, dy = ev.clientY - sy; sx = ev.clientX; sy = ev.clientY; tx += dx; ty += dy; apply(); }; + const onUp = () => { dragging = false; apply(); }; + img.addEventListener("wheel", onWheel, { passive: false }); img.addEventListener("mousedown", onDown); document.addEventListener("mousemove", onMove); document.addEventListener("mouseup", onUp); img.addEventListener("click", (ev) => ev.stopPropagation()); + const onKey = (ev) => { if (ev.key === "Escape") close(); }; + const close = () => { + document.body.style.overflow = "auto"; + img.removeEventListener("wheel", onWheel); + img.removeEventListener("mousedown", onDown); + document.removeEventListener("mousemove", onMove); + document.removeEventListener("mouseup", onUp); + document.removeEventListener("keydown", onKey); + mask.remove(); + }; + mask.addEventListener("click", (ev)=>{ if (ev.target === mask) close(); }); + box.addEventListener("click", (ev)=>ev.stopPropagation()); + const dl = document.createElement("button"); dl.textContent = "下载图片"; Object.assign(dl.style, { position: "absolute", right: "24px", bottom: "24px", zIndex: "10001", padding: "8px 14px", borderRadius: "6px", border: "none", cursor: "pointer", backgroundColor: "#50e3c2", color: "#000" }); + dl.addEventListener("click", (ev) => { ev.stopPropagation(); const name = (src.split("/").pop() || "image").split("?")[0]; fetch(src).then((r) => r.blob()).then((blob) => { const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = name || "image"; document.body.appendChild(a); a.click(); a.remove(); setTimeout(()=>URL.revokeObjectURL(url),0); }).catch(() => { const a = document.createElement("a"); a.href = src; a.target = "_blank"; document.body.appendChild(a); a.click(); a.remove(); }); }); + box.appendChild(dl); + document.body.appendChild(mask); + document.addEventListener("keydown", onKey); + document.body.style.overflow = "hidden"; + apply(); + } +} +if (!customElements.get("preview-image")) customElements.define("preview-image", PreviewImage); +// 3. 暴露统一对象(可使用 previewImage.initComponent(url)) +PreviewImage.initComponent = function(url){ + if (window.previewImageComponent) { window.previewImageComponent.init(url); return true; } + PreviewImage.open(url); return true; +}; +window.previewImage = PreviewImage; diff --git a/css/details.css b/css/details.css index 492bf31..e53f527 100644 --- a/css/details.css +++ b/css/details.css @@ -156,7 +156,7 @@ font-family: "PingFangSC-Regular", "PingFang SC", sans-serif; font-size: 15px; color: #555555; - line-height: 24px; + line-height: 26px; margin-bottom: 66px; } #details .matter .matter-left .html a { @@ -177,6 +177,13 @@ #details .matter .matter-left .html video { margin: 0 auto; } +#details .matter .matter-left .html h2 { + font-family: "PingFangSC-Semibold", "PingFang SC Semibold", "PingFang SC", sans-serif; + font-weight: 650; + color: #000000; + font-size: 18px; + line-height: 30px; +} #details .matter .matter-left .last-time { color: #aaaaaa; font-size: 13px; @@ -1124,6 +1131,7 @@ height: 80vh; border-radius: 8px; background-color: #111; + overflow: hidden; } .detail-image-mask .detail-image .detail-img { max-width: 100%; diff --git a/css/details.less b/css/details.less index 7283cc8..608bfc0 100644 --- a/css/details.less +++ b/css/details.less @@ -180,7 +180,7 @@ font-family: "PingFangSC-Regular", "PingFang SC", sans-serif; font-size: 15px; color: #555555; - line-height: 24px; + line-height: 26px; margin-bottom: 66px; a { @@ -204,6 +204,14 @@ video { margin: 0 auto; } + + h2 { + font-family: "PingFangSC-Semibold", "PingFang SC Semibold", "PingFang SC", sans-serif; + font-weight: 650; + color: #000000; + font-size: 18px; + line-height: 30px; + } } .last-time { @@ -1316,6 +1324,7 @@ height: 80vh; border-radius: 8px; background-color: #111; + overflow: hidden; } .detail-image-mask .detail-image .detail-img { diff --git a/css/signIn.css b/css/signIn.css new file mode 100644 index 0000000..cd950f4 --- /dev/null +++ b/css/signIn.css @@ -0,0 +1,112 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: "PingFangSC-Regular", "PingFang SC", sans-serif; + font-weight: 400; + font-style: normal; + word-break: break-word; +} +a { + text-decoration: none; + color: unset; +} +body { + background-color: #eef2f5; +} +.flexflex { + display: flex; +} +.flexcenter { + display: flex; + justify-content: center; + align-items: center; +} +.flexjcenter { + display: flex; + justify-content: center; +} +.flexacenter { + display: flex; + align-items: center; +} +.flex1 { + flex: 1; +} +.signInBox-mask { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 10005; +} +.signInBox-mask .signInBox { + width: 1060px; + height: 658px; + background-color: #fff; + border-radius: 20px; + position: relative; + filter: drop-shadow(0 -5px 0 #f7c308); +} +.signInBox-mask .signInBox .signInBox-head { + position: relative; + height: 64px; + border-bottom: 1px dotted #d7d7d7; +} +.signInBox-mask .signInBox .signInBox-head .header-bi { + width: 83px; + height: 99px; + position: absolute; + top: -61px; + left: 50%; + transform: translateX(-50%); +} +.signInBox-mask .signInBox .signInBox-head .header-halo { + width: 160px; + height: 154px; + position: absolute; + top: -89px; + left: 50%; + transform: translateX(-50%); +} +.signInBox-mask .signInBox .signInBox-head .header-cross { + width: 18px; + height: 18px; + position: absolute; + top: 10px; + right: 10px; + cursor: pointer; +} +.signInBox-mask .signInBox .signInBox-content .left-box { + width: 538px; + padding: 20px 30px; + border-right: 1px dotted #d7d7d7; +} +.signInBox-mask .signInBox .signInBox-content .left-box .content-header { + font-size: 15px; + color: #555555; + line-height: 40px; +} +.signInBox-mask .signInBox .signInBox-content .left-box .content-header .bi-img { + width: 25px; + height: 30px; + margin-right: 7px; +} +.signInBox-mask .signInBox .signInBox-content .left-box .content-header .bi-value { + font-family: Arial-Black, "Arial Black", sans-serif; + font-weight: 900; + font-style: normal; + font-size: 28px; + color: #000000; + margin-right: 7px; +} +.signInBox-mask .signInBox .signInBox-content .left-box .content-header .bi-text { + font-size: 15px; + color: #555555; + line-height: normal; + margin-top: 8px; +} +.signInBox-mask .signInBox .signInBox-content .left-box .content-header .bi-rule { + margin-left: auto; +} diff --git a/css/signIn.less b/css/signIn.less new file mode 100644 index 0000000..e7adf9e --- /dev/null +++ b/css/signIn.less @@ -0,0 +1,135 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: "PingFangSC-Regular", "PingFang SC", sans-serif; + font-weight: 400; + font-style: normal; + word-break: break-word; +} + +a { + text-decoration: none; + color: unset; +} + +body { + background-color: rgba(238, 242, 245, 1); +} + +.flexflex { + display: flex; +} + +.flexcenter { + display: flex; + justify-content: center; + align-items: center; +} + +.flexjcenter { + display: flex; + justify-content: center; +} + +.flexacenter { + display: flex; + align-items: center; +} + +.flex1 { + flex: 1; +} + +.signInBox-mask { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + // background-color: rgba(0, 0, 0, 0.5); + z-index: 10005; + + .signInBox { + width: 1060px; + height: 658px; + background-color: #fff; + border-radius: 20px; + position: relative; + filter: drop-shadow(0 -5px 0 rgba(247, 195, 8, 1)); + + .signInBox-head { + position: relative; + height: 64px; + + border-bottom: 1px dotted #d7d7d7; + + .header-bi { + width: 83px; + height: 99px; + position: absolute; + top: -61px; + left: 50%; + transform: translateX(-50%); + } + + .header-halo { + width: 160px; + height: 154px; + position: absolute; + top: -89px; + left: 50%; + transform: translateX(-50%); + } + + .header-cross { + width: 18px; + height: 18px; + position: absolute; + top: 10px; + right: 10px; + cursor: pointer; + } + } + + .signInBox-content { + .left-box { + width: 538px; + padding: 20px 30px; + border-right: 1px dotted #d7d7d7; + + .content-header { + font-size: 15px; + color: rgb(85, 85, 85); + line-height: 40px; + + .bi-img { + width: 25px; + height: 30px; + margin-right: 7px; + } + + .bi-value { + font-family: Arial-Black, "Arial Black", sans-serif; + font-weight: 900; + font-style: normal; + font-size: 28px; + color: rgb(0, 0, 0); + margin-right: 7px; + } + + .bi-text { + font-size: 15px; + color: #555555; + line-height: normal; + margin-top: 8px; + } + + .bi-rule { + margin-left: auto; + } + } + } + } + } +} diff --git a/details.html b/details.html index 131498c..9b39132 100644 --- a/details.html +++ b/details.html @@ -17,7 +17,7 @@
-
uzP1eSyPjvvD
+
fi88yrHXiDSj
@@ -77,7 +77,7 @@
{{ info.title }}
-
+
最后编辑:{{ updatedTime || timestamp }}
@@ -482,9 +482,11 @@
+ + \ No newline at end of file diff --git a/img/halo-icon.png b/img/halo-icon.png new file mode 100644 index 0000000..a338049 Binary files /dev/null and b/img/halo-icon.png differ diff --git a/js/details.js b/js/details.js index fde684b..64706e7 100644 --- a/js/details.js +++ b/js/details.js @@ -89,8 +89,6 @@ const appSectionIndex = createApp({ const checkWConfig = () => { const wConfig = JSON.parse(localStorage.getItem("wConfig")) || {}; - console.log("wConfig", wConfig); - if (wConfig.time) { const time = new Date(wConfig.time); const now = new Date(); @@ -127,10 +125,11 @@ const appSectionIndex = createApp({ const data = res.data; let targetInfo = data.info; - console.log("data", data); if (!targetInfo.hidden) targetInfo.hidden = 0; + targetInfo.content = '如果你热爱古典文献,又希望在现代职场大展身手——这个项目可能就是你的“本命”!作为香港最正统的中国语言文学项目,它既传承经典,又为你打跨境传播等全新赛道!\n\n🌟 项目核心亮点权威认证:中国语言文学专业认证,考公考编无障碍\n古今结合:深耕古典文献与理论,同时对接AI内容创作等新兴领域\n语言友好:全程中文授课(普通话+粤语),无语言适应压力\n规模可观:每年录取150+,机会相对较多\n\n点击前往 [港校项目库] 查看 \n中国语言文学\n手机扫码查看\n[attachimg]1008942[/attachimg]\n\n🎯 谁最适合申请?中文系、汉语言、古代文学等对口专业背景\n希望在教育、传媒、AI内容或国际中文教育领域发展\n看重学校声誉与专业正统性的同学\n💼 毕业出路超多元除了教师、公务员等传统路径,毕业生还活跃于:\n✔ 跨境文化传播\n✔ AI内容策划与生成\n✔ 国际中文教育\n✔ 出版与编辑行业\n📌 申请指南专业背景:严格限定中文相关专业,暂不接受跨专业申请\n成绩要求:985/211同学建议86+\n语言成绩:雅思7.0(小分5.5)即可\n面试体验:氛围轻松,专业问题较少\n💡 内部消息参考前几轮拿到面试邀请的同学基本都能录取\n985背景优势明显,建议尽早提交申请\n双非同学如背景特别匹配也可尝试\n🤝 欢迎交流你对中国文学在AI时代的发展有什么想法?或者对哪个就业方向,申请问题欢迎在评论区分享交流!\n欢迎加入寄托香港群交流\n\n[attachimg]969489[/attachimg]'; + // 替换换行 targetInfo.content = targetInfo.content?.replace(/\n/g, "
") || ""; @@ -177,6 +176,9 @@ const appSectionIndex = createApp({ let html = formattedText; + html = html.replaceAll('', "[b]"); + html = html.replaceAll('', "[/b]"); + // 1. 还原换行符为
标签 html = html.replace(/\n/g, "
"); @@ -190,6 +192,8 @@ const appSectionIndex = createApp({ // 4. 还原粗体标记为h2标签 html = html.replace(/\[b\]([\s\S]*?)\[\/b\]/gi, "

$1

"); + console.log(html); + // 5. 统一在单次遍历中按出现顺序替换 attach/attachimg const byAid = new Map(); imageList.forEach((e) => byAid.set(Number(e.aid), { type: "image", ...e })); @@ -214,7 +218,7 @@ const appSectionIndex = createApp({ html = html.replace(/([^<]+<\/span>)\s+/gi, '$1 '); // 7. 清理多余的
标签 - html = html.replace(/

/g, "
"); + // html = html.replace(/

/g, "
"); if (type != "comment") { byAid.forEach((item, aid) => { @@ -271,8 +275,6 @@ const appSectionIndex = createApp({ actions: ["like", "collection"], }) .then((res) => { - console.log("res", res); - const data = res.data; const like = data.like; const collection = data.collection; @@ -418,7 +420,6 @@ const appSectionIndex = createApp({ let commentTotalCount = ref(0); const getComment = () => { - console.log("commentPage.value", commentPage.value); if (commentPage.value == 0 || isgetCommentSate || !token) return; isgetCommentSate = true; ajaxGet(`/v2/api/forum/getCommentList?token=${token}&page=${commentPage.value}&limit=20`) @@ -439,7 +440,7 @@ const appSectionIndex = createApp({ if (element.child.length > 0) { element.child.forEach((el) => { el["picture"] = []; - el.timestamp = strtimeago(element.created_at, 4); + el.timestamp = strtimeago(el.created_at, 4); el["isReplyBoxShow"] = 0; if (el["content"]) el["content"] = restoreHtml(el["content"], el.attachments, "comment"); @@ -518,16 +519,7 @@ const appSectionIndex = createApp({ const handleAnswerText = (e) => { if (e.target.tagName === "IMG") { var src = e.target.getAttribute("src"); - const div = document.createElement("div"); - div.innerHTML = `
`; - div.className = "detail-image-mask flexcenter"; - div.addEventListener("click", () => { - document.body.style.overflow = "auto"; - div.remove(); - }); - - document.body.appendChild(div); - document.body.style.overflow = "hidden"; + previewImage.initComponent(src); } }; @@ -775,8 +767,6 @@ const appSectionIndex = createApp({ images: image, }; - console.log("userInfoWin", userInfoWin.value); - ajax("/v2/api/forum/postComment", { content, token, @@ -872,12 +862,10 @@ const appSectionIndex = createApp({ let target = {}; if (i != null) target = list[index]["child"][i]; else target = list[index]; - console.log("target", target); editToken.value = target.token || ""; editInput.value = target.content || ""; editPicture.value = target.attachments?.images || []; - console.log("editCommentState", editPicture.value); editCommentState.value = true; }; diff --git a/js/public.js b/js/public.js index 68f8076..17a509d 100644 --- a/js/public.js +++ b/js/public.js @@ -9,6 +9,8 @@ const ajax = (url, data) => { url = url.indexOf("https://") > -1 ? url : forumBaseURL + url; return new Promise(function (resolve, reject) { + if (location.hostname == "127.0.0.1") axios.defaults.headers.common["Authorization"] = "n1pstcsmw6m6bcx49z705xhvduqviw29"; + axios .post(url, data, { emulateJSON: true, @@ -67,6 +69,8 @@ const ajaxGet = (url) => { url = url.indexOf("https://") > -1 ? url : forumBaseURL + url; return new Promise(function (resolve, reject) { + if (location.hostname == "127.0.0.1") axios.defaults.headers.common["Authorization"] = "n1pstcsmw6m6bcx49z705xhvduqviw29"; + axios .get( url, diff --git a/js/signIn.js b/js/signIn.js new file mode 100644 index 0000000..0899910 --- /dev/null +++ b/js/signIn.js @@ -0,0 +1,63 @@ +const { createApp, ref, onMounted, nextTick, onUnmounted, computed, watch, provide } = Vue; + +const appSectionIndex = createApp({ + setup() { + onMounted(() => { + console.log("signIn"); + + getFirstDay(); + }); + + let dayOfWeek = ref(0); // 当月第一天是星期几 + let totalDaysInMonth = ref(0); // 当月第一共今天 + let currentDay = ref(0); // 今天几号 + let showList = ref([]); // 展示的 签到列表 + + const getFirstDay = () => { + const firstDayOfMonth = new Date(); + firstDayOfMonth.setDate(1); + // 获取当月第一天是星期几(0 表示星期日,1 表示星期一,依此类推) + dayOfWeek.value = firstDayOfMonth.getDay(); + + const currentDate = new Date(); + const currentMonth = currentDate.getMonth() + 1; + const currentYear = currentDate.getFullYear(); + currentDay.value = currentDate.getDate(); + + // 获取当前月份的总天数 + totalDaysInMonth.value = new Date(currentYear, currentMonth, 0).getDate(); + + init(); + }; + + // 初始化 + const init = () => { + ajaxGet("https://api.gter.net/v2/api/forum/getSignInfo").then((res) => { + if (res.code != 200) return; + console.log("res", res); + const data = res.data; + + const list = data.list || {}; + this.getDateList(list); + + const issign = data.issign || 0; + if (issign == 1) wx.setStorageSync("signInState", util.getCurrentDate()); // 存储签到时间 + + this.setData({ + tips: data.tips || [], + integral: Number(data.integral) || 0, + token: data.token || "", + signnum: data.signnum || 0, + signreward: data.signreward || 0, + issign, + }); + + console.log("integral", this.data.integral); + }); + }; + + return { dayOfWeek }; + }, +}); + +appSectionIndex.mount("#signInBox"); diff --git a/signIn.html b/signIn.html new file mode 100644 index 0000000..6045be5 --- /dev/null +++ b/signIn.html @@ -0,0 +1,62 @@ + + + + + + + + + Document + + + +
+
+
+ + + +
+
+
+
+
+ +
216
+
寄托币
+
签到规则
+
+ +
+ +
+
+ +
+ +
+ +
+
+ {{ item.name }} + +
+
+ + + +
+
+
+
+ +
+ + + + + + + \ No newline at end of file