2 lines
14 KiB
JavaScript
2 lines
14 KiB
JavaScript
import{q as Fe,r as Ue,v as Oe,x as Ge,y as Ze,l as je,A as He}from"./vendor-element-CJoVtPsD.js";import{a as Qe,_ as Ke,f as Ye}from"./index-ZQnpYe51.js";import{f as Je}from"./email-D8pS1Pbx.js";import{f as Xe,a as et,b as tt,c as lt,d as at}from"./tasks-BrCJEcYb.js";import{f as st}from"./system-DO-Wv0rM.js";import{M as ut}from"./MetricGrid-DBgW22G4.js";import{i as le,r as d,c as a,v as ot,Y as nt,aW as M,z as k,A as h,B as u,S as r,N as L,Q as p,R as ae,ak as se,L as x,P as ue,K as rt,E as it}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";async function ct(){const{data:G}=await Qe.get("/browser_pool/stats");return G}const vt={class:"page-stack"},dt={class:"report-hero"},_t={class:"hero-head"},mt={class:"hero-main"},bt={class:"hero-meta app-muted"},pt={key:0},ft={key:1,class:"hero-dot"},ht={key:2},gt={class:"mobile-report"},kt={class:"mobile-module-head"},wt={class:"mobile-module-title"},yt={class:"mobile-module-desc app-muted"},xt={class:"mobile-metrics"},St={class:"mobile-metric-label app-muted"},qt={class:"mobile-metric-value"},$t={key:0,class:"module-extra-actions"},Mt={class:"request-dialog-summary app-muted"},Tt={class:"request-dialog-block"},Pt={class:"table-wrap"},Rt={class:"request-dialog-block"},Ct={class:"table-wrap"},At=5e3,Nt=2e4,Lt={__name:"ReportPage",setup(G){const oe=le("refreshStats",null),ne=le("adminStats",null),I=d(!1),W=d(!1),S=d(""),D=d(null),_=d(null),c=d(null),g=d(null),f=d(null),R=d(null),q=d(null),m=d(null),o=d(null),E=d(!1);d("running");function re(){try{S.value=new Date().toLocaleString("zh-CN",{hour12:!1,timeZone:"Asia/Shanghai"})}catch{S.value=""}}function t(l){const e=Number(l);return Number.isFinite(e)?e:0}function ie(l){const e=String(l??"").trim();if(!e)return 0;const s=e.endsWith("%")?e.slice(0,-1):e,n=Number(s);return!Number.isFinite(n)||n<0?0:n>1e3?1e3:n}function z(l){return`${Math.round(ie(l))}%`}function w(l){const e=Number(l);return!Number.isFinite(e)||e<0?"-":e>=100?`${Math.round(e)}ms`:`${e.toFixed(1)}ms`}function ce(l){const e=Number(l);if(!Number.isFinite(e)||e<=0)return"-";try{return new Date(e*1e3).toLocaleTimeString("zh-CN",{hour12:!1,timeZone:"Asia/Shanghai"})}catch{return"-"}}function ve(l){const e=Number(l);if(!Number.isFinite(e)||e<=0)return"-";try{return new Date(e*1e3).toLocaleString("zh-CN",{hour12:!1,timeZone:"Asia/Shanghai"})}catch{return"-"}}function de(l){const e=String(l??"").trim();return!e||e==="manual"?"手动":e==="scheduled"?"系统定时":e==="batch"?"批量执行":e==="resumed"?"断点续跑":e.startsWith("user_scheduled:")?"用户定时":e}const Z=a(()=>{const l=ne?.value||{},e=t(_.value?.max_concurrent);return[{label:"总用户数",value:t(l.total_users),icon:Fe,tone:"blue"},{label:"今日注册",value:t(l.new_users_today),icon:Ue,tone:"green"},{label:"近7天注册",value:t(l.new_users_7d),icon:Oe,tone:"purple"},{label:"总账号数",value:t(l.total_accounts),icon:Ge,tone:"cyan"},{label:"VIP用户",value:t(l.vip_users),icon:Ze,tone:"orange"},{label:"运行中任务",value:t(_.value?.running_count),icon:je,tone:"green",sub:e?`并发上限 ${e}`:""},{label:"排队任务",value:t(_.value?.queuing_count),icon:He,tone:"purple"}]}),b=a(()=>D.value?.today||{}),y=a(()=>D.value?.total||{});a(()=>_.value?.running||[]);const C=a(()=>_.value?.queuing||[]),_e=a(()=>t(_.value?.running_count)),me=a(()=>t(_.value?.queuing_count)),be=a(()=>{const l=q.value?.workers;return Array.isArray(l)?[...l].sort((e,s)=>t(e?.worker_id)-t(s?.worker_id)):[]}),j=a(()=>t(q.value?.total_workers)),B=a(()=>be.value.filter(l=>!!l?.has_browser).length),H=a(()=>t(q.value?.idle_workers)),Q=a(()=>t(q.value?.queue_size)),V=a(()=>t(q.value?.active_workers)),K=a(()=>{const l=t(b.value.success_tasks),e=t(b.value.failed_tasks),s=l+e;return s>0?Math.round(l/s*1e3)/10:0}),F=a(()=>t(c.value?.success_rate));a(()=>[{label:"总任务",value:t(b.value.total_tasks),tone:"blue"},{label:"成功",value:t(b.value.success_tasks),tone:"green"},{label:"失败",value:t(b.value.failed_tasks),tone:"red"},{label:"浏览内容",value:t(b.value.total_items),tone:"purple"},{label:"查看附件",value:t(b.value.total_attachments),tone:"cyan"}]),a(()=>[{label:"总任务",value:t(y.value.total_tasks),tone:"blue"},{label:"成功",value:t(y.value.success_tasks),tone:"green"},{label:"失败",value:t(y.value.failed_tasks),tone:"red"},{label:"浏览内容",value:t(y.value.total_items),tone:"purple"},{label:"查看附件",value:t(y.value.total_attachments),tone:"cyan"}]),a(()=>[{label:"总发送",value:t(c.value?.total_sent),tone:"blue"},{label:"成功",value:t(c.value?.total_success),tone:"green"},{label:"失败",value:t(c.value?.total_failed),tone:"red"},{label:"成功率",value:`${F.value}%`,tone:"purple"}]),a(()=>[{label:"注册验证",value:t(c.value?.register_sent),tone:"cyan"},{label:"密码重置",value:t(c.value?.reset_sent),tone:"orange"},{label:"邮箱绑定",value:t(c.value?.bind_sent),tone:"purple"},{label:"任务完成",value:t(c.value?.task_complete_sent),tone:"green"}]),a(()=>[{label:"总反馈",value:t(g.value?.total),tone:"blue"},{label:"待处理",value:t(g.value?.pending),tone:"orange"},{label:"已回复",value:t(g.value?.replied),tone:"green"}]),a(()=>[{label:"总 Worker",value:j.value,tone:"blue"},{label:"活跃 Worker",value:B.value,tone:"green"},{label:"空闲 Worker",value:H.value,tone:"cyan"},{label:"忙碌 Worker",value:V.value,tone:"orange"},{label:"队列",value:Q.value,tone:"purple"}]);const pe=a(()=>(m.value?.schedule_enabled??0)===1),fe=a(()=>m.value?.schedule_time||"-"),he=a(()=>m.value?.schedule_browse_type||"-"),ge=a(()=>String(m.value?.schedule_weekdays||"").trim());a(()=>{const l=ge.value;if(!l)return"";const e={1:"周一",2:"周二",3:"周三",4:"周四",5:"周五",6:"周六",7:"周日"},s=l.split(",").map(n=>n.trim()).filter(Boolean);return s.length?s.map(n=>e[Number(n)]||n).join("、"):l});const ke=a(()=>(m.value?.proxy_enabled??0)===1);a(()=>m.value?.proxy_api_url||"");const Y=a(()=>t(m.value?.proxy_expire_minutes)),U=a(()=>t(m.value?.max_concurrent_global)),we=a(()=>t(m.value?.max_concurrent_per_account)),ye=a(()=>t(m.value?.max_screenshot_concurrent)),xe=a(()=>{const l=t(_.value?.running_count),e=t(_.value?.queuing_count),s=t(_.value?.max_concurrent);return`运行中 ${l} / 排队 ${e} / 并发上限 ${s||U.value||"-"}`}),Se=a(()=>Z.value.map(l=>({label:l.label,value:l.sub?`${l.value}(${l.sub})`:l.value}))),qe=a(()=>[{label:"今日总任务",value:t(b.value.total_tasks)},{label:"今日成功",value:t(b.value.success_tasks)},{label:"今日失败",value:t(b.value.failed_tasks)},{label:"今日成功率",value:`${K.value}%`},{label:"累计任务",value:t(y.value.total_tasks)},{label:"累计成功",value:t(y.value.success_tasks)}]),$e=a(()=>[{label:"运行中",value:_e.value},{label:"排队中",value:me.value},{label:"并发上限",value:t(_.value?.max_concurrent)||U.value||"-"},{label:"排队首条来源",value:de(C.value[0]?.source)},{label:"排队首条状态",value:C.value[0]?.detail_status||C.value[0]?.status||"-"},{label:"最长等待",value:C.value[0]?.elapsed_display||"-"}]),Me=a(()=>[{label:"总发送",value:t(c.value?.total_sent)},{label:"成功",value:t(c.value?.total_success)},{label:"失败",value:t(c.value?.total_failed)},{label:"成功率",value:`${F.value}%`},{label:"注册验证",value:t(c.value?.register_sent)},{label:"重置密码",value:t(c.value?.reset_sent)}]),Te=a(()=>[{label:"总反馈",value:t(g.value?.total)},{label:"待处理",value:t(g.value?.pending)},{label:"已回复",value:t(g.value?.replied)}]),Pe=a(()=>[{label:"CPU",value:z(f.value?.cpu_percent)},{label:"内存",value:z(f.value?.memory_percent)},{label:"磁盘",value:z(f.value?.disk_percent)},{label:"容器状态",value:R.value?.status||"-"},{label:"容器名",value:R.value?.container_name||"-"},{label:"容器运行",value:R.value?.uptime||"-"}]),Re=a(()=>[{label:"总 Worker",value:j.value},{label:"活跃 Worker",value:B.value},{label:"忙碌 Worker",value:V.value},{label:"空闲 Worker",value:H.value},{label:"任务队列",value:Q.value}]),Ce=a(()=>{const l=o.value?.top_paths;return Array.isArray(l)?l.slice(0,3):[]}),Ae=a(()=>{const l=[{label:"总请求",value:t(o.value?.total_requests)},{label:"API请求",value:t(o.value?.api_requests)},{label:"慢请求",value:t(o.value?.slow_requests)},{label:"错误请求",value:t(o.value?.error_requests)}];return Ce.value.forEach((e,s)=>{const n=String(e?.path||"-");l.push({label:`慢接口${s+1}`,value:`${n} · 峰值 ${w(e?.max_ms)}`})}),l}),Ne=a(()=>{const l=w(o.value?.avg_duration_ms),e=w(o.value?.max_duration_ms),s=ce(o.value?.last_request_ts),n=w(o.value?.slow_threshold_ms);return`均值 ${l} · 峰值 ${e} · 慢阈 ${n} · 最近 ${s}`}),Le=a(()=>(Array.isArray(o.value?.top_paths)?o.value.top_paths:[]).map((e,s)=>({rank:s+1,path:String(e?.path||"-"),count:t(e?.count),avg_ms:w(e?.avg_ms),max_ms:w(e?.max_ms),status_5xx:t(e?.status_5xx)}))),Ie=a(()=>[...Array.isArray(o.value?.recent_slow)?o.value.recent_slow:[]].sort((e,s)=>Number(s?.time||0)-Number(e?.time||0)).map(e=>({time_text:ve(e?.time),method:String(e?.method||"-").toUpperCase(),path:String(e?.path||"-"),status:t(e?.status),duration_ms:w(e?.duration_ms)})));function We(l){const e=t(l);return e>=500?"danger":e>=400?"warning":e>=300?"info":"success"}function De(){E.value=!0}const Ee=a(()=>[{label:"定时任务",value:pe.value?"启用":"关闭"},{label:"执行时间",value:fe.value||"-"},{label:"浏览类型",value:he.value||"-"},{label:"代理",value:ke.value?"启用":"关闭"},{label:"代理有效期",value:Y.value?`${Y.value} 分钟`:"-"},{label:"全局并发",value:U.value||"-"},{label:"单账号并发",value:we.value||"-"},{label:"截图并发",value:ye.value||"-"}]),ze=a(()=>[{key:"overview",title:"平台概览",desc:S.value?`更新 ${S.value}`:"核心指标",tone:"blue",items:Se.value},{key:"task",title:"任务概览",desc:t(b.value.total_tasks)>0?`今日成功率 ${K.value}%`:"今日暂无任务",tone:"purple",items:qe.value},{key:"queue",title:"队列监控",desc:xe.value,tone:"blue",items:$e.value},{key:"email",title:"邮件报表",desc:`成功率 ${F.value}%`,tone:"cyan",items:Me.value},{key:"feedback",title:"反馈概览",desc:`待处理 ${t(g.value?.pending)} 条`,tone:"orange",items:Te.value},{key:"resource",title:"系统资源",desc:f.value?.uptime?`运行 ${f.value.uptime}`:"运行状态获取中",tone:"green",items:Pe.value},{key:"request",title:"接口性能",desc:Ne.value,tone:"purple",items:Ae.value},{key:"worker",title:"截图线程池",desc:`活跃 ${B.value} · 忙碌 ${V.value}`,tone:"cyan",items:Re.value},{key:"config",title:"配置概览",desc:"并发 / 代理 / 定时任务",tone:"red",items:Ee.value}]);async function J(l={}){const e=l.showLoading??!0;if(!W.value){W.value=!0,e&&(I.value=!0);try{const[s,n,v,P,A,N,i,$,te]=await Promise.allSettled([Xe(),et(),Je(),Ye(),tt(),lt(),ct(),at(),st()]);s.status==="fulfilled"&&(D.value=s.value),n.status==="fulfilled"&&(_.value=n.value),v.status==="fulfilled"&&(c.value=v.value),P.status==="fulfilled"&&(g.value=P.value),A.status==="fulfilled"&&(f.value=A.value),N.status==="fulfilled"&&(R.value=N.value),i.status==="fulfilled"&&(q.value=i.value),$.status==="fulfilled"&&(o.value=$.value),te.status==="fulfilled"&&(m.value=te.value),await oe?.(),re()}finally{W.value=!1,e&&(I.value=!1)}}}let T=null;function Be(){return typeof document>"u"?!1:document.visibilityState==="hidden"}function Ve(){return Be()?Nt:At}function X(){T&&(clearTimeout(T),T=null)}function O(){X(),T=window.setTimeout(async()=>{T=null,await J({showLoading:!1}).catch(()=>{}),O()},Ve())}function ee(){O()}return ot(()=>{J({showLoading:!1}).catch(()=>{}).finally(()=>{O()}),window.addEventListener("visibilitychange",ee)}),nt(()=>{X(),window.removeEventListener("visibilitychange",ee)}),(l,e)=>{const s=M("el-button"),n=M("el-card"),v=M("el-table-column"),P=M("el-table"),A=M("el-tag"),N=M("el-dialog");return h(),k("div",vt,[u("section",dt,[u("div",_t,[u("div",mt,[e[1]||(e[1]=u("h2",null,"报表中心",-1)),u("div",bt,[S.value?(h(),k("span",pt,"更新时间:"+p(S.value),1)):L("",!0),f.value?.uptime?(h(),k("span",ft,"·")):L("",!0),f.value?.uptime?(h(),k("span",ht,"运行 "+p(f.value.uptime),1)):L("",!0)])])]),r(ut,{class:"hero-overview-grid",items:Z.value,loading:I.value,"min-width":165},null,8,["items","loading"])]),u("section",gt,[(h(!0),k(ae,null,se(ze.value,i=>(h(),rt(n,{key:i.key,shadow:"never",class:it(["mobile-module-card",`mobile-tone-${i.tone}`]),"body-style":{padding:"12px"}},{default:x(()=>[u("div",kt,[u("div",wt,p(i.title),1),u("div",yt,p(i.desc),1)]),u("div",xt,[(h(!0),k(ae,null,se(i.items,$=>(h(),k("div",{key:`${i.key}-${$.label}`,class:"mobile-metric-item"},[u("div",St,p($.label),1),u("div",qt,p($.value),1)]))),128))]),i.key==="request"?(h(),k("div",$t,[r(s,{size:"small",type:"primary",plain:"",onClick:De},{default:x(()=>[...e[2]||(e[2]=[ue("查看慢接口详情",-1)])]),_:1})])):L("",!0)]),_:2},1032,["class"]))),128))]),r(N,{modelValue:E.value,"onUpdate:modelValue":e[0]||(e[0]=i=>E.value=i),title:"慢接口详情",width:"min(1080px, 96vw)"},{default:x(()=>[u("div",Mt,[u("span",null,"总请求:"+p(t(o.value?.total_requests)),1),u("span",null,"API请求:"+p(t(o.value?.api_requests)),1),u("span",null,"慢请求:"+p(t(o.value?.slow_requests)),1),u("span",null,"错误请求:"+p(t(o.value?.error_requests)),1)]),u("div",Tt,[e[3]||(e[3]=u("div",{class:"request-dialog-title"},"慢接口排行榜",-1)),u("div",Pt,[r(P,{data:Le.value,size:"small","max-height":"280"},{default:x(()=>[r(v,{prop:"rank",label:"#",width:"60"}),r(v,{prop:"path",label:"接口路径","min-width":"340","show-overflow-tooltip":""}),r(v,{prop:"count",label:"请求数",width:"100"}),r(v,{prop:"avg_ms",label:"平均耗时",width:"120"}),r(v,{prop:"max_ms",label:"峰值耗时",width:"120"}),r(v,{prop:"status_5xx",label:"5xx",width:"90"})]),_:1},8,["data"])])]),u("div",Rt,[e[4]||(e[4]=u("div",{class:"request-dialog-title"},"最近慢请求",-1)),u("div",Ct,[r(P,{data:Ie.value,size:"small","max-height":"320"},{default:x(()=>[r(v,{prop:"time_text",label:"时间",width:"180"}),r(v,{prop:"method",label:"方法",width:"90"}),r(v,{prop:"path",label:"接口路径","min-width":"320","show-overflow-tooltip":""}),r(v,{label:"状态",width:"100"},{default:x(i=>[r(A,{size:"small",type:We(i.row.status)},{default:x(()=>[ue(p(i.row.status||"-"),1)]),_:2},1032,["type"])]),_:1}),r(v,{prop:"duration_ms",label:"耗时",width:"110"})]),_:1},8,["data"])])])]),_:1},8,["modelValue"])])}}},Ot=Ke(Lt,[["__scopeId","data-v-f984ef82"]]);export{Ot as default};
|