v0.3.20: 每日汇报系统 — 每天8点自动收集前一日数据并推送汇总报告

新增:
- src/services/daily-report.service.ts (核心服务: 数据收集/报告生成/格式化/调度器)
- API: GET/PUT daily-report/config, GET daily-report/preview, POST daily-report/test, GET daily-report/last-run
- 前端: 侧边栏"📊 每日汇报"菜单 + SystemConfig.vue 配置面板(时间/内容开关/预览/测试发送)
- main.ts: 每60秒检查调度, 08:00-08:04 窗口内运行

报告内容: 搜索统计/转存统计(成功率)/各网盘容量和活跃状态/用户数
This commit is contained in:
2026-05-17 17:10:39 +08:00
parent 95df193e26
commit 0e0cad1271
45 changed files with 622 additions and 64 deletions

View File

@@ -1 +1 @@
0.3.18
0.3.20

View File

@@ -1,4 +1,4 @@
import{x as qu,m as $_,h as Ce,B as Hg,d as q_,o as K_,a as Tt,c as Nt,K as ml,L as _l,b as Q,F as Vr,r as Gr,f as $t,w as qt,e as Oe,v as Ka,j as Hr,i as Q_,t as wt,n as Nc,y as Ei,l as zc,p as J_,E as j_,u as t1}from"./index-D279dJND.js";import{a as e1,h as r1,c as i1,i as n1,j as a1,t as o1,_ as s1}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import l1 from"./CloudConfig-BADbnuPV.js";import u1 from"./SystemConfig-C3is0eeI.js";import f1 from"./SaveRecords-DLmXAM3V.js";import"./index-Bn7NwETH.js";import"./CloudBadge-OZZzB6Zg.js";/*! *****************************************************************************
import{x as qu,m as $_,h as Ce,B as Hg,d as q_,o as K_,a as Tt,c as Nt,K as ml,L as _l,b as Q,F as Vr,r as Gr,f as $t,w as qt,e as Oe,v as Ka,j as Hr,i as Q_,t as wt,n as Nc,y as Ei,l as zc,p as J_,E as j_,u as t1}from"./index-D_srC3bj.js";import{a as e1,h as r1,c as i1,i as n1,j as a1,t as o1,_ as s1}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import l1 from"./CloudConfig-3znuBWUR.js";import u1 from"./SystemConfig-BbG7uBv0.js";import f1 from"./SaveRecords-B5cCMWaP.js";import"./index-Bn7NwETH.js";import"./CloudBadge-CbpZHKLy.js";/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any

View File

@@ -1 +0,0 @@
import{d as B,o as N,a as V,c as I,b as n,t as c,f as e,w as t,h as g,v as y,j as i,k as r,C as M,l,D as T,G as j,H as q,I as z,J as A,u as D,z as H}from"./index-D279dJND.js";import{a as L,_ as R}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const E={class:"admin-layout"},G={class:"admin-sidebar"},J={class:"sidebar-brand"},W={class:"sidebar-brand-text"},F={class:"sidebar-version"},K={class:"admin-content"},O={class:"content-header"},P={class:"content-breadcrumb"},Q={class:"breadcrumb-current"},U={class:"content-actions"},X={class:"content-body"},Y=B({__name:"AdminLayout",setup(Z){const d=D(),f=H(),m=g(""),_=g(""),b={dashboard:"仪表盘","cloud-configs-toggle":"网盘设置及授权","cloud-configs-cleanup":"存储清理","sys-site":"网站设置","sys-services":"外部服务 & 缓存","sys-strategy":"性能配置","sys-password":"修改管理员密码","sys-notify":"消息推送","save-records":"转存日志"},p=y(()=>{const o=f.name;return o==="admin-cloud-configs"?"cloud-configs-toggle":o==="admin-cleanup"?"cloud-configs-cleanup":o==="admin-system"?f.query.section||"sys-site":o==="admin-save-records"?"save-records":"dashboard"}),x=y(()=>b[p.value]||"仪表盘");function w(o){o==="dashboard"?d.push("/admin/dashboard"):o==="cloud-configs-toggle"?d.push("/admin/cloud-configs"):o==="cloud-configs-cleanup"?d.push("/admin/cleanup"):o.startsWith("sys-")?d.push({path:"/admin/system",query:{section:o}}):o==="save-records"?d.push("/admin/save-records"):o==="logout"&&(localStorage.removeItem("admin_token"),d.push("/admin/login"))}function h(){d.push("/")}return N(async()=>{try{const o=await L();m.value=o.site_name||""}catch{}try{const s=await(await fetch("/health")).json();_.value=s.version}catch{}}),(o,s)=>{const u=i("el-icon"),a=i("el-menu-item"),v=i("el-sub-menu"),C=i("el-menu"),k=i("el-button"),S=i("router-view");return V(),I("div",E,[n("aside",G,[n("div",J,[s[1]||(s[1]=n("div",{class:"sidebar-logo"},"☁️",-1)),n("div",W,[n("h2",null,c(m.value||"CloudSearch"),1),s[0]||(s[0]=n("p",null,"管理控制台",-1))])]),e(C,{"default-active":p.value,class:"sidebar-menu",onSelect:w},{default:t(()=>[e(a,{index:"dashboard"},{default:t(()=>[e(u,null,{default:t(()=>[e(r(M))]),_:1}),s[2]||(s[2]=n("span",null,"仪表盘",-1))]),_:1}),e(v,{index:"cloud-configs"},{title:t(()=>[e(u,null,{default:t(()=>[e(r(T))]),_:1}),s[3]||(s[3]=n("span",null,"网盘管理",-1))]),default:t(()=>[e(a,{index:"cloud-configs-toggle"},{default:t(()=>[...s[4]||(s[4]=[l("📋 设置及授权",-1)])]),_:1}),e(a,{index:"cloud-configs-cleanup"},{default:t(()=>[...s[5]||(s[5]=[l("🧹 存储清理",-1)])]),_:1})]),_:1}),e(v,{index:"system"},{title:t(()=>[e(u,null,{default:t(()=>[e(r(j))]),_:1}),s[6]||(s[6]=n("span",null,"系统设置",-1))]),default:t(()=>[e(a,{index:"sys-site"},{default:t(()=>[...s[7]||(s[7]=[l("🌐 网站设置",-1)])]),_:1}),e(a,{index:"sys-services"},{default:t(()=>[...s[8]||(s[8]=[l("🔗 外部服务 & 缓存",-1)])]),_:1}),e(a,{index:"sys-strategy"},{default:t(()=>[...s[9]||(s[9]=[l("⚡ 性能配置",-1)])]),_:1}),e(a,{index:"sys-password"},{default:t(()=>[...s[10]||(s[10]=[l("🔑 修改密码",-1)])]),_:1}),e(a,{index:"sys-notify"},{default:t(()=>[...s[11]||(s[11]=[l("📬 消息推送",-1)])]),_:1})]),_:1}),e(a,{index:"save-records"},{default:t(()=>[e(u,null,{default:t(()=>[e(r(q))]),_:1}),s[12]||(s[12]=n("span",null,"转存日志",-1))]),_:1}),s[14]||(s[14]=n("div",{class:"sidebar-spacer"},null,-1)),n("div",F,"v"+c(_.value),1),e(a,{index:"logout"},{default:t(()=>[e(u,null,{default:t(()=>[e(r(z))]),_:1}),s[13]||(s[13]=n("span",null,"退出登录",-1))]),_:1})]),_:1},8,["default-active"])]),n("div",K,[n("header",O,[n("div",P,[n("span",Q,c(x.value),1)]),n("div",U,[e(k,{text:"",size:"small",onClick:h},{default:t(()=>[e(u,null,{default:t(()=>[e(r(A))]),_:1}),s[15]||(s[15]=l(" 返回前台 ",-1))]),_:1})])]),n("main",X,[e(S)])])])}}}),es=R(Y,[["__scopeId","data-v-29c9acc0"]]);export{es as default};

View File

@@ -0,0 +1 @@
.admin-layout[data-v-469751e8]{display:flex;height:100vh;background:var(--bg-page)}.admin-sidebar[data-v-469751e8]{width:var(--sidebar-w);flex-shrink:0;display:flex;flex-direction:column;background:linear-gradient(180deg,#111827,#1e293b);position:relative;z-index:10}.sidebar-brand[data-v-469751e8]{display:flex;align-items:center;gap:10px;padding:20px 20px 16px;border-bottom:1px solid rgba(255,255,255,.06)}.sidebar-logo[data-v-469751e8]{font-size:28px;line-height:1;flex-shrink:0}.sidebar-brand-text h2[data-v-469751e8]{font-size:16px;font-weight:700;margin:0;color:#fff;line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-brand-text p[data-v-469751e8]{font-size:11px;margin:2px 0 0;color:#ffffff73;letter-spacing:1px}.sidebar-menu[data-v-469751e8]{flex:1;display:flex;flex-direction:column;background:transparent!important;border-right:none!important;padding:4px 0}.sidebar-menu[data-v-469751e8] .el-menu-item,.sidebar-menu[data-v-469751e8] .el-sub-menu__title{color:#ffffffa6;height:44px;line-height:44px;transition:all .2s ease;margin:0 6px;border-radius:var(--radius-sm)}.sidebar-menu[data-v-469751e8] .el-menu-item:hover,.sidebar-menu[data-v-469751e8] .el-sub-menu__title:hover{background:#ffffff14;color:#ffffffe6}.sidebar-menu[data-v-469751e8] .el-menu-item.is-active{color:#fff;background:linear-gradient(90deg,#409eff40,#6366f126);font-weight:500}.sidebar-menu[data-v-469751e8] .el-menu-item:after{display:none}.sidebar-menu[data-v-469751e8] .el-sub-menu .el-menu{background:#0003!important}.sidebar-menu[data-v-469751e8] .el-sub-menu .el-menu .el-menu-item{padding-left:52px!important;font-size:13px;height:38px;line-height:38px}.sidebar-menu[data-v-469751e8] .el-icon{font-size:16px}.sidebar-spacer[data-v-469751e8]{flex:1}.sidebar-version[data-v-469751e8]{text-align:center;font-size:11px;color:#ffffff40;padding:8px 0;letter-spacing:.5px}.admin-content[data-v-469751e8]{flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0}.content-header[data-v-469751e8]{display:flex;align-items:center;justify-content:space-between;padding:16px 28px;background:var(--bg-card);border-bottom:1px solid var(--border-light);flex-shrink:0}.content-breadcrumb[data-v-469751e8]{display:flex;align-items:center;gap:8px}.breadcrumb-current[data-v-469751e8]{font-size:18px;font-weight:700;color:var(--text)}.content-actions[data-v-469751e8] .el-button{color:var(--text-secondary);gap:4px}.content-body[data-v-469751e8]{flex:1;overflow-y:auto;padding:24px 28px}.content-body[data-v-469751e8] .save-bar{position:fixed;bottom:32px;right:32px;z-index:100;background:var(--bg-card);padding:12px 16px;border-radius:var(--radius-lg);border:1px solid var(--border);box-shadow:0 4px 16px #0000001f;display:flex;gap:10px;transition:box-shadow .2s,transform .2s}.content-body[data-v-469751e8] .save-bar:hover{box-shadow:0 6px 24px #0000002e;transform:translateY(-2px)}

View File

@@ -1 +0,0 @@
.admin-layout[data-v-29c9acc0]{display:flex;height:100vh;background:var(--bg-page)}.admin-sidebar[data-v-29c9acc0]{width:var(--sidebar-w);flex-shrink:0;display:flex;flex-direction:column;background:linear-gradient(180deg,#111827,#1e293b);position:relative;z-index:10}.sidebar-brand[data-v-29c9acc0]{display:flex;align-items:center;gap:10px;padding:20px 20px 16px;border-bottom:1px solid rgba(255,255,255,.06)}.sidebar-logo[data-v-29c9acc0]{font-size:28px;line-height:1;flex-shrink:0}.sidebar-brand-text h2[data-v-29c9acc0]{font-size:16px;font-weight:700;margin:0;color:#fff;line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-brand-text p[data-v-29c9acc0]{font-size:11px;margin:2px 0 0;color:#ffffff73;letter-spacing:1px}.sidebar-menu[data-v-29c9acc0]{flex:1;display:flex;flex-direction:column;background:transparent!important;border-right:none!important;padding:4px 0}.sidebar-menu[data-v-29c9acc0] .el-menu-item,.sidebar-menu[data-v-29c9acc0] .el-sub-menu__title{color:#ffffffa6;height:44px;line-height:44px;transition:all .2s ease;margin:0 6px;border-radius:var(--radius-sm)}.sidebar-menu[data-v-29c9acc0] .el-menu-item:hover,.sidebar-menu[data-v-29c9acc0] .el-sub-menu__title:hover{background:#ffffff14;color:#ffffffe6}.sidebar-menu[data-v-29c9acc0] .el-menu-item.is-active{color:#fff;background:linear-gradient(90deg,#409eff40,#6366f126);font-weight:500}.sidebar-menu[data-v-29c9acc0] .el-menu-item:after{display:none}.sidebar-menu[data-v-29c9acc0] .el-sub-menu .el-menu{background:#0003!important}.sidebar-menu[data-v-29c9acc0] .el-sub-menu .el-menu .el-menu-item{padding-left:52px!important;font-size:13px;height:38px;line-height:38px}.sidebar-menu[data-v-29c9acc0] .el-icon{font-size:16px}.sidebar-spacer[data-v-29c9acc0]{flex:1}.sidebar-version[data-v-29c9acc0]{text-align:center;font-size:11px;color:#ffffff40;padding:8px 0;letter-spacing:.5px}.admin-content[data-v-29c9acc0]{flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0}.content-header[data-v-29c9acc0]{display:flex;align-items:center;justify-content:space-between;padding:16px 28px;background:var(--bg-card);border-bottom:1px solid var(--border-light);flex-shrink:0}.content-breadcrumb[data-v-29c9acc0]{display:flex;align-items:center;gap:8px}.breadcrumb-current[data-v-29c9acc0]{font-size:18px;font-weight:700;color:var(--text)}.content-actions[data-v-29c9acc0] .el-button{color:var(--text-secondary);gap:4px}.content-body[data-v-29c9acc0]{flex:1;overflow-y:auto;padding:24px 28px}.content-body[data-v-29c9acc0] .save-bar{position:fixed;bottom:32px;right:32px;z-index:100;background:var(--bg-card);padding:12px 16px;border-radius:var(--radius-lg);border:1px solid var(--border);box-shadow:0 4px 16px #0000001f;display:flex;gap:10px;transition:box-shadow .2s,transform .2s}.content-body[data-v-29c9acc0] .save-bar:hover{box-shadow:0 6px 24px #0000002e;transform:translateY(-2px)}

View File

@@ -0,0 +1 @@
import{d as B,o as N,a as V,c as I,b as n,t as c,f as e,w as t,h as g,v as y,j as u,k as r,C as M,l,D as T,G as j,H as q,I as z,J as A,u as D,z as H}from"./index-D_srC3bj.js";import{a as L,_ as R}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const E={class:"admin-layout"},G={class:"admin-sidebar"},J={class:"sidebar-brand"},W={class:"sidebar-brand-text"},F={class:"sidebar-version"},K={class:"admin-content"},O={class:"content-header"},P={class:"content-breadcrumb"},Q={class:"breadcrumb-current"},U={class:"content-actions"},X={class:"content-body"},Y=B({__name:"AdminLayout",setup(Z){const d=D(),f=H(),m=g(""),_=g(""),b={dashboard:"仪表盘","cloud-configs-toggle":"网盘设置及授权","cloud-configs-cleanup":"存储清理","sys-site":"网站设置","sys-services":"外部服务 & 缓存","sys-strategy":"性能配置","sys-password":"修改管理员密码","sys-notify":"消息推送","sys-daily-report":"每日汇报","save-records":"转存日志"},p=y(()=>{const o=f.name;return o==="admin-cloud-configs"?"cloud-configs-toggle":o==="admin-cleanup"?"cloud-configs-cleanup":o==="admin-system"?f.query.section||"sys-site":o==="admin-save-records"?"save-records":"dashboard"}),x=y(()=>b[p.value]||"仪表盘");function w(o){o==="dashboard"?d.push("/admin/dashboard"):o==="cloud-configs-toggle"?d.push("/admin/cloud-configs"):o==="cloud-configs-cleanup"?d.push("/admin/cleanup"):o.startsWith("sys-")?d.push({path:"/admin/system",query:{section:o}}):o==="save-records"?d.push("/admin/save-records"):o==="logout"&&(localStorage.removeItem("admin_token"),d.push("/admin/login"))}function h(){d.push("/")}return N(async()=>{try{const o=await L();m.value=o.site_name||""}catch{}try{const s=await(await fetch("/health")).json();_.value=s.version}catch{}}),(o,s)=>{const i=u("el-icon"),a=u("el-menu-item"),v=u("el-sub-menu"),C=u("el-menu"),k=u("el-button"),S=u("router-view");return V(),I("div",E,[n("aside",G,[n("div",J,[s[1]||(s[1]=n("div",{class:"sidebar-logo"},"☁️",-1)),n("div",W,[n("h2",null,c(m.value||"CloudSearch"),1),s[0]||(s[0]=n("p",null,"管理控制台",-1))])]),e(C,{"default-active":p.value,class:"sidebar-menu",onSelect:w},{default:t(()=>[e(a,{index:"dashboard"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(M))]),_:1}),s[2]||(s[2]=n("span",null,"仪表盘",-1))]),_:1}),e(v,{index:"cloud-configs"},{title:t(()=>[e(i,null,{default:t(()=>[e(r(T))]),_:1}),s[3]||(s[3]=n("span",null,"网盘管理",-1))]),default:t(()=>[e(a,{index:"cloud-configs-toggle"},{default:t(()=>[...s[4]||(s[4]=[l("📋 设置及授权",-1)])]),_:1}),e(a,{index:"cloud-configs-cleanup"},{default:t(()=>[...s[5]||(s[5]=[l("🧹 存储清理",-1)])]),_:1})]),_:1}),e(v,{index:"system"},{title:t(()=>[e(i,null,{default:t(()=>[e(r(j))]),_:1}),s[6]||(s[6]=n("span",null,"系统设置",-1))]),default:t(()=>[e(a,{index:"sys-site"},{default:t(()=>[...s[7]||(s[7]=[l("🌐 网站设置",-1)])]),_:1}),e(a,{index:"sys-services"},{default:t(()=>[...s[8]||(s[8]=[l("🔗 外部服务 & 缓存",-1)])]),_:1}),e(a,{index:"sys-strategy"},{default:t(()=>[...s[9]||(s[9]=[l("⚡ 性能配置",-1)])]),_:1}),e(a,{index:"sys-password"},{default:t(()=>[...s[10]||(s[10]=[l("🔑 修改密码",-1)])]),_:1}),e(a,{index:"sys-notify"},{default:t(()=>[...s[11]||(s[11]=[l("📬 消息推送",-1)])]),_:1}),e(a,{index:"sys-daily-report"},{default:t(()=>[...s[12]||(s[12]=[l("📊 每日汇报",-1)])]),_:1})]),_:1}),e(a,{index:"save-records"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(q))]),_:1}),s[13]||(s[13]=n("span",null,"转存日志",-1))]),_:1}),s[15]||(s[15]=n("div",{class:"sidebar-spacer"},null,-1)),n("div",F,"v"+c(_.value),1),e(a,{index:"logout"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(z))]),_:1}),s[14]||(s[14]=n("span",null,"退出登录",-1))]),_:1})]),_:1},8,["default-active"])]),n("div",K,[n("header",O,[n("div",P,[n("span",Q,c(x.value),1)]),n("div",U,[e(k,{text:"",size:"small",onClick:h},{default:t(()=>[e(i,null,{default:t(()=>[e(r(A))]),_:1}),s[16]||(s[16]=l(" 返回前台 ",-1))]),_:1})])]),n("main",X,[e(S)])])])}}}),es=R(Y,[["__scopeId","data-v-469751e8"]]);export{es as default};

View File

@@ -1 +1 @@
import{d as k,o as C,a as w,c as y,b as a,t as m,f as t,w as i,g as x,e as L,h as d,j as p,l as N,i as S,E as B}from"./index-D279dJND.js";import{a as E,d as M,_ as U}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const j={class:"admin-login-page"},q={class:"login-card"},A={class:"login-brand"},I={class:"login-title"},K={key:0,class:"error-msg"},R={class:"login-footer"},z=k({__name:"AdminLogin",setup(D){const f=d(),u=d(!1),c=d(""),g=d(""),v=d("");E().then(l=>{l.site_name&&(g.value=l.site_name)}).catch(()=>{});const s=S({username:"",password:""}),b={username:[{required:!0,message:"请输入用户名",trigger:"blur"}],password:[{required:!0,message:"请输入密码",trigger:"blur"}]};async function h(){var e,r,n;if(await((e=f.value)==null?void 0:e.validate().catch(()=>!1))){u.value=!0,c.value="";try{const o=await M(s.username,s.password);localStorage.setItem("admin_token",o.token),B.success("登录成功"),window.location.href="/admin"}catch(o){c.value=((n=(r=o==null?void 0:o.response)==null?void 0:r.data)==null?void 0:n.message)||(o==null?void 0:o.message)||"登录失败"}finally{u.value=!1}}}return C(async()=>{try{const e=await(await fetch("/health")).json();v.value=e.version||""}catch{}}),(l,e)=>{const r=p("el-input"),n=p("el-form-item"),o=p("el-button"),V=p("el-form");return w(),y("div",j,[e[4]||(e[4]=a("div",{class:"login-bg-pattern"},null,-1)),a("div",q,[a("div",A,[e[2]||(e[2]=a("div",{class:"login-logo"},"☁️",-1)),a("h1",I,m(g.value||"CloudSearch"),1),e[3]||(e[3]=a("p",{class:"login-subtitle"},"管理后台",-1))]),t(V,{ref_key:"formRef",ref:f,model:s,rules:b,"label-width":"0",size:"large",onKeyup:x(h,["enter"])},{default:i(()=>[t(n,{prop:"username"},{default:i(()=>[t(r,{modelValue:s.username,"onUpdate:modelValue":e[0]||(e[0]=_=>s.username=_),placeholder:"用户名","prefix-icon":"User"},null,8,["modelValue"])]),_:1}),t(n,{prop:"password"},{default:i(()=>[t(r,{modelValue:s.password,"onUpdate:modelValue":e[1]||(e[1]=_=>s.password=_),type:"password",placeholder:"密码","prefix-icon":"Lock","show-password":""},null,8,["modelValue"])]),_:1}),t(n,null,{default:i(()=>[t(o,{type:"primary",loading:u.value,class:"login-btn",onClick:h},{default:i(()=>[N(m(u.value?"登录中...":"登 录"),1)]),_:1},8,["loading"])]),_:1})]),_:1},8,["model"]),c.value?(w(),y("p",K,m(c.value),1)):L("",!0),a("p",R,"CloudSearch v"+m(v.value),1)])])}}}),G=U(z,[["__scopeId","data-v-bd0b6672"]]);export{G as default};
import{d as k,o as C,a as w,c as y,b as a,t as m,f as t,w as i,g as x,e as L,h as d,j as p,l as N,i as S,E as B}from"./index-D_srC3bj.js";import{a as E,d as M,_ as U}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const j={class:"admin-login-page"},q={class:"login-card"},A={class:"login-brand"},I={class:"login-title"},K={key:0,class:"error-msg"},R={class:"login-footer"},z=k({__name:"AdminLogin",setup(D){const f=d(),u=d(!1),c=d(""),g=d(""),v=d("");E().then(l=>{l.site_name&&(g.value=l.site_name)}).catch(()=>{});const s=S({username:"",password:""}),b={username:[{required:!0,message:"请输入用户名",trigger:"blur"}],password:[{required:!0,message:"请输入密码",trigger:"blur"}]};async function h(){var e,r,n;if(await((e=f.value)==null?void 0:e.validate().catch(()=>!1))){u.value=!0,c.value="";try{const o=await M(s.username,s.password);localStorage.setItem("admin_token",o.token),B.success("登录成功"),window.location.href="/admin"}catch(o){c.value=((n=(r=o==null?void 0:o.response)==null?void 0:r.data)==null?void 0:n.message)||(o==null?void 0:o.message)||"登录失败"}finally{u.value=!1}}}return C(async()=>{try{const e=await(await fetch("/health")).json();v.value=e.version||""}catch{}}),(l,e)=>{const r=p("el-input"),n=p("el-form-item"),o=p("el-button"),V=p("el-form");return w(),y("div",j,[e[4]||(e[4]=a("div",{class:"login-bg-pattern"},null,-1)),a("div",q,[a("div",A,[e[2]||(e[2]=a("div",{class:"login-logo"},"☁️",-1)),a("h1",I,m(g.value||"CloudSearch"),1),e[3]||(e[3]=a("p",{class:"login-subtitle"},"管理后台",-1))]),t(V,{ref_key:"formRef",ref:f,model:s,rules:b,"label-width":"0",size:"large",onKeyup:x(h,["enter"])},{default:i(()=>[t(n,{prop:"username"},{default:i(()=>[t(r,{modelValue:s.username,"onUpdate:modelValue":e[0]||(e[0]=_=>s.username=_),placeholder:"用户名","prefix-icon":"User"},null,8,["modelValue"])]),_:1}),t(n,{prop:"password"},{default:i(()=>[t(r,{modelValue:s.password,"onUpdate:modelValue":e[1]||(e[1]=_=>s.password=_),type:"password",placeholder:"密码","prefix-icon":"Lock","show-password":""},null,8,["modelValue"])]),_:1}),t(n,null,{default:i(()=>[t(o,{type:"primary",loading:u.value,class:"login-btn",onClick:h},{default:i(()=>[N(m(u.value?"登录中...":"登 录"),1)]),_:1},8,["loading"])]),_:1})]),_:1},8,["model"]),c.value?(w(),y("p",K,m(c.value),1)):L("",!0),a("p",R,"CloudSearch v"+m(v.value),1)])])}}}),G=U(z,[["__scopeId","data-v-bd0b6672"]]);export{G as default};

View File

@@ -1 +1 @@
import{C as s,b as a,a as n}from"./index-Bn7NwETH.js";import{d as l,a as t,c,p as d,k as o,e as r,l as u,t as m}from"./index-D279dJND.js";import{_}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const p=["src"],i=l({__name:"CloudBadge",props:{cloud_type:{},showIcon:{type:Boolean}},setup(e){return(C,y)=>(t(),c("span",{class:"cloud-badge",style:d({background:o(s)[e.cloud_type]})},[e.showIcon&&o(a)[e.cloud_type]?(t(),c("img",{key:0,src:o(a)[e.cloud_type],class:"badge-icon"},null,8,p)):r("",!0),u(" "+m(o(n)[e.cloud_type]),1)],4))}}),L=_(i,[["__scopeId","data-v-9106805f"]]);export{L as C};
import{C as s,b as a,a as n}from"./index-Bn7NwETH.js";import{d as l,a as t,c,p as d,k as o,e as r,l as u,t as m}from"./index-D_srC3bj.js";import{_}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const p=["src"],i=l({__name:"CloudBadge",props:{cloud_type:{},showIcon:{type:Boolean}},setup(e){return(C,y)=>(t(),c("span",{class:"cloud-badge",style:d({background:o(s)[e.cloud_type]})},[e.showIcon&&o(a)[e.cloud_type]?(t(),c("img",{key:0,src:o(a)[e.cloud_type],class:"badge-icon"},null,8,p)):r("",!0),u(" "+m(o(n)[e.cloud_type]),1)],4))}}),L=_(i,[["__scopeId","data-v-9106805f"]]);export{L as C};

View File

@@ -1,4 +1,4 @@
import{d as ke,o as L,m as ve,E as _,a as c,c as k,f as n,w as a,b as r,h as C,j as p,i as be,F as R,r as K,t as v,y as g,l as d,e as A,k as Ce,M as he,p as xe,n as H,K as Be,L as Te,v as h}from"./index-D279dJND.js";import{a as x}from"./index-Bn7NwETH.js";import{c as we,k as Fe,h as Ne,l as G,t as Ve,u as P,m as ze,n as Se,o as $e,_ as Ue}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import{C as De}from"./CloudBadge-OZZzB6Zg.js";const Ie={class:"cloud-config"},Me={class:"cloud-toggle-grid"},Oe=["src"],qe={class:"cloud-label"},Ee={class:"toolbar"},Le={key:0,class:"nickname-text"},Re={key:0,class:"promotion-text"},Ke={key:0,class:"uid-cell"},Ae={key:0,class:"verifying"},He={key:0,class:"storage-cell"},Ge={class:"storage-bar-wrap"},Pe={class:"storage-text"},je={class:"storage-used"},Je={class:"storage-total"},Qe={class:"storage-free"},We={key:0,class:"save-count"},Xe={style:{"line-height":"1.6"}},Ye={class:"cookie-tips-header"},Ze={class:"cookie-tips-title"},et=["innerHTML"],tt=ke({__name:"CloudConfig",setup(ot){const z=C([]),D=C(),F=C([]),B=C(!1),T=C(!1),b=C(null),l=be({cloud_type:"",nickname:"",promotion_account:"",is_transfer_enabled:!1,cookie:"",_verifying:!1,_storageUsed:"",_storageTotal:""}),j=h(()=>({cloud_type:[{required:!0,message:"请选择网盘类型",trigger:"change"}],nickname:[{required:!1,message:"请填写昵称(区分多个同类型网盘)",trigger:"blur"}],promotion_account:[{required:!0,message:"请填写推广平台及账号",trigger:"blur"}]})),J=h(()=>Object.entries(x)),Q=h(()=>{if(!l.cloud_type)return"请先选择网盘类型";const t=l.cloud_type;return t==="quark"||t==="baidu"?`请输入 ${x[t]||t} 的完整 Cookie`:b.value?"留空则保持原有":"输入完整 Cookie"}),W=h(()=>x[l.cloud_type]||l.cloud_type||""),X=h(()=>{const t=l.cloud_type;return t?{quark:`<li>在电脑上打开 <a href="https://pan.quark.cn" target="_blank">pan.quark.cn</a> 并登录你的夸克账号</li>
import{d as ke,o as L,m as ve,E as _,a as c,c as k,f as n,w as a,b as r,h as C,j as p,i as be,F as R,r as K,t as v,y as g,l as d,e as A,k as Ce,M as he,p as xe,n as H,K as Be,L as Te,v as h}from"./index-D_srC3bj.js";import{a as x}from"./index-Bn7NwETH.js";import{c as we,k as Fe,h as Ne,l as G,t as Ve,u as P,m as ze,n as Se,o as $e,_ as Ue}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import{C as De}from"./CloudBadge-CbpZHKLy.js";const Ie={class:"cloud-config"},Me={class:"cloud-toggle-grid"},Oe=["src"],qe={class:"cloud-label"},Ee={class:"toolbar"},Le={key:0,class:"nickname-text"},Re={key:0,class:"promotion-text"},Ke={key:0,class:"uid-cell"},Ae={key:0,class:"verifying"},He={key:0,class:"storage-cell"},Ge={class:"storage-bar-wrap"},Pe={class:"storage-text"},je={class:"storage-used"},Je={class:"storage-total"},Qe={class:"storage-free"},We={key:0,class:"save-count"},Xe={style:{"line-height":"1.6"}},Ye={class:"cookie-tips-header"},Ze={class:"cookie-tips-title"},et=["innerHTML"],tt=ke({__name:"CloudConfig",setup(ot){const z=C([]),D=C(),F=C([]),B=C(!1),T=C(!1),b=C(null),l=be({cloud_type:"",nickname:"",promotion_account:"",is_transfer_enabled:!1,cookie:"",_verifying:!1,_storageUsed:"",_storageTotal:""}),j=h(()=>({cloud_type:[{required:!0,message:"请选择网盘类型",trigger:"change"}],nickname:[{required:!1,message:"请填写昵称(区分多个同类型网盘)",trigger:"blur"}],promotion_account:[{required:!0,message:"请填写推广平台及账号",trigger:"blur"}]})),J=h(()=>Object.entries(x)),Q=h(()=>{if(!l.cloud_type)return"请先选择网盘类型";const t=l.cloud_type;return t==="quark"||t==="baidu"?`请输入 ${x[t]||t} 的完整 Cookie`:b.value?"留空则保持原有":"输入完整 Cookie"}),W=h(()=>x[l.cloud_type]||l.cloud_type||""),X=h(()=>{const t=l.cloud_type;return t?{quark:`<li>在电脑上打开 <a href="https://pan.quark.cn" target="_blank">pan.quark.cn</a> 并登录你的夸克账号</li>
<li> <code>F12</code> <strong> (Network)</strong> </li>
<li>刷新页面在请求列表中点击任意一个请求 <code>account/info</code></li>
<li>在右侧 <strong>请求头 (Request Headers)</strong> <code>Cookie</code> </li>

View File

@@ -1 +1 @@
import{d as K,o as G,a as n,c as a,b as o,F as w,t as c,e as h,f as v,w as f,g as Q,r as z,h as l,i as B,j as x,u as W,k as Y,s as J,l as D,n as I}from"./index-D279dJND.js";import{g as X,a as Z,_ as ee}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const te={class:"home-page"},se={class:"hero-section"},oe=["src","alt"],ne={key:1,class:"logo-text"},ae={class:"search-box"},ie={key:1,class:"quote-section"},ce={class:"quote-text"},le={class:"quote-author"},re={class:"content-section"},ue={key:0,class:"rankings-grid"},de={class:"panel-header"},_e={class:"panel-title"},he={class:"panel-tabs"},ve=["onClick"],pe=["onClick"],ge={class:"panel-body"},fe=["onClick"],me={class:"rank-name"},ye={class:"rank-cnt"},ke=["onClick"],Ce={class:"panel-footer"},be={key:0},we={key:1},xe={key:2},Ie={key:3},qe={class:"footer-time"},Ae={key:0,class:"site-footer"},Se={class:"footer-inner"},Ne={class:"footer-actions"},R=8,Te=K({__name:"HomePage",setup(Ve){const q=W(),m=l(""),u=l([]),d=B({}),_=B({}),p=l(""),y=l(""),k=l(""),A=l(!1),g=l(""),C=l(""),S=l(""),F={movie:"🎬",western_movie:"🎥",western_tv:"🌍",donghua:"🐉",global_anime:"🌐",tv:"📺",niche:"💎",hotsite:"🏆"};function L(e){return F[e]||"📋"}function j(e){const t=[];if(e.rating&&t.push(`${e.rating}`),e.searchCount>0){const i=e.searchCount;i>=1e8?t.push(`${(i/1e8).toFixed(1)}亿`):i>=1e4?t.push(`${(i/1e4).toFixed(0)}`):t.push(String(i))}return t.join(" ")||""}function N(e){return(_[e.category]||"hot")==="hot"?e.hot||[]:e.newest||[]}function E(e){const t=N(e);return d[e.category]?t:t.slice(0,R)}function H(e){return N(e).length>R&&!d[e.category]}function M(e){d[e]=!0}function T(e,t){_[e]=t,d[e]=!1}function O(){window.open("/disclaimer/","_blank")}G(async()=>{try{const t=await(await fetch("https://v1.hitokoto.cn/")).json();g.value=t.hitokoto||"",C.value=t.from_who||t.from||""}catch{g.value="学而时习之,不亦说乎。",C.value="孔子"}try{const[e,t]=await Promise.all([X(),Z()]);e.fetchedAt?(S.value=e.fetchedAt,u.value=e.categories||[]):u.value=Array.isArray(e)?e:[];for(const i of u.value)_[i.category]="hot",d[i.category]=!1;t.site_logo&&(p.value=t.site_logo),t.site_name&&(y.value=t.site_name),t.site_disclaimer&&(k.value=t.site_disclaimer),A.value=!0}catch(e){console.error("加载首页数据失败",e)}});function V(){const e=m.value.trim();e&&q.push("/search?q="+encodeURIComponent(e))}function P(e){q.push("/search?q="+encodeURIComponent(e))}return(e,t)=>{const i=x("el-icon"),U=x("el-input"),$=x("el-button");return n(),a("div",te,[o("div",se,[A.value?(n(),a(w,{key:0},[p.value?(n(),a("img",{key:0,src:p.value,alt:y.value||"CloudSearch",class:"logo-img",onError:t[0]||(t[0]=s=>{s.target.style.display="none",p.value=""})},null,40,oe)):(n(),a("div",ne,c(y.value||"CloudSearch"),1))],64)):h("",!0),o("div",ae,[v(U,{modelValue:m.value,"onUpdate:modelValue":t[1]||(t[1]=s=>m.value=s),placeholder:"搜索网盘资源,或粘贴视频/网盘链接...",size:"large",clearable:"",onKeyup:Q(V,["enter"])},{prefix:f(()=>[v(i,null,{default:f(()=>[v(Y(J))]),_:1})]),_:1},8,["modelValue"]),v($,{type:"primary",size:"large",onClick:V,class:"search-btn"},{default:f(()=>[...t[2]||(t[2]=[D(" 搜 索 ",-1)])]),_:1})]),g.value?(n(),a("div",ie,[o("span",ce,"「 "+c(g.value)+" 」",1),o("span",le,"---"+c(C.value),1)])):h("",!0)]),o("div",re,[u.value.length>0?(n(),a("div",ue,[(n(!0),a(w,null,z(u.value,s=>(n(),a("div",{key:s.category,class:"rank-panel"},[o("div",de,[o("span",_e,c(L(s.category))+" "+c(s.label),1),o("div",he,[o("span",{class:I(["panel-tab",{active:_[s.category]==="hot"}]),onClick:r=>T(s.category,"hot")},"热榜",10,ve),o("span",{class:I(["panel-tab",{active:_[s.category]==="newest"}]),onClick:r=>T(s.category,"newest")},"最新",10,pe)])]),o("div",ge,[(n(!0),a(w,null,z(E(s),(r,b)=>(n(),a("div",{key:s.category+"-"+b,class:"rank-item",onClick:$e=>P(r.keyword)},[o("span",{class:I(["rank-idx",{"top-three":b<3}])},c(b+1),3),o("span",me,c(r.keyword),1),o("span",ye,c(j(r)),1)],8,fe))),128)),H(s)?(n(),a("div",{key:0,class:"rank-expand",onClick:r=>M(s.category)}," 展开全部 ▼ ",8,ke)):h("",!0)]),o("div",Ce,[s.category==="hotsite"?(n(),a("span",be,"基于本站搜索数据")):s.category==="donghua"||s.category==="global_anime"?(n(),a("span",we,"数据来源Bilibili")):s.category==="movie"||s.category==="tv"?(n(),a("span",xe,"数据来源:百度")):(n(),a("span",Ie,"数据来源TMDB")),o("span",qe,c(S.value),1)])]))),128))])):h("",!0)]),k.value?(n(),a("div",Ae,[o("div",Se,c(k.value),1),o("div",Ne,[v($,{class:"footer-disclaimer-btn",size:"small",onClick:O},{default:f(()=>[...t[3]||(t[3]=[D("📜 免责声明",-1)])]),_:1})])])):h("",!0)])}}}),De=ee(Te,[["__scopeId","data-v-1f536d99"]]);export{De as default};
import{d as K,o as G,a as n,c as a,b as o,F as w,t as c,e as h,f as v,w as f,g as Q,r as z,h as l,i as B,j as x,u as W,k as Y,s as J,l as D,n as I}from"./index-D_srC3bj.js";import{g as X,a as Z,_ as ee}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const te={class:"home-page"},se={class:"hero-section"},oe=["src","alt"],ne={key:1,class:"logo-text"},ae={class:"search-box"},ie={key:1,class:"quote-section"},ce={class:"quote-text"},le={class:"quote-author"},re={class:"content-section"},ue={key:0,class:"rankings-grid"},de={class:"panel-header"},_e={class:"panel-title"},he={class:"panel-tabs"},ve=["onClick"],pe=["onClick"],ge={class:"panel-body"},fe=["onClick"],me={class:"rank-name"},ye={class:"rank-cnt"},ke=["onClick"],Ce={class:"panel-footer"},be={key:0},we={key:1},xe={key:2},Ie={key:3},qe={class:"footer-time"},Ae={key:0,class:"site-footer"},Se={class:"footer-inner"},Ne={class:"footer-actions"},R=8,Te=K({__name:"HomePage",setup(Ve){const q=W(),m=l(""),u=l([]),d=B({}),_=B({}),p=l(""),y=l(""),k=l(""),A=l(!1),g=l(""),C=l(""),S=l(""),F={movie:"🎬",western_movie:"🎥",western_tv:"🌍",donghua:"🐉",global_anime:"🌐",tv:"📺",niche:"💎",hotsite:"🏆"};function L(e){return F[e]||"📋"}function j(e){const t=[];if(e.rating&&t.push(`${e.rating}`),e.searchCount>0){const i=e.searchCount;i>=1e8?t.push(`${(i/1e8).toFixed(1)}亿`):i>=1e4?t.push(`${(i/1e4).toFixed(0)}`):t.push(String(i))}return t.join(" ")||""}function N(e){return(_[e.category]||"hot")==="hot"?e.hot||[]:e.newest||[]}function E(e){const t=N(e);return d[e.category]?t:t.slice(0,R)}function H(e){return N(e).length>R&&!d[e.category]}function M(e){d[e]=!0}function T(e,t){_[e]=t,d[e]=!1}function O(){window.open("/disclaimer/","_blank")}G(async()=>{try{const t=await(await fetch("https://v1.hitokoto.cn/")).json();g.value=t.hitokoto||"",C.value=t.from_who||t.from||""}catch{g.value="学而时习之,不亦说乎。",C.value="孔子"}try{const[e,t]=await Promise.all([X(),Z()]);e.fetchedAt?(S.value=e.fetchedAt,u.value=e.categories||[]):u.value=Array.isArray(e)?e:[];for(const i of u.value)_[i.category]="hot",d[i.category]=!1;t.site_logo&&(p.value=t.site_logo),t.site_name&&(y.value=t.site_name),t.site_disclaimer&&(k.value=t.site_disclaimer),A.value=!0}catch(e){console.error("加载首页数据失败",e)}});function V(){const e=m.value.trim();e&&q.push("/search?q="+encodeURIComponent(e))}function P(e){q.push("/search?q="+encodeURIComponent(e))}return(e,t)=>{const i=x("el-icon"),U=x("el-input"),$=x("el-button");return n(),a("div",te,[o("div",se,[A.value?(n(),a(w,{key:0},[p.value?(n(),a("img",{key:0,src:p.value,alt:y.value||"CloudSearch",class:"logo-img",onError:t[0]||(t[0]=s=>{s.target.style.display="none",p.value=""})},null,40,oe)):(n(),a("div",ne,c(y.value||"CloudSearch"),1))],64)):h("",!0),o("div",ae,[v(U,{modelValue:m.value,"onUpdate:modelValue":t[1]||(t[1]=s=>m.value=s),placeholder:"搜索网盘资源,或粘贴视频/网盘链接...",size:"large",clearable:"",onKeyup:Q(V,["enter"])},{prefix:f(()=>[v(i,null,{default:f(()=>[v(Y(J))]),_:1})]),_:1},8,["modelValue"]),v($,{type:"primary",size:"large",onClick:V,class:"search-btn"},{default:f(()=>[...t[2]||(t[2]=[D(" 搜 索 ",-1)])]),_:1})]),g.value?(n(),a("div",ie,[o("span",ce,"「 "+c(g.value)+" 」",1),o("span",le,"---"+c(C.value),1)])):h("",!0)]),o("div",re,[u.value.length>0?(n(),a("div",ue,[(n(!0),a(w,null,z(u.value,s=>(n(),a("div",{key:s.category,class:"rank-panel"},[o("div",de,[o("span",_e,c(L(s.category))+" "+c(s.label),1),o("div",he,[o("span",{class:I(["panel-tab",{active:_[s.category]==="hot"}]),onClick:r=>T(s.category,"hot")},"热榜",10,ve),o("span",{class:I(["panel-tab",{active:_[s.category]==="newest"}]),onClick:r=>T(s.category,"newest")},"最新",10,pe)])]),o("div",ge,[(n(!0),a(w,null,z(E(s),(r,b)=>(n(),a("div",{key:s.category+"-"+b,class:"rank-item",onClick:$e=>P(r.keyword)},[o("span",{class:I(["rank-idx",{"top-three":b<3}])},c(b+1),3),o("span",me,c(r.keyword),1),o("span",ye,c(j(r)),1)],8,fe))),128)),H(s)?(n(),a("div",{key:0,class:"rank-expand",onClick:r=>M(s.category)}," 展开全部 ▼ ",8,ke)):h("",!0)]),o("div",Ce,[s.category==="hotsite"?(n(),a("span",be,"基于本站搜索数据")):s.category==="donghua"||s.category==="global_anime"?(n(),a("span",we,"数据来源Bilibili")):s.category==="movie"||s.category==="tv"?(n(),a("span",xe,"数据来源:百度")):(n(),a("span",Ie,"数据来源TMDB")),o("span",qe,c(S.value),1)])]))),128))])):h("",!0)]),k.value?(n(),a("div",Ae,[o("div",Se,c(k.value),1),o("div",Ne,[v($,{class:"footer-disclaimer-btn",size:"small",onClick:O},{default:f(()=>[...t[3]||(t[3]=[D("📜 免责声明",-1)])]),_:1})])])):h("",!0)])}}}),De=ee(Te,[["__scopeId","data-v-1f536d99"]]);export{De as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
.el-card[data-v-6cdc2b1a]{margin-bottom:20px}.el-card[data-v-6cdc2b1a] .el-card__header{font-weight:600;font-size:15px}[data-v-6cdc2b1a] .el-divider__text.is-left{left:0;padding-left:0}.form-tip[data-v-6cdc2b1a]{font-size:12px;color:#909399;margin-top:4px}.fallback-upload-wrap[data-v-6cdc2b1a]{display:flex;flex-direction:column;gap:12px}.fallback-upload-row[data-v-6cdc2b1a]{display:flex;align-items:center;flex-wrap:wrap}.fallback-preview[data-v-6cdc2b1a]{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.fallback-preview img[data-v-6cdc2b1a]{max-width:100%;height:auto;max-height:120px;border-radius:8px;border:1px solid var(--border-color);background:#f0f0f0;object-fit:contain}.strategy-grid[data-v-6cdc2b1a]{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px 16px}.grid-cell[data-v-6cdc2b1a]{display:flex;flex-direction:column;gap:4px}.strategy-section[data-v-6cdc2b1a]{padding:0 4px}.field-block[data-v-6cdc2b1a]{margin:12px 0}.field-label-row[data-v-6cdc2b1a]{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.field-label[data-v-6cdc2b1a]{font-size:14px;font-weight:500;color:#303133;white-space:nowrap}.field-desc[data-v-6cdc2b1a]{font-size:12px;color:#909399;margin:3px 0 0;line-height:1.5}.keyword-input-row[data-v-6cdc2b1a]{display:flex;gap:8px;flex:1;min-width:200px}.tag-list[data-v-6cdc2b1a]{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}.tag-empty[data-v-6cdc2b1a]{font-size:13px;color:#c0c4cc;margin-top:8px}.filter-rule-help[data-v-6cdc2b1a]{margin-top:8px;padding:10px 12px;background:#f8f9fa;border-radius:8px;border:1px solid #e8e8e8}.filter-rule-help .help-title[data-v-6cdc2b1a]{font-weight:600;font-size:13px;margin:8px 0 4px;color:#333}.filter-rule-help .help-title[data-v-6cdc2b1a]:first-child{margin-top:0}.filter-rule-help .help-row[data-v-6cdc2b1a]{font-size:12px;color:#555;margin:3px 0;line-height:1.6}.filter-rule-help .help-row code[data-v-6cdc2b1a]{background:#eef1f5;padding:1px 5px;border-radius:3px;font-size:11px;font-family:monospace}.filter-rules-help[data-v-6cdc2b1a]{margin-top:8px;padding:12px;background:#f8f9fa;border-radius:8px;border:1px solid #e8e8e8}.help-title[data-v-6cdc2b1a]{font-weight:600;font-size:13px;margin:10px 0 6px;color:#333}.help-title[data-v-6cdc2b1a]:first-child{margin-top:0}.help-row[data-v-6cdc2b1a]{font-size:12px;color:#555;margin:3px 0;line-height:1.6}.help-row code[data-v-6cdc2b1a]{background:#eef1f5;padding:1px 5px;border-radius:3px;font-size:11px;font-family:monospace}.help-sample[data-v-6cdc2b1a]{background:#1e1e1e;color:#d4d4d4;padding:10px 14px;border-radius:6px;font-size:12px;line-height:1.6;overflow-x:auto;white-space:pre;margin:6px 0 0;font-family:monospace}.help-preview-row[data-v-6cdc2b1a]{font-size:13px;margin:4px 0;display:flex;align-items:center;gap:6px}.help-preview-label[data-v-6cdc2b1a]{color:#888;min-width:70px;font-size:12px}.help-preview-original[data-v-6cdc2b1a]{color:#e74c3c}.help-preview-filtered[data-v-6cdc2b1a]{color:#27ae60;font-weight:500}.filter-input-row[data-v-6cdc2b1a]{display:flex;gap:8px;width:100%;margin-bottom:8px}.filter-tag-list[data-v-6cdc2b1a]{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}.filter-empty[data-v-6cdc2b1a]{font-size:13px;color:#c0c4cc;padding:8px 0;margin-bottom:8px}.db-status-grid[data-v-6cdc2b1a]{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px;margin-top:8px}.db-stat-item[data-v-6cdc2b1a]{background:#f8f9fa;border-radius:10px;padding:16px 12px;text-align:center;border:1px solid #eee;transition:transform .15s,box-shadow .15s}.db-stat-item[data-v-6cdc2b1a]:hover{transform:translateY(-2px);box-shadow:0 4px 12px #0000000f}.db-stat-value[data-v-6cdc2b1a]{white-space:nowrap;font-size:24px;font-weight:700;color:#303133;margin-bottom:4px}.db-stat-value.text-success[data-v-6cdc2b1a]{color:#67c23a}.db-stat-value.text-warning[data-v-6cdc2b1a]{color:#e6a23c}.db-stat-label[data-v-6cdc2b1a]{font-size:12px;color:#909399}@media (max-width: 900px){.strategy-grid[data-v-6cdc2b1a]{grid-template-columns:1fr 1fr}}@media (max-width: 600px){.strategy-grid[data-v-6cdc2b1a]{grid-template-columns:1fr}}.pansou-status-grid[data-v-6cdc2b1a]{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px;margin-top:8px}.status-dot[data-v-6cdc2b1a]{width:8px;height:8px;border-radius:50%;display:inline-block}.dot-ok[data-v-6cdc2b1a]{background:#67c23a}.dot-err[data-v-6cdc2b1a]{background:#f56c6c}

View File

@@ -1 +0,0 @@
.el-card[data-v-641a8223]{margin-bottom:20px}.el-card[data-v-641a8223] .el-card__header{font-weight:600;font-size:15px}[data-v-641a8223] .el-divider__text.is-left{left:0;padding-left:0}.form-tip[data-v-641a8223]{font-size:12px;color:#909399;margin-top:4px}.fallback-upload-wrap[data-v-641a8223]{display:flex;flex-direction:column;gap:12px}.fallback-upload-row[data-v-641a8223]{display:flex;align-items:center;flex-wrap:wrap}.fallback-preview[data-v-641a8223]{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.fallback-preview img[data-v-641a8223]{max-width:100%;height:auto;max-height:120px;border-radius:8px;border:1px solid var(--border-color);background:#f0f0f0;object-fit:contain}.strategy-grid[data-v-641a8223]{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px 16px}.grid-cell[data-v-641a8223]{display:flex;flex-direction:column;gap:4px}.strategy-section[data-v-641a8223]{padding:0 4px}.field-block[data-v-641a8223]{margin:12px 0}.field-label-row[data-v-641a8223]{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.field-label[data-v-641a8223]{font-size:14px;font-weight:500;color:#303133;white-space:nowrap}.field-desc[data-v-641a8223]{font-size:12px;color:#909399;margin:3px 0 0;line-height:1.5}.keyword-input-row[data-v-641a8223]{display:flex;gap:8px;flex:1;min-width:200px}.tag-list[data-v-641a8223]{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}.tag-empty[data-v-641a8223]{font-size:13px;color:#c0c4cc;margin-top:8px}.filter-rule-help[data-v-641a8223]{margin-top:8px;padding:10px 12px;background:#f8f9fa;border-radius:8px;border:1px solid #e8e8e8}.filter-rule-help .help-title[data-v-641a8223]{font-weight:600;font-size:13px;margin:8px 0 4px;color:#333}.filter-rule-help .help-title[data-v-641a8223]:first-child{margin-top:0}.filter-rule-help .help-row[data-v-641a8223]{font-size:12px;color:#555;margin:3px 0;line-height:1.6}.filter-rule-help .help-row code[data-v-641a8223]{background:#eef1f5;padding:1px 5px;border-radius:3px;font-size:11px;font-family:monospace}.filter-rules-help[data-v-641a8223]{margin-top:8px;padding:12px;background:#f8f9fa;border-radius:8px;border:1px solid #e8e8e8}.help-title[data-v-641a8223]{font-weight:600;font-size:13px;margin:10px 0 6px;color:#333}.help-title[data-v-641a8223]:first-child{margin-top:0}.help-row[data-v-641a8223]{font-size:12px;color:#555;margin:3px 0;line-height:1.6}.help-row code[data-v-641a8223]{background:#eef1f5;padding:1px 5px;border-radius:3px;font-size:11px;font-family:monospace}.help-sample[data-v-641a8223]{background:#1e1e1e;color:#d4d4d4;padding:10px 14px;border-radius:6px;font-size:12px;line-height:1.6;overflow-x:auto;white-space:pre;margin:6px 0 0;font-family:monospace}.help-preview-row[data-v-641a8223]{font-size:13px;margin:4px 0;display:flex;align-items:center;gap:6px}.help-preview-label[data-v-641a8223]{color:#888;min-width:70px;font-size:12px}.help-preview-original[data-v-641a8223]{color:#e74c3c}.help-preview-filtered[data-v-641a8223]{color:#27ae60;font-weight:500}.filter-input-row[data-v-641a8223]{display:flex;gap:8px;width:100%;margin-bottom:8px}.filter-tag-list[data-v-641a8223]{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}.filter-empty[data-v-641a8223]{font-size:13px;color:#c0c4cc;padding:8px 0;margin-bottom:8px}.db-status-grid[data-v-641a8223]{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px;margin-top:8px}.db-stat-item[data-v-641a8223]{background:#f8f9fa;border-radius:10px;padding:16px 12px;text-align:center;border:1px solid #eee;transition:transform .15s,box-shadow .15s}.db-stat-item[data-v-641a8223]:hover{transform:translateY(-2px);box-shadow:0 4px 12px #0000000f}.db-stat-value[data-v-641a8223]{white-space:nowrap;font-size:24px;font-weight:700;color:#303133;margin-bottom:4px}.db-stat-value.text-success[data-v-641a8223]{color:#67c23a}.db-stat-value.text-warning[data-v-641a8223]{color:#e6a23c}.db-stat-label[data-v-641a8223]{font-size:12px;color:#909399}@media (max-width: 900px){.strategy-grid[data-v-641a8223]{grid-template-columns:1fr 1fr}}@media (max-width: 600px){.strategy-grid[data-v-641a8223]{grid-template-columns:1fr}}.pansou-status-grid[data-v-641a8223]{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px;margin-top:8px}.status-dot[data-v-641a8223]{width:8px;height:8px;border-radius:50%;display:inline-block}.dot-ok[data-v-641a8223]{background:#67c23a}.dot-err[data-v-641a8223]{background:#f56c6c}

View File

@@ -21,7 +21,7 @@
}
})();
</script>
<script type="module" crossorigin src="/assets/index-D279dJND.js"></script>
<script type="module" crossorigin src="/assets/index-D_srC3bj.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Ekbe64zQ.css">
</head>
<body>

View File

@@ -38,6 +38,7 @@
<el-menu-item index="sys-strategy"> 性能配置</el-menu-item>
<el-menu-item index="sys-password">🔑 修改密码</el-menu-item>
<el-menu-item index="sys-notify">📬 消息推送</el-menu-item>
<el-menu-item index="sys-daily-report">📊 每日汇报</el-menu-item>
</el-sub-menu>
<el-menu-item index="save-records">
@@ -96,6 +97,7 @@ const pageTitles: Record<string, string> = {
'sys-strategy': '性能配置',
'sys-password': '修改管理员密码',
'sys-notify': '消息推送',
'sys-daily-report': '每日汇报',
'save-records': '转存日志',
}

View File

@@ -612,6 +612,51 @@
</el-table>
</el-card>
<!-- 📊 每日汇报 -->
<el-card id="section-sys-daily-report" v-show="!activeSection || activeSection === 'sys-daily-report'">
<template #header>
<div style="display:flex; align-items:center; justify-content:space-between;">
<span>📊 每日汇报</span>
<div>
<el-button size="small" :loading="dailyReportPreviewing" @click="handleDailyReportPreview">📋 预览</el-button>
<el-button size="small" type="primary" :loading="dailyReportSending" @click="handleDailyReportSendTest"> 发送测试</el-button>
</div>
</div>
</template>
<el-form label-width="140px" label-position="left">
<el-form-item label="启用每日汇报">
<el-switch v-model="dailyReportForm.enabled" active-text="每天8点自动发送" />
</el-form-item>
<el-form-item label="发送时间">
<el-time-picker
v-model="dailyReportForm.time"
format="HH:mm"
value-format="HH:mm"
placeholder="选择时间"
:disabled="!dailyReportForm.enabled"
/>
<div class="form-tip">默认每天 08:00 发送前一天的汇总报告</div>
</el-form-item>
<el-form-item label="报告内容">
<div style="display:flex; flex-wrap:wrap; gap:16px;">
<el-switch v-model="dailyReportForm.includeSearch" active-text="搜索统计" :disabled="!dailyReportForm.enabled" />
<el-switch v-model="dailyReportForm.includeSaves" active-text="转存统计" :disabled="!dailyReportForm.enabled" />
<el-switch v-model="dailyReportForm.includeStorage" active-text="网盘容量" :disabled="!dailyReportForm.enabled" />
<el-switch v-model="dailyReportForm.includeUsers" active-text="用户数" :disabled="!dailyReportForm.enabled" />
</div>
</el-form-item>
<el-form-item label="上次发送">
<span>{{ dailyReportLastRun || '从未发送' }}</span>
</el-form-item>
</el-form>
<!-- Preview modal -->
<el-dialog v-model="dailyReportPreviewVisible" title="📊 每日汇报预览" width="600px">
<div style="white-space: pre-wrap; font-family: monospace; background: var(--el-fill-color-light); padding: 16px; border-radius: 8px; max-height: 500px; overflow-y: auto;">{{ dailyReportPreview }}</div>
</el-dialog>
</el-card>
<!-- 🔄 系统维护 --> <el-card id="section-sys-maintenance" v-show="!activeSection || activeSection === 'sys-maintenance'"> <template #header> <span>🔄 系统维护</span> </template> <el-form label-width="180px" label-position="left"> <el-form-item label="自动更新镜像"> <el-switch v-model="autoUpdateEnabled" active-text="启用" inactive-text="禁用" /> <div class="form-tip">启用后 CloudSearch 将自动检测并更新到最新镜像版本</div> <div class="form-tip" style="color: var(--(--el-color-warning,#e6a23c));"> 当前需手动在服务器执行docker-compose -f /opt/CloudSearch/docker-compose.yml pull && docker-compose -f /opt/CloudSearch/docker-compose.yml up -d </div> </el-form-item> </el-form> </el-card>
<!-- 保存按钮 -->
@@ -694,6 +739,92 @@ const autoUpdateEnabled = computed({
})
// ======================== Push User Notifications ========================
// ======================== Daily Report ========================
const dailyReportForm = reactive({
enabled: true,
time: '08:00',
includeSearch: true,
includeSaves: true,
includeStorage: true,
includeUsers: true,
})
const dailyReportPreviewing = ref(false)
const dailyReportSending = ref(false)
const dailyReportPreview = ref('')
const dailyReportPreviewVisible = ref(false)
const dailyReportLastRun = ref('')
async function loadDailyReportConfig() {
try {
const res = await fetch('/api/admin/daily-report/config', {
headers: { Authorization: `Bearer ${localStorage.getItem("admin_token")}` }
})
if (res.ok) {
const cfg = await res.json()
Object.assign(dailyReportForm, cfg)
}
} catch {}
}
async function loadDailyReportLastRun() {
try {
const res = await fetch('/api/admin/daily-report/last-run', {
headers: { Authorization: `Bearer ${localStorage.getItem("admin_token")}` }
})
if (res.ok) {
const data = await res.json()
if (data.date) {
dailyReportLastRun.value = `${data.date} ${new Date(data.sentAt).toLocaleTimeString('zh-CN')}`
}
}
} catch {}
}
async function saveDailyReportConfig() {
try {
await fetch('/api/admin/daily-report/config', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${localStorage.getItem("admin_token")}`,
},
body: JSON.stringify({ ...dailyReportForm }),
})
} catch {}
}
async function handleDailyReportPreview() {
dailyReportPreviewing.value = true
try {
const res = await fetch('/api/admin/daily-report/preview', {
headers: { Authorization: `Bearer ${localStorage.getItem("admin_token")}` }
})
if (res.ok) {
const data = await res.json()
dailyReportPreview.value = data.content
dailyReportPreviewVisible.value = true
}
} finally {
dailyReportPreviewing.value = false
}
}
async function handleDailyReportSendTest() {
dailyReportSending.value = true
try {
const res = await fetch('/api/admin/daily-report/test', {
method: 'POST',
headers: { Authorization: `Bearer ${localStorage.getItem("admin_token")}` },
})
if (res.ok) {
ElMessage.success('测试报告已发送到全局通知通道')
} else {
ElMessage.error('发送失败')
}
} catch {
ElMessage.error('发送失败')
} finally {
dailyReportSending.value = false
}
}
const pushUsers = ref<any[]>([])
const notifyProviders = ref<Record<string, any>>({})
// const pushUserDialogVisible = ref(false) // removed - using inline form
@@ -1005,6 +1136,8 @@ onMounted(async () => {
initGlobalNotifyForm()
await loadGlobalNotifyConfig()
loadPushUsers()
loadDailyReportConfig()
loadDailyReportLastRun()
loadPushUserAccountOptions()
})
@@ -1320,6 +1453,7 @@ async function handleSave() {
key: cfg.key,
value: String(configs[cfg.key] ?? cfg.value),
}))
await saveDailyReportConfig()
// Add global_notify_config as JSON entry
entries.push({
key: 'global_notify_config',

View File

@@ -1,4 +1,4 @@
import{x as qu,m as $_,h as Ce,B as Hg,d as q_,o as K_,a as Tt,c as Nt,K as ml,L as _l,b as Q,F as Vr,r as Gr,f as $t,w as qt,e as Oe,v as Ka,j as Hr,i as Q_,t as wt,n as Nc,y as Ei,l as zc,p as J_,E as j_,u as t1}from"./index-D279dJND.js";import{a as e1,h as r1,c as i1,i as n1,j as a1,t as o1,_ as s1}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import l1 from"./CloudConfig-BADbnuPV.js";import u1 from"./SystemConfig-C3is0eeI.js";import f1 from"./SaveRecords-DLmXAM3V.js";import"./index-Bn7NwETH.js";import"./CloudBadge-OZZzB6Zg.js";/*! *****************************************************************************
import{x as qu,m as $_,h as Ce,B as Hg,d as q_,o as K_,a as Tt,c as Nt,K as ml,L as _l,b as Q,F as Vr,r as Gr,f as $t,w as qt,e as Oe,v as Ka,j as Hr,i as Q_,t as wt,n as Nc,y as Ei,l as zc,p as J_,E as j_,u as t1}from"./index-D_srC3bj.js";import{a as e1,h as r1,c as i1,i as n1,j as a1,t as o1,_ as s1}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import l1 from"./CloudConfig-3znuBWUR.js";import u1 from"./SystemConfig-BbG7uBv0.js";import f1 from"./SaveRecords-B5cCMWaP.js";import"./index-Bn7NwETH.js";import"./CloudBadge-CbpZHKLy.js";/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any

View File

@@ -1 +0,0 @@
import{d as B,o as N,a as V,c as I,b as n,t as c,f as e,w as t,h as g,v as y,j as i,k as r,C as M,l,D as T,G as j,H as q,I as z,J as A,u as D,z as H}from"./index-D279dJND.js";import{a as L,_ as R}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const E={class:"admin-layout"},G={class:"admin-sidebar"},J={class:"sidebar-brand"},W={class:"sidebar-brand-text"},F={class:"sidebar-version"},K={class:"admin-content"},O={class:"content-header"},P={class:"content-breadcrumb"},Q={class:"breadcrumb-current"},U={class:"content-actions"},X={class:"content-body"},Y=B({__name:"AdminLayout",setup(Z){const d=D(),f=H(),m=g(""),_=g(""),b={dashboard:"仪表盘","cloud-configs-toggle":"网盘设置及授权","cloud-configs-cleanup":"存储清理","sys-site":"网站设置","sys-services":"外部服务 & 缓存","sys-strategy":"性能配置","sys-password":"修改管理员密码","sys-notify":"消息推送","save-records":"转存日志"},p=y(()=>{const o=f.name;return o==="admin-cloud-configs"?"cloud-configs-toggle":o==="admin-cleanup"?"cloud-configs-cleanup":o==="admin-system"?f.query.section||"sys-site":o==="admin-save-records"?"save-records":"dashboard"}),x=y(()=>b[p.value]||"仪表盘");function w(o){o==="dashboard"?d.push("/admin/dashboard"):o==="cloud-configs-toggle"?d.push("/admin/cloud-configs"):o==="cloud-configs-cleanup"?d.push("/admin/cleanup"):o.startsWith("sys-")?d.push({path:"/admin/system",query:{section:o}}):o==="save-records"?d.push("/admin/save-records"):o==="logout"&&(localStorage.removeItem("admin_token"),d.push("/admin/login"))}function h(){d.push("/")}return N(async()=>{try{const o=await L();m.value=o.site_name||""}catch{}try{const s=await(await fetch("/health")).json();_.value=s.version}catch{}}),(o,s)=>{const u=i("el-icon"),a=i("el-menu-item"),v=i("el-sub-menu"),C=i("el-menu"),k=i("el-button"),S=i("router-view");return V(),I("div",E,[n("aside",G,[n("div",J,[s[1]||(s[1]=n("div",{class:"sidebar-logo"},"☁️",-1)),n("div",W,[n("h2",null,c(m.value||"CloudSearch"),1),s[0]||(s[0]=n("p",null,"管理控制台",-1))])]),e(C,{"default-active":p.value,class:"sidebar-menu",onSelect:w},{default:t(()=>[e(a,{index:"dashboard"},{default:t(()=>[e(u,null,{default:t(()=>[e(r(M))]),_:1}),s[2]||(s[2]=n("span",null,"仪表盘",-1))]),_:1}),e(v,{index:"cloud-configs"},{title:t(()=>[e(u,null,{default:t(()=>[e(r(T))]),_:1}),s[3]||(s[3]=n("span",null,"网盘管理",-1))]),default:t(()=>[e(a,{index:"cloud-configs-toggle"},{default:t(()=>[...s[4]||(s[4]=[l("📋 设置及授权",-1)])]),_:1}),e(a,{index:"cloud-configs-cleanup"},{default:t(()=>[...s[5]||(s[5]=[l("🧹 存储清理",-1)])]),_:1})]),_:1}),e(v,{index:"system"},{title:t(()=>[e(u,null,{default:t(()=>[e(r(j))]),_:1}),s[6]||(s[6]=n("span",null,"系统设置",-1))]),default:t(()=>[e(a,{index:"sys-site"},{default:t(()=>[...s[7]||(s[7]=[l("🌐 网站设置",-1)])]),_:1}),e(a,{index:"sys-services"},{default:t(()=>[...s[8]||(s[8]=[l("🔗 外部服务 & 缓存",-1)])]),_:1}),e(a,{index:"sys-strategy"},{default:t(()=>[...s[9]||(s[9]=[l("⚡ 性能配置",-1)])]),_:1}),e(a,{index:"sys-password"},{default:t(()=>[...s[10]||(s[10]=[l("🔑 修改密码",-1)])]),_:1}),e(a,{index:"sys-notify"},{default:t(()=>[...s[11]||(s[11]=[l("📬 消息推送",-1)])]),_:1})]),_:1}),e(a,{index:"save-records"},{default:t(()=>[e(u,null,{default:t(()=>[e(r(q))]),_:1}),s[12]||(s[12]=n("span",null,"转存日志",-1))]),_:1}),s[14]||(s[14]=n("div",{class:"sidebar-spacer"},null,-1)),n("div",F,"v"+c(_.value),1),e(a,{index:"logout"},{default:t(()=>[e(u,null,{default:t(()=>[e(r(z))]),_:1}),s[13]||(s[13]=n("span",null,"退出登录",-1))]),_:1})]),_:1},8,["default-active"])]),n("div",K,[n("header",O,[n("div",P,[n("span",Q,c(x.value),1)]),n("div",U,[e(k,{text:"",size:"small",onClick:h},{default:t(()=>[e(u,null,{default:t(()=>[e(r(A))]),_:1}),s[15]||(s[15]=l(" 返回前台 ",-1))]),_:1})])]),n("main",X,[e(S)])])])}}}),es=R(Y,[["__scopeId","data-v-29c9acc0"]]);export{es as default};

View File

@@ -0,0 +1 @@
.admin-layout[data-v-469751e8]{display:flex;height:100vh;background:var(--bg-page)}.admin-sidebar[data-v-469751e8]{width:var(--sidebar-w);flex-shrink:0;display:flex;flex-direction:column;background:linear-gradient(180deg,#111827,#1e293b);position:relative;z-index:10}.sidebar-brand[data-v-469751e8]{display:flex;align-items:center;gap:10px;padding:20px 20px 16px;border-bottom:1px solid rgba(255,255,255,.06)}.sidebar-logo[data-v-469751e8]{font-size:28px;line-height:1;flex-shrink:0}.sidebar-brand-text h2[data-v-469751e8]{font-size:16px;font-weight:700;margin:0;color:#fff;line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-brand-text p[data-v-469751e8]{font-size:11px;margin:2px 0 0;color:#ffffff73;letter-spacing:1px}.sidebar-menu[data-v-469751e8]{flex:1;display:flex;flex-direction:column;background:transparent!important;border-right:none!important;padding:4px 0}.sidebar-menu[data-v-469751e8] .el-menu-item,.sidebar-menu[data-v-469751e8] .el-sub-menu__title{color:#ffffffa6;height:44px;line-height:44px;transition:all .2s ease;margin:0 6px;border-radius:var(--radius-sm)}.sidebar-menu[data-v-469751e8] .el-menu-item:hover,.sidebar-menu[data-v-469751e8] .el-sub-menu__title:hover{background:#ffffff14;color:#ffffffe6}.sidebar-menu[data-v-469751e8] .el-menu-item.is-active{color:#fff;background:linear-gradient(90deg,#409eff40,#6366f126);font-weight:500}.sidebar-menu[data-v-469751e8] .el-menu-item:after{display:none}.sidebar-menu[data-v-469751e8] .el-sub-menu .el-menu{background:#0003!important}.sidebar-menu[data-v-469751e8] .el-sub-menu .el-menu .el-menu-item{padding-left:52px!important;font-size:13px;height:38px;line-height:38px}.sidebar-menu[data-v-469751e8] .el-icon{font-size:16px}.sidebar-spacer[data-v-469751e8]{flex:1}.sidebar-version[data-v-469751e8]{text-align:center;font-size:11px;color:#ffffff40;padding:8px 0;letter-spacing:.5px}.admin-content[data-v-469751e8]{flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0}.content-header[data-v-469751e8]{display:flex;align-items:center;justify-content:space-between;padding:16px 28px;background:var(--bg-card);border-bottom:1px solid var(--border-light);flex-shrink:0}.content-breadcrumb[data-v-469751e8]{display:flex;align-items:center;gap:8px}.breadcrumb-current[data-v-469751e8]{font-size:18px;font-weight:700;color:var(--text)}.content-actions[data-v-469751e8] .el-button{color:var(--text-secondary);gap:4px}.content-body[data-v-469751e8]{flex:1;overflow-y:auto;padding:24px 28px}.content-body[data-v-469751e8] .save-bar{position:fixed;bottom:32px;right:32px;z-index:100;background:var(--bg-card);padding:12px 16px;border-radius:var(--radius-lg);border:1px solid var(--border);box-shadow:0 4px 16px #0000001f;display:flex;gap:10px;transition:box-shadow .2s,transform .2s}.content-body[data-v-469751e8] .save-bar:hover{box-shadow:0 6px 24px #0000002e;transform:translateY(-2px)}

View File

@@ -1 +0,0 @@
.admin-layout[data-v-29c9acc0]{display:flex;height:100vh;background:var(--bg-page)}.admin-sidebar[data-v-29c9acc0]{width:var(--sidebar-w);flex-shrink:0;display:flex;flex-direction:column;background:linear-gradient(180deg,#111827,#1e293b);position:relative;z-index:10}.sidebar-brand[data-v-29c9acc0]{display:flex;align-items:center;gap:10px;padding:20px 20px 16px;border-bottom:1px solid rgba(255,255,255,.06)}.sidebar-logo[data-v-29c9acc0]{font-size:28px;line-height:1;flex-shrink:0}.sidebar-brand-text h2[data-v-29c9acc0]{font-size:16px;font-weight:700;margin:0;color:#fff;line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-brand-text p[data-v-29c9acc0]{font-size:11px;margin:2px 0 0;color:#ffffff73;letter-spacing:1px}.sidebar-menu[data-v-29c9acc0]{flex:1;display:flex;flex-direction:column;background:transparent!important;border-right:none!important;padding:4px 0}.sidebar-menu[data-v-29c9acc0] .el-menu-item,.sidebar-menu[data-v-29c9acc0] .el-sub-menu__title{color:#ffffffa6;height:44px;line-height:44px;transition:all .2s ease;margin:0 6px;border-radius:var(--radius-sm)}.sidebar-menu[data-v-29c9acc0] .el-menu-item:hover,.sidebar-menu[data-v-29c9acc0] .el-sub-menu__title:hover{background:#ffffff14;color:#ffffffe6}.sidebar-menu[data-v-29c9acc0] .el-menu-item.is-active{color:#fff;background:linear-gradient(90deg,#409eff40,#6366f126);font-weight:500}.sidebar-menu[data-v-29c9acc0] .el-menu-item:after{display:none}.sidebar-menu[data-v-29c9acc0] .el-sub-menu .el-menu{background:#0003!important}.sidebar-menu[data-v-29c9acc0] .el-sub-menu .el-menu .el-menu-item{padding-left:52px!important;font-size:13px;height:38px;line-height:38px}.sidebar-menu[data-v-29c9acc0] .el-icon{font-size:16px}.sidebar-spacer[data-v-29c9acc0]{flex:1}.sidebar-version[data-v-29c9acc0]{text-align:center;font-size:11px;color:#ffffff40;padding:8px 0;letter-spacing:.5px}.admin-content[data-v-29c9acc0]{flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0}.content-header[data-v-29c9acc0]{display:flex;align-items:center;justify-content:space-between;padding:16px 28px;background:var(--bg-card);border-bottom:1px solid var(--border-light);flex-shrink:0}.content-breadcrumb[data-v-29c9acc0]{display:flex;align-items:center;gap:8px}.breadcrumb-current[data-v-29c9acc0]{font-size:18px;font-weight:700;color:var(--text)}.content-actions[data-v-29c9acc0] .el-button{color:var(--text-secondary);gap:4px}.content-body[data-v-29c9acc0]{flex:1;overflow-y:auto;padding:24px 28px}.content-body[data-v-29c9acc0] .save-bar{position:fixed;bottom:32px;right:32px;z-index:100;background:var(--bg-card);padding:12px 16px;border-radius:var(--radius-lg);border:1px solid var(--border);box-shadow:0 4px 16px #0000001f;display:flex;gap:10px;transition:box-shadow .2s,transform .2s}.content-body[data-v-29c9acc0] .save-bar:hover{box-shadow:0 6px 24px #0000002e;transform:translateY(-2px)}

View File

@@ -0,0 +1 @@
import{d as B,o as N,a as V,c as I,b as n,t as c,f as e,w as t,h as g,v as y,j as u,k as r,C as M,l,D as T,G as j,H as q,I as z,J as A,u as D,z as H}from"./index-D_srC3bj.js";import{a as L,_ as R}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const E={class:"admin-layout"},G={class:"admin-sidebar"},J={class:"sidebar-brand"},W={class:"sidebar-brand-text"},F={class:"sidebar-version"},K={class:"admin-content"},O={class:"content-header"},P={class:"content-breadcrumb"},Q={class:"breadcrumb-current"},U={class:"content-actions"},X={class:"content-body"},Y=B({__name:"AdminLayout",setup(Z){const d=D(),f=H(),m=g(""),_=g(""),b={dashboard:"仪表盘","cloud-configs-toggle":"网盘设置及授权","cloud-configs-cleanup":"存储清理","sys-site":"网站设置","sys-services":"外部服务 & 缓存","sys-strategy":"性能配置","sys-password":"修改管理员密码","sys-notify":"消息推送","sys-daily-report":"每日汇报","save-records":"转存日志"},p=y(()=>{const o=f.name;return o==="admin-cloud-configs"?"cloud-configs-toggle":o==="admin-cleanup"?"cloud-configs-cleanup":o==="admin-system"?f.query.section||"sys-site":o==="admin-save-records"?"save-records":"dashboard"}),x=y(()=>b[p.value]||"仪表盘");function w(o){o==="dashboard"?d.push("/admin/dashboard"):o==="cloud-configs-toggle"?d.push("/admin/cloud-configs"):o==="cloud-configs-cleanup"?d.push("/admin/cleanup"):o.startsWith("sys-")?d.push({path:"/admin/system",query:{section:o}}):o==="save-records"?d.push("/admin/save-records"):o==="logout"&&(localStorage.removeItem("admin_token"),d.push("/admin/login"))}function h(){d.push("/")}return N(async()=>{try{const o=await L();m.value=o.site_name||""}catch{}try{const s=await(await fetch("/health")).json();_.value=s.version}catch{}}),(o,s)=>{const i=u("el-icon"),a=u("el-menu-item"),v=u("el-sub-menu"),C=u("el-menu"),k=u("el-button"),S=u("router-view");return V(),I("div",E,[n("aside",G,[n("div",J,[s[1]||(s[1]=n("div",{class:"sidebar-logo"},"☁️",-1)),n("div",W,[n("h2",null,c(m.value||"CloudSearch"),1),s[0]||(s[0]=n("p",null,"管理控制台",-1))])]),e(C,{"default-active":p.value,class:"sidebar-menu",onSelect:w},{default:t(()=>[e(a,{index:"dashboard"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(M))]),_:1}),s[2]||(s[2]=n("span",null,"仪表盘",-1))]),_:1}),e(v,{index:"cloud-configs"},{title:t(()=>[e(i,null,{default:t(()=>[e(r(T))]),_:1}),s[3]||(s[3]=n("span",null,"网盘管理",-1))]),default:t(()=>[e(a,{index:"cloud-configs-toggle"},{default:t(()=>[...s[4]||(s[4]=[l("📋 设置及授权",-1)])]),_:1}),e(a,{index:"cloud-configs-cleanup"},{default:t(()=>[...s[5]||(s[5]=[l("🧹 存储清理",-1)])]),_:1})]),_:1}),e(v,{index:"system"},{title:t(()=>[e(i,null,{default:t(()=>[e(r(j))]),_:1}),s[6]||(s[6]=n("span",null,"系统设置",-1))]),default:t(()=>[e(a,{index:"sys-site"},{default:t(()=>[...s[7]||(s[7]=[l("🌐 网站设置",-1)])]),_:1}),e(a,{index:"sys-services"},{default:t(()=>[...s[8]||(s[8]=[l("🔗 外部服务 & 缓存",-1)])]),_:1}),e(a,{index:"sys-strategy"},{default:t(()=>[...s[9]||(s[9]=[l("⚡ 性能配置",-1)])]),_:1}),e(a,{index:"sys-password"},{default:t(()=>[...s[10]||(s[10]=[l("🔑 修改密码",-1)])]),_:1}),e(a,{index:"sys-notify"},{default:t(()=>[...s[11]||(s[11]=[l("📬 消息推送",-1)])]),_:1}),e(a,{index:"sys-daily-report"},{default:t(()=>[...s[12]||(s[12]=[l("📊 每日汇报",-1)])]),_:1})]),_:1}),e(a,{index:"save-records"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(q))]),_:1}),s[13]||(s[13]=n("span",null,"转存日志",-1))]),_:1}),s[15]||(s[15]=n("div",{class:"sidebar-spacer"},null,-1)),n("div",F,"v"+c(_.value),1),e(a,{index:"logout"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(z))]),_:1}),s[14]||(s[14]=n("span",null,"退出登录",-1))]),_:1})]),_:1},8,["default-active"])]),n("div",K,[n("header",O,[n("div",P,[n("span",Q,c(x.value),1)]),n("div",U,[e(k,{text:"",size:"small",onClick:h},{default:t(()=>[e(i,null,{default:t(()=>[e(r(A))]),_:1}),s[16]||(s[16]=l(" 返回前台 ",-1))]),_:1})])]),n("main",X,[e(S)])])])}}}),es=R(Y,[["__scopeId","data-v-469751e8"]]);export{es as default};

View File

@@ -1 +1 @@
import{d as k,o as C,a as w,c as y,b as a,t as m,f as t,w as i,g as x,e as L,h as d,j as p,l as N,i as S,E as B}from"./index-D279dJND.js";import{a as E,d as M,_ as U}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const j={class:"admin-login-page"},q={class:"login-card"},A={class:"login-brand"},I={class:"login-title"},K={key:0,class:"error-msg"},R={class:"login-footer"},z=k({__name:"AdminLogin",setup(D){const f=d(),u=d(!1),c=d(""),g=d(""),v=d("");E().then(l=>{l.site_name&&(g.value=l.site_name)}).catch(()=>{});const s=S({username:"",password:""}),b={username:[{required:!0,message:"请输入用户名",trigger:"blur"}],password:[{required:!0,message:"请输入密码",trigger:"blur"}]};async function h(){var e,r,n;if(await((e=f.value)==null?void 0:e.validate().catch(()=>!1))){u.value=!0,c.value="";try{const o=await M(s.username,s.password);localStorage.setItem("admin_token",o.token),B.success("登录成功"),window.location.href="/admin"}catch(o){c.value=((n=(r=o==null?void 0:o.response)==null?void 0:r.data)==null?void 0:n.message)||(o==null?void 0:o.message)||"登录失败"}finally{u.value=!1}}}return C(async()=>{try{const e=await(await fetch("/health")).json();v.value=e.version||""}catch{}}),(l,e)=>{const r=p("el-input"),n=p("el-form-item"),o=p("el-button"),V=p("el-form");return w(),y("div",j,[e[4]||(e[4]=a("div",{class:"login-bg-pattern"},null,-1)),a("div",q,[a("div",A,[e[2]||(e[2]=a("div",{class:"login-logo"},"☁️",-1)),a("h1",I,m(g.value||"CloudSearch"),1),e[3]||(e[3]=a("p",{class:"login-subtitle"},"管理后台",-1))]),t(V,{ref_key:"formRef",ref:f,model:s,rules:b,"label-width":"0",size:"large",onKeyup:x(h,["enter"])},{default:i(()=>[t(n,{prop:"username"},{default:i(()=>[t(r,{modelValue:s.username,"onUpdate:modelValue":e[0]||(e[0]=_=>s.username=_),placeholder:"用户名","prefix-icon":"User"},null,8,["modelValue"])]),_:1}),t(n,{prop:"password"},{default:i(()=>[t(r,{modelValue:s.password,"onUpdate:modelValue":e[1]||(e[1]=_=>s.password=_),type:"password",placeholder:"密码","prefix-icon":"Lock","show-password":""},null,8,["modelValue"])]),_:1}),t(n,null,{default:i(()=>[t(o,{type:"primary",loading:u.value,class:"login-btn",onClick:h},{default:i(()=>[N(m(u.value?"登录中...":"登 录"),1)]),_:1},8,["loading"])]),_:1})]),_:1},8,["model"]),c.value?(w(),y("p",K,m(c.value),1)):L("",!0),a("p",R,"CloudSearch v"+m(v.value),1)])])}}}),G=U(z,[["__scopeId","data-v-bd0b6672"]]);export{G as default};
import{d as k,o as C,a as w,c as y,b as a,t as m,f as t,w as i,g as x,e as L,h as d,j as p,l as N,i as S,E as B}from"./index-D_srC3bj.js";import{a as E,d as M,_ as U}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const j={class:"admin-login-page"},q={class:"login-card"},A={class:"login-brand"},I={class:"login-title"},K={key:0,class:"error-msg"},R={class:"login-footer"},z=k({__name:"AdminLogin",setup(D){const f=d(),u=d(!1),c=d(""),g=d(""),v=d("");E().then(l=>{l.site_name&&(g.value=l.site_name)}).catch(()=>{});const s=S({username:"",password:""}),b={username:[{required:!0,message:"请输入用户名",trigger:"blur"}],password:[{required:!0,message:"请输入密码",trigger:"blur"}]};async function h(){var e,r,n;if(await((e=f.value)==null?void 0:e.validate().catch(()=>!1))){u.value=!0,c.value="";try{const o=await M(s.username,s.password);localStorage.setItem("admin_token",o.token),B.success("登录成功"),window.location.href="/admin"}catch(o){c.value=((n=(r=o==null?void 0:o.response)==null?void 0:r.data)==null?void 0:n.message)||(o==null?void 0:o.message)||"登录失败"}finally{u.value=!1}}}return C(async()=>{try{const e=await(await fetch("/health")).json();v.value=e.version||""}catch{}}),(l,e)=>{const r=p("el-input"),n=p("el-form-item"),o=p("el-button"),V=p("el-form");return w(),y("div",j,[e[4]||(e[4]=a("div",{class:"login-bg-pattern"},null,-1)),a("div",q,[a("div",A,[e[2]||(e[2]=a("div",{class:"login-logo"},"☁️",-1)),a("h1",I,m(g.value||"CloudSearch"),1),e[3]||(e[3]=a("p",{class:"login-subtitle"},"管理后台",-1))]),t(V,{ref_key:"formRef",ref:f,model:s,rules:b,"label-width":"0",size:"large",onKeyup:x(h,["enter"])},{default:i(()=>[t(n,{prop:"username"},{default:i(()=>[t(r,{modelValue:s.username,"onUpdate:modelValue":e[0]||(e[0]=_=>s.username=_),placeholder:"用户名","prefix-icon":"User"},null,8,["modelValue"])]),_:1}),t(n,{prop:"password"},{default:i(()=>[t(r,{modelValue:s.password,"onUpdate:modelValue":e[1]||(e[1]=_=>s.password=_),type:"password",placeholder:"密码","prefix-icon":"Lock","show-password":""},null,8,["modelValue"])]),_:1}),t(n,null,{default:i(()=>[t(o,{type:"primary",loading:u.value,class:"login-btn",onClick:h},{default:i(()=>[N(m(u.value?"登录中...":"登 录"),1)]),_:1},8,["loading"])]),_:1})]),_:1},8,["model"]),c.value?(w(),y("p",K,m(c.value),1)):L("",!0),a("p",R,"CloudSearch v"+m(v.value),1)])])}}}),G=U(z,[["__scopeId","data-v-bd0b6672"]]);export{G as default};

View File

@@ -1 +1 @@
import{C as s,b as a,a as n}from"./index-Bn7NwETH.js";import{d as l,a as t,c,p as d,k as o,e as r,l as u,t as m}from"./index-D279dJND.js";import{_}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const p=["src"],i=l({__name:"CloudBadge",props:{cloud_type:{},showIcon:{type:Boolean}},setup(e){return(C,y)=>(t(),c("span",{class:"cloud-badge",style:d({background:o(s)[e.cloud_type]})},[e.showIcon&&o(a)[e.cloud_type]?(t(),c("img",{key:0,src:o(a)[e.cloud_type],class:"badge-icon"},null,8,p)):r("",!0),u(" "+m(o(n)[e.cloud_type]),1)],4))}}),L=_(i,[["__scopeId","data-v-9106805f"]]);export{L as C};
import{C as s,b as a,a as n}from"./index-Bn7NwETH.js";import{d as l,a as t,c,p as d,k as o,e as r,l as u,t as m}from"./index-D_srC3bj.js";import{_}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const p=["src"],i=l({__name:"CloudBadge",props:{cloud_type:{},showIcon:{type:Boolean}},setup(e){return(C,y)=>(t(),c("span",{class:"cloud-badge",style:d({background:o(s)[e.cloud_type]})},[e.showIcon&&o(a)[e.cloud_type]?(t(),c("img",{key:0,src:o(a)[e.cloud_type],class:"badge-icon"},null,8,p)):r("",!0),u(" "+m(o(n)[e.cloud_type]),1)],4))}}),L=_(i,[["__scopeId","data-v-9106805f"]]);export{L as C};

View File

@@ -1,4 +1,4 @@
import{d as ke,o as L,m as ve,E as _,a as c,c as k,f as n,w as a,b as r,h as C,j as p,i as be,F as R,r as K,t as v,y as g,l as d,e as A,k as Ce,M as he,p as xe,n as H,K as Be,L as Te,v as h}from"./index-D279dJND.js";import{a as x}from"./index-Bn7NwETH.js";import{c as we,k as Fe,h as Ne,l as G,t as Ve,u as P,m as ze,n as Se,o as $e,_ as Ue}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import{C as De}from"./CloudBadge-OZZzB6Zg.js";const Ie={class:"cloud-config"},Me={class:"cloud-toggle-grid"},Oe=["src"],qe={class:"cloud-label"},Ee={class:"toolbar"},Le={key:0,class:"nickname-text"},Re={key:0,class:"promotion-text"},Ke={key:0,class:"uid-cell"},Ae={key:0,class:"verifying"},He={key:0,class:"storage-cell"},Ge={class:"storage-bar-wrap"},Pe={class:"storage-text"},je={class:"storage-used"},Je={class:"storage-total"},Qe={class:"storage-free"},We={key:0,class:"save-count"},Xe={style:{"line-height":"1.6"}},Ye={class:"cookie-tips-header"},Ze={class:"cookie-tips-title"},et=["innerHTML"],tt=ke({__name:"CloudConfig",setup(ot){const z=C([]),D=C(),F=C([]),B=C(!1),T=C(!1),b=C(null),l=be({cloud_type:"",nickname:"",promotion_account:"",is_transfer_enabled:!1,cookie:"",_verifying:!1,_storageUsed:"",_storageTotal:""}),j=h(()=>({cloud_type:[{required:!0,message:"请选择网盘类型",trigger:"change"}],nickname:[{required:!1,message:"请填写昵称(区分多个同类型网盘)",trigger:"blur"}],promotion_account:[{required:!0,message:"请填写推广平台及账号",trigger:"blur"}]})),J=h(()=>Object.entries(x)),Q=h(()=>{if(!l.cloud_type)return"请先选择网盘类型";const t=l.cloud_type;return t==="quark"||t==="baidu"?`请输入 ${x[t]||t} 的完整 Cookie`:b.value?"留空则保持原有":"输入完整 Cookie"}),W=h(()=>x[l.cloud_type]||l.cloud_type||""),X=h(()=>{const t=l.cloud_type;return t?{quark:`<li>在电脑上打开 <a href="https://pan.quark.cn" target="_blank">pan.quark.cn</a> 并登录你的夸克账号</li>
import{d as ke,o as L,m as ve,E as _,a as c,c as k,f as n,w as a,b as r,h as C,j as p,i as be,F as R,r as K,t as v,y as g,l as d,e as A,k as Ce,M as he,p as xe,n as H,K as Be,L as Te,v as h}from"./index-D_srC3bj.js";import{a as x}from"./index-Bn7NwETH.js";import{c as we,k as Fe,h as Ne,l as G,t as Ve,u as P,m as ze,n as Se,o as $e,_ as Ue}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import{C as De}from"./CloudBadge-CbpZHKLy.js";const Ie={class:"cloud-config"},Me={class:"cloud-toggle-grid"},Oe=["src"],qe={class:"cloud-label"},Ee={class:"toolbar"},Le={key:0,class:"nickname-text"},Re={key:0,class:"promotion-text"},Ke={key:0,class:"uid-cell"},Ae={key:0,class:"verifying"},He={key:0,class:"storage-cell"},Ge={class:"storage-bar-wrap"},Pe={class:"storage-text"},je={class:"storage-used"},Je={class:"storage-total"},Qe={class:"storage-free"},We={key:0,class:"save-count"},Xe={style:{"line-height":"1.6"}},Ye={class:"cookie-tips-header"},Ze={class:"cookie-tips-title"},et=["innerHTML"],tt=ke({__name:"CloudConfig",setup(ot){const z=C([]),D=C(),F=C([]),B=C(!1),T=C(!1),b=C(null),l=be({cloud_type:"",nickname:"",promotion_account:"",is_transfer_enabled:!1,cookie:"",_verifying:!1,_storageUsed:"",_storageTotal:""}),j=h(()=>({cloud_type:[{required:!0,message:"请选择网盘类型",trigger:"change"}],nickname:[{required:!1,message:"请填写昵称(区分多个同类型网盘)",trigger:"blur"}],promotion_account:[{required:!0,message:"请填写推广平台及账号",trigger:"blur"}]})),J=h(()=>Object.entries(x)),Q=h(()=>{if(!l.cloud_type)return"请先选择网盘类型";const t=l.cloud_type;return t==="quark"||t==="baidu"?`请输入 ${x[t]||t} 的完整 Cookie`:b.value?"留空则保持原有":"输入完整 Cookie"}),W=h(()=>x[l.cloud_type]||l.cloud_type||""),X=h(()=>{const t=l.cloud_type;return t?{quark:`<li>在电脑上打开 <a href="https://pan.quark.cn" target="_blank">pan.quark.cn</a> 并登录你的夸克账号</li>
<li> <code>F12</code> <strong> (Network)</strong> </li>
<li>刷新页面在请求列表中点击任意一个请求 <code>account/info</code></li>
<li>在右侧 <strong>请求头 (Request Headers)</strong> <code>Cookie</code> </li>

View File

@@ -1 +1 @@
import{d as K,o as G,a as n,c as a,b as o,F as w,t as c,e as h,f as v,w as f,g as Q,r as z,h as l,i as B,j as x,u as W,k as Y,s as J,l as D,n as I}from"./index-D279dJND.js";import{g as X,a as Z,_ as ee}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const te={class:"home-page"},se={class:"hero-section"},oe=["src","alt"],ne={key:1,class:"logo-text"},ae={class:"search-box"},ie={key:1,class:"quote-section"},ce={class:"quote-text"},le={class:"quote-author"},re={class:"content-section"},ue={key:0,class:"rankings-grid"},de={class:"panel-header"},_e={class:"panel-title"},he={class:"panel-tabs"},ve=["onClick"],pe=["onClick"],ge={class:"panel-body"},fe=["onClick"],me={class:"rank-name"},ye={class:"rank-cnt"},ke=["onClick"],Ce={class:"panel-footer"},be={key:0},we={key:1},xe={key:2},Ie={key:3},qe={class:"footer-time"},Ae={key:0,class:"site-footer"},Se={class:"footer-inner"},Ne={class:"footer-actions"},R=8,Te=K({__name:"HomePage",setup(Ve){const q=W(),m=l(""),u=l([]),d=B({}),_=B({}),p=l(""),y=l(""),k=l(""),A=l(!1),g=l(""),C=l(""),S=l(""),F={movie:"🎬",western_movie:"🎥",western_tv:"🌍",donghua:"🐉",global_anime:"🌐",tv:"📺",niche:"💎",hotsite:"🏆"};function L(e){return F[e]||"📋"}function j(e){const t=[];if(e.rating&&t.push(`${e.rating}`),e.searchCount>0){const i=e.searchCount;i>=1e8?t.push(`${(i/1e8).toFixed(1)}亿`):i>=1e4?t.push(`${(i/1e4).toFixed(0)}`):t.push(String(i))}return t.join(" ")||""}function N(e){return(_[e.category]||"hot")==="hot"?e.hot||[]:e.newest||[]}function E(e){const t=N(e);return d[e.category]?t:t.slice(0,R)}function H(e){return N(e).length>R&&!d[e.category]}function M(e){d[e]=!0}function T(e,t){_[e]=t,d[e]=!1}function O(){window.open("/disclaimer/","_blank")}G(async()=>{try{const t=await(await fetch("https://v1.hitokoto.cn/")).json();g.value=t.hitokoto||"",C.value=t.from_who||t.from||""}catch{g.value="学而时习之,不亦说乎。",C.value="孔子"}try{const[e,t]=await Promise.all([X(),Z()]);e.fetchedAt?(S.value=e.fetchedAt,u.value=e.categories||[]):u.value=Array.isArray(e)?e:[];for(const i of u.value)_[i.category]="hot",d[i.category]=!1;t.site_logo&&(p.value=t.site_logo),t.site_name&&(y.value=t.site_name),t.site_disclaimer&&(k.value=t.site_disclaimer),A.value=!0}catch(e){console.error("加载首页数据失败",e)}});function V(){const e=m.value.trim();e&&q.push("/search?q="+encodeURIComponent(e))}function P(e){q.push("/search?q="+encodeURIComponent(e))}return(e,t)=>{const i=x("el-icon"),U=x("el-input"),$=x("el-button");return n(),a("div",te,[o("div",se,[A.value?(n(),a(w,{key:0},[p.value?(n(),a("img",{key:0,src:p.value,alt:y.value||"CloudSearch",class:"logo-img",onError:t[0]||(t[0]=s=>{s.target.style.display="none",p.value=""})},null,40,oe)):(n(),a("div",ne,c(y.value||"CloudSearch"),1))],64)):h("",!0),o("div",ae,[v(U,{modelValue:m.value,"onUpdate:modelValue":t[1]||(t[1]=s=>m.value=s),placeholder:"搜索网盘资源,或粘贴视频/网盘链接...",size:"large",clearable:"",onKeyup:Q(V,["enter"])},{prefix:f(()=>[v(i,null,{default:f(()=>[v(Y(J))]),_:1})]),_:1},8,["modelValue"]),v($,{type:"primary",size:"large",onClick:V,class:"search-btn"},{default:f(()=>[...t[2]||(t[2]=[D(" 搜 索 ",-1)])]),_:1})]),g.value?(n(),a("div",ie,[o("span",ce,"「 "+c(g.value)+" 」",1),o("span",le,"---"+c(C.value),1)])):h("",!0)]),o("div",re,[u.value.length>0?(n(),a("div",ue,[(n(!0),a(w,null,z(u.value,s=>(n(),a("div",{key:s.category,class:"rank-panel"},[o("div",de,[o("span",_e,c(L(s.category))+" "+c(s.label),1),o("div",he,[o("span",{class:I(["panel-tab",{active:_[s.category]==="hot"}]),onClick:r=>T(s.category,"hot")},"热榜",10,ve),o("span",{class:I(["panel-tab",{active:_[s.category]==="newest"}]),onClick:r=>T(s.category,"newest")},"最新",10,pe)])]),o("div",ge,[(n(!0),a(w,null,z(E(s),(r,b)=>(n(),a("div",{key:s.category+"-"+b,class:"rank-item",onClick:$e=>P(r.keyword)},[o("span",{class:I(["rank-idx",{"top-three":b<3}])},c(b+1),3),o("span",me,c(r.keyword),1),o("span",ye,c(j(r)),1)],8,fe))),128)),H(s)?(n(),a("div",{key:0,class:"rank-expand",onClick:r=>M(s.category)}," 展开全部 ▼ ",8,ke)):h("",!0)]),o("div",Ce,[s.category==="hotsite"?(n(),a("span",be,"基于本站搜索数据")):s.category==="donghua"||s.category==="global_anime"?(n(),a("span",we,"数据来源Bilibili")):s.category==="movie"||s.category==="tv"?(n(),a("span",xe,"数据来源:百度")):(n(),a("span",Ie,"数据来源TMDB")),o("span",qe,c(S.value),1)])]))),128))])):h("",!0)]),k.value?(n(),a("div",Ae,[o("div",Se,c(k.value),1),o("div",Ne,[v($,{class:"footer-disclaimer-btn",size:"small",onClick:O},{default:f(()=>[...t[3]||(t[3]=[D("📜 免责声明",-1)])]),_:1})])])):h("",!0)])}}}),De=ee(Te,[["__scopeId","data-v-1f536d99"]]);export{De as default};
import{d as K,o as G,a as n,c as a,b as o,F as w,t as c,e as h,f as v,w as f,g as Q,r as z,h as l,i as B,j as x,u as W,k as Y,s as J,l as D,n as I}from"./index-D_srC3bj.js";import{g as X,a as Z,_ as ee}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const te={class:"home-page"},se={class:"hero-section"},oe=["src","alt"],ne={key:1,class:"logo-text"},ae={class:"search-box"},ie={key:1,class:"quote-section"},ce={class:"quote-text"},le={class:"quote-author"},re={class:"content-section"},ue={key:0,class:"rankings-grid"},de={class:"panel-header"},_e={class:"panel-title"},he={class:"panel-tabs"},ve=["onClick"],pe=["onClick"],ge={class:"panel-body"},fe=["onClick"],me={class:"rank-name"},ye={class:"rank-cnt"},ke=["onClick"],Ce={class:"panel-footer"},be={key:0},we={key:1},xe={key:2},Ie={key:3},qe={class:"footer-time"},Ae={key:0,class:"site-footer"},Se={class:"footer-inner"},Ne={class:"footer-actions"},R=8,Te=K({__name:"HomePage",setup(Ve){const q=W(),m=l(""),u=l([]),d=B({}),_=B({}),p=l(""),y=l(""),k=l(""),A=l(!1),g=l(""),C=l(""),S=l(""),F={movie:"🎬",western_movie:"🎥",western_tv:"🌍",donghua:"🐉",global_anime:"🌐",tv:"📺",niche:"💎",hotsite:"🏆"};function L(e){return F[e]||"📋"}function j(e){const t=[];if(e.rating&&t.push(`${e.rating}`),e.searchCount>0){const i=e.searchCount;i>=1e8?t.push(`${(i/1e8).toFixed(1)}亿`):i>=1e4?t.push(`${(i/1e4).toFixed(0)}`):t.push(String(i))}return t.join(" ")||""}function N(e){return(_[e.category]||"hot")==="hot"?e.hot||[]:e.newest||[]}function E(e){const t=N(e);return d[e.category]?t:t.slice(0,R)}function H(e){return N(e).length>R&&!d[e.category]}function M(e){d[e]=!0}function T(e,t){_[e]=t,d[e]=!1}function O(){window.open("/disclaimer/","_blank")}G(async()=>{try{const t=await(await fetch("https://v1.hitokoto.cn/")).json();g.value=t.hitokoto||"",C.value=t.from_who||t.from||""}catch{g.value="学而时习之,不亦说乎。",C.value="孔子"}try{const[e,t]=await Promise.all([X(),Z()]);e.fetchedAt?(S.value=e.fetchedAt,u.value=e.categories||[]):u.value=Array.isArray(e)?e:[];for(const i of u.value)_[i.category]="hot",d[i.category]=!1;t.site_logo&&(p.value=t.site_logo),t.site_name&&(y.value=t.site_name),t.site_disclaimer&&(k.value=t.site_disclaimer),A.value=!0}catch(e){console.error("加载首页数据失败",e)}});function V(){const e=m.value.trim();e&&q.push("/search?q="+encodeURIComponent(e))}function P(e){q.push("/search?q="+encodeURIComponent(e))}return(e,t)=>{const i=x("el-icon"),U=x("el-input"),$=x("el-button");return n(),a("div",te,[o("div",se,[A.value?(n(),a(w,{key:0},[p.value?(n(),a("img",{key:0,src:p.value,alt:y.value||"CloudSearch",class:"logo-img",onError:t[0]||(t[0]=s=>{s.target.style.display="none",p.value=""})},null,40,oe)):(n(),a("div",ne,c(y.value||"CloudSearch"),1))],64)):h("",!0),o("div",ae,[v(U,{modelValue:m.value,"onUpdate:modelValue":t[1]||(t[1]=s=>m.value=s),placeholder:"搜索网盘资源,或粘贴视频/网盘链接...",size:"large",clearable:"",onKeyup:Q(V,["enter"])},{prefix:f(()=>[v(i,null,{default:f(()=>[v(Y(J))]),_:1})]),_:1},8,["modelValue"]),v($,{type:"primary",size:"large",onClick:V,class:"search-btn"},{default:f(()=>[...t[2]||(t[2]=[D(" 搜 索 ",-1)])]),_:1})]),g.value?(n(),a("div",ie,[o("span",ce,"「 "+c(g.value)+" 」",1),o("span",le,"---"+c(C.value),1)])):h("",!0)]),o("div",re,[u.value.length>0?(n(),a("div",ue,[(n(!0),a(w,null,z(u.value,s=>(n(),a("div",{key:s.category,class:"rank-panel"},[o("div",de,[o("span",_e,c(L(s.category))+" "+c(s.label),1),o("div",he,[o("span",{class:I(["panel-tab",{active:_[s.category]==="hot"}]),onClick:r=>T(s.category,"hot")},"热榜",10,ve),o("span",{class:I(["panel-tab",{active:_[s.category]==="newest"}]),onClick:r=>T(s.category,"newest")},"最新",10,pe)])]),o("div",ge,[(n(!0),a(w,null,z(E(s),(r,b)=>(n(),a("div",{key:s.category+"-"+b,class:"rank-item",onClick:$e=>P(r.keyword)},[o("span",{class:I(["rank-idx",{"top-three":b<3}])},c(b+1),3),o("span",me,c(r.keyword),1),o("span",ye,c(j(r)),1)],8,fe))),128)),H(s)?(n(),a("div",{key:0,class:"rank-expand",onClick:r=>M(s.category)}," 展开全部 ▼ ",8,ke)):h("",!0)]),o("div",Ce,[s.category==="hotsite"?(n(),a("span",be,"基于本站搜索数据")):s.category==="donghua"||s.category==="global_anime"?(n(),a("span",we,"数据来源Bilibili")):s.category==="movie"||s.category==="tv"?(n(),a("span",xe,"数据来源:百度")):(n(),a("span",Ie,"数据来源TMDB")),o("span",qe,c(S.value),1)])]))),128))])):h("",!0)]),k.value?(n(),a("div",Ae,[o("div",Se,c(k.value),1),o("div",Ne,[v($,{class:"footer-disclaimer-btn",size:"small",onClick:O},{default:f(()=>[...t[3]||(t[3]=[D("📜 免责声明",-1)])]),_:1})])])):h("",!0)])}}}),De=ee(Te,[["__scopeId","data-v-1f536d99"]]);export{De as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
.el-card[data-v-6cdc2b1a]{margin-bottom:20px}.el-card[data-v-6cdc2b1a] .el-card__header{font-weight:600;font-size:15px}[data-v-6cdc2b1a] .el-divider__text.is-left{left:0;padding-left:0}.form-tip[data-v-6cdc2b1a]{font-size:12px;color:#909399;margin-top:4px}.fallback-upload-wrap[data-v-6cdc2b1a]{display:flex;flex-direction:column;gap:12px}.fallback-upload-row[data-v-6cdc2b1a]{display:flex;align-items:center;flex-wrap:wrap}.fallback-preview[data-v-6cdc2b1a]{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.fallback-preview img[data-v-6cdc2b1a]{max-width:100%;height:auto;max-height:120px;border-radius:8px;border:1px solid var(--border-color);background:#f0f0f0;object-fit:contain}.strategy-grid[data-v-6cdc2b1a]{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px 16px}.grid-cell[data-v-6cdc2b1a]{display:flex;flex-direction:column;gap:4px}.strategy-section[data-v-6cdc2b1a]{padding:0 4px}.field-block[data-v-6cdc2b1a]{margin:12px 0}.field-label-row[data-v-6cdc2b1a]{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.field-label[data-v-6cdc2b1a]{font-size:14px;font-weight:500;color:#303133;white-space:nowrap}.field-desc[data-v-6cdc2b1a]{font-size:12px;color:#909399;margin:3px 0 0;line-height:1.5}.keyword-input-row[data-v-6cdc2b1a]{display:flex;gap:8px;flex:1;min-width:200px}.tag-list[data-v-6cdc2b1a]{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}.tag-empty[data-v-6cdc2b1a]{font-size:13px;color:#c0c4cc;margin-top:8px}.filter-rule-help[data-v-6cdc2b1a]{margin-top:8px;padding:10px 12px;background:#f8f9fa;border-radius:8px;border:1px solid #e8e8e8}.filter-rule-help .help-title[data-v-6cdc2b1a]{font-weight:600;font-size:13px;margin:8px 0 4px;color:#333}.filter-rule-help .help-title[data-v-6cdc2b1a]:first-child{margin-top:0}.filter-rule-help .help-row[data-v-6cdc2b1a]{font-size:12px;color:#555;margin:3px 0;line-height:1.6}.filter-rule-help .help-row code[data-v-6cdc2b1a]{background:#eef1f5;padding:1px 5px;border-radius:3px;font-size:11px;font-family:monospace}.filter-rules-help[data-v-6cdc2b1a]{margin-top:8px;padding:12px;background:#f8f9fa;border-radius:8px;border:1px solid #e8e8e8}.help-title[data-v-6cdc2b1a]{font-weight:600;font-size:13px;margin:10px 0 6px;color:#333}.help-title[data-v-6cdc2b1a]:first-child{margin-top:0}.help-row[data-v-6cdc2b1a]{font-size:12px;color:#555;margin:3px 0;line-height:1.6}.help-row code[data-v-6cdc2b1a]{background:#eef1f5;padding:1px 5px;border-radius:3px;font-size:11px;font-family:monospace}.help-sample[data-v-6cdc2b1a]{background:#1e1e1e;color:#d4d4d4;padding:10px 14px;border-radius:6px;font-size:12px;line-height:1.6;overflow-x:auto;white-space:pre;margin:6px 0 0;font-family:monospace}.help-preview-row[data-v-6cdc2b1a]{font-size:13px;margin:4px 0;display:flex;align-items:center;gap:6px}.help-preview-label[data-v-6cdc2b1a]{color:#888;min-width:70px;font-size:12px}.help-preview-original[data-v-6cdc2b1a]{color:#e74c3c}.help-preview-filtered[data-v-6cdc2b1a]{color:#27ae60;font-weight:500}.filter-input-row[data-v-6cdc2b1a]{display:flex;gap:8px;width:100%;margin-bottom:8px}.filter-tag-list[data-v-6cdc2b1a]{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}.filter-empty[data-v-6cdc2b1a]{font-size:13px;color:#c0c4cc;padding:8px 0;margin-bottom:8px}.db-status-grid[data-v-6cdc2b1a]{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px;margin-top:8px}.db-stat-item[data-v-6cdc2b1a]{background:#f8f9fa;border-radius:10px;padding:16px 12px;text-align:center;border:1px solid #eee;transition:transform .15s,box-shadow .15s}.db-stat-item[data-v-6cdc2b1a]:hover{transform:translateY(-2px);box-shadow:0 4px 12px #0000000f}.db-stat-value[data-v-6cdc2b1a]{white-space:nowrap;font-size:24px;font-weight:700;color:#303133;margin-bottom:4px}.db-stat-value.text-success[data-v-6cdc2b1a]{color:#67c23a}.db-stat-value.text-warning[data-v-6cdc2b1a]{color:#e6a23c}.db-stat-label[data-v-6cdc2b1a]{font-size:12px;color:#909399}@media (max-width: 900px){.strategy-grid[data-v-6cdc2b1a]{grid-template-columns:1fr 1fr}}@media (max-width: 600px){.strategy-grid[data-v-6cdc2b1a]{grid-template-columns:1fr}}.pansou-status-grid[data-v-6cdc2b1a]{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px;margin-top:8px}.status-dot[data-v-6cdc2b1a]{width:8px;height:8px;border-radius:50%;display:inline-block}.dot-ok[data-v-6cdc2b1a]{background:#67c23a}.dot-err[data-v-6cdc2b1a]{background:#f56c6c}

View File

@@ -1 +0,0 @@
.el-card[data-v-641a8223]{margin-bottom:20px}.el-card[data-v-641a8223] .el-card__header{font-weight:600;font-size:15px}[data-v-641a8223] .el-divider__text.is-left{left:0;padding-left:0}.form-tip[data-v-641a8223]{font-size:12px;color:#909399;margin-top:4px}.fallback-upload-wrap[data-v-641a8223]{display:flex;flex-direction:column;gap:12px}.fallback-upload-row[data-v-641a8223]{display:flex;align-items:center;flex-wrap:wrap}.fallback-preview[data-v-641a8223]{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.fallback-preview img[data-v-641a8223]{max-width:100%;height:auto;max-height:120px;border-radius:8px;border:1px solid var(--border-color);background:#f0f0f0;object-fit:contain}.strategy-grid[data-v-641a8223]{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px 16px}.grid-cell[data-v-641a8223]{display:flex;flex-direction:column;gap:4px}.strategy-section[data-v-641a8223]{padding:0 4px}.field-block[data-v-641a8223]{margin:12px 0}.field-label-row[data-v-641a8223]{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.field-label[data-v-641a8223]{font-size:14px;font-weight:500;color:#303133;white-space:nowrap}.field-desc[data-v-641a8223]{font-size:12px;color:#909399;margin:3px 0 0;line-height:1.5}.keyword-input-row[data-v-641a8223]{display:flex;gap:8px;flex:1;min-width:200px}.tag-list[data-v-641a8223]{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}.tag-empty[data-v-641a8223]{font-size:13px;color:#c0c4cc;margin-top:8px}.filter-rule-help[data-v-641a8223]{margin-top:8px;padding:10px 12px;background:#f8f9fa;border-radius:8px;border:1px solid #e8e8e8}.filter-rule-help .help-title[data-v-641a8223]{font-weight:600;font-size:13px;margin:8px 0 4px;color:#333}.filter-rule-help .help-title[data-v-641a8223]:first-child{margin-top:0}.filter-rule-help .help-row[data-v-641a8223]{font-size:12px;color:#555;margin:3px 0;line-height:1.6}.filter-rule-help .help-row code[data-v-641a8223]{background:#eef1f5;padding:1px 5px;border-radius:3px;font-size:11px;font-family:monospace}.filter-rules-help[data-v-641a8223]{margin-top:8px;padding:12px;background:#f8f9fa;border-radius:8px;border:1px solid #e8e8e8}.help-title[data-v-641a8223]{font-weight:600;font-size:13px;margin:10px 0 6px;color:#333}.help-title[data-v-641a8223]:first-child{margin-top:0}.help-row[data-v-641a8223]{font-size:12px;color:#555;margin:3px 0;line-height:1.6}.help-row code[data-v-641a8223]{background:#eef1f5;padding:1px 5px;border-radius:3px;font-size:11px;font-family:monospace}.help-sample[data-v-641a8223]{background:#1e1e1e;color:#d4d4d4;padding:10px 14px;border-radius:6px;font-size:12px;line-height:1.6;overflow-x:auto;white-space:pre;margin:6px 0 0;font-family:monospace}.help-preview-row[data-v-641a8223]{font-size:13px;margin:4px 0;display:flex;align-items:center;gap:6px}.help-preview-label[data-v-641a8223]{color:#888;min-width:70px;font-size:12px}.help-preview-original[data-v-641a8223]{color:#e74c3c}.help-preview-filtered[data-v-641a8223]{color:#27ae60;font-weight:500}.filter-input-row[data-v-641a8223]{display:flex;gap:8px;width:100%;margin-bottom:8px}.filter-tag-list[data-v-641a8223]{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}.filter-empty[data-v-641a8223]{font-size:13px;color:#c0c4cc;padding:8px 0;margin-bottom:8px}.db-status-grid[data-v-641a8223]{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px;margin-top:8px}.db-stat-item[data-v-641a8223]{background:#f8f9fa;border-radius:10px;padding:16px 12px;text-align:center;border:1px solid #eee;transition:transform .15s,box-shadow .15s}.db-stat-item[data-v-641a8223]:hover{transform:translateY(-2px);box-shadow:0 4px 12px #0000000f}.db-stat-value[data-v-641a8223]{white-space:nowrap;font-size:24px;font-weight:700;color:#303133;margin-bottom:4px}.db-stat-value.text-success[data-v-641a8223]{color:#67c23a}.db-stat-value.text-warning[data-v-641a8223]{color:#e6a23c}.db-stat-label[data-v-641a8223]{font-size:12px;color:#909399}@media (max-width: 900px){.strategy-grid[data-v-641a8223]{grid-template-columns:1fr 1fr}}@media (max-width: 600px){.strategy-grid[data-v-641a8223]{grid-template-columns:1fr}}.pansou-status-grid[data-v-641a8223]{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px;margin-top:8px}.status-dot[data-v-641a8223]{width:8px;height:8px;border-radius:50%;display:inline-block}.dot-ok[data-v-641a8223]{background:#67c23a}.dot-err[data-v-641a8223]{background:#f56c6c}

View File

@@ -21,7 +21,7 @@
}
})();
</script>
<script type="module" crossorigin src="/assets/index-D279dJND.js"></script>
<script type="module" crossorigin src="/assets/index-D_srC3bj.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Ekbe64zQ.css">
</head>
<body>

View File

@@ -183,6 +183,23 @@ async function start(): Promise<void> {
setInterval(() => { refreshAllStorageInfo().catch(err => console.error('[Storage] Refresh error:', err.message)); }, STORAGE_REFRESH_INTERVAL);
setTimeout(() => { refreshAllStorageInfo().catch(err => console.error('[Storage] Initial refresh error:', err.message)); }, 60000);
// Daily Report scheduler — check every 60 seconds
const DAILY_REPORT_CHECK_INTERVAL = 60 * 1000;
setInterval(() => {
try {
const { runDailyReportIfScheduled } = require('./services/daily-report.service');
runDailyReportIfScheduled().catch(err => console.error('[DailyReport] Scheduler error:', err.message));
} catch {}
}, DAILY_REPORT_CHECK_INTERVAL);
// Also run once 30s after startup (catch case where server starts at 08:00-08:05)
setTimeout(() => {
try {
const { runDailyReportIfScheduled } = require('./services/daily-report.service');
runDailyReportIfScheduled().catch(err => console.error('[DailyReport] Initial check error:', err.message));
} catch {}
}, 30000);
const server = app.listen(config.port, () => {
console.log(`[Server] CloudSearch Backend running on port ${config.port} (${config.nodeEnv})`);
});

View File

@@ -796,5 +796,71 @@ router.delete('/admin/push-users/:id', (req: Request, res: Response) => {
}
});
// ═══════════════════════════════════════════════
// Daily Report
// ═══════════════════════════════════════════════
/** GET /api/admin/daily-report/config */
router.get('/admin/daily-report/config', (_req, res) => {
try {
const { getDailyReportConfig } = require('../services/daily-report.service');
const cfg = getDailyReportConfig();
res.json(cfg);
} catch (err: any) {
res.status(500).json({ error: err.message || 'Failed to get daily report config' });
}
});
/** PUT /api/admin/daily-report/config */
router.put('/admin/daily-report/config', (req, res) => {
try {
const { saveDailyReportConfig } = require('../services/daily-report.service');
saveDailyReportConfig(req.body);
const { getDailyReportConfig } = require('../services/daily-report.service');
res.json(getDailyReportConfig());
} catch (err: any) {
res.status(500).json({ error: err.message || 'Failed to save daily report config' });
}
});
/** GET /api/admin/daily-report/preview */
router.get('/admin/daily-report/preview', (req, res) => {
try {
const { previewDailyReport, generateDailyReport } = require('../services/daily-report.service');
const date = req.query.date as string || undefined;
const content = previewDailyReport(date);
const report = generateDailyReport(date);
res.json({ content, report });
} catch (err: any) {
res.status(500).json({ error: err.message || 'Failed to preview daily report' });
}
});
/** POST /api/admin/daily-report/test — send a test report immediately */
router.post('/admin/daily-report/test', async (_req, res) => {
try {
const { sendTestDailyReport } = require('../services/daily-report.service');
const result = await sendTestDailyReport();
res.json(result);
} catch (err: any) {
res.status(500).json({ error: err.message || 'Failed to send test report' });
}
});
/** GET /api/admin/daily-report/last-run */
router.get('/admin/daily-report/last-run', (_req, res) => {
try {
const { getSystemConfig } = require('../admin/system-config.service');
const raw = getSystemConfig('daily_report_last_run') || '{}';
let data: any = {};
try { data = JSON.parse(raw); } catch {}
res.json(data);
} catch (err: any) {
res.status(500).json({ error: err.message });
}
});
export default router;

