diff --git a/internal/app/api/ws.go b/internal/app/api/ws.go index 0c1535e..6b2a633 100644 --- a/internal/app/api/ws.go +++ b/internal/app/api/ws.go @@ -71,7 +71,7 @@ func (w *wsApi) WebsocketHandle(ctx *gin.Context, req model.WebsocketHandleReq) if err != nil { return err } - + defer conn.Close() log.Logger.Infow("ws连接成功") wsCtx, cancel := context.WithCancel(context.Background()) @@ -79,8 +79,10 @@ func (w *wsApi) WebsocketHandle(ctx *gin.Context, req model.WebsocketHandleReq) WsConnect: conn, CancelFunc: cancel, wsLock: sync.Mutex{}, + } + if err := proc.ReadCache(wci); err != nil { + return nil } - proc.ReadCache(wci) if proc.State.State == eum.ProcessStateRunning { proc.SetTerminalSize(req.Cols, req.Rows) w.startWsConnect(wci, cancel, proc, hasOprPermission(ctx, req.Uuid, eum.OperationTerminalWrite)) @@ -99,7 +101,6 @@ func (w *wsApi) WebsocketHandle(ctx *gin.Context, req model.WebsocketHandleReq) case <-wsCtx.Done(): log.Logger.Infow("ws连接断开", "操作类型", "tcp连接建立已被关闭") } - conn.Close() return } @@ -129,7 +130,7 @@ func (w *wsApi) WebsocketShareHandle(ctx *gin.Context, req model.WebsocketHandle if err != nil { return err } - + defer conn.Close() log.Logger.Infow("ws连接成功") data.UpdatedAt = time.Now() repository.WsShare.Edit(data) @@ -141,7 +142,9 @@ func (w *wsApi) WebsocketShareHandle(ctx *gin.Context, req model.WebsocketHandle CancelFunc: cancel, wsLock: sync.Mutex{}, } - proc.ReadCache(wci) + if err := proc.ReadCache(wci); err != nil { + return nil + } w.startWsConnect(wci, cancel, proc, data.Write) proc.AddConn(guestName, wci) defer proc.DeleteConn(guestName) @@ -159,7 +162,6 @@ func (w *wsApi) WebsocketShareHandle(ctx *gin.Context, req model.WebsocketHandle case <-time.After(time.Until(data.ExpireTime)): log.Logger.Infow("ws连接断开", "操作类型", "分享时间已结束") } - conn.Close() return } diff --git a/internal/app/logic/process_base.go b/internal/app/logic/process_base.go index 59c6790..27fa01c 100644 --- a/internal/app/logic/process_base.go +++ b/internal/app/logic/process_base.go @@ -21,7 +21,7 @@ import ( ) type Process interface { - ReadCache(ConnectInstance) + ReadCache(ConnectInstance) error Write(string) error WriteBytes([]byte) error readInit() diff --git a/internal/app/logic/process_pty_linux.go b/internal/app/logic/process_pty_linux.go index 5244a22..d4f0eb6 100644 --- a/internal/app/logic/process_pty_linux.go +++ b/internal/app/logic/process_pty_linux.go @@ -2,6 +2,7 @@ package logic import ( "bytes" + "errors" "os" "os/exec" "strings" @@ -113,10 +114,12 @@ func (p *ProcessPty) readInit() { } } -func (p *ProcessPty) ReadCache(ws ConnectInstance) { - if p.cacheBytesBuf != nil { - ws.Write(p.cacheBytesBuf.Bytes()) +func (p *ProcessPty) ReadCache(ws ConnectInstance) error { + if p.cacheBytesBuf == nil { + return errors.New("cache is null") } + ws.Write(p.cacheBytesBuf.Bytes()) + return nil } func (p *ProcessPty) bufHanle(b []byte) { diff --git a/internal/app/logic/process_pty_windows.go b/internal/app/logic/process_pty_windows.go index 16bf21d..55d0169 100644 --- a/internal/app/logic/process_pty_windows.go +++ b/internal/app/logic/process_pty_windows.go @@ -122,8 +122,12 @@ func (p *ProcessPty) readInit() { } } -func (p *ProcessPty) ReadCache(ws ConnectInstance) { +func (p *ProcessPty) ReadCache(ws ConnectInstance) error { + if p.cacheBytesBuf == nil { + return errors.New("cache is null") + } ws.Write(p.cacheBytesBuf.Bytes()) + return nil } func (p *ProcessPty) bufHanle(b []byte) { diff --git a/internal/app/logic/process_std.go b/internal/app/logic/process_std.go index 757a57e..66044b3 100644 --- a/internal/app/logic/process_std.go +++ b/internal/app/logic/process_std.go @@ -87,10 +87,14 @@ func (p *ProcessStd) doOnInit() { p.cacheLine = make([]string, config.CF.ProcessMsgCacheLinesLimit) } -func (p *ProcessStd) ReadCache(ws ConnectInstance) { +func (p *ProcessStd) ReadCache(ws ConnectInstance) error { + if len(p.cacheLine) == 0 { + return errors.New("cache is null") + } for _, line := range p.cacheLine { ws.WriteString(line) } + return nil } func (p *ProcessStd) doOnKilled() { diff --git a/resources/src/api/process.ts b/resources/src/api/process.ts index 118bef8..7b85ae0 100644 --- a/resources/src/api/process.ts +++ b/resources/src/api/process.ts @@ -9,12 +9,12 @@ export function getProcessListWait() { return api.get("/process/wait", undefined).then((res) => res); } -export function killProcessAll(uuid) { - return api.delete("/process/all", { uuid }).then((res) => res); +export function killProcessAll() { + return api.delete("/process/all", { }).then((res) => res); } -export function startProcessAll(uuid) { - return api.put("/process/all", { uuid }).then((res) => res); +export function startProcessAll() { + return api.put("/process/all", { }).then((res) => res); } export function killProcess(uuid) { diff --git a/resources/src/components/ConfirmButton.vue b/resources/src/components/ConfirmButton.vue new file mode 100644 index 0000000..f422e72 --- /dev/null +++ b/resources/src/components/ConfirmButton.vue @@ -0,0 +1,45 @@ + + + diff --git a/resources/src/components/process/ProcessCard.vue b/resources/src/components/process/ProcessCard.vue index 4ffaa40..08aa5b6 100644 --- a/resources/src/components/process/ProcessCard.vue +++ b/resources/src/components/process/ProcessCard.vue @@ -2,7 +2,12 @@ import { ProcessItem } from "~/src/types/process/process"; import { init } from "echarts"; import TerminalPty from "./TerminalPty.vue"; -import { killProcess, startProcess } from "~/src/api/process"; +import { + deleteProcessConfig, + getContorl, + killProcess, + startProcess, +} from "~/src/api/process"; import { useSnackbarStore } from "~/src/stores/snackbarStore"; import ProcessConfig from "./ProcessConfig.vue"; let chartInstance; @@ -17,7 +22,7 @@ const initEChart = () => { ); const cpu = props.data.usage.cpu[props.data.usage.cpu.length - 1] ?? "-"; const mem = props.data.usage.mem[props.data.usage.mem.length - 1] ?? "-"; - var myChart = init(document.getElementById("echarts" + props.index)); + var myChart = init(document.getElementById("echarts" + props.data.uuid)); var option = { tooltip: { trigger: "axis", @@ -95,7 +100,7 @@ const initEChart = () => { name: "CPU限制(%)", type: "line", yAxisIndex: 0, - data: new Array(props.data.usage.time!.length).fill( + data: new Array(props.data.usage.time?.length ?? 0).fill( props.data.cpuLimit ), lineStyle: { @@ -110,7 +115,7 @@ const initEChart = () => { name: "内存限制(MB)", type: "line", yAxisIndex: 1, - data: new Array(props.data.usage.time!.length).fill( + data: new Array(props.data.usage.time?.length ?? 0).fill( props.data.memoryLimit ), lineStyle: { @@ -132,7 +137,6 @@ const terminalComponent = ref(null); type ConfigHandle = { openConfigDialog: () => void; - test: () => void; }; const processConfigComponent = ref(null); @@ -182,8 +186,23 @@ onMounted(() => { const props = defineProps<{ data: ProcessItem; - index: Number; }>(); + +const control = () => { + getContorl(props.data.uuid).then((e) => { + if (e.code === 0) { + snackbarStore.showSuccessMessage("sucess"); + } + }); +}; + +const del = () => { + deleteProcessConfig(props.data.uuid).then((e) => { + if (e.code === 0) { + snackbarStore.showSuccessMessage("sucess"); + } + }); +}; - 获取控制权 - 删除进程 + 获取控制权 + 删除进程 创建分享链接 @@ -240,7 +259,7 @@ const props = defineProps<{ -
+
diff --git a/resources/src/components/process/ProcessConfig.vue b/resources/src/components/process/ProcessConfig.vue index afb1e07..59eb0fe 100644 --- a/resources/src/components/process/ProcessConfig.vue +++ b/resources/src/components/process/ProcessConfig.vue @@ -105,9 +105,6 @@ const initPushItem = () => { density="compact" > - - - { density="compact" > - - - + + diff --git a/resources/src/components/process/ProcessCreate.vue b/resources/src/components/process/ProcessCreate.vue new file mode 100644 index 0000000..af6a352 --- /dev/null +++ b/resources/src/components/process/ProcessCreate.vue @@ -0,0 +1,197 @@ + + + diff --git a/resources/src/components/process/TerminalPty.vue b/resources/src/components/process/TerminalPty.vue index fc181c1..76fd233 100644 --- a/resources/src/components/process/TerminalPty.vue +++ b/resources/src/components/process/TerminalPty.vue @@ -5,8 +5,8 @@ import { ProcessItem } from "~/src/types/process/process"; import { Terminal } from "xterm"; import { FitAddon } from "xterm-addon-fit"; import { AttachAddon } from "xterm-addon-attach"; -import { CanvasAddon } from '@xterm/addon-canvas'; -import 'xterm/css/xterm.css'; +import { CanvasAddon } from "@xterm/addon-canvas"; +import "xterm/css/xterm.css"; const snackbarStore = useSnackbarStore(); const dialog = ref(false); @@ -35,7 +35,6 @@ watch(dialog, (newValue) => { } }); - const initWebSocketPty = () => { if (!xtermEl.value) { snackbarStore.showErrorMessage("终端容器初始化失败"); @@ -46,7 +45,9 @@ const initWebSocketPty = () => { const initialRows = Math.floor(xtermEl.value.clientHeight / 19); const baseUrl = `ws://${window.location.hostname}:8797/api/ws`; - const url = `${baseUrl}?uuid=${props.data.uuid}&token=${localStorage.getItem("token")}&cols=${initialCols}&rows=${initialRows}`; + const url = `${baseUrl}?uuid=${props.data.uuid}&token=${localStorage.getItem( + "token" + )}&cols=${initialCols}&rows=${initialRows}`; initSocket(url); }; @@ -61,6 +62,7 @@ const initSocket = (url: string) => { socket.onclose = () => { snackbarStore.showErrorMessage("终端连接断开"); + dialog.value = false; }; socket.onerror = (err) => { @@ -71,15 +73,15 @@ const initSocket = (url: string) => { const initTerm = () => { if (!socket || !xtermEl.value) return; - + const showCursor = props.data.state.state === 3; term = new Terminal({ - // rendererType: "canvas", // 已通过插件方式加载,此处无需设置 convertEol: true, disableStdin: false, - cursorBlink: true, + cursorBlink: showCursor, + cursorStyle: "block", theme: { foreground: "#ECECEC", - cursor: "help", + cursor: "help" }, }); @@ -106,6 +108,13 @@ const wsClose = () => { cleanup(); }; +const toolbarColor = computed(() => { + if (props.data.state.state == 3) { + return; + } + return "red"; +}); + const cleanup = () => { window.removeEventListener("resize", handleResize); if (term) { @@ -129,7 +138,7 @@ onUnmounted(() => { hide-overlay transition="dialog-bottom-transition" v-model="dialog" - @update:modelValue="val => !val && cleanup()" + @update:modelValue="(val) => !val && cleanup()" > { -
+
diff --git a/resources/src/views/process/Process.vue b/resources/src/views/process/Process.vue index 885ec25..cd585dd 100644 --- a/resources/src/views/process/Process.vue +++ b/resources/src/views/process/Process.vue @@ -1,22 +1,48 @@