Files
backmanagerweb/src/components/user.vue
2026-06-22 21:36:22 +08:00

217 lines
7.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="page-container">
<!-- 搜索栏 -->
<div class="search-bar">
<el-input v-model="search.username" placeholder="用户名" clearable style="width: 200px" @keyup.enter="handleSearch" />
<el-select v-model="search.role" placeholder="角色" clearable style="width: 130px">
<el-option label="管理员" value="admin" />
<el-option label="普通用户" value="user" />
</el-select>
<el-select v-model="search.status" placeholder="状态" clearable style="width: 130px">
<el-option label="启用" :value="1" />
<el-option label="禁用" :value="0" />
</el-select>
<el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button>
<el-button @click="resetSearch">重置</el-button>
<el-button color="#E60012" @click="openAdd">新增用户</el-button>
</div>
<!-- 表格 -->
<el-table :data="tableData" border v-loading="loading" stripe>
<el-table-column prop="id" label="ID" width="60" />
<el-table-column prop="username" label="用户名" width="120" />
<el-table-column prop="real_name" label="真实姓名" width="120" />
<el-table-column prop="role" label="角色" width="100">
<template #default="{ row }">
<el-tag :type="row.role === 'admin' ? 'danger' : 'info'">
{{ row.role === 'admin' ? '管理员' : '普通用户' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="80">
<template #default="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'danger'">{{ row.status === 1 ? '启用' : '禁用' }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="created_at" label="创建时间" width="170">
<template #default="{ row }">{{ row.created_at?.slice(0, 19)?.replace('T', ' ') || '-' }}</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<el-button link type="primary" @click="openEdit(row)">编辑</el-button>
<el-button link type="warning" @click="resetPwd(row.id)">重置密码</el-button>
<el-button link type="danger" @click="handleDelete(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination-bar">
<el-pagination
v-model:current-page="pagination.page"
v-model:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next, jumper"
@size-change="fetchList"
@current-change="fetchList"
/>
</div>
<!-- 新增/编辑弹窗 -->
<el-dialog v-model="dialogVisible" :title="isEdit ? '编辑用户' : '新增用户'" width="500px" destroy-on-close>
<el-form ref="formRef" :model="form" :rules="rules" label-width="90px" label-position="top">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" placeholder="3-50个字符" :disabled="isEdit" />
</el-form-item>
<el-form-item v-if="!isEdit" label="密码" prop="password">
<el-input v-model="form.password" type="password" show-password placeholder="至少6位" />
</el-form-item>
<el-form-item label="真实姓名">
<el-input v-model="form.real_name" placeholder="真实姓名" />
</el-form-item>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="角色">
<el-select v-model="form.role" style="width:100%">
<el-option label="管理员" value="admin" />
<el-option label="普通用户" value="user" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-select v-model="form.status" style="width:100%">
<el-option label="启用" :value="1" />
<el-option label="禁用" :value="0" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">确定</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import {ref, reactive, onMounted} from 'vue'
import {Search} from '@element-plus/icons-vue'
import {ElMessage, ElMessageBox} from 'element-plus'
import {getUserList, createUser, updateUser, deleteUser} from '../api/user'
const search = reactive({username: '', role: '', status: ''})
const loading = ref(false)
const tableData = ref([])
const pagination = reactive({page: 1, pageSize: 10, total: 0})
const dialogVisible = ref(false)
const isEdit = ref(false)
const editId = ref(null)
const submitLoading = ref(false)
const formRef = ref(null)
const form = reactive({
username: '', password: '', real_name: '', role: 'user', status: 1,
})
const rules = {
username: [{required: true, message: '请输入用户名', trigger: 'blur'}, {min: 3, max: 50, message: '3-50个字符', trigger: 'blur'}],
password: [{required: true, message: '请输入密码', trigger: 'blur'}, {min: 6, message: '至少6位', trigger: 'blur'}],
}
const fetchList = async () => {
loading.value = true
try {
const params = {page: pagination.page, pageSize: pagination.pageSize, ...search}
Object.keys(params).forEach(k => { if (params[k] === '' || params[k] === null) delete params[k] })
const res = await getUserList(params)
tableData.value = res.data.list
pagination.total = res.data.total
} catch {} finally { loading.value = false }
}
const handleSearch = () => { pagination.page = 1; fetchList() }
const resetSearch = () => {
Object.assign(search, {username: '', role: '', status: ''})
handleSearch()
}
const openAdd = () => {
isEdit.value = false
editId.value = null
Object.assign(form, {username: '', password: '', real_name: '', role: 'user', status: 1})
dialogVisible.value = true
}
const openEdit = (row) => {
isEdit.value = true
editId.value = row.id
Object.assign(form, {
username: row.username, password: '', real_name: row.real_name || '',
role: row.role, status: row.status,
})
dialogVisible.value = true
}
const handleSubmit = async () => {
if (!formRef.value) return
await formRef.value.validate()
submitLoading.value = true
try {
if (isEdit.value) {
const payload = {real_name: form.real_name, role: form.role, status: form.status}
await updateUser(editId.value, payload)
ElMessage.success('更新成功')
} else {
await createUser({username: form.username, password: form.password, real_name: form.real_name, role: form.role, status: form.status})
ElMessage.success('新增成功')
}
dialogVisible.value = false
fetchList()
} catch {} finally { submitLoading.value = false }
}
const resetPwd = async (id) => {
try {
await ElMessageBox.confirm('将密码重置为 123456确定', '重置密码', {type: 'warning'})
await updateUser(id, {password: '123456'})
ElMessage.success('密码已重置为 123456')
} catch {}
}
const handleDelete = async (id) => {
try {
await ElMessageBox.confirm('确定删除该用户?', '提示', {type: 'warning'})
await deleteUser(id)
ElMessage.success('删除成功')
fetchList()
} catch {}
}
onMounted(() => { fetchList() })
</script>
<style scoped>
.page-container {
background: #fff;
padding: 20px;
border-radius: 8px;
}
.search-bar {
display: flex;
gap: 10px;
margin-bottom: 16px;
flex-wrap: wrap;
align-items: center;
}
.pagination-bar {
margin-top: 16px;
display: flex;
justify-content: flex-end;
}
</style>