feat: 新增linux进程操作

This commit is contained in:
meilin.huang
2022-01-16 21:45:00 +08:00
parent 1df943d825
commit 5cd9b61acb
11 changed files with 285 additions and 21 deletions

View File

@@ -51,8 +51,8 @@
<el-row type="flex" justify="center">
<slot name="btns" :submitDisabled="submitDisabled" :data="form" :submit="submit">
<el-button @click="reset" size="mini"> </el-button>
<el-button type="primary" @click="submit" size="mini"> </el-button>
<el-button @click="reset" size="small"> </el-button>
<el-button type="primary" @click="submit" size="small"> </el-button>
</slot>
</el-row>
</el-form>

View File

@@ -4,8 +4,8 @@
<dynamic-form ref="df" :form-info="formInfo" :form-data="formData" @submitSuccess="submitSuccess">
<template #btns="props">
<slot name="btns">
<el-button :disabled="props.submitDisabled" type="primary" @click="props.submit" size="mini"> </el-button>
<el-button :disabled="props.submitDisabled" @click="close()" size="mini"> </el-button>
<el-button :disabled="props.submitDisabled" type="primary" @click="props.submit" size="small"> </el-button>
<el-button :disabled="props.submitDisabled" @click="close()" size="small"> </el-button>
</slot>
</template>
</dynamic-form>

View File

@@ -152,7 +152,7 @@
:min="0"
:max="9999"
@change="setLocalThemeConfig"
size="mini"
size="small"
style="width: 90px"
>
</el-input-number>
@@ -236,7 +236,7 @@
<div class="layout-breadcrumb-seting-bar-flex-value">
<el-input
v-model="getThemeConfig.wartermarkText"
size="mini"
size="small"
style="width: 90px"
@input="onWartermarkTextInput($event)"
></el-input>
@@ -251,7 +251,7 @@
<el-select
v-model="getThemeConfig.tagsStyle"
placeholder="请选择"
size="mini"
size="small"
style="width: 90px"
@change="setLocalThemeConfig"
>
@@ -268,7 +268,7 @@
<el-select
v-model="getThemeConfig.animation"
placeholder="请选择"
size="mini"
size="small"
style="width: 90px"
@change="setLocalThemeConfig"
>
@@ -284,7 +284,7 @@
<el-select
v-model="getThemeConfig.columnsAsideStyle"
placeholder="请选择"
size="mini"
size="small"
style="width: 90px"
@change="setLocalThemeConfig"
>

View File

