LoongPanel-Asp/web/components/ServerUserPage/UserList.vue

203 lines
4.5 KiB
Vue

<script setup lang="ts">
import {useMainLayoutStore} from "~/strores/UseMainLayoutStore";
import {useToast} from "vue-toastification";
const toast = useToast()
const mainLayoutStore = useMainLayoutStore()
const userList = ref<UserListItem[]>([])
type UserListItem = {
"name": string,
"isOnline": boolean,
"lastLoginTime": string,
"address": string,
"port": string,
}
const GetServerUserList = () => {
$fetch('/Api/Server/GetServerUserList', {
method: 'GET',
params: {
ServerId: mainLayoutStore.SelectServer.value
},
headers: {
'Content-Type': 'application/json',
'Authorization': "Bearer " + useCookie('token').value
},
baseURL: useRuntimeConfig().public.baseUrl
}).then(res => {
userList.value=res as UserListItem[];
}).catch(err => {
toast.error(err)
})
}
onMounted(() => {
GetServerUserList()
})
const refresh = () => {
userList.value=[]
GetServerUserList()
}
const page=ref<number>(1)
const filterPage=computed(()=>{
if(userList.value.length<=10){
return userList.value
}
return userList.value.slice((page.value-1)*14,page.value*14)
})
</script>
<template>
<div class="user-list-layout">
<div class="user-list-header">
<Icon name="ArrowDownUp" :size="24" :stroke-width="1.5"></Icon>
<h3>用户列表</h3>
<Icon name="Repeat2" :size="24" :stroke-width="1.5" @click="refresh"/>
</div>
<div class="user-list-body">
<div class="user-list-item" @click="navigateTo(`/serverUser/all`)">
<div class="avatar">
<n-avatar
:size="48"> 全部 </n-avatar>
</div>
<div class="info">
<div class="top">
<h3>全部</h3>
</div>
</div>
</div>
<div :class="{'user-list-item':true,'user-list-item-active':$route.params.id===item.name}" v-for="item in filterPage" @click="navigateTo(`/serverUser/${item.name.split(':')[0]}`)">
<div class="avatar">
<n-avatar
:size="48">
{{item.name.slice(0,3).toUpperCase()}}
</n-avatar>
</div>
<div class="info">
<div class="top">
<h3>{{ item.name.split(':')[0] }}</h3>
<div class="tags">
<n-tag type="info" :bordered="false">UID:{{item.name.split(':')[1]}}</n-tag>
<n-Tag v-if="item.isOnline">在线</n-Tag>
<n-Tag v-if="item.isOnline">{{item.port}}</n-Tag>
<n-Tag v-if="item.isOnline">{{item.address}}</n-Tag>
</div>
</div>
<p>{{item.lastLoginTime}}</p>
</div>
</div>
</div>
<div class="pages">
<n-pagination v-model:page="page" :page-count="Math.floor(userList.length/13)" size="medium"/>
</div>
</div>
</template>
<style scoped lang="scss">
@import "base";
.user-list-layout {
background: $light-bg-color;
border-radius: $radius;
border: $border;
padding: $padding 0;
grid-row: 1/3;
display: flex;
flex-direction: column;
*{
@include SC_Font;
}
.dark-mode &{
background: $dark-bg-color;
}
}
.user-list-header {
display: flex;
align-items: center;
padding: 0 $padding;
justify-content: space-between;
h3{
color: $light-text-color;
}
svg {
color: rgba(51, 51, 51, 0.34);
stroke: rgba(51, 51, 51, 0.44);
cursor: pointer;
&:hover {
stroke: rgba(51, 51, 51, 0.64);
}
}
.dark-mode &{
h3{
color: $dark-text-color;
}
svg{
color: rgba(255, 255, 255, 0.34);
stroke: rgba(255, 255, 255, 0.44);
&:hover {
stroke: rgba(255, 255, 255, 0.64);
}
}
}
}
.pages{
padding: $padding;
display: flex;
justify-content: center;
align-items: center;
}
.user-list-body{
display: flex;
flex-direction: column;
flex: 1;
gap: $gap;
padding: $padding*2 $padding;
}
.user-list-item{
display: flex;
align-items: center;
gap: $gap*4;
padding: 8px;
border-radius: $radius;
cursor: pointer;
.avatar{
display: flex;
}
h3,p{
color: $light-text-color;
}
.dark-mode &{
h3,p{
color: $dark-text-color;
}
}
&:hover{
background: rgba(51, 51, 51, 0.06);
}
.dark-mode &{
&:hover{
background: rgba(255, 255, 255, 0.06);
}
}
.info{
display: flex;
flex-direction: column;
flex:1;
gap: $gap;
.top{
display: flex;
justify-content: space-between;
}
.tags{
display: flex;
gap: $gap;
}
}
}
.user-list-item-active{
background: rgba(51, 51, 51, 0.2);
.dark-mode &{
background: rgba(255, 255, 255, 0.2);
}
}
</style>