From 8360dbc66518a3d4b6aee9f915e6092a1673a2b5 Mon Sep 17 00:00:00 2001
From: Leo <98382335+gaoziman@users.noreply.github.com>
Date: Tue, 8 Jul 2025 20:31:36 +0800
Subject: [PATCH] =?UTF-8?q?refactor(system):=20=E4=BC=98=E5=8C=96=E7=94=A8?=
=?UTF-8?q?=E6=88=B7=E5=92=8C=E8=A7=92=E8=89=B2=E7=AE=A1=E7=90=86=E9=A1=B5?=
=?UTF-8?q?=E9=9D=A2=E4=BA=A4=E4=BA=92=E4=BD=93=E9=AA=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
**角色管理页面优化:**
- 新增批量修改和批量分配权限按钮,提升操作效率
- 优化权限分配界面,新增展开/折叠、全选/全不选、父子联动等功能按钮
- 所有按钮统一添加图标,改善视觉效果和用户体验
- 权限标识码使用 NTag 组件显示,遵循主题色统一规范
- 调整操作列宽度,适应新增的权限分配按钮
**用户管理页面优化:**
- 移除调试日志,优化代码可读性
- 改进文件上传大小限制从10MB调整为2MB,提升上传体验
- 优化错误处理,提供更详细的错误信息反馈
- 改进Excel导入功能的错误提示和异常处理
**个人中心页面优化:**
- 头像上传大小限制从5MB调整为2MB
- 优化头像上传错误处理,支持解析后端返回的具体错误信息
- 改进文件大小超限提示,显示当前文件大小和最大允许大小
- 增强网络错误和HTTP状态码错误的用户友好提示
---
src/views/personal-center/index.vue | 43 ++++++++++++--
src/views/system/role/index.vue | 91 +++++++++++++++++++++++++++--
src/views/system/user/index.vue | 78 ++++++++++++++++---------
3 files changed, 171 insertions(+), 41 deletions(-)
diff --git a/src/views/personal-center/index.vue b/src/views/personal-center/index.vue
index e906a1f..1774f7d 100644
--- a/src/views/personal-center/index.vue
+++ b/src/views/personal-center/index.vue
@@ -422,15 +422,16 @@ async function handleAvatarChange(event: Event) {
return
}
- // 验证文件大小(5MB)
- if (file.size > 5 * 1024 * 1024) {
- coiMsgError('图片大小不能超过5MB')
+ // 验证文件大小(2MB)
+ const fileSizeMB = file.size / 1024 / 1024
+ if (fileSizeMB > 2) {
+ coiMsgError(`头像文件大小超出限制!当前文件:${fileSizeMB.toFixed(2)}MB,最大允许:2MB`)
return
}
try {
uploading.value = true
- const result = await uploadAvatar(file, 5)
+ const result = await uploadAvatar(file, 2)
if (result.isSuccess) {
// 使用配置文件中的服务地址构建头像访问URL
const baseUrl = serviceConfig[import.meta.env.MODE].url
@@ -446,8 +447,38 @@ async function handleAvatarChange(event: Event) {
coiMsgError('头像上传失败')
}
}
- catch {
- coiMsgError('头像上传失败')
+ catch (error: any) {
+ // 解析后端返回的错误信息
+ let errorMessage = '头像上传失败'
+
+ // 检查是否是服务返回的结构化错误
+ if (error?.isSuccess === false) {
+ // alova 返回的结构化错误
+ if (error.message) {
+ errorMessage = error.message
+ }
+ else if (error.msg) {
+ errorMessage = error.msg
+ }
+ }
+ else if (error?.response?.data?.msg) {
+ // 原始HTTP响应错误
+ errorMessage = error.response.data.msg
+ }
+ else if (error?.message) {
+ // 网络错误或其他错误
+ if (error.message.includes('413')) {
+ errorMessage = '头像文件大小超出限制,请选择较小的文件'
+ }
+ else if (error.message.includes('400')) {
+ errorMessage = '头像文件格式不支持或文件无效'
+ }
+ else {
+ errorMessage = error.message
+ }
+ }
+
+ coiMsgError(errorMessage)
}
finally {
uploading.value = false
diff --git a/src/views/system/role/index.vue b/src/views/system/role/index.vue
index 2b2cf2b..4890ef8 100644
--- a/src/views/system/role/index.vue
+++ b/src/views/system/role/index.vue
@@ -103,6 +103,21 @@
新增
+
+
+
+
+
+
+ 修改
+
+
删除
+
+
+
+
+
+
+
+ 分配权限
+
@@ -307,6 +337,12 @@
:type="allExpanded ? 'default' : 'primary'"
@click="toggleExpandAll"
>
+
+
+
+
+
+
{{ allExpanded ? '折叠' : '展开' }}
@@ -315,6 +351,12 @@
:type="allSelected ? 'default' : 'primary'"
@click="toggleSelectAll"
>
+
+
+
+
+
+
{{ allSelected ? '全不选' : '全选' }}
@@ -323,6 +365,11 @@
:type="cascadeEnabled ? 'primary' : 'default'"
@click="toggleCascade"
>
+
+
+
+
+
父子联动
@@ -331,6 +378,11 @@
:type="showPermissionCode ? 'primary' : 'default'"
@click="togglePermissionCode"
>
+
+
+
+
+
权限标识
@@ -372,7 +424,7 @@ import type { DataTableColumns, FormInst } from 'naive-ui'
import { NButton, NIcon, NPopconfirm, NSpace, NSwitch, NTag, NTooltip, NTree } from 'naive-ui'
import IconParkOutlineEditOne from '~icons/icon-park-outline/edit-one'
import IconParkOutlineDelete from '~icons/icon-park-outline/delete'
-import IconParkOutlineShield from '~icons/icon-park-outline/shield'
+import IconParkOutlineKey from '~icons/icon-park-outline/key'
import CoiDialog from '@/components/common/CoiDialog.vue'
import CoiEmpty from '@/components/common/CoiEmpty.vue'
import {
@@ -553,7 +605,7 @@ const columns: DataTableColumns = [
{
title: '操作',
key: 'actions',
- width: 160,
+ width: 200,
align: 'center',
fixed: 'right',
render: (row) => {
@@ -615,7 +667,7 @@ const columns: DataTableColumns = [
class: 'action-btn action-btn-warning',
onClick: () => handleAssignMenu(row),
}, {
- icon: () => h(NIcon, { size: 18 }, { default: () => h(IconParkOutlineShield) }),
+ icon: () => h(NIcon, { size: 18 }, { default: () => h(IconParkOutlineKey) }),
}),
}))
}
@@ -780,6 +832,31 @@ function handleRowSelectionChange(rowKeys: (string | number)[]) {
selectedRows.value = tableData.value.filter(row => numericKeys.includes(row.roleId))
}
+// 批量修改(选中一个角色进行修改)
+function handleBatchEdit() {
+ if (selectedRows.value.length !== 1) {
+ coiMsgWarning('请选择一个角色进行修改')
+ return
+ }
+ handleEdit(selectedRows.value[0])
+}
+
+// 批量分配权限(选中一个角色进行权限分配)
+function handleBatchAssignMenu() {
+ if (selectedRows.value.length !== 1) {
+ coiMsgWarning('请选择一个角色进行权限分配')
+ return
+ }
+
+ const selectedRole = selectedRows.value[0]
+ if (selectedRole.roleId === 1) {
+ coiMsgError('超级管理员角色无需分配权限')
+ return
+ }
+
+ handleAssignMenu(selectedRole)
+}
+
// 新增角色
async function handleAdd() {
modalTitle.value = '新增角色'
@@ -1111,10 +1188,12 @@ function renderPermissionCode({ option }: { option: any }) {
return null
}
- return h('span', {
- class: 'ml-2 px-2 py-1 bg-blue-50 text-blue-600 text-xs rounded font-mono border border-blue-200',
+ return h(NTag, {
+ type: 'primary',
+ size: 'small',
+ class: 'ml-2 font-mono',
style: 'font-size: 11px; line-height: 1.2; transform: translateY(-5px); display: inline-flex; align-items: center;',
- }, code)
+ }, { default: () => code })
}
// 提交表单
diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue
index c18e848..cdfc617 100644
--- a/src/views/system/user/index.vue
+++ b/src/views/system/user/index.vue
@@ -1140,14 +1140,12 @@ async function getUserList() {
pagination.value.itemCount = data.total || 0
}
else {
- console.warn('获取用户列表失败,可能是权限或网络问题')
coiMsgError('获取用户列表失败,请检查网络连接或联系管理员')
tableData.value = []
pagination.value.itemCount = 0
}
}
- catch (error) {
- console.error('获取用户列表失败:', error)
+ catch {
coiMsgError('获取用户列表失败,请检查网络连接')
tableData.value = []
pagination.value.itemCount = 0
@@ -1166,8 +1164,7 @@ async function getRoleList() {
roleOptions.value = data
}
}
- catch (error) {
- console.warn('获取角色列表失败,将不显示角色选择:', error)
+ catch {
}
}
@@ -1291,8 +1288,7 @@ async function handleEdit(user: UserVo) {
}
}
}
- catch (error) {
- console.error('获取用户详情失败:', error)
+ catch {
// 如果获取详情出错,使用列表数据作为备用
formData.value = {
loginName: user.loginName,
@@ -1324,8 +1320,7 @@ async function handleDelete(userId: number) {
coiMsgError('删除失败')
}
}
- catch (error) {
- console.error('删除失败:', error)
+ catch {
coiMsgError('删除失败')
}
}
@@ -1359,8 +1354,7 @@ async function handleBatchDelete() {
coiMsgError('批量删除失败')
}
}
- catch (error) {
- console.error('批量删除失败:', error)
+ catch {
coiMsgError('批量删除失败')
}
}
@@ -1382,8 +1376,7 @@ async function handleToggleStatus(user: UserVo) {
coiMsgError(`用户${statusText}失败`)
}
}
- catch (error) {
- console.error('状态修改失败:', error)
+ catch {
coiMsgError('状态修改失败,请检查网络连接')
}
}
@@ -1425,8 +1418,7 @@ async function handleConfirmResetPassword() {
coiMsgError('重置密码失败,请稍后重试')
}
}
- catch (error) {
- console.error('重置密码API调用失败:', error)
+ catch {
coiMsgError('重置密码失败,请检查网络连接')
}
}
@@ -1567,8 +1559,7 @@ async function handleExportCurrent() {
downloadBlob(response, filename)
coiMsgSuccess('导出成功')
}
- catch (error) {
- console.error('导出失败:', error)
+ catch {
coiMsgError('导出失败,请重试')
}
}
@@ -1583,8 +1574,7 @@ async function handleExportAll() {
downloadBlob(response, filename)
coiMsgSuccess('导出成功')
}
- catch (error) {
- console.error('导出失败:', error)
+ catch {
coiMsgError('导出失败,请重试')
}
}
@@ -1599,8 +1589,7 @@ async function handleDownloadTemplate() {
downloadBlob(response, filename)
coiMsgSuccess('模板下载成功')
}
- catch (error) {
- console.error('模板下载失败:', error)
+ catch {
coiMsgError('模板下载失败,请重试')
}
}
@@ -1631,6 +1620,8 @@ function handleImport() {
// 文件选择处理
function handleFileSelect(file: File) {
+ // 添加调试日志
+
// 验证文件类型
const allowedTypes = [
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
@@ -1642,9 +1633,10 @@ function handleFileSelect(file: File) {
return false
}
- // 验证文件大小(限制为10MB)
- if (file.size > 10 * 1024 * 1024) {
- coiMsgError('文件大小不能超过10MB')
+ // 验证文件大小(限制为2MB)
+ const fileSizeMB = file.size / 1024 / 1024
+ if (fileSizeMB > 2) {
+ coiMsgError(`Excel文件大小超出限制!当前文件:${fileSizeMB.toFixed(2)}MB,最大允许:2MB`)
return false
}
@@ -1698,9 +1690,38 @@ async function handleConfirmImport() {
coiMsgError(response.message || '导入失败,请重试')
}
}
- catch (error) {
- console.error('导入失败:', error)
- coiMsgError('导入失败,请检查文件格式或联系管理员')
+ catch (error: any) {
+ // 解析后端返回的错误信息
+ let errorMessage = '导入失败,请检查文件格式或联系管理员'
+
+ // 检查是否是服务返回的结构化错误
+ if (error?.isSuccess === false) {
+ // alova 返回的结构化错误
+ if (error.message) {
+ errorMessage = error.message
+ }
+ else if (error.msg) {
+ errorMessage = error.msg
+ }
+ }
+ else if (error?.response?.data?.msg) {
+ // 原始HTTP响应错误
+ errorMessage = error.response.data.msg
+ }
+ else if (error?.message) {
+ // 网络错误或其他错误
+ if (error.message.includes('413')) {
+ errorMessage = 'Excel文件大小超出限制,请选择较小的文件'
+ }
+ else if (error.message.includes('400')) {
+ errorMessage = 'Excel文件格式不支持或文件内容有误'
+ }
+ else {
+ errorMessage = error.message
+ }
+ }
+
+ coiMsgError(errorMessage)
}
finally {
// 清理定时器
@@ -1866,8 +1887,7 @@ async function handleSubmit() {
coiMsgError(isEdit.value ? '更新失败,请稍后重试' : '创建失败,请稍后重试')
}
}
- catch (error) {
- console.error('API调用失败:', error)
+ catch {
coiMsgError(isEdit.value ? '更新失败,请检查网络连接' : '创建失败,请检查网络连接')
}
}