新增用户管理页面
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
<template>
|
||||
<n-config-provider :theme="theme" :theme-overrides="themeOverrides" :locale="zhCN" :date-locale="dateZhCN">
|
||||
<n-message-provider>
|
||||
<router-view />
|
||||
<n-dialog-provider>
|
||||
<router-view />
|
||||
</n-dialog-provider>
|
||||
</n-message-provider>
|
||||
</n-config-provider>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { NConfigProvider, NMessageProvider, darkTheme, zhCN, dateZhCN } from 'naive-ui'
|
||||
import { NConfigProvider, NMessageProvider, NDialogProvider, zhCN, dateZhCN } from 'naive-ui'
|
||||
import { ref } from 'vue'
|
||||
|
||||
// 主题配置,默认使用亮色主题
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import request from '@/utils/request'
|
||||
import type { ApiResponse, LoginResponseData, UserInfo } from '@/types/api'
|
||||
|
||||
export const login = (username: string, password: string) => {
|
||||
export const login = (username: string, password: string): Promise<ApiResponse<LoginResponseData>> => {
|
||||
return request({
|
||||
url: '/api/admin/login',
|
||||
method: 'post',
|
||||
@@ -8,7 +9,7 @@ export const login = (username: string, password: string) => {
|
||||
})
|
||||
}
|
||||
|
||||
export const getCurrentUser = () => {
|
||||
export const getCurrentUser = (): Promise<ApiResponse<UserInfo>> => {
|
||||
return request({
|
||||
url: '/api/admin/me',
|
||||
method: 'get'
|
||||
|
||||
@@ -48,12 +48,14 @@ import { ref, h } from 'vue'
|
||||
import { NLayout, NLayoutSider, NLayoutHeader, NLayoutContent, NLayoutFooter, NMenu, NDropdown } from 'naive-ui'
|
||||
import { RouterLink, useRoute, useRouter } from 'vue-router'
|
||||
import { useAdminStore } from '@/stores/admin'
|
||||
import { RiDashboardLine, RiArrowDownSLine, RiUserLine, RiLogoutBoxRLine } from '@remixicon/vue'
|
||||
import { RiDashboardLine, RiArrowDownSLine, RiUserLine, RiLogoutBoxRLine, RiSettings3Line, RiUserSettingsLine } from '@remixicon/vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const adminStore = useAdminStore()
|
||||
|
||||
console.log('AdminLayout - adminStore.userInfo:', adminStore.userInfo)
|
||||
|
||||
const activeKey = ref(String(route.name))
|
||||
|
||||
const menuOptions = [
|
||||
@@ -61,6 +63,18 @@ const menuOptions = [
|
||||
label: () => h(RouterLink, { to: '/admin/dashboard' }, { default: () => '工作台' }),
|
||||
key: 'AdminDashboard',
|
||||
icon: () => h(RiDashboardLine, { size: '20px' })
|
||||
},
|
||||
{
|
||||
label: '系统管理',
|
||||
key: 'SystemManagement',
|
||||
icon: () => h(RiSettings3Line, { size: '20px' }),
|
||||
children: [
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/admin/user-management' }, { default: () => '用户管理' }),
|
||||
key: 'UserManagement',
|
||||
icon: () => h(RiUserSettingsLine, { size: '20px' })
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -32,12 +32,19 @@ const routes = [
|
||||
{
|
||||
path: '/admin',
|
||||
component: () => import('@/layouts/AdminLayout.vue'),
|
||||
redirect: '/admin/dashboard',
|
||||
children: [
|
||||
{
|
||||
path: 'dashboard',
|
||||
name: 'AdminDashboard',
|
||||
component: () => import('@/views/admin/Dashboard.vue'),
|
||||
meta: { title: '管理控制台', requiresAdminAuth: true }
|
||||
},
|
||||
{
|
||||
path: 'user-management',
|
||||
name: 'UserManagement',
|
||||
component: () => import('@/views/admin/UserManagement.vue'),
|
||||
meta: { title: '用户管理', requiresAdminAuth: true }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { login as loginApi } from '@/api/admin'
|
||||
import type { UserInfo } from '@/types/api'
|
||||
|
||||
export const useAdminStore = defineStore('admin', () => {
|
||||
const token = ref<string | null>(localStorage.getItem('admin_token'))
|
||||
const userInfo = ref<any>(JSON.parse(localStorage.getItem('admin_userInfo') || 'null'))
|
||||
const userInfo = ref<UserInfo | null>(JSON.parse(localStorage.getItem('admin_userInfo') || 'null'))
|
||||
|
||||
const setToken = (newToken: string) => {
|
||||
token.value = newToken
|
||||
localStorage.setItem('admin_token', newToken)
|
||||
}
|
||||
|
||||
const setUserInfo = (info: any) => {
|
||||
const setUserInfo = (info: UserInfo) => {
|
||||
userInfo.value = info
|
||||
localStorage.setItem('admin_userInfo', JSON.stringify(info))
|
||||
}
|
||||
@@ -28,11 +29,14 @@ export const useAdminStore = defineStore('admin', () => {
|
||||
|
||||
const login = async (username: string, password: string) => {
|
||||
try {
|
||||
const response = await loginApi(username, password)
|
||||
const data = response.data
|
||||
const data = await loginApi(username, password)
|
||||
console.log('登录API返回的数据:', data)
|
||||
if (data.success && data.data) {
|
||||
console.log('设置token:', data.data.token)
|
||||
console.log('设置用户信息:', data.data.user)
|
||||
setToken(data.data.token)
|
||||
setUserInfo(data.data.user)
|
||||
console.log('登录后userInfo:', userInfo.value)
|
||||
return { success: true, message: data.message || '登录成功' }
|
||||
}
|
||||
return { success: false, message: data.message || '登录失败' }
|
||||
|
||||
35
frontend/src/types/api.ts
Normal file
35
frontend/src/types/api.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* API响应类型定义
|
||||
*/
|
||||
|
||||
/**
|
||||
* 通用API响应接口
|
||||
*/
|
||||
export interface ApiResponse<T = any> {
|
||||
success: boolean
|
||||
message?: string
|
||||
data?: T
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录响应数据
|
||||
*/
|
||||
export interface LoginResponseData {
|
||||
token: string
|
||||
user: {
|
||||
id: number
|
||||
username: string
|
||||
realName?: string
|
||||
roleId: number
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*/
|
||||
export interface UserInfo {
|
||||
id: number
|
||||
username: string
|
||||
realName?: string
|
||||
roleId: number
|
||||
}
|
||||
326
frontend/src/views/admin/UserManagement.vue
Normal file
326
frontend/src/views/admin/UserManagement.vue
Normal file
@@ -0,0 +1,326 @@
|
||||
<template>
|
||||
<div class="user-management-container">
|
||||
<n-card title="用户管理">
|
||||
<!-- 搜索表单 -->
|
||||
<n-form inline :model="searchForm" label-placement="left" label-width="auto">
|
||||
<n-grid :cols="24" :x-gap="12">
|
||||
<n-gi :span="6">
|
||||
<n-form-item label="用户名">
|
||||
<n-input v-model:value="searchForm.username" placeholder="请输入用户名" clearable />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi :span="6">
|
||||
<n-form-item label="角色组">
|
||||
<n-select
|
||||
v-model:value="searchForm.roleId"
|
||||
placeholder="请选择角色组"
|
||||
:options="roleOptions"
|
||||
clearable
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi :span="6">
|
||||
<n-form-item label="状态">
|
||||
<n-select
|
||||
v-model:value="searchForm.status"
|
||||
placeholder="请选择状态"
|
||||
:options="statusOptions"
|
||||
clearable
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi :span="6">
|
||||
<n-space>
|
||||
<n-button type="primary" @click="handleSearch">查询</n-button>
|
||||
<n-button @click="handleReset">重置</n-button>
|
||||
</n-space>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</n-form>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<n-space class="action-buttons" justify="space-between">
|
||||
<n-space>
|
||||
<n-button type="primary" @click="handleCreate">
|
||||
<template #icon>
|
||||
<RiAddLine />
|
||||
</template>
|
||||
新建用户
|
||||
</n-button>
|
||||
<n-button @click="handleImport">
|
||||
<template #icon>
|
||||
<RiUploadLine />
|
||||
</template>
|
||||
导入
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
|
||||
<!-- 用户列表表格 -->
|
||||
<n-data-table
|
||||
:columns="columns"
|
||||
:data="userList"
|
||||
:loading="loading"
|
||||
:pagination="pagination"
|
||||
:row-key="(row: any) => row.id"
|
||||
class="user-table"
|
||||
/>
|
||||
|
||||
<!-- 新建/编辑用户对话框 -->
|
||||
<UserFormModal
|
||||
v-model:show="showUserFormModal"
|
||||
:user="currentUser"
|
||||
:mode="userFormMode"
|
||||
:roles="roleList"
|
||||
@success="handleUserFormSuccess"
|
||||
/>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, h } from 'vue'
|
||||
import { NCard, NForm, NFormItem, NInput, NSelect, NButton, NSpace, NGrid, NGi, NDataTable, useMessage, useDialog } from 'naive-ui'
|
||||
import { RiAddLine, RiUploadLine, RiEditLine, RiDeleteBinLine, RiLockLine, RiLockUnlockLine } from '@remixicon/vue'
|
||||
import axios from 'axios'
|
||||
import UserFormModal from './components/UserFormModal.vue'
|
||||
|
||||
// 消息提示
|
||||
const message = useMessage()
|
||||
// 对话框
|
||||
const dialog = useDialog()
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
username: '',
|
||||
roleId: null as number | null,
|
||||
status: null as number | null
|
||||
})
|
||||
|
||||
// 角色选项
|
||||
const roleOptions = ref<any[]>([])
|
||||
// 状态选项
|
||||
const statusOptions = [
|
||||
{ label: '启用', value: 1 },
|
||||
{ label: '禁用', value: 0 }
|
||||
]
|
||||
|
||||
// 用户列表
|
||||
const userList = ref<any[]>([])
|
||||
// 角色列表
|
||||
const roleList = ref<any[]>([])
|
||||
// 加载状态
|
||||
const loading = ref(false)
|
||||
|
||||
// 分页配置
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
showSizePicker: true,
|
||||
pageSizes: [10, 20, 30, 50],
|
||||
onChange: (page: number) => {
|
||||
pagination.page = page
|
||||
fetchUserList()
|
||||
},
|
||||
onUpdatePageSize: (pageSize: number) => {
|
||||
pagination.pageSize = pageSize
|
||||
pagination.page = 1
|
||||
fetchUserList()
|
||||
},
|
||||
itemCount: 0
|
||||
})
|
||||
|
||||
// 表格列定义
|
||||
const columns = [
|
||||
{ title: 'ID', key: 'id', width: 80 },
|
||||
{ title: '用户名', key: 'username', width: 150 },
|
||||
{ title: '角色组', key: 'roleName', width: 150 },
|
||||
{
|
||||
title: '用户状态',
|
||||
key: 'status',
|
||||
width: 100,
|
||||
render: (row: any) => {
|
||||
return h('span', {
|
||||
style: {
|
||||
color: row.status === 1 ? '#18a058' : '#d03050'
|
||||
}
|
||||
}, row.status === 1 ? '启用' : '禁用')
|
||||
}
|
||||
},
|
||||
{ title: '创建时间', key: 'createdAt', width: 180 },
|
||||
{ title: '更新时间', key: 'updatedAt', width: 180 },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
width: 150,
|
||||
fixed: 'right' as const,
|
||||
render: (row: any) => {
|
||||
return h(NSpace, { size: 'small' }, () => [
|
||||
h(NButton, {
|
||||
size: 'small',
|
||||
type: 'primary',
|
||||
onClick: () => handleEdit(row)
|
||||
}, { icon: () => h(RiEditLine) }),
|
||||
h(NButton, {
|
||||
size: 'small',
|
||||
type: row.status === 1 ? 'warning' : 'success',
|
||||
onClick: () => handleToggleStatus(row)
|
||||
}, { icon: () => row.status === 1 ? h(RiLockLine) : h(RiLockUnlockLine) }),
|
||||
h(NButton, {
|
||||
size: 'small',
|
||||
type: 'error',
|
||||
onClick: () => handleDelete(row)
|
||||
}, { icon: () => h(RiDeleteBinLine) })
|
||||
])
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
// 用户表单对话框
|
||||
const showUserFormModal = ref(false)
|
||||
const userFormMode = ref<'create' | 'edit'>('create')
|
||||
const currentUser = ref<any>(null)
|
||||
|
||||
// 获取用户列表
|
||||
const fetchUserList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const response = await axios.get('/api/admin/users', {
|
||||
params: {
|
||||
username: searchForm.username || undefined,
|
||||
roleId: searchForm.roleId || undefined,
|
||||
status: searchForm.status !== null ? searchForm.status : undefined,
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize
|
||||
}
|
||||
})
|
||||
|
||||
if (response.data.success) {
|
||||
userList.value = response.data.data.list
|
||||
pagination.itemCount = response.data.data.total
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('获取用户列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取角色列表
|
||||
const fetchRoleList = async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/admin/roles/list')
|
||||
if (response.data.success) {
|
||||
roleList.value = response.data.data
|
||||
roleOptions.value = response.data.data.map((role: any) => ({
|
||||
label: role.roleName,
|
||||
value: role.id
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('获取角色列表失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
pagination.page = 1
|
||||
fetchUserList()
|
||||
}
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
searchForm.username = ''
|
||||
searchForm.roleId = null
|
||||
searchForm.status = null
|
||||
pagination.page = 1
|
||||
fetchUserList()
|
||||
}
|
||||
|
||||
// 新建用户
|
||||
const handleCreate = () => {
|
||||
userFormMode.value = 'create'
|
||||
currentUser.value = null
|
||||
showUserFormModal.value = true
|
||||
}
|
||||
|
||||
// 编辑用户
|
||||
const handleEdit = (row: any) => {
|
||||
userFormMode.value = 'edit'
|
||||
currentUser.value = { ...row }
|
||||
showUserFormModal.value = true
|
||||
}
|
||||
|
||||
// 切换用户状态
|
||||
const handleToggleStatus = (row: any) => {
|
||||
const newStatus = row.status === 1 ? 0 : 1
|
||||
dialog.warning({
|
||||
title: '确认操作',
|
||||
content: `确定要${newStatus === 1 ? '启用' : '禁用'}用户 "${row.username}" 吗?`,
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: async () => {
|
||||
try {
|
||||
await axios.put(`/api/admin/users/${row.id}`, {
|
||||
roleId: row.roleId,
|
||||
status: newStatus
|
||||
})
|
||||
message.success(`${newStatus === 1 ? '启用' : '禁用'}成功`)
|
||||
fetchUserList()
|
||||
} catch (error: any) {
|
||||
message.error(error.response?.data?.message || '操作失败')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
const handleDelete = (row: any) => {
|
||||
dialog.warning({
|
||||
title: '确认删除',
|
||||
content: `确定要删除用户 "${row.username}" 吗?此操作不可恢复。`,
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: async () => {
|
||||
try {
|
||||
await axios.delete(`/api/admin/users/${row.id}`)
|
||||
message.success('删除成功')
|
||||
fetchUserList()
|
||||
} catch (error: any) {
|
||||
message.error(error.response?.data?.message || '删除失败')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 导入(预留)
|
||||
const handleImport = () => {
|
||||
message.info('导入功能开发中')
|
||||
}
|
||||
|
||||
// 用户表单成功回调
|
||||
const handleUserFormSuccess = () => {
|
||||
showUserFormModal.value = false
|
||||
fetchUserList()
|
||||
}
|
||||
|
||||
// 页面加载时获取数据
|
||||
onMounted(() => {
|
||||
fetchRoleList()
|
||||
fetchUserList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.user-management-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.user-table {
|
||||
margin-top: 16px;
|
||||
}
|
||||
</style>
|
||||
199
frontend/src/views/admin/components/UserFormModal.vue
Normal file
199
frontend/src/views/admin/components/UserFormModal.vue
Normal file
@@ -0,0 +1,199 @@
|
||||
<template>
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
preset="card"
|
||||
:title="mode === 'create' ? '新建用户' : '编辑用户'"
|
||||
:style="{ width: '600px' }"
|
||||
:mask-closable="false"
|
||||
@after-leave="handleAfterLeave"
|
||||
>
|
||||
<n-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-placement="left"
|
||||
label-width="100px"
|
||||
require-mark-placement="right-hanging"
|
||||
>
|
||||
<n-form-item label="用户名" path="username">
|
||||
<n-input
|
||||
v-model:value="formData.username"
|
||||
placeholder="请输入用户名"
|
||||
:disabled="mode === 'edit'"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="密码" path="password">
|
||||
<n-input-group>
|
||||
<n-input
|
||||
v-model:value="formData.password"
|
||||
type="password"
|
||||
show-password-on="click"
|
||||
placeholder="请输入密码"
|
||||
/>
|
||||
<n-button type="primary" @click="generateRandomPassword">
|
||||
生成随机密码
|
||||
</n-button>
|
||||
</n-input-group>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="角色组" path="roleId">
|
||||
<n-select
|
||||
v-model:value="formData.roleId"
|
||||
placeholder="请选择角色组"
|
||||
:options="roleOptions"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
||||
<template #footer>
|
||||
<n-space justify="end">
|
||||
<n-button @click="handleCancel">取消</n-button>
|
||||
<n-button type="primary" :loading="loading" @click="handleSubmit">
|
||||
确定
|
||||
</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch, computed } from 'vue'
|
||||
import { NModal, NForm, NFormItem, NInput, NInputGroup, NSelect, NButton, NSpace, useMessage, type FormInst, type FormRules } from 'naive-ui'
|
||||
import axios from 'axios'
|
||||
|
||||
// 定义props
|
||||
interface Props {
|
||||
show: boolean
|
||||
user: any
|
||||
mode: 'create' | 'edit'
|
||||
roles: any[]
|
||||
}
|
||||
|
||||
// 定义emits
|
||||
interface Emits {
|
||||
(e: 'update:show', value: boolean): void
|
||||
(e: 'success'): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// 消息提示
|
||||
const message = useMessage()
|
||||
|
||||
// 表单引用
|
||||
const formRef = ref<FormInst | null>(null)
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(false)
|
||||
|
||||
// 对话框显示状态
|
||||
const showModal = computed({
|
||||
get: () => props.show,
|
||||
set: (value) => emit('update:show', value)
|
||||
})
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
username: '',
|
||||
password: '',
|
||||
roleId: null as number | null
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
const formRules: FormRules = {
|
||||
username: [
|
||||
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
||||
{ min: 3, max: 20, message: '用户名长度应为3-20个字符', trigger: 'blur' },
|
||||
{ pattern: /^[a-zA-Z0-9_]+$/, message: '用户名只能包含字母、数字和下划线', trigger: 'blur' }
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||
{ min: 6, max: 20, message: '密码长度应为6-20个字符', trigger: 'blur' }
|
||||
],
|
||||
roleId: [
|
||||
{ required: true, message: '请选择角色组', trigger: 'change', type: 'number' }
|
||||
]
|
||||
}
|
||||
|
||||
// 角色选项
|
||||
const roleOptions = computed(() => {
|
||||
return props.roles.map(role => ({
|
||||
label: role.roleName,
|
||||
value: role.id
|
||||
}))
|
||||
})
|
||||
|
||||
// 监听用户数据变化
|
||||
watch(() => props.user, (newUser) => {
|
||||
if (newUser) {
|
||||
formData.username = newUser.username || ''
|
||||
formData.password = ''
|
||||
formData.roleId = newUser.roleId || null
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
// 生成随机密码
|
||||
const generateRandomPassword = () => {
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*'
|
||||
let password = ''
|
||||
for (let i = 0; i < 12; i++) {
|
||||
password += chars.charAt(Math.floor(Math.random() * chars.length))
|
||||
}
|
||||
formData.password = password
|
||||
message.success('随机密码已生成')
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
await formRef.value?.validate()
|
||||
|
||||
loading.value = true
|
||||
|
||||
if (props.mode === 'create') {
|
||||
// 创建用户
|
||||
await axios.post('/api/admin/users', {
|
||||
username: formData.username,
|
||||
password: formData.password,
|
||||
roleId: formData.roleId
|
||||
})
|
||||
message.success('创建用户成功')
|
||||
} else {
|
||||
// 编辑用户
|
||||
await axios.put(`/api/admin/users/${props.user.id}`, {
|
||||
password: formData.password,
|
||||
roleId: formData.roleId
|
||||
})
|
||||
message.success('更新用户成功')
|
||||
}
|
||||
|
||||
emit('success')
|
||||
} catch (error: any) {
|
||||
if (error.errors) {
|
||||
// 表单验证错误
|
||||
return
|
||||
}
|
||||
message.error(error.response?.data?.message || '操作失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
showModal.value = false
|
||||
}
|
||||
|
||||
// 对话框关闭后重置表单
|
||||
const handleAfterLeave = () => {
|
||||
formData.username = ''
|
||||
formData.password = ''
|
||||
formData.roleId = null
|
||||
formRef.value?.restoreValidation()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
Reference in New Issue
Block a user