k8s管理系统项目前端-user
k8s管理系统项目前端-user
一、userView
<template>
<div class="container">
<!-- 第一部分: 头部 -->
<div class="header shadow">
<div class="left-group">
<el-button disabled type="primary" @click="createUser">
<span style="vertical-align: middle"> 创建 </span>
</el-button>
<el-button type="primary" @click="transferDialogVisible = true">
<span style="vertical-align: middle"> 添加到组 </span>
</el-button>
<el-button type="primary" @click="DeleteUser(row)">
<span style="vertical-align: middle"> 删除</span>
</el-button>
<el-button disabled type="primary" @click="UnlockUser">
<span style="vertical-align: middle"> 解锁 </span>
</el-button>
<el-input placeholder="请输入内容" v-model="searchText" class="search-input" @input="handleInput">
<template #append>
<el-button type="primary" @click="search()">
<el-icon><Search /></el-icon>
</el-button>
</template>
</el-input>
</div>
</div>
<!-- 第二部分: 表格 -->
<div class="table-wrapper shadow">
<el-table :data="tableData" style="width: 100%" ref="multipleTable" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="Id" align="center">
<template #default="{ row }">
<div>
<span style="vertical-align: middle; color: #1395FF; cursor: pointer;" @click="handleRowClick(row)">
{{ row.id }}
</span>
</div>
</template>
</el-table-column>
<el-table-column prop="name" label="name" align="center">
<template #default="{ row }">
<div>
<span style="vertical-align: middle; color: #1395FF; cursor: pointer;" @click="handleRowClick(row)">
{{ row.name }}
</span>
</div>
</template>
</el-table-column>
<el-table-column prop="phone" label="手机号" align="center">
<template #default="{ row }">
<div>
{{ row.phone }}
</div>
</template>
</el-table-column>
<el-table-column prop="email" label="邮箱" align="center">
<template #default="{ row }">
<div>
{{ row.email }}
</div>
</template>
</el-table-column>
<el-table-column prop="type" label="账号类型" align="center" >
<template #default="{ row }">
<div>
<p style="color: #4795EE; margin: 0;">{{ row.type }}</p>
</div>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100px" align="center">
<template #default="{ row }">
<el-tag :type="row.statusType" class="ml-2">{{ row.status }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center" >
<template #default="{ row }">
<div>
<el-tag class="ml-2" type="warning">{{row.createTime}}</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="Operation" label="操作" align="center">
<template #default="{ row }">
<div class="button-group">
<el-button size="small" color="#5AABFF" :dark="isDark" plain @click="addUserToGroup(row)">
<el-icon><EditPen /></el-icon>
<span style="vertical-align: middle"> 添加到组 </span>
</el-button>
<el-button size="small" color="#F58D79" :dark="isDark" plain @click="DeleteUser(row)">
<el-icon><Tickets /></el-icon>
<span style="vertical-align: middle"> 删除 </span>
</el-button>
</div>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[5, 10, 20, 30]"
:small="small"
:disabled="disabled"
:background="background"
layout="total, sizes, prev, pager, next, jumper"
:total=deploymentCount
class="paginations"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
<el-dialog v-model="transferDialogVisible" title="请选择组">
<el-transfer
v-model="targetKeys"
:data="groupData"
:titles="['可选组', '已选组']"
class="transfer-custom"
></el-transfer>
<span slot="footer" class="dialog-footer">
<el-button @click="transferDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleTransferConfirm">确定</el-button>
</span>
</el-dialog>
</template>
<script setup>
import {nextTick, onBeforeMount, reactive, ref, watch} from 'vue';
import 'element-plus/dist/index.css';
import { EditPen, Search } from '@element-plus/icons-vue';
import {
DELETE_SECRET,
PV_DETAIL, PV_LIST,
} from "../../../api/k8s.js";
import _, {parseInt} from 'lodash';
import json2yaml from 'json2yaml'
import router from "@/router/index.js";
import {ADDUSER_GROUP, DELETE_USER, GROUP_LIST, USER_LIST} from "../../../api/user.js";
import {ElMessage, ElMessageBox} from "element-plus";
let currentPage = ref(1)
let pageSize = ref(5)
const small = ref(false)
const background = ref(false)
const disabled = ref(false)
const selectedIds = ref([])
var deploymentCount = ref(0)
const multipleTable = ref()
const handleSelectionChange = (selection)=> {
selectedIds.value = selection.map(item => item.id)
console.log(selectedIds.value)
}
const transferDialogVisible = ref(false);
const groupData = ref([]); // 这里应该是一个包含所有组的数组
const targetKeys = ref([]); // 这里是穿梭框右侧的key数组
const renderFunc = (h, option) => {
return h('span', option.label);
};
const handleTransferConfirm = async () => {
console.log('已选组:', targetKeys.value);
console.log(selectedIds.value)
const addUser_group = reactive({
user_id: selectedIds.value,
group_id: targetKeys.value
})
console.log(addUser_group.value)
try {
const resp = await ADDUSER_GROUP(addUser_group);
console.log("添加用户到组 ", resp);
} catch (e) {
console.error(e);
}
// 此处可以添加关联组的逻辑
transferDialogVisible.value = false;
// 调用 API 关联组或者执行其他操作
};
const handleSizeChange = (val) => {
console.log(`${val} items per page`)
// namespaceAllParameters.page_size = val
localStorage.setItem('servicepageSize',val)
getUserData()
}
const handleCurrentChange = (val) => {
console.log(`current page: ${val}`)
currentPage.value = val
// namespaceAllParameters.page_number = val
localStorage.setItem('servicecurrentPage', val); // 将当前页保存在 localStorage
getUserData()
}
// 在模板中可以直接使用 Refresh, EditPen, 和 Search
// 辅助函数,用于隐藏手机号中间四位
const hidePhoneMiddleDigits = (phone) => {
if (phone && phone.length === 11) {
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
}
return phone; // 如果格式不正确,返回原始值
};
const createUser = ()=>{
}
const addUserToGroup = (params)=>{
selectedIds.value = [params.id]
console.log(selectedIds.value)
}
const DeleteUser = async ()=>{
ElMessageBox.confirm(
`确定要删除用户吗?`,
'警告',
{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}
).then(async () => {
const user_params = reactive({
users_id: selectedIds.value
})
try {
const resp = await DELETE_USER(user_params);
console.log("————————————————",resp)
ElMessage({
type: 'success',
message: `用户已被删除`
});
getUserData()
}catch (e){
console.log(e)
ElMessage.error(`删除失败: ${e}`);
}
}).catch(() => {
ElMessage({
type: 'info',
message: '已取消删除'
});
});
}
const UnlockUser = ()=>{
}
const handleInput = ()=> {
}
const handleRowClick = (row) => {
router.push({
name: 'userDetail',
params: { id: row.id}
});
};
const createDialogVisible = ref(false);
// fetchNamespaces 函数使用 getNSData 的返回值来更新命名空间的下拉菜单
// getNSData 函数获取命名空间并返回名称数组
const formatDateTime = (dateTimeString) => {
return dateTimeString.replace('T', ' ').replace('Z', '');
};
// 示例数据和方法
const searchText = ref('');
const tableData = ref([
{
id: "",
name: "",
nickName: '',
phone: '',
email: '',
type: '',
status: '',
createTime:"",
Operation:"",
},
// ...其他数据项
]);
const search = async () => {
console.log('执行搜索:', searchText.value);
const searchParameters = reactive({
page_size: pageSize,
page_number: currentPage,
filterName: searchText.value,
namespace: ''
})
try {
const resp = await PV_LIST(searchParameters);
if (resp && resp.data && Array.isArray(resp.data.items)) {
tableData.value = resp.data.items.map((item) => {
console.log(item.spec.claimRef,'握草无情')
let pvc
if (item.spec.claimRef === undefined) {
pvc = '-'
}else {
pvc = item.spec.claimRef.name
}
// 根据后端数据结构提取所需信息
return {
name: item.metadata.name, // PersistentVolume的名字
status: item.status.phase, // PersistentVolume的状态
mode: item.spec.volumeMode, // PersistentVolume的模式
capacity: item.spec.capacity.storage, // PersistentVolume的容量
pvc: pvc, // PVC信息,根据实际情况填写或调整
accessModes: item.spec.accessModes.join(', '), // PersistentVolume的访问模式
reclaimPolicy: item.spec.persistentVolumeReclaimPolicy, // PersistentVolume的回收策略
createTime: formatDateTime(item.metadata.creationTimestamp), // 创建时间,假设您已定义formatDateTime函数
// 其他属性可以根据需要添加
};
});
}
// 更新部署计数
deploymentCount.value = resp.data.count;
} catch (e) {
console.error(e);
// 处理错误情况,可能要向用户显示错误信息或日志输出
}
};
const refresh = () => {
getUserData()
console.log('刷新表格数据');
};
const updateParameters = reactive({
name: "",
namespace: '',
content: ""
})
const user_params = reactive({
page_size: pageSize,
page_number: currentPage,
})
const group_params = reactive({
page_size: pageSize,
page_number: currentPage,
})
const getGroupsList = async () => {
try {
const resp = await GROUP_LIST(group_params);
console.log("组啊===== ", resp);
if (resp && resp.data && resp.data.items) {
// Map items to the expected data structure for el-transfer
groupData.value = resp.data.items.map(item => ({
key: item.id, // 假设id是唯一的
label: item.name, // label是显示在列表中的文本
disabled: false // 可以根据需要设置
}));
}
} catch (e) {
console.error(e);
}
}
const getUserData = async () => {
try {
const resp = await USER_LIST(user_params);
console.log("用户", resp);
if (resp && resp.data && Array.isArray(resp.data.items)) {
tableData.value = resp.data.items.map((item) => {
// 用户类型判断
const userType = item.username === 'admin' ? '管理员' : '一般用户';
// 用户状态判断
let userStatus = '';
let userStatusType = '';
switch (item.status) {
case 0:
userStatus = '正常';
userStatusType = 'success';
break;
case 1:
userStatus = '临时锁定';
userStatusType = 'error';
break;
case 2:
userStatus = '永久锁定';
userStatusType = 'error';
break;
// 默认情况,您可以根据需要添加其他状态
default:
userStatus = '未知';
userStatusType = 'info';
break;
}
return {
id: item.id,
name: item.username,
phone: hidePhoneMiddleDigits(item.phone),
nickName: item.nickname,
email: item.email,
type: userType,
status: userStatus,
statusType: userStatusType, // 新增属性,用于标识状态类型
createTime: formatDateTime(item.created_at),
};
});
}
// 更新部署计数
deploymentCount.value = resp.data.count;
} catch (e) {
console.error(e);
}
};
// const getDeployDetailData = async (serviceName)=>{
// try {
// const DeploymentDetailparams = reactive({
// name: serviceName,
// namespace: selectedNamespace.value
// })
// console.log("ddddddddd",DeploymentDetailparams)
// const resp = await PV_DETAIL(DeploymentDetailparams)
// console.log("cccccccc",resp)
// console.log("yaml =======",json2yaml.stringify(resp.data))
// yamlContent.value = json2yaml.stringify(resp.data); // 确保将数据赋值给 yamlContent
// currentDeployName.value = resp.data.metadata.name
// updateParameters.content = yamlContent.value
// await nextTick()
// dialogVisible.value = true;
//
// }catch (e){
// console.log(e)
// console.log("你吗")
// }
// }
// 在setup函数中定义定时器
let refreshInterval = null;
onBeforeMount( async ()=> {
clearInterval(refreshInterval);
// 尝试从 localStorage 中读取状态
const savedPageSize = localStorage.getItem('nspageSize');
const savedCurrentPage = localStorage.getItem('nscurrentPage');
// 如果存在则更新到响应式变量中
if (savedPageSize) {
pageSize.value = parseInt(savedPageSize, 10);
}
if (savedCurrentPage) {
currentPage.value = parseInt(savedCurrentPage, 10);
}
getUserData()
getGroupsList()
// 假设这是从 API 获取的组列表
groupData.value = [
{ key: 1, label: '组1' },
{ key: 2, label: '组2' },
// ...更多组
];
});
</script>
<style scoped>
.loading-icon {
width: 20px; /* 或者您希望的任何尺寸 */
height: 20px; /* 保持与宽度相同以保持图标的纵横比 */
margin-left: 5px; /* 添加一点空间在状态文本和图标之间 */
animation: loading-spin 2s linear infinite;
}
/* 如果需要,可以移除这个类,因为它可能会导致对齐问题 */
/* .loader {
animation: loader-spin 1s linear infinite;
} */
@keyframes loading-spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.container {
margin: 10px;
background-color: #F2F2F2;
}
.deployment-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px;
margin: 10px;
margin-bottom: -10px;
background: #FFF;
border: 2px solid #ebeef5;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
/* 新增左侧部分样式,放置“命名空间:”文本和下拉框 */
.left-section {
display: flex;
align-items: center;
}
/* 确保下拉框和文本在同一行 */
.el-select {
margin-left: 10px; /* 为下拉框添加左侧间隔 */
}
.header {
display: flex;
align-items: center;
justify-content: space-between; /* 添加此属性对子元素进行分散对齐 */
margin-bottom: 0px;
gap: 10px;
padding: 10px;
background: #FFF;
border: 2px solid #ebeef5;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.search-input {
/*flex-grow: 1;*/
width: 200px;
}
.table-wrapper {
background: #FFF;
border: 2px solid #ebeef5; /* 浅色边框线 */
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.paginations {
margin-top: 10px;
margin-left: 20px;
margin-bottom: 10px;
}
/* 左侧组合样式,创建按钮和搜索框靠在一起 */
.left-group {
display: flex;
align-items: center;
gap: 10px; /* You can adjust the gap as needed */
}
/* 右侧刷新按钮 */
.right-group {
display: flex;
align-items: center;
}
.yaml-content {
background-color: #f5f5f5;
border-left: 3px solid #4795EE;
padding: 15px;
white-space: pre-wrap;
text-align: left;
margin: 20px 0;
overflow-x: auto;
}
.status-active {
color: #67C23A;
}
.status-inactive {
color: red;
}
.dialog-footer {
/*text-align: right;*/
display: flex;
justify-content: flex-end;
padding: 8px;
}
.deployment-header {
display: flex;
align-items: center;
height: 30px;
padding: 10px;
margin: 10px;
margin-bottom: -10px;
background: #FFF;
border: 2px solid #ebeef5;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.form-item-with-help {
margin-top: 10px;
margin-left: 20px;
}
.form-item-with-resource {
margin-top: 10px;
margin-left: 20px;
}
.form-item {
flex-wrap: wrap; /* 确保换行 */
/*align-items: center; !* 如果需要垂直居中 *!*/
margin-bottom: 10px; /* 保持垂直间距 */
}
.input-item {
width: 200px;
margin-right: 10px;
}
.help-text {
display: block; /* 保证帮助文本在新的行显示 */
font-size: 12px;
width: 1000px;
color: #999999;
margin-top: 5px;
}
.input-with-help {
margin-top: 20px;
display: flex;
flex-direction: column;
}
.input-deployname {
width: 300px; /* 限制这个div的宽度 */
display: flex;
flex-direction: column; /* 让子元素垂直排列 */
}
.input-containername {
width: 250px; /* 限制这个div的宽度 */
display: flex;
margin-left: -50px;
flex-direction: column; /* 让子元素垂直排列 */
}
.add-button {
margin-top: -20px; /* 添加按钮与输入行之间的空间 */
margin-left: 200px;
}
.input-container-cpu {
display: flex;
flex-direction: column;
/*padding-left: -20px; !* 往右移动整个容器 *!*/
}
.cpu-label {
margin-bottom: 5px; /* 调整为所需的间距 */
margin-left: -50px;
}
.container {
margin: 10px;
}
.item-container {
margin-bottom: 10px;
}
.content-container {
background-color: #F2F2F2;
padding: 10px;
display: flex;
width: 700px;
justify-content: space-between;
align-items: center;
transition: height 0.3s;
overflow: hidden;
position: relative;
}
.content-container.collapsed {
height: 40px;
}
.info {
display: flex;
align-items: center;
}
.actions {
position: absolute;
right: 10px; /* 调整为需要的值 */
top: 10px; /* 调整为需要的值 */
}
.input-row {
display: flex;
align-items: center;
gap: 10px;
/*margin-left: -50px;*/
}
.input-row .el-input {
flex: 1;
}
.input-row label {
margin-left: 10px; /* 或者需要的任何值 */
}
.input-row .el-input .el-input__inner {
width: 100%; /* 让输入框充满其容器 */
}
.input-containername p {
margin-bottom: 10px; /* 为“CPU:”下方添加一些间隔 */
}
.form-item-resource {
margin-left: 20px; /* 整个表单项向右移动 20px */
margin-top: 10px;
}
.custom-form-item {
height: auto;
overflow: auto;
}
.check-method-container,
.execution-command-container {
display: flex;
align-items: center;
margin-bottom: 10px; /* 添加一些垂直间距 */
}
.method-label {
width: 100px;
margin: 10px;
margin-right: 20px; /* 文本与选择框/输入框之间的间隔 */
}
.command-label {
/*margin-right: 20px; !* 文本与输入框之间的间隔 *!*/
width: 100px;
margin: 10px;
}
.livenessdiv {
background-color: white;
width: 500px;
}
.port-range {
margin-left: 10px;
}
.input-healthContainer {
margin-left: -50px;
}
.el-select,
.el-input {
/*flex-grow: 1; !* 输入框和选择框将占据剩余空间 *!*/
max-width: calc(100% - 100px); /* 限制最大宽度,这里的100px是示例,可以根据实际情况调整 */
}
.button-group {
display: flex;
justify-content: center;
align-items: center;
gap: 10px; /* 调整按钮之间的间隔 */
}
.variables-header {
display: flex;
justify-content: space-between;
padding-bottom: 10px;
}
.variable-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.variable-name, .variable-value {
width: 100px;
}
.variable-input {
flex: 1;
margin-right: 10px;
}
.el-input {
max-width: 95%;
}
/* CSS */
.transfer-custom {
flex: 1; /* 使两个面板均匀分配空间 */
margin-left: 120px;
}
.transfer-custom .el-transfer {
display: flex;
align-items: stretch; /* 确保两个面板高度相同 */
}
</style>
二、userInfoView
<template>
<div class="container">
<!-- 第一部分: 头部 -->
<div class="header shadow">
<el-page-header @back="goBack">
<template #content>
<span style="font-size: 14px"> 用户详情 </span>
</template>
</el-page-header>
</div>
<div class="info shadow">
<h4 class="InfoHeader">用户信息</h4>
<div class="user-info">
<p><span class="label">用户名:</span><span class="value" id="username-value">{{userInfo.username}}</span></p>
<p><span class="label">昵称:</span><span class="value" id="nickname-value">{{userInfo.nickname}}</span></p>
<p><span class="label">手机号:</span><span class="value" id="phone-value">{{userInfo.phone}}</span></p>
<p><span class="label">邮箱:</span><span class="value" id="email-value">{{userInfo.email}}</span></p>
</div>
</div>
<div class="roleInfo shadow">
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
<el-tab-pane label="已关联的权限" name="first">
<el-button disabled type="primary" @click="addUserPermission">
<span style="vertical-align: middle">关联策略 </span>
</el-button>
<el-button disabled type="primary" @click="deleteUserPermission">
<span style="vertical-align: middle"> 解除策略 </span>
</el-button>
<el-table
ref="multipleTable"
:data="permissionData"
style="width: 100%;margin-top: 10px"
@selection-change="permissionDataChange"
>
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="ID" align="center" style="50px">
<template #default="{ row }">
<div>
<span style="vertical-align: middle; color: #1395FF; cursor: pointer;">
{{ row.id }}
</span>
</div>
</template>
</el-table-column>
<el-table-column prop="resource" label="资源" align="center">
<template #default="{ row }">
<div>
<span style="vertical-align: middle; color: #1395FF; cursor: pointer;">
{{ row.resource }}
</span>
</div>
</template>
</el-table-column>
<el-table-column prop="operation" label="操作" align="center">
<template #default="{ row }">
<div>
<span style="vertical-align: middle; color: #1395FF; cursor: pointer;">
{{ row.operation }}
</span>
</div>
</template>
</el-table-column>
<el-table-column prop="description" label="描述" align="center">
<template #default="{ row }">
<div>
<span style="vertical-align: middle; color: #1395FF; cursor: pointer;">
{{ row.description }}
</span>
</div>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="已加入的组" name="second">
<el-table
ref="multipleTables"
:data="groupData"
style="width: 100%;margin-top: 10px"
@selection-change="groupDataChange"
>
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="ID" align="center">
<template #default="{ row }">
<div>
<span style="vertical-align: middle; color: #1395FF; cursor: pointer;">
{{ row.id }}
</span>
</div>
</template>
</el-table-column>
<el-table-column prop="name" label="名称" align="center">
<template #default="{ row }">
<div>
<span style="vertical-align: middle; color: #1395FF; cursor: pointer;">
{{ row.name }}
</span>
</div>
</template>
</el-table-column>
<el-table-column prop="description" label="描述" align="center">
<template #default="{ row }">
<div>
<span style="vertical-align: middle; color: #1395FF; cursor: pointer;">
{{ row.description }}
</span>
</div>
</template>
</el-table-column>
<el-table-column prop="created_at" label="创建时间" align="center">
<template #default="{ row }">
<div>
<span style="vertical-align: middle; color: #1395FF; cursor: pointer;">
{{ row.created_at }}
</span>
</div>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</div>
</div>
</template>
<script setup>
import router from "@/router/index.js";
import {onBeforeMount, reactive, ref} from "vue";
import {ADDUSER_GROUP, USER_DETAIL, USER_GROUP_LIST, USER_PERMISSION_LIST} from "../../../api/user.js";
const activeName = ref('first')
const multipleTable = ref()
const handleClick = (tab, event) => {
console.log(tab, event)
}
const permissionData = ref([{
id:'',
resource: '',
operation: '',
description: '',
},])
const groupData = ref([{
id:'',
name: '',
description: '',
created_at: '',
},])
const permissionDataChange = (val) => {
console.log(val)
// multipleSelection.value = val
}
const groupDataChange = (val) => {
console.log(val)
// multipleSelection.value = val
}
const { id } = defineProps({
id: String,
});
const addUserPermission = ()=>{
}
const deleteUserPermission = ()=>{
}
const getUserPermissions = async ()=>{
try {
console.log(id)
const resp = await USER_PERMISSION_LIST(id)
console.log("用户的权限:", resp);
if (resp && resp.data && Array.isArray(resp.data.items)) {
permissionData.value = resp.data.items.map((item) => ({
id: item.id,
resource: item.resource,
operation: item.operation,
description: item.description,
}));
}
} catch (e) {
console.error(e);
}
}
const getUserGroups = async ()=>{
try {
console.log(id)
const resp = await USER_GROUP_LIST(id)
console.log("用户的组:", resp);
if (resp && resp.data && Array.isArray(resp.data)) {
groupData.value = resp.data.map((item) => ({
id: item.id,
name: item.name,
created_at: item.created_at,
description: item.description,
}));
}
} catch (e) {
console.error(e);
}
}
const goBack = () => {
router.go(-1)
}
const userInfo = ref({
username: '',
nickname: '',
phone: '',
email: ''
});
const getUserDetail = async () => {
try {
const resp = await USER_DETAIL(id);
console.log("用户信息", resp);
if (resp.code === 200) {
userInfo.value.nickname = resp.data.nickname
userInfo.value.username = resp.data.username
userInfo.value.phone = resp.data.phone
userInfo.value.email = resp.data.email
}
} catch (e) {
console.error(e);
}
// 调用 API 关联组或者执行其他操作
};
onBeforeMount(()=>{
getUserDetail()
getUserPermissions()
getUserGroups()
})
</script>
<style scoped>
.container {
margin: 10px;
}
/* 左侧组合样式,创建按钮和搜索框靠在一起 */
.left-group {
display: flex;
align-items: center;
gap: 10px; /* You can adjust the gap as needed */
}
.header {
display: flex;
align-items: center;
justify-content: space-between; /* 添加此属性对子元素进行分散对齐 */
margin-bottom: 0px;
gap: 10px;
padding: 10px;
background: #FFF;
border: 2px solid #ebeef5;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.info {
/*display: flex;*/
/*align-items: center;*/
/*justify-content: space-between; !* 添加此属性对子元素进行分散对齐 *!*/
/*gap: 10px;*/
padding: 10px;
height: 250px;
background: #FFF;
border: 2px solid #ebeef5;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.roleInfo {
/*display: flex;*/
/*align-items: center;*/
/*justify-content: space-between; !* 添加此属性对子元素进行分散对齐 *!*/
/*gap: 10px;*/
padding: 10px;
height: 400px;
background: #FFF;
border: 2px solid #ebeef5;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
/* CSS */
.label {
color: grey;
margin-left: 20px;
font-size: 13px;
}
.shadow {
/* 阴影效果的样式 */
}
.InfoHeader {
color: #333; /* 标题颜色 */
margin-bottom: 10px; /* 标题下边距 */
}
.label {
color: grey; /* 标签颜色 */
font-size: 14px; /* 标签字体大小 */
margin-right: 5px; /* 标签右边距 */
}
.value {
color: #333; /* 值的字体颜色 */
font-size: 14px; /* 值的字体大小 */
}
.demo-tabs > .el-tabs__content {
padding: 32px;
color: #6b778c;
font-size: 32px;
font-weight: 600;
}
</style>
三、groupView
<template>
<div class="container">
<!-- 第一部分: 头部 -->
<div class="header shadow">
<div class="left-group">
<el-button disabled type="primary" @click="createUser">
<span style="vertical-align: middle"> 创建 </span>
</el-button>
<el-button type="primary" @click="transferDialogVisible = true">
<span style="vertical-align: middle"> 添加到组 </span>
</el-button>
<el-button type="primary" @click="DeleteUser(row)">
<span style="vertical-align: middle"> 删除</span>
</el-button>
<el-button disabled type="primary" @click="UnlockUser">
<span style="vertical-align: middle"> 解锁 </span>
</el-button>
<el-input placeholder="请输入内容" v-model="searchText" class="search-input" @input="handleInput">
<template #append>
<el-button type="primary" @click="search()">
<el-icon><Search /></el-icon>
</el-button>
</template>
</el-input>
</div>
</div>
<!-- 第二部分: 表格 -->
<div class="table-wrapper shadow">
<el-table :data="tableData" style="width: 100%" ref="multipleTable" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="Id" align="center">
<template #default="{ row }">
<div>
<span style="vertical-align: middle; color: #1395FF; cursor: pointer;" @click="handleRowClick(row)">
{{ row.id }}
</span>
</div>
</template>
</el-table-column>
<el-table-column prop="name" label="name" align="center">
<template #default="{ row }">
<div>
<span style="vertical-align: middle; color: #1395FF; cursor: pointer;" @click="handleRowClick(row)">
{{ row.name }}
</span>
</div>
</template>
</el-table-column>
<el-table-column prop="phone" label="手机号" align="center">
<template #default="{ row }">
<div>
{{ row.phone }}
</div>
</template>
</el-table-column>
<el-table-column prop="email" label="邮箱" align="center">
<template #default="{ row }">
<div>
{{ row.email }}
</div>
</template>
</el-table-column>
<el-table-column prop="type" label="账号类型" align="center" >
<template #default="{ row }">
<div>
<p style="color: #4795EE; margin: 0;">{{ row.type }}</p>
</div>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100px" align="center">
<template #default="{ row }">
<el-tag :type="row.statusType" class="ml-2">{{ row.status }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center" >
<template #default="{ row }">
<div>
<el-tag class="ml-2" type="warning">{{row.createTime}}</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="Operation" label="操作" align="center">
<template #default="{ row }">
<div class="button-group">
<el-button size="small" color="#5AABFF" :dark="isDark" plain @click="addUserToGroup(row)">
<el-icon><EditPen /></el-icon>
<span style="vertical-align: middle"> 添加到组 </span>
</el-button>
<el-button size="small" color="#F58D79" :dark="isDark" plain @click="DeleteUser(row)">
<el-icon><Tickets /></el-icon>
<span style="vertical-align: middle"> 删除 </span>
</el-button>
</div>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[5, 10, 20, 30]"
:small="small"
:disabled="disabled"
:background="background"
layout="total, sizes, prev, pager, next, jumper"
:total=deploymentCount
class="paginations"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
<el-dialog v-model="transferDialogVisible" title="请选择组">
<el-transfer
v-model="targetKeys"
:data="groupData"
:titles="['可选组', '已选组']"
class="transfer-custom"
></el-transfer>
<span slot="footer" class="dialog-footer">
<el-button @click="transferDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleTransferConfirm">确定</el-button>
</span>
</el-dialog>
</template>
<script setup>
import {nextTick, onBeforeMount, reactive, ref, watch} from 'vue';
import 'element-plus/dist/index.css';
import { EditPen, Search } from '@element-plus/icons-vue';
import {
DELETE_SECRET,
PV_DETAIL, PV_LIST,
} from "../../../api/k8s.js";
import _, {parseInt} from 'lodash';
import json2yaml from 'json2yaml'
import router from "@/router/index.js";
import {ADDUSER_GROUP, DELETE_USER, GROUP_LIST, USER_LIST} from "../../../api/user.js";
import {ElMessage, ElMessageBox} from "element-plus";
let currentPage = ref(1)
let pageSize = ref(5)
const small = ref(false)
const background = ref(false)
const disabled = ref(false)
const selectedIds = ref([])
var deploymentCount = ref(0)
const multipleTable = ref()
const handleSelectionChange = (selection)=> {
selectedIds.value = selection.map(item => item.id)
console.log(selectedIds.value)
}
const transferDialogVisible = ref(false);
const groupData = ref([]); // 这里应该是一个包含所有组的数组
const targetKeys = ref([]); // 这里是穿梭框右侧的key数组
const renderFunc = (h, option) => {
return h('span', option.label);
};
const handleTransferConfirm = async () => {
console.log('已选组:', targetKeys.value);
console.log(selectedIds.value)
const addUser_group = reactive({
user_id: selectedIds.value,
group_id: targetKeys.value
})
console.log(addUser_group.value)
try {
const resp = await ADDUSER_GROUP(addUser_group);
console.log("添加用户到组 ", resp);
} catch (e) {
console.error(e);
}
// 此处可以添加关联组的逻辑
transferDialogVisible.value = false;
// 调用 API 关联组或者执行其他操作
};
const handleSizeChange = (val) => {
console.log(`${val} items per page`)
// namespaceAllParameters.page_size = val
localStorage.setItem('servicepageSize',val)
getUserData()
}
const handleCurrentChange = (val) => {
console.log(`current page: ${val}`)
currentPage.value = val
// namespaceAllParameters.page_number = val
localStorage.setItem('servicecurrentPage', val); // 将当前页保存在 localStorage
getUserData()
}
// 在模板中可以直接使用 Refresh, EditPen, 和 Search
// 辅助函数,用于隐藏手机号中间四位
const hidePhoneMiddleDigits = (phone) => {
if (phone && phone.length === 11) {
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
}
return phone; // 如果格式不正确,返回原始值
};
const createUser = ()=>{
}
const addUserToGroup = (params)=>{
selectedIds.value = [params.id]
console.log(selectedIds.value)
}
const DeleteUser = async ()=>{
ElMessageBox.confirm(
`确定要删除用户吗?`,
'警告',
{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}
).then(async () => {
const user_params = reactive({
users_id: selectedIds.value
})
try {
const resp = await DELETE_USER(user_params);
console.log("————————————————",resp)
ElMessage({
type: 'success',
message: `用户已被删除`
});
getUserData()
}catch (e){
console.log(e)
ElMessage.error(`删除失败: ${e}`);
}
}).catch(() => {
ElMessage({
type: 'info',
message: '已取消删除'
});
});
}
const UnlockUser = ()=>{
}
const handleInput = ()=> {
}
const handleRowClick = (row) => {
router.push({
name: 'userDetail',
params: { id: row.id}
});
};
const createDialogVisible = ref(false);
// fetchNamespaces 函数使用 getNSData 的返回值来更新命名空间的下拉菜单
// getNSData 函数获取命名空间并返回名称数组
const formatDateTime = (dateTimeString) => {
return dateTimeString.replace('T', ' ').replace('Z', '');
};
// 示例数据和方法
const searchText = ref('');
const tableData = ref([
{
id: "",
name: "",
nickName: '',
phone: '',
email: '',
type: '',
status: '',
createTime:"",
Operation:"",
},
// ...其他数据项
]);
const search = async () => {
console.log('执行搜索:', searchText.value);
const searchParameters = reactive({
page_size: pageSize,
page_number: currentPage,
filterName: searchText.value,
namespace: ''
})
try {
const resp = await PV_LIST(searchParameters);
if (resp && resp.data && Array.isArray(resp.data.items)) {
tableData.value = resp.data.items.map((item) => {
console.log(item.spec.claimRef,'握草无情')
let pvc
if (item.spec.claimRef === undefined) {
pvc = '-'
}else {
pvc = item.spec.claimRef.name
}
// 根据后端数据结构提取所需信息
return {
name: item.metadata.name, // PersistentVolume的名字
status: item.status.phase, // PersistentVolume的状态
mode: item.spec.volumeMode, // PersistentVolume的模式
capacity: item.spec.capacity.storage, // PersistentVolume的容量
pvc: pvc, // PVC信息,根据实际情况填写或调整
accessModes: item.spec.accessModes.join(', '), // PersistentVolume的访问模式
reclaimPolicy: item.spec.persistentVolumeReclaimPolicy, // PersistentVolume的回收策略
createTime: formatDateTime(item.metadata.creationTimestamp), // 创建时间,假设您已定义formatDateTime函数
// 其他属性可以根据需要添加
};
});
}
// 更新部署计数
deploymentCount.value = resp.data.count;
} catch (e) {
console.error(e);
// 处理错误情况,可能要向用户显示错误信息或日志输出
}
};
const refresh = () => {
getUserData()
console.log('刷新表格数据');
};
const updateParameters = reactive({
name: "",
namespace: '',
content: ""
})
const user_params = reactive({
page_size: pageSize,
page_number: currentPage,
})
const group_params = reactive({
page_size: pageSize,
page_number: currentPage,
})
const getGroupsList = async () => {
try {
const resp = await GROUP_LIST(group_params);
console.log("组啊===== ", resp);
if (resp && resp.data && resp.data.items) {
// Map items to the expected data structure for el-transfer
groupData.value = resp.data.items.map(item => ({
key: item.id, // 假设id是唯一的
label: item.name, // label是显示在列表中的文本
disabled: false // 可以根据需要设置
}));
}
} catch (e) {
console.error(e);
}
}
const getUserData = async () => {
try {
const resp = await USER_LIST(user_params);
console.log("用户", resp);
if (resp && resp.data && Array.isArray(resp.data.items)) {
tableData.value = resp.data.items.map((item) => {
// 用户类型判断
const userType = item.username === 'admin' ? '管理员' : '一般用户';
// 用户状态判断
let userStatus = '';
let userStatusType = '';
switch (item.status) {
case 0:
userStatus = '正常';
userStatusType = 'success';
break;
case 1:
userStatus = '临时锁定';
userStatusType = 'error';
break;
case 2:
userStatus = '永久锁定';
userStatusType = 'error';
break;
// 默认情况,您可以根据需要添加其他状态
default:
userStatus = '未知';
userStatusType = 'info';
break;
}
return {
id: item.id,
name: item.username,
phone: hidePhoneMiddleDigits(item.phone),
nickName: item.nickname,
email: item.email,
type: userType,
status: userStatus,
statusType: userStatusType, // 新增属性,用于标识状态类型
createTime: formatDateTime(item.created_at),
};
});
}
// 更新部署计数
deploymentCount.value = resp.data.count;
} catch (e) {
console.error(e);
}
};
// const getDeployDetailData = async (serviceName)=>{
// try {
// const DeploymentDetailparams = reactive({
// name: serviceName,
// namespace: selectedNamespace.value
// })
// console.log("ddddddddd",DeploymentDetailparams)
// const resp = await PV_DETAIL(DeploymentDetailparams)
// console.log("cccccccc",resp)
// console.log("yaml =======",json2yaml.stringify(resp.data))
// yamlContent.value = json2yaml.stringify(resp.data); // 确保将数据赋值给 yamlContent
// currentDeployName.value = resp.data.metadata.name
// updateParameters.content = yamlContent.value
// await nextTick()
// dialogVisible.value = true;
//
// }catch (e){
// console.log(e)
// console.log("你吗")
// }
// }
// 在setup函数中定义定时器
let refreshInterval = null;
onBeforeMount( async ()=> {
clearInterval(refreshInterval);
// 尝试从 localStorage 中读取状态
const savedPageSize = localStorage.getItem('nspageSize');
const savedCurrentPage = localStorage.getItem('nscurrentPage');
// 如果存在则更新到响应式变量中
if (savedPageSize) {
pageSize.value = parseInt(savedPageSize, 10);
}
if (savedCurrentPage) {
currentPage.value = parseInt(savedCurrentPage, 10);
}
getUserData()
getGroupsList()
// 假设这是从 API 获取的组列表
groupData.value = [
{ key: 1, label: '组1' },
{ key: 2, label: '组2' },
// ...更多组
];
});
</script>
<style scoped>
.loading-icon {
width: 20px; /* 或者您希望的任何尺寸 */
height: 20px; /* 保持与宽度相同以保持图标的纵横比 */
margin-left: 5px; /* 添加一点空间在状态文本和图标之间 */
animation: loading-spin 2s linear infinite;
}
/* 如果需要,可以移除这个类,因为它可能会导致对齐问题 */
/* .loader {
animation: loader-spin 1s linear infinite;
} */
@keyframes loading-spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.container {
margin: 10px;
background-color: #F2F2F2;
}
.deployment-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px;
margin: 10px;
margin-bottom: -10px;
background: #FFF;
border: 2px solid #ebeef5;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
/* 新增左侧部分样式,放置“命名空间:”文本和下拉框 */
.left-section {
display: flex;
align-items: center;
}
/* 确保下拉框和文本在同一行 */
.el-select {
margin-left: 10px; /* 为下拉框添加左侧间隔 */
}
.header {
display: flex;
align-items: center;
justify-content: space-between; /* 添加此属性对子元素进行分散对齐 */
margin-bottom: 0px;
gap: 10px;
padding: 10px;
background: #FFF;
border: 2px solid #ebeef5;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.search-input {
/*flex-grow: 1;*/
width: 200px;
}
.table-wrapper {
background: #FFF;
border: 2px solid #ebeef5; /* 浅色边框线 */
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.paginations {
margin-top: 10px;
margin-left: 20px;
margin-bottom: 10px;
}
/* 左侧组合样式,创建按钮和搜索框靠在一起 */
.left-group {
display: flex;
align-items: center;
gap: 10px; /* You can adjust the gap as needed */
}
/* 右侧刷新按钮 */
.right-group {
display: flex;
align-items: center;
}
.yaml-content {
background-color: #f5f5f5;
border-left: 3px solid #4795EE;
padding: 15px;
white-space: pre-wrap;
text-align: left;
margin: 20px 0;
overflow-x: auto;
}
.status-active {
color: #67C23A;
}
.status-inactive {
color: red;
}
.dialog-footer {
/*text-align: right;*/
display: flex;
justify-content: flex-end;
padding: 8px;
}
.deployment-header {
display: flex;
align-items: center;
height: 30px;
padding: 10px;
margin: 10px;
margin-bottom: -10px;
background: #FFF;
border: 2px solid #ebeef5;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.form-item-with-help {
margin-top: 10px;
margin-left: 20px;
}
.form-item-with-resource {
margin-top: 10px;
margin-left: 20px;
}
.form-item {
flex-wrap: wrap; /* 确保换行 */
/*align-items: center; !* 如果需要垂直居中 *!*/
margin-bottom: 10px; /* 保持垂直间距 */
}
.input-item {
width: 200px;
margin-right: 10px;
}
.help-text {
display: block; /* 保证帮助文本在新的行显示 */
font-size: 12px;
width: 1000px;
color: #999999;
margin-top: 5px;
}
.input-with-help {
margin-top: 20px;
display: flex;
flex-direction: column;
}
.input-deployname {
width: 300px; /* 限制这个div的宽度 */
display: flex;
flex-direction: column; /* 让子元素垂直排列 */
}
.input-containername {
width: 250px; /* 限制这个div的宽度 */
display: flex;
margin-left: -50px;
flex-direction: column; /* 让子元素垂直排列 */
}
.add-button {
margin-top: -20px; /* 添加按钮与输入行之间的空间 */
margin-left: 200px;
}
.input-container-cpu {
display: flex;
flex-direction: column;
/*padding-left: -20px; !* 往右移动整个容器 *!*/
}
.cpu-label {
margin-bottom: 5px; /* 调整为所需的间距 */
margin-left: -50px;
}
.container {
margin: 10px;
}
.item-container {
margin-bottom: 10px;
}
.content-container {
background-color: #F2F2F2;
padding: 10px;
display: flex;
width: 700px;
justify-content: space-between;
align-items: center;
transition: height 0.3s;
overflow: hidden;
position: relative;
}
.content-container.collapsed {
height: 40px;
}
.info {
display: flex;
align-items: center;
}
.actions {
position: absolute;
right: 10px; /* 调整为需要的值 */
top: 10px; /* 调整为需要的值 */
}
.input-row {
display: flex;
align-items: center;
gap: 10px;
/*margin-left: -50px;*/
}
.input-row .el-input {
flex: 1;
}
.input-row label {
margin-left: 10px; /* 或者需要的任何值 */
}
.input-row .el-input .el-input__inner {
width: 100%; /* 让输入框充满其容器 */
}
.input-containername p {
margin-bottom: 10px; /* 为“CPU:”下方添加一些间隔 */
}
.form-item-resource {
margin-left: 20px; /* 整个表单项向右移动 20px */
margin-top: 10px;
}
.custom-form-item {
height: auto;
overflow: auto;
}
.check-method-container,
.execution-command-container {
display: flex;
align-items: center;
margin-bottom: 10px; /* 添加一些垂直间距 */
}
.method-label {
width: 100px;
margin: 10px;
margin-right: 20px; /* 文本与选择框/输入框之间的间隔 */
}
.command-label {
/*margin-right: 20px; !* 文本与输入框之间的间隔 *!*/
width: 100px;
margin: 10px;
}
.livenessdiv {
background-color: white;
width: 500px;
}
.port-range {
margin-left: 10px;
}
.input-healthContainer {
margin-left: -50px;
}
.el-select,
.el-input {
/*flex-grow: 1; !* 输入框和选择框将占据剩余空间 *!*/
max-width: calc(100% - 100px); /* 限制最大宽度,这里的100px是示例,可以根据实际情况调整 */
}
.button-group {
display: flex;
justify-content: center;
align-items: center;
gap: 10px; /* 调整按钮之间的间隔 */
}
.variables-header {
display: flex;
justify-content: space-between;
padding-bottom: 10px;
}
.variable-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.variable-name, .variable-value {
width: 100px;
}
.variable-input {
flex: 1;
margin-right: 10px;
}
.el-input {
max-width: 95%;
}
/* CSS */
.transfer-custom {
flex: 1; /* 使两个面板均匀分配空间 */
margin-left: 120px;
}
.transfer-custom .el-transfer {
display: flex;
align-items: stretch; /* 确保两个面板高度相同 */
}
</style>
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 J.のblog!
评论