LoongPanel-Asp/web/pages/host/process.vue

223 lines
5.8 KiB
Vue

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useRuntimeConfig, useCookie } from '#imports';
import {useMainLayoutStore} from "~/strores/UseMainLayoutStore";
import { useToast } from 'vue-toastification';
type ProcessListType = {
pid: string;
user: string;
cpu: string;
memory: string;
processName: string;
};
const toast=useToast()
const processList = ref<ProcessListType[]>([]);
const mainLayoutStore = useMainLayoutStore();
const currentSort = ref<'pid' | 'user' | 'cpu' | 'memory' | 'processName'>('cpu');
const currentSortDir = ref<'asc' | 'desc'>('desc');
const props=defineProps({
userName:{
type:String,
default:''
},
})
const emit=defineEmits([
'update'
])
const getProcessList = async () => {
const response = await $fetch('/Api/Server/GetServerProcessesList', {
method: 'GET',
params: {
ServerId: mainLayoutStore.SelectServer.id,
UserName:props.userName
},
baseURL: useRuntimeConfig().public.baseUrl,
headers: {
'Authorization': 'Bearer ' + useCookie('token').value,
},
});
processList.value = response as ProcessListType[];
}
let interval:NodeJS.Timeout;
onMounted(async () => {
await getProcessList();
interval = setInterval(async ()=>{
await getProcessList();
},10000)
});
onBeforeUnmount(()=>{
clearInterval(interval);
})
const sortedProcessList = computed(() => {
emit('update',processList.value.map(x=>x.pid))
return processList.value.sort((a, b) => {
let modifier = 1;
if (currentSortDir.value === 'desc') modifier = -1;
if (a[currentSort.value] < b[currentSort.value]) return -1 * modifier;
if (a[currentSort.value] > b[currentSort.value]) return modifier;
return 0;
});
});
const sort = (s: 'pid' | 'user' | 'cpu' | 'memory' | 'processName') => {
if (currentSort.value === s) {
currentSortDir.value = currentSortDir.value === 'asc' ? 'desc' : 'asc';
} else {
currentSort.value = s;
currentSortDir.value = 'asc';
}
};
const killProcess = (pid: string,force:boolean=false) => {
$fetch('/Api/Server/GetServerProcessesKill', {
method: 'GET',
params: {
ServerId: mainLayoutStore.SelectServer.id,
Pid: pid,
Force:force,
},
baseURL: useRuntimeConfig().public.baseUrl,
headers: {
'Authorization': 'Bearer ' + useCookie('token').value,
},
}).then((res) => {
console.log(res)
toast.success(res)
}).catch((err) => {
toast.error(err)
})
}
</script>
<template>
<div class="process-table">
<table>
<thead>
<tr>
<th @click="sort('processName')">
<div>
<p>进程名称</p>
<Icon v-if="currentSort==='processName'&&currentSortDir==='desc'" name="ArrowDownNarrowWide"></Icon>
<Icon v-if="currentSort==='processName'&&currentSortDir==='asc'" name="ArrowUpNarrowWide"></Icon>
</div>
</th>
<th @click="sort('pid')">
<div>
<p>进程ID</p>
<Icon v-if="currentSort==='pid'&&currentSortDir==='desc'" name="ArrowDownNarrowWide"></Icon>
<Icon v-if="currentSort==='pid'&&currentSortDir==='asc'" name="ArrowUpNarrowWide"></Icon>
</div>
</th>
<th @click="sort('user')">
<div>
<p>用户</p>
<Icon v-if="currentSort==='user'&&currentSortDir==='desc'" name="ArrowDownNarrowWide"></Icon>
<Icon v-if="currentSort==='user'&&currentSortDir==='asc'" name="ArrowUpNarrowWide"></Icon>
</div>
</th>
<th @click="sort('cpu')">
<div>
<p>CPU使用率</p>
<Icon v-if="currentSort==='cpu'&&currentSortDir==='desc'" name="ArrowDownNarrowWide"></Icon>
<Icon v-if="currentSort==='cpu'&&currentSortDir==='asc'" name="ArrowUpNarrowWide"></Icon>
</div>
</th>
<th @click="sort('memory')">
<div>
<p>内存使用率</p>
<Icon v-if="currentSort==='memory'&&currentSortDir==='desc'" name="ArrowDownNarrowWide"></Icon>
<Icon v-if="currentSort==='memory'&&currentSortDir==='asc'" name="ArrowUpNarrowWide"></Icon>
</div>
</th>
<th>
<div>
<p>操作</p>
</div>
</th>
</tr>
</thead>
<tbody>
<tr v-for="item in sortedProcessList" :key="item.pid">
<td>
<Icon name="Shell"/>
{{ item.processName }}
</td>
<td>{{ item.pid }}</td>
<td>{{ item.user }}</td>
<td>{{ item.cpu }}</td>
<td>{{ item.memory }}</td>
<td><div>
<button @click="killProcess(item.pid)">关闭</button><button @click="killProcess(item.pid,true)">杀死</button>
</div></td>
</tr>
</tbody>
</table>
</div>
</template>
<style scoped lang="scss">
@import "base";
.process-table {
width: 100%;
padding: $padding*2;
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #ddd;
border-top: unset;
border-bottom: unset;
padding: 8px;
}
th {
>div{
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
cursor: pointer;
p{
margin: 0;
}
}
}
tr:hover{
background: $light-bg-underline-color;
}
tr>td:first-of-type{
display: flex;
gap: $gap;
}
td:not(:first-child):not(:last-child) {
text-align: right;
}
td:last-of-type{
//大小适应内容
>div{
display: flex;
gap: $gap*2;
justify-content: center;
align-items: center;
button{
background: unset;
border: unset;
padding: 0;
&:hover{
color: $primary-color;
font-weight: 800;
}
&:last-of-type:hover{
color: red;
}
}
}
}
td:first-of-type,th:first-of-type,td:last-of-type,th:last-of-type {
border: unset;
}
}
</style>