feat(admin): 实现用户管理列表及新增用户功能

- 新增用户列表页面,实现分页查询和条件筛选
- 增加新增用户弹窗表单,支持姓名、手机号及密码录入和校验
- 后端新增 AdminController 提供用户列表查询和创建接口
- 完善 UserService 和 RoleService,支持分页用户数据获取及用户角色映射
- 丰富数据库 Mapper 增加用户及用户角色相关查询插入操作
- 定时任务 UserRoleTask 调整调用角色服务更新权限缓存
- 前端接口封装新建用户相关请求便于调用
- 使用密码加密存储新建用户密码保障安全
This commit is contained in:
lbw
2025-12-24 11:25:27 +08:00
parent 5404f295e4
commit 4135b72648
19 changed files with 424 additions and 90 deletions

View File

@@ -0,0 +1,10 @@
import axios from "@/axios";
export function getUserList(data) {
return axios.post('/admin/user/list', data)
}
export function createUser(data) {
return axios.post('/admin/user/create', data)
}

View File

@@ -6,7 +6,48 @@
</el-header>
<el-main class="p-4">
管理学生
<el-card>
<div class="flex items-center mb-4">
<el-input v-model="query.name" placeholder="姓名" clearable style="max-width:220px" />
<el-button type="primary" class="ml-2" @click="fetchList">查询</el-button>
<el-button class="ml-2" @click="resetSearch">重置</el-button>
<el-button type="success" class="ml-2" @click="openCreate">新增用户</el-button>
</div>
<el-table :data="list" v-loading="loading" border stripe>
<el-table-column prop="name" label="姓名" />
<el-table-column prop="phone" label="手机号" />
<el-table-column prop="roleName" label="角色" />
</el-table>
<div class="mt-4 flex justify-end">
<el-pagination
background
:current-page="page"
:page-size="pageSize"
:total="totalCount"
layout="prev, pager, next, sizes, total"
@current-change="onPageChange"
@size-change="onSizeChange"
/>
</div>
</el-card>
<el-dialog v-model="createVisible" title="新增用户" width="420px">
<el-form :model="createForm" :rules="rules" ref="createFormRef" label-width="80px">
<el-form-item label="姓名" prop="name">
<el-input v-model="createForm.name" />
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="createForm.phone" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="createForm.password" type="password" show-password />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="createVisible=false">取消</el-button>
<el-button type="primary" :loading="createLoading" @click="submitCreate">提交</el-button>
</template>
</el-dialog>
</el-main>
</el-container>
@@ -15,5 +56,92 @@
<script setup>
import Header from '@/layouts/components/Header.vue'
import { ref, reactive, onMounted } from 'vue'
import { getUserList, createUser } from '@/api/admin'
import { showMessage } from '@/composables/util.js'
const loading = ref(false)
const list = ref([])
const page = ref(1)
const pageSize = ref(10)
const totalCount = ref(0)
const query = reactive({ name: '' })
async function fetchList() {
try {
loading.value = true
const r = await getUserList({ page: page.value, pageSize: pageSize.value, name: query.name })
const d = r?.data
if (d?.success) {
list.value = d?.data || []
page.value = d?.pageNo || page.value
totalCount.value = d?.totalCount || 0
pageSize.value = d?.pageSize || pageSize.value
} else {
list.value = []
totalCount.value = 0
}
} finally {
loading.value = false
}
}
function resetSearch() {
query.name = ''
page.value = 1
fetchList()
}
function onPageChange(p) {
page.value = p
fetchList()
}
function onSizeChange(s) {
pageSize.value = s
page.value = 1
fetchList()
}
const createVisible = ref(false)
const createForm = reactive({ name: '', phone: '', password: '' })
const createFormRef = ref()
const createLoading = ref(false)
const rules = {
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
phone: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
}
function openCreate() {
createVisible.value = true
}
function submitCreate() {
createFormRef.value?.validate(async (valid) => {
if (!valid) return
createLoading.value = true
try {
const r = await createUser({ name: createForm.name, phone: createForm.phone, password: createForm.password })
const d = r?.data
if (d?.success) {
showMessage('新增成功', 'success')
createVisible.value = false
createForm.name = ''
createForm.phone = ''
createForm.password = ''
fetchList()
} else {
showMessage(d?.message || '新增失败', 'error')
}
} finally {
createLoading.value = false
}
})
}
onMounted(() => {
fetchList()
})
</script>