完成前端子账户增删操作
This commit is contained in:
parent
74ce37b72c
commit
87d469a47b
@ -6,6 +6,7 @@ import com.example.entity.vo.request.RenameNodeVO;
|
||||
import com.example.entity.vo.request.RuntimeDetailVO;
|
||||
import com.example.entity.vo.response.ClientDetailsVO;
|
||||
import com.example.entity.vo.response.ClientPreviewVO;
|
||||
import com.example.entity.vo.response.ClientSimpleVO;
|
||||
import com.example.entity.vo.response.RuntimeDetailsVO;
|
||||
import com.example.service.ClientService;
|
||||
import jakarta.annotation.Resource;
|
||||
@ -26,6 +27,11 @@ public class MonitorController {
|
||||
return RestBean.success(service.listClients());
|
||||
}
|
||||
|
||||
@GetMapping("/simple-list")
|
||||
public RestBean<List<ClientSimpleVO>> simpleClientList() {
|
||||
return RestBean.success(service.listSimpleList());
|
||||
}
|
||||
|
||||
@PostMapping("/rename")
|
||||
public RestBean<Void> renameClient(@RequestBody @Valid RenameClientVO vo) {
|
||||
service.renameClient(vo);
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.example.entity.vo.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ClientSimpleVO {
|
||||
int id;
|
||||
String name;
|
||||
String location;
|
||||
String osName;
|
||||
String osVersion;
|
||||
String ip;
|
||||
}
|
@ -6,7 +6,7 @@ import lombok.Data;
|
||||
@Data
|
||||
public class SubAccountVO {
|
||||
int id;
|
||||
String name;
|
||||
String username;
|
||||
String email;
|
||||
JSONArray clients;
|
||||
JSONArray clientList;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import com.example.entity.vo.request.RenameNodeVO;
|
||||
import com.example.entity.vo.request.RuntimeDetailVO;
|
||||
import com.example.entity.vo.response.ClientDetailsVO;
|
||||
import com.example.entity.vo.response.ClientPreviewVO;
|
||||
import com.example.entity.vo.response.ClientSimpleVO;
|
||||
import com.example.entity.vo.response.RuntimeDetailsVO;
|
||||
|
||||
import java.util.List;
|
||||
@ -20,6 +21,7 @@ public interface ClientService extends IService<Client> {
|
||||
void updateClientDetail(ClientDetailVO vo, Client client);
|
||||
void updateRuntimeDetail(RuntimeDetailVO vo, Client client);
|
||||
List<ClientPreviewVO> listClients();
|
||||
List<ClientSimpleVO> listSimpleList();
|
||||
void renameClient(RenameClientVO vo);
|
||||
void renameNode(RenameNodeVO vo);
|
||||
ClientDetailsVO clientDetails(int clientId);
|
||||
|
@ -156,7 +156,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
||||
return this.list(Wrappers.<Account>query().eq("role", "user"))
|
||||
.stream().map(account -> {
|
||||
SubAccountVO vo = account.asViewObject(SubAccountVO.class);
|
||||
vo.setClients(JSONArray.parse(account.getClients()));
|
||||
vo.setClientList(JSONArray.parse(account.getClients()));
|
||||
return vo;
|
||||
}).toList();
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import com.example.entity.vo.request.RenameNodeVO;
|
||||
import com.example.entity.vo.request.RuntimeDetailVO;
|
||||
import com.example.entity.vo.response.ClientDetailsVO;
|
||||
import com.example.entity.vo.response.ClientPreviewVO;
|
||||
import com.example.entity.vo.response.ClientSimpleVO;
|
||||
import com.example.entity.vo.response.RuntimeDetailsVO;
|
||||
import com.example.mapper.ClientDetailMapper;
|
||||
import com.example.mapper.ClientMapper;
|
||||
@ -111,6 +112,15 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClientSimpleVO> listSimpleList() {
|
||||
return clientIdCache.values().stream().map(client -> {
|
||||
ClientSimpleVO vo = client.asViewObject(ClientSimpleVO.class);
|
||||
BeanUtils.copyProperties(detailMapper.selectById(vo.getId()), vo);
|
||||
return vo;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renameClient(RenameClientVO vo) {
|
||||
this.update(Wrappers.<Client>update().eq("id", vo.getId()).set("name", vo.getName()));
|
||||
|
155
itbaima-monitor-web/src/component/CreateSubAccount.vue
Normal file
155
itbaima-monitor-web/src/component/CreateSubAccount.vue
Normal file
@ -0,0 +1,155 @@
|
||||
<script setup>
|
||||
import {Lock, Message, User} from "@element-plus/icons-vue";
|
||||
import {reactive, ref} from "vue";
|
||||
import {osNameToIcon} from "@/tools";
|
||||
import {post} from "@/net";
|
||||
import {ElMessage} from "element-plus";
|
||||
|
||||
defineProps({
|
||||
clients: Array
|
||||
})
|
||||
|
||||
const emits = defineEmits(['create'])
|
||||
|
||||
const formRef = ref()
|
||||
const valid = ref(false)
|
||||
const onValidate = (prop, isValid) => valid.value = isValid
|
||||
const form = reactive({
|
||||
username: '',
|
||||
email: '',
|
||||
password: '',
|
||||
})
|
||||
|
||||
const validateUsername = (rule, value, callback) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请输入用户名'))
|
||||
} else if(!/^[a-zA-Z0-9\u4e00-\u9fa5]+$/.test(value)){
|
||||
callback(new Error('用户名不能包含特殊字符,只能是中文/英文'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
const rules = {
|
||||
username: [
|
||||
{ required: true, message: '请输入用户名', trigger: ['blur', 'change'] },
|
||||
{ validator: validateUsername, trigger: ['blur', 'change'] },
|
||||
{ min: 2, max: 8, message: '用户名的长度必须在2-8个字符之间', trigger: ['blur', 'change'] },
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: '请输入密码', trigger: ['blur', 'change'] },
|
||||
{ min: 6, max: 16, message: '密码的长度必须在6-16个字符之间', trigger: ['blur', 'change'] }
|
||||
], email: [
|
||||
{ required: true, message: '请输入邮件地址', trigger: ['blur', 'change'] },
|
||||
{type: 'email', message: '请输入合法的电子邮件地址', trigger: ['blur', 'change']}
|
||||
]
|
||||
}
|
||||
|
||||
const checkedClients = []
|
||||
const onCheck = (state, id) => {
|
||||
if(state) {
|
||||
checkedClients.push(id)
|
||||
} else {
|
||||
const index = checkedClients.indexOf(id);
|
||||
checkedClients.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
function createSubAccount() {
|
||||
formRef.value.validate((isValid) => {
|
||||
if(checkedClients.length === 0) {
|
||||
ElMessage.warning('请至少选择一个服务器用于子账户进行管理')
|
||||
return
|
||||
}
|
||||
if(isValid) {
|
||||
post('/api/user/sub/create', {
|
||||
...form,
|
||||
clients: checkedClients
|
||||
}, () => {
|
||||
ElMessage.success('子账户创建成功!')
|
||||
emits('create')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div style="padding: 15px 20px;height: 100%">
|
||||
<div style="display: flex;flex-direction: column;height: 100%">
|
||||
<div>
|
||||
<div class="title">
|
||||
<i class="fa-solid fa-user-plus"></i> 添加新的子账户
|
||||
</div>
|
||||
<div class="desc">子账户同样用于管理服务器,但是可以自由分配指定的服务器,子账户只能访问被分配到的服务器。</div>
|
||||
<el-divider style="margin: 10px 0"/>
|
||||
</div>
|
||||
<div>
|
||||
<el-form label-position="top" :rules="rules" :model="form"
|
||||
@validate="onValidate" ref="formRef">
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input type="text" v-model="form.username"
|
||||
:prefix-icon="User" placeholder="子账户用户名" maxlength="16"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="电子邮件" prop="email">
|
||||
<el-input type="email" v-model="form.email"
|
||||
:prefix-icon="Message" placeholder="子账户电子邮件" maxlength="16"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input type="password" v-model="form.password"
|
||||
:prefix-icon="Lock" placeholder="子账户密码" maxlength="16"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-divider style="margin: 10px 0"/>
|
||||
<div class="desc">请在下方选择允许子账户访问的服务器列表。</div>
|
||||
</div>
|
||||
<el-scrollbar style="flex: 1">
|
||||
<div class="client-card" v-for="item in clients">
|
||||
<el-checkbox @change="state => onCheck(state, item.id)"/>
|
||||
<div style="margin-left: 20px">
|
||||
<div style="font-size: 14px;font-weight: bold">
|
||||
<span :class="`flag-icon flag-icon-${item.location}`"></span>
|
||||
<span style="margin: 0 10px">{{ item.name }}</span>
|
||||
</div>
|
||||
<div style="font-size: 12px;color: grey">
|
||||
操作系统:
|
||||
<i :style="{color: osNameToIcon(item.osName).color}"
|
||||
:class="`fa-brands ${osNameToIcon(item.osName).icon}`"></i>
|
||||
{{`${item.osName} ${item.osVersion}`}}
|
||||
</div>
|
||||
<div style="font-size: 12px;color: grey">
|
||||
<span style="margin-right: 10px">公网IP: {{item.ip}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<div style="text-align: center;margin-top: 10px">
|
||||
<el-button @click="createSubAccount" type="success"
|
||||
:disabled="!valid" plain>确认创建</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: dodgerblue;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 13px;
|
||||
color: grey;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.client-card {
|
||||
border-radius: 5px;
|
||||
background-color: var(--el-bg-color-page);
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 10px;
|
||||
}
|
||||
</style>
|
@ -28,7 +28,7 @@
|
||||
<el-main class="main-content">
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition name="el-fade-in-linear" mode="out-in">
|
||||
<keep-alive>
|
||||
<keep-alive exclude="Security">
|
||||
<component :is="Component"/>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
|
@ -1,9 +1,10 @@
|
||||
<script setup>
|
||||
import {reactive, ref} from "vue";
|
||||
import {logout, post} from "@/net";
|
||||
import {get, logout, post} from "@/net";
|
||||
import {ElMessage} from "element-plus";
|
||||
import {Lock, Plus, Switch} from "@element-plus/icons-vue";
|
||||
import {Delete, Lock, Plus, Switch} from "@element-plus/icons-vue";
|
||||
import router from "@/router";
|
||||
import CreateSubAccount from "@/component/CreateSubAccount.vue";
|
||||
|
||||
const formRef = ref()
|
||||
const valid = ref(false)
|
||||
@ -49,6 +50,24 @@ function resetPassword() {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const accounts = ref([])
|
||||
const initSubAccounts = () =>
|
||||
get('/api/user/sub/list', list => accounts.value = list)
|
||||
|
||||
const createAccount = ref(false)
|
||||
const simpleList = ref([])
|
||||
get('/api/monitor/simple-list', list => {
|
||||
simpleList.value = list
|
||||
initSubAccounts()
|
||||
})
|
||||
|
||||
function deleteAccount(id) {
|
||||
get(`/api/user/sub/delete?uid=${id}`, () => {
|
||||
ElMessage.success('子账户删除成功')
|
||||
initSubAccounts()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -79,10 +98,33 @@ function resetPassword() {
|
||||
<div class="info-card">
|
||||
<div class="title"><i class="fa-solid fa-users"></i> 子用户管理</div>
|
||||
<el-divider style="margin: 10px 0"/>
|
||||
<el-empty :image-size="100" description="还没有任何子用户哦">
|
||||
<el-button :icon="Plus" type="primary" plain>添加子用户</el-button>
|
||||
<div v-if="accounts.length" style="text-align: center">
|
||||
<div v-for="item in accounts" class="account-card">
|
||||
<el-avatar class="avatar" :size="30"
|
||||
src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"/>
|
||||
<div style="margin-left: 15px;line-height: 18px;flex: 1">
|
||||
<div>
|
||||
<span>{{item.username}}</span>
|
||||
<span style="font-size: 13px;color: grey;margin-left: 5px">
|
||||
管理 {{item.clientList.length}} 个服务器
|
||||
</span>
|
||||
</div>
|
||||
<div style="font-size: 13px;color: grey">{{item.email}}</div>
|
||||
</div>
|
||||
<el-button type="danger" :icon="Delete"
|
||||
@click="deleteAccount(item.id)" text>删除子账户</el-button>
|
||||
</div>
|
||||
<el-button :icon="Plus" type="primary"
|
||||
@click="createAccount = true" plain>添加更多子用户</el-button>
|
||||
</div>
|
||||
<el-empty :image-size="100" description="还没有任何子用户哦" v-else>
|
||||
<el-button :icon="Plus" type="primary"
|
||||
@click="createAccount = true" plain>添加子用户</el-button>
|
||||
</el-empty>
|
||||
</div>
|
||||
<el-drawer v-model="createAccount" size="350" :with-header="false">
|
||||
<create-sub-account @create="createAccount = false;initSubAccounts()" :clients="simpleList"/>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -100,4 +142,24 @@ function resetPassword() {
|
||||
color: dodgerblue;
|
||||
}
|
||||
}
|
||||
|
||||
.account-card {
|
||||
border-radius: 5px;
|
||||
background-color: var(--el-bg-color-page);
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: left;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
:deep(.el-drawer) {
|
||||
margin: 10px;
|
||||
height: calc(100% - 20px);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
:deep(.el-drawer__body) {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
x
Reference in New Issue
Block a user