优化后台管理用户管理功能

This commit is contained in:
yangjian 2021-05-28 22:28:41 +08:00
parent c3e2b174e2
commit 4c323f142e
7 changed files with 410 additions and 138 deletions

View File

@ -24,7 +24,7 @@ sitemaps = SitemapAll()
urlpatterns = [
path('',include('app_doc.urls')), # doc应用
path('user/',include('app_admin.urls'),), # admin应用
path('admin/',include('app_admin.urls'),), # admin应用
path('api/',include('app_api.urls')), # 用户 Token API 接口
path('api_app/',include('app_api.urls_app')), # RESTFUL API 接口
re_path('^static/(?P<path>.*)$',serve,{'document_root':settings.STATIC_ROOT}),# 静态文件

View File

@ -2,18 +2,22 @@ from django.urls import path,re_path
from app_admin import views
urlpatterns = [
path('login/',views.log_in,name='login'),# 登录
path('logout/',views.log_out,name='logout'),# 注销
path('register/',views.register,name="register"), # 注册
path('user_manage/',views.admin_user,name="user_manage"), # 用户管理
path('create_user/',views.admin_create_user,name="create_user"), # 新建用户
path('del_user/',views.admin_del_user,name='del_user'), # 删除用户
path('change_pwd',views.admin_change_pwd,name="change_pwd"), # 管理员修改用户密码
path('modify_pwd',views.change_pwd,name="modify_pwd"), # 普通用户修改密码
path('login/',views.log_in,name='login'), # 登录
path('logout/',views.log_out,name='logout'), # 注销
path('register/',views.register,name="register"), # 注册
path('user_manage/',views.admin_user,name="user_manage"), # 用户管理页面
path('user_profile/',views.admin_user_profile, name="user_profile"), # 用户资料页面
path('api/users', views.AdminUserList.as_view(), name="api_admin_users"), # 用户列表接口
path('api/user/<int:id>',views.AdminUserDetail.as_view(), name="api_admin_user"), # 用户接口
path('modify_pwd',views.change_pwd,name="modify_pwd"), # 普通用户修改密码
path('project_manage/',views.admin_project,name='project_manage'), # 文集管理
path('project_role_manage/<int:pro_id>/',views.admin_project_role,name="admin_project_role"), # 管理文集权限
path('project_manage_istop',views.admin_project_istop,name="admin_project_istop"), # 修改文集置顶状态
path('project_del/', views.admin_project_delete, name="admin_project_del"), # 删除文集
path('project_del/',views.admin_project_delete,name="admin_project_del"), # 删除文集
path('doc_manage/',views.admin_doc,name='doc_manage'), # 文档管理
path('doctemp_manage/',views.admin_doctemp,name='doctemp_manage'), # 文档模板管理
path('setting/',views.admin_setting,name="sys_setting"), # 应用设置

View File

@ -10,6 +10,14 @@ from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from rest_framework.views import APIView # 视图
from rest_framework.response import Response # 响应
from rest_framework.pagination import PageNumberPagination # 分页
from rest_framework.authentication import SessionAuthentication # 认证
from rest_framework.permissions import IsAdminUser # 权限
from app_api.serializers_app import *
from app_api.auth_app import AppAuth,AppMustAuth # 自定义认证
from app_api.permissions_app import SuperUserPermission # 自定义权限
from app_admin.decorators import superuser_only,open_register
from app_doc.models import *
from app_admin.models import *
@ -69,7 +77,7 @@ def log_in(request):
errormsg = _('用户名或密码错误!')
return render(request, 'login.html', locals())
else:
errormsg = _('用户名或密码错误')
errormsg = _('用户名或密码未输入')
return render(request, 'login.html', locals())
except Exception as e:
logger.exception("登录异常")
@ -259,73 +267,67 @@ def admin_overview(request):
else:
pass
# 后台管理 - 用户管理
# 后台管理 - 用户管理HTML
@superuser_only
@logger.catch()
@require_GET
def admin_user(request):
if request.method == 'GET':
return render(request, 'app_admin/admin_user.html', locals())
elif request.method == 'POST':
username = request.POST.get('username','')
page = request.POST.get('page', 1)
limit = request.POST.get('limit', 10)
return render(request, 'app_admin/admin_user.html', locals())
# 后台管理 - 用户管理 - 用户资料编辑HTML
def admin_user_profile(request):
return render(request, 'app_admin/admin_user_profile.html',locals())
# 后台管理 - 用户列表接口
class AdminUserList(APIView):
authentication_classes = [SessionAuthentication,AppMustAuth]
permission_classes = [SuperUserPermission]
# 获取用户列表
def get(self, request):
username = request.query_params.get('username', '')
page_num = request.query_params.get('page', 1)
limit = request.query_params.get('limit', 10)
if username == '':
user_data = User.objects.all().values(
'id','last_login','is_superuser','username','email','date_joined','is_active','first_name'
'id', 'last_login', 'is_superuser', 'username', 'email', 'date_joined', 'is_active', 'first_name'
)
else:
user_data = User.objects.filter(username__icontains=username).values(
'id','last_login','is_superuser','username','email','date_joined','is_active','first_name'
'id', 'last_login', 'is_superuser', 'username', 'email', 'date_joined', 'is_active', 'first_name'
)
# 分页处理
paginator = Paginator(user_data, limit)
page = request.GET.get('page', page)
try:
users = paginator.page(page)
except PageNotAnInteger:
users = paginator.page(1)
except EmptyPage:
users = paginator.page(paginator.num_pages)
page = PageNumberPagination() # 实例化一个分页器
page.page_size = limit
page_users = page.paginate_queryset(user_data, request, view=self) # 进行分页查询
serializer = UserSerializer(page_users, many=True) # 对分页后的结果进行序列化处理
resp = {
'code': 0,
'data': serializer.data,
'count': user_data.count()
}
table_data = []
for i in users:
item = {
'id':i['id'],
'last_login':i['last_login'],
'is_superuser':i['is_superuser'],
'username':i['username'],
'email':i['email'],
'date_joined':i['date_joined'],
'is_active':i['is_active'],
'first_name':i['first_name'],
}
table_data.append(item)
return JsonResponse({'code':0,'data':table_data,"count": user_data.count()})
else:
return JsonResponse({'code':1,'msg':_('方法错误')})
return Response(resp)
# 后台管理 - 创建用户
@superuser_only
@logger.catch()
def admin_create_user(request):
if request.method == 'POST':
username = request.POST.get('username','') # 接收用户名参数
email = request.POST.get('email','') # 接收email参数
password = request.POST.get('password','') # 接收密码参数
user_type = request.POST.get('user_type',0) # 用户类型 0为普通用户1位管理员
# 新增用户
def post(self, request):
username = request.data.get('username', '') # 接收用户名参数
email = request.data.get('email', '') # 接收email参数
password = request.data.get('password', '') # 接收密码参数
user_type = request.data.get('user_type', 0) # 用户类型 0为普通用户1位管理员
# 用户名只能为英文小写或数字且大于等于5位密码大于等于6位
if len(username) >= 5 and \
len(password) >= 6 and \
'@' in email and \
re.match(r'^[0-9a-z]',username):
re.match(r'^[0-9a-z]', username):
# 不允许电子邮箱重复
if User.objects.filter(email = email).count() > 0:
return JsonResponse({'status':False,'data':_('电子邮箱不可重复')})
if User.objects.filter(email=email).count() > 0:
return JsonResponse({'status': False, 'data': _('电子邮箱不可重复')})
# 不允许重复的用户名
if User.objects.filter(username = username).count() > 0:
return JsonResponse({'status': False,'data':_('用户名不可重复')})
if User.objects.filter(username=username).count() > 0:
return JsonResponse({'status': False, 'data': _('用户名不可重复')})
try:
if user_type == 0:
user = User.objects.create_user(
@ -341,62 +343,111 @@ def admin_create_user(request):
email=email
)
user.save()
return JsonResponse({'status':True})
return Response({'code': 0})
except Exception as e:
return JsonResponse({'status':False,'data':_('系统异常')})
return Response({'code': 4, 'data': _('系统异常')})
else:
return JsonResponse({'status':False,'data':_('请检查参数')})
else:
return HttpResponse(_('方法不允许'))
return JsonResponse({'code': 5, 'data': _('请检查参数')})
# 后台管理 - 修改密码
@superuser_only
@logger.catch()
def admin_change_pwd(request):
if request.method == 'POST':
# 后台管理 - 用户接口
class AdminUserDetail(APIView):
authentication_classes = [SessionAuthentication,AppMustAuth]
permission_classes = [SuperUserPermission]
def get_object(self, id):
try:
user_id = request.POST.get('user_id',None)
password = request.POST.get('password',None)
password2 = request.POST.get('password2',None)
if user_id and password:
if password == password2:
user = User.objects.get(id=int(user_id))
user.set_password(password)
user.save()
return JsonResponse({'status':True,'data':_('修改成功')})
return User.objects.get(id=id)
except ObjectDoesNotExist:
raise Http404
# 获取用户
def get(self,request, id):
user = self.get_object(id)
serializer = UserSerializer(user)
resp = {
'code': 0,
'data': serializer.data,
}
return Response(resp)
# 修改用户(资料、密码)
def put(self, request, id):
obj = request.data.get('obj','')
if obj.replace(' ','') == '':
resp = {
'code':5,
'data':'无效类型'
}
return Response(resp)
elif obj == 'info': # 修改资料
status = request.POST.get('is_active', '') # 状态
username = request.POST.get('username', '') # 用户名
nickname = request.POST.get('nickname', '') # 昵称
email = request.POST.get('email', '') # 电子邮箱
is_superuser = request.POST.get('is_superuser', '') # 是否超级管理员
try:
User.objects.filter(id=id).update(
username = username,
first_name = nickname,
email = email,
is_active = True if status == 'on' else False,
is_superuser = True if is_superuser == 'true' else False
)
return Response({'code': 0, 'data': _('修改成功')})
except:
logger.exception("修改用户资料异常")
return Response({'code': 4, 'data': _('修改异常')})
elif obj == 'pwd': # 修改密码
try:
password = request.data.get('password', None)
password2 = request.data.get('password2', None)
if id and password:
if password == password2:
user = User.objects.get(id=int(id))
user.set_password(password)
user.save()
return Response({'code': 0, 'data': _('修改成功')})
else:
return Response({'code': 5, 'data': _('两个密码不一致')})
else:
return JsonResponse({'status':False,'data':_('两个密码不一致')})
else:
return JsonResponse({'status':False,'data':_('参数错误')})
except Exception as e:
print(repr(e))
return JsonResponse({'status':False,'data':_('请求错误')})
else:
return JsonResponse({'status':False,'data':_('方法错误')})
return JsonResponse({'code': 5, 'data': _('参数错误')})
except Exception as e:
return JsonResponse({'code': 4, 'data': _('请求错误')})
else:
resp = {
'code': 5,
'data': '无效类型'
}
return Response(resp)
# 后台管理 - 删除用户
@superuser_only
@logger.catch()
def admin_del_user(request):
if request.method == 'POST':
# 删除用户
def delete(self, request, id):
try:
user_id = request.POST.get('user_id',None) # 获取用户ID
user = User.objects.get(id=int(user_id)) # 获取用户
colloas = ProjectCollaborator.objects.filter(user=user) # 获取参与协作的文集
user = self.get_object(id) # 获取用户
colloas = ProjectCollaborator.objects.filter(user=user) # 获取参与协作的文集
# 遍历用户参与协作的文集
for colloa in colloas:
# 查询出用户协作创建的文档,修改作者为文集所有者
Doc.objects.filter(
top_doc=colloa.project.id,create_user=user
top_doc=colloa.project.id, create_user=user
).update(create_user=colloa.project.create_user)
user.delete()
return JsonResponse({'status':True,'data':_('删除成功')})
resp = {
'code':0,
'data':_('删除成功')
}
return Response(resp)
except Exception as e:
return JsonResponse({'status':False,'data':_('删除出错')})
else:
return JsonResponse({'status':False,'data':_('方法错误')})
logger.exception("删除用户出错")
resp = {
'code': 4,
'data': _('删除出错')
}
return Response(resp)
# 后台管理 - 文集管理
@ -526,7 +577,6 @@ def admin_project_delete(request):
return JsonResponse({'status':False,'data':_('请求出错')})
# 后台管理 - 控制文集置顶状态
@superuser_only
@require_POST

View File

@ -7,6 +7,15 @@
from rest_framework.permissions import BasePermission,SAFE_METHODS
from django.utils.translation import gettext_lazy as _
# 超级管理员权限
class SuperUserPermission(BasePermission):
message = _('无权访问')
def has_permission(self, request, view):
return bool(request.user and request.user.is_superuser)
class AppPermission(BasePermission):
message = _('只有VIP才能访问')

View File

@ -8,6 +8,15 @@ from rest_framework import serializers
from rest_framework.serializers import ModelSerializer,SerializerMethodField
from app_doc.models import *
# 用户序列化器
class UserSerializer(ModelSerializer):
class Meta:
model = User
fields = (
'id', 'last_login', 'is_superuser', 'username', 'email', 'date_joined', 'is_active', 'first_name'
)
# 文集序列化器
class ProjectSerializer(ModelSerializer):
create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M')

View File

@ -22,7 +22,7 @@
</div>
</div>
<div class="layui-row">
<table class="layui-table" id="user-list"></table>
<table class="layui-table" id="user-list" lay-filter="user-table"></table>
</div>
</div>
</div>
@ -64,8 +64,9 @@
<!-- 用户操作模板 -->
<script type="text/html" id="userOpera">
{% verbatim %}
<a class="layui-table-link" href="javascript:void(0);" onclick="changePwd('{{ d.id }}','{{ d.username }}')">修改密码</a>&nbsp;&nbsp;
<a class="layui-table-link" href="javascript:void(0);" onclick="delUser('{{ d.id }}','{{ d.username }}')">删除用户</a>
<a class="layui-table-link" href="javascript:void(0);" onclick="changeInfo('{{ d.id }}','{{ d.username }}')">编辑</a>&nbsp;&nbsp;
<!-- <a class="layui-table-link" href="javascript:void(0);" onclick="changePwd('{{ d.id }}','{{ d.username }}')">修改密码</a>&nbsp;&nbsp; -->
<a class="layui-table-link" href="javascript:void(0);" onclick="delUser('{{ d.id }}','{{ d.username }}')">删除</a>
{% endverbatim %}
</script>
<script>
@ -77,12 +78,13 @@
let element = layui.element;
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
headers: {"X-CSRFToken":'{{ csrf_token }}'},
});
//获取用户列表,执行表格渲染
table.render({
elem: '#user-list',
url: "{% url 'user_manage' %}",
method:'post',
url: "{% url 'api_admin_users' %}",
method:'get',
where:{
'username':$("#username").val(),
},
@ -116,11 +118,11 @@
'password':$("#password").val(),
'email':$("#email").val()
}
$.post("{% url 'create_user' %}",data,function(r){
layer.closeAll('loading');
if(r.status){
$.post("{% url 'api_admin_users' %}",data,function(r){
layer.closeAll();
if(r.code === 0){
//创建成功,刷新页面
window.location.reload();
table.reload('user-list');
}else{
//创建失败,提示
// console.log(r)
@ -148,11 +150,11 @@
'email':$("#email2").val(),
'user_type':1,
}
$.post("{% url 'create_user' %}",data,function(r){
layer.closeAll('loading');
if(r.status){
$.post("{% url 'api_admin_users' %}",data,function(r){
layer.closeAll();
if(r.code === 0){
//创建成功,刷新页面
window.location.reload();
table.reload('user-list');
}else{
//创建失败,提示
// console.log(r)
@ -174,25 +176,38 @@
yes:function (index,layero) {
layer.load();
data = {
'user_id':uid,
'obj':'pwd',
'password':$("#newPwd1").val(),
'password2':$("#newPwd2").val(),
}
$.post("{% url 'change_pwd' %}",data,function(r){
layer.closeAll('loading');
if(r.status){
//修改成功
window.location.reload();
//layer.close(index)
}else{
//修改失败,提示
//console.log(r)
$.ajax({
url:'/admin/api/user/'+uid,
type:'put',
data:data,
success:function(r){
layer.closeAll();
if(r.code === 0){
//删除成功
layer.msg(r.data)
// table.reload('user-list',{page:{curr:1}});
}else{
//删除失败,提示
//console.log(r)
layer.msg(r.data)
}
},
error:function(){
layer.closeAll();
layer.msg(r.data)
}
})
});
},
})
};
// 修改用户资料
changeInfo = function(uid,username){
location.href = "{% url 'user_profile' %}?id="+uid
};
//删除用户
delUser = function(uid,username){
layer.open({
@ -205,21 +220,25 @@
btnAlign:'c', //按钮居中
yes:function (index,layero) {
layer.load(1);
data = {
'user_id':uid,
}
$.post("{% url 'del_user' %}",data,function(r){
layer.closeAll('loading');
if(r.status){
//删除成功
window.location.reload();
//layer.close(index)
}else{
//删除失败,提示
//console.log(r)
$.ajax({
url:'/admin/api/user/'+uid,
type:'delete',
success:function(r){
layer.closeAll();
if(r.code === 0){
//删除成功
table.reload('user-list',{page:{curr:1}});
}else{
//删除失败,提示
//console.log(r)
layer.msg(r.data)
}
},
error:function(){
layer.closeAll();
layer.msg(r.data)
}
})
});
},
});
};

View File

@ -0,0 +1,181 @@
{% extends 'app_admin/admin_base.html' %}
{% load static %}
{% load i18n %}
{% block title %}{% trans "用户资料设置" %}{% endblock %}
{% block content %}
<div class="layui-card">
<div class="layui-card-header">
<span class="layui-breadcrumb" lay-separator="-">
<a href="{% url 'user_manage' %}">用户管理</a>
<a><cite>用户资料编辑</cite></a>
</span>
</div>
<div class="layui-card-body">
<div class="layui-form" lay-filter="user-profile">
<div class="layui-form-item">
<label class="layui-form-label">{% trans "用户名" %}</label>
<div class="layui-input-inline">
<input type="text" name="username" disabled autocomplete="off" class="layui-input" >
</div>
<div class="layui-form-mid layui-word-aux">{% trans "不可修改" %}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">{% trans "昵称" %}</label>
<div class="layui-input-inline">
<input type="text" name="nickname" id="first_name" required lay-verify="required" placeholder="{% trans '请输入昵称' %}" autocomplete="off" class="layui-input" value="{{user.first_name}}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">{% trans "电子邮箱" %}</label>
<div class="layui-input-inline">
<input type="email" name="email" id="email" required lay-verify="required" placeholder="{% trans '请输入电子邮箱地址' %}" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">{% trans "用户状态" %}</label>
<div class="layui-input-inline">
<input type="checkbox" name="is_active" lay-skin="switch" lay-text="启用|停用">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">{% trans "用户角色" %}</label>
<div class="layui-input-inline">
<select name="is_superuser" lay-verify="">
<option value=""></option>
<option value="false">普通用户</option>
<option value="true">超级管理员</option>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">{% trans "新密码" %}</label>
<div class="layui-form-mid layui-word-aux"><button class="layui-btn layui-btn-primary layui-btn-xs" onclick="changePwd();">{% trans "点击修改密码" %}</button></div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="pear-btn pear-btn-primary" onclick="updateUser();">{% trans "更新用户资料" %}</button>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_script %}
<script>
layui.use(['table', 'form', 'jquery', 'dtree', 'element','layer'], function() {
let table = layui.table;
let form = layui.form;
let $ = layui.jquery;
let dtree = layui.dtree;
var element = layui.element;
var layer = layui.layer;
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
headers: {"X-CSRFToken":'{{ csrf_token }}'},
});
// URL参数解析
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
};
var user_id = getQueryVariable("id");
// 获取用户资料
getUserProfile = function(){
$.ajax({
url:'/admin/api/user/'+user_id,
type:'get',
success:function(r){
if(r.code === 0){
form.val("user-profile",{
"username":r.data.username,
"nickname":r.data.first_name,
"email":r.data.email,
"is_active":r.data.is_active,
"is_superuser":r.data.is_superuser?'true':'false',
})
}else{
layer.msg("用户资料获取出错")
}
},
error:function(){
layer.msg("用户资料获取异常")
}
})
};
getUserProfile();
//修改用户密码
changePwd = function(uid,username){
layer.open({
type:1,
title:'修改密码',
area:'300px;',
id:'changePwd',
content:'<div style="padding:10px 0 0 20px;">修改用户的密码:</div><div style="padding: 20px;"><input class="layui-input" type="password" id="newPwd1" style="margin-bottom:10px;" placeholder="输入新密码" required lay-verify="required"><input class="layui-input" type="password" id="newPwd2" placeholder="再次确认新密码" required lay-verify="required"></div>',
btn:['确认修改','取消'],
yes:function (index,layero) {
layer.load();
data = {
'obj':'pwd',
'password':$("#newPwd1").val(),
'password2':$("#newPwd2").val(),
}
$.ajax({
url:'/admin/api/user/'+user_id,
type:'put',
data:data,
success:function(r){
layer.closeAll();
if(r.code === 0){
//修改成功
layer.msg(r.data)
}else{
//修改失败,提示
layer.msg(r.data)
}
},
error:function(){
layer.closeAll();
layer.msg(r.data)
}
});
},
})
};
// 更新用户选项
updateUser = function(){
layer.load();
let data = form.val('user-profile')
data['obj'] = 'info'
// console.log(data)
$.ajax({
url:'/admin/api/user/'+user_id,
type:'put',
data:data,
success:function(r){
layer.closeAll();
if(r.code === 0){
//删除成功
layer.msg(r.data)
}else{
//删除失败,提示
layer.msg(r.data)
}
},
error:function(){
layer.closeAll();
layer.msg(r.data)
}
});
}
});
</script>
{% endblock %}