PageSourceSearch

https://seodoon-church-admin.web.app/assets/AccessLogsPage-C1K74qgV.js

js seodoon-church-admin.web.app collected 2026-10-03 12:36:42 UTC 18,984 bytes, 2 lines download raw bytes

1import{j as e}from"./vendor-data-Z5doMMu-.js";import{r as d}from"./vendor-react-zNM0AU50.js";import{l as ne,q as ce,w as de,T as ie,x as xe,B as oe,m as me}from"./vendor-firebase-Da9KY1q_.js";import{d as he}from"./index-D1K3lVhu.js";import{K as ge,$ as pe,R as O,D as ue,ak as je,aT as S,U as F,i as be,s as ye,c as Ne,S as fe}from"./vendor-ui-CW5bJ11U.js";import"./vendor-charts-08G1rM8P.js";function Ce(){const[h,I]=d.useState([]),[C,k]=d.useState(!0),[g,B]=d.useState("all"),[p,K]=d.useState("today"),[b,$]=d.useState("dashboard"),[r,V]=d.useState({totalToday:0,webToday:0,adminToday:0,uniqueUsers:0,peakHour:0,avgPerHour:0}),[E,z]=d.useState([]),[y,Q]=d.useState([]),[H,W]=d.useState([]),[N,_]=d.useState([]),[f,G]=d.useState([]),L=(s,l)=>{const i=l==="web"?{"/":"홈","/index.html":"홈","/index-pc.html":"홈 (PC)","/bulletin.html":"주보","/qt.html":"QT","/my-journey.html":"나의 신앙여정","/bible-responsive.html":"성경읽기","/worship.html":"예배","/profile.html":"프로필","/login.html":"로그인","/communication.html":"소통","/directions.html":"오시는 길","/offering.html":"헌금","/praise.html":"찬양","/notification-center.html":"알림센터","/smart-directory.html":"스마트주소록","/church-history-pc.html":"교회역사","/pastor-greeting-pc.html":"목사님인사"}:{"/":"대시보드","/dashboard":"대시보드","/members":"교적부","/attendance":"출석관리","/content/bulletin":"주보관리","/content/qt":"QT관리","/content/push":"푸시알림","/settings":"설정","/settings/access-logs":"접속로그","/settings/app-users":"회원관리","/election":"선거관리","/pastoral":"목양"};if(i[s])return i[s];for(const[n,x]of Object.entries(i))if(s.includes(n)&&n!=="/")return x;return s.replace(/\.html$/,"").replace(/^\//,"")||"홈"},M=async()=>{k(!0);try{const s=ne(he,"accessLogs"),l=new Date;let c=new Date;p==="today"?c.setHours(0,0,0,0):p==="week"?c.setDate(l.getDate()-7):c.setMonth(l.getMonth()-1);let u=ce(s,de("accessTime",">=",ie.fromDate(c)),xe("accessTime","desc"),oe(1e3));const n=(await me(u)).docs.map(t=>({id:t.id,...t.data()})),x=g==="all"?n:n.filter(t=>t.platform===g);I(x);const R=new Date;R.setHours(0,0,0,0);const o=n.filter(t=>t.accessTime.toDate()>=R),ee=new Set(o.filter(t=>t.userId).map(t=>t.userId)),j={};for(let t=0;t<24;t++)j[t]=0;o.forEach(t=>{const a=t.accessTime.toDate().getHours();j[a]=(j[a]||0)+1});const q=Object.entries(j).map(([t,a])=>({hour:parseInt(t),count:a}));z(q);const se=q.reduce((t,a)=>a.count>t.count?a:t,{hour:0,count:0}).hour,v={};x.forEach(t=>{const a=t.page||"/";v[a]=(v[a]||0)+1});const te=Object.entries(v).map(([t,a])=>({page:t,count:a})).sort((t,a)=>a.count-t.count).slice(0,10);Q(te);const ae=n.filter(t=>t.userName).slice(0,10).map(t=>({name:t.userName||"비회원",time:J(t.accessTime),platform:t.platform}));W(ae);const w=n.filter(t=>t.platform==="web"),T=n.filter(t=>t.platform==="admin"),D={};w.forEach(t=>{const a=t.page||"/",m=L(a,"web");D[m]=(D[m]||0)+1});const le=Object.entries(D).map(([t,a])=>({page:t,count:a,percent:w.length>0?Math.round(a/w.length*100):0})).sort((t,a)=>a.count-t.count).slice(0,10);_(le);const P={};T.forEach(t=>{const a=t.page||"/",m=L(a,"admin");P[m]=(P[m]||0)+1});const re=Object.entries(P).map(([t,a])=>({page:t,count:a,percent:T.length>0?Math.round(a/T.length*100):0})).sort((t,a)=>a.count-t.count).slice(0,10);G(re),V({totalToday:o.length,webToday:o.filter(t=>t.platform==="web").length,adminToday:o.filter(t=>t.platform==="admin").length,uniqueUsers:ee.size,peakHour:se,avgPerHour:Math.round(o.length/Math.max(new Date().getHours(),1))})}catch(s){console.error("Failed to fetch access logs:",s)}finally{k(!1)}};d.useEffect(()=>{M()},[g,p]);const U=s=>s.toDate().toLocaleString("ko-KR",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}),J=s=>s.toDate().toLocaleString("ko-KR",{hour:"2-digit",minute:"2-digit"}),X=s=>s==="mobile"||s==="tablet"?e.jsx(fe,{className:"w-4 h-4"}):e.jsx(S,{className:"w-4 h-4"}),A=s=>{const l={web:"bg-blue-100 text-blue-700",admin:"bg-purple-100 text-purple-700",mobile:"bg-green-100 text-green-700"},c={web:"홈페이지",admin:"관리자",mobile:"모바일"};return e.jsx("span",{className:`px-2 py-0.5 rounded-full text-xs font-medium ${l[s]||"bg-gray-100 text-gray-700"}`,children:c[s]||s})},Y=()=>{const s=["접속시간","플랫폼","사용자","이메일","페이지","기기","User Agent"],l=h.map(n=>[U(n.accessTime),n.platform,n.userName||"-",n.userEmail||"-",n.page,n.deviceType,n.userAgent]),c=[s.join(","),...l.map(n=>n.map(x=>`"${x}"`).join(","))].join(`
2`),u=new Blob(["\uFEFF"+c],{type:"text/csv;charset=utf-8;"}),i=document.createElement("a");i.href=URL.createObjectURL(u),i.download=`접속로그_${new Date().toISOString().split("T")[0]}.csv`,i.click()},Z=Math.max(...E.map(s=>s.count),1);return e.jsxs("div",{className:"p-6 space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold text-gray-900",children:"접속 로그"}),e.jsx("p",{className:"text-sm text-gray-500 mt-1",children:"홈페이지 및 관리자 페이지 접속 기록"})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("div",{className:"flex bg-gray-100 rounded-lg p-1",children:[e.jsxs("button",{onClick:()=>
2$("dashboard"),className:`px-3 py-1.5 text-sm rounded-md transition-all ${b==="dashboard"?"bg-white shadow text-gray-900":"text-gray-600"}`,children:[e.jsx(ge,{className:"w-4 h-4 inline mr-1"}),"대시보드"]}),e.jsxs("button",{onClick:()=>$("table"),className:`px-3 py-1.5 text-sm rounded-md transition-all ${b==="table"?"bg-white shadow text-gray-900":"text-gray-600"}`,children:[e.jsx(pe,{className:"w-4 h-4 inline mr-1"}),"상세로그"]})]}),e.jsxs("button",{onClick:M,className:"flex items-center gap-2 px-4 py-2 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 text-sm",children:[e.jsx(O,{className:`w-4 h-4 ${C?"animate-spin":""}`}),"새로고침"]}),e.jsxs("button",{onClick:Y,className:"flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm",children:[e.jsx(ue,{className:"w-4 h-4"}),"CSV 다운로드"]})]})]}),e.jsxs("div",{className:"grid grid-cols-6 gap-4",children:[e.jsx("div",{className:"bg-white rounded-xl border border-gray-200 p-4",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"p-2 bg-blue-100 rounded-lg",children:e.jsx(je,{className:"w-5 h-5 text-blue-600"})}),e.jsxs("div",{children:[e.jsx("p",{className:"text-xs text-gray-500",children:"오늘 총 접속"}),e.jsx("p",{className:"text-xl font-bold text-gray-900",children:r.totalToday})]})]})}),e.jsx("div",{className:"bg-white rounded-xl border border-gray-200 p-4",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"p-2 bg-green-100 rounded-lg",children:e.jsx(S,{className:"w-5 h-5 text-green-600"})}),e.jsxs("div",{children:[e.jsx("p",{className:"text-xs text-gray-500",children:"홈페이지"}),e.jsx("p",{className:"text-xl font-bold text-gray-900",children:r.webToday})]})]})}),e.jsx("div",{className:"bg-white rounded-xl border border-gray-200 p-4",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"p-2 bg-blue-50 rounded-lg",children:e.jsx(F,{className:"w-5 h-5 text-blue-600"})}),e.jsxs("div",{children:[e.jsx("p",{className:"text-xs text-gray-500",children:"관리자페이지"}),e.jsx("p",{className:"text-xl font-bold text-gray-900",children:r.adminToday})]})]})}),e.jsx("div",{className:"bg-white rounded-xl border border-gray-200 p-4",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"p-2 bg-orange-100 rounded-lg",children:e.jsx(F,{className:"w-5 h-5 text-orange-600"})}),e.jsxs("div",{children:[e.jsx("p",{className:"text-xs text-gray-500",children:"순 방문자"}),e.jsx("p",{className:"text-xl font-bold text-gray-900",children:r.uniqueUsers})]})]})}),e.jsx("div",{className:"bg-white rounded-xl border border-gray-200 p-4",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"p-2 bg-red-100 rounded-lg",children:e.jsx(be,{className:"w-5 h-5 text-red-600"})}),e.jsxs("div",{children:[e.jsx("p",{className:"text-xs text-gray-500",children:"피크 시간"}),e.jsxs("p",{className:"text-xl font-bold text-gray-900",children:[r.peakHour,"시"]})]})]})}),e.jsx("div",{className:"bg-white rounded-xl border border-gray-200 p-4",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"p-2 bg-cyan-100 rounded-lg",children:e.jsx(ye,{className:"w-5 h-5 text-cyan-600"})}),e.jsxs("div",{children:[e.jsx("p",{className:"text-xs text-gray-500",children:"시간당 평균"}),e.jsx("p",{className:"text-xl font-bold text-gray-900",children:r.avgPerHour})]})]})})]}),b==="dashboard"?e.jsxs("div",{className:"grid grid-cols-3 gap-6",children:[e.jsxs("div",{className:"col-span-2 bg-white rounded-xl border border-gray-200 p-6",children:[e.jsx("h3",{className:"text-lg font-semibold text-gray-900 mb-4",children:"시간대별 접속 현황"}),e.jsx("div",{className:"h-48 flex items-end gap-1",children:E.map(s=>e.jsxs("div",{className:"flex-1 flex flex-col items-center",children:[e.jsx("div",{className:"w-full bg-blue-500 rounded-t transition-all hover:bg-blue-600",style:{height:`${s.count/Z*100}%`,minHeight:s.count>0?"4px":"0"},title:`${s.hour}시: ${s.count}건`}),e.jsx("span",{className:"text-[10px] text-gray-400 mt-1",children:s.hour})]},s.hour))}),e.jsx("p",{className:"text-xs text-gray-400 text-center mt-2",children:"시간 (0~23시)"})]}),e.jsxs("div",{className:"bg-white rounded-xl border border-gray-200 p-6",children:[e.jsx("h3",{className:"text-lg font-semibold text-gray-900 mb-4",children:"최근 접속자"}),e.jsx("div",{className:"space-y-3",children:H.length===0?e.jsx("p",{className:"text-sm text-gray-500 text-center py-4",children:"접속 기록이 없습니다"}):H.map((s,l)=>e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-8 h-8 bg-gray-100 rounded-full flex items-center justify-center text-sm font-medium text-gray-600",children:s.name.charAt(0)}),e.jsx("span",{className:"text-sm font-medium text-gray-900",children:s.name})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[A(s.platform),e.jsx("span",{className:"text-xs text-gray-400",children:s.time})]})]},l))})]}),e.jsxs("div",{className:"col-span-2 bg-white rounded-xl border border-gray-200 p-6",children:[e.jsx("h3",{className:"text-lg font-semibold text-gray-900 mb-4",children:"인기 페이지 TOP 10"}),e.jsx("div",{className:"space-y-2",children:y.length===0?e.jsx("p",{className:"text-sm text-gray-500 text-center py-4",children:"데이터가 없습니다"}):y.map((s,l)=>{var c;return e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"w-6 h-6 bg-blue-100 text-blue-700 rounded-full flex items-center justify-center text-xs font-bold",children:l+1}),e.jsxs("div",{className:"flex-1",children:[e.jsxs("div",{className:"flex items-center justify-between mb-1",children:[e.jsx("span",{className:"text-sm text-gray-700 truncate max-w-[300px]",children:s.page}),e.jsxs("span",{className:"text-sm font-medium text-gray-900",children:[s.count,"회"]})]}),e.jsx("div",{className:"h-1.5 bg-gray-100 rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full bg-blue-500 rounded-full",style:{width:`${s.count/(((c=y[0])==null?void 0:c.count)||1)*100}%`}})})]})]},l)})})]}),e.jsxs("div",{className:"bg-white rounded-xl border border-gray-200 p-6",children:[e.jsx("h3",{className:"text-lg font-semibold text-gray-900 mb-4",children:"플랫폼별 비율"}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex justify-between text-sm mb-1",children:[e.jsx("span",{className:"text-gray-600",children:"홈페이지"}),e.jsxs("span",{className:"font-medium",children:[r.totalToday?Math.round(r.webToday/r.totalToday*100):0,"%"]})]}),e.jsx("div",{className:"h-3 bg-gray-100 rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full bg-blue-500 rounded-full transition-all",style:{width:`${r.totalToday?r.webToday/r.totalToday*100:0}%`}})})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex justify-between text-sm mb-1",children:[e.jsx("span",{className:"text-gray-600",children:"관리자페이지"}),e.jsxs("span",{className:"font-medium",children:[r.totalToday?Math.round(r.adminToday/r.totalToday*100):0,"%"]})]}),e.jsx("div",{className:"h-3 bg-gray-100 rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full bg-purple-500 rounded-full transition-all",style:{width:`${r.totalToday?r.adminToday/r.totalToday*100:0}%`}})})]})]}),e.jsx("div",{className:"mt-6 pt-4 border-t border-gray-100",children:e.jsxs("div",{className:"flex items-center justify-center gap-6",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-3 h-3 bg-blue-500 rounded-full"}),e.jsxs("span",{className:"text-xs text-gray-500",children:["홈페이지 (",r.webToday,")"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-3 h-3 bg-purple-500 rounded-full"}),e.jsxs("span",{className:"text-xs text-gray-500",children:["관리자 (",r.adminToday,")"]})]})]})})]}),e.jsxs("div",{className:"bg-white rounded-xl border border-gray-200 p-6",children:[e.jsx("h3",{className:"text-lg font-semibold text-gray-900 mb-1",children:e.jsxs("span",{className:"inline-flex items-center gap-2",children:[e.jsx("div",{className:"w-3 h-3 bg-blue-500 rounded-full"}),"홈페이지 페이지별"]})}),e.jsxs("p",{className:"text-xs text-gray-400 mb-4",children:["총 ",N.reduce((s,l)=>s+l.count,0),"건"]}),e.jsx("div",{className:"space-y-2",children:N.length===0?e.jsx("p",{className:"text-sm text-gray-500 text-center py-4",children:"데이터가 없습니다"}):N.map((s,l)=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"w-16 text-xs text-gray-500 truncate",children:s.page}),e.jsxs("div",{className:"flex-1 h-5 bg-gray-100 rounded-full overflow-hidden relative",children:[e.jsx("div",{className:"h-full bg-blue-400 rounded-full transition-all",style:{width:`${s.percent}%`}}),e.jsxs("span",{className:"absolute inset-0 flex items-center justify-center text-[10px] font-medium",children:[s.count,"건 (",s.percent,"%)"]})]})]},l))})]}),e.jsxs("div",{className:"bg-white rounded-xl border border-gray-200 p-6",children:[e.jsx("h3",{className:"text-lg font-semibold text-gray-900 mb-1",children:e.jsxs("span",{className:"inline-flex items-center gap-2",children:[e.jsx("div",{className:"w-3 h-3 bg-purple-500 rounded-full"}),"관리자 페이지별"]})}),e.jsxs("p",{className:"text-xs text-gray-400 mb-4",children:["총 ",f.reduce((s,l)=>s+l.count,0),"건"]}),e.jsx("div",{className:"space-y-2",children:f.length===0?e.jsx("p",{className:"text-sm text-gray-500 text-center py-4",children:"데이터가 없습니다"}):f.map((s,l)=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"w-16 text-xs text-gray-500 truncate",children:s.page}),e.jsxs("div",{className:"flex-1 h-5 bg-gray-100 rounded-full overflow-hidden relative",children:[e.jsx("div",{className:"h-full bg-purple-400 rounded-full transition-all",style:{width:`${s.percent}%`}}),e.jsxs("span",{className:"absolute inset-0 flex items-center justify-center text-[10px] font-medium",children:[s.count,"건 (",s.percent,"%)"]})]})]},l))})]})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-4 bg-white p-4 rounded-xl border border-gray-200",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Ne,{className:"w-4 h-4 text-gray-400"}),e.jsxs("select",{value:p,onChange:s=>K(s.target.value),className:"border border-gray-300 rounded-lg px-3 py-1.5 text-sm",children:[e.jsx("option",{value:"today",children:"오늘"}),e.jsx("option",{value:"week",children:"최근 7일"}),e.jsx("option",{value:"month",children:"최근 30일"})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(S,{className:"w-4 h-4 text-gray-400"}),e.jsxs("select",{value:g,onChange:s=>B(s.target.value),className:"border border-gray-300 rounded-lg px-3 py-1.5 text-sm",children:[e.jsx("option",{value:"all",children:"전체"}),e.jsx("option",{value:"web",children:"홈페이지"}),e.jsx("option",{value:"admin",children:"관리자페이지"})]})]}),e.jsxs("span",{className:"text-sm text-gray-500",children:["총 ",h.length,"건"]})]}),e.jsx("div",{className:"bg-white rounded-xl border border-gray-200 overflow-hidden",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full",children:[e.jsx("thead",{className:"bg-gray-50 border-b border-gray-200",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"접속시간"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"플랫폼"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"사용자"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"페이지"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"기기"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"브라우저"})]})}),e.jsx("tbody",{className:"divide-y divide-gray-200",children:C?e.jsx("tr",{children:e.jsxs("td",{colSpan:6,className:"px-4 py-8 text-center text-gray-500",children:[e.jsx(O,{className:"w-5 h-5 animate-spin mx-auto mb-2"}),"로딩 중..."]})}):h.length===0?e.jsx("tr",{children:e.jsx("td",{colSpan:6,className:"px-4 py-8 text-center text-gray-500",children:"접속 기록이 없습니다"})}):h.map(s=>e.jsxs("tr",{className:"hover:bg-gray-50",children:[e.jsx("td",{className:"px-4 py-3 text-sm text-gray-900 whitespace-nowrap",children:U(s.accessTime)}),e.jsx("td",{className:"px-4 py-3",children:A(s.platform)}),e.jsx("td",{className:"px-4 py-3",children:e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-gray-900",children:s.userName||"비회원"}),s.userEmail&&e.jsx("p",{className:"text-xs text-gray-500",children:s.userEmail})]})}),e.jsx("td",{className:"px-4 py-3 text-sm text-gray-600 max-w-[200px] truncate",children:s.page}),e.jsx("td",{className:"px-4 py-3",children:e.jsxs("div",{className:"flex items-center gap-2 text-gray-600",children:[X(s.deviceType),e.jsx("span",{className:"text-sm capitalize",children:s.deviceType})]})}),e.jsx("td",{className:"px-4 py-3 text-xs text-gray-500 max-w-[200px] truncate",children:s.userAgent.
2split(" ").slice(0,3).join(" ")})]},s.id))})]})})})]})]})}export{Ce as AccessLogsPage};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.