From 426c2fdae11a178448805b20e31710d2938685d9 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Sun, 26 Apr 2020 17:44:10 +0800 Subject: [PATCH] export --- test_client/src/api/analyse.js | 1 + test_client/src/api/crm.js | 7 +++ test_client/src/api/examtest.js | 7 +++ test_client/src/utils/request.js | 2 +- test_client/src/views/analyse/examtest.vue | 58 +++++++++++++++++++++- test_client/src/views/crm/consumer.vue | 27 +++++++--- test_server/crm/exports.py | 26 ++++++++++ test_server/crm/views.py | 12 +++-- test_server/examtest/exports.py | 26 ++++++++++ test_server/examtest/serializers.py | 17 +++++++ test_server/examtest/views.py | 12 ++++- test_server/question/views.py | 36 ++++++++------ test_server/utils/file.py | 2 +- 13 files changed, 200 insertions(+), 33 deletions(-) create mode 100644 test_server/crm/exports.py create mode 100644 test_server/examtest/exports.py diff --git a/test_client/src/api/analyse.js b/test_client/src/api/analyse.js index b452ad7..6e85016 100644 --- a/test_client/src/api/analyse.js +++ b/test_client/src/api/analyse.js @@ -6,3 +6,4 @@ export function getBasicCount() { method: 'get', }) } + diff --git a/test_client/src/api/crm.js b/test_client/src/api/crm.js index ce162f7..6149046 100644 --- a/test_client/src/api/crm.js +++ b/test_client/src/api/crm.js @@ -61,4 +61,11 @@ export function importConsumer(data) { method: 'post', data }) +} +export function exportConsumer(query) { + return request({ + url: '/crm/consumer/export', + method: 'get', + params: query + }) } \ No newline at end of file diff --git a/test_client/src/api/examtest.js b/test_client/src/api/examtest.js index 1b58d07..53879b5 100644 --- a/test_client/src/api/examtest.js +++ b/test_client/src/api/examtest.js @@ -117,4 +117,11 @@ export function deletePaper(id) { url: `/examtest/paper/${id}/`, method: 'delete', }) +} +export function exportTest(query) { + return request({ + url: '/examtest/examtest/export', + method: 'get', + params: query + }) } \ No newline at end of file diff --git a/test_client/src/utils/request.js b/test_client/src/utils/request.js index 51e1d27..e29d814 100644 --- a/test_client/src/utils/request.js +++ b/test_client/src/utils/request.js @@ -7,7 +7,7 @@ import { getToken } from '@/utils/auth' const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url // withCredentials: true, // send cookies when cross-domain requests - timeout: 10000, // request timeout + timeout: 30000, // request timeout }) // request interceptor diff --git a/test_client/src/views/analyse/examtest.vue b/test_client/src/views/analyse/examtest.vue index 44582aa..b501288 100644 --- a/test_client/src/views/analyse/examtest.vue +++ b/test_client/src/views/analyse/examtest.vue @@ -31,12 +31,23 @@ :value="item.value" /> + + 刷新重置 + 导出Excel
@@ -67,7 +78,7 @@ - + @@ -94,7 +105,7 @@ diff --git a/test_client/src/views/crm/consumer.vue b/test_client/src/views/crm/consumer.vue index c5b594f..e42f199 100644 --- a/test_client/src/views/crm/consumer.vue +++ b/test_client/src/views/crm/consumer.vue @@ -32,7 +32,7 @@ /> --> 上传导入 - Excel导入 + Excel导入 +导出Excel { + loading.close() + window.open(response.data.path, "_blank"); + }); } } }; diff --git a/test_server/crm/exports.py b/test_server/crm/exports.py new file mode 100644 index 0000000..624a786 --- /dev/null +++ b/test_server/crm/exports.py @@ -0,0 +1,26 @@ +from openpyxl.workbook import Workbook +from django.conf import settings +from datetime import datetime +from openpyxl.styles import Font, Fill + + +BASE_DIR = settings.BASE_DIR + +def export_consumer(users): + ''' + params: serializer users + return: xlsx path + ''' + wb = Workbook() + ws1 = wb.active + ws1.title = '用户表' + ws1.append(['姓名','手机号', '单位', '微信昵称', '工作类别', '创建日期']) + row = ws1.row_dimensions[1] + row.font = Font(bold=True) + for i in users: + ws1.append([i['name'], i['username'], i['company_name'], i['nickname'], i['workscope_name'], i['create_time']]) + filename = 'users' + datetime.now().strftime("%Y%m%d%H%M%S") +'.xlsx' + path = '/media/export/' + filename + wb.save((BASE_DIR + path).replace('\\', '/')) + return path + diff --git a/test_server/crm/views.py b/test_server/crm/views.py index d6769a6..48b5fdf 100644 --- a/test_server/crm/views.py +++ b/test_server/crm/views.py @@ -5,6 +5,7 @@ from calendar import timegm from datetime import datetime import requests +from django.db.models import Q from django_filters.rest_framework import DjangoFilterBackend from openpyxl import Workbook, load_workbook from rest_framework import status @@ -15,7 +16,8 @@ from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.viewsets import ModelViewSet from rest_framework_jwt.authentication import JSONWebTokenAuthentication -from rest_framework_jwt.serializers import jwt_encode_handler, jwt_payload_handler +from rest_framework_jwt.serializers import (jwt_encode_handler, + jwt_payload_handler) from rest_framework_jwt.settings import api_settings from crm.zhenzismsclient import ZhenziSmsClient @@ -25,6 +27,7 @@ from question.serializers import QuestionSerializer from server import settings from utils.custom import CommonPagination +from .exports import export_consumer from .models import Company, Consumer, PaySubject, SendCode from .serializers import CompanySerializer, ConsumerSerializer @@ -229,10 +232,13 @@ class ConsumerViewSet(ModelViewSet): return Response(status=status.HTTP_200_OK) @action(methods=['get'], detail=False, - url_path='export', url_name='export_consumer') + url_path='export', url_name='export_consumer', perms_map=[{'*':'export_consumer'}]) def export(self, request): queryset = self.filter_queryset(self.queryset) - print(queryset) + queryset = ConsumerSerializer.setup_eager_loading(queryset) # 性能优化 + serializer = ConsumerSerializer(instance=queryset, many=True) + path = export_consumer(serializer.data) + return Response({'path': path}) class ConsumerMPLoginView(APIView): """ diff --git a/test_server/examtest/exports.py b/test_server/examtest/exports.py new file mode 100644 index 0000000..532c084 --- /dev/null +++ b/test_server/examtest/exports.py @@ -0,0 +1,26 @@ +from openpyxl.workbook import Workbook +from django.conf import settings +from datetime import datetime +from openpyxl.styles import Font, Fill + + +BASE_DIR = settings.BASE_DIR + +def export_test(tests): + ''' + params: serializer tests + return: xlsx path + ''' + wb = Workbook() + ws1 = wb.active + ws1.title = '用户表' + ws1.append(['类型','用户姓名', '用户单位', '工作类别', '押题卷', '得分', '耗时', '答题时间']) + row = ws1.row_dimensions[1] + row.font = Font(bold=True) + for i in tests: + ws1.append([i['type'], i['consumer_name'], i['consumer_company_name'], i['workscope_name'], i['paper_name'], i['score'], i['took_format'], i['start_time']]) + filename = 'tests' + datetime.now().strftime("%Y%m%d%H%M%S") +'.xlsx' + path = '/media/export/' + filename + wb.save((BASE_DIR + path).replace('\\', '/')) + return path + diff --git a/test_server/examtest/serializers.py b/test_server/examtest/serializers.py index 8de9e76..1dc3b21 100644 --- a/test_server/examtest/serializers.py +++ b/test_server/examtest/serializers.py @@ -62,6 +62,8 @@ class ExamTestListSerializer(serializers.ModelSerializer): workscope_name = serializers.StringRelatedField(source='workscope', read_only=True) paper_name = serializers.StringRelatedField(source='paper', read_only=True) consumer_name = serializers.SerializerMethodField() + took_format = serializers.SerializerMethodField() + consumer_company_name = serializers.SerializerMethodField() class Meta: model = ExamTest exclude = ('detail',) @@ -69,6 +71,21 @@ class ExamTestListSerializer(serializers.ModelSerializer): def get_consumer_name(self, obj): return obj.consumer.name + def get_took_format(self, obj): + m, s = divmod(obj.took, 60) + h, m = divmod(m, 60) + return "%02d:%02d:%02d" % (h, m, s) + + def get_consumer_company_name(self, obj): + if obj.consumer.company: + return obj.consumer.company.name + + @staticmethod + def setup_eager_loading(queryset): + """ Perform necessary eager loading of data. """ + queryset = queryset.select_related('consumer','paper', 'workscope') + return queryset + class AnswerDetailSerializer(serializers.ModelSerializer): class Meta: model = AnswerDetail diff --git a/test_server/examtest/views.py b/test_server/examtest/views.py index 6062afa..6de6ed5 100644 --- a/test_server/examtest/views.py +++ b/test_server/examtest/views.py @@ -18,6 +18,7 @@ from question.serializers import QuestionSerializer from server import settings from utils.custom import CommonPagination +from .exports import export_test from .models import AnswerDetail, Banner, ExamTest from .models_paper import Paper, PaperQuestions, TestRule, WorkScope from .serializers import ( @@ -258,8 +259,15 @@ class ExamTestViewSet(ModelViewSet): return Response({'error':'答题记录不存在'}) else: return Response(serializer.errors) - - + + @action(methods=['get'], detail=False, + url_path='export', url_name='export_test', perms_map=[{'*':'export_test'}]) + def export(self, request): + queryset = self.filter_queryset(self.queryset) + queryset = ExamTestListSerializer.setup_eager_loading(queryset) # 性能优化 + serializer = ExamTestListSerializer(instance=queryset, many=True) + path = export_test(serializer.data) + return Response({'path': path}) class PaperViewSet(ModelViewSet): """ 押题卷增删改查 diff --git a/test_server/question/views.py b/test_server/question/views.py index 9bc9fd9..6295a80 100644 --- a/test_server/question/views.py +++ b/test_server/question/views.py @@ -1,22 +1,26 @@ -from rest_framework.filters import SearchFilter, OrderingFilter -from rest_framework.permissions import IsAuthenticated -from rest_framework.views import APIView -from rest_framework.viewsets import ModelViewSet -from rest_framework.generics import GenericAPIView -from rest_framework.response import Response -from rest_framework.decorators import action -from rest_framework import status -from django_filters.rest_framework import DjangoFilterBackend -from openpyxl import Workbook, load_workbook -from rest_framework_jwt.authentication import JSONWebTokenAuthentication import json -from utils.custom import CommonPagination -from .models import Questioncat, Question -from .serializers import QuestioncatSerializer, QuestionSerializer, SubjectSerializer, QuestioncatSerializerDefault -from server import settings +from django_filters.rest_framework import DjangoFilterBackend +from openpyxl import Workbook, load_workbook +from rest_framework import status +from rest_framework.decorators import action +from rest_framework.filters import OrderingFilter, SearchFilter +from rest_framework.generics import GenericAPIView +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework.viewsets import ModelViewSet +from rest_framework_jwt.authentication import JSONWebTokenAuthentication + from crm.models import PaySubject from examtest.models import WorkScope +from server import settings +from utils.custom import CommonPagination + + +from .models import Question, Questioncat +from .serializers import (QuestioncatSerializer, QuestioncatSerializerDefault, + QuestionSerializer, SubjectSerializer) class SubjectViewSet(ModelViewSet): @@ -240,4 +244,4 @@ class ExerciseView(APIView): i['is_collect'] = True else: i['is_collect'] = False - return Response({'count':count, 'results':results}) \ No newline at end of file + return Response({'count':count, 'results':results}) diff --git a/test_server/utils/file.py b/test_server/utils/file.py index 47afae1..9ae732f 100644 --- a/test_server/utils/file.py +++ b/test_server/utils/file.py @@ -15,7 +15,7 @@ class UploadFileView(APIView): def post(self, request, *args, **kwargs): fileobj = request.FILES['file'] file_name = fileobj.name.encode('utf-8').decode('utf-8') - file_name_new = str(uuid.uuid1()) + '.' + file_name.split('.')[1] + file_name_new = str(uuid.uuid1()) + '.' + file_name.split('.')[-1] subfolder = os.path.join('media', datetime.now().strftime("%Y%m%d")) if not os.path.exists(subfolder): os.mkdir(subfolder)