{{.PostTitle}}
diff --git a/templates/profile/view.tmpl b/templates/profile/view.tmpl
index 1633ac3..a4bab16 100644
--- a/templates/profile/view.tmpl
+++ b/templates/profile/view.tmpl
@@ -14,13 +14,67 @@
{{.CommentCount}}评论
{{.FavoriteCount}}收藏
{{.LikeReceived}}获赞
+ {{.Points}}积分
+
+
+
+
+ {{else}}
+
+
\n") + ""; + } + const block = openTag + inner + closeTag; + textarea.value = + textarea.value.slice(0, start) + block + textarea.value.slice(end); + textarea.focus(); + const pos = start + block.length; + textarea.setSelectionRange(pos, pos); + if (statusEl) statusEl.textContent = "已插入门控块"; + } + + if (fileInput) { + fileInput.addEventListener("change", async () => { + const file = fileInput.files && fileInput.files[0]; + fileInput.value = ""; + if (!file) return; + if (statusEl) statusEl.textContent = "上传中…"; + const fd = new FormData(); + fd.append("image", file); + fd.append("_csrf", csrf); + try { + const res = await fetch(uploadURL, { + method: "POST", + headers: { "X-CSRF-Token": csrf }, + body: fd, + credentials: "same-origin", + }); + const data = await res.json().catch(() => ({})); + if (!res.ok) throw new Error(data.error || "上传失败"); + const url = data.url; + if (!url) throw new Error("未返回图片地址"); + insertAtCursor(`\n\n\n\n`); + if (statusEl) statusEl.textContent = "已插入图片"; + } catch (e) { + if (statusEl) statusEl.textContent = e.message || "上传失败"; } - const url = data.url; - if (!url) throw new Error("未返回图片地址"); - const md = `\n\n\n\n`; - const start = textarea.selectionStart || textarea.value.length; - const end = textarea.selectionEnd || start; - textarea.value = - textarea.value.slice(0, start) + md + textarea.value.slice(end); - textarea.focus(); - if (statusEl) statusEl.textContent = "已插入图片"; - } catch (e) { - if (statusEl) statusEl.textContent = e.message || "上传失败"; + }); + } + + document.getElementById("compose-gate-login")?.addEventListener("click", () => { + wrapSelection( + '',
+ " "
+ );
+ });
+ document.getElementById("compose-gate-reply")?.addEventListener("click", () => {
+ wrapSelection(
+ '',
+ " "
+ );
+ });
+ document.getElementById("compose-gate-points")?.addEventListener("click", () => {
+ let cost = window.prompt("积分价格(1–9999)", "10");
+ if (cost == null) return;
+ cost = String(cost).trim();
+ const n = parseInt(cost, 10);
+ if (!n || n < 1 || n > 9999) {
+ if (statusEl) statusEl.textContent = "价格须为 1–9999 的整数";
+ return;
+ }
+ wrapSelection(
+ ``,
+ " "
+ );
+ });
+})();
+
+(function postContentGates() {
+ const article = document.querySelector(".j13-post[data-post-id]");
+ if (!article) return;
+
+ const postId = article.getAttribute("data-post-id");
+ const csrf = article.getAttribute("data-csrf") || "";
+ const loggedIn = article.getAttribute("data-logged-in") === "1";
+ const path = window.location.pathname + window.location.hash;
+
+ article.querySelectorAll('[data-locked="true"]').forEach((el) => {
+ const gate = el.getAttribute("data-gate") || "";
+ const shell = el.querySelector("[data-gate-shell]");
+ if (!shell) return;
+
+ if (gate === "login" && !loggedIn) {
+ const a = document.createElement("a");
+ a.href = "/login?redirect=" + encodeURIComponent(path || "/");
+ a.textContent = "登录查看";
+ const p = document.createElement("p");
+ p.appendChild(a);
+ shell.appendChild(p);
+ }
+ if (gate === "reply" && loggedIn) {
+ const a = document.createElement("a");
+ a.href = "#comments";
+ a.textContent = "去评论解锁";
+ const p = document.createElement("p");
+ p.appendChild(a);
+ shell.appendChild(p);
+ }
+ if (gate === "points") {
+ const key = el.getAttribute("data-block-key") || "";
+ const cost = el.getAttribute("data-cost") || "";
+ if (!loggedIn) {
+ const a = document.createElement("a");
+ a.href = "/login?redirect=" + encodeURIComponent(path || "/");
+ a.textContent = "登录后解锁";
+ const p = document.createElement("p");
+ p.appendChild(a);
+ shell.appendChild(p);
+ return;
+ }
+ if (!key) return;
+ const btn = document.createElement("button");
+ btn.type = "button";
+ btn.className = "j13-gate__unlock";
+ btn.textContent = "花费 " + cost + " 积分解锁";
+ btn.addEventListener("click", async () => {
+ btn.disabled = true;
+ btn.textContent = "解锁中…";
+ try {
+ const res = await fetch("/post/" + postId + "/unlock", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "X-CSRF-Token": csrf,
+ },
+ credentials: "same-origin",
+ body: JSON.stringify({ block_key: key }),
+ });
+ const data = await res.json().catch(() => ({}));
+ if (!res.ok) throw new Error(data.error || "解锁失败");
+ const inner = data.unlock && data.unlock.inner_html;
+ if (typeof inner !== "string") throw new Error("未返回内容");
+ el.setAttribute("data-locked", "false");
+ el.innerHTML = inner;
+ } catch (e) {
+ btn.disabled = false;
+ btn.textContent = "花费 " + cost + " 积分解锁";
+ alert(e.message || "解锁失败");
+ }
+ });
+ const p = document.createElement("p");
+ p.appendChild(btn);
+ shell.appendChild(p);
}
});
})();
积分钱包
+当前余额 {{.Points}} 积分
+
+
+
+
+ 每日签到
+ {{if .CheckIn.CheckedIn}} +今日已签到 · 连续 {{.CheckIn.Streak}} 天 · 获得 {{.CheckIn.TodayPoints}} 积分
+ + {{else}} +连续将至 {{.CheckIn.Streak}} 天 · 预计可得 {{.CheckIn.TodayPoints}} 积分(基础 5,连签 +1,封顶 15)
+ + {{end}} +
+
+ 每日抽奖
+ {{if .Lottery.Drawn}} +今日已抽 · 结果 {{.Lottery.Points}} 积分
+ + {{else}} +每日一次 · 成本 {{.Lottery.Cost}} · 奖池 0/2/5/10/20
+ + {{end}} +最近流水
+ {{if .Ledger}} +| 时间 | 事由 | 变动 | 余额 |
|---|---|---|---|
| {{.CreatedAt}} | +{{.ReasonLabel}}{{if .Note}} {{.Note}}{{end}} | +{{if gt .Delta 0}}+{{end}}{{.Delta}} | +{{.Balance}} | +
暂无积分流水
+ {{end}} +账号
用户名 {{.Username}}
邮箱 {{.Email}}
-等级 Lv.{{.Level}} · 经验 {{.Exp}} · 积分 {{.Points}}
+等级 Lv.{{.Level}} · 经验 {{.Exp}}
{{if .Avatar}}\n") + ""; + } + const block = openTag + inner + closeTag; + textarea.value = + textarea.value.slice(0, start) + block + textarea.value.slice(end); + textarea.focus(); + const pos = start + block.length; + textarea.setSelectionRange(pos, pos); + if (statusEl) statusEl.textContent = "已插入门控块"; + } + + if (fileInput) { + fileInput.addEventListener("change", async () => { + const file = fileInput.files && fileInput.files[0]; + fileInput.value = ""; + if (!file) return; + if (statusEl) statusEl.textContent = "上传中…"; + const fd = new FormData(); + fd.append("image", file); + fd.append("_csrf", csrf); + try { + const res = await fetch(uploadURL, { + method: "POST", + headers: { "X-CSRF-Token": csrf }, + body: fd, + credentials: "same-origin", + }); + const data = await res.json().catch(() => ({})); + if (!res.ok) throw new Error(data.error || "上传失败"); + const url = data.url; + if (!url) throw new Error("未返回图片地址"); + insertAtCursor(`\n\n\n\n`); + if (statusEl) statusEl.textContent = "已插入图片"; + } catch (e) { + if (statusEl) statusEl.textContent = e.message || "上传失败"; } - const url = data.url; - if (!url) throw new Error("未返回图片地址"); - const md = `\n\n\n\n`; - const start = textarea.selectionStart || textarea.value.length; - const end = textarea.selectionEnd || start; - textarea.value = - textarea.value.slice(0, start) + md + textarea.value.slice(end); - textarea.focus(); - if (statusEl) statusEl.textContent = "已插入图片"; - } catch (e) { - if (statusEl) statusEl.textContent = e.message || "上传失败"; + }); + } + + document.getElementById("compose-gate-login")?.addEventListener("click", () => { + wrapSelection( + '