Files
Nexus/web/app/assets/ScriptsPage-B184djiB.js
T
Nexus Agent 0b2d7ac50d feat(scripts): 异步执行、全局进度看板与完成提示音设置
脚本 exec 立即返回 running 并在后台跑批次;/ws/alerts 推送 script_progress/complete;
新增 ScriptRunsPage、Telegram 汇总通知与可配置的浏览器完成提示音。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 07:07:02 +08:00

1 line
14 KiB
JavaScript

import{t as e,x as t}from"./VDataTable-B8xy9iJY.js";import{$n as ee,Dt as te,F as n,Jn as ne,L as r,Lr as i,M as a,N as o,P as s,Sr as c,Tr as re,Vr as l,Xn as ie,Y as ae,Yn as oe,Z as u,Zn as se,_ as ce,ar as d,er as f,gr as p,hr as le,jr as m,k as h,mr as ue,nr as g,or as _,rr as v,sr as de,t as y,tr as b,ur as fe,vr as pe,w as me,wr as x,z as S,zt as C}from"./index-8R5Vx1WH.js";import{o as he,t as ge}from"./VContainer-ByAXNVXy.js";import{t as w}from"./VChip-CO9HT0ch.js";import{t as _e}from"./VSelect-BB7JEkD3.js";import{n as T,t as ve}from"./VRow-BVJ9K6vV.js";import{t as E}from"./VSpacer-CTDq7Cy_.js";import{t as ye}from"./apiError-DdoXm_FH.js";import{t as be}from"./useServerList-Xwm-w1s9.js";import{i as D}from"./validation-DMwOxx4a.js";import{t as O}from"./VDialog-dXQJNBjB.js";import{t as xe}from"./VTextarea-kvfN04zZ.js";var Se={class:`text-body-1 font-weight-medium`},Ce={class:`text-body-2 text-medium-emphasis`},we={class:`text-caption text-medium-emphasis mt-2`},Te={key:1,class:`d-flex justify-center mt-4`},Ee={class:`text-caption`},De={class:`d-flex align-center ga-2`},Oe={class:`text-body-2`},ke={key:0},Ae={key:1,class:`text-medium-emphasis`},k=de({__name:`ScriptsPage`,setup(de){let k=he(),{servers:je,loadServers:Me}=be(),A=m(!1),j=m(``),M=m([]),N=m(1),P=m(0),F=m(20),I=m(!1),L=m(null),R=m(!1),z=m({name:``,category:``,description:``,content:``}),B=m(!1),V=m(null),H=m([]),U=m(300),W=m(!1),G=m(!1),K=m(null),q=m(!1),Ne=m(null),J=m([]),Y=m(!1),X=m(``),Z=m([]),Pe=m(60),Fe=m(!1),Q=m([]),Ie=null,Le=[{title:`命令`,key:`command`},{title:`状态`,key:`status`,width:100},{title:`进度`,key:`progress`,width:100},{title:`操作人`,key:`operator`,width:80},{title:`开始时间`,key:`started_at`,width:160}],Re=ee(()=>{if(!j.value)return M.value;let e=j.value.toLowerCase();return M.value.filter(t=>t.name.toLowerCase().includes(e)||(t.category||``).toLowerCase().includes(e))});async function $(){A.value=!0;try{let e=await C.getList(`/scripts/`,{page:N.value,per_page:F.value});M.value=e.items,P.value=e.total}catch(e){M.value=[],k(ye(e,`加载脚本列表失败`),`error`)}finally{A.value=!1}}c(j,()=>{N.value=1,$()});function ze(e){L.value=e,e?z.value={name:e.name,category:e.category||``,description:e.description||``,content:e.content||``}:z.value={name:``,category:``,description:``,content:``},I.value=!0}async function Be(){R.value=!0;try{L.value?await C.put(`/scripts/${L.value.id}`,z.value):await C.post(`/scripts/`,z.value),I.value=!1,$(),k(`保存成功`)}catch(e){k(e.message||`保存失败`,`error`)}finally{R.value=!1}}function Ve(e){V.value=e,H.value=[],B.value=!0}async function He(){if(!V.value||!H.value.length){k(`请选择服务器`,`warning`);return}W.value=!0;try{let e=await C.post(`/scripts/exec`,{script_id:V.value.id,server_ids:H.value,timeout:U.value});B.value=!1,k(`脚本已提交执行`),qe(V.value.name,e.execution_id,H.value.length)}catch(e){k(e.message||`执行失败`,`error`)}finally{W.value=!1}}function Ue(e){K.value=e,G.value=!0}async function We(){if(K.value)try{await C.delete(`/scripts/${K.value.id}`),G.value=!1,$(),k(`已删除`)}catch(e){k(e.message||`删除失败`,`error`)}}async function Ge(e){Ne.value=e,q.value=!0;try{J.value=(await C.get(`/scripts/executions`,{script_id:e.id})).items||[]}catch{J.value=[]}}async function Ke(){if(!(!X.value||Z.value.length===0)){Fe.value=!0;try{let e=await C.post(`/scripts/exec`,{command:X.value,server_ids:Z.value,timeout:Pe.value});k(`已在 ${Z.value.length} 台服务器上执行`),qe(`临时命令`,e.execution_id,Z.value.length)}catch(e){k(e.message||`执行失败`,`error`)}finally{Fe.value=!1}}}function qe(e,t,ee){Q.value.unshift({id:t,name:e,status:`running`,totalServers:ee,completedServers:0,refreshing:!1}),Je()}function Je(){Ie||=setInterval(async()=>{let e=Q.value.filter(e=>e.status===`running`);if(e.length===0){Ye();return}for(let t of e)await Xe(t)},5e3)}function Ye(){Ie&&=(clearInterval(Ie),null)}async function Xe(e){e.refreshing=!0;try{let t=await C.get(`/scripts/executions/${e.id}`),ee=t.results||{};e.completedServers=Object.values(ee).filter(e=>e.status!==`running`&&e.status!==`pending`).length,e.status=t.status}catch{}finally{e.refreshing=!1}}async function Ze(e){try{await C.post(`/scripts/executions/${e.id}/stop`),e.status=`failed`,k(`已发送停止指令`)}catch(e){k(e.message||`停止失败`,`error`)}}function Qe(e){return e===`running`?`blue`:e===`completed`?`green`:e===`failed`?`red`:`orange`}function $e(e){return e===`running`?`执行中`:e===`completed`?`已完成`:e===`failed`?`失败`:`部分完成`}return ue(()=>{$(),Me()}),le(()=>{Ye()}),(ee,c)=>(p(),b(ge,{fluid:``,class:`pa-6`},{default:x(()=>[_(o,{elevation:`0`,border:``,rounded:`lg`,class:`mb-4`},{default:x(()=>[_(n,{class:`d-flex align-center`},{default:x(()=>[c[22]||=d(` 脚本库 `,-1),_(E),_(y,{modelValue:j.value,"onUpdate:modelValue":c[0]||=e=>j.value=e,"prepend-inner-icon":`mdi-magnify`,label:`搜索...`,density:`compact`,"hide-details":``,variant:`outlined`,rounded:``,style:{"max-width":`240px`}},null,8,[`modelValue`]),_(S,{color:`primary`,variant:`flat`,class:`ml-3`,"prepend-icon":`mdi-plus`,size:`small`,onClick:c[1]||=e=>ze(null)},{default:x(()=>[...c[21]||=[d(` 新建脚本 `,-1)]]),_:1})]),_:1})]),_:1}),_(o,{elevation:`0`,border:``,rounded:`lg`,class:`mb-4`},{default:x(()=>[_(n,{class:`d-flex align-center`,style:{cursor:`pointer`},onClick:c[2]||=e=>Y.value=!Y.value},{default:x(()=>[_(u,{class:`mr-2`},{default:x(()=>[...c[23]||=[d(`mdi-console`,-1)]]),_:1}),c[24]||=d(` 临时命令执行 `,-1),_(E),_(u,null,{default:x(()=>[d(l(Y.value?`mdi-chevron-up`:`mdi-chevron-down`),1)]),_:1})]),_:1}),_(te,null,{default:x(()=>[re(f(`div`,null,[_(a),_(s,null,{default:x(()=>[_(xe,{modelValue:X.value,"onUpdate:modelValue":c[3]||=e=>X.value=e,label:`命令`,variant:`outlined`,density:`compact`,rows:`3`,placeholder:`输入要执行的命令... (Ctrl+Enter 执行)`,class:`mb-3`,onKeydown:oe(ie(Ke,[`ctrl`]),[`enter`]),rules:[i(D)(`命令`)]},null,8,[`modelValue`,`onKeydown`,`rules`]),_(ve,{dense:``},{default:x(()=>[_(T,{cols:`12`,md:`6`},{default:x(()=>[_(_e,{modelValue:Z.value,"onUpdate:modelValue":c[4]||=e=>Z.value=e,items:i(je),"item-title":`name`,"item-value":`id`,label:`目标服务器`,variant:`outlined`,density:`compact`,multiple:``,chips:``,"closable-chips":``},null,8,[`modelValue`,`items`])]),_:1}),_(T,{cols:`6`,md:`3`},{default:x(()=>[_(y,{modelValue:Pe.value,"onUpdate:modelValue":c[5]||=e=>Pe.value=e,modelModifiers:{number:!0},label:`超时(秒)`,variant:`outlined`,density:`compact`,type:`number`},null,8,[`modelValue`])]),_:1}),_(T,{cols:`6`,md:`3`,class:`d-flex align-center`},{default:x(()=>[_(S,{color:`primary`,variant:`flat`,onClick:Ke,loading:Fe.value,disabled:!X.value||Z.value.length===0},{default:x(()=>[...c[25]||=[d(` 执行 `,-1)]]),_:1},8,[`loading`,`disabled`])]),_:1})]),_:1})]),_:1})],512),[[ne,Y.value]])]),_:1})]),_:1}),A.value?(p(),b(ae,{key:0,indeterminate:``,color:`primary`})):g(``,!0),_(ve,null,{default:x(()=>[(p(!0),v(se,null,pe(Re.value,e=>(p(),b(T,{cols:`12`,sm:`6`,md:`4`,key:e.id},{default:x(()=>[_(o,{elevation:`0`,border:``,rounded:`lg`,class:`fill-height`},{default:x(()=>[_(n,{class:`d-flex align-center`},{default:x(()=>[_(u,{color:`primary`,class:`mr-2`},{default:x(()=>[...c[26]||=[d(`mdi-code-braces`,-1)]]),_:1}),f(`span`,Se,l(e.name),1),_(E),_(ce,null,{activator:x(({props:e})=>[_(S,fe({icon:`mdi-dots-vertical`,variant:`text`,size:`small`},{ref_for:!0},e),null,16)]),default:x(()=>[_(me,{density:`compact`},{default:x(()=>[_(h,{title:`编辑`,onClick:t=>ze(e)},{prepend:x(()=>[_(u,null,{default:x(()=>[...c[27]||=[d(`mdi-pencil`,-1)]]),_:1})]),_:1},8,[`onClick`]),_(h,{title:`执行`,onClick:t=>Ve(e)},{prepend:x(()=>[_(u,null,{default:x(()=>[...c[28]||=[d(`mdi-play`,-1)]]),_:1})]),_:1},8,[`onClick`]),_(h,{title:`删除`,onClick:t=>Ue(e),class:`text-error`},{prepend:x(()=>[_(u,{color:`error`},{default:x(()=>[...c[29]||=[d(`mdi-delete`,-1)]]),_:1})]),_:1},8,[`onClick`])]),_:2},1024)]),_:2},1024)]),_:2},1024),_(s,null,{default:x(()=>[e.category?(p(),b(w,{key:0,size:`small`,variant:`tonal`,label:``,class:`mb-2`},{default:x(()=>[d(l(e.category),1)]),_:2},1024)):g(``,!0),f(`div`,Ce,l(e.description||`无描述`),1),f(`div`,we,` 更新于 `+l(e.updated_at||e.created_at),1)]),_:2},1024),_(r,null,{default:x(()=>[_(S,{size:`small`,variant:`tonal`,"prepend-icon":`mdi-play`,color:`primary`,onClick:t=>Ve(e)},{default:x(()=>[...c[30]||=[d(`执行`,-1)]]),_:1},8,[`onClick`]),_(E),_(S,{size:`small`,variant:`text`,onClick:t=>Ge(e)},{default:x(()=>[...c[31]||=[d(`历史`,-1)]]),_:1},8,[`onClick`])]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),P.value>F.value?(p(),v(`div`,Te,[_(t,{modelValue:N.value,"onUpdate:modelValue":[c[6]||=e=>N.value=e,$],length:Math.ceil(P.value/F.value),rounded:``,density:`compact`},null,8,[`modelValue`,`length`])])):g(``,!0),Q.value.length>0?(p(),b(o,{key:2,elevation:`0`,border:``,rounded:`lg`,class:`mt-4`},{default:x(()=>[_(n,{class:`d-flex align-center text-subtitle-1`},{default:x(()=>[_(u,{class:`mr-2`},{default:x(()=>[...c[32]||=[d(`mdi-progress-clock`,-1)]]),_:1}),c[34]||=d(` 执行状态 `,-1),_(E),_(S,{size:`small`,variant:`text`,onClick:c[7]||=e=>Q.value=[]},{default:x(()=>[...c[33]||=[d(`清除`,-1)]]),_:1})]),_:1}),_(a),_(s,null,{default:x(()=>[_(me,{density:`compact`},{default:x(()=>[(p(!0),v(se,null,pe(Q.value,e=>(p(),b(h,{key:e.id,title:e.name},{subtitle:x(()=>[f(`span`,Ee,`ID: `+l(e.id)+` · `+l(e.totalServers)+` 台服务器`,1)]),append:x(()=>[f(`div`,De,[_(w,{color:Qe(e.status),size:`x-small`,variant:`tonal`,label:``},{default:x(()=>[d(l($e(e.status)),1)]),_:2},1032,[`color`]),_(S,{size:`x-small`,variant:`text`,onClick:t=>Xe(e),loading:e.refreshing},{default:x(()=>[...c[35]||=[d(` 刷新 `,-1)]]),_:1},8,[`onClick`,`loading`]),e.status===`running`?(p(),b(S,{key:0,size:`x-small`,variant:`text`,color:`error`,onClick:t=>Ze(e)},{default:x(()=>[...c[36]||=[d(` 停止 `,-1)]]),_:1},8,[`onClick`])):g(``,!0)])]),_:2},1032,[`title`]))),128))]),_:1})]),_:1})]),_:1})):g(``,!0),_(O,{modelValue:I.value,"onUpdate:modelValue":c[13]||=e=>I.value=e,"max-width":`800`,scrollable:``},{default:x(()=>[_(o,{border:``},{default:x(()=>[_(n,null,{default:x(()=>[d(l(L.value?`编辑脚本`:`新建脚本`),1)]),_:1}),_(a),_(s,null,{default:x(()=>[_(y,{modelValue:z.value.name,"onUpdate:modelValue":c[8]||=e=>z.value.name=e,label:`脚本名称`,variant:`outlined`,density:`compact`,class:`mb-2`,rules:[i(D)(`脚本名称`)]},null,8,[`modelValue`,`rules`]),_(y,{modelValue:z.value.category,"onUpdate:modelValue":c[9]||=e=>z.value.category=e,label:`分类`,variant:`outlined`,density:`compact`,class:`mb-2`},null,8,[`modelValue`]),_(xe,{modelValue:z.value.description,"onUpdate:modelValue":c[10]||=e=>z.value.description=e,label:`描述`,variant:`outlined`,density:`compact`,rows:`2`,class:`mb-2`},null,8,[`modelValue`]),_(xe,{modelValue:z.value.content,"onUpdate:modelValue":c[11]||=e=>z.value.content=e,label:`脚本内容`,variant:`outlined`,density:`compact`,rows:`14`,class:`mt-2 font-monospace`,rules:[i(D)(`脚本内容`)]},null,8,[`modelValue`,`rules`])]),_:1}),_(a),_(r,null,{default:x(()=>[_(E),_(S,{variant:`text`,onClick:c[12]||=e=>I.value=!1},{default:x(()=>[...c[37]||=[d(`取消`,-1)]]),_:1}),_(S,{color:`primary`,variant:`flat`,onClick:Be,loading:R.value},{default:x(()=>[...c[38]||=[d(`保存`,-1)]]),_:1},8,[`loading`])]),_:1})]),_:1})]),_:1},8,[`modelValue`]),_(O,{modelValue:B.value,"onUpdate:modelValue":c[17]||=e=>B.value=e,"max-width":`600`},{default:x(()=>[_(o,{border:``},{default:x(()=>[_(n,null,{default:x(()=>[d(`执行脚本: `+l(V.value?.name),1)]),_:1}),_(s,null,{default:x(()=>[_(_e,{modelValue:H.value,"onUpdate:modelValue":c[14]||=e=>H.value=e,items:i(je),"item-title":`name`,"item-value":`id`,label:`选择服务器`,variant:`outlined`,density:`compact`,multiple:``,chips:``,class:`mb-2`},null,8,[`modelValue`,`items`]),_(y,{modelValue:U.value,"onUpdate:modelValue":c[15]||=e=>U.value=e,label:`超时(秒)`,variant:`outlined`,density:`compact`,type:`number`},null,8,[`modelValue`])]),_:1}),_(r,null,{default:x(()=>[_(E),_(S,{variant:`text`,onClick:c[16]||=e=>B.value=!1},{default:x(()=>[...c[39]||=[d(`取消`,-1)]]),_:1}),_(S,{color:`primary`,variant:`flat`,onClick:He,loading:W.value},{default:x(()=>[...c[40]||=[d(`执行`,-1)]]),_:1},8,[`loading`])]),_:1})]),_:1})]),_:1},8,[`modelValue`]),_(O,{modelValue:G.value,"onUpdate:modelValue":c[19]||=e=>G.value=e,"max-width":`400`},{default:x(()=>[_(o,{border:``},{default:x(()=>[_(n,null,{default:x(()=>[...c[41]||=[d(`确认删除`,-1)]]),_:1}),_(s,null,{default:x(()=>[c[42]||=d(`确定要删除脚本 `,-1),f(`strong`,null,l(K.value?.name),1),c[43]||=d(` 吗?`,-1)]),_:1}),_(r,null,{default:x(()=>[_(E),_(S,{variant:`text`,onClick:c[18]||=e=>G.value=!1},{default:x(()=>[...c[44]||=[d(`取消`,-1)]]),_:1}),_(S,{color:`error`,variant:`flat`,onClick:We},{default:x(()=>[...c[45]||=[d(`删除`,-1)]]),_:1})]),_:1})]),_:1})]),_:1},8,[`modelValue`]),_(O,{modelValue:q.value,"onUpdate:modelValue":c[20]||=e=>q.value=e,"max-width":`800`,scrollable:``},{default:x(()=>[_(o,{border:``},{default:x(()=>[_(n,null,{default:x(()=>[d(`执行历史: `+l(Ne.value?.name),1)]),_:1}),_(a),_(s,null,{default:x(()=>[_(e,{items:J.value,headers:Le,density:`compact`,hover:``},{"item.status":x(({item:e})=>[_(w,{color:e.status===`completed`?`success`:e.status===`failed`?`error`:`info`,size:`small`,variant:`tonal`,label:``},{default:x(()=>[d(l(e.status),1)]),_:2},1032,[`color`])]),"item.command":x(({item:e})=>[f(`code`,Oe,l(e.command.length>60?e.command.slice(0,60)+`…`:e.command),1)]),"item.progress":x(({item:e})=>[e.progress?(p(),v(`span`,ke,l(e.progress.done)+`/`+l(e.progress.total),1)):(p(),v(`span`,Ae,`—`))]),"no-data":x(()=>[...c[46]||=[f(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`])]),_:1})]),_:1})]),_:1},8,[`modelValue`])]),_:1}))}});export{k as default};