Files
zsglpt/static/admin/assets/LogsPage-CemQ-Y_T.js
yuyx 89f3fd9759 feat: 安全增强 + 删除密码重置申请功能 + 登录提醒开关
安全增强:
- 新增 SSRF、XXE、模板注入、敏感路径探测检测规则
- security/constants.py: 添加新的威胁类型和检测模式
- security/threat_detector.py: 实现新检测逻辑

删除密码重置申请功能:
- 移除 /api/password_resets 相关API
- 删除 password_reset_requests 数据库表
- 前端移除密码重置申请页面和菜单
- 用户只能通过邮��找回密码,未绑定邮箱需联系管理员

登录提醒全局开关:
- email_service.py: 添加 login_alert_enabled 字段
- routes/api_auth.py: 检查开关状态再发送登录提醒
- EmailPage.vue: 添加新设备登录提醒开关

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-27 12:08:36 +08:00

2 lines
6.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import{f as H}from"./users-DCcrmSwH.js";import{d as J,e as K}from"./tasks-Cx_Yf55V.js";import{_ as Q,r as u,c as X,o as Z,d as r,G as ee,e as P,f as y,g as v,h as t,w as a,n as p,F as te,q as le,j as B,H as ae,p as m,I as $,J as oe}from"./index-C9w-iZIr.js";function ne(f){return String(f||"").trim()}function se(f){return!f.startsWith("user_scheduled")||!f.includes(":")?"":f.split(":",2)[1]||""}function ue(f){const s=ne(f);if(!s||s==="manual")return{group:"manual",label:"手动",type:"success",tooltip:""};if(s==="scheduled")return{group:"scheduled",label:"定时任务",type:"primary",tooltip:"系统定时"};if(s.startsWith("user_scheduled")){const i=se(s),_=String(i||"").replace(/^batch_/,"");return{group:"scheduled",label:"定时任务",type:"primary",tooltip:_?`用户定时批次:${_}`:"用户定时"}}return{group:"manual",label:"手动",type:"success",tooltip:{batch:"手动批量",manual_screenshot:"手动截图",immediate:"立即执行",resumed:"断点恢复"}[s]||s}}const re={class:"page-stack"},ie={class:"app-page-title"},ce={class:"toolbar"},de={class:"filters"},pe={class:"table-wrap"},me={class:"ellipsis"},fe={class:"pagination"},ve={class:"page-hint app-muted"},T=20,_e={__name:"LogsPage",setup(f){const s=u(!1),S=u([]),h=u(0),i=u(1),_=u(!1),C=u([]),w=u(""),V=u(""),x=u(""),k=u(""),M=u(""),E=X(()=>Math.max(1,Math.ceil((h.value||0)/T)));function Y(o){if(o==null)return"-";const e=Number(o);return Number.isFinite(e)?e<60?`${e}`:`${Math.floor(e/60)}${e%60}`:"-"}function g(o){const e=ue(o);return{key:e.group,label:e.label,type:e.type,tooltip:e.tooltip}}function D(o){return o==="success"?{label:"成功",type:"success"}:o==="failed"?{label:"失败",type:"danger"}:{label:o||"-",type:"info"}}async function z(){_.value=!0;try{const o=await H();C.value=(o||[]).map(e=>({id:e.id,username:e.username}))}catch{C.value=[]}finally{_.value=!1}}async function b(){s.value=!0;try{const o=(i.value-1)*T,e={limit:T,offset:o};w.value&&(e.date=w.value),V.value&&(e.status=V.value),x.value&&(e.source=x.value),k.value&&(e.user_id=k.value),M.value&&(e.account=M.value);const c=await J(e);S.value=c?.logs||[],h.value=c?.total||0}catch{S.value=[],h.value=0}finally{s.value=!1}}function O(){i.value=1,b()}function j(){w.value="",V.value="",x.value="",k.value="",M.value="",i.value=1,b()}async function R(){let o;try{const e=await $.prompt("请输入要清理多少天前的日志默认30天","清理旧日志",{inputValue:"30",confirmButtonText:"下一步",cancelButtonText:"取消",inputValidator:c=>{const F=parseInt(String(c),10);return Number.isFinite(F)&&F>=1},inputErrorMessage:"请输入有效的天数大于0的整数"});o=parseInt(String(e.value),10)}catch{return}try{await $.confirm(`确定要删除 ${o} 天前的所有日志吗?此操作不可恢复!`,"二次确认",{confirmButtonText:"删除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await K(o);oe.success(e?.message||"清理成功"),i.value=1,await b()}catch{}}return Z(async()=>{await z(),await b()}),(o,e)=>{const c=r("el-button"),F=r("el-date-picker"),n=r("el-option"),U=r("el-select"),W=r("el-input"),L=r("el-card"),d=r("el-table-column"),I=r("el-tag"),N=r("el-tooltip"),q=r("el-table"),A=r("el-pagination"),G=ee("loading");return y(),P("div",re,[v("div",ie,[e[7]||(e[7]=v("h2",null,"任务日志",-1)),v("div",ce,[t(c,{onClick:b},{default:a(()=>[...e[6]||(e[6]=[p("刷新",-1)])]),_:1})])]),t(L,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:a(()=>[v("div",de,[t(F,{modelValue:w.value,"onUpdate:modelValue":e[0]||(e[0]=l=>w.value=l),type:"date","value-format":"YYYY-MM-DD",placeholder:"日期",style:{width:"150px"}},null,8,["modelValue"]),t(U,{modelValue:V.value,"onUpdate:modelValue":e[1]||(e[1]=l=>V.value=l),placeholder:"状态",style:{width:"120px"}},{default:a(()=>[t(n,{label:"全部",value:""}),t(n,{label:"成功",value:"success"}),t(n,{label:"失败",value:"failed"})]),_:1},8,["modelValue"]),t(U,{modelValue:x.value,"onUpdate:modelValue":e[2]||(e[2]=l=>x.value=l),placeholder:"来源",style:{width:"120px"}},{default:a(()=>[t(n,{label:"全部",value:""}),t(n,{label:"手动",value:"manual"}),t(n,{label:"定时任务(系统)",value:"scheduled"}),t(n,{label:"定时任务(用户)",value:"user_scheduled"}),t(n,{label:"手动(批量)",value:"batch"}),t(n,{label:"手动(截图)",value:"manual_screenshot"}),t(n,{label:"手动(立即)",value:"immediate"}),t(n,{label:"手动(恢复)",value:"resumed"})]),_:1},8,["modelValue"]),t(U,{modelValue:k.value,"onUpdate:modelValue":e[3]||(e[3]=l=>k.value=l),placeholder:"用户",style:{width:"140px"},loading:_.value,filterable:"",clearable:""},{default:a(()=>[t(n,{label:"全部",value:""}),(y(!0),P(te,null,le(C.value,l=>(y(),B(n,{key:l.id,label:l.username,value:String(l.id)},null,8,["label","value"]))),128))]),_:1},8,["modelValue","loading"]),t(W,{modelValue:M.value,"onUpdate:modelValue":e[4]||(e[4]=l=>M.value=l),placeholder:"账号关键字",style:{width:"170px"},clearable:""},null,8,["modelValue"]),t(c,{type:"primary",onClick:O},{default:a(()=>[...e[8]||(e[8]=[p("筛选",-1)])]),_:1}),t(c,{onClick:j},{default:a(()=>[...e[9]||(e[9]=[p("重置",-1)])]),_:1}),t(c,{type:"danger",plain:"",onClick:R},{default:a(()=>[...e[10]||(e[10]=[p("清理旧日志",-1)])]),_:1})])]),_:1}),t(L,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:a(()=>[v("div",pe,[ae((y(),B(q,{data:S.value,style:{width:"100%"}},{default:a(()=>[t(d,{prop:"created_at",label:"时间",width:"180"}),t(d,{label:"来源",width:"110"},{default:a(({row:l})=>[g(l.source).tooltip?(y(),B(N,{key:0,content:g(l.source).tooltip,placement:"top","show-after":300},{default:a(()=>[t(I,{type:g(l.source).type,effect:"light"},{default:a(()=>[p(m(g(l.source).label),1)]),_:2},1032,["type"])]),_:2},1032,["content"])):(y(),B(I,{key:1,type:g(l.source).type,effect:"light"},{default:a(()=>[p(m(g(l.source).label),1)]),_:2},1032,["type"]))]),_:1}),t(d,{prop:"user_username",label:"用户",width:"140"}),t(d,{prop:"username",label:"账号",width:"160"}),t(d,{prop:"browse_type",label:"浏览类型",width:"120"}),t(d,{label:"状态",width:"90"},{default:a(({row:l})=>[t(I,{type:D(l.status).type,effect:"light"},{default:a(()=>[p(m(D(l.status).label),1)]),_:2},1032,["type"])]),_:1}),t(d,{label:"内容/附件",width:"110"},{default:a(({row:l})=>[p(m(l.total_items)+" / "+m(l.total_attachments),1)]),_:1}),t(d,{label:"用时",width:"90"},{default:a(({row:l})=>[p(m(Y(l.duration)),1)]),_:1}),t(d,{label:"失败原因","min-width":"220"},{default:a(({row:l})=>[t(N,{content:l.error_message||"",placement:"top","show-after":300},{default:a(()=>[v("span",me,m(l.error_message||"-"),1)]),_:2},1032,["content"])]),_:1})]),_:1},8,["data"])),[[G,s.value]])]),v("div",fe,[t(A,{"current-page":i.value,"onUpdate:currentPage":e[5]||(e[5]=l=>i.value=l),"page-size":T,total:h.value,layout:"prev, pager, next, jumper, ->, total",onCurrentChange:b},null,8,["current-page","total"]),v("div",ve,"第 "+m(i.value)+" / "+m(E.value)+" 页",1)])]),_:1})])}}},he=Q(_e,[["__scopeId","data-v-080a6c1f"]]);export{he as default};