|
@@ -12,14 +12,14 @@
|
|
|
<el-icon><Plus /></el-icon>
|
|
<el-icon><Plus /></el-icon>
|
|
|
创建用户
|
|
创建用户
|
|
|
</el-button>
|
|
</el-button>
|
|
|
- <el-button
|
|
|
|
|
|
|
+ <!--<el-button
|
|
|
type="danger"
|
|
type="danger"
|
|
|
:disabled="selectedUsers.length === 0"
|
|
:disabled="selectedUsers.length === 0"
|
|
|
@click="batchDelete"
|
|
@click="batchDelete"
|
|
|
>
|
|
>
|
|
|
<el-icon><Delete /></el-icon>
|
|
<el-icon><Delete /></el-icon>
|
|
|
批量删除
|
|
批量删除
|
|
|
- </el-button>
|
|
|
|
|
|
|
+ </el-button> -->
|
|
|
</div>
|
|
</div>
|
|
|
<div class="toolbar-right">
|
|
<div class="toolbar-right">
|
|
|
<el-input
|
|
<el-input
|
|
@@ -45,7 +45,7 @@
|
|
|
:scroll-x="true"
|
|
:scroll-x="true"
|
|
|
>
|
|
>
|
|
|
<el-table-column type="selection" width="55" />
|
|
<el-table-column type="selection" width="55" />
|
|
|
- <el-table-column prop="username" label="用户信息" width="140" fixed="left">
|
|
|
|
|
|
|
+ <el-table-column prop="username" label="用户信息" min-width="160" fixed="left">
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
<div class="user-info">
|
|
<div class="user-info">
|
|
|
<el-avatar :size="28" :src="row.avatar_url">
|
|
<el-avatar :size="28" :src="row.avatar_url">
|
|
@@ -58,9 +58,9 @@
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column prop="email" label="邮箱" width="180" show-overflow-tooltip />
|
|
|
|
|
- <el-table-column prop="phone" label="手机号" width="120" />
|
|
|
|
|
- <el-table-column prop="roles" label="角色" width="130">
|
|
|
|
|
|
|
+ <el-table-column prop="email" label="邮箱" min-width="200" show-overflow-tooltip />
|
|
|
|
|
+ <el-table-column prop="phone" label="手机号" min-width="130" />
|
|
|
|
|
+ <el-table-column prop="roles" label="角色" min-width="140">
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
<div class="roles-container">
|
|
<div class="roles-container">
|
|
|
<el-tag
|
|
<el-tag
|
|
@@ -74,14 +74,14 @@
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column prop="is_superuser" label="管理员" width="70" align="center">
|
|
|
|
|
|
|
+ <el-table-column prop="is_superuser" label="管理员" width="80" align="center">
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
<el-tag :type="row.is_superuser ? 'danger' : 'info'" size="small">
|
|
<el-tag :type="row.is_superuser ? 'danger' : 'info'" size="small">
|
|
|
{{ row.is_superuser ? '是' : '否' }}
|
|
{{ row.is_superuser ? '是' : '否' }}
|
|
|
</el-tag>
|
|
</el-tag>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column prop="is_active" label="状态" width="70" align="center">
|
|
|
|
|
|
|
+ <el-table-column prop="is_active" label="状态" width="80" align="center">
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
<el-switch
|
|
<el-switch
|
|
|
v-model="row.is_active"
|
|
v-model="row.is_active"
|
|
@@ -90,36 +90,58 @@
|
|
|
/>
|
|
/>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column prop="last_login_at" label="最后登录" width="130">
|
|
|
|
|
|
|
+ <el-table-column prop="last_login_at" label="最后登录" min-width="140">
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
<div class="time-info">
|
|
<div class="time-info">
|
|
|
{{ formatDateTime(row.last_login_at) }}
|
|
{{ formatDateTime(row.last_login_at) }}
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column label="操作" width="160" fixed="right">
|
|
|
|
|
|
|
+ <el-table-column prop="created_by" label="创建人" min-width="100">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <div class="user-info-simple">
|
|
|
|
|
+ {{ row.created_by_name || '-' }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column prop="created_time" label="创建时间" min-width="140">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <div class="time-info">
|
|
|
|
|
+ {{ formatDateTime(row.created_time) }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column prop="updated_by" label="修改人" min-width="100">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <div class="user-info-simple">
|
|
|
|
|
+ {{ row.updated_by_name || '-' }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column prop="updated_time" label="修改时间" min-width="140">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <div class="time-info">
|
|
|
|
|
+ {{ formatDateTime(row.updated_time) }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="操作" width="280" fixed="right">
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
<div class="action-buttons">
|
|
<div class="action-buttons">
|
|
|
<el-button type="primary" size="small" @click="editUser(row)">
|
|
<el-button type="primary" size="small" @click="editUser(row)">
|
|
|
编辑
|
|
编辑
|
|
|
</el-button>
|
|
</el-button>
|
|
|
- <el-dropdown @command="(command) => handleDropdownCommand(command, row)">
|
|
|
|
|
- <el-button size="small">
|
|
|
|
|
- 更多<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
|
|
|
|
- </el-button>
|
|
|
|
|
- <template #dropdown>
|
|
|
|
|
- <el-dropdown-menu>
|
|
|
|
|
- <el-dropdown-item command="roles">分配角色</el-dropdown-item>
|
|
|
|
|
- <el-dropdown-item
|
|
|
|
|
- command="delete"
|
|
|
|
|
- :disabled="row.is_superuser || isCurrentUser(row.id)"
|
|
|
|
|
- divided
|
|
|
|
|
- >
|
|
|
|
|
- 删除用户
|
|
|
|
|
- </el-dropdown-item>
|
|
|
|
|
- </el-dropdown-menu>
|
|
|
|
|
- </template>
|
|
|
|
|
- </el-dropdown>
|
|
|
|
|
|
|
+ <el-button type="success" size="small" @click="assignRoles(row)">
|
|
|
|
|
+ 分配角色
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="danger"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ @click="deleteUser(row)"
|
|
|
|
|
+ :disabled="row.is_superuser || isCurrentUser(row.id)"
|
|
|
|
|
+ >
|
|
|
|
|
+ 删除
|
|
|
|
|
+ </el-button>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
@@ -143,33 +165,38 @@
|
|
|
<el-dialog
|
|
<el-dialog
|
|
|
v-model="showCreateDialog"
|
|
v-model="showCreateDialog"
|
|
|
:title="editingUser ? '编辑用户' : '创建用户'"
|
|
:title="editingUser ? '编辑用户' : '创建用户'"
|
|
|
- width="600px"
|
|
|
|
|
|
|
+ width="660px"
|
|
|
@close="resetForm"
|
|
@close="resetForm"
|
|
|
>
|
|
>
|
|
|
<el-form
|
|
<el-form
|
|
|
ref="userFormRef"
|
|
ref="userFormRef"
|
|
|
:model="userForm"
|
|
:model="userForm"
|
|
|
:rules="userRules"
|
|
:rules="userRules"
|
|
|
- label-width="80px"
|
|
|
|
|
|
|
+ label-width="88px"
|
|
|
>
|
|
>
|
|
|
- <el-row :gutter="16">
|
|
|
|
|
|
|
+ <el-row :gutter="18">
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
<el-form-item label="用户名" prop="username">
|
|
<el-form-item label="用户名" prop="username">
|
|
|
<el-input
|
|
<el-input
|
|
|
v-model="userForm.username"
|
|
v-model="userForm.username"
|
|
|
placeholder="请输入用户名"
|
|
placeholder="请输入用户名"
|
|
|
:disabled="!!editingUser"
|
|
:disabled="!!editingUser"
|
|
|
|
|
+ size="default"
|
|
|
/>
|
|
/>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
<el-form-item label="邮箱" prop="email">
|
|
<el-form-item label="邮箱" prop="email">
|
|
|
- <el-input v-model="userForm.email" placeholder="请输入邮箱" />
|
|
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="userForm.email"
|
|
|
|
|
+ placeholder="请输入邮箱"
|
|
|
|
|
+ size="default"
|
|
|
|
|
+ />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
</el-row>
|
|
</el-row>
|
|
|
|
|
|
|
|
- <el-row :gutter="16">
|
|
|
|
|
|
|
+ <el-row :gutter="18">
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
<el-form-item label="密码" :prop="editingUser ? '' : 'password'">
|
|
<el-form-item label="密码" :prop="editingUser ? '' : 'password'">
|
|
|
<el-input
|
|
<el-input
|
|
@@ -177,33 +204,50 @@
|
|
|
type="password"
|
|
type="password"
|
|
|
:placeholder="editingUser ? '留空则不修改密码' : '请输入密码'"
|
|
:placeholder="editingUser ? '留空则不修改密码' : '请输入密码'"
|
|
|
show-password
|
|
show-password
|
|
|
|
|
+ size="default"
|
|
|
/>
|
|
/>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
<el-form-item label="手机号" prop="phone">
|
|
<el-form-item label="手机号" prop="phone">
|
|
|
- <el-input v-model="userForm.phone" placeholder="请输入手机号" />
|
|
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="userForm.phone"
|
|
|
|
|
+ placeholder="请输入手机号"
|
|
|
|
|
+ size="default"
|
|
|
|
|
+ />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
</el-row>
|
|
</el-row>
|
|
|
|
|
|
|
|
- <el-row :gutter="16">
|
|
|
|
|
|
|
+ <el-row :gutter="18">
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
<el-form-item label="真实姓名" prop="real_name">
|
|
<el-form-item label="真实姓名" prop="real_name">
|
|
|
- <el-input v-model="userForm.real_name" placeholder="请输入真实姓名" />
|
|
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="userForm.real_name"
|
|
|
|
|
+ placeholder="请输入真实姓名"
|
|
|
|
|
+ size="default"
|
|
|
|
|
+ />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
<el-form-item label="公司" prop="company">
|
|
<el-form-item label="公司" prop="company">
|
|
|
- <el-input v-model="userForm.company" placeholder="请输入公司名称" />
|
|
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="userForm.company"
|
|
|
|
|
+ placeholder="请输入公司名称"
|
|
|
|
|
+ size="default"
|
|
|
|
|
+ />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
</el-row>
|
|
</el-row>
|
|
|
|
|
|
|
|
- <el-row :gutter="16">
|
|
|
|
|
|
|
+ <el-row :gutter="18">
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
<el-form-item label="部门" prop="department">
|
|
<el-form-item label="部门" prop="department">
|
|
|
- <el-input v-model="userForm.department" placeholder="请输入部门" />
|
|
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="userForm.department"
|
|
|
|
|
+ placeholder="请输入部门"
|
|
|
|
|
+ size="default"
|
|
|
|
|
+ />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
@@ -213,11 +257,12 @@
|
|
|
multiple
|
|
multiple
|
|
|
placeholder="请选择角色"
|
|
placeholder="请选择角色"
|
|
|
style="width: 100%"
|
|
style="width: 100%"
|
|
|
|
|
+ size="default"
|
|
|
>
|
|
>
|
|
|
<el-option
|
|
<el-option
|
|
|
v-for="role in allRoles"
|
|
v-for="role in allRoles"
|
|
|
:key="role.id"
|
|
:key="role.id"
|
|
|
- :label="role.display_name"
|
|
|
|
|
|
|
+ :label="role.name"
|
|
|
:value="role.id"
|
|
:value="role.id"
|
|
|
/>
|
|
/>
|
|
|
</el-select>
|
|
</el-select>
|
|
@@ -225,10 +270,10 @@
|
|
|
</el-col>
|
|
</el-col>
|
|
|
</el-row>
|
|
</el-row>
|
|
|
|
|
|
|
|
- <el-row :gutter="16">
|
|
|
|
|
|
|
+ <el-row :gutter="18">
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
<el-form-item label="管理员">
|
|
<el-form-item label="管理员">
|
|
|
- <el-switch v-model="userForm.is_superuser" />
|
|
|
|
|
|
|
+ <el-switch v-model="userForm.is_superuser" size="default" />
|
|
|
<span style="margin-left: 8px; font-size: 12px; color: #666;">
|
|
<span style="margin-left: 8px; font-size: 12px; color: #666;">
|
|
|
拥有系统所有权限
|
|
拥有系统所有权限
|
|
|
</span>
|
|
</span>
|
|
@@ -236,7 +281,7 @@
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
<el-form-item label="启用状态">
|
|
<el-form-item label="启用状态">
|
|
|
- <el-switch v-model="userForm.is_active" />
|
|
|
|
|
|
|
+ <el-switch v-model="userForm.is_active" size="default" />
|
|
|
<span style="margin-left: 8px; font-size: 12px; color: #666;">
|
|
<span style="margin-left: 8px; font-size: 12px; color: #666;">
|
|
|
用户是否可以登录
|
|
用户是否可以登录
|
|
|
</span>
|
|
</span>
|
|
@@ -256,7 +301,7 @@
|
|
|
<el-dialog
|
|
<el-dialog
|
|
|
v-model="showRoleDialog"
|
|
v-model="showRoleDialog"
|
|
|
title="分配角色"
|
|
title="分配角色"
|
|
|
- width="500px"
|
|
|
|
|
|
|
+ width="550px"
|
|
|
>
|
|
>
|
|
|
<div v-if="currentUser">
|
|
<div v-if="currentUser">
|
|
|
<h4>为用户 "{{ currentUser.username }}" 分配角色</h4>
|
|
<h4>为用户 "{{ currentUser.username }}" 分配角色</h4>
|
|
@@ -267,7 +312,7 @@
|
|
|
:label="role.id"
|
|
:label="role.id"
|
|
|
:value="role.id"
|
|
:value="role.id"
|
|
|
>
|
|
>
|
|
|
- {{ role.display_name }}
|
|
|
|
|
|
|
+ {{ role.name }}
|
|
|
<el-tag v-if="role.is_system" type="info" size="small" style="margin-left: 8px;">
|
|
<el-tag v-if="role.is_system" type="info" size="small" style="margin-left: 8px;">
|
|
|
系统角色
|
|
系统角色
|
|
|
</el-tag>
|
|
</el-tag>
|
|
@@ -287,7 +332,7 @@
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
import { ref, reactive, onMounted } from 'vue'
|
|
import { ref, reactive, onMounted } from 'vue'
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
-import { Plus, Search, Delete, ArrowDown } from '@element-plus/icons-vue'
|
|
|
|
|
|
|
+import { Plus, Search, Delete } from '@element-plus/icons-vue'
|
|
|
import { useAuthStore } from '@/stores/auth'
|
|
import { useAuthStore } from '@/stores/auth'
|
|
|
import request from '@/api/request'
|
|
import request from '@/api/request'
|
|
|
|
|
|
|
@@ -339,6 +384,9 @@ const userRules = {
|
|
|
password: [
|
|
password: [
|
|
|
{ required: true, message: '请输入密码', trigger: 'blur' },
|
|
{ required: true, message: '请输入密码', trigger: 'blur' },
|
|
|
{ min: 6, message: '密码长度不能少于6位', trigger: 'blur' }
|
|
{ min: 6, message: '密码长度不能少于6位', trigger: 'blur' }
|
|
|
|
|
+ ],
|
|
|
|
|
+ real_name: [
|
|
|
|
|
+ { required: true, message: '请输入真实姓名', trigger: 'blur' }
|
|
|
]
|
|
]
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -428,20 +476,48 @@ const handleStatusChange = async (user: any) => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 编辑用户
|
|
// 编辑用户
|
|
|
-const editUser = (user: any) => {
|
|
|
|
|
|
|
+const editUser = async (user: any) => {
|
|
|
editingUser.value = user
|
|
editingUser.value = user
|
|
|
- Object.assign(userForm, {
|
|
|
|
|
- username: user.username,
|
|
|
|
|
- email: user.email,
|
|
|
|
|
- password: '',
|
|
|
|
|
- phone: user.phone || '',
|
|
|
|
|
- real_name: user.real_name || '',
|
|
|
|
|
- company: user.company || '',
|
|
|
|
|
- department: user.department || '',
|
|
|
|
|
- role_ids: [], // 需要从用户角色关联中获取
|
|
|
|
|
- is_superuser: user.is_superuser,
|
|
|
|
|
- is_active: user.is_active
|
|
|
|
|
- })
|
|
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 获取用户详情(包含角色信息)
|
|
|
|
|
+ const result = await request.get(`/api/v1/system/admin/users/${user.id}`)
|
|
|
|
|
+
|
|
|
|
|
+ if (result.code === 0) {
|
|
|
|
|
+ const userDetail = result.data
|
|
|
|
|
+ Object.assign(userForm, {
|
|
|
|
|
+ username: userDetail.username,
|
|
|
|
|
+ email: userDetail.email,
|
|
|
|
|
+ password: '',
|
|
|
|
|
+ phone: userDetail.phone || '',
|
|
|
|
|
+ real_name: userDetail.real_name || '',
|
|
|
|
|
+ company: userDetail.company || '',
|
|
|
|
|
+ department: userDetail.department || '',
|
|
|
|
|
+ role_ids: userDetail.role_ids || [],
|
|
|
|
|
+ is_superuser: userDetail.is_superuser,
|
|
|
|
|
+ is_active: userDetail.is_active
|
|
|
|
|
+ })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new Error(result.message)
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取用户详情失败:', error)
|
|
|
|
|
+ ElMessage.error('获取用户详情失败')
|
|
|
|
|
+ // 如果获取详情失败,使用列表中的基本信息
|
|
|
|
|
+ Object.assign(userForm, {
|
|
|
|
|
+ username: user.username,
|
|
|
|
|
+ email: user.email,
|
|
|
|
|
+ password: '',
|
|
|
|
|
+ phone: user.phone || '',
|
|
|
|
|
+ real_name: user.real_name || '',
|
|
|
|
|
+ company: user.company || '',
|
|
|
|
|
+ department: user.department || '',
|
|
|
|
|
+ role_ids: [],
|
|
|
|
|
+ is_superuser: user.is_superuser,
|
|
|
|
|
+ is_active: user.is_active
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
showCreateDialog.value = true
|
|
showCreateDialog.value = true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -497,23 +573,26 @@ const batchDelete = async () => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// 下拉菜单处理
|
|
|
|
|
-const handleDropdownCommand = (command: string, user: any) => {
|
|
|
|
|
- switch (command) {
|
|
|
|
|
- case 'roles':
|
|
|
|
|
- assignRoles(user)
|
|
|
|
|
- break
|
|
|
|
|
- case 'delete':
|
|
|
|
|
- deleteUser(user)
|
|
|
|
|
- break
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
// 分配角色
|
|
// 分配角色
|
|
|
const assignRoles = async (user: any) => {
|
|
const assignRoles = async (user: any) => {
|
|
|
currentUser.value = user
|
|
currentUser.value = user
|
|
|
- // TODO: 获取用户当前角色
|
|
|
|
|
- selectedRoleIds.value = []
|
|
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 获取用户详情(包含角色信息)
|
|
|
|
|
+ const result = await request.get(`/api/v1/system/admin/users/${user.id}`)
|
|
|
|
|
+
|
|
|
|
|
+ if (result.code === 0) {
|
|
|
|
|
+ const userDetail = result.data
|
|
|
|
|
+ selectedRoleIds.value = userDetail.role_ids || []
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new Error(result.message)
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取用户角色失败:', error)
|
|
|
|
|
+ ElMessage.error('获取用户角色失败')
|
|
|
|
|
+ selectedRoleIds.value = []
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
showRoleDialog.value = true
|
|
showRoleDialog.value = true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -528,17 +607,17 @@ const saveUser = async () => {
|
|
|
// 更新用户
|
|
// 更新用户
|
|
|
const updateData: any = {
|
|
const updateData: any = {
|
|
|
email: userForm.email,
|
|
email: userForm.email,
|
|
|
- phone: userForm.phone,
|
|
|
|
|
|
|
+ phone: userForm.phone || null, // 确保空字符串转为null
|
|
|
real_name: userForm.real_name,
|
|
real_name: userForm.real_name,
|
|
|
- company: userForm.company,
|
|
|
|
|
- department: userForm.department,
|
|
|
|
|
|
|
+ company: userForm.company || null,
|
|
|
|
|
+ department: userForm.department || null,
|
|
|
role_ids: userForm.role_ids,
|
|
role_ids: userForm.role_ids,
|
|
|
is_superuser: userForm.is_superuser,
|
|
is_superuser: userForm.is_superuser,
|
|
|
is_active: userForm.is_active
|
|
is_active: userForm.is_active
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 如果填写了密码,则更新密码
|
|
// 如果填写了密码,则更新密码
|
|
|
- if (userForm.password) {
|
|
|
|
|
|
|
+ if (userForm.password && userForm.password.trim()) {
|
|
|
updateData.password = userForm.password
|
|
updateData.password = userForm.password
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -546,7 +625,14 @@ const saveUser = async () => {
|
|
|
ElMessage.success('用户更新成功')
|
|
ElMessage.success('用户更新成功')
|
|
|
} else {
|
|
} else {
|
|
|
// 创建用户
|
|
// 创建用户
|
|
|
- await request.post('/api/v1/system/admin/users', userForm)
|
|
|
|
|
|
|
+ const createData = {
|
|
|
|
|
+ ...userForm,
|
|
|
|
|
+ phone: userForm.phone || null, // 确保空字符串转为null
|
|
|
|
|
+ company: userForm.company || null,
|
|
|
|
|
+ department: userForm.department || null
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ await request.post('/api/v1/system/admin/users', createData)
|
|
|
ElMessage.success('用户创建成功')
|
|
ElMessage.success('用户创建成功')
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -606,23 +692,16 @@ const resetForm = () => {
|
|
|
const formatDateTime = (dateTime: string) => {
|
|
const formatDateTime = (dateTime: string) => {
|
|
|
if (!dateTime) return '-'
|
|
if (!dateTime) return '-'
|
|
|
const date = new Date(dateTime)
|
|
const date = new Date(dateTime)
|
|
|
- const now = new Date()
|
|
|
|
|
- const diffTime = now.getTime() - date.getTime()
|
|
|
|
|
- const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24))
|
|
|
|
|
|
|
|
|
|
- if (diffDays === 0) {
|
|
|
|
|
- return date.toLocaleTimeString('zh-CN', {
|
|
|
|
|
- hour: '2-digit',
|
|
|
|
|
- minute: '2-digit'
|
|
|
|
|
- })
|
|
|
|
|
- } else if (diffDays < 7) {
|
|
|
|
|
- return `${diffDays}天前`
|
|
|
|
|
- } else {
|
|
|
|
|
- return date.toLocaleDateString('zh-CN', {
|
|
|
|
|
- month: '2-digit',
|
|
|
|
|
- day: '2-digit'
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 格式化为 YYYY-MM-DD HH:mm:ss
|
|
|
|
|
+ const year = date.getFullYear()
|
|
|
|
|
+ const month = String(date.getMonth() + 1).padStart(2, '0')
|
|
|
|
|
+ const day = String(date.getDate()).padStart(2, '0')
|
|
|
|
|
+ const hours = String(date.getHours()).padStart(2, '0')
|
|
|
|
|
+ const minutes = String(date.getMinutes()).padStart(2, '0')
|
|
|
|
|
+ const seconds = String(date.getSeconds()).padStart(2, '0')
|
|
|
|
|
+
|
|
|
|
|
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 组件挂载
|
|
// 组件挂载
|
|
@@ -679,12 +758,22 @@ onMounted(() => {
|
|
|
background: #fff;
|
|
background: #fff;
|
|
|
border-radius: 8px;
|
|
border-radius: 8px;
|
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
|
|
|
+ min-width: 1200px; /* 设置最小宽度确保表格不会过度压缩 */
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.user-info {
|
|
.user-info {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
gap: 8px;
|
|
gap: 8px;
|
|
|
|
|
+ min-width: 120px; /* 确保用户信息列有足够宽度 */
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.user-info-simple {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.user-details {
|
|
.user-details {
|
|
@@ -701,6 +790,7 @@ onMounted(() => {
|
|
|
white-space: nowrap;
|
|
white-space: nowrap;
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
text-overflow: ellipsis;
|
|
|
|
|
+ max-width: 100px; /* 限制用户名最大宽度 */
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.real-name {
|
|
.real-name {
|
|
@@ -709,6 +799,7 @@ onMounted(() => {
|
|
|
white-space: nowrap;
|
|
white-space: nowrap;
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
text-overflow: ellipsis;
|
|
|
|
|
+ max-width: 100px; /* 限制真实姓名最大宽度 */
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.roles-container {
|
|
.roles-container {
|
|
@@ -716,6 +807,7 @@ onMounted(() => {
|
|
|
flex-wrap: wrap;
|
|
flex-wrap: wrap;
|
|
|
gap: 2px;
|
|
gap: 2px;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
|
|
+ min-width: 80px; /* 确保角色列有最小宽度 */
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.time-info {
|
|
.time-info {
|
|
@@ -728,6 +820,8 @@ onMounted(() => {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
gap: 6px;
|
|
gap: 6px;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
|
|
+ justify-content: flex-start; /* 左对齐操作按钮 */
|
|
|
|
|
+ flex-wrap: nowrap; /* 不允许换行 */
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.pagination {
|
|
.pagination {
|
|
@@ -747,7 +841,7 @@ onMounted(() => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
:deep(.el-dialog__body) {
|
|
:deep(.el-dialog__body) {
|
|
|
- padding: 20px;
|
|
|
|
|
|
|
+ padding: 22px; /* 增加对话框内边距 10% */
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
:deep(.el-checkbox-group) {
|
|
:deep(.el-checkbox-group) {
|
|
@@ -759,4 +853,92 @@ onMounted(() => {
|
|
|
:deep(.el-checkbox) {
|
|
:deep(.el-checkbox) {
|
|
|
margin-right: 0;
|
|
margin-right: 0;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+/* 响应式设计 */
|
|
|
|
|
+@media (max-width: 1400px) {
|
|
|
|
|
+ .table-container {
|
|
|
|
|
+ min-width: 1300px; /* 增加最小宽度以适应更多列 */
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .username, .real-name {
|
|
|
|
|
+ max-width: 80px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+@media (max-width: 1200px) {
|
|
|
|
|
+ .table-container {
|
|
|
|
|
+ min-width: 1200px; /* 增加最小宽度 */
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .username, .real-name {
|
|
|
|
|
+ max-width: 70px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .toolbar {
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ align-items: stretch;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .toolbar-left, .toolbar-right {
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 中等屏幕下操作按钮调整 */
|
|
|
|
|
+ .action-buttons {
|
|
|
|
|
+ gap: 4px; /* 减少间距 */
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .action-buttons .el-button {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ padding: 4px 8px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+@media (max-width: 1000px) {
|
|
|
|
|
+ .table-container {
|
|
|
|
|
+ min-width: 1000px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 小屏幕下操作按钮垂直排列 */
|
|
|
|
|
+ .action-buttons {
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 2px;
|
|
|
|
|
+ flex-wrap: nowrap;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .action-buttons .el-button {
|
|
|
|
|
+ font-size: 11px;
|
|
|
|
|
+ padding: 2px 6px;
|
|
|
|
|
+ min-width: 70px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+@media (max-width: 768px) {
|
|
|
|
|
+ .users-management {
|
|
|
|
|
+ padding: 10px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .table-container {
|
|
|
|
|
+ min-width: 900px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .toolbar {
|
|
|
|
|
+ padding: 12px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .toolbar-left {
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .pagination {
|
|
|
|
|
+ margin-top: 15px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ :deep(.el-pagination) {
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|