Files
jiang13-forum/embed_static/static/spa/assets/PostDetailPage-DEqZitTA.js
freefire d0555de28e 统一 React 管理后台,修复评论换行与帖子置顶
- /admin/* 全部由 React SPA 渲染,替代旧版 HTML 后台页面
- 新增仪表盘、帖子/评论/用户管理、系统设置与 JSON API
- 帖子详情页支持管理员置顶;评论换行显示修复

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 23:06:44 +08:00

2 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import{j as e,r as l,e as X,w as ue}from"./react-vendor-CFzzFOsg.js";import{c as V,u as de,a as _,S as he,B as I,n as b}from"./index-DurEdRMk.js";import{B as G}from"./badge-E7fnzaIj.js";import{h as fe,f as xe}from"./content-BR0rw1k4.js";import{u as ge,X as pe,p as ve,v as Q,w as je,x as be,A as Ne,y as ke,i as we,z as Se,B as ye}from"./ui-vendor-BLDO93FK.js";import{r as Ce}from"./postContent-CNPsgNvN.js";import"./markdown-vendor-DxR1h-Bq.js";function Ee({content:t,onMentionClick:s}){return e.jsx("div",{className:"floor-body",dangerouslySetInnerHTML:{__html:fe(t)}})}function z(t){var s;return(s=t.user)!=null&&s.nickname?t.user.nickname:t.guest_nick?t.guest_nick:"游客"}function _e(t){return z(t)[0]||"?"}function Ie(t){return!t.user_id||t.user_id===0}function Me(t){const s=new Map,o=[];for(const a of t)s.set(a.id,{comment:a,children:[]});for(const a of t){const h=s.get(a.id);a.reply_to&&s.has(a.reply_to)?s.get(a.reply_to).children.push(h):o.push(h)}return o}function Pe(t){const s=new Date(t),o=new Date,a=h=>String(h).padStart(2,"0");return s.getFullYear()===o.getFullYear()?`${a(s.getMonth()+1)}${a(s.getDate())}`:`${s.getFullYear()}${s.getMonth()+1}${s.getDate()}`}function Z({node:t,nested:s,highlightFloor:o,replyToId:a,onReply:h,onCancelReply:c,renderReplyBox:d}){var m,g;const i=t.comment,f=z(i),j=Ie(i),x=o===i.floor,w=!!i.content_hidden,p=a===i.id;return e.jsxs("div",{id:`floor-${i.floor}`,className:`waline-comment ${s?"nested":""} ${x?"highlight":""}`,children:[e.jsx("div",{className:`waline-comment-avatar ${j&&!((m=i.user)!=null&&m.avatar)?"guest":""}`,children:(g=i.user)!=null&&g.avatar?e.jsx("img",{src:i.user.avatar,alt:""}):_e(i)}),e.jsxs("div",{className:"waline-comment-main",children:[e.jsx("div",{className:"waline-comment-head",children:i.guest_url?e.jsx("a",{href:i.guest_url,target:"_blank",rel:"noopener noreferrer",className:"waline-comment-author",children:f}):e.jsx("span",{className:"waline-comment-author",children:f})}),w?e.jsx("div",{className:"waline-comment-private-mask",children:"该评论为私密评论,仅文章作者与评论发起者可见!"}):e.jsxs("div",{className:"waline-comment-bubble",children:[i.reply_target&&e.jsxs("span",{className:"waline-reply-at",children:["@",z(i.reply_target)]}),e.jsx(Ee,{content:i.content})]}),e.jsxs("div",{className:"waline-comment-meta",children:[e.jsxs("span",{className:"waline-comment-date",children:[e.jsx(ge,{size:14}),Pe(i.created_at)]}),p?e.jsxs("button",{type:"button",className:"waline-comment-reply-btn cancel",onClick:c,children:[e.jsx(pe,{size:14}),"取消"]}):e.jsxs("button",{type:"button",className:"waline-comment-reply-btn",onClick:()=>h(i),children:[e.jsx(ve,{size:14}),"回复"]})]}),p&&d&&e.jsx("div",{id:`reply-box-${i.id}`,className:"comment-box-wrap inline",children:d(i)}),t.children.length>0&&e.jsx("div",{className:"waline-replies",children:t.children.map(S=>e.jsx(Z,{node:S,nested:!0,highlightFloor:o,replyToId:a,onReply:h,onCancelReply:c,renderReplyBox:d},S.comment.id))})]})]})}function Le({comments:t,highlightFloor:s,replyToId:o,onReply:a,onCancelReply:h,renderReplyBox:c}){const d=Me(t);return e.jsx("div",{className:"comment-thread-list",children:d.map(i=>e.jsx(Z,{node:i,highlightFloor:s,replyToId:o,onReply:a,onCancelReply:h,renderReplyBox:c},i.comment.id))})}const ee=l.forwardRef(({className:t,...s},o)=>e.jsx(Q,{className:V("peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-[var(--j13-green)] data-[state=unchecked]:bg-input",t),...s,ref:o,children:e.jsx(je,{className:V("pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0")})}));ee.displayName=Q.displayName;const $e=["😀","😁","😂","🤣","😃","😄","😅","😆","😉","😊","😋","😎","😍","😘","🥰","😗","😙","😚","🙂","🤗","🤩","🤔","🤨","😐","😑","😶","🙄","😏","😣","😥","😮","🤐","😯","😪","😫","🥱","😴","😌","😛","😜","😝","🤤","😒","😓","😔","😕","🙃","🤑","😲","🙁","😖","😞","😟","😤","😢","😭","😦","😧","😨","😩","🤯","😬","😰","😱","🥵","🥶","😳","🤪","😵","🥴","😠","😡","🤬","😷","🤒","🤕","🤢","🤮","🤧","😇","🥳","🥺","🤠","🤡","🤥","🤫","🤭","🧐","🤓","😈","👻","💀","☠️","👽","👾","🤖","🎃","😺","😸","😹","😻","😼","😽","🙀","😿","😾","👋","🤚","🖐","✋","🖖","👌","🤏","✌️","🤞","🤟","🤘","🤙","👈","👉","👆","👇","☝️","👍","👎","✊","👊","🤛","🤜","👏","🙌","👐","🤲","🤝","🙏","💪","🦾","🦿","🦵","🦶","❤️","🧡","💛","💚","💙","💜","🖤","🤍","🤎","💔","❣️","💕","💞","💓","💗","💖","💘","💝","💟","☮️","✨","⭐","🌟","💫","🔥","💥","💯","✅","❌","❓","❗","💢","💤","💦","🎉","🎊","🎁","🏆","🥇","🥈"];function Re({onSelect:t}){return e.jsx("div",{className:"emoji-picker",children:$e.map(s=>e.jsx("button",{type:"button",className:"emoji-picker-item",onClick:()=>t(s),children:s},s))})}const te="j13_guest_nick",se="j13_guest_email",ne="j13_guest_url",ae="j13_my_comment_ids";function ze(){return{nick:localStorage.getItem(te)||"",email:localStorage.getItem(se)||"",url:localStorage.getItem(ne)||""}}function De(t){localStorage.setItem(te,t.nick),localStorage.setItem(se,t.email),localStorage.setItem(ne,t.url)}function oe(){try{const t=localStorage.getItem(ae);if(!t)return[];const s=JSON.parse(t);return Array.isArray(s)?s.filter(o=>typeof o=="number"):[]}catch{return[]}}function Te(t){const s=oe();s.includes(t)||(s.push(t),localStorage.setItem(ae,JSON.stringify(s.slice(-200))))}function W({user:t,replyTo:s,inline:o,submitting:a,submitCount:h=0,onSubmit:c,onCancelReply:d}){var C;const i=ze(),[f,j]=l.useState(""),[x,w]=l.useState(i.nick),[p,m]=l.useState(i.email),[g,S]=l.useState(i.url),[N,M]=l.useState(!1),[k,P]=l.useState(!1),y=l.useRef(null),L=l.useRef(null);l.useEffect(()=>{var r;o&&s&&((r=y.current)==null||r.focus({preventScroll:!0}))},[s==null?void 0:s.id,o]),l.useEffect(()=>{j(""),P(!1),M(!1)},[h]),l.useEffect(()=>{if(!k)return;const r=v=>{L.current&&!L.current.contains(v.target)&&P(!1)};return document.addEventListener("mousedown",r),()=>document.removeEventListener("mousedown",r)},[k]);const D=r=>{const v=y.current;if(v){const E=v.selectionStart??f.length,Y=v.selectionEnd??f.length,A=f.slice(0,E)+r+f.slice(Y);j(A),requestAnimationFrame(()=>{v.focus();const R=E+r.length;v.setSelectionRange(R,R)})}else j(E=>E+r)},$=()=>{const r=f.trim();r&&(!t&&!x.trim()||(t||De({nick:x.trim(),email:p.trim(),url:g.trim()}),c({content:r,guestNick:t?void 0:x.trim(),guestEmail:t?void 0:p.trim(),guestUrl:t?void 0:g.trim(),isPrivate:N})))},T=r=>{r.key==="Enter"&&(r.ctrlKey||r.metaKey)&&(r.preventDefault(),$())},B=((C=t==null?void 0:t.nickname)==null?void 0:C[0])||(x==null?void 0:x[0])||"?";return e.jsxs("div",{className:"comment-box",ref:L,children:[e.jsx("div",{className:"comment-box-avatar",children:t!=null&&t.avatar?e.jsx("img",{src:t.avatar,alt:"",className:"comment-box-avatar-img"}):e.jsx("div",{className:`comment-box-avatar-placeholder ${t?"":"guest"}`,children:t?B:e.jsx("svg",{viewBox:"0 0 24 24",width:"20",height:"20",fill:"currentColor",children:e.jsx("path",{d:"M12 12c2.7 0 4.8-2.1 4.8-4.8S14.7 2.4 12 2.4 7.2 4.5 7.2 7.2 9.3 12 12 12zm0 2.4c-3.2 0-9.6 1.6-9.6 4.8v2.4h19.2v-2.4c0-3.2-6.4-4.8-9.6-4.8z"})})})}),e.jsxs("div",{className:"comment-box-main",children:[s&&!o&&e.jsxs("div",{className:"comment-box-reply-hint",children:[e.jsxs("span",{children:["回复 #",s.floor," ",z(s)]}),d&&e.jsx("button",{type:"button",className:"comment-box-reply-cancel",onClick:d,children:"取消"})]}),e.jsxs("div",{className:`comment-box-input-wrap ${N?"private-mode":""}`,children:[e.jsx("textarea",{ref:y,className:"comment-box-textarea",placeholder:N?"正在隐私评论中...":"说点什么吧",value:f,onChange:r=>j(r.target.value),onKeyDown:T,rows:3}),e.jsx("button",{type:"button",className:"comment-box-send",disabled:a||!f.trim()||!t&&!x.trim(),onClick:$,title:"发送",children:e.jsx(be,{size:16})})]}),!t&&e.jsxs("div",{className:"comment-box-guest-fields",children:[e.jsxs("label",{className:"comment-box-guest-field",children:[e.jsxs("span",{className:"comment-box-guest-label",children:["昵称",e.jsx("em",{className:"comment-box-guest-required",children:"必填"})]}),e.jsx("input",{className:"comment-box-guest-input",placeholder:"怎么称呼你",autoComplete:"nickname",value:x,onChange:r=>w(r.target.value)})]}),e.jsxs("label",{className:"comment-box-guest-field",children:[e.jsxs("span",{className:"comment-box-guest-label",children:["邮箱",e.jsx("em",{className:"comment-box-guest-optional",children:"选填"})]}),e.jsx("input",{className:"comment-box-guest-input",placeholder:"name@example.com",type:"email",autoComplete:"email",value:p,onChange:r=>m(r.target.value)})]}),e.jsxs("label",{className:"comment-box-guest-field",children:[e.jsxs("span",{className:"comment-box-guest-label",children:["网址",e.jsx("em",{className:"comment-box-guest-optional",children:"选填"})]}),e.jsx("input",{className:"comment-box-guest-input",placeholder:"https://example.com",type:"url",autoComplete:"url",value:g,onChange:r=>S(r.target.value)})]}),e.jsx("p",{className:"comment-box-guest-hint",children:"邮箱不会公开展示,仅用于站内记录。"})]}),e.jsxs("div",{className:"comment-box-toolbar",children:[e.jsx("button",{type:"button",className:`comment-box-owo ${k?"active":""}`,onClick:()=>P(r=>!r),children:"OwO"}),e.jsxs("label",{className:"comment-box-private",children:[e.jsx(ee,{checked:N,onCheckedChange:M}),e.jsx("span",{children:"隐私评论"})]})]}),k&&e.jsx(Re,{onSelect:D})]})]})}function Be({html:t,isLoggedIn:s,className:o="post-detail-content"}){const a=X(),h=l.useMemo(()=>Ce(t,s),[t,s]),c=l.useCallback(d=>{const i=d.target;if(i.closest("[data-members-login]")){d.preventDefault(),a("/login");return}i.closest("[data-members-register]")&&(d.preventDefault(),a("/register"))},[a]);return e.jsx("div",{className:o,onClick:c,dangerouslySetInnerHTML:{__html:h}})}function Ye(t,s){const{overflowY:o}=getComputedStyle(t);return o!=="auto"&&o!=="scroll"&&o!=="overlay"||t.scrollHeight<=t.clientHeight+1?!1:s<0?t.scrollTop>0:t.scrollTop+t.clientHeight<t.scrollHeight-1}function Ae(t,s,o){let a=t;for(;a&&a!==o;){if(Ye(a,s))return a;a=a.parentElement}return null}function Ge(t,s=!0){l.useEffect(()=>{if(!s)return;const o=t.current;if(!o)return;const a=o.closest(".app-shell");if(!a)return;const h=c=>{const d=c.target instanceof HTMLElement?c.target:null;if(!d)return;const i=Ae(d,c.deltaY,a);if(i&&i!==o&&o.contains(i)||i===o)return;const f=o.scrollTop;o.scrollTop+=c.deltaY,o.scrollTop!==f&&c.preventDefault()};return a.addEventListener("wheel",h,{passive:!1}),()=>a.removeEventListener("wheel",h)},[t,s])}function We(){var K,F,O,q,J;const{id:t}=ue(),s=Number(t),o=X(),{user:a,refresh:h}=de(),[c,d]=l.useState(null),[i,f]=l.useState([]),[j,x]=l.useState(!1),[w,p]=l.useState(!1),[m,g]=l.useState(null),[S,N]=l.useState(!1),[M,k]=l.useState(!0),[P,y]=l.useState(null),[L,D]=l.useState(0),$=l.useRef(null),T=l.useRef(null),B=l.useRef(null),C=l.useRef();Ge($,!M&&!!c);const r=l.useCallback(async()=>{const n=a?[]:oe(),u=await _.comments(s,n);return Array.isArray(u.comments)?u.comments:[]},[s,a]),v=async()=>{if(s){k(!0);try{const[n,u]=await Promise.all([_.post(s),r()]);d(n.post),x(n.liked),p(n.favorited),f(u),await h()}catch(n){b.error(n instanceof Error?n.message:"加载失败")}finally{k(!1)}}};l.useEffect(()=>{g(null),v()},[s]);const E=l.useCallback(n=>{const u=document.getElementById(`floor-${n}`);u&&(u.scrollIntoView({behavior:"smooth",block:"center"}),y(n),clearTimeout(C.current),C.current=setTimeout(()=>y(null),2e3))},[]),Y=n=>{if((m==null?void 0:m.id)===n.id){g(null);return}g(n)};l.useLayoutEffect(()=>{if(!m)return;const n=document.getElementById(`reply-box-${m.id}`);n==null||n.scrollIntoView({behavior:"smooth",block:"nearest"})},[m==null?void 0:m.id]),l.useEffect(()=>()=>clearTimeout(C.current),[]);const A=async()=>{if(!a){o("/login");return}try{const n=await _.like(s);x(n.liked),d(u=>u&&{...u,like_count:n.like_count})}catch(n){b.error(n instanceof Error?n.message:"操作失败")}},R=async()=>{if(!a){o("/login");return}try{const n=await _.favorite(s);p(n.favorited),b.success(n.favorited?"已收藏":"已取消收藏")}catch(n){b.error(n instanceof Error?n.message:"操作失败")}},H={user:a,submitting:S,submitCount:L,onSubmit:async n=>{N(!0);try{const u=await _.addComment(s,{content:n.content,replyTo:m==null?void 0:m.id,guestNick:n.guestNick,guestEmail:n.guestEmail,guestUrl:n.guestUrl,isPrivate:n.isPrivate});a||Te(u.id),g(null),D(me=>me+1),b.success("评论成功"),f(await r()),setTimeout(()=>E(u.floor),100)}catch(u){b.error(u instanceof Error?u.message:"评论失败")}finally{N(!1)}},onCancelReply:()=>g(null)};if(M)return e.jsx("div",{className:"post-detail-loading flex justify-center py-16",children:e.jsx(he,{size:"lg"})});if(!c)return e.jsxs("div",{className:"empty-state",children:[e.jsx("p",{children:"帖子不存在"}),e.jsx(I,{variant:"outline",onClick:()=>o("/"),children:"返回首页"})]});const ie=((F=(K=c.user)==null?void 0:K.nickname)==null?void 0:F[0])||"?",U=((O=c.tags)==null?void 0:O.split(/[,]/).map(n=>n.trim()).filter(Boolean))??[],ce=a&&(a.role==="admin"||a.id===c.user_id),le=(a==null?void 0:a.role)==="admin",re=async()=>{if(c)try{const n=await _.adminPinPost(s,!c.pinned);d(u=>u&&{...u,pinned:n.pinned}),b.success(n.message)}catch(n){b.error(n instanceof Error?n.message:"操作失败")}};return e.jsxs("div",{className:"page-wrap post-detail-page",ref:$,children:[e.jsxs("div",{className:"post-detail-header",children:[e.jsxs("div",{className:"post-detail-nav",children:[e.jsxs(I,{variant:"ghost",size:"sm",onClick:()=>o(-1),children:[e.jsx(Ne,{}),"返回"]}),c.board&&e.jsx(G,{variant:"green",className:"post-detail-board-tag",children:c.board.name})]}),e.jsxs("div",{className:"post-detail-head",children:[e.jsxs("h1",{className:"post-detail-title",children:[c.pinned&&e.jsx(G,{variant:"orange",className:"mr-2 align-middle",children:"置顶"}),c.title]}),e.jsxs("div",{className:"post-detail-author-row",children:[e.jsx("div",{className:"post-avatar post-avatar-lg",children:(q=c.user)!=null&&q.avatar?e.jsx("img",{src:c.user.avatar,alt:""}):ie}),e.jsxs("div",{className:"post-detail-author-info",children:[e.jsx("span",{className:"post-detail-author-name",children:(J=c.user)==null?void 0:J.nickname}),e.jsxs("span",{className:"post-detail-meta-line",children:[xe(c.created_at)," · ",c.view_count," 次浏览"]})]})]})]}),U.length>0&&e.jsx("div",{className:"post-detail-tags",children:U.map(n=>e.jsx(G,{variant:"secondary",children:n},n))}),e.jsx(Be,{html:c.content||"",isLoggedIn:!!a}),e.jsxs("div",{className:"post-detail-actions",children:[e.jsxs(I,{variant:j?"default":"outline",size:"sm",onClick:A,children:[e.jsx(ke,{}),"点赞 ",c.like_count]}),e.jsxs(I,{variant:w?"default":"outline",size:"sm",onClick:R,children:[e.jsx(we,{}),w?"已收藏":"收藏"]}),ce&&e.jsxs(I,{variant:"outline",size:"sm",onClick:()=>o(`/post/${s}/edit`),children:[e.jsx(Se,{}),"编辑"]}),le&&e.jsxs(I,{variant:"outline",size:"sm",onClick:re,children:[e.jsx(ye,{}),c.pinned?"取消置顶":"置顶"]})]})]}),e.jsxs("div",{className:"comment-section",ref:T,children:[e.jsxs("div",{className:"comment-section-bar",children:[e.jsx("span",{className:"comment-section-title",children:"评论区"}),e.jsxs("span",{className:"comment-section-count",children:[i.length," 条评论"]})]}),!m&&e.jsx("div",{className:"comment-box-wrap",ref:B,children:e.jsx(W,{...H})}),e.jsx("div",{className:"comment-list-area",children:i.length===0&&!m?e.jsxs("div",{className:"comment-empty",children:[e.jsx("div",{className:"comment-empty-icon",children:"💬"}),e.jsx("p",{children:"暂无评论,来抢沙发吧"})]}):e.jsx(Le,{comments:i,highlightFloor:P,replyToId:(m==null?void 0:m.id)??null,onReply:Y,onCancelReply:()=>g(null),renderReplyBox:n=>e.jsx(W,{...H,replyTo:n,inline:!0},n.id)})})]})]})}export{We as default};