View File

@@ -0,0 +1,339 @@
/**
* Daily Report Service — generates a summary of yesterday's cloud storage activity
* and sends it through configured notification channels at 08:00 daily.
*/
import { getDb } from '../database/database';
import { getSystemConfig } from '../admin/system-config.service';
import { getCloudConfigs } from '../cloud/credential.service';
import { notify } from '../cloud/notification.service';
// ═══════════════════════════════════════════════
// Types
// ═══════════════════════════════════════════════
export interface DailyReportConfig {
enabled: boolean;
time: string; // "HH:mm" e.g. "08:00"
includeSearch: boolean;
includeSaves: boolean;
includeStorage: boolean;
includeUsers: boolean;
}
export interface DailyReport {
date: string;
searchCount: number;
uniqueSearchers: number;
saveCounts: { total: number; success: number; fail: number };
byCloud: Array<{
cloudType: string;
nickname: string;
saves: number;
successes: number;
storageUsed: string;
storageTotal: string;
isActive: boolean;
}>;
uniqueSavers: number;
}
// ═══════════════════════════════════════════════
// Config
// ═══════════════════════════════════════════════
export function getDailyReportConfig(): DailyReportConfig {
const raw = getSystemConfig('daily_report_config') || '{}';
let parsed: Partial<DailyReportConfig> = {};
try { parsed = JSON.parse(raw); } catch {}
return {
enabled: parsed.enabled !== false,
time: parsed.time || '08:00',
includeSearch: parsed.includeSearch !== false,
includeSaves: parsed.includeSaves !== false,
includeStorage: parsed.includeStorage !== false,
includeUsers: parsed.includeUsers !== false,
};
}
export function saveDailyReportConfig(cfg: Partial<DailyReportConfig>): void {
const current = getDailyReportConfig();
const merged = { ...current, ...cfg };
const { getDb } = require('../database/database');
const db = getDb();
const existing = db.prepare("SELECT key FROM system_configs WHERE key = 'daily_report_config'").get();
if (existing) {
db.prepare("UPDATE system_configs SET value = ?, updated_at = datetime('now','localtime') WHERE key = 'daily_report_config'")
.run(JSON.stringify(merged));
} else {
db.prepare("INSERT INTO system_configs (key, value, description) VALUES (?, ?, ?)")
.run('daily_report_config', JSON.stringify(merged), 'Daily report configuration');
}
}
// ═══════════════════════════════════════════════
// Report Generation
// ═══════════════════════════════════════════════
function getYesterday(): string {
const d = new Date();
d.setDate(d.getDate() - 1);
return d.toISOString().slice(0, 10); // "2026-05-16"
}
function getYesterdayRange(): { start: string; end: string } {
const date = getYesterday();
return {
start: `${date}T00:00:00`,
end: `${date}T23:59:59`,
};
}
export function generateDailyReport(dateOverride?: string): DailyReport {
const db = getDb();
const { start, end } = dateOverride
? { start: `${dateOverride}T00:00:00`, end: `${dateOverride}T23:59:59` }
: getYesterdayRange();
const date = dateOverride || getYesterday();
// ── Searches ──
let searchCount = 0;
let uniqueSearchers = 0;
try {
const searchRow = db.prepare(
"SELECT COUNT(*) as cnt FROM search_stats WHERE created_at >= ? AND created_at <= ?"
).get(start, end) as any;
searchCount = searchRow?.cnt || 0;
const searcherRow = db.prepare(
"SELECT COUNT(DISTINCT ip_address) as cnt FROM search_stats WHERE created_at >= ? AND created_at <= ?"
).get(start, end) as any;
uniqueSearchers = searcherRow?.cnt || 0;
} catch {}
// ── Saves ──
let totalSaves = 0;
let successSaves = 0;
let failSaves = 0;
let uniqueSavers = 0;
try {
const saveRow = db.prepare(
"SELECT COUNT(*) as cnt FROM save_records WHERE created_at >= ? AND created_at <= ?"
).get(start, end) as any;
totalSaves = saveRow?.cnt || 0;
const successRow = db.prepare(
"SELECT COUNT(*) as cnt FROM save_records WHERE created_at >= ? AND created_at <= ? AND status = 'success'"
).get(start, end) as any;
successSaves = successRow?.cnt || 0;
const failRow = db.prepare(
"SELECT COUNT(*) as cnt FROM save_records WHERE created_at >= ? AND created_at <= ? AND status != 'success'"
).get(start, end) as any;
failSaves = failRow?.cnt || 0;
const saverRow = db.prepare(
"SELECT COUNT(DISTINCT ip_address) as cnt FROM save_records WHERE created_at >= ? AND created_at <= ?"
).get(start, end) as any;
uniqueSavers = saverRow?.cnt || 0;
} catch {}
// ── Per Cloud Breakdown ──
const byCloud: DailyReport['byCloud'] = [];
try {
const clouds = getCloudConfigs();
for (const c of clouds) {
const cloudSaveRow = db.prepare(
"SELECT COUNT(*) as cnt FROM save_records WHERE created_at >= ? AND created_at <= ? AND target_cloud = ?"
).get(start, end, c.cloud_type) as any;
const cloudSuccessRow = db.prepare(
"SELECT COUNT(*) as cnt FROM save_records WHERE created_at >= ? AND created_at <= ? AND target_cloud = ? AND status = 'success'"
).get(start, end, c.cloud_type) as any;
byCloud.push({
cloudType: c.cloud_type,
nickname: c.nickname || '未知',
saves: cloudSaveRow?.cnt || 0,
successes: cloudSuccessRow?.cnt || 0,
storageUsed: c.storage_used || 'N/A',
storageTotal: c.storage_total || 'N/A',
isActive: !!c.is_active,
});
}
} catch {}
return {
date,
searchCount,
uniqueSearchers,
saveCounts: { total: totalSaves, success: successSaves, fail: failSaves },
byCloud,
uniqueSavers,
};
}
// ═══════════════════════════════════════════════
// Formatting
// ═══════════════════════════════════════════════
function formatStorage(used: string, total: string): string {
try {
const parseSize = (s: string): number => {
const m = s.match(/^([\d.]+)\s*(B|KB|MB|GB|TB)$/i);
if (!m) return 0;
const units: Record<string, number> = { B: 1, KB: 1024, MB: 1024**2, GB: 1024**3, TB: 1024**4 };
return parseFloat(m[1]) * (units[m[2].toUpperCase()] || 1);
};
const u = parseSize(used);
const t = parseSize(total);
if (t === 0) return `${used} / ${total}`;
const pct = ((u / t) * 100).toFixed(1);
return `${used} / ${total} (${pct}%)`;
} catch {
return `${used} / ${total}`;
}
}
const CLOUD_LABELS: Record<string, string> = {
quark: '夸克', baidu: '百度', aliyun: '阿里云盘', '115': '115网盘',
tianyi: '天翼云', '123pan': '123云盘', uc: 'UC网盘', xunlei: '迅雷云盘',
pikpak: 'PikPak', magnet: '磁力链接', ed2k: '电驴链接', others: '其他',
};
function cloudLabel(type: string): string {
return CLOUD_LABELS[type] || type;
}
export function formatDailyReport(report: DailyReport, includeSearch = true, includeSaves = true, includeStorage = true, includeUsers = true): string {
const lines: string[] = [];
const formattedDate = report.date.replace(/-/g, '/');
lines.push(`📊 **CloudSearch 每日汇报**`);
lines.push(`📅 ${formattedDate}`);
lines.push('');
if (includeSearch && report.searchCount > 0) {
lines.push(`🔍 **搜索统计**`);
lines.push(` 总搜索: ${report.searchCount}`);
if (includeUsers) lines.push(` 搜索用户: ${report.uniqueSearchers}`);
lines.push('');
}
if (includeSaves) {
const { total, success, fail } = report.saveCounts;
lines.push(`💾 **转存统计**`);
lines.push(` 总转存: ${total}`);
lines.push(` 成功: ${success} 次 | 失败: ${fail}`);
if (total > 0) lines.push(` 成功率: ${((success / total) * 100).toFixed(1)}%`);
if (includeUsers) lines.push(` 转存用户: ${report.uniqueSavers}`);
lines.push('');
}
if (includeStorage && report.byCloud.length > 0) {
lines.push(`☁️ **网盘状态**`);
for (const c of report.byCloud) {
const icon = c.isActive ? '🟢' : '🔴';
const label = cloudLabel(c.cloudType);
if (c.saves > 0) {
lines.push(` ${icon} ${label} · ${c.nickname} · 转存 ${c.saves} 次 · ${formatStorage(c.storageUsed, c.storageTotal)}`);
} else {
lines.push(` ${icon} ${label} · ${c.nickname} · ${formatStorage(c.storageUsed, c.storageTotal)}`);
}
}
lines.push('');
}
if (report.saveCounts.total === 0 && report.searchCount === 0) {
lines.push(`💤 昨日无活动记录`);
}
return lines.join('\n');
}
// ═══════════════════════════════════════════════
// Scheduler
// ═══════════════════════════════════════════════
let lastRunDate = '';
function getTodayStr(): string {
return new Date().toISOString().slice(0, 10);
}
export async function runDailyReportIfScheduled(): Promise<void> {
const cfg = getDailyReportConfig();
if (!cfg.enabled) return;
const now = new Date();
const [hh, mm] = cfg.time.split(':').map(Number);
const scheduledMinute = hh * 60 + mm;
const currentMinute = now.getHours() * 60 + now.getMinutes();
// Run within a 5-minute window of scheduled time
const diff = currentMinute - scheduledMinute;
if (diff < 0 || diff >= 5) return;
const today = getTodayStr();
if (lastRunDate === today) return; // already ran today
lastRunDate = today;
console.log(`[DailyReport] Running daily report for ${today}...`);
try {
const report = generateDailyReport();
const content = formatDailyReport(
report,
cfg.includeSearch,
cfg.includeSaves,
cfg.includeStorage,
cfg.includeUsers
);
notify('CloudSearch 每日汇报', content, 'info');
// Record last run
const { getDb } = require('../database/database');
const db = getDb();
const existing = db.prepare("SELECT key FROM system_configs WHERE key = 'daily_report_last_run'").get();
if (existing) {
db.prepare("UPDATE system_configs SET value = ?, updated_at = datetime('now','localtime') WHERE key = 'daily_report_last_run'")
.run(JSON.stringify({ date: today, sentAt: new Date().toISOString() }));
} else {
db.prepare("INSERT INTO system_configs (key, value, description) VALUES (?, ?, ?)")
.run('daily_report_last_run', JSON.stringify({ date: today, sentAt: new Date().toISOString() }), 'Last daily report run');
}
console.log(`[DailyReport] Report sent successfully for ${today}`);
} catch (err: any) {
console.error(`[DailyReport] Failed:`, err.message);
}
}
// ═══════════════════════════════════════════════
// Manual test preview
// ═══════════════════════════════════════════════
export function previewDailyReport(dateOverride?: string): string {
const report = generateDailyReport(dateOverride);
const cfg = getDailyReportConfig();
return formatDailyReport(
report,
cfg.includeSearch,
cfg.includeSaves,
cfg.includeStorage,
cfg.includeUsers
);
}
export async function sendTestDailyReport(): Promise<{ success: boolean; report: DailyReport }> {
const report = generateDailyReport();
const cfg = getDailyReportConfig();
const content = formatDailyReport(
report,
cfg.includeSearch,
cfg.includeSaves,
cfg.includeStorage,
cfg.includeUsers
);
notify('CloudSearch 每日汇报 [测试]', content, 'info');
return { success: true, report };
}