Files
zsglpt/static/admin/assets/SystemPage-DVj-4Lnp.js
yuyx b0fe325154 feat: KDocs 上传增强 + 离线监控 + Bug修复
KDocs 上传功能增强:
- 搜索优化:只用姓名搜索 + C列验证,避免匹配到错误单元格
- 有效行范围:支持配置起始行/结束行,限制上传区域
- 图片覆盖:支持覆盖单元格已有图片(Escape + Delete)
- 配置持久化:kdocs_row_start/row_end 保存到数据库(v18迁移)

二次登录功能:
- 登录后立即再次登录,让"上次登录时间"显示为刚刚

KDocs 离线监控:
- 每5分钟检测金山文档登录状态
- 离线时发送邮件通知管理员(每次掉线只通知一次)
- 恢复在线后重置通知状态

Bug 修复:
- 任务日志搜索账号关键词报错500:添加异常处理

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 23:40:46 +08:00

18 lines
17 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import{f as Ee,u as oe,e as $e}from"./system-C6kBIFhi.js";import{a as A,_ as Le,r as n,c as fe,U as He,T as qe,o as Qe,f as v,I as Fe,J as Me,h as f,g as k,j as u,m as l,w as o,q as m,B as ne,n as w,F as Re,v as je,p as ue,K as se,L as i}from"./index-DKH_HvPt.js";async function ie(p={}){const{data:_}=await A.get("/kdocs/status",{params:p});return _}async function ze(p={}){const _={force:!0,...p},{data:U}=await A.post("/kdocs/qr",_);return U}async function Oe(){const{data:p}=await A.post("/kdocs/clear-login",{});return p}async function We(){const{data:p}=await A.get("/proxy/config");return p}async function Ge(p){const{data:_}=await A.post("/proxy/config",p);return _}async function Je(p){const{data:_}=await A.post("/proxy/test",p);return _}const Xe={class:"page-stack"},Ye={class:"app-page-title"},Ze={class:"row-actions"},el={class:"row-actions"},ll={style:{display:"flex","align-items":"center",gap:"8px"}},al={class:"row-actions"},tl={class:"help"},ol={key:0},nl={key:1},ul={key:2},sl={key:3},dl={key:0,class:"help"},rl={class:"kdocs-qr"},il=["src"],ml={__name:"SystemPage",setup(p){const _=n(!1),U=n(2),$=n(1),L=n(3),y=n(!1),H=n("02:00"),B=n("应读"),g=n(["1","2","3","4","5","6","7"]),T=n(!0),D=n(!1),x=n(""),q=n(3),Q=n(!1),F=n(10),M=n(7),R=n(!1),j=n(""),z=n(""),O=n(""),W=n(0),G=n("A"),J=n("D"),X=n(0),Y=n(0),Z=n(!1),ee=n(""),b=n({}),C=n(!1),P=n(""),me=n(!1),h=n(!1),S=n(!1),I=n(!1),le=n("");let ae=null;const _e=[{label:"周一",value:"1"},{label:"周二",value:"2"},{label:"周三",value:"3"},{label:"周四",value:"4"},{label:"周五",value:"5"},{label:"周六",value:"6"},{label:"周日",value:"7"}],ye={1:"周一",2:"周二",3:"周三",4:"周四",5:"周五",6:"周六",7:"周日"},be=fe(()=>(g.value||[]).map(a=>ye[Number(a)]||a).join("、")),de=fe(()=>h.value||S.value||I.value);function ke(a){return String(a)==="注册前未读"?"注册前未读":"应读"}function c(a){if(!a){le.value="";return}const e=new Date().toLocaleTimeString("zh-CN",{hour12:!1});le.value=`${a} (${e})`}async function ce(){_.value=!0;try{const[a,e,d]=await Promise.all([Ee(),We(),ie().catch(()=>({}))]);U.value=a.max_concurrent_global??2,$.value=a.max_concurrent_per_account??1,L.value=a.max_screenshot_concurrent??3,y.value=(a.schedule_enabled??0)===1,H.value=a.schedule_time||"02:00",B.value=ke(a.schedule_browse_type);const r=String(a.schedule_weekdays||"1,2,3,4,5,6,7").split(",").map(s=>s.trim()).filter(Boolean);g.value=r.length?r:["1","2","3","4","5","6","7"],T.value=(a.enable_screenshot??1)===1,Q.value=(a.auto_approve_enabled??0)===1,F.value=a.auto_approve_hourly_limit??10,M.value=a.auto_approve_vip_days??7,D.value=(e.proxy_enabled??0)===1,x.value=e.proxy_api_url||"",q.value=e.proxy_expire_minutes??3,R.value=(a.kdocs_enabled??0)===1,j.value=a.kdocs_doc_url||"",z.value=a.kdocs_default_unit||"",O.value=a.kdocs_sheet_name||"",W.value=a.kdocs_sheet_index??0,G.value=(a.kdocs_unit_column||"A").toUpperCase(),J.value=(a.kdocs_image_column||"D").toUpperCase(),X.value=a.kdocs_row_start??0,Y.value=a.kdocs_row_end??0,Z.value=(a.kdocs_admin_notify_enabled??0)===1,ee.value=a.kdocs_admin_notify_email||"",b.value=d||{}}catch{}finally{_.value=!1}}async function ge(){const a={max_concurrent_global:Number(U.value),max_concurrent_per_account:Number($.value),max_screenshot_concurrent:Number(L.value)};try{await se.confirm(`确定更新并发配置吗?
全局并发数: ${a.max_concurrent_global}
单账号并发数: ${a.max_concurrent_per_account}
截图并发数: ${a.max_screenshot_concurrent}`,"保存并发配置",{confirmButtonText:"保存",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await oe(a);i.success(e?.message||"并发配置已更新")}catch{}}async function xe(){if(y.value&&(!g.value||g.value.length===0)){i.error("请至少选择一个执行日期");return}const a={schedule_enabled:y.value?1:0,schedule_time:H.value,schedule_browse_type:B.value,schedule_weekdays:(g.value||[]).join(","),enable_screenshot:T.value?1:0},e=T.value?"截图":"不截图",d=y.value?`确定启用定时任务吗?
执行时间: 每天 ${a.schedule_time}
执行日期: ${be.value}
浏览类型: ${a.schedule_browse_type}
截图: ${e}
系统将自动执行所有账号的浏览任务`:"确定关闭定时任务吗?";try{await se.confirm(d,"保存定时任务",{confirmButtonText:"确认",cancelButtonText:"取消",type:"warning"})}catch{return}try{const r=await oe(a);i.success(r?.message||(y.value?"定时任务已启用":"定时任务已关闭"))}catch{}}async function Ve(){const a=`确定要立即执行定时任务吗?
这将执行所有账号的浏览任务
浏览类型: ${B.value}
注意:无视定时时间和执行日期配置,立即开始执行!`;try{await se.confirm(a,"立即执行",{confirmButtonText:"立即执行",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await $e();i.success(e?.message||"定时任务已开始执行")}catch{}}async function we(){if(D.value&&!x.value.trim()){i.error("启用代理时API地址不能为空");return}const a={proxy_enabled:D.value?1:0,proxy_api_url:x.value.trim(),proxy_expire_minutes:Number(q.value)||3};try{const e=await Ge(a);i.success(e?.message||"代理配置已更新")}catch{}}async function Ue(){const a={kdocs_enabled:R.value?1:0,kdocs_doc_url:j.value.trim(),kdocs_default_unit:z.value.trim(),kdocs_sheet_name:O.value.trim(),kdocs_sheet_index:Number(W.value)||0,kdocs_unit_column:G.value.trim().toUpperCase(),kdocs_image_column:J.value.trim().toUpperCase(),kdocs_row_start:Number(X.value)||0,kdocs_row_end:Number(Y.value)||0,kdocs_admin_notify_enabled:Z.value?1:0,kdocs_admin_notify_email:ee.value.trim()};try{const e=await oe(a);i.success(e?.message||"表格配置已更新")}catch{}}async function re(){if(!h.value){h.value=!0,c("正在刷新状态");try{b.value=await ie({live:1}),c("状态已刷新")}catch{c("刷新失败,请稍后重试")}finally{h.value=!1}}}async function ve(){try{const a=await ie({live:1});b.value=a,(a?.logged_in===!0||a?.last_login_ok===!0)&&(i.success("扫码成功,已登录"),c("扫码成功,已登录"),C.value=!1,te())}catch{}}function Ce(){te(),me.value=!0,c("扫码检测中"),ve(),ae=setInterval(ve,2e3)}function te(){ae&&(clearInterval(ae),ae=null),me.value=!1}async function Pe(){if(!S.value){S.value=!0,c("正在获取二维码");try{P.value="";const a=await ze();if(P.value=a?.qr_image||"",!P.value){if(a?.logged_in){i.success("当前已登录,无需扫码"),c("当前已登录,无需扫码"),await re();return}i.warning("未获取到二维码"),c("未获取到二维码");return}c("二维码已获取"),C.value=!0}catch{c("获取二维码失败")}finally{S.value=!1}}}async function he(){if(!I.value){I.value=!0,c("正在清除登录态");try{await Oe(),C.value=!1,P.value="",i.success("登录态已清除"),c("登录态已清除"),await re()}catch{c("清除登录态失败")}finally{I.value=!1}}}He(C,a=>{a?Ce():te()}),qe(()=>{te()});async function Se(){if(!x.value.trim()){i.error("请先输入代理API地址");return}try{const a=await Je({api_url:x.value.trim()});await se.alert(a?.message||"测试完成","代理测试",{confirmButtonText:"知道了"})}catch{}}async function Ie(){const a=Number(F.value),e=Number(M.value);if(!Number.isFinite(a)||a<1){i.error("每小时注册限制必须大于0");return}if(!Number.isFinite(e)||e<0){i.error("VIP天数不能为负数");return}const d={auto_approve_enabled:Q.value?1:0,auto_approve_hourly_limit:a,auto_approve_vip_days:e};try{const r=await oe(d);i.success(r?.message||"注册设置已保存")}catch{}}return Qe(ce),(a,e)=>{const d=v("el-button"),r=v("el-input-number"),s=v("el-form-item"),K=v("el-form"),E=v("el-card"),N=v("el-switch"),Ne=v("el-time-picker"),pe=v("el-option"),Ae=v("el-select"),Be=v("el-checkbox"),Te=v("el-checkbox-group"),V=v("el-input"),De=v("el-dialog"),Ke=Fe("loading");return Me((f(),k("div",Xe,[u("div",Ye,[e[27]||(e[27]=u("h2",null,"系统配置",-1)),u("div",null,[l(d,{onClick:ce},{default:o(()=>[...e[26]||(e[26]=[m("刷新",-1)])]),_:1})])]),l(E,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:o(()=>[e[32]||(e[32]=u("h3",{class:"section-title"},"系统并发配置",-1)),l(K,{"label-width":"130px"},{default:o(()=>[l(s,{label:"全局最大并发数"},{default:o(()=>[l(r,{modelValue:U.value,"onUpdate:modelValue":e[0]||(e[0]=t=>U.value=t),min:1,max:200},null,8,["modelValue"]),e[28]||(e[28]=u("div",{class:"help"},"同时最多运行的账号数量(浏览任务使用 API 方式,资源占用较低)。",-1))]),_:1}),l(s,{label:"单账号最大并发数"},{default:o(()=>[l(r,{modelValue:$.value,"onUpdate:modelValue":e[1]||(e[1]=t=>$.value=t),min:1,max:50},null,8,["modelValue"]),e[29]||(e[29]=u("div",{class:"help"},"单个账号同时最多运行的任务数量(建议设为 1。",-1))]),_:1}),l(s,{label:"截图最大并发数"},{default:o(()=>[l(r,{modelValue:L.value,"onUpdate:modelValue":e[2]||(e[2]=t=>L.value=t),min:1,max:50},null,8,["modelValue"]),e[30]||(e[30]=u("div",{class:"help"},"同时进行截图的最大数量wkhtmltoimage 资源占用较低,可按需提高)。",-1))]),_:1})]),_:1}),l(d,{type:"primary",onClick:ge},{default:o(()=>[...e[31]||(e[31]=[m("保存并发配置",-1)])]),_:1})]),_:1}),l(E,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:o(()=>[e[37]||(e[37]=u("h3",{class:"section-title"},"定时任务配置",-1)),l(K,{"label-width":"130px"},{default:o(()=>[l(s,{label:"启用定时任务"},{default:o(()=>[l(N,{modelValue:y.value,"onUpdate:modelValue":e[3]||(e[3]=t=>y.value=t)},null,8,["modelValue"]),e[33]||(e[33]=u("div",{class:"help"},"开启后,系统会按计划自动执行浏览任务。",-1))]),_:1}),y.value?(f(),ne(s,{key:0,label:"执行时间"},{default:o(()=>[l(Ne,{modelValue:H.value,"onUpdate:modelValue":e[4]||(e[4]=t=>H.value=t),"value-format":"HH:mm",format:"HH:mm"},null,8,["modelValue"])]),_:1})):w("",!0),y.value?(f(),ne(s,{key:1,label:"浏览类型"},{default:o(()=>[l(Ae,{modelValue:B.value,"onUpdate:modelValue":e[5]||(e[5]=t=>B.value=t),style:{width:"220px"}},{default:o(()=>[l(pe,{label:"注册前未读",value:"注册前未读"}),l(pe,{label:"应读",value:"应读"})]),_:1},8,["modelValue"])]),_:1})):w("",!0),y.value?(f(),ne(s,{key:2,label:"执行日期"},{default:o(()=>[l(Te,{modelValue:g.value,"onUpdate:modelValue":e[6]||(e[6]=t=>g.value=t)},{default:o(()=>[(f(),k(Re,null,je(_e,t=>l(Be,{key:t.value,label:t.value},{default:o(()=>[m(ue(t.label),1)]),_:2},1032,["label"])),64))]),_:1},8,["modelValue"])]),_:1})):w("",!0),y.value?(f(),ne(s,{key:3,label:"定时任务截图"},{default:o(()=>[l(N,{modelValue:T.value,"onUpdate:modelValue":e[7]||(e[7]=t=>T.value=t)},null,8,["modelValue"]),e[34]||(e[34]=u("div",{class:"help"},"开启后,定时任务执行时会生成截图。",-1))]),_:1})):w("",!0)]),_:1}),u("div",Ze,[l(d,{type:"primary",onClick:xe},{default:o(()=>[...e[35]||(e[35]=[m("保存定时任务配置",-1)])]),_:1}),l(d,{type:"success",plain:"",onClick:Ve},{default:o(()=>[...e[36]||(e[36]=[m("立即执行",-1)])]),_:1})])]),_:1}),l(E,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:o(()=>[e[42]||(e[42]=u("h3",{class:"section-title"},"代理设置",-1)),l(K,{"label-width":"130px"},{default:o(()=>[l(s,{label:"启用IP代理"},{default:o(()=>[l(N,{modelValue:D.value,"onUpdate:modelValue":e[8]||(e[8]=t=>D.value=t)},null,8,["modelValue"]),e[38]||(e[38]=u("div",{class:"help"},"开启后所有浏览任务将通过代理IP访问失败自动重试3次。",-1))]),_:1}),l(s,{label:"代理API地址"},{default:o(()=>[l(V,{modelValue:x.value,"onUpdate:modelValue":e[9]||(e[9]=t=>x.value=t),placeholder:"http://api.xxx/Tools/IP.ashx?..."},null,8,["modelValue"]),e[39]||(e[39]=u("div",{class:"help"},"API 应返回IP:PORT例如 123.45.67.89:8888。",-1))]),_:1}),l(s,{label:"代理有效期(分钟)"},{default:o(()=>[l(r,{modelValue:q.value,"onUpdate:modelValue":e[10]||(e[10]=t=>q.value=t),min:1,max:60},null,8,["modelValue"])]),_:1})]),_:1}),u("div",el,[l(d,{type:"primary",onClick:we},{default:o(()=>[...e[40]||(e[40]=[m("保存代理配置",-1)])]),_:1}),l(d,{onClick:Se},{default:o(()=>[...e[41]||(e[41]=[m("测试代理",-1)])]),_:1})])]),_:1}),l(E,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:o(()=>[e[45]||(e[45]=u("h3",{class:"section-title"},"注册设置",-1)),l(K,{"label-width":"130px"},{default:o(()=>[l(s,{label:"注册赠送VIP"},{default:o(()=>[l(N,{modelValue:Q.value,"onUpdate:modelValue":e[11]||(e[11]=t=>Q.value=t)},null,8,["modelValue"]),e[43]||(e[43]=u("div",{class:"help"},"开启后新用户注册成功后将赠送下方设置的VIP天数注册已默认无需审核。",-1))]),_:1}),l(s,{label:"每小时注册限制"},{default:o(()=>[l(r,{modelValue:F.value,"onUpdate:modelValue":e[12]||(e[12]=t=>F.value=t),min:1,max:1e4},null,8,["modelValue"])]),_:1}),l(s,{label:"注册赠送VIP天数"},{default:o(()=>[l(r,{modelValue:M.value,"onUpdate:modelValue":e[13]||(e[13]=t=>M.value=t),min:0,max:999999},null,8,["modelValue"])]),_:1})]),_:1}),l(d,{type:"primary",onClick:Ie},{default:o(()=>[...e[44]||(e[44]=[m("保存注册设置",-1)])]),_:1})]),_:1}),l(E,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:o(()=>[e[55]||(e[55]=u("h3",{class:"section-title"},"金山文档上传",-1)),l(K,{"label-width":"130px"},{default:o(()=>[l(s,{label:"启用上传"},{default:o(()=>[l(N,{modelValue:R.value,"onUpdate:modelValue":e[14]||(e[14]=t=>R.value=t)},null,8,["modelValue"]),e[46]||(e[46]=u("div",{class:"help"},"表格结构变化时可先关闭,避免错误上传。",-1))]),_:1}),l(s,{label:"文档链接"},{default:o(()=>[l(V,{modelValue:j.value,"onUpdate:modelValue":e[15]||(e[15]=t=>j.value=t),placeholder:"https://kdocs.cn/..."},null,8,["modelValue"])]),_:1}),l(s,{label:"默认县区"},{default:o(()=>[l(V,{modelValue:z.value,"onUpdate:modelValue":e[16]||(e[16]=t=>z.value=t),placeholder:"如:道县(用户可覆盖)"},null,8,["modelValue"])]),_:1}),l(s,{label:"Sheet名称"},{default:o(()=>[l(V,{modelValue:O.value,"onUpdate:modelValue":e[17]||(e[17]=t=>O.value=t),placeholder:"留空使用第一个Sheet"},null,8,["modelValue"])]),_:1}),l(s,{label:"Sheet序号"},{default:o(()=>[l(r,{modelValue:W.value,"onUpdate:modelValue":e[18]||(e[18]=t=>W.value=t),min:0,max:50},null,8,["modelValue"]),e[47]||(e[47]=u("div",{class:"help"},"0 表示第一个Sheet。",-1))]),_:1}),l(s,{label:"县区列"},{default:o(()=>[l(V,{modelValue:G.value,"onUpdate:modelValue":e[19]||(e[19]=t=>G.value=t),placeholder:"A",style:{"max-width":"120px"}},null,8,["modelValue"])]),_:1}),l(s,{label:"图片列"},{default:o(()=>[l(V,{modelValue:J.value,"onUpdate:modelValue":e[20]||(e[20]=t=>J.value=t),placeholder:"D",style:{"max-width":"120px"}},null,8,["modelValue"])]),_:1}),l(s,{label:"有效行范围"},{default:o(()=>[u("div",ll,[l(r,{modelValue:X.value,"onUpdate:modelValue":e[21]||(e[21]=t=>X.value=t),min:0,max:1e4,placeholder:"起始行",style:{width:"120px"}},null,8,["modelValue"]),e[48]||(e[48]=u("span",null,"至",-1)),l(r,{modelValue:Y.value,"onUpdate:modelValue":e[22]||(e[22]=t=>Y.value=t),min:0,max:1e4,placeholder:"结束行",style:{width:"120px"}},null,8,["modelValue"])]),e[49]||(e[49]=u("div",{class:"help"},"限制上传的行范围(如 50-1000 表示不限制。用于防止重名导致误传到其他县区。",-1))]),_:1}),l(s,{label:"管理员通知"},{default:o(()=>[l(N,{modelValue:Z.value,"onUpdate:modelValue":e[23]||(e[23]=t=>Z.value=t)},null,8,["modelValue"])]),_:1}),l(s,{label:"通知邮箱"},{default:o(()=>[l(V,{modelValue:ee.value,"onUpdate:modelValue":e[24]||(e[24]=t=>ee.value=t),placeholder:"admin@example.com"},null,8,["modelValue"])]),_:1})]),_:1}),u("div",al,[l(d,{type:"primary",onClick:Ue},{default:o(()=>[...e[50]||(e[50]=[m("保存表格配置",-1)])]),_:1}),l(d,{loading:h.value,disabled:de.value&&!h.value,onClick:re},{default:o(()=>[...e[51]||(e[51]=[m(" 刷新状态 ",-1)])]),_:1},8,["loading","disabled"]),l(d,{type:"success",plain:"",loading:S.value,disabled:de.value&&!S.value,onClick:Pe},{default:o(()=>[...e[52]||(e[52]=[m(" 获取二维码 ",-1)])]),_:1},8,["loading","disabled"]),l(d,{type:"danger",plain:"",loading:I.value,disabled:de.value&&!I.value,onClick:he},{default:o(()=>[...e[53]||(e[53]=[m(" 清除登录 ",-1)])]),_:1},8,["loading","disabled"])]),u("div",tl,[e[54]||(e[54]=m(" 登录状态: ",-1)),b.value.last_login_ok===!0?(f(),k("span",ol,"已登录")):b.value.login_required?(f(),k("span",nl,"需要扫码")):(f(),k("span",ul,"未知")),m(" · 待上传 "+ue(b.value.queue_size||0)+" ",1),b.value.last_error?(f(),k("span",sl,"· 最近错误:"+ue(b.value.last_error),1)):w("",!0)]),le.value?(f(),k("div",dl,"操作提示:"+ue(le.value),1)):w("",!0)]),_:1}),l(De,{modelValue:C.value,"onUpdate:modelValue":e[25]||(e[25]=t=>C.value=t),title:"扫码登录",width:"min(420px, 92vw)"},{default:o(()=>[u("div",rl,[P.value?(f(),k("img",{key:0,src:`data:image/png;base64,${P.value}`,alt:"KDocs QR"},null,8,il)):w("",!0),e[56]||(e[56]=u("div",{class:"help"},"请使用管理员微信扫码登录。",-1))])]),_:1},8,["modelValue"])])),[[Ke,_.value]])}}},pl=Le(ml,[["__scopeId","data-v-b359577d"]]);export{pl as default};