@@ -171,7 +171,6 @@ import { codemirror } from '@/components/codemirror';
import { getSession } from '@/common/utils/storage';
import enums from './enums';
import config from '@/common/config';
import SvgIcon from '@/components/svgIcon/index.vue';
export default defineComponent({
name: 'FileManage',

View File

@@ -32,8 +32,8 @@
<template #footer>
<div class="dialog-footer">
<el-button type="primary" :loading="btnLoading" @click="btnOk" size="mini"> </el-button>
<el-button @click="cancel()" size="mini"> </el-button>
<el-button type="primary" :loading="btnLoading" @click="btnOk"> </el-button>
<el-button @click="cancel()"> </el-button>
</div>
</template>
</el-dialog>

View File

@@ -53,17 +53,12 @@
{{ $filters.dateFormat(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column prop="creator" label="创建者" min-width="55"></el-table-column>
<!-- <el-table-column prop="updateTime" label="更新时间" min-width="160">
<template #default="scope">
{{ $filters.dateFormat(scope.row.updateTime) }}
</template>
</el-table-column>
<el-table-column prop="modifier" label="修改者" :min-width="55"></el-table-column> -->
<el-table-column prop="creator" label="创建者" min-width="60"></el-table-column>
<el-table-column label="操作" min-width="260" fixed="right">
<template #default="scope">
<el-button type="success" @click="serviceManager(scope.row)" plain size="small">脚本</el-button>
<el-button v-auth="'machine:terminal'" type="primary" @click="showTerminal(scope.row)" plain size="small">终端</el-button>
<el-button @click="showProcess(scope.row)" plain size="small">进程</el-button>
<el-button :disabled="!scope.row.hasCli" type="danger" @click="closeCli(scope.row)" plain size="small">关闭连接</el-button>
</template>
</el-table-column>
@@ -91,6 +86,8 @@
<monitor ref="monitorDialogRef" :machineId="monitorDialog.machineId" />
</el-dialog> -->
<process-list v-model:visible="processDialog.visible" v-model:machineId="processDialog.machineId" />
<service-manage :title="serviceDialog.title" v-model:visible="serviceDialog.visible" v-model:machineId="serviceDialog.machineId" />
<file-manage :title="fileDialog.title" v-model:visible="fileDialog.visible" v-model:machineId="fileDialog.machineId" />
@@ -107,11 +104,13 @@ import { projectApi } from '../project/api.ts';
import ServiceManage from './ServiceManage.vue';
import FileManage from './FileManage.vue';
import MachineEdit from './MachineEdit.vue';
import ProcessList from './ProcessList.vue';
export default defineComponent({
name: 'MachineList',
components: {
ServiceManage,
ProcessList,
FileManage,
MachineEdit,
},
@@ -142,6 +141,10 @@ export default defineComponent({
machineId: 0,
title: '',
},
processDialog: {
visible: false,
machineId: 0,
},
fileDialog: {
visible: false,
machineId: 0,
@@ -256,6 +259,11 @@ export default defineComponent({
state.data = res;
};
const showProcess = (row: any) => {
state.processDialog.machineId = row.id;
state.processDialog.visible = true;
};
return {
...toRefs(state),
choose,
@@ -266,6 +274,7 @@ export default defineComponent({
deleteMachine,
closeCli,
serviceManager,
showProcess,
submitSuccess,
fileManage,
search,

View File

@@ -0,0 +1,203 @@
<template>
<div class="file-manage">
<el-dialog title="进程信息" v-model="dialogVisible" :destroy-on-close="true" :show-close="true" :before-close="handleClose" width="65%">
<div class="toolbar">
<el-row>
<el-col :span="4">
<el-input size="small" placeholder="进程名" v-model="params.name" plain clearable></el-input>
</el-col>
<el-col :span="4" class="ml5">
<el-select @change="getProcess" size="small" v-model="params.sortType" placeholder="请选择排序类型">
<el-option key="cpu" label="cpu降序" value="1"> </el-option>
<el-option key="cpu" label="mem降序" value="2"> </el-option>
</el-select>
</el-col>
<el-col :span="4" class="ml5">
<el-select @change="getProcess" size="small" v-model="params.count" placeholder="请选择进程个数">
<el-option key="10" label="10" value="10"> </el-option>
<el-option key="15" label="15" value="15"> </el-option>
<el-option key="20" label="20" value="20"> </el-option>
<el-option key="25" label="25" value="25"> </el-option>
</el-select>
</el-col>
<el-col :span="6">
<el-button class="ml5" @click="getProcess" type="primary" icon="tickets" size="small" plain>刷新</el-button>
</el-col>
</el-row>
</div>
<el-table :data="processList" size="small" style="width: 100%" empty-text="获取进程中...">
<el-table-column prop="user" label="USER" :min-width="50"> </el-table-column>
<el-table-column prop="pid" label="PID" :min-width="50" show-overflow-tooltip></el-table-column>
<el-table-column prop="cpu" label="%CPU" :min-width="40"> </el-table-column>
<el-table-column prop="mem" label="%MEM" :min-width="42"> </el-table-column>
<el-table-column prop="vsz" label="vsz" :min-width="55">
<template #header>
VSZ
<el-tooltip class="box-item" effect="dark" content="虚拟内存" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="rss" :min-width="52">
<template #header>
RSS
<el-tooltip class="box-item" effect="dark" content="固定内存" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="stat" :min-width="50">
<template #header>
STAT
<el-tooltip class="box-item" effect="dark" content="进程状态" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="start" :min-width="50">
<template #header>
START
<el-tooltip class="box-item" effect="dark" content="启动时间" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="time" :min-width="50">
<template #header>
TIME
<el-tooltip class="box-item" effect="dark" content="该进程实际使用CPU运作的时间" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="command" label="command" :min-width="120" show-overflow-tooltip> </el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-popconfirm title="确定终止该进程?" @confirm="confirmKillProcess(scope.row.pid)">
<template #reference>
<el-button v-auth="'machine:killprocess'" type="danger" icon="delete" size="small" plain>终止</el-button>
</template>
</el-popconfirm>
<!-- <el-button @click="addFiles(scope.row)" type="danger" icon="delete" size="small" plain>终止</el-button> -->
</template>
</el-table-column>
</el-table>
</el-dialog>
</div>
</template>
<script lang="ts">
import { ref, toRefs, reactive, watch, defineComponent } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { machineApi } from './api';
import enums from './enums';
export default defineComponent({
name: 'ProcessList',
components: {},
props: {
visible: { type: Boolean },
machineId: { type: Number },
title: { type: String },
},
setup(props: any, context) {
const state = reactive({
dialogVisible: false,
params: {
name: '',
sortType: '1',
count: '10',
id: 0,
},
processList: [],
});
watch(props, (newValue) => {
if (props.machineId) {
state.params.id = props.machineId;
getProcess();
}
state.dialogVisible = newValue.visible;
});
const getProcess = async () => {
const res = await machineApi.process.request(state.params);
// 解析字符串
// USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
// root 1 0.0 0.0 125632 3352 ? Ss 2019 154:04 /usr/lib/systemd/systemd --system --deserialize 22
const psStrings = res.split('\n');
const ps = [];
for (let i = 1; i < psStrings.length; i++) {
const psStr = psStrings[i];
const process = psStr.split(/\s+/);
if (process.length < 2) {
continue;
}
let command = process[10];
// 搜索进程时由于使用grep命令可能会多个bash或grep进程
if (state.params.name) {
if (command == 'bash' || command == 'grep') {
continue;
}
}
// 获取command由于command中也有可能存在空格被切割故重新拼接
for (let j = 10; j < process.length - 1; j++) {
command += ' ' + process[j + 1];
}
ps.push({
user: process[0],
pid: process[1],
cpu: process[2],
mem: process[3],
vsz: kb2Mb(process[4]),
rss: kb2Mb(process[5]),
stat: process[7],
start: process[8],
time: process[9],
command,
});
}
state.processList = ps as any;
};
const confirmKillProcess = async (pid: any) => {
await machineApi.killProcess.request({
pid,
id: state.params.id,
});
ElMessage.success('kill success');
state.params.name = '';
getProcess();
};
const kb2Mb = (kb: string) => {
return (parseInt(kb) / 1024).toFixed(2) + 'M';
};
/**
* 关闭取消按钮触发的事件
*/
const handleClose = () => {
context.emit('update:visible', false);
context.emit('update:machineId', null);
context.emit('cancel');
state.params = {
name: '',
sortType: '1',
count: '10',
id: 0,
};
state.processList = [];
};
return {
...toRefs(state),
getProcess,
confirmKillProcess,
enums,
handleClose,
};
},
});
</script>

View File

@@ -40,11 +40,11 @@
type="primary"
:loading="btnLoading"
@click="btnOk"
size="mini"
size="small"
:disabled="submitDisabled"
> </el-button
>
<el-button @click="cancel()" :disabled="submitDisabled" size="mini"> </el-button>
<el-button @click="cancel()" :disabled="submitDisabled" size="small"> </el-button>
</div>
</template>
</el-dialog>

View File

@@ -5,6 +5,9 @@ export const machineApi = {
list: Api.create("/machines", 'get'),
info: Api.create("/machines/{id}/sysinfo", 'get'),
stats: Api.create("/machines/{id}/stats", 'get'),
process: Api.create("/machines/{id}/process", 'get'),
// 终止进程
killProcess: Api.create("/machines/{id}/process", 'delete'),
closeCli: Api.create("/machines/{id}/close-cli", 'delete'),
// 保存按钮
saveMachine: Api.create("/machines", 'post'),