!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
parent
b715eff90d
commit
9970eed34d
24
README.md
24
README.md
|
@ -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
|
||||||
|
~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 演示图
|
## 演示图
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'))
|
||||||
|
|
|
@ -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
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
|
|
|
@ -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) # 导出、用户上传.
|
||||||
|
|
|
@ -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':
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
## 发布
|
## 发布
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -7,7 +7,8 @@ const user = {
|
||||||
name: '',
|
name: '',
|
||||||
avatar: '',
|
avatar: '',
|
||||||
roles: [],
|
roles: [],
|
||||||
permissions: []
|
permissions: [],
|
||||||
|
unread_msg_count: 0
|
||||||
},
|
},
|
||||||
|
|
||||||
mutations: {
|
mutations: {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue