liu tao 3 tahun lalu
induk
melakukan
c1427d8df8

+ 6 - 0
apps/api/admin/exam/views.py

@@ -125,3 +125,9 @@ class ExamLogViewSet(ReadOnlyModelViewSet):
     def answer_log(self, request, pk):
         rows = ExamAnswerLog.objects.filter(main_id=pk).order_by('detail__order').values_list('status', flat=True)
         return response_ok(list(rows))
+
+    @action(methods=['get'], detail=False)
+    def export(self, request):
+        queryset = self.filter_queryset(self.queryset)
+        serializer = self.get_serializer(queryset, many=True)
+        return response_ok(serializer.data)

+ 6 - 0
apps/api/admin/views.py

@@ -4,7 +4,9 @@ from django.contrib.auth import get_user_model
 from rest_framework_jwt.views import ObtainJSONWebToken, VerifyJSONWebToken, RefreshJSONWebToken
 from rest_framework.serializers import ValidationError
 from utils import response_error, response_ok
+from utils.empower import checkLicence
 from apps.staff.serializers import AdminUserJWTSerializer
+from utils.exceptions import CustomError
 
 User = get_user_model()
 
@@ -12,6 +14,10 @@ class AdminUserLoginView(ObtainJSONWebToken):
     serializer_class = AdminUserJWTSerializer
 
     def post(self, request, *args, **kwargs):
+
+        if not checkLicence():
+            raise CustomError(u'授权失败!')
+
         try:
             ser = self.serializer_class(data=request.data)
             ser.request = request

+ 11 - 2
apps/api/staff/exam/views.py

@@ -128,7 +128,16 @@ class ExamLogViewSet(CustomModelViewSet):
                     if not detail:
                         raise CustomError('提交的考试习题有误,请刷新重试!')
                     now_question = detail.question
-                    if len(answers) > 0:
+
+                    has_answers = len(answers) > 0
+                    if now_question.type == ExamQuestion.FILL:
+                        has_answers = False
+                        for a in range(0, len(answers)):
+                            if answers[a]:
+                                has_answers = True
+                                break
+
+                    if has_answers > 0:
                         answer_log, create = ExamAnswerLog.objects.get_or_create(main=instance,
                                                                                  detail=detail, )
                         if now_question.type <= ExamQuestion.MULTIPLE:
@@ -142,7 +151,7 @@ class ExamLogViewSet(CustomModelViewSet):
                             answers_len = len(answers)
                             ExamAnswerFillLog.objects.filter(main=answer_log).delete()
                             for a in range(0, answers_len):
-                                ExamAnswerFillLog.objects.create(main=answer_log, content=answers[a], order=a + 1)
+                                ExamAnswerFillLog.objects.create(main=answer_log, content=answers[a] or '', order=a + 1)
                         else:
                             # 判断
                             if answers[0] == 1:

+ 11 - 2
apps/api/staff/mock/views.py

@@ -119,7 +119,16 @@ class ExamLogViewSet(CustomModelViewSet):
                     if not detail:
                         raise CustomError('提交的考试习题有误,请刷新重试!')
                     now_question = detail.question
-                    if len(answers) > 0:
+
+                    has_answers = len(answers) > 0
+                    if now_question.type == ExamQuestion.FILL:
+                        has_answers = False
+                        for a in range(0, len(answers)):
+                            if answers[a]:
+                                has_answers = True
+                                break
+
+                    if has_answers > 0:
                         answer_log, create = ExamAnswerLog.objects.get_or_create(main=instance,
                                                                                  detail=detail, )
                         if now_question.type <= ExamQuestion.MULTIPLE:
@@ -133,7 +142,7 @@ class ExamLogViewSet(CustomModelViewSet):
                             answers_len = len(answers)
                             ExamAnswerFillLog.objects.filter(main=answer_log).delete()
                             for a in range(0, answers_len):
-                                ExamAnswerFillLog.objects.create(main=answer_log, content=answers[a], order=a + 1)
+                                ExamAnswerFillLog.objects.create(main=answer_log, content=answers[a] or '', order=a + 1)
                         else:
                             # 判断
                             if answers[0] == 1:

+ 11 - 2
apps/api/staff/practise/views.py

@@ -71,7 +71,16 @@ class PractiseLogViewSet(CustomModelViewSet):
                     now_question = ExamQuestion.objects.filter(id=now_practise).first()
                     if not now_question:
                         raise CustomError('提交的习题有误,请刷新重试!')
-                    if len(answers) > 0:
+
+                    has_answers = len(answers) > 0
+                    if now_question.type == ExamQuestion.FILL:
+                        has_answers = False
+                        for a in range(0, len(answers)):
+                            if answers[a]:
+                                has_answers = True
+                                break
+
+                    if has_answers > 0:
                         answer_log, create = PractiseAnswerLog.objects.get_or_create(main=instance,
                                                                                      question=now_question, )
                         if now_question.type == ExamQuestion.SINGLE:
@@ -104,7 +113,7 @@ class PractiseLogViewSet(CustomModelViewSet):
                             right = 1
                             PractiseAnswerFillLog.objects.filter(main=answer_log).delete()
                             for a in range(0, answers_len):
-                                PractiseAnswerFillLog.objects.create(main=answer_log, content=answers[a], order=a + 1)
+                                PractiseAnswerFillLog.objects.create(main=answer_log, content=answers[a] or '', order=a + 1)
                                 right_answer = ExamQuestionFill.objects.filter(main=now_question, content=answers[a],
                                                                                order=a + 1)
                                 if not right_answer:

+ 3 - 0
ks/licence.py

@@ -0,0 +1,3 @@
+#coding=utf-8
+
+licence = ''

+ 2 - 1
requirements

@@ -4,4 +4,5 @@ djangorestframework
 djangorestframework-jwt
 django-cors-headers
 tablib==3.1.0
-openpyxl==3.0.9
+openpyxl==3.0.9
+cx-Oracle

+ 20 - 0
uis/admin/examlog/index.html

@@ -63,6 +63,9 @@
             <div class="layui-row layui-col-space15">
                 <div class="layui-col-md12">
                     <div class="LAY-btns" style="margin-bottom: 10px;">
+                        <div style="float: left">
+                            <button class="layui-btn" id="btn_download"><i class="layui-icon layui-icon-download-circle"></i>导出</button>
+                        </div>
                         <form class="layui-form" lay-filter="query-form-element">
                             <div class="seach_items">
                                 <button class="layui-btn" lay-submit lay-filter="query-form-element"><i
@@ -107,6 +110,8 @@
 
 <script src="../../layuiadmin/layui/layui.js"></script>
 <script>
+    var _params = '';
+
     layui.config({
         base: '../../../layuiadmin/' //静态资源所在路径
     }).extend({
@@ -134,6 +139,8 @@
         table.render({
             elem: '#exampaper_datagrid'
             , url: '/admin/exam/examlog/'
+            ,title: '考试记录'
+            ,id: 'exampaper_datagrid'
             , cols: [[
                 {title: '编号', type: 'numbers'}
                 , {field: 'exam_name', title: '考试名称', width: 200}
@@ -177,9 +184,22 @@
                 where: data.field
                 , page: {curr: 1}
             });
+            _params = data.field;
             layer.closeAll();
             return false
         });
+
+        $('#btn_download').on('click', function(){
+        $.get({
+            url: '/admin/exam/examlog/export/',
+            dataType: 'json',
+            data: _params,
+            success: function (res) {
+                table.exportFile('exampaper_datagrid', res.data, 'xls')
+            }
+        })
+    });
+
     });
 
 </script>

TEMPAT SAMPAH
uis/dist/img/log.png


+ 61 - 0
utils/empower.py

@@ -0,0 +1,61 @@
+#coding=utf-8
+import Crypto.Hash
+import Crypto.PublicKey.RSA
+import Crypto.Signature.PKCS1_v1_5
+
+import uuid
+import platform
+import base64
+import hashlib
+
+import ks.licence as licence
+
+XorKey = [0xB2, 0x09, 0xBB, 0x55, 0x93, 0x83, 0x03, 0x24]
+
+def enc(src):
+    j, result = 0, ""
+    for s in src:
+        result = result + hex(ord(s) ^ (XorKey[j]))[2:]
+        j = (j + 1) % 8
+    return result
+
+def getMac():
+    sysstr = platform.system()
+    if (sysstr == "Windows"):
+        import winreg
+        key = winreg.OpenKey(
+            winreg.HKEY_LOCAL_MACHINE,
+            "SOFTWARE\\Microsoft\\Cryptography",
+            0,
+            winreg.KEY_READ | winreg.KEY_WOW64_64KEY
+        )
+        result = winreg.QueryValueEx(key, "MachineGuid")
+        mac = result[0]
+    else:
+        mac = ':'.join(['{:02x}'.format((uuid.getnode() >> i) & 0xff) for i in range(0, 8 * 6, 8)][::-1])
+
+    path = '/auth/kaohe/v2/'
+    mac += 'ZZLY[' + path + ']20190325'
+    mac = enc(mac)
+    mac = base64.b64encode(mac.encode())
+    mac = hashlib.sha256(mac).hexdigest()
+    return mac
+
+def checkLicence():
+    pub_key = """-----BEGIN RSA PUBLIC KEY-----
+    MIGJAoGBAMhqydgWZUV7qy96aGTY6i/pGC5mC8AyjvwIwoH2zE6hi5MQsW5cpOLS
+    d2VNhfi2ypg19w3Z2sd248X/fc4lGwDwP8/fXNoRtVBDR/3F/+WlaK9beFIyp5J4
+    Fa2XHj5lOiCjLoJpzehE2Dguv+3xORJn10oGAHQhXxFjdWEt5xBBAgMBAAE=
+    -----END RSA PUBLIC KEY-----"""
+
+    mac = getMac()
+
+    d_rsa = Crypto.PublicKey.RSA.importKey(pub_key)
+    verifer = Crypto.Signature.PKCS1_v1_5.new(d_rsa)
+    msg_hash = Crypto.Hash.SHA256.new()
+    msg_hash.update(mac.encode('utf-8'))
+    return verifer.verify(msg_hash, base64.decodebytes(licence.licence.encode('utf-8')))
+
+
+
+

+ 3 - 0
生成授权码/mac.py

@@ -0,0 +1,3 @@
+#coding=utf-8
+
+mac = 'a248cc2184e6ea930541839ed68d747028c83ddb3bf33aa993f3a5733137b6ca'

+ 43 - 0
生成授权码/sign.py

@@ -0,0 +1,43 @@
+#coding=utf-8
+
+import os
+import Crypto.Hash
+import Crypto.PublicKey.RSA
+import Crypto.Signature.PKCS1_v1_5
+import base64
+import mac
+
+priv_key = """-----BEGIN RSA PRIVATE KEY-----
+MIICYQIBAAKBgQDIasnYFmVFe6svemhk2Oov6RguZgvAMo78CMKB9sxOoYuTELFu
+XKTi0ndlTYX4tsqYNfcN2drHduPF/33OJRsA8D/P31zaEbVQQ0f9xf/lpWivW3hS
+MqeSeBWtlx4+ZTogoy6Cac3oRNg4Lr/t8TkSZ9dKBgB0IV8RY3VhLecQQQIDAQAB
+AoGAMINpCJ2jNgaRkZSX4JGBXseVyuV4wrV6VxfnvX34RrBkEN1hlc1nPGCl9iel
+3mag8+dcPkYV52KoEC2gFZHc45/X8+MNAB/a3pYTK64VJE6mjEKSfq4nVWrCiIY2
+vHBSNuGI+9H5j6lYVbukuT6X+D7u9BD1+ozcUHcjFIgrVWECRQDqpN9Fq8Ub/PYS
+b+xRchkQEieZxwWmD1/gcUxp5X7P6VRgErh/cPD3QZlG5kQ/OLeGSPpYFXhbVyhR
+yB2rLVMbuAK78wI9ANqocPAjFAcCVn6I/+f1qAhqg/AURULFRHUCOf/mVPhC0Jc7
++yxSfYueNjuE5KapfPrOAJV8GjEO7dNT+wJENnXb6ITMtAlLZ84YcHLmBEfibxu1
+YOySmTpSvQVqIIGMdtwBfHrPQuQz2jPZxT65we4wRL9+9txM3GZxFGjpsDZOVCcC
+PQC09pjZtT5a+q1Y9ctNTzstE/Jz3GLh+t9IM3qK9ja2bJ2zvHmI2hB7X4okwjx2
+TmlYLOvAy7/lgCSGNMcCRQCAEpmLCgDV5cy+x+XZR1p7xvED87kaa0jZ8UQtcET7
+gRdW88GKbBXJaWUeFsLjOwuLWYXloDYyDZR9jtM12bzQf+LJnQ==
+-----END RSA PRIVATE KEY-----"""
+
+c_rsa = Crypto.PublicKey.RSA.importKey(priv_key)
+signer = Crypto.Signature.PKCS1_v1_5.new(c_rsa)
+msg_hash = Crypto.Hash.SHA256.new()
+msg_hash.update(mac.mac.encode('utf-8'))
+sign = base64.b64encode(signer.sign(msg_hash)).decode('utf-8')
+
+cmd = 'echo ' + sign + '| clip'
+os.system(cmd)
+
+print(u'#=========================================================================')
+print('#')
+print(u'#签名: ', sign)
+print('#')
+print(u'#签名已复制,可直接粘贴发送给使用人员')
+print('#')
+print(u'#=============================郑州燎原版权所有=============================')
+print('')
+os.system('pause')

+ 50 - 0
获取机器码/mac.py

@@ -0,0 +1,50 @@
+#coding=utf-8
+import uuid
+import datetime
+import os
+
+import platform
+import base64
+import hashlib
+
+XorKey = [0xB2, 0x09, 0xBB, 0x55, 0x93, 0x83, 0x03, 0x24]
+
+def enc(src):
+    j, result = 0, ""
+    for s in src:
+        result = result + hex(ord(s) ^ (XorKey[j]))[2:]
+        j = (j + 1) % 8
+    return result
+
+sysstr = platform.system()
+if (sysstr == "Windows"):
+    import winreg
+    key = winreg.OpenKey(
+        winreg.HKEY_LOCAL_MACHINE,
+        "SOFTWARE\\Microsoft\\Cryptography",
+        0,
+        winreg.KEY_READ | winreg.KEY_WOW64_64KEY
+    )
+    result = winreg.QueryValueEx(key, "MachineGuid")
+    mac = result[0]
+else:
+    mac = ':'.join(['{:02x}'.format((uuid.getnode() >> i) & 0xff) for i in range(0,8*6,8)][::-1])
+
+path = '/auth/kaohe/v2/'
+mac += 'ZZLY[' + path + ']20190325'
+mac = enc(mac)
+mac = base64.b64encode(mac.encode())
+mac = hashlib.sha256(mac).hexdigest()
+
+cmd = 'echo ' + mac + '| clip'
+os.system(cmd)
+
+print(u'#=========================================================================')
+print('#')
+print(u'#机器码: ', mac)
+print('#')
+print(u'#机器码已复制,可直接粘贴发送给授权人员')
+print('#')
+print(u'#=============================郑州燎原版权所有=============================')
+print('')
+os.system('pause')