feat(user): 集成 NovaDialog 组件到用户管理页面
- 替换所有原生 n-modal 为自定义 NovaDialog 组件 - 统一用户表单、角色分配、重置密码、头像查看和导入功能的弹框交互 - 使用 novaOpen/novaClose 方法控制所有弹框显示状态 - 保持原有功能和用户体验不变 - 与角色管理页面保持一致的弹框风格 - 提升整体页面的一致性和可维护性
This commit is contained in:
parent
7577077c26
commit
ebffbd78bc
@ -2,6 +2,7 @@
|
|||||||
import { h, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
import { h, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||||
import type { DataTableColumns, FormInst } from 'naive-ui'
|
import type { DataTableColumns, FormInst } from 'naive-ui'
|
||||||
import { NButton, NCheckbox, NDropdown, NIcon, NPopconfirm, NProgress, NSpace, NSwitch, NTag, NUpload, NUploadDragger } from 'naive-ui'
|
import { NButton, NCheckbox, NDropdown, NIcon, NPopconfirm, NProgress, NSpace, NSwitch, NTag, NUpload, NUploadDragger } from 'naive-ui'
|
||||||
|
import NovaDialog from '@/components/common/NovaDialog.vue'
|
||||||
import {
|
import {
|
||||||
addUser,
|
addUser,
|
||||||
batchDeleteUsers,
|
batchDeleteUsers,
|
||||||
@ -29,7 +30,6 @@ import { coiMsgBox, coiMsgError, coiMsgInfo, coiMsgSuccess, coiMsgWarning } from
|
|||||||
// 响应式数据
|
// 响应式数据
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const tableData = ref<UserVo[]>([])
|
const tableData = ref<UserVo[]>([])
|
||||||
const showModal = ref(false)
|
|
||||||
const modalTitle = ref('新增用户')
|
const modalTitle = ref('新增用户')
|
||||||
const formRef = ref<FormInst | null>(null)
|
const formRef = ref<FormInst | null>(null)
|
||||||
const searchFormRef = ref<FormInst | null>(null)
|
const searchFormRef = ref<FormInst | null>(null)
|
||||||
@ -38,8 +38,14 @@ const currentUser = ref<UserVo | null>(null)
|
|||||||
const selectedRows = ref<UserVo[]>([])
|
const selectedRows = ref<UserVo[]>([])
|
||||||
const roleOptions = ref<RoleVo[]>([])
|
const roleOptions = ref<RoleVo[]>([])
|
||||||
|
|
||||||
|
// 弹框引用
|
||||||
|
const userDialogRef = ref()
|
||||||
|
const roleDialogRef = ref()
|
||||||
|
const resetPwdDialogRef = ref()
|
||||||
|
const avatarDialogRef = ref()
|
||||||
|
const importDialogRef = ref()
|
||||||
|
|
||||||
// 角色分配相关
|
// 角色分配相关
|
||||||
const showRoleModal = ref(false)
|
|
||||||
const roleModalTitle = ref('分配角色')
|
const roleModalTitle = ref('分配角色')
|
||||||
const currentAssignUser = ref<UserVo | null>(null)
|
const currentAssignUser = ref<UserVo | null>(null)
|
||||||
const availableRoles = ref<{ label: string, value: number }[]>([])
|
const availableRoles = ref<{ label: string, value: number }[]>([])
|
||||||
@ -47,7 +53,6 @@ const selectedRoleIds = ref<number[]>([])
|
|||||||
const roleLoading = ref(false)
|
const roleLoading = ref(false)
|
||||||
|
|
||||||
// 重置密码相关
|
// 重置密码相关
|
||||||
const showResetPwdModal = ref(false)
|
|
||||||
const resetPwdFormRef = ref<FormInst | null>(null)
|
const resetPwdFormRef = ref<FormInst | null>(null)
|
||||||
const currentResetUser = ref<UserVo | null>(null)
|
const currentResetUser = ref<UserVo | null>(null)
|
||||||
const resetPwdForm = ref({
|
const resetPwdForm = ref({
|
||||||
@ -56,12 +61,10 @@ const resetPwdForm = ref({
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 头像查看相关
|
// 头像查看相关
|
||||||
const showAvatarModal = ref(false)
|
|
||||||
const currentAvatar = ref('')
|
const currentAvatar = ref('')
|
||||||
const currentAvatarUser = ref<UserVo | null>(null)
|
const currentAvatarUser = ref<UserVo | null>(null)
|
||||||
|
|
||||||
// 导入相关
|
// 导入相关
|
||||||
const showImportModal = ref(false)
|
|
||||||
const importLoading = ref(false)
|
const importLoading = ref(false)
|
||||||
const selectedFile = ref<File | null>(null)
|
const selectedFile = ref<File | null>(null)
|
||||||
const updateSupport = ref(false)
|
const updateSupport = ref(false)
|
||||||
@ -488,7 +491,7 @@ function handleAdd() {
|
|||||||
remark: '',
|
remark: '',
|
||||||
roleIds: [],
|
roleIds: [],
|
||||||
}
|
}
|
||||||
showModal.value = true
|
userDialogRef.value?.novaOpen()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 编辑用户
|
// 编辑用户
|
||||||
@ -509,7 +512,7 @@ function handleEdit(user: UserVo) {
|
|||||||
remark: user.remark || '',
|
remark: user.remark || '',
|
||||||
roleIds: user.roleIds || [],
|
roleIds: user.roleIds || [],
|
||||||
}
|
}
|
||||||
showModal.value = true
|
userDialogRef.value?.novaOpen()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除用户
|
// 删除用户
|
||||||
@ -595,7 +598,7 @@ function handleResetPassword(user: UserVo) {
|
|||||||
newPassword: '',
|
newPassword: '',
|
||||||
confirmPassword: '',
|
confirmPassword: '',
|
||||||
}
|
}
|
||||||
showResetPwdModal.value = true
|
resetPwdDialogRef.value?.novaOpen()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行重置密码
|
// 执行重置密码
|
||||||
@ -619,7 +622,7 @@ async function handleConfirmResetPassword() {
|
|||||||
const { isSuccess } = await resetUserPassword(currentResetUser.value.userId, resetPwdForm.value.newPassword)
|
const { isSuccess } = await resetUserPassword(currentResetUser.value.userId, resetPwdForm.value.newPassword)
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
coiMsgSuccess(`用户「${currentResetUser.value.userName}」密码重置成功`)
|
coiMsgSuccess(`用户「${currentResetUser.value.userName}」密码重置成功`)
|
||||||
showResetPwdModal.value = false
|
resetPwdDialogRef.value?.novaClose()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
coiMsgError('重置密码失败,请稍后重试')
|
coiMsgError('重置密码失败,请稍后重试')
|
||||||
@ -633,7 +636,7 @@ async function handleConfirmResetPassword() {
|
|||||||
|
|
||||||
// 取消重置密码
|
// 取消重置密码
|
||||||
function handleCancelResetPassword() {
|
function handleCancelResetPassword() {
|
||||||
showResetPwdModal.value = false
|
resetPwdDialogRef.value?.novaClose()
|
||||||
resetPwdForm.value = {
|
resetPwdForm.value = {
|
||||||
newPassword: '',
|
newPassword: '',
|
||||||
confirmPassword: '',
|
confirmPassword: '',
|
||||||
@ -679,12 +682,12 @@ function handleViewAvatar(user: UserVo) {
|
|||||||
currentAvatar.value = blobUrl
|
currentAvatar.value = blobUrl
|
||||||
createdBlobUrls.value.push(blobUrl)
|
createdBlobUrls.value.push(blobUrl)
|
||||||
}
|
}
|
||||||
showAvatarModal.value = true
|
avatarDialogRef.value?.novaOpen()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭头像查看
|
// 关闭头像查看
|
||||||
function handleCloseAvatar() {
|
function handleCloseAvatar() {
|
||||||
showAvatarModal.value = false
|
avatarDialogRef.value?.novaClose()
|
||||||
// 如果是生成的默认头像,释放URL
|
// 如果是生成的默认头像,释放URL
|
||||||
if (currentAvatar.value.startsWith('blob:')) {
|
if (currentAvatar.value.startsWith('blob:')) {
|
||||||
URL.revokeObjectURL(currentAvatar.value)
|
URL.revokeObjectURL(currentAvatar.value)
|
||||||
@ -826,7 +829,7 @@ function handleImport() {
|
|||||||
selectedFile.value = null
|
selectedFile.value = null
|
||||||
updateSupport.value = false
|
updateSupport.value = false
|
||||||
uploadProgress.value = 0
|
uploadProgress.value = 0
|
||||||
showImportModal.value = true
|
importDialogRef.value?.novaOpen()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 文件选择处理
|
// 文件选择处理
|
||||||
@ -891,7 +894,7 @@ async function handleConfirmImport() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// 关闭模态框并刷新列表
|
// 关闭模态框并刷新列表
|
||||||
showImportModal.value = false
|
importDialogRef.value?.novaClose()
|
||||||
await getUserList()
|
await getUserList()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -916,7 +919,7 @@ async function handleConfirmImport() {
|
|||||||
|
|
||||||
// 取消导入
|
// 取消导入
|
||||||
function handleCancelImport() {
|
function handleCancelImport() {
|
||||||
showImportModal.value = false
|
importDialogRef.value?.novaClose()
|
||||||
selectedFile.value = null
|
selectedFile.value = null
|
||||||
updateSupport.value = false
|
updateSupport.value = false
|
||||||
uploadProgress.value = 0
|
uploadProgress.value = 0
|
||||||
@ -954,7 +957,7 @@ async function handleAssignRole(user: UserVo) {
|
|||||||
|
|
||||||
// 预选用户当前角色(使用后端返回的用户角色ID)
|
// 预选用户当前角色(使用后端返回的用户角色ID)
|
||||||
selectedRoleIds.value = userRoleIds
|
selectedRoleIds.value = userRoleIds
|
||||||
showRoleModal.value = true
|
roleDialogRef.value?.novaOpen()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
coiMsgInfo('当前系统没有可分配的角色')
|
coiMsgInfo('当前系统没有可分配的角色')
|
||||||
@ -992,7 +995,7 @@ async function handleConfirmAssignRole() {
|
|||||||
|
|
||||||
if (response.isSuccess) {
|
if (response.isSuccess) {
|
||||||
coiMsgSuccess('角色分配成功')
|
coiMsgSuccess('角色分配成功')
|
||||||
showRoleModal.value = false
|
roleDialogRef.value?.novaClose()
|
||||||
|
|
||||||
// 更新当前用户的角色信息
|
// 更新当前用户的角色信息
|
||||||
if (currentAssignUser.value) {
|
if (currentAssignUser.value) {
|
||||||
@ -1016,7 +1019,7 @@ async function handleConfirmAssignRole() {
|
|||||||
|
|
||||||
// 取消分配角色
|
// 取消分配角色
|
||||||
function handleCancelAssignRole() {
|
function handleCancelAssignRole() {
|
||||||
showRoleModal.value = false
|
roleDialogRef.value?.novaClose()
|
||||||
currentAssignUser.value = null
|
currentAssignUser.value = null
|
||||||
selectedRoleIds.value = []
|
selectedRoleIds.value = []
|
||||||
availableRoles.value = []
|
availableRoles.value = []
|
||||||
@ -1059,7 +1062,7 @@ async function handleSubmit() {
|
|||||||
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
coiMsgSuccess(isEdit.value ? '用户信息更新成功' : '用户创建成功')
|
coiMsgSuccess(isEdit.value ? '用户信息更新成功' : '用户创建成功')
|
||||||
showModal.value = false
|
userDialogRef.value?.novaClose()
|
||||||
await getUserList()
|
await getUserList()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1074,7 +1077,7 @@ async function handleSubmit() {
|
|||||||
|
|
||||||
// 取消操作
|
// 取消操作
|
||||||
function handleCancel() {
|
function handleCancel() {
|
||||||
showModal.value = false
|
userDialogRef.value?.novaClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 组件挂载时获取数据
|
// 组件挂载时获取数据
|
||||||
@ -1339,15 +1342,19 @@ onBeforeUnmount(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 用户表单模态框 -->
|
<!-- 用户表单弹框 -->
|
||||||
<n-modal
|
<NovaDialog
|
||||||
v-model:show="showModal"
|
ref="userDialogRef"
|
||||||
:title="modalTitle"
|
:title="modalTitle"
|
||||||
preset="card"
|
:width="800"
|
||||||
:style="{ width: '800px' }"
|
height="auto"
|
||||||
:mask-closable="false"
|
confirm-text="确定"
|
||||||
class="user-modal"
|
cancel-text="取消"
|
||||||
|
@nova-confirm="handleSubmit"
|
||||||
|
@nova-cancel="handleCancel"
|
||||||
>
|
>
|
||||||
|
<template #content>
|
||||||
|
<div class="px-3 py-2">
|
||||||
<n-form
|
<n-form
|
||||||
ref="formRef"
|
ref="formRef"
|
||||||
:model="formData"
|
:model="formData"
|
||||||
@ -1470,29 +1477,23 @@ onBeforeUnmount(() => {
|
|||||||
/>
|
/>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
</n-form>
|
</n-form>
|
||||||
|
|
||||||
<template #footer>
|
|
||||||
<div class="flex justify-end gap-3">
|
|
||||||
<NButton @click="handleCancel">
|
|
||||||
取消
|
|
||||||
</NButton>
|
|
||||||
<NButton type="primary" @click="handleSubmit">
|
|
||||||
确定
|
|
||||||
</NButton>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</n-modal>
|
</NovaDialog>
|
||||||
|
|
||||||
<!-- 角色分配模态框 -->
|
<!-- 角色分配弹框 -->
|
||||||
<n-modal
|
<NovaDialog
|
||||||
v-model:show="showRoleModal"
|
ref="roleDialogRef"
|
||||||
:title="roleModalTitle"
|
:title="roleModalTitle"
|
||||||
preset="card"
|
:width="600"
|
||||||
:style="{ width: '600px' }"
|
height="auto"
|
||||||
:mask-closable="false"
|
confirm-text="确定"
|
||||||
class="role-assign-modal"
|
cancel-text="取消"
|
||||||
|
@nova-confirm="handleConfirmAssignRole"
|
||||||
|
@nova-cancel="handleCancelAssignRole"
|
||||||
>
|
>
|
||||||
<div class="space-y-4">
|
<template #content>
|
||||||
|
<div class="p-3 space-y-4">
|
||||||
<div class="bg-gray-50 p-4 rounded-lg">
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<div class="w-10 h-10 rounded-full bg-gradient-to-r from-blue-400 to-purple-500 flex items-center justify-center text-white text-sm font-bold">
|
<div class="w-10 h-10 rounded-full bg-gradient-to-r from-blue-400 to-purple-500 flex items-center justify-center text-white text-sm font-bold">
|
||||||
@ -1537,37 +1538,22 @@ onBeforeUnmount(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
|
||||||
<div class="flex justify-end gap-3">
|
|
||||||
<NButton
|
|
||||||
:disabled="roleLoading"
|
|
||||||
@click="handleCancelAssignRole"
|
|
||||||
>
|
|
||||||
取消
|
|
||||||
</NButton>
|
|
||||||
<NButton
|
|
||||||
type="primary"
|
|
||||||
:loading="roleLoading"
|
|
||||||
:disabled="availableRoles.length === 0"
|
|
||||||
@click="handleConfirmAssignRole"
|
|
||||||
>
|
|
||||||
确定
|
|
||||||
</NButton>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</n-modal>
|
</NovaDialog>
|
||||||
|
|
||||||
<!-- 重置密码模态框 -->
|
<!-- 重置密码弹框 -->
|
||||||
<n-modal
|
<NovaDialog
|
||||||
v-model:show="showResetPwdModal"
|
ref="resetPwdDialogRef"
|
||||||
title="重置用户密码"
|
title="重置用户密码"
|
||||||
preset="card"
|
:width="500"
|
||||||
:style="{ width: '500px' }"
|
height="auto"
|
||||||
:mask-closable="false"
|
confirm-text="确认重置"
|
||||||
class="reset-pwd-modal"
|
cancel-text="取消"
|
||||||
|
@nova-confirm="handleConfirmResetPassword"
|
||||||
|
@nova-cancel="handleCancelResetPassword"
|
||||||
>
|
>
|
||||||
<div class="space-y-4">
|
<template #content>
|
||||||
|
<div class="p-3 space-y-4">
|
||||||
<div class="bg-gray-50 p-4 rounded-lg">
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<div class="w-10 h-10 rounded-full bg-gradient-to-r from-orange-400 to-red-500 flex items-center justify-center text-white text-sm font-bold">
|
<div class="w-10 h-10 rounded-full bg-gradient-to-r from-orange-400 to-red-500 flex items-center justify-center text-white text-sm font-bold">
|
||||||
@ -1629,27 +1615,17 @@ onBeforeUnmount(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
|
||||||
<div class="flex justify-end gap-3">
|
|
||||||
<NButton @click="handleCancelResetPassword">
|
|
||||||
取消
|
|
||||||
</NButton>
|
|
||||||
<NButton type="primary" @click="handleConfirmResetPassword">
|
|
||||||
确认重置
|
|
||||||
</NButton>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</n-modal>
|
</NovaDialog>
|
||||||
|
|
||||||
<!-- 头像查看模态框 -->
|
<!-- 头像查看弹框 -->
|
||||||
<n-modal
|
<NovaDialog
|
||||||
v-model:show="showAvatarModal"
|
ref="avatarDialogRef"
|
||||||
preset="card"
|
:width="600"
|
||||||
:style="{ width: '600px' }"
|
height="auto"
|
||||||
:mask-closable="true"
|
cancel-text="关闭"
|
||||||
class="avatar-modal"
|
:show-confirm="false"
|
||||||
@close="handleCloseAvatar"
|
@nova-cancel="handleCloseAvatar"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
@ -1663,7 +1639,8 @@ onBeforeUnmount(() => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="flex flex-col items-center space-y-4">
|
<template #content>
|
||||||
|
<div class="flex flex-col items-center space-y-4 p-3">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<img
|
<img
|
||||||
:src="currentAvatar"
|
:src="currentAvatar"
|
||||||
@ -1689,26 +1666,22 @@ onBeforeUnmount(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
|
||||||
<div class="flex justify-end">
|
|
||||||
<NButton @click="handleCloseAvatar">
|
|
||||||
关闭
|
|
||||||
</NButton>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</n-modal>
|
</NovaDialog>
|
||||||
|
|
||||||
<!-- 导入用户模态框 -->
|
<!-- 导入用户弹框 -->
|
||||||
<n-modal
|
<NovaDialog
|
||||||
v-model:show="showImportModal"
|
ref="importDialogRef"
|
||||||
title="导入用户数据"
|
title="导入用户数据"
|
||||||
preset="card"
|
:width="600"
|
||||||
:style="{ width: '600px' }"
|
height="auto"
|
||||||
:mask-closable="false"
|
confirm-text="开始导入"
|
||||||
class="import-modal"
|
cancel-text="取消"
|
||||||
|
@nova-confirm="handleConfirmImport"
|
||||||
|
@nova-cancel="handleCancelImport"
|
||||||
>
|
>
|
||||||
<div class="space-y-6">
|
<template #content>
|
||||||
|
<div class="p-3 space-y-6">
|
||||||
<!-- 文件上传区域 -->
|
<!-- 文件上传区域 -->
|
||||||
<div>
|
<div>
|
||||||
<h4 class="text-sm font-medium text-gray-700 mb-3">
|
<h4 class="text-sm font-medium text-gray-700 mb-3">
|
||||||
@ -1782,10 +1755,9 @@ onBeforeUnmount(() => {
|
|||||||
<li>• 用户状态默认为"启用"</li>
|
<li>• 用户状态默认为"启用"</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<template #footer>
|
<!-- 下载模板按钮 -->
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-start">
|
||||||
<NButton
|
<NButton
|
||||||
:disabled="importLoading"
|
:disabled="importLoading"
|
||||||
@click="handleDownloadTemplate"
|
@click="handleDownloadTemplate"
|
||||||
@ -1795,23 +1767,10 @@ onBeforeUnmount(() => {
|
|||||||
</template>
|
</template>
|
||||||
下载模板
|
下载模板
|
||||||
</NButton>
|
</NButton>
|
||||||
|
|
||||||
<div class="flex gap-3">
|
|
||||||
<NButton :disabled="importLoading" @click="handleCancelImport">
|
|
||||||
取消
|
|
||||||
</NButton>
|
|
||||||
<NButton
|
|
||||||
type="primary"
|
|
||||||
:loading="importLoading"
|
|
||||||
:disabled="!selectedFile"
|
|
||||||
@click="handleConfirmImport"
|
|
||||||
>
|
|
||||||
开始导入
|
|
||||||
</NButton>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</n-modal>
|
</NovaDialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user