From d88e03ca8907fe5de0ec0f119e9464f8c5128ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BC=BA?= <1206709430@qq.com> Date: Sat, 20 Mar 2021 15:47:16 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=85=A5=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dvadmin-backend/apps/vadmin/logurus/test.py | 31 ++++++++ dvadmin-backend/apps/vadmin/op_drf/mixins.py | 74 +++++++++++++++++++ .../apps/vadmin/op_drf/viewsets.py | 4 +- .../apps/vadmin/permission/serializers.py | 23 ++++++ .../apps/vadmin/permission/urls.py | 11 ++- .../apps/vadmin/permission/views.py | 37 +++++----- .../apps/vadmin/utils/exceptions.py | 4 +- .../apps/vadmin/utils/export_excel.py | 41 ++++++++-- dvadmin-backend/requirements.txt | 1 + dvadmin-ui/src/api/vadmin/permission/user.js | 15 +++- .../src/components/FileUpload/index.vue | 2 +- .../views/vadmin/permission/user/index.vue | 32 +++++--- 12 files changed, 232 insertions(+), 43 deletions(-) create mode 100644 dvadmin-backend/apps/vadmin/logurus/test.py diff --git a/dvadmin-backend/apps/vadmin/logurus/test.py b/dvadmin-backend/apps/vadmin/logurus/test.py new file mode 100644 index 0000000..d48c393 --- /dev/null +++ b/dvadmin-backend/apps/vadmin/logurus/test.py @@ -0,0 +1,31 @@ +from logging import StreamHandler, getLevelName +from logging.handlers import RotatingFileHandler +from typing import Optional, IO + + +class MyStreamHandler(StreamHandler): + + def __init__(self, stream: Optional[IO[str]] = ...) -> None: + print(222) + super().__init__(stream) + + def __repr__(self): + level = getLevelName(self.level) + name = getattr(self.stream, 'name', '') + # bpo-36015: name can be an int + name = str(name) + if name: + name += ' ' + print(111) + return '<%s %s(%s)>' % (self.__class__.__name__, name, level) +class MyRotatingFileHandler(RotatingFileHandler): + + def __init__(self, filename: str, mode: str = ..., maxBytes: int = ..., backupCount: int = ..., + encoding: Optional[str] = ..., delay: bool = ...) -> None: + print(4444) + super().__init__(filename, mode, maxBytes, backupCount, encoding, delay) + + def __repr__(self): + level = getLevelName(self.level) + print(22) + return '<%s %s (%s)>' % (self.__class__.__name__, self.baseFilename, level) diff --git a/dvadmin-backend/apps/vadmin/op_drf/mixins.py b/dvadmin-backend/apps/vadmin/op_drf/mixins.py index cd9aba3..5bc65ef 100644 --- a/dvadmin-backend/apps/vadmin/op_drf/mixins.py +++ b/dvadmin-backend/apps/vadmin/op_drf/mixins.py @@ -1,3 +1,4 @@ +from django.db import transaction from rest_framework import mixins from rest_framework import serializers from rest_framework import status @@ -5,6 +6,7 @@ from rest_framework.relations import ManyRelatedField, RelatedField, PrimaryKeyR from rest_framework.request import Request from .response import SuccessResponse +from ..utils.export_excel import excel_to_data, export_excel_save_model class CreateModelMixin(mixins.CreateModelMixin): @@ -271,3 +273,75 @@ class TableSerializerMixin: info['type'] = 'select' column.append(info) return column + + +class ImportSerializerMixin: + """ + 自定义导出模板、导入功能 + """ + # 导入字段 + import_field_data = {} + # 导入序列化器 + import_serializer_class = None + + + @transaction.atomic # Django 事物 + def importTemplate(self, request: Request, *args, **kwargs): + """ + 用户导人模板 + :param request: + :param args: + :param kwargs: + :return: + """ + assert self.import_field_data, ( + "'%s' 请配置对应的导出模板字段。" + % self.__class__.__name__ + ) + # 导出模板 + if request.method == 'GET': + # 示例数据 + return SuccessResponse( + export_excel_save_model(request, self.import_field_data.values(), [], '导入用户数据模板.xls')) + updateSupport = request.data.get('updateSupport') + # 从excel中组织对应的数据结构,然后使用序列化器保存 + data = excel_to_data(request.data.get('file_url'), self.import_field_data) + unique_list = [ele.attname for ele in self.get_queryset().model._meta.get_fields() if + hasattr(ele, 'unique') and ele.unique == True] + for ele in data: + # 获取 unique 字段 + filter_dic = {i: ele.get(i) for i in list(set(self.import_field_data.keys()) & set(unique_list))} + instance = self.get_queryset().filter(**filter_dic).first() + if instance and not updateSupport: + continue + if not filter_dic: + instance = None + serializer = self.import_serializer_class(instance, data=ele) + serializer.is_valid(raise_exception=True) + serializer.save() + return SuccessResponse(msg=f"导入成功!") + + +class ExportSerializerMixin: + """ + 自定义导出功能 + """ + # 导出字段 + export_field_data = [] + # 导出序列化器 + export_serializer_class = None + + def export(self, request: Request, *args, **kwargs): + """ + 导出功能 + :param request: + :param args: + :param kwargs: + :return: + """ + assert self.export_field_data, ( + "'%s' 请配置对应的导出模板字段。" + % self.__class__.__name__ + ) + data = self.export_serializer_class(self.get_queryset(), many=True).data + return SuccessResponse(export_excel_save_model(request, self.export_field_data, data, '导出用户数据.xls')) diff --git a/dvadmin-backend/apps/vadmin/op_drf/viewsets.py b/dvadmin-backend/apps/vadmin/op_drf/viewsets.py index edd9b81..d707526 100644 --- a/dvadmin-backend/apps/vadmin/op_drf/viewsets.py +++ b/dvadmin-backend/apps/vadmin/op_drf/viewsets.py @@ -201,7 +201,9 @@ class MongoModelViewSet(mixins.CreateModelMixin, pass -class CustomModelViewSet(ModelViewSet, mixins.TableSerializerMixin): +class CustomModelViewSet(ModelViewSet, mixins.TableSerializerMixin, + mixins.ImportSerializerMixin, + mixins.ExportSerializerMixin): """ 自定义的ModelViewSet: (1)默认分页器就为统一分页器op_drf.pagination.Pagination diff --git a/dvadmin-backend/apps/vadmin/permission/serializers.py b/dvadmin-backend/apps/vadmin/permission/serializers.py index ebfb510..4e67563 100644 --- a/dvadmin-backend/apps/vadmin/permission/serializers.py +++ b/dvadmin-backend/apps/vadmin/permission/serializers.py @@ -1,4 +1,5 @@ from rest_framework import serializers +from rest_framework.fields import empty from rest_framework.validators import UniqueValidator from ..op_drf.serializers import CustomModelSerializer @@ -285,3 +286,25 @@ class UserProfileCreateUpdateSerializer(CustomModelSerializer): model = UserProfile exclude = ('password', 'secret', 'user_permissions', 'groups', 'is_superuser', 'date_joined') read_only_fields = ('dept',) + +class UserProfileImportSerializer(CustomModelSerializer): + + def save(self, **kwargs): + data = super().save(**kwargs) + data.set_password(self.initial_data.get('password', None)) + data.save() + return data + + def run_validation(self, data={}): + # 把excel 数据进行格式转换 + if type(data) is dict: + data['role'] = str(data['role']).split(',') + data['post'] = str(data['post']).split(',') + data['gender'] = {'男': '0', '女': '1', '未知': '2'}.get(data['gender']) + data['is_active'] = {'启用': True, '禁用': False}.get(data['is_active']) + return super().run_validation(data) + + + class Meta: + model = UserProfile + exclude = ('password', 'secret', 'user_permissions', 'groups', 'is_superuser', 'date_joined') diff --git a/dvadmin-backend/apps/vadmin/permission/urls.py b/dvadmin-backend/apps/vadmin/permission/urls.py index e3fd71a..cc746ac 100644 --- a/dvadmin-backend/apps/vadmin/permission/urls.py +++ b/dvadmin-backend/apps/vadmin/permission/urls.py @@ -29,13 +29,16 @@ urlpatterns = [ # 用户自己重置密码 re_path('user/profile/updatePwd/', UserProfileModelViewSet.as_view({'put': 'update_pwd'})), # 获取、更新用户个人信息 - re_path('user/profile/', UserProfileModelViewSet.as_view({'get': 'profile','put': 'put_profile'})), + re_path('user/profile/', UserProfileModelViewSet.as_view({'get': 'profile', 'put': 'put_profile'})), # 导出用户 - re_path('user/export/', UserProfileModelViewSet.as_view({'get': 'export',})), + re_path('user/export/', UserProfileModelViewSet.as_view({'get': 'export', })), # 导出角色 - re_path('role/export/', RoleModelViewSet.as_view({'get': 'export',})), + re_path('role/export/', RoleModelViewSet.as_view({'get': 'export', })), # 导出岗位 - re_path('post/export/', PostModelViewSet.as_view({'get': 'export',})), + re_path('post/export/', PostModelViewSet.as_view({'get': 'export', })), + # 用户导入模板下载及导入 + re_path('user/importTemplate/', + UserProfileModelViewSet.as_view({'get': 'importTemplate', 'post': 'importTemplate'})), ] urlpatterns += router.urls diff --git a/dvadmin-backend/apps/vadmin/permission/views.py b/dvadmin-backend/apps/vadmin/permission/views.py index d1d09e3..d82b4c6 100644 --- a/dvadmin-backend/apps/vadmin/permission/views.py +++ b/dvadmin-backend/apps/vadmin/permission/views.py @@ -2,16 +2,17 @@ from django.contrib.auth import authenticate from rest_framework.request import Request from rest_framework.views import APIView +from ..op_drf.filters import DataLevelPermissionsFilter from ..op_drf.viewsets import CustomModelViewSet from ..permission.filters import MenuFilter, DeptFilter, PostFilter, RoleFilter, UserProfileFilter from ..permission.models import Role, Menu, Dept, Post, UserProfile from ..permission.serializers import UserProfileSerializer, MenuSerializer, RoleSerializer, \ MenuCreateUpdateSerializer, DeptSerializer, DeptCreateUpdateSerializer, PostSerializer, PostCreateUpdateSerializer, \ RoleCreateUpdateSerializer, DeptTreeSerializer, MenuTreeSerializer, UserProfileCreateUpdateSerializer, \ - PostSimpleSerializer, RoleSimpleSerializer, ExportUserProfileSerializer, ExportRoleSerializer, ExportPostSerializer -from ..op_drf.filters import DataLevelPermissionsFilter + PostSimpleSerializer, RoleSimpleSerializer, ExportUserProfileSerializer, ExportRoleSerializer, ExportPostSerializer, \ + UserProfileImportSerializer from ..system.models import DictDetails -from ..utils.export_excel import export_excel_save_model +from ..utils.export_excel import export_excel_save_model, excel_to_data from ..utils.response import SuccessResponse, ErrorResponse @@ -22,7 +23,7 @@ class GetUserProfileView(APIView): def get(self, request, format=None): user_dict = UserProfileSerializer(request.user).data - permissions_list = ["*:*:*"] if user_dict.get('admin') else Menu.objects.filter( + permissions_list = ['*:*:*'] if user_dict.get('admin') else Menu.objects.filter( role__userprofile=request.user).values_list('perms', flat=True) return SuccessResponse({ 'permissions': [ele for ele in permissions_list if ele], @@ -47,14 +48,14 @@ class GetRouters(APIView): def get(self, request, format=None): # data = GetUserInfoSerializer(request.user).data - menus = Menu.objects.filter(role__userprofile=request.user).exclude(menuType="2").values('id', 'name', + menus = Menu.objects.filter(role__userprofile=request.user).exclude(menuType='2').values('id', 'name', 'web_path', 'visible', 'status', 'isFrame', 'component_path', 'icon', 'parentId', 'isCache').distinct() - # data = '{"msg":"操作成功","code":200,"data":[{"name":"System","path":"/system","hidden":false,"redirect":"noRedirect","component":"Layout","alwaysShow":true,"meta":{"title":"系统管理","icon":"system","noCache":false},"children":[{"name":"User","path":"user","hidden":false,"component":"permission/user/index","meta":{"title":"用户管理","icon":"user","noCache":false}},{"name":"Role","path":"role","hidden":false,"component":"permission/role/index","meta":{"title":"角色管理","icon":"peoples","noCache":false}},{"name":"Menu","path":"menu","hidden":false,"component":"permission/menu/index","meta":{"title":"菜单管理","icon":"tree-table","noCache":false}},{"name":"Dept","path":"dept","hidden":false,"component":"permission/dept/index","meta":{"title":"部门管理","icon":"tree","noCache":false}},{"name":"Post","path":"post","hidden":false,"component":"permission/post/index","meta":{"title":"岗位管理","icon":"post","noCache":false}},{"name":"Dict","path":"dict","hidden":false,"component":"system/dict/index","meta":{"title":"字典管理","icon":"dict","noCache":false}},{"name":"Config","path":"config","hidden":false,"component":"system/config/index","meta":{"title":"参数设置","icon":"edit","noCache":false}},{"name":"Notice","path":"notice","hidden":false,"component":"system/notice/index","meta":{"title":"通知公告","icon":"message","noCache":false}},{"name":"Log","path":"log","hidden":false,"redirect":"noRedirect","component":"ParentView","alwaysShow":true,"meta":{"title":"日志管理","icon":"log","noCache":false},"children":[{"name":"Operlog","path":"operlog","hidden":false,"component":"monitor/operlog/index","meta":{"title":"操作日志","icon":"form","noCache":false}},{"name":"Logininfor","path":"logininfor","hidden":false,"component":"monitor/logininfor/index","meta":{"title":"登录日志","icon":"logininfor","noCache":false}}]}]},{"name":"Monitor","path":"/monitor","hidden":false,"redirect":"noRedirect","component":"Layout","alwaysShow":true,"meta":{"title":"系统监控","icon":"monitor","noCache":false},"children":[{"name":"Online","path":"online","hidden":false,"component":"monitor/online/index","meta":{"title":"在线用户","icon":"online","noCache":false}},{"name":"Job","path":"job","hidden":false,"component":"monitor/job/index","meta":{"title":"定时任务","icon":"job","noCache":false}},{"name":"Druid","path":"druid","hidden":false,"component":"monitor/druid/index","meta":{"title":"数据监控","icon":"druid","noCache":false}},{"name":"Server","path":"server","hidden":false,"component":"monitor/server/index","meta":{"title":"服务监控","icon":"server","noCache":false}},{"name":"Cache","path":"cache","hidden":false,"component":"monitor/cache/index","meta":{"title":"缓存监控","icon":"redis","noCache":false}}]},{"name":"Tool","path":"/tool","hidden":false,"redirect":"noRedirect","component":"Layout","alwaysShow":true,"meta":{"title":"系统工具","icon":"tool","noCache":false},"children":[{"name":"Build","path":"build","hidden":false,"component":"tool/build/index","meta":{"title":"表单构建","icon":"build","noCache":false}},{"name":"Gen","path":"gen","hidden":false,"component":"tool/gen/index","meta":{"title":"代码生成","icon":"code","noCache":false}},{"name":"Swagger","path":"swagger","hidden":false,"component":"tool/swagger/index","meta":{"title":"系统接口","icon":"swagger","noCache":false}}]},{"name":"Http://ruoyi.vip","path":"http://ruoyi.vip","hidden":false,"component":"Layout","meta":{"title":"若依官网","icon":"guide","noCache":false}}]}' + # data = '{'msg':'操作成功','code':200,'data':[{'name':'System','path':'/system','hidden':false,'redirect':'noRedirect','component':'Layout','alwaysShow':true,'meta':{'title':'系统管理','icon':'system','noCache':false},'children':[{'name':'User','path':'user','hidden':false,'component':'permission/user/index','meta':{'title':'用户管理','icon':'user','noCache':false}},{'name':'Role','path':'role','hidden':false,'component':'permission/role/index','meta':{'title':'角色管理','icon':'peoples','noCache':false}},{'name':'Menu','path':'menu','hidden':false,'component':'permission/menu/index','meta':{'title':'菜单管理','icon':'tree-table','noCache':false}},{'name':'Dept','path':'dept','hidden':false,'component':'permission/dept/index','meta':{'title':'部门管理','icon':'tree','noCache':false}},{'name':'Post','path':'post','hidden':false,'component':'permission/post/index','meta':{'title':'岗位管理','icon':'post','noCache':false}},{'name':'Dict','path':'dict','hidden':false,'component':'system/dict/index','meta':{'title':'字典管理','icon':'dict','noCache':false}},{'name':'Config','path':'config','hidden':false,'component':'system/config/index','meta':{'title':'参数设置','icon':'edit','noCache':false}},{'name':'Notice','path':'notice','hidden':false,'component':'system/notice/index','meta':{'title':'通知公告','icon':'message','noCache':false}},{'name':'Log','path':'log','hidden':false,'redirect':'noRedirect','component':'ParentView','alwaysShow':true,'meta':{'title':'日志管理','icon':'log','noCache':false},'children':[{'name':'Operlog','path':'operlog','hidden':false,'component':'monitor/operlog/index','meta':{'title':'操作日志','icon':'form','noCache':false}},{'name':'Logininfor','path':'logininfor','hidden':false,'component':'monitor/logininfor/index','meta':{'title':'登录日志','icon':'logininfor','noCache':false}}]}]},{'name':'Monitor','path':'/monitor','hidden':false,'redirect':'noRedirect','component':'Layout','alwaysShow':true,'meta':{'title':'系统监控','icon':'monitor','noCache':false},'children':[{'name':'Online','path':'online','hidden':false,'component':'monitor/online/index','meta':{'title':'在线用户','icon':'online','noCache':false}},{'name':'Job','path':'job','hidden':false,'component':'monitor/job/index','meta':{'title':'定时任务','icon':'job','noCache':false}},{'name':'Druid','path':'druid','hidden':false,'component':'monitor/druid/index','meta':{'title':'数据监控','icon':'druid','noCache':false}},{'name':'Server','path':'server','hidden':false,'component':'monitor/server/index','meta':{'title':'服务监控','icon':'server','noCache':false}},{'name':'Cache','path':'cache','hidden':false,'component':'monitor/cache/index','meta':{'title':'缓存监控','icon':'redis','noCache':false}}]},{'name':'Tool','path':'/tool','hidden':false,'redirect':'noRedirect','component':'Layout','alwaysShow':true,'meta':{'title':'系统工具','icon':'tool','noCache':false},'children':[{'name':'Build','path':'build','hidden':false,'component':'tool/build/index','meta':{'title':'表单构建','icon':'build','noCache':false}},{'name':'Gen','path':'gen','hidden':false,'component':'tool/gen/index','meta':{'title':'代码生成','icon':'code','noCache':false}},{'name':'Swagger','path':'swagger','hidden':false,'component':'tool/swagger/index','meta':{'title':'系统接口','icon':'swagger','noCache':false}}]},{'name':'Http://ruoyi.vip','path':'http://ruoyi.vip','hidden':false,'component':'Layout','meta':{'title':'若依官网','icon':'guide','noCache':false}}]}' # data = json.loads(data) data = [] sys_show_hide = DictDetails.get_default_dictValue('sys_show_hide') @@ -66,7 +67,8 @@ class GetRouters(APIView): 'hidden': True if ele.get('visible') != '1' else False, 'redirect': ele.get('web_path') if ele.get('isFrame') == '1' else 'noRedirect', 'component': ele.get('component_path') or 'Layout', - 'meta': {"title": ele.get('name'), "icon": ele.get('icon'), "noCache": True if ele.get('isCache') == sys_show_hide else False}, + 'meta': {'title': ele.get('name'), 'icon': ele.get('icon'), + 'noCache': True if ele.get('isCache') == sys_show_hide else False}, 'parentId': ele.get('parentId') }) return SuccessResponse(data) @@ -254,6 +256,15 @@ class UserProfileModelViewSet(CustomModelViewSet): update_serializer_class = UserProfileCreateUpdateSerializer filter_class = UserProfileFilter extra_filter_backends = [DataLevelPermissionsFilter] + # 导出 + export_serializer_class = ExportUserProfileSerializer + export_field_data = ['用户序号', '登录名称', '用户名称', '用户邮箱', '手机号码', '用户性别', '帐号状态', '最后登录时间', '部门名称', '部门负责人'] + # 导入 + import_serializer_class = UserProfileImportSerializer + import_field_data = {'username': '登录账号', 'name': '用户名称', 'email': '用户邮箱', 'mobile': '手机号码', + 'gender': '用户性别(男/女/未知)', + 'is_active': '帐号状态(启用/禁用)', 'password': '登录密码', 'dept': '部门ID', 'role': '角色ID', + 'post': '岗位ID'} # update_extra_permission_classes = (IsManagerPermission,) # destroy_extra_permission_classes = (IsManagerPermission,) # create_extra_permission_classes = (IsManagerPermission,) @@ -366,15 +377,3 @@ class UserProfileModelViewSet(CustomModelViewSet): if hasattr(self, 'handle_logging'): self.handle_logging(request, instance=instance, *args, **kwargs) return SuccessResponse(serializer.data) - - def export(self, request: Request, *args, **kwargs): - """ - 导出用户 - :param request: - :param args: - :param kwargs: - :return: - """ - field_data = ['用户序号', '登录名称', '用户名称', '用户邮箱', '手机号码', '用户性别', '帐号状态', '最后登录时间', '部门名称', '部门负责人'] - data = ExportUserProfileSerializer(UserProfile.objects.all(), many=True).data - return SuccessResponse(export_excel_save_model(request, field_data, data, '导出用户数据.xls')) diff --git a/dvadmin-backend/apps/vadmin/utils/exceptions.py b/dvadmin-backend/apps/vadmin/utils/exceptions.py index c6969b7..1f38afa 100644 --- a/dvadmin-backend/apps/vadmin/utils/exceptions.py +++ b/dvadmin-backend/apps/vadmin/utils/exceptions.py @@ -2,6 +2,7 @@ import logging import traceback from rest_framework import serializers, exceptions +from rest_framework.views import set_rollback from .response import ErrorResponse @@ -67,9 +68,10 @@ def op_exception_handler(ex, context): code = 401 msg = ex.detail elif isinstance(ex, DRFAPIException): - # set_rollback() + set_rollback() msg = ex.detail elif isinstance(ex, exceptions.APIException): + set_rollback() msg = ex.detail elif isinstance(ex, Exception): logger.error(traceback.format_exc()) diff --git a/dvadmin-backend/apps/vadmin/utils/export_excel.py b/dvadmin-backend/apps/vadmin/utils/export_excel.py index bd18c5c..c6484bd 100644 --- a/dvadmin-backend/apps/vadmin/utils/export_excel.py +++ b/dvadmin-backend/apps/vadmin/utils/export_excel.py @@ -3,6 +3,7 @@ import hashlib import os import time +import xlrd import xlwt from django.conf import settings @@ -68,8 +69,8 @@ def export_excel(field_data: list, data: list, FileName: str, file_path: str = s # 确定栏位宽度 col_width = [] - for index,ele in enumerate(data): - for inx,values in enumerate(ele.values()): + for index, ele in enumerate(data): + for inx, values in enumerate(ele.values()): if index == 0: col_width.append(len_byte(str(values))) else: @@ -83,7 +84,6 @@ def export_excel(field_data: list, data: list, FileName: str, file_path: str = s else: sheet.col(i).width = 256 * (default_width) - row = 1 # 内容背景颜色 left_pattern = xlwt.Pattern() # 创建一个模式 @@ -113,7 +113,8 @@ def export_excel(field_data: list, data: list, FileName: str, file_path: str = s wbk.save(path_name) return os.path.join('system', monthTime, FileName) -def export_excel_save_model(request,field_data,data,FilName): + +def export_excel_save_model(request, field_data, data, FilName): """ 导出Excel并保存到 SaveFile 文件管理中 :param request: @@ -125,7 +126,7 @@ def export_excel_save_model(request,field_data,data,FilName): # 根据生成的字典MD5 time_stamp = hashlib.md5(str(field_data).encode('utf8')).hexdigest() # 存入文件数据库中 - FilName = str(time_stamp) + FilName + FilName = '.'.join(FilName.split('.')[:-1]) + str(time_stamp) + '.' + FilName.split('.')[-1] file_rul = export_excel(field_data=field_data, data=data, FileName=FilName) savefile, _ = SaveFile.objects.get_or_create(file=file_rul) if _ == True: @@ -137,3 +138,33 @@ def export_excel_save_model(request,field_data,data,FilName): savefile.modifier = request.user.username savefile.save() return SaveFileSerializer(savefile).data + + +def excel_to_data(file_url, field_data): + """ + 读取导入的excel文件 + :param request: + :param field_data: 首行数据源 + :param data: 数据源 + :param FilName: 文件名 + :return: + """ + # 读取excel 文件 + data = xlrd.open_workbook(os.path.join(settings.BASE_DIR, *file_url.split(os.sep))) + table = data.sheets()[0] + # 创建一个空列表,存储Excel的数据 + tables = [] + for i, rown in enumerate(range(table.nrows)): + if i == 0: continue + array = {} + for index, ele in enumerate(field_data.keys()): + cell_value = table.cell_value(rown, index) + # 由于excel导入数字类型后,会出现数字加 .0 的,进行处理 + if type(cell_value) is float and str(cell_value).split('.')[1] == '0': + cell_value = int(str(cell_value).split('.')[0]) + if type(cell_value) is str: + cell_value = cell_value.strip(' \t\n\r') + array[ele] = cell_value + + tables.append(array) + return tables diff --git a/dvadmin-backend/requirements.txt b/dvadmin-backend/requirements.txt index 953c6e4..3c2399d 100644 --- a/dvadmin-backend/requirements.txt +++ b/dvadmin-backend/requirements.txt @@ -20,6 +20,7 @@ redis==3.5.3 six==1.15.0 sqlparse==0.4.1 xlwt==1.3.0 +xlrd==2.0.1 coreapi==2.3.3 user-agents==2.2.0 eventlet==0.30.2 diff --git a/dvadmin-ui/src/api/vadmin/permission/user.js b/dvadmin-ui/src/api/vadmin/permission/user.js index 365b96d..7ab6326 100755 --- a/dvadmin-ui/src/api/vadmin/permission/user.js +++ b/dvadmin-ui/src/api/vadmin/permission/user.js @@ -13,7 +13,7 @@ export function listUser(query) { // 查询用户详细 export function getUser(userId) { return request({ - url: '/admin/permission/user/details/?userId=' + praseStrEmpty(userId) , + url: '/admin/permission/user/details/?userId=' + praseStrEmpty(userId), method: 'get' }) } @@ -112,7 +112,7 @@ export function updateUserPwd(oldPassword, newPassword) { // 用户头像上传 export function uploadAvatar(data) { return request({ - url: '/admin/permission/user/profile/avatar', + url: '/admin/permission/user/profile/avatar/', method: 'post', data: data }) @@ -121,7 +121,16 @@ export function uploadAvatar(data) { // 下载用户导入模板 export function importTemplate() { return request({ - url: '/admin/permission/user/importTemplate', + url: '/admin/permission/user/importTemplate/', method: 'get' }) } + +// 用户导入 +export function importsUser(data) { + return request({ + url: '/admin/permission/user/importTemplate/', + method: 'post', + data: data + }) +} diff --git a/dvadmin-ui/src/components/FileUpload/index.vue b/dvadmin-ui/src/components/FileUpload/index.vue index 1fe014f..8447bca 100755 --- a/dvadmin-ui/src/components/FileUpload/index.vue +++ b/dvadmin-ui/src/components/FileUpload/index.vue @@ -64,7 +64,7 @@ export default { name:'FileUpload', data() { return { - uploadFileUrl: process.env.VUE_APP_BASE_API + "/system/savefile/", // 上传的图片服务器地址 + uploadFileUrl: process.env.VUE_APP_BASE_API + "/admin/system/savefile/", // 上传的图片服务器地址 headers: { Authorization: "Bearer " + getToken(), }, diff --git a/dvadmin-ui/src/views/vadmin/permission/user/index.vue b/dvadmin-ui/src/views/vadmin/permission/user/index.vue index 13972c8..1991185 100755 --- a/dvadmin-ui/src/views/vadmin/permission/user/index.vue +++ b/dvadmin-ui/src/views/vadmin/permission/user/index.vue @@ -343,13 +343,24 @@