!13 发布1.0正式版本前合并

* 修复BUG(docker 部署): docker-compose.yml 提交修改
* 文档(文档提交): README.md 文档
* 文档(文档修改): README.md 文档修改
* 修复BUG(添加依赖): 添加依赖 psutil==5.8.0
* 修复BUG(通知消息): 添加通知消息未发布状态过滤
* Merge branch 'dvadmin-liqianglog' of https://gitee.com/liqianglog/djan…
* 修复BUG(个人信息): 个人信息中未读消息显示数量错误
* 功能变化(获取路由接口): admin用户菜单可查看全部,便于开发
* 修复BUG(用户管理): 个人修改密码bug,UserProfile模型添加数据创建人
* update dvadmin-backend/apps/vadmin/op_drf/middleware.py.
* update dvadmin-backend/apps/vadmin/op_drf/middleware.py.
* 修复BUG(个人信息&通知公告): 个人未读通知公告数量错误
* 修复BUG(中间件bug): 日志中间件存入模块信息不全
* Merge remote-tracking branch 'remotes/origin/master' into dvadmin-liqianglog
* 修复BUG(提交错误): DEMO_ENV
* Merge remote-tracking branch 'remotes/origin/dvadmin-liqianglog' into …
* 修复BUG(中间件bug): 日志中间件存入模块信息不全
* !11 修复多个bug
* 修复BUG(中间件bug): 日志中间件存入模块信息不全
* !10 后端接口权限验证bug修改
* 测试(部署测试):
* 修复BUG(文件上传): doc,docx,xlsx文件都无法上传成功
* 修复BUG(删除部门): 部门里面存在用户,依然能够删除部门
pull/13/MERGE
李强 2021-04-01 00:11:04 +08:00
parent b715eff90d
commit 9970eed34d
19 changed files with 103 additions and 52 deletions

View File

