iFileProxyAdmin/src/views/UserManagement.vue
2024-12-01 00:17:27 +08:00

523 lines
No EOL
13 KiB
Vue

<template>
<div class="user-management">
<el-card class="user-card">
<template #header>
<div class="card-header">
<div class="header-left">
<span class="title">用户列表</span>
<el-tag class="user-count" type="info" effect="plain">
{{ total }}
</el-tag>
</div>
<div class="header-right">
<el-input
v-model="searchQuery"
placeholder="搜索用户..."
class="search-input"
clearable
@clear="handleSearch">
<template #prefix>
<el-icon><Search /></el-icon>
</template>
</el-input>
</div>
</div>
</template>
<el-table
v-loading="loading"
:data="filteredUsers"
style="width: 100%"
:header-cell-style="{ background: '#f5f7fa' }"
border>
<el-table-column prop="username" label="用户名" width="150" />
<el-table-column prop="nickname" label="昵称" width="150" />
<el-table-column prop="lastLoginIP" label="最后登录IP" width="140" />
<el-table-column prop="lastLoginTime" label="最后登录时间" width="180">
<template #default="scope">
{{ formatDateTime(scope.row.lastLoginTime) }}
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="180">
<template #default="scope">
{{ formatDateTime(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column prop="mask" label="权限" width="120">
<template #default="scope">
<el-tag :type="getMaskType(scope.row.mask)">
{{ getMaskLabel(scope.row.mask) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right">
<template #default="scope">
<el-button
link
type="primary"
@click="handleUpdateMask(scope.row)"
:disabled="scope.row.mask === 2">
<el-icon><Edit /></el-icon>修改权限
</el-button>
<el-button
link
type="primary"
@click="handleUpdateNickname(scope.row)"
:disabled="scope.row.mask === 2">
<el-icon><EditPen /></el-icon>修改昵称
</el-button>
<el-button
link
type="warning"
@click="handleResetPassword(scope.row)"
:disabled="scope.row.mask === 2">
<el-icon><Key /></el-icon>重置密码
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handlePageChange"
/>
</div>
</el-card>
<!-- 修改权限对话框 -->
<el-dialog
v-model="maskDialogVisible"
title="修改用户权限"
width="400px">
<el-form :model="maskForm" label-width="80px">
<el-form-item label="权限级别">
<el-select v-model="maskForm.newMask">
<el-option :value="0" label="普通用户" />
<el-option :value="1" label="管理员" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="maskDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitUpdateMask" :loading="updating">
确定
</el-button>
</span>
</template>
</el-dialog>
<!-- 添加重置密码对话框 -->
<el-dialog
v-model="resetPasswordDialogVisible"
title="重置用户密码"
width="400px">
<el-form
ref="resetPasswordFormRef"
:model="resetPasswordForm"
:rules="resetPasswordRules"
label-width="80px">
<el-form-item label="新密码" prop="newPassword">
<el-input
v-model="resetPasswordForm.newPassword"
type="password"
show-password
placeholder="请输入新密码" />
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input
v-model="resetPasswordForm.confirmPassword"
type="password"
show-password
placeholder="请再次输入新密码" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="resetPasswordDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitResetPassword" :loading="updating">
确定
</el-button>
</span>
</template>
</el-dialog>
<!-- 添加修改昵称对话框 -->
<el-dialog
v-model="nicknameDialogVisible"
title="修改用户昵称"
width="400px">
<el-form
ref="nicknameFormRef"
:model="nicknameForm"
:rules="nicknameRules"
label-width="80px">
<el-form-item label="新昵称" prop="newNickname">
<el-input
v-model="nicknameForm.newNickname"
placeholder="请输入新昵称" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="nicknameDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitUpdateNickname" :loading="updating">
确定
</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Search, Edit, EditPen, Key } from '@element-plus/icons-vue'
import { UserAPI } from '../api/user'
const loading = ref(false)
const updating = ref(false)
const total = ref(0)
const currentPage = ref(1)
const pageSize = ref(10)
const users = ref([])
const searchQuery = ref('')
// 权限对话框相关
const maskDialogVisible = ref(false)
const currentUser = ref(null)
const maskForm = ref({
newMask: 0
})
// 重置密码相关
const resetPasswordDialogVisible = ref(false)
const resetPasswordFormRef = ref(null)
const resetPasswordForm = ref({
newPassword: '',
confirmPassword: ''
})
// 修改昵称相关
const nicknameDialogVisible = ref(false)
const nicknameFormRef = ref(null)
const nicknameForm = ref({
newNickname: ''
})
const nicknameRules = {
newNickname: [
{ required: true, message: '请输入新昵称', trigger: 'blur' },
{ min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' }
]
}
const validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入新密码'))
} else {
if (resetPasswordForm.value.confirmPassword !== '') {
resetPasswordFormRef.value.validateField('confirmPassword')
}
callback()
}
}
const validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入新密码'))
} else if (value !== resetPasswordForm.value.newPassword) {
callback(new Error('两次输入密码不一致!'))
} else {
callback()
}
}
const resetPasswordRules = {
newPassword: [
{ validator: validatePass, trigger: 'blur' },
{ min: 6, message: '密码长度不能小于6位', trigger: 'blur' }
],
confirmPassword: [
{ validator: validatePass2, trigger: 'blur' }
]
}
// 过滤用户列表
const filteredUsers = computed(() => {
if (!searchQuery.value) return users.value
const query = searchQuery.value.toLowerCase()
return users.value.filter(user => {
return (
user.username?.toLowerCase().includes(query) ||
user.nickname?.toLowerCase().includes(query) ||
user.lastLoginIP?.includes(query)
)
})
})
// 获取用户列表
const fetchUsers = async () => {
loading.value = true
try {
const response = await UserAPI.getUserList({
page: currentPage.value,
pageSize: pageSize.value
})
if (response.data) {
users.value = response.data.data || []
total.value = response.data.total || 0
}
} catch (error) {
console.error('获取用户列表失败:', error)
} finally {
loading.value = false
}
}
// 处理搜索
const handleSearch = () => {
console.log('Searching for:', searchQuery.value)
}
// 处理页码变化
const handlePageChange = (page) => {
currentPage.value = page
fetchUsers()
}
// 处理每页数量变化
const handleSizeChange = (size) => {
pageSize.value = size
currentPage.value = 1
fetchUsers()
}
// 格式化时间
const formatDateTime = (dateStr) => {
if (!dateStr) return '-'
return new Date(dateStr).toLocaleString()
}
// 获取权限标签类型
const getMaskType = (mask) => {
switch (mask) {
case 2:
return 'danger'
case 1:
return 'warning'
default:
return 'info'
}
}
// 获取权限标签文本
const getMaskLabel = (mask) => {
switch (mask) {
case 2:
return '超级管理员'
case 1:
return '管理员'
default:
return '普通用户'
}
}
// 处理修改权限
const handleUpdateMask = (user) => {
currentUser.value = user
maskForm.value.newMask = user.mask
maskDialogVisible.value = true
}
// 提交权限修改
const submitUpdateMask = async () => {
if (!currentUser.value) return
updating.value = true
try {
const response = await UserAPI.updateUserMask(
currentUser.value.userId,
maskForm.value.newMask
)
if (response.retcode === 0) {
ElMessage.success('权限修改成功')
maskDialogVisible.value = false
fetchUsers()
}
} catch (error) {
console.error('修改权限失败:', error)
} finally {
updating.value = false
}
}
// 处理重置密码
const handleResetPassword = (user) => {
currentUser.value = user
resetPasswordForm.value = {
newPassword: '',
confirmPassword: ''
}
resetPasswordDialogVisible.value = true
}
// 提交重置密码
const submitResetPassword = async () => {
if (!resetPasswordFormRef.value || !currentUser.value) return
await resetPasswordFormRef.value.validate(async (valid) => {
if (valid) {
ElMessageBox.confirm(
`确定要重置用户 ${currentUser.value.nickname}(${currentUser.value.username}) 的密码吗?`,
'警告',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(async () => {
updating.value = true
try {
const response = await UserAPI.resetPassword(
currentUser.value.userId,
resetPasswordForm.value.newPassword
)
if (response.retcode === 0) {
ElMessage.success('密码重置成功')
resetPasswordDialogVisible.value = false
}
} catch (error) {
console.error('重置密码失败:', error)
} finally {
updating.value = false
}
}).catch(() => {
// 用户取消操作
})
}
})
}
// 处理修改昵称
const handleUpdateNickname = (user) => {
currentUser.value = user
nicknameForm.value.newNickname = user.nickname
nicknameDialogVisible.value = true
}
// 提交昵称修改
const submitUpdateNickname = async () => {
if (!nicknameFormRef.value || !currentUser.value) return
await nicknameFormRef.value.validate(async (valid) => {
if (valid) {
ElMessageBox.confirm(
`确定要修改用户 ${currentUser.value.username} 的昵称吗?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'info'
}
).then(async () => {
updating.value = true
try {
const response = await UserAPI.updateUserNickname(
currentUser.value.userId,
nicknameForm.value.newNickname
)
if (response.retcode === 0) {
ElMessage.success('昵称修改成功')
nicknameDialogVisible.value = false
fetchUsers() // 刷新用户列表
}
} catch (error) {
console.error('修改昵称失败:', error)
} finally {
updating.value = false
}
}).catch(() => {
// 用户取消操作
})
}
})
}
// 初始化
onMounted(() => {
fetchUsers()
})
</script>
<style scoped>
.user-management {
padding: 20px;
}
.user-card {
background: #fff;
border-radius: 4px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.header-left {
display: flex;
align-items: center;
}
.title {
font-size: 16px;
font-weight: 500;
margin-right: 12px;
}
.user-count {
font-size: 13px;
}
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
.search-input {
width: 240px;
}
:deep(.el-button) {
display: inline-flex;
align-items: center;
gap: 4px;
}
:deep(.el-table) {
margin-top: 20px;
}
.pagination-container {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
:deep(.el-form-item__label) {
font-weight: 500;
}
</style>