Parcourir la source

fix:修复用户管理中用户列表和新增编辑表单中字段不完整的问题

yangyi il y a 4 mois
Parent
commit
f4178a832f
1 fichiers modifiés avec 98 ajouts et 6 suppressions
  1. 98 6
      src/view/UserView.vue

+ 98 - 6
src/view/UserView.vue

@@ -1,5 +1,6 @@
 <script setup lang="ts">
 import { getUserController } from '@/api/user-controller'
+import { getImageController } from '@/api/image-controller'
 import type { UserDto, UserVo } from '@/api/models'
 import { ElMessage, ElMessageBox, type FormInstance, type FormRules, ElIcon } from 'element-plus'
 import { Plus, RefreshRight, Search, Delete, Edit } from '@element-plus/icons-vue'
@@ -25,7 +26,10 @@ const userForm = reactive<Partial<UserDto>>({
   username: '',
   account: '',
   password: '',
-  role: ''
+  role: '',
+  email: '',
+  phone: '',
+  avatar: ''
 })
 const formRules: FormRules = {
   username: [
@@ -43,6 +47,12 @@ const formRules: FormRules = {
   role: [
     { required: true, message: '请选择角色', trigger: 'change' },
     { min: 4, max: 32, message: '角色长度需在 4 到 32 个字符之间', trigger: 'change' }
+  ],
+  email: [
+    { type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
+  ],
+  phone: [
+    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
   ]
 }
 
@@ -68,6 +78,24 @@ const roleOptions = [
 // 是否编辑模式
 const isEdit = computed(() => !!userForm.id)
 
+const uploading = ref(false)
+
+const handleAvatarChange = async (uploadFile: any) => {
+  uploading.value = true
+  try {
+    const res = await getImageController().upload({ imageFile: uploadFile.raw as Blob })
+    if (res?.data) {
+      userForm.avatar = res.data
+    } else {
+      ElMessage.error('图片上传失败')
+    }
+  } catch {
+    ElMessage.error('图片上传失败')
+  } finally {
+    uploading.value = false
+  }
+}
+
 // 搜索
 const handleSearch = () => {
   pagination.pageNum = 1
@@ -119,7 +147,7 @@ const handleSizeChange = (size: number) => {
 // 打开新增
 const handleAdd = () => {
   dialogTitle.value = '新增用户'
-  Object.assign(userForm, { id: undefined, username: '', account: '', password: '', role: '' })
+  Object.assign(userForm, { id: undefined, username: '', account: '', password: '', role: '', email: '', phone: '', avatar: '' })
   dialogVisible.value = true
 }
 
@@ -134,7 +162,10 @@ const handleEdit = async (row: UserVo) => {
         username: res.data?.username,
         account: res.data?.account,
         password: '',
-        role: res.data?.role
+        role: res.data?.role,
+        email: res.data?.email ?? '',
+        phone: res.data?.phone ?? '',
+        avatar: res.data?.avatar ?? ''
       })
       dialogVisible.value = true
     }
@@ -151,7 +182,10 @@ const handleSave = async () => {
       const baseData = {
         username: userForm.username!,
         account: userForm.account!,
-        role: userForm.role!
+        role: userForm.role!,
+        email: userForm.email || undefined,
+        phone: userForm.phone || undefined,
+        avatar: userForm.avatar || undefined
       }
       
       if (isEdit.value) {
@@ -326,6 +360,8 @@ fetchData()
         <el-table-column prop="id" label="ID" width="80" align="center" />
         <el-table-column prop="username" label="用户名" min-width="120" align="center" />
         <el-table-column prop="account" label="账号" min-width="150" align="center" />
+        <el-table-column prop="email" label="邮箱" min-width="180" align="center" />
+        <el-table-column prop="phone" label="手机号" min-width="130" align="center" />
         <el-table-column prop="role" label="角色" width="120" align="center">
           <template #default="{ row }">
             <el-tag :type="row.role === 'admin' ? 'danger' : row.role === 'user' ? 'success' : 'info'">
@@ -345,8 +381,19 @@ fetchData()
         </el-table-column>
         <el-table-column prop="avatar" label="头像" width="100" align="center">
           <template #default="{ row }">
-            <el-avatar v-if="row.avatar" :src="row.avatar" :size="40" />
-            <el-avatar v-else :size="40">{{ row.username?.charAt(0) || '?' }}</el-avatar>
+            <el-avatar
+              v-if="row.avatar"
+              :src="row.avatar"
+              :size="40"
+              class="clickable-avatar"
+              @click="handleEdit(row)"
+            />
+            <el-avatar
+              v-else
+              :size="40"
+              class="clickable-avatar"
+              @click="handleEdit(row)"
+            >{{ row.username?.charAt(0) || '?' }}</el-avatar>
           </template>
         </el-table-column>
         <el-table-column label="操作" width="180" align="center" fixed="right">
@@ -393,6 +440,28 @@ fetchData()
             <el-option v-for="item in roleOptions" :key="item.value" :label="item.label" :value="item.value" />
           </el-select>
         </el-form-item>
+        <el-form-item label="邮箱" prop="email">
+          <el-input v-model="userForm.email" placeholder="请输入邮箱" />
+        </el-form-item>
+        <el-form-item label="手机号" prop="phone">
+          <el-input v-model="userForm.phone" placeholder="请输入手机号" />
+        </el-form-item>
+        <el-form-item label="头像" prop="avatar">
+          <div class="avatar-upload">
+            <el-avatar v-if="userForm.avatar" :size="60" :src="userForm.avatar" shape="square" />
+            <el-avatar v-else :size="60" shape="square">?</el-avatar>
+            <el-upload
+              :show-file-list="false"
+              :on-change="handleAvatarChange"
+              :auto-upload="false"
+              accept="image/jpeg,image/png,image/gif,image/webp"
+            >
+              <template #trigger>
+                <el-button size="small" :loading="uploading">选择图片</el-button>
+              </template>
+            </el-upload>
+          </div>
+        </el-form-item>
       </el-form>
       <template #footer>
         <el-button @click="dialogVisible = false">取消</el-button>
@@ -430,4 +499,27 @@ fetchData()
   color: #909399;
   line-height: 1.4;
 }
+
+.clickable-avatar {
+  cursor: pointer;
+  transition: opacity 0.2s;
+}
+.clickable-avatar:hover {
+  opacity: 0.8;
+}
+
+.avatar-upload {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+@media (max-width: 768px) {
+  .table-card :deep(.el-table) {
+    overflow-x: auto;
+  }
+  .table-card :deep(.el-table__body-wrapper) {
+    overflow-x: auto;
+  }
+}
 </style>