@ -12,26 +12,25 @@ Django-Vue-Admin 是一套全部开源的快速开发平台,毫无保留给个
* 后端采用Python语言Django框架。 * 后端采用Python语言Django框架。
* 权限认证使用Jwt支持多终端认证系统。 * 权限认证使用Jwt支持多终端认证系统。
* 支持加载动态权限菜单,多方式轻松权限控制。 * 支持加载动态权限菜单,多方式轻松权限控制。
* ~~高效率开发,使用代码生成器可以一键生成前后端代码。~~ * 特别鸣谢:<u>[Gin-Vue-Admin](https://www.gin-vue-admin.com/)</u>[RuoYi](https://gitee.com/y_project/RuoYi-Vue) [Vue-Element-Admin](https://github.com/PanJiaChen/vue-element-admin)[eladmin-web](https://gitee.com/elunez/eladmin-web?_from=gitee_search)。
* 特别鸣谢:[RuoYi](https://gitee.com/y_project/RuoYi-Vue) [Vue-Element-Admin](https://github.com/PanJiaChen/vue-element-admin)[eladmin-web](https://gitee.com/elunez/eladmin-web?_from=gitee_search)[Gin-Vue-Admin](https://www.gin-vue-admin.com/)。
## QQ群 ## QQ群
- QQ群号812482043 - QQ群号812482043
- 由于项目正在启步阶段第一版预计3月底发后序会慢慢维护其他版本有什么不到位的请大家担待~ - 二维码
<img src='https://gitee.com/liqianglog/django-vue-admin/raw/master/dvadmin-ui/src/assets/images/qq.jpg' width='200'> <img src='https://gitee.com/liqianglog/django-vue-admin/raw/master/dvadmin-ui/src/assets/images/qq.jpg' width='200'>
## 源码地址 ## 源码地址
gitee地址[https://gitee.com/liqianglog/django-vue-admin](https://gitee.com/liqianglog/django-vue-admin) gitee地址(主推)[https://gitee.com/liqianglog/django-vue-admin](https://gitee.com/liqianglog/django-vue-admin)
github地址[https://github.com/liqianglog/django-vue-admin](https://github.com/liqianglog/django-vue-admin) github地址[https://github.com/liqianglog/django-vue-admin](https://github.com/liqianglog/django-vue-admin)
## 内置功能 ## 内置功能
##### 预计3月底发布v1.0正式版本,个别功能开发中 [版本功能说明](https://gitee.com/liqianglog/django-vue-admin/wikis/releaseNote?sort_id=3615540) ##### 后期版本 [版本功能说明](https://gitee.com/liqianglog/django-vue-admin/wikis/releaseNote?sort_id=3615540)
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
@ -119,6 +118,21 @@ npm run build:prod
后端接口文档地址http://127.0.0.1:8000/docs/ 后端接口文档地址http://127.0.0.1:8000/docs/
~~~ ~~~
### docker-compose 运行
~~~shell
# 先安装docker-compose (自行百度安装),执行此命令等待安装
docker-compose up
# 初始化后端数据(第一次执行即可)
docker exec -ti dvadmin-django bash
python manage.py init -y
exit
前端地址http://127.0.0.1:8080
后端地址http://127.0.0.1:8000
账号admin 密码123456
~~~
## 演示图 ## 演示图

View File

@ -23,6 +23,7 @@ services:
npm install --registry=https://registry.npm.taobao.org npm install --registry=https://registry.npm.taobao.org
rm -rf /dvadmin-ui/dist rm -rf /dvadmin-ui/dist
npm run build:prod npm run build:prod
npm run dev
dvadmin-redis: dvadmin-redis:

View File

@ -54,7 +54,6 @@ INSTALLED_APPS = [
] ]
MIDDLEWARE = [ MIDDLEWARE = [
'vadmin.op_drf.middleware.PermissionModeMiddleware', # 权限中间件
'corsheaders.middleware.CorsMiddleware', 'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
@ -64,6 +63,7 @@ MIDDLEWARE = [
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'vadmin.op_drf.middleware.ApiLoggingMiddleware', # 用于记录API访问日志 'vadmin.op_drf.middleware.ApiLoggingMiddleware', # 用于记录API访问日志
'vadmin.op_drf.middleware.PermissionModeMiddleware', # 权限中间件
] ]
# 允许跨域源 # 允许跨域源
CORS_ORIGIN_ALLOW_ALL = CORS_ORIGIN_ALLOW_ALL CORS_ORIGIN_ALLOW_ALL = CORS_ORIGIN_ALLOW_ALL

View File

@ -1,6 +1,7 @@
""" """
django中间件 django中间件
""" """
import json
import logging import logging
import os import os
@ -11,7 +12,7 @@ from django.utils.deprecation import MiddlewareMixin
from apps.vadmin.permission.models import Menu from apps.vadmin.permission.models import Menu
from apps.vadmin.system.models import OperationLog from apps.vadmin.system.models import OperationLog
from ..utils.request_util import get_request_ip, get_request_data, get_request_path, get_browser, get_os, \ from ..utils.request_util import get_request_ip, get_request_data, get_request_path, get_browser, get_os, \
get_login_location, get_request_canonical_path, get_request_user get_login_location, get_request_canonical_path, get_request_user, get_verbose_name
from ..utils.response import ErrorJsonResponse from ..utils.response import ErrorJsonResponse
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -42,9 +43,16 @@ class ApiLoggingMiddleware(MiddlewareMixin):
body['password'] = '*' * len(body['password']) body['password'] = '*' * len(body['password'])
if not hasattr(response, 'data') or not isinstance(response.data, dict): if not hasattr(response, 'data') or not isinstance(response.data, dict):
response.data = {} response.data = {}
if not response.data and response.content:
try:
content = json.loads(response.content.decode())
response.data = content if isinstance(content, dict) else {}
except:
pass
user = get_request_user(request)
info = { info = {
'request_ip': getattr(request, 'request_ip', 'unknown'), 'request_ip': getattr(request, 'request_ip', 'unknown'),
'creator': request.user, 'creator': user if not isinstance(user, AnonymousUser) else None,
'dept_belong_id': getattr(request.user, 'dept_id', None), 'dept_belong_id': getattr(request.user, 'dept_id', None),
'request_method': request.method, 'request_method': request.method,
'request_path': request.request_path, 'request_path': request.request_path,
@ -58,11 +66,14 @@ class ApiLoggingMiddleware(MiddlewareMixin):
'json_result': {"code": response.data.get('code'), "msg": response.data.get('msg')}, 'json_result': {"code": response.data.get('code'), "msg": response.data.get('msg')},
'request_modular': request.session.get('model_name'), 'request_modular': request.session.get('model_name'),
} }
if isinstance(request.user, AnonymousUser):
info['creator'] = None
log = OperationLog(**info) log = OperationLog(**info)
log.save() log.save()
def process_view(self, request, view_func, view_args, view_kwargs):
if hasattr(view_func, 'cls') and hasattr(view_func.cls, 'queryset'):
request.session['model_name'] = get_verbose_name(view_func.cls.queryset)
return
def process_request(self, request): def process_request(self, request):
self.__handle_request(request) self.__handle_request(request)
@ -85,14 +96,7 @@ class PermissionModeMiddleware(MiddlewareMixin):
""" """
def process_request(self, request): def process_request(self, request):
""" return
判断环境变量中是否为演示模式(正常可忽略此判断)
:param request:
:return:
"""
white_list = ['/admin/logout/', '/admin/login/']
if os.getenv('DEMO_ENV') and not request.method == 'GET' and request.path not in white_list:
return ErrorJsonResponse(data={}, msg=f'演示模式,不允许操作!')
def has_interface_permission(self, request, method, view_path, user=None): def has_interface_permission(self, request, method, view_path, user=None):
""" """
@ -130,18 +134,23 @@ class PermissionModeMiddleware(MiddlewareMixin):
if user.is_superuser or (hasattr(user, 'role') and user.role.filter(status='1', admin=True).count()): if user.is_superuser or (hasattr(user, 'role') and user.role.filter(status='1', admin=True).count()):
return 20 return 20
# (3)user的角色有该接口权限, 是:通过, 否:不通过 # (3)user的角色有该接口权限, 是:通过, 否:不通过
if view_path in user.get_user_interface_dict: if view_path in user.get_user_interface_dict.get(method, []):
return 30 return 30
return -10 return -10
def process_view(self, request, view_func, view_args, view_kwargs): def process_view(self, request, view_func, view_args, view_kwargs):
# 判断环境变量中,是否为演示模式(正常可忽略此判断)
white_list = ['/admin/logout/', '/admin/login/']
if os.getenv('DEMO_ENV') and not request.method in ['GET', 'OPTIONS'] and request.path not in white_list:
return ErrorJsonResponse(data={}, msg=f'演示模式,不允许操作!')
if not settings.INTERFACE_PERMISSION: if not settings.INTERFACE_PERMISSION:
return return
user = get_request_user(request) user = get_request_user(request)
if user and not isinstance(user, AnonymousUser): if user and not isinstance(user, AnonymousUser):
method = request.method.upper() method = request.method.upper()
if method == 'GET': # GET 不设置接口权限 if method == 'GET': # GET 不设置接口权限
return return
view_path = get_request_canonical_path(request, *view_args, **view_kwargs) view_path = get_request_canonical_path(request, *view_args, **view_kwargs)
auth_code = self.has_interface_permission(request, method, view_path, user) auth_code = self.has_interface_permission(request, method, view_path, user)

View File

@ -4,10 +4,10 @@ from django.contrib.auth.models import UserManager, AbstractUser
from django.core.cache import cache from django.core.cache import cache
from django.db.models import IntegerField, ForeignKey, CharField, TextField, ManyToManyField, CASCADE from django.db.models import IntegerField, ForeignKey, CharField, TextField, ManyToManyField, CASCADE
from ...op_drf.fields import CreateDateTimeField, UpdateDateTimeField from ...op_drf.models import CoreModel
class UserProfile(AbstractUser): class UserProfile(AbstractUser, CoreModel):
USER_TYPE_CHOICES = ( USER_TYPE_CHOICES = (
(0, "后台用户"), (0, "后台用户"),
(1, "前台用户"), (1, "前台用户"),
@ -25,9 +25,6 @@ class UserProfile(AbstractUser):
post = ManyToManyField(to='Post', verbose_name='关联岗位', db_constraint=False) post = ManyToManyField(to='Post', verbose_name='关联岗位', db_constraint=False)
role = ManyToManyField(to='Role', verbose_name='关联角色', db_constraint=False) role = ManyToManyField(to='Role', verbose_name='关联角色', db_constraint=False)
dept = ForeignKey(to='Dept', verbose_name='归属部门', on_delete=CASCADE, db_constraint=False, null=True, blank=True) dept = ForeignKey(to='Dept', verbose_name='归属部门', on_delete=CASCADE, db_constraint=False, null=True, blank=True)
dept_belong_id = CharField(max_length=64, verbose_name="数据归属部门", null=True, blank=True)
create_datetime = CreateDateTimeField()
update_datetime = UpdateDateTimeField()
@property @property
def get_user_interface_dict(self): def get_user_interface_dict(self):
@ -52,6 +49,7 @@ class UserProfile(AbstractUser):
:return: :return:
""" """
return cache.delete(f'permission_interface_dict_{self.username}') return cache.delete(f'permission_interface_dict_{self.username}')
class Meta: class Meta:
verbose_name = '用户管理' verbose_name = '用户管理'
verbose_name_plural = verbose_name verbose_name_plural = verbose_name

View File

@ -93,3 +93,23 @@ class CommonPermission(CustomPermission):
self.message = f"没有此数据操作权限!" self.message = f"没有此数据操作权限!"
res = self.check_queryset(request, instance) res = self.check_queryset(request, instance)
return res return res
class DeptDestroyPermission(CustomPermission):
"""
部门删除权限校验判断部门下是否有用户存在存在不可删除
"""
message = '没有有操作权限'
def has_permission(self, request: Request, view: APIView):
return True
def check_queryset(self, request, instance):
if instance.values_list('userprofile', flat=True):
self.message = "该部门下有关联用户,无法删除!"
return False
return True
def has_object_permission(self, request: Request, view: APIView, instance):
res = self.check_queryset(request, instance)
return res

View File

@ -226,8 +226,8 @@ class UserProfileSerializer(CustomModelSerializer):
return False return False
def get_unread_msg_count(self, obj: UserProfile): def get_unread_msg_count(self, obj: UserProfile):
return MessagePush.objects.filter(status='2').exclude(user=obj, return MessagePush.objects.filter(status='2').exclude(messagepushuser_message_push__is_read=True,
messagepushuser_message_push__is_read=True).count() messagepushuser_message_push__user=obj).count()
class Meta: class Meta:
model = UserProfile model = UserProfile

View File

@ -2,7 +2,7 @@ from django.contrib.auth import authenticate
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.views import APIView from rest_framework.views import APIView
from .permissions import CommonPermission from .permissions import CommonPermission, DeptDestroyPermission
from ..op_drf.filters import DataLevelPermissionsFilter from ..op_drf.filters import DataLevelPermissionsFilter
from ..op_drf.viewsets import CustomModelViewSet from ..op_drf.viewsets import CustomModelViewSet
from ..permission.filters import MenuFilter, DeptFilter, PostFilter, RoleFilter, UserProfileFilter from ..permission.filters import MenuFilter, DeptFilter, PostFilter, RoleFilter, UserProfileFilter
@ -48,7 +48,10 @@ class GetRouters(APIView):
return dict return dict
def get(self, request, format=None): def get(self, request, format=None):
menus = Menu.objects.filter(role__userprofile=request.user) \ kwargs = {}
if not request.user.is_superuser:
kwargs['role__userprofile'] = request.user
menus = Menu.objects.filter(**kwargs) \
.exclude(menuType='2').values('id', 'name', 'web_path', 'visible', 'status', 'isFrame', 'component_path', .exclude(menuType='2').values('id', 'name', 'web_path', 'visible', 'status', 'isFrame', 'component_path',
'icon', 'parentId', 'orderNum', 'isCache').distinct() 'icon', 'parentId', 'orderNum', 'isCache').distinct()
data = [] data = []
@ -129,7 +132,7 @@ class DeptModelViewSet(CustomModelViewSet):
filter_class = DeptFilter filter_class = DeptFilter
extra_filter_backends = [DataLevelPermissionsFilter] extra_filter_backends = [DataLevelPermissionsFilter]
update_extra_permission_classes = (CommonPermission,) update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,) destroy_extra_permission_classes = (CommonPermission, DeptDestroyPermission)
create_extra_permission_classes = (CommonPermission,) create_extra_permission_classes = (CommonPermission,)
search_fields = ('deptName',) search_fields = ('deptName',)
ordering = 'create_datetime' # 默认排序 ordering = 'create_datetime' # 默认排序
@ -359,7 +362,7 @@ class UserProfileModelViewSet(CustomModelViewSet):
:return: :return:
""" """
instance = self.queryset.get(id=request.user.id) instance = self.queryset.get(id=request.user.id)
instance.mobile = request.data.get('newPassword', None) instance.password = request.data.get('newPassword', None)
if not authenticate(username=request.user.username, password=request.data.get('oldPassword', None)): if not authenticate(username=request.user.username, password=request.data.get('oldPassword', None)):
return ErrorResponse(msg='旧密码不正确!') return ErrorResponse(msg='旧密码不正确!')
instance.set_password(request.data.get('newPassword')) instance.set_password(request.data.get('newPassword'))

View File

@ -33,8 +33,8 @@
-- ---------------------------- -- ----------------------------
-- Records of permission_userprofile -- Records of permission_userprofile
-- ---------------------------- -- ----------------------------
INSERT INTO `permission_userprofile` (id, password, last_login, is_superuser, first_name, last_name, is_staff, is_active, date_joined, username, secret, email, mobile, avatar, name, gender, remark, user_type, create_datetime, update_datetime, dept_id, dept_belong_id) VALUES (1, 'pbkdf2_sha256$150000$OjTMSXJgkzrE$jEQCjWbIbXwpN4k2z0o8Yvou1UQGuoJALyL/kGDZFd4=', '2021-02-27 06:20:28.214775', 1, '', '', 1, 1, '2021-02-27 06:20:09.188689', 'admin', '3704adf3-380f-4c27-a8da-60420e8cb4ab', 'admin@qq.com', NULL, NULL, '管理员', '2', '1', 2, '2021-02-27 06:20:09.263192', '2021-02-27 09:14:30.009998', 8, 1); INSERT INTO `permission_userprofile` (id, password, last_login, is_superuser, first_name, last_name, is_staff, is_active, date_joined, username, secret, email, mobile, avatar, name, gender, remark, user_type, create_datetime, update_datetime, dept_id, dept_belong_id, creator_id) VALUES (1, 'pbkdf2_sha256$150000$OjTMSXJgkzrE$jEQCjWbIbXwpN4k2z0o8Yvou1UQGuoJALyL/kGDZFd4=', '2021-02-27 06:20:28.214775', 1, '', '', 1, 1, '2021-02-27 06:20:09.188689', 'admin', '3704adf3-380f-4c27-a8da-60420e8cb4ab', 'admin@qq.com', NULL, NULL, '管理员', '2', '1', 2, '2021-02-27 06:20:09.263192', '2021-02-27 09:14:30.009998', 1, 1, 1);
INSERT INTO `permission_userprofile` (id, password, last_login, is_superuser, first_name, last_name, is_staff, is_active, date_joined, username, secret, email, mobile, avatar, name, gender, remark, user_type, create_datetime, update_datetime, dept_id, dept_belong_id) VALUES (2, 'pbkdf2_sha256$150000$5Z9LSi7LpNms$xVguE/dOEpI4D95LjSaKm0xzG7vNSopUolANr8f/6/E=', NULL, 0, '', '', 0, 1, '2021-03-03 15:38:27.009893', 'dvadmin', 'b4c5d79a-f01c-4244-92f8-b5288eca1d50', NULL, NULL, NULL, '普通用户', '2', NULL, 0, '2021-03-03 15:38:27.010771', '2021-03-03 15:38:27.086069', 8, 1); INSERT INTO `permission_userprofile` (id, password, last_login, is_superuser, first_name, last_name, is_staff, is_active, date_joined, username, secret, email, mobile, avatar, name, gender, remark, user_type, create_datetime, update_datetime, dept_id, dept_belong_id, creator_id) VALUES (2, 'pbkdf2_sha256$150000$5Z9LSi7LpNms$xVguE/dOEpI4D95LjSaKm0xzG7vNSopUolANr8f/6/E=', NULL, 0, '', '', 0, 1, '2021-03-03 15:38:27.009893', 'dvadmin', 'b4c5d79a-f01c-4244-92f8-b5288eca1d50', NULL, NULL, NULL, '普通用户', '2', NULL, 0, '2021-03-03 15:38:27.010771', '2021-03-03 15:38:27.086069', 1, 1, 1);
-- ---------------------------- -- ----------------------------
-- Table structure for permission_userprofile_post -- Table structure for permission_userprofile_post
-- ---------------------------- -- ----------------------------

View File

@ -13,7 +13,7 @@ def files_path(instance, filename):
class SaveFile(CoreModel): class SaveFile(CoreModel):
name = CharField(max_length=128, verbose_name="文件名称", null=True, blank=True) name = CharField(max_length=128, verbose_name="文件名称", null=True, blank=True)
type = CharField(max_length=32, verbose_name="文件类型", null=True, blank=True) type = CharField(max_length=200, verbose_name="文件类型", null=True, blank=True)
size = CharField(max_length=64, verbose_name="文件大小", null=True, blank=True) size = CharField(max_length=64, verbose_name="文件大小", null=True, blank=True)
address = CharField(max_length=16, verbose_name="存储位置", null=True, blank=True) # 本地、阿里云、腾讯云.. address = CharField(max_length=16, verbose_name="存储位置", null=True, blank=True) # 本地、阿里云、腾讯云..
source = CharField(max_length=16, verbose_name="文件来源", null=True, blank=True) # 导出、用户上传. source = CharField(max_length=16, verbose_name="文件来源", null=True, blank=True) # 导出、用户上传.

View File

@ -202,7 +202,7 @@ class MessagePushModelViewSet(CustomModelViewSet):
serializer_class = MessagePushSerializer serializer_class = MessagePushSerializer
create_serializer_class = MessagePushCreateUpdateSerializer create_serializer_class = MessagePushCreateUpdateSerializer
update_serializer_class = MessagePushCreateUpdateSerializer update_serializer_class = MessagePushCreateUpdateSerializer
extra_filter_backends = [DataLevelPermissionsFilter] # extra_filter_backends = [DataLevelPermissionsFilter]
update_extra_permission_classes = (CommonPermission,) update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,) destroy_extra_permission_classes = (CommonPermission,)
create_extra_permission_classes = (CommonPermission,) create_extra_permission_classes = (CommonPermission,)
@ -217,6 +217,7 @@ class MessagePushModelViewSet(CustomModelViewSet):
获取用户自己消息列表 获取用户自己消息列表
""" """
queryset = self.filter_queryset(self.get_queryset()) queryset = self.filter_queryset(self.get_queryset())
queryset = queryset.filter(status=2)
is_read = request.query_params.get('is_read', None) is_read = request.query_params.get('is_read', None)
if is_read: if is_read:
if is_read == 'False': if is_read == 'False':

View File

@ -12,8 +12,8 @@ from django.utils.translation import ugettext as _
from rest_framework import exceptions from rest_framework import exceptions
from rest_framework_jwt.utils import jwt_decode_handler from rest_framework_jwt.utils import jwt_decode_handler
from .decorators import exceptionHandler
from .jwt_util import jwt_get_session_id from .jwt_util import jwt_get_session_id
from ..permission.models.users import UserProfile
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
User = get_user_model() User = get_user_model()
@ -38,6 +38,8 @@ class OpAuthJwtAuthentication(object):
raise exceptions.AuthenticationFailed(msg) raise exceptions.AuthenticationFailed(msg)
except jwt.InvalidTokenError: except jwt.InvalidTokenError:
raise exceptions.AuthenticationFailed() raise exceptions.AuthenticationFailed()
except UserProfile.DoesNotExist:
raise exceptions.AuthenticationFailed()
username = payload.get('username', None) username = payload.get('username', None)
if not username: if not username:

View File

@ -65,8 +65,6 @@ def op_exception_handler(ex, context):
""" """
msg = '' msg = ''
code = '201' code = '201'
request = context.get('request')
request.session['model_name'] = str(get_verbose_name(view=context.get('view')))
if isinstance(ex, AuthenticationFailed): if isinstance(ex, AuthenticationFailed):
code = 401 code = 401

View File

@ -26,3 +26,4 @@ xlrd==2.0.1
coreapi==2.3.3 coreapi==2.3.3
user-agents==2.2.0 user-agents==2.2.0
eventlet==0.30.2 eventlet==0.30.2
psutil==5.8.0

View File

@ -2,22 +2,22 @@
```bash ```bash
# 克隆项目 # 克隆项目
git clone https://gitee.com/y_project/RuoYi-Vue git clone https://gitee.com/liqianglog/django-vue-admin.git
# 进入项目目录 # 进入项目目录
cd ruoyi-ui cd dvadmin-ui
# 安装依赖 # 安装依赖
npm install
# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
npm install --registry=https://registry.npm.taobao.org npm install --registry=https://registry.npm.taobao.org
# 启动服务 # 启动服务
npm run dev npm run dev
# 浏览器访问 http://localhost:8080
# .env.development 文件中可配置启动端口等参数
``` ```
浏览器访问 http://localhost:80 浏览器访问 http://localhost:8080
## 发布 ## 发布

View File

@ -14,7 +14,7 @@
<div class="right-menu-item hover-effect"> <div class="right-menu-item hover-effect">
<router-link to="/user/msg"> <router-link to="/user/msg">
<i class="el-icon-message-solid badge-item-icon"></i> <i class="el-icon-message-solid badge-item-icon"></i>
<el-badge :value="count" :max="99" style="margin-left: -4px;" v-if="count"> <el-badge :value="unread_msg_count" :max="99" style="margin-left: -4px;" v-if="unread_msg_count">
</el-badge> </el-badge>
</router-link> </router-link>
</div> </div>
@ -81,11 +81,11 @@ export default {
}, },
data() { data() {
return { return {
count: store.getters.unread_msg_count, count: store.unread_msg_count,
}; };
}, },
computed: { computed: {
...mapGetters(["sidebar", "avatar", "device"]), ...mapGetters(["sidebar", "avatar", "device", "unread_msg_count"]),
setting: { setting: {
get() { get() {
return this.$store.state.settings.showSettings; return this.$store.state.settings.showSettings;

View File

@ -7,7 +7,8 @@ const user = {
name: '', name: '',
avatar: '', avatar: '',
roles: [], roles: [],
permissions: [] permissions: [],
unread_msg_count: 0
}, },
mutations: { mutations: {

View File

@ -161,7 +161,7 @@
<i class="el-icon-arrow-down el-icon--right"></i> <i class="el-icon-arrow-down el-icon--right"></i>
</span> </span>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="role in scope.row.role">{{role.roleName}}</el-dropdown-item> <el-dropdown-item v-for="(role,index) in scope.row.role" :key="index">{{role.roleName}}</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
</template> </template>
@ -648,6 +648,7 @@
this.$refs['form'].validate(valid => { this.$refs['form'].validate(valid => {
if (valid) { if (valid) {
if (this.form.id != undefined) { if (this.form.id != undefined) {
this.form.creator = undefined
updateUser(this.form).then(response => { updateUser(this.form).then(response => {
this.msgSuccess('修改成功') this.msgSuccess('修改成功')
this.open = false this.open = false

View File

@ -103,9 +103,11 @@
// //
if (this.badgeType === "danger") { if (this.badgeType === "danger") {
updateIsRead(this.showingMsgItem).then(response => { updateIsRead(this.showingMsgItem).then(response => {
store.getters.unread_msg_count if(response.code === 200){
this.open = false; store.commit('SET_UNREAD_MSG_COUNT', store.getters.unread_msg_count - 1);
this.getList(); this.open = false;
this.getList();
}
}); });
} }
} }