daShangDao_newAdmin/src/views/User/List.vue

445 lines
11 KiB
Vue

<template>
<div class="user-list-container">
<div class="header-actions">
<el-input
v-model="searchKeyword"
placeholder="请输入用户名搜索"
clearable
class="search-input"
@clear="loadUserList"
@keyup.enter="handleSearch"
>
<template #append>
<el-button @click="handleSearch">
<el-icon><Search /></el-icon>
</el-button>
</template>
</el-input>
<el-button type="primary" @click="openUserDialog()">
<el-icon><Plus /></el-icon>新增用户
</el-button>
</div>
<el-table
v-loading="loading"
:data="userList"
border
style="width: 100%"
row-key="id"
>
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="username" label="用户名" />
<el-table-column prop="nickname" label="昵称" />
<el-table-column prop="phone" label="手机号" />
<el-table-column prop="email" label="邮箱" />
<el-table-column prop="createTime" label="创建时间" :formatter="formatDate" />
<el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="openUserDialog(row)">
编辑
</el-button>
<el-button type="danger" link @click="handleDelete(row)">
删除
</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]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
<!-- 用户表单对话框 -->
<el-dialog
v-model="dialogVisible"
:title="isEdit ? '编辑用户' : '新增用户'"
width="500px"
@closed="resetForm"
>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="100px"
class="user-form"
>
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="密码" prop="password" v-if="!isEdit">
<el-input v-model="form.password" type="password" placeholder="请输入密码" show-password />
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword" v-if="!isEdit">
<el-input v-model="form.confirmPassword" type="password" placeholder="请确认密码" show-password />
</el-form-item>
<el-form-item label="昵称" prop="nickname">
<el-input v-model="form.nickname" placeholder="请输入昵称" />
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="form.phone" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="角色" prop="roleId">
<el-select v-model="form.roleId" placeholder="请选择角色">
<el-option
v-for="role in roleList"
:key="role.id"
:label="role.roleName"
:value="role.id"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="submitLoading" @click="submitForm">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Search, Plus } from '@element-plus/icons-vue'
import { userApi } from '@/api'
import { getRoleList } from '@/api/role'
// 表格数据
const userList = ref([])
const loading = ref(false)
const searchKeyword = ref('')
// 分页参数
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(0)
// 对话框相关
const dialogVisible = ref(false)
const isEdit = ref(false)
const submitLoading = ref(false)
const roleList = ref([])
// 表单数据
const form = reactive({
id: null,
username: '',
password: '',
confirmPassword: '',
nickname: '',
phone: '',
email: '',
roleId: null // 角色ID
})
// 表单校验规则
const validatePass = (rule, value, callback) => {
if (!isEdit.value && !value) {
callback(new Error('请输入密码'))
} else {
if (form.confirmPassword !== '') {
formRef.value?.validateField('confirmPassword')
}
callback()
}
}
const validateConfirmPass = (rule, value, callback) => {
if (!isEdit.value && !value) {
callback(new Error('请再次输入密码'))
} else if (value !== form.password) {
callback(new Error('两次输入密码不一致'))
} else {
callback()
}
}
const rules = reactive({
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur' }
],
password: [
{ validator: validatePass, trigger: 'blur' }
],
confirmPassword: [
{ validator: validateConfirmPass, trigger: 'blur' }
],
phone: [
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
],
email: [
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
],
roleId: [
{ required: true, message: '请选择角色', trigger: 'change' }
]
})
// 表单引用
const formRef = ref(null)
// 加载用户列表
const loadUserList = async () => {
try {
loading.value = true
const res = await userApi.getUserList()
if (res.code === 200) {
userList.value = res.data || []
total.value = res.data?.length || 0
// 如果有搜索关键词,进行前端过滤
if (searchKeyword.value) {
userList.value = userList.value.filter(user =>
user.username?.toLowerCase().includes(searchKeyword.value.toLowerCase()) ||
user.nickname?.toLowerCase().includes(searchKeyword.value.toLowerCase())
)
}
} else {
ElMessage.error(res.message || '获取用户列表失败')
}
} catch (error) {
console.error('获取用户列表出错:', error)
ElMessage.error(error.message || '获取用户列表失败')
} finally {
loading.value = false
}
}
// 搜索
const handleSearch = () => {
currentPage.value = 1
loadUserList()
}
// 加载角色列表
const loadRoleList = async () => {
try {
const res = await getRoleList()
console.log(res)
if (res.code === 200) {
roleList.value = res.data || []
} else {
ElMessage.error(res.message || '获取角色列表失败')
}
} catch (error) {
console.error('获取角色列表出错:', error)
ElMessage.error(error.message || '获取角色列表失败')
}
}
// 打开用户对话框
const openUserDialog = (row) => {
resetForm()
if (row) {
// 编辑模式
isEdit.value = true
getUserDetail(row.id)
} else {
// 新增模式
isEdit.value = false
}
dialogVisible.value = true
}
// 获取用户详情
const getUserDetail = async (id) => {
try {
submitLoading.value = true
const res = await userApi.getUserById(id)
if (res.code === 200 && res.data) {
// 填充表单数据
Object.keys(form).forEach(key => {
if (key !== 'password' && key !== 'confirmPassword' && res.data[key] !== undefined) {
form[key] = res.data[key]
}
})
} else {
ElMessage.error(res.message || '获取用户信息失败')
dialogVisible.value = false
}
} catch (error) {
console.error('获取用户信息出错:', error)
ElMessage.error(error.message || '获取用户信息失败')
dialogVisible.value = false
} finally {
submitLoading.value = false
}
}
// 提交表单
const submitForm = async () => {
if (!formRef.value) return
await formRef.value.validate(async (valid) => {
if (valid) {
try {
submitLoading.value = true
// 移除确认密码字段
const submitData = { ...form }
delete submitData.confirmPassword
// 如果是编辑模式且没有设置密码,则移除密码字段
if (isEdit.value && !submitData.password) {
delete submitData.password
}
let res
if (isEdit.value) {
console.log(submitData)
res = await userApi.updateUser(submitData)
} else {
res = await userApi.register(submitData)
}
if (res.code === 200) {
ElMessage.success(`${isEdit.value ? '更新' : '添加'}成功`)
dialogVisible.value = false
loadUserList()
} else {
ElMessage.error(res.message || `${isEdit.value ? '更新' : '添加'}失败`)
}
} catch (error) {
console.error(`${isEdit.value ? '更新' : '添加'}用户出错:`, error)
ElMessage.error(error.message || `${isEdit.value ? '更新' : '添加'}失败`)
} finally {
submitLoading.value = false
}
}
})
}
// 重置表单
const resetForm = () => {
if (formRef.value) {
formRef.value.resetFields()
}
// 重置表单数据
Object.keys(form).forEach(key => {
form[key] = key === 'id' ? null : ''
})
}
// 删除用户
const handleDelete = (row) => {
ElMessageBox.confirm(
`确定要删除用户 "${row.username || row.nickname || row.id}" 吗?`,
'删除确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(async () => {
try {
const res = await userApi.deleteUser(row.id)
if (res.code === 200) {
ElMessage.success('删除成功')
loadUserList()
} else {
ElMessage.error(res.message || '删除失败')
}
} catch (error) {
console.error('删除用户出错:', error)
ElMessage.error(error.message || '删除失败')
}
}).catch(() => {
// 取消删除
})
}
// 分页大小变化
const handleSizeChange = (val) => {
pageSize.value = val
loadUserList()
}
// 页码变化
const handleCurrentChange = (val) => {
currentPage.value = val
loadUserList()
}
// 格式化日期
const formatDate = (row, column) => {
const dateValue = row[column.property]
if (!dateValue) return '-'
try {
const date = new Date(dateValue)
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
})
} catch (e) {
return dateValue
}
}
// 组件挂载时加载数据
onMounted(() => {
loadUserList()
loadRoleList() //
})
</script>
<style scoped>
.user-list-container {
padding: 20px;
}
.header-actions {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.search-input {
width: 300px;
}
.pagination-container {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
.user-form {
margin: 0 20px;
}
:deep(.el-dialog__body) {
padding-top: 10px;
padding-bottom: 10px;
}
</style>