用户管理完成

pull/1/head
李强 2021-02-27 13:48:31 +08:00
parent d8ea729d2e
commit e9e8808d40
7 changed files with 246 additions and 107 deletions

View File

@ -47,7 +47,7 @@ class UserProfileFilter(django_filters.rest_framework.FilterSet):
"""
用户管理 简单序过滤器
"""
deptId = django_filters.CharFilter(field_name='dept__id')
class Meta:
model = UserProfile
exclude = ('secret', 'password',)

View File

@ -21,7 +21,7 @@ class UserProfile(AbstractUser):
secret = CharField(max_length=255, default=uuid4, verbose_name='加密秘钥')
email = CharField(max_length=255, verbose_name="邮箱", null=True)
mobile = CharField(max_length=255, verbose_name="电话", null=True)
avatar = TextField(verbose_name="头像")
avatar = TextField(verbose_name="头像",null=True)
name = CharField(max_length=40, verbose_name="姓名")
gender = IntegerField(default=2, choices=GENDER_CHOICES, verbose_name="性别")
remark = TextField(verbose_name="备注", null=True)

View File

@ -1,32 +1,10 @@
from rest_framework import serializers
from rest_framework.validators import UniqueValidator
from apps.op_drf.serializers import CustomModelSerializer
from apps.permission.models import Menu, Dept, Post, Role, UserProfile
# ================================================= #
# ************** 用户管理 序列化器 ************** #
# ================================================= #
class UserProfileSerializer(CustomModelSerializer):
"""
简单用户序列化器
"""
admin = serializers.SerializerMethodField(read_only=True)
def get_admin(self, obj: UserProfile):
role_list = obj.role.all().values_list('admin', flat=True)
if True in list(set(role_list)):
return True
return False
class Meta:
model = UserProfile
dept = 2
exclude = ('password', 'secret', 'user_permissions', 'groups', 'is_superuser', 'date_joined')
# ================================================= #
# ************** 菜单管理 序列化器 ************** #
# ================================================= #
@ -131,6 +109,16 @@ class PostSerializer(CustomModelSerializer):
exclude = ('description', 'creator', 'modifier')
class PostSimpleSerializer(CustomModelSerializer):
"""
岗位管理 极简单序列化器
"""
class Meta:
model = Post
fields = ('id', 'postName', 'postCode', 'status')
class PostCreateUpdateSerializer(CustomModelSerializer):
"""
岗位管理 创建/更新时的列化器
@ -159,6 +147,16 @@ class RoleSerializer(CustomModelSerializer):
exclude = ('description', 'creator', 'modifier')
class RoleSimpleSerializer(CustomModelSerializer):
"""
角色管理 极简单序列化器
"""
class Meta:
model = Role
fields = ('id', 'roleName', 'roleKey', 'status')
class RoleCreateUpdateSerializer(CustomModelSerializer):
"""
角色管理 创建/更新时的列化器
@ -179,3 +177,66 @@ class RoleCreateUpdateSerializer(CustomModelSerializer):
model = Role
exclude = ('description', 'creator', 'modifier')
read_only_fields = ('update_datetime', 'create_datetime', 'creator', 'modifier')
# ================================================= #
# ************** 用户管理 序列化器 ************** #
# ================================================= #
class UserProfileSerializer(CustomModelSerializer):
"""
简单用户序列化器
"""
admin = serializers.SerializerMethodField(read_only=True)
deptId = serializers.IntegerField(source='dept.id',read_only=True)
def get_admin(self, obj: UserProfile):
role_list = obj.role.all().values_list('admin', flat=True)
if True in list(set(role_list)):
return True
return False
class Meta:
model = UserProfile
depth = 1
exclude = ('password', 'secret', 'user_permissions', 'groups', 'is_superuser', 'date_joined')
class UserProfileCreateUpdateSerializer(CustomModelSerializer):
"""
用户管理 创建/更新时的列化器
"""
admin = serializers.SerializerMethodField(read_only=True)
post = PostSerializer(many=True, read_only=True)
role = RoleSerializer(many=True, read_only=True)
username = serializers.CharField(required=True, max_length=150,
validators=[UniqueValidator(queryset=UserProfile.objects.all(), message="用戶已存在")],
error_messages={
"blank":"请输入用户名称",
"required":"用户名称不能为空",
"max_length":"用户名称过长",
})
def get_admin(self, obj: UserProfile):
role_list = obj.role.all().values_list('admin', flat=True)
if True in list(set(role_list)):
return True
return False
def validate(self, attrs: dict):
return super().validate(attrs)
def save(self, **kwargs):
self.validated_data['dept_id'] = self.initial_data.get('deptId',None)
data = super().save(**kwargs)
data.set_password(self.initial_data.get('password',None))
data.save()
data.post.set(self.initial_data.get('postIds'))
data.role.set(self.initial_data.get('roleIds'))
return data
class Meta:
model = UserProfile
exclude = ('password', 'secret', 'user_permissions', 'groups', 'is_superuser', 'date_joined')
read_only_fields = ('dept',)

View File

@ -1,7 +1,8 @@
from django.urls import re_path
from rest_framework.routers import DefaultRouter
from apps.permission.views import MenuModelViewSet, DeptModelViewSet, PostModelViewSet, RoleModelViewSet
from apps.permission.views import MenuModelViewSet, DeptModelViewSet, PostModelViewSet, RoleModelViewSet, \
UserProfileModelViewSet
router = DefaultRouter()
router.register(r'menus', MenuModelViewSet)
@ -9,6 +10,7 @@ router.register(r'dept', DeptModelViewSet)
router.register(r'dept/exclude', DeptModelViewSet)
router.register(r'post', PostModelViewSet)
router.register(r'role', RoleModelViewSet)
router.register(r'user', UserProfileModelViewSet)
urlpatterns = [
re_path('dept/exclude/(?P<pk>.*)/', DeptModelViewSet.as_view({'get': 'exclude_list'})),
@ -18,6 +20,11 @@ urlpatterns = [
re_path('menus/roleMenuTreeselect/(?P<pk>.*)/', MenuModelViewSet.as_view({'get': 'role_menu_tree_select'})),
# 根据角色ID查询部门树结构
re_path('dept/roleDeptTreeselect/(?P<pk>.*)/', DeptModelViewSet.as_view({'get': 'role_dept_tree_select'})),
# 更新状态
re_path('user/changeStatus/', UserProfileModelViewSet.as_view({'put': 'change_status'})),
# 获取用户详情
re_path('user/details/', UserProfileModelViewSet.as_view({'get': 'get_user_details'})),
re_path('user/resetPwd/', UserProfileModelViewSet.as_view({'put': 'reset_pwd'})),
]
urlpatterns += router.urls

View File

@ -5,11 +5,12 @@ from rest_framework.response import Response
from rest_framework.views import APIView
from apps.op_drf.viewsets import CustomModelViewSet
from apps.permission.filters import MenuFilter, DeptFilter, PostFilter, RoleFilter
from apps.permission.models import Role, Menu, Dept, Post
from apps.permission.filters import MenuFilter, DeptFilter, PostFilter, RoleFilter, UserProfileFilter
from apps.permission.models import Role, Menu, Dept, Post, UserProfile
from apps.permission.serializers import UserProfileSerializer, MenuSerializer, RoleSerializer, \
MenuCreateUpdateSerializer, DeptSerializer, DeptCreateUpdateSerializer, PostSerializer, PostCreateUpdateSerializer, \
RoleCreateUpdateSerializer, DeptTreeSerializer, MenuTreeSerializer
RoleCreateUpdateSerializer, DeptTreeSerializer, MenuTreeSerializer, UserProfileCreateUpdateSerializer, \
PostSimpleSerializer, RoleSimpleSerializer
from utils.response import SuccessResponse
@ -184,3 +185,74 @@ class RoleModelViewSet(CustomModelViewSet):
# create_extra_permission_classes = (IsManagerPermission,)
search_fields = ('roleName',)
ordering = 'create_datetime' # 默认排序
class UserProfileModelViewSet(CustomModelViewSet):
"""
用户管理 的CRUD视图
"""
queryset = UserProfile.objects.all()
serializer_class = UserProfileSerializer
create_serializer_class = UserProfileCreateUpdateSerializer
update_serializer_class = UserProfileCreateUpdateSerializer
filter_class = UserProfileFilter
# update_extra_permission_classes = (IsManagerPermission,)
# destroy_extra_permission_classes = (IsManagerPermission,)
# create_extra_permission_classes = (IsManagerPermission,)
search_fields = ('username',)
ordering = 'create_datetime' # 默认排序
def change_status(self, request: Request, *args, **kwargs):
"""
修改用户状态
:param request:
:param args:
:param kwargs:
:return:
"""
instance = self.queryset.get(id=request.data.get('userId'))
instance.is_active = request.data.get('status')
instance.save()
serializer = self.get_serializer(instance)
if hasattr(self, 'handle_logging'):
self.handle_logging(request, instance=instance, *args, **kwargs)
return SuccessResponse(serializer.data)
def get_user_details(self, request: Request, *args, **kwargs):
"""
获取用户详情
:param request:
:param args:
:param kwargs:
:return:
"""
userId = request.query_params.get('userId')
data = {
'posts': PostSimpleSerializer(Post.objects.all().order_by('postSort'), many=True).data,
'roles': RoleSimpleSerializer(Role.objects.all().order_by('roleSort'), many=True).data
}
if userId:
instance = self.queryset.get(id=userId)
serializer = self.get_serializer(instance)
data['data'] = serializer.data
data['postIds'] = [ele.get('id') for ele in serializer.data.get('post')]
data['roleIds'] = [ele.get('id') for ele in serializer.data.get('role')]
if hasattr(self, 'handle_logging'):
self.handle_logging(request, instance=instance, *args, **kwargs)
return SuccessResponse(data)
def reset_pwd(self, request: Request, *args, **kwargs):
"""
重置密码
:param request:
:param args:
:param kwargs:
:return:
"""
instance = self.queryset.get(id=request.data.get('userId'))
serializer = self.get_serializer(instance)
instance.set_password(request.data.get('password'))
instance.save()
if hasattr(self, 'handle_logging'):
self.handle_logging(request, instance=instance, *args,**kwargs)
return SuccessResponse(serializer.data)

View File

@ -1,10 +1,10 @@
import request from '@/utils/request'
import { praseStrEmpty } from "@/utils/ruoyi";
import {praseStrEmpty} from "@/utils/ruoyi";
// 查询用户列表
export function listUser(query) {
return request({
url: '/system/user/list',
url: '/permission/user/',
method: 'get',
params: query
})
@ -13,7 +13,7 @@ export function listUser(query) {
// 查询用户详细
export function getUser(userId) {
return request({
url: '/system/user/' + praseStrEmpty(userId),
url: '/permission/user/details/?userId=' + praseStrEmpty(userId) ,
method: 'get'
})
}
@ -21,7 +21,7 @@ export function getUser(userId) {
// 新增用户
export function addUser(data) {
return request({
url: '/system/user',
url: '/permission/user/',
method: 'post',
data: data
})
@ -30,7 +30,7 @@ export function addUser(data) {
// 修改用户
export function updateUser(data) {
return request({
url: '/system/user',
url: '/permission/user/' + data.id + '/',
method: 'put',
data: data
})
@ -39,7 +39,7 @@ export function updateUser(data) {
// 删除用户
export function delUser(userId) {
return request({
url: '/system/user/' + userId,
url: '/permission/user/' + userId + '/',
method: 'delete'
})
}
@ -47,7 +47,7 @@ export function delUser(userId) {
// 导出用户
export function exportUser(query) {
return request({
url: '/system/user/export',
url: '/permission/user/export/',
method: 'get',
params: query
})
@ -60,7 +60,7 @@ export function resetUserPwd(userId, password) {
password
}
return request({
url: '/system/user/resetPwd',
url: '/permission/user/resetPwd/',
method: 'put',
data: data
})
@ -73,7 +73,7 @@ export function changeUserStatus(userId, status) {
status
}
return request({
url: '/system/user/changeStatus',
url: '/permission/user/changeStatus/',
method: 'put',
data: data
})
@ -82,7 +82,7 @@ export function changeUserStatus(userId, status) {
// 查询用户个人信息
export function getUserProfile() {
return request({
url: '/system/user/profile',
url: '/permission/user/profile/',
method: 'get'
})
}
@ -90,7 +90,7 @@ export function getUserProfile() {
// 修改用户个人信息
export function updateUserProfile(data) {
return request({
url: '/system/user/profile',
url: '/permission/user/profile',
method: 'put',
data: data
})
@ -103,7 +103,7 @@ export function updateUserPwd(oldPassword, newPassword) {
newPassword
}
return request({
url: '/system/user/profile/updatePwd',
url: '/permission/user/profile/updatePwd/',
method: 'put',
params: data
})
@ -112,7 +112,7 @@ export function updateUserPwd(oldPassword, newPassword) {
// 用户头像上传
export function uploadAvatar(data) {
return request({
url: '/system/user/profile/avatar',
url: '/permission/user/profile/avatar',
method: 'post',
data: data
})
@ -121,7 +121,7 @@ export function uploadAvatar(data) {
// 下载用户导入模板
export function importTemplate() {
return request({
url: '/system/user/importTemplate',
url: '/permission/user/importTemplate',
method: 'get'
})
}

View File

@ -28,9 +28,9 @@
<!--用户数据-->
<el-col :span="20" :xs="24">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="用户名称" prop="userName">
<el-form-item label="用户名称" prop="username">
<el-input
v-model="queryParams.userName"
v-model="queryParams.username"
placeholder="请输入用户名称"
clearable
size="small"
@ -38,9 +38,9 @@
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-form-item label="手机号码" prop="mobile">
<el-input
v-model="queryParams.phonenumber"
v-model="queryParams.mobile"
placeholder="请输入手机号码"
clearable
size="small"
@ -48,9 +48,9 @@
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-form-item label="状态" prop="is_active">
<el-select
v-model="queryParams.status"
v-model="queryParams.is_active"
placeholder="用户状态"
clearable
size="small"
@ -64,7 +64,7 @@
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-form-item label="创建时间" v-if="false">
<el-date-picker
v-model="dateRange"
size="small"
@ -140,17 +140,15 @@
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
<el-table-column label="用户编号" align="center" key="id" prop="id" v-if="columns[0].visible" />
<el-table-column label="用户名称" align="center" key="username" prop="username" v-if="columns[1].visible" :show-overflow-tooltip="true" />
<el-table-column label="用户昵称" align="center" key="name" prop="name" v-if="columns[2].visible" :show-overflow-tooltip="true" />
<el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible" :show-overflow-tooltip="true" />
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
<el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
<el-table-column label="手机号码" align="center" key="mobile" prop="mobile" v-if="columns[4].visible" width="120" />
<el-table-column label="状态" align="center" key="is_active" v-if="columns[5].visible">
<template slot-scope="scope">
<el-switch
v-model="scope.row.status"
active-value="0"
inactive-value="1"
v-model="scope.row.is_active"
@change="handleStatusChange(scope.row)"
></el-switch>
</template>
@ -175,7 +173,7 @@
v-hasPermi="['system:user:edit']"
>修改</el-button>
<el-button
v-if="scope.row.userId !== 1"
v-if="scope.row.id !== 1"
size="mini"
type="text"
icon="el-icon-delete"
@ -208,8 +206,8 @@
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="12">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入用户昵称" />
<el-form-item label="用户昵称" prop="name">
<el-input v-model="form.name" placeholder="请输入用户昵称" />
</el-form-item>
</el-col>
<el-col :span="12">
@ -220,8 +218,8 @@
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
<el-form-item label="手机号码" prop="mobile">
<el-input v-model="form.mobile" placeholder="请输入手机号码" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
@ -232,12 +230,12 @@
</el-row>
<el-row>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
<el-input v-model="form.userName" placeholder="请输入用户名称" />
<el-form-item v-if="form.id == undefined" label="用户名称" prop="username">
<el-input v-model="form.username" placeholder="请输入用户名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
<el-form-item v-if="form.id == undefined" label="用户密码" prop="password">
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" />
</el-form-item>
</el-col>
@ -257,7 +255,7 @@
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio-group v-model="form.is_active">
<el-radio
v-for="dict in statusOptions"
:key="dict.dictValue"
@ -273,9 +271,9 @@
<el-select v-model="form.postIds" multiple placeholder="请选择">
<el-option
v-for="item in postOptions"
:key="item.postId"
:key="item.id"
:label="item.postName"
:value="item.postId"
:value="item.id"
:disabled="item.status == 1"
></el-option>
</el-select>
@ -286,9 +284,9 @@
<el-select v-model="form.roleIds" multiple placeholder="请选择">
<el-option
v-for="item in roleOptions"
:key="item.roleId"
:key="item.id"
:label="item.roleName"
:value="item.roleId"
:value="item.id"
:disabled="item.status == 1"
></el-option>
</el-select>
@ -381,7 +379,7 @@ export default {
//
dateRange: [],
//
statusOptions: [],
statusOptions: [{dictLabel: '正常', dictValue: true,}, {dictLabel: '停用', dictValue: false,}],
//
sexOptions: [],
//
@ -413,9 +411,9 @@ export default {
queryParams: {
pageNum: 1,
pageSize: 10,
userName: undefined,
phonenumber: undefined,
status: undefined,
username: undefined,
mobile: undefined,
is_active: undefined,
deptId: undefined
},
//
@ -430,10 +428,10 @@ export default {
],
//
rules: {
userName: [
username: [
{ required: true, message: "用户名称不能为空", trigger: "blur" }
],
nickName: [
name: [
{ required: true, message: "用户昵称不能为空", trigger: "blur" }
],
password: [
@ -446,7 +444,7 @@ export default {
trigger: ["blur", "change"]
}
],
phonenumber: [
mobile: [
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
@ -465,9 +463,9 @@ export default {
created() {
this.getList();
this.getTreeselect();
this.getDicts("sys_normal_disable").then(response => {
this.statusOptions = response.data;
});
// this.getDicts("sys_normal_disable").then(response => {
// this.statusOptions = response.data;
// });
this.getDicts("sys_user_sex").then(response => {
this.sexOptions = response.data;
});
@ -480,8 +478,8 @@ export default {
getList() {
this.loading = true;
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows;
this.total = response.total;
this.userList = response.data.results;
this.total = response.data.count;
this.loading = false;
}
);
@ -489,7 +487,7 @@ export default {
/** 查询部门下拉树结构 */
getTreeselect() {
treeselect().then(response => {
this.deptOptions = response.data;
this.deptOptions = this.handleTree(response.data,'id');
});
},
//
@ -504,17 +502,17 @@ export default {
},
//
handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用";
this.$confirm('确认要"' + text + '""' + row.userName + '"用户吗?', "警告", {
let text = row.is_active === true ? "启用" : "停用";
this.$confirm('确认要"' + text + '""' + row.username + '"用户吗?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return changeUserStatus(row.userId, row.status);
return changeUserStatus(row.id, row.is_active);
}).then(() => {
this.msgSuccess(text + "成功");
}).catch(function() {
row.status = row.status === "0" ? "1" : "0";
row.is_active = row.is_active === false ? true : false;
});
},
//
@ -525,15 +523,15 @@ export default {
//
reset() {
this.form = {
userId: undefined,
id: undefined,
deptId: undefined,
userName: undefined,
nickName: undefined,
username: undefined,
name: undefined,
password: undefined,
phonenumber: undefined,
mobile: undefined,
email: undefined,
sex: undefined,
status: "0",
is_active: false,
remark: undefined,
postIds: [],
roleIds: []
@ -548,12 +546,13 @@ export default {
/** 重置按钮操作 */
resetQuery() {
this.dateRange = [];
this.queryParams.deptId = ''
this.resetForm("queryForm");
this.handleQuery();
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.userId);
this.ids = selection.map(item => item.id);
this.single = selection.length != 1;
this.multiple = !selection.length;
},
@ -562,8 +561,8 @@ export default {
this.reset();
this.getTreeselect();
getUser().then(response => {
this.postOptions = response.posts;
this.roleOptions = response.roles;
this.postOptions = response.data.posts;
this.roleOptions = response.data.roles;
this.open = true;
this.title = "添加用户";
this.form.password = this.initPassword;
@ -573,13 +572,13 @@ export default {
handleUpdate(row) {
this.reset();
this.getTreeselect();
const userId = row.userId || this.ids;
getUser(userId).then(response => {
this.form = response.data;
this.postOptions = response.posts;
this.roleOptions = response.roles;
this.form.postIds = response.postIds;
this.form.roleIds = response.roleIds;
const id = row.id || this.ids;
getUser(id).then(response => {
this.form = response.data.data;
this.postOptions = response.data.posts;
this.roleOptions = response.data.roles;
this.form.postIds = response.data.postIds;
this.form.roleIds = response.data.roleIds;
this.open = true;
this.title = "修改用户";
this.form.password = "";
@ -587,11 +586,11 @@ export default {
},
/** 重置密码按钮操作 */
handleResetPwd(row) {
this.$prompt('请输入"' + row.userName + '"的新密码', "提示", {
this.$prompt('请输入"' + row.username + '"的新密码', "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消"
}).then(({ value }) => {
resetUserPwd(row.userId, value).then(response => {
resetUserPwd(row.id, value).then(response => {
this.msgSuccess("修改成功,新密码是:" + value);
});
}).catch(() => {});
@ -600,7 +599,7 @@ export default {
submitForm: function() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.userId != undefined) {
if (this.form.id != undefined) {
updateUser(this.form).then(response => {
this.msgSuccess("修改成功");
this.open = false;
@ -618,7 +617,7 @@ export default {
},
/** 删除按钮操作 */
handleDelete(row) {
const userIds = row.userId || this.ids;
const userIds = row.id || this.ids;
this.$confirm('是否确认删除用户编号为"' + userIds + '"的数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",