liu tao 3 yıl önce
ebeveyn
işleme
f6049565df
100 değiştirilmiş dosya ile 1350 ekleme ve 0 silme
  1. 12 0
      .gitignore
  2. 0 0
      apps/__init__.py
  3. 0 0
      apps/api/__init__.py
  4. 0 0
      apps/api/admin/__init__.py
  5. 0 0
      apps/api/admin/department/__init__.py
  6. 68 0
      apps/api/admin/department/serializers.py
  7. 13 0
      apps/api/admin/department/urls.py
  8. 45 0
      apps/api/admin/department/views.py
  9. 0 0
      apps/api/admin/exam/__init__.py
  10. 0 0
      apps/api/admin/exampaper/__init__.py
  11. 0 0
      apps/api/admin/examquestion/__init__.py
  12. 0 0
      apps/api/admin/knowledge/__init__.py
  13. 0 0
      apps/api/admin/subject/__init__.py
  14. 0 0
      apps/api/admin/syslog/__init__.py
  15. 17 0
      apps/api/admin/urls.py
  16. 0 0
      apps/api/admin/user/__init__.py
  17. 41 0
      apps/api/admin/views.py
  18. 0 0
      apps/api/staff/__init__.py
  19. 0 0
      apps/api/staff/errorbook/__init__.py
  20. 0 0
      apps/api/staff/exam/__init__.py
  21. 0 0
      apps/api/staff/knowledge/__init__.py
  22. 0 0
      apps/api/staff/mock/__init__.py
  23. 0 0
      apps/api/staff/practise/__init__.py
  24. 17 0
      apps/api/staff/urls.py
  25. 41 0
      apps/api/staff/views.py
  26. 0 0
      apps/dashboard/__init__.py
  27. 9 0
      apps/dashboard/views.py
  28. 0 0
      apps/examination/__init__.py
  29. 0 0
      apps/examination/exam/__init__.py
  30. 0 0
      apps/examination/exam/migrations/__init__.py
  31. 17 0
      apps/examination/exam/models.py
  32. 0 0
      apps/examination/exampaper/__init__.py
  33. 0 0
      apps/examination/exampaper/migrations/__init__.py
  34. 10 0
      apps/examination/exampaper/models.py
  35. 0 0
      apps/examination/examquestion/__init__.py
  36. 0 0
      apps/examination/examquestion/migrations/__init__.py
  37. 17 0
      apps/examination/examquestion/models.py
  38. 0 0
      apps/foundation/__init__.py
  39. 0 0
      apps/foundation/migrations/__init__.py
  40. 17 0
      apps/foundation/models.py
  41. 0 0
      apps/knowledge/__init__.py
  42. 0 0
      apps/knowledge/migrations/__init__.py
  43. 17 0
      apps/knowledge/models.py
  44. 0 0
      apps/practise/__init__.py
  45. 0 0
      apps/practise/errorbook/__init__.py
  46. 0 0
      apps/practise/errorbook/migrations/__init__.py
  47. 10 0
      apps/practise/errorbook/models.py
  48. 0 0
      apps/practise/practiselog/__init__.py
  49. 0 0
      apps/practise/practiselog/migrations/__init__.py
  50. 10 0
      apps/practise/practiselog/models.py
  51. 1 0
      apps/staff/__init__.py
  52. 12 0
      apps/staff/consts.py
  53. 14 0
      apps/staff/filters.py
  54. 0 0
      apps/staff/migrations/__init__.py
  55. 216 0
      apps/staff/models.py
  56. 0 0
      apps/system/__init__.py
  57. 19 0
      apps/system/filters.py
  58. 0 0
      apps/system/migrations/__init__.py
  59. 53 0
      apps/system/models.py
  60. 0 0
      ks/__init__.py
  61. 214 0
      ks/settings.py
  62. 29 0
      ks/urls.py
  63. 16 0
      ks/wsgi.py
  64. 21 0
      manage.py
  65. 5 0
      requirements
  66. 145 0
      uis/admin/index.html
  67. 118 0
      uis/admin/login/login.html
  68. 95 0
      uis/layuiadmin/config.js
  69. 1 0
      uis/layuiadmin/layui/css/layui.css
  70. 1 0
      uis/layuiadmin/layui/css/layui.mobile.css
  71. 2 0
      uis/layuiadmin/layui/css/modules/code.css
  72. 1 0
      uis/layuiadmin/layui/css/modules/laydate/default/laydate.css
  73. BIN
      uis/layuiadmin/layui/css/modules/layer/default/icon-ext.png
  74. BIN
      uis/layuiadmin/layui/css/modules/layer/default/icon.png
  75. 1 0
      uis/layuiadmin/layui/css/modules/layer/default/layer.css
  76. BIN
      uis/layuiadmin/layui/css/modules/layer/default/loading-0.gif
  77. BIN
      uis/layuiadmin/layui/css/modules/layer/default/loading-1.gif
  78. BIN
      uis/layuiadmin/layui/css/modules/layer/default/loading-2.gif
  79. BIN
      uis/layuiadmin/layui/font/iconfont.eot
  80. 25 0
      uis/layuiadmin/layui/font/iconfont.svg
  81. BIN
      uis/layuiadmin/layui/font/iconfont.ttf
  82. BIN
      uis/layuiadmin/layui/font/iconfont.woff
  83. BIN
      uis/layuiadmin/layui/images/face/0.gif
  84. BIN
      uis/layuiadmin/layui/images/face/1.gif
  85. BIN
      uis/layuiadmin/layui/images/face/10.gif
  86. BIN
      uis/layuiadmin/layui/images/face/11.gif
  87. BIN
      uis/layuiadmin/layui/images/face/12.gif
  88. BIN
      uis/layuiadmin/layui/images/face/13.gif
  89. BIN
      uis/layuiadmin/layui/images/face/14.gif
  90. BIN
      uis/layuiadmin/layui/images/face/15.gif
  91. BIN
      uis/layuiadmin/layui/images/face/16.gif
  92. BIN
      uis/layuiadmin/layui/images/face/17.gif
  93. BIN
      uis/layuiadmin/layui/images/face/18.gif
  94. BIN
      uis/layuiadmin/layui/images/face/19.gif
  95. BIN
      uis/layuiadmin/layui/images/face/2.gif
  96. BIN
      uis/layuiadmin/layui/images/face/20.gif
  97. BIN
      uis/layuiadmin/layui/images/face/21.gif
  98. BIN
      uis/layuiadmin/layui/images/face/22.gif
  99. BIN
      uis/layuiadmin/layui/images/face/23.gif
  100. BIN
      uis/layuiadmin/layui/images/face/24.gif

+ 12 - 0
.gitignore

@@ -0,0 +1,12 @@
+# See https://help.github.com/ignore-files/ for more about ignoring files. 
+
+**/migrations/*
+!**/migrations/__init__.py
+
+*.py[cod]
+local_settings.*
+*.bat
+*.txt
+*.whl
+venv
+.idea

+ 0 - 0
apps/__init__.py


+ 0 - 0
apps/api/__init__.py


+ 0 - 0
apps/api/admin/__init__.py


+ 0 - 0
apps/api/admin/department/__init__.py


+ 68 - 0
apps/api/admin/department/serializers.py

@@ -0,0 +1,68 @@
+# coding=utf-8
+
+from rest_framework import serializers
+
+from utils.exceptions import CustomError
+from utils.serializersfield import BooleanCharField
+from apps.base import Formater
+from apps.coupon.models import Coupon, CouponItem
+
+
+class CouponSerializer(serializers.ModelSerializer):
+    show_amount = serializers.SerializerMethodField()
+    create_user_text = serializers.CharField(source='create_user.employee.name', read_only=True)
+    date_type_text = serializers.CharField(source="get_date_type_display", read_only=True)
+    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M', read_only=True)
+
+    def get_show_amount(self, obj):
+        return Formater.formatAmountShow(obj.amount)
+
+    class Meta:
+        model = Coupon
+        fields = '__all__'
+
+    def validate(self, attrs):
+        if 'amount' in attrs:
+            attrs['amount'] = Formater.formatAmount(attrs['amount'])
+        if attrs['validity_begin_time'] and attrs['validity_end_time'] and attrs['validity_begin_time'] > attrs['validity_end_time']:
+            raise CustomError(u'无效的有效期开始/结束时间')
+        if attrs['receive_begin_time'] and attrs['receive_end_time'] and attrs['receive_begin_time'] > attrs['receive_end_time']:
+            raise CustomError(u'无效的领取开始/结束时间')
+        return attrs
+
+    def create(self, validated_data):
+        user = self.context['request'].user
+        validated_data['tenant'] = user.employee.tenant
+        validated_data['create_user'] = user
+        instance = super(CouponSerializer, self).create(validated_data)
+        return instance
+
+    def update(self, instance, validated_data):
+        if instance.tenant != self.context['request'].user.employee.tenant:
+            raise CustomError(u'禁止跨租户操作!')
+        if instance.delete:
+            raise CustomError(u'优惠券[%s]已经被删除,禁止操作' % instance.name)
+        if instance.left_count > validated_data['total_count']:
+            raise CustomError(u'总数量不能小于已领取数量!')
+        instance = super(CouponSerializer, self).update(instance, validated_data)
+        return instance
+
+
+class CouponItemSerializer(serializers.ModelSerializer):
+    write_off_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M', read_only=True)
+    write_off_user_text = serializers.CharField(source='write_off_user.employee.name', read_only=True)
+    is_used_text = BooleanCharField(source='is_used', read_only=True)
+    validity_begin_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M', read_only=True)
+    validity_end_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M', read_only=True)
+    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M', read_only=True)
+    customer_name = serializers.CharField(source='customer.name', read_only=True)
+    customer_tel = serializers.CharField(source='customer.tel', read_only=True)
+    coupon_name = serializers.CharField(source='coupon.name', read_only=True)
+    amount = serializers.SerializerMethodField()
+
+    def get_amount(self, obj):
+        return Formater.formatAmountShow(obj.amount)
+
+    class Meta:
+        model = CouponItem
+        fields = '__all__'

+ 13 - 0
apps/api/admin/department/urls.py

@@ -0,0 +1,13 @@
+# coding=utf-8
+
+from django.conf.urls import url, include
+from rest_framework.routers import SimpleRouter
+
+from .views import *
+
+urlpatterns = [
+]
+
+router = SimpleRouter()
+router.register(r'', CouponViewSet)
+urlpatterns += router.urls

+ 45 - 0
apps/api/admin/department/views.py

@@ -0,0 +1,45 @@
+# coding=utf-8
+
+import json
+from rest_framework.decorators import action
+from django.db import transaction
+from utils.permission import IsAdministrator
+from utils.custom_modelviewset import CustomModelViewSet
+from apps.coupon.models import Coupon, CouponItem
+from apps.coupon.filters import CouponFilter, CouponItemFilter
+from .serializers import CouponSerializer, CouponItemSerializer
+from utils.exceptions import CustomError
+from utils import response_ok
+from apps.system.models import SysLog
+
+class CouponViewSet(CustomModelViewSet):
+    permission_classes = [IsAdministrator, ]
+    queryset = Coupon.objects.filter(delete=False)
+    serializer_class = CouponSerializer
+
+    def filter_queryset(self, queryset):
+        queryset = queryset.filter(tenant=self.request.user.employee.tenant)
+        f = CouponFilter(self.request.GET, queryset=queryset)
+        return f.qs
+
+    def perform_create(self, serializer):
+        super(CouponViewSet, self).perform_create(serializer)
+        instance = serializer.instance
+        validated_data = serializer.validated_data
+        tenant_log(self.request.user.employee, BizLog.INSERT, u'添加优惠券[%s],id=%d' % (instance.name, instance.id), validated_data)
+
+    def perform_update(self, serializer):
+        super(CouponViewSet, self).perform_update(serializer)
+        instance = serializer.instance
+        validated_data = serializer.validated_data
+        tenant_log(self.request.user.employee, BizLog.UPDATE, u'修改优惠券[%s],id=%d' % (instance.name, instance.id), validated_data)
+
+    def destroy(self, request, *args, **kwargs):
+        with transaction.atomic():
+            instance = self.get_object()
+            if instance.tenant != request.user.employee.tenant:
+                raise CustomError(u'禁止跨租户操作!')
+            instance.delete = True
+            instance.save()
+            tenant_log(self.request.user.employee, BizLog.DELETE, u'删除优惠券[%s],id=%d' % (instance.name, instance.id))
+        return response_ok()

+ 0 - 0
apps/api/admin/exam/__init__.py


+ 0 - 0
apps/api/admin/exampaper/__init__.py


+ 0 - 0
apps/api/admin/examquestion/__init__.py


+ 0 - 0
apps/api/admin/knowledge/__init__.py


+ 0 - 0
apps/api/admin/subject/__init__.py


+ 0 - 0
apps/api/admin/syslog/__init__.py


+ 17 - 0
apps/api/admin/urls.py

@@ -0,0 +1,17 @@
+# coding=utf-8
+
+from django.conf.urls import url, include
+from apps.dashboard.views import admin_index
+from .views import *
+
+urlpatterns = [
+    url(r'^$', admin_index),
+    url(r'^token/obtain/$', AdminUserLoginView.as_view()),
+    url(r'^token_refresh/$', AdminUserRefreshTokenView.as_view()),
+    url(r'^token_verify/$', AdminUserVerifyTokenView.as_view()),
+
+    url(r'^user/', include('apps.admin.user.urls')),
+    url(r'^tenant/', include('apps.admin.tenant.urls')),
+    url(r'^wechatapp/', include('apps.admin.wechatapplet.urls')),
+    url(r'^wechattp/', include('apps.admin.wechattp.urls')),
+]

+ 0 - 0
apps/api/admin/user/__init__.py


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

@@ -0,0 +1,41 @@
+# coding=utf-8
+
+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 .serializers import AdminUserJWTSerializer
+
+User = get_user_model()
+
+class AdminUserLoginView(ObtainJSONWebToken):
+    serializer_class = AdminUserJWTSerializer
+
+    def post(self, request, *args, **kwargs):
+        try:
+            ser = self.serializer_class(data=request.data)
+            ser.request = request
+            if ser.is_valid(raise_exception=True):
+                return response_ok(ser.validated_data)
+        except ValidationError as e:
+            return response_error(e.detail['error'][0])
+
+
+class AdminUserVerifyTokenView(VerifyJSONWebToken):
+    def post(self, request, *args, **kwargs):
+        try:
+            ser = self.serializer_class(data=request.data)
+            if ser.is_valid(raise_exception=True):
+                return response_ok({'token': ser.validated_data['token']})
+        except ValidationError as e:
+            return response_error(u'登录状态失效,请重新登录[' + e.detail['error'][0] + ']')
+
+
+class AdminUserRefreshTokenView(RefreshJSONWebToken):
+    def post(self, request, *args, **kwargs):
+        try:
+            ser = self.serializer_class(data=request.data)
+            if ser.is_valid(raise_exception=True):
+                return response_ok({'token': ser.validated_data['token']})
+        except ValidationError as e:
+            return response_error(u'登录状态失效,请重新登录[' + e.detail['error'][0] + ']')

+ 0 - 0
apps/api/staff/__init__.py


+ 0 - 0
apps/api/staff/errorbook/__init__.py


+ 0 - 0
apps/api/staff/exam/__init__.py


+ 0 - 0
apps/api/staff/knowledge/__init__.py


+ 0 - 0
apps/api/staff/mock/__init__.py


+ 0 - 0
apps/api/staff/practise/__init__.py


+ 17 - 0
apps/api/staff/urls.py

@@ -0,0 +1,17 @@
+# coding=utf-8
+
+from django.conf.urls import url, include
+from apps.dashboard.views import index
+from .views import *
+
+urlpatterns = [
+    url(r'^$', index),
+    url(r'^token/obtain/$', AdminUserLoginView.as_view()),
+    url(r'^token_refresh/$', AdminUserRefreshTokenView.as_view()),
+    url(r'^token_verify/$', AdminUserVerifyTokenView.as_view()),
+
+    url(r'^user/', include('apps.admin.user.urls')),
+    url(r'^tenant/', include('apps.admin.tenant.urls')),
+    url(r'^wechatapp/', include('apps.admin.wechatapplet.urls')),
+    url(r'^wechattp/', include('apps.admin.wechattp.urls')),
+]

+ 41 - 0
apps/api/staff/views.py

@@ -0,0 +1,41 @@
+# coding=utf-8
+
+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 .serializers import AdminUserJWTSerializer
+
+User = get_user_model()
+
+class AdminUserLoginView(ObtainJSONWebToken):
+    serializer_class = AdminUserJWTSerializer
+
+    def post(self, request, *args, **kwargs):
+        try:
+            ser = self.serializer_class(data=request.data)
+            ser.request = request
+            if ser.is_valid(raise_exception=True):
+                return response_ok(ser.validated_data)
+        except ValidationError as e:
+            return response_error(e.detail['error'][0])
+
+
+class AdminUserVerifyTokenView(VerifyJSONWebToken):
+    def post(self, request, *args, **kwargs):
+        try:
+            ser = self.serializer_class(data=request.data)
+            if ser.is_valid(raise_exception=True):
+                return response_ok({'token': ser.validated_data['token']})
+        except ValidationError as e:
+            return response_error(u'登录状态失效,请重新登录[' + e.detail['error'][0] + ']')
+
+
+class AdminUserRefreshTokenView(RefreshJSONWebToken):
+    def post(self, request, *args, **kwargs):
+        try:
+            ser = self.serializer_class(data=request.data)
+            if ser.is_valid(raise_exception=True):
+                return response_ok({'token': ser.validated_data['token']})
+        except ValidationError as e:
+            return response_error(u'登录状态失效,请重新登录[' + e.detail['error'][0] + ']')

+ 0 - 0
apps/dashboard/__init__.py


+ 9 - 0
apps/dashboard/views.py

@@ -0,0 +1,9 @@
+#coding=utf-8
+
+from django.http import HttpResponseRedirect
+
+def index(request):
+    return HttpResponseRedirect('/staff/login/login.html')
+
+def admin_index(request):
+    return HttpResponseRedirect('/admin/login/login.html')

+ 0 - 0
apps/examination/__init__.py


+ 0 - 0
apps/examination/exam/__init__.py


+ 0 - 0
apps/examination/exam/migrations/__init__.py


+ 17 - 0
apps/examination/exam/models.py

@@ -0,0 +1,17 @@
+# coding=utf-8
+
+from django.db import models
+
+class Exam(models.Model):
+    class Meta:
+        db_table = "exam"
+        ordering = ['-id']
+        verbose_name = u"考试管理"
+        default_permissions = ()
+
+class ExamLog(models.Model):
+    class Meta:
+        db_table = "exam_log"
+        ordering = ['-id']
+        verbose_name = u"考试记录"
+        default_permissions = ()

+ 0 - 0
apps/examination/exampaper/__init__.py


+ 0 - 0
apps/examination/exampaper/migrations/__init__.py


+ 10 - 0
apps/examination/exampaper/models.py

@@ -0,0 +1,10 @@
+# coding=utf-8
+
+from django.db import models
+
+class ExamPaper(models.Model):
+    class Meta:
+        db_table = "exam_paper"
+        ordering = ['-id']
+        verbose_name = u"试卷管理"
+        default_permissions = ()

+ 0 - 0
apps/examination/examquestion/__init__.py


+ 0 - 0
apps/examination/examquestion/migrations/__init__.py


+ 17 - 0
apps/examination/examquestion/models.py

@@ -0,0 +1,17 @@
+# coding=utf-8
+
+from django.db import models
+
+class ExamQuestion(models.Model):
+    class Meta:
+        db_table = "exam_question"
+        ordering = ['-id']
+        verbose_name = u"试题管理"
+        default_permissions = ()
+
+class ExamQuestionFeedback(models.Model):
+    class Meta:
+        db_table = "exam_question_feedback"
+        ordering = ['-id']
+        verbose_name = u"错误反馈"
+        default_permissions = ()

+ 0 - 0
apps/foundation/__init__.py


+ 0 - 0
apps/foundation/migrations/__init__.py


+ 17 - 0
apps/foundation/models.py

@@ -0,0 +1,17 @@
+# coding=utf-8
+
+from django.db import models
+
+class Subject(models.Model):
+    class Meta:
+        db_table = "base_subject"
+        ordering = ['-id']
+        verbose_name = u"科目章节设置"
+        default_permissions = ()
+
+class Chapter(models.Model):
+    class Meta:
+        db_table = "base_chapter"
+        ordering = ['-id']
+        verbose_name = u"章节"
+        default_permissions = ()

+ 0 - 0
apps/knowledge/__init__.py


+ 0 - 0
apps/knowledge/migrations/__init__.py


+ 17 - 0
apps/knowledge/models.py

@@ -0,0 +1,17 @@
+# coding=utf-8
+
+from django.db import models
+
+class KnowledgeBase(models.Model):
+    class Meta:
+        db_table = "knowledge_base"
+        ordering = ['-id']
+        verbose_name = u"知识管理"
+        default_permissions = ()
+
+class KnowledgeBaseFeedback(models.Model):
+    class Meta:
+        db_table = "knowledge_base_feedback"
+        ordering = ['-id']
+        verbose_name = u"错误反馈"
+        default_permissions = ()

+ 0 - 0
apps/practise/__init__.py


+ 0 - 0
apps/practise/errorbook/__init__.py


+ 0 - 0
apps/practise/errorbook/migrations/__init__.py


+ 10 - 0
apps/practise/errorbook/models.py

@@ -0,0 +1,10 @@
+# coding=utf-8
+
+from django.db import models
+
+class ErrorBook(models.Model):
+    class Meta:
+        db_table = "practise_error_book"
+        ordering = ['-id']
+        verbose_name = u"错题集"
+        default_permissions = ()

+ 0 - 0
apps/practise/practiselog/__init__.py


+ 0 - 0
apps/practise/practiselog/migrations/__init__.py


+ 10 - 0
apps/practise/practiselog/models.py

@@ -0,0 +1,10 @@
+# coding=utf-8
+
+from django.db import models
+
+class PractiseLog(models.Model):
+    class Meta:
+        db_table = "practise_log"
+        ordering = ['-id']
+        verbose_name = u"练习记录"
+        default_permissions = ()

+ 1 - 0
apps/staff/__init__.py

@@ -0,0 +1 @@
+#coding=utf-8

+ 12 - 0
apps/staff/consts.py

@@ -0,0 +1,12 @@
+#coding=utf-8
+
+CONTENT_TYPE_SORTING = (
+    'staff-user',  # 账户管理
+)
+
+MENU_TO_MODEL = (
+    (u'试题库管理', ()),
+    (u'知识库管理', ()),
+    (u'考试管理', ()),
+    (u'系统管理', ('staff-user', )),
+)

+ 14 - 0
apps/staff/filters.py

@@ -0,0 +1,14 @@
+# coding=utf-8
+import django_filters
+
+from django.contrib.auth import get_user_model
+
+User = get_user_model()
+
+class UserFilter(django_filters.FilterSet):
+    username = django_filters.CharFilter(field_name='username', lookup_expr='icontains')
+    is_active = django_filters.CharFilter(field_name='is_active')
+
+    class Meta:
+        model = User
+        fields = ['username', 'is_active']

+ 0 - 0
apps/staff/migrations/__init__.py


+ 216 - 0
apps/staff/models.py

@@ -0,0 +1,216 @@
+# coding=utf-8
+
+from django.db import models
+from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager, Group
+from django.utils import timezone
+from rest_framework.utils import model_meta
+
+from .consts import CONTENT_TYPE_SORTING, MENU_TO_MODEL
+from apps.system.models import SysLog
+from utils.exceptions import CustomError
+
+class Department(models.Model):
+    name = models.CharField(max_length=100, verbose_name=u"名称")
+    notes = models.CharField(max_length=500, verbose_name=u"备注",blank=True,null=True)
+    parent_id = models.IntegerField(verbose_name=u"父部门",null=True,blank=True)
+    lft = models.IntegerField(verbose_name=u"左值")
+    rgt = models.IntegerField(verbose_name=u"右值")
+
+    def __str__(self):
+        return self.name
+
+    def __unicode__(self):
+        return self.name
+
+    @staticmethod
+    def getById(id):
+        try:
+            id = int(id)
+        except:
+            raise CustomError(u'无效的部门ID')
+
+        instance = Department.objects.filter(pk=id).first()
+        if not instance:
+            raise CustomError(u'未找到相应的部门')
+        return instance
+
+    def getCompany(self):
+        instance = Department.objects.filter(parent_id__isnull=True, lft__lte=self.lft, rgt__gte=self.rgt).first()
+        if not instance:
+            raise CustomError(u'未找到部门所属的公司')
+        return instance
+
+    @staticmethod
+    def getLft(instance):
+        if instance:
+            return instance.lft
+        return 1
+
+    class Meta:
+        db_table = "staff_department"
+        verbose_name = u"部门管理"
+        ordering = ["parent_id", 'id']
+        default_permissions = ()
+        permissions = (
+            ("view_department", u"浏览"),
+            ("add_department", u"添加"),
+            ("edit_department", u"修改"),
+            ("delete_department", u"删除"),
+        )
+
+class UserManager(BaseUserManager):
+    def create_administrator(self, username, password=None, **extra_fields):
+        return self.create_user(User.ADMINSTRATOR, username, password, **extra_fields)
+
+    def create_staff(self, username, password=None, **extra_fields):
+        return self.create_user(User.STUDENT, username, password, **extra_fields)
+
+    def create_superuser(self, username, password, **extra_fields):
+        u = self.create_administrator(username, password, **extra_fields)
+        u.is_active = True
+        u.is_superuser = True
+        u.save(using=self._db)
+        return u
+
+    def create_user(self, type, username, password=None, **extra_fields):
+        if not username:
+            raise CustomError(u'请输入用户名!')
+        count = User.objects.filter(username=username).count()
+        if count > 0:
+            raise CustomError(u'该用户名已存在!')
+        user = self.model(
+            type=type,
+            username=username,
+            is_superuser=False,
+            last_login=timezone.now(),
+            **extra_fields
+        )
+
+        user.set_password(password)
+        user.save(using=self._db)
+        return user
+
+    def sort_perms(self, perms):
+        def get_index(app_label, model):
+            try:
+                return CONTENT_TYPE_SORTING.index('{}-{}'.format(app_label, model))
+            except:
+                return 9999
+
+        perms = perms.order_by('content_type__model', 'id')
+        perms = sorted(perms, key=lambda n: get_index(n.content_type.app_label, n.content_type.model))
+        return perms
+
+    def get_menuname_of_contenttype(self, app_label, model):
+        for menu in MENU_TO_MODEL:
+            val = '{}-{}'.format(app_label, model)
+            if val in menu[1]:
+                return menu[0]
+        return u'未分类'
+
+    def save_group(self, id, name, permissions, user):
+        name = name.strip(u' ')
+        # old_permissions = None
+        if id == None or id == '':
+            is_exist = Group.objects.filter(name=name).first()
+            if is_exist:
+                raise CustomError(u'名称为[%s]的权限组已存在' % name)
+            group = Group.objects.create(name=name)
+            SysLog.objects.addnew(user, SysLog.INSERT, u"添加权限组[%s],id=%d" % (group.name, group.id))
+        else:
+            is_exist = Group.objects.filter(name=name).exclude(pk=id).first()
+            if is_exist:
+                raise CustomError(u'名称为[%s]的权限组已存在' % name)
+            group = Group.objects.filter(pk=id).first()
+            if not group:
+                raise CustomError(u'未找到相应的权限组')
+            group.name = name
+            group.save()
+            #    old_permissions = [p.id for p in group.permissions.all()]
+            SysLog.objects.addnew(user, SysLog.UPDATE, u"修改权限组[%s],id=%d" % (group.name, group.id))
+        group.permissions = permissions
+
+class User(AbstractBaseUser, PermissionsMixin):
+    ADMINSTRATOR = 1
+    STAFF = 2
+
+    type = models.PositiveSmallIntegerField(verbose_name=u"类型", editable=False)
+    department = models.ForeignKey(Department, verbose_name=u"所属部门", null=True, blank=True, on_delete=models.PROTECT)
+    username = models.CharField(verbose_name=u'帐号', max_length=30, unique=True, db_index=True)
+    is_active = models.BooleanField(verbose_name=u'激活', default=True)
+    date_joined = models.DateTimeField(verbose_name=u'注册时间', default=timezone.now, editable=False)
+
+    objects = UserManager()
+
+    USERNAME_FIELD = 'username'
+    REQUIRED_FIELDS = []
+
+    class Meta:
+        db_table = "staff_user"
+        verbose_name = u"账户管理"
+        unique_together = [
+            ('username')
+        ]
+        index_together = (
+            'date_joined',
+        )
+        ordering = ['-id']
+        default_permissions = ()
+        permissions = (
+            ("view_user", u"浏览"),
+            ("add_user", u"添加"),
+            ("edit_user", u"修改"),
+            ("delete_user", u"删除"),
+        )
+
+    def __unicode__(self):
+        return self.username
+
+    def add_administrator(self):
+        self.type = self.type | self.ADMINSTRATOR
+
+    def add_staff(self):
+        self.type = self.type | self.STAFF
+
+    def is_staff(self):
+        if self.type & self.STAFF:
+            return True
+        return False
+
+    def is_administrator(self):
+        if self.type & self.ADMINSTRATOR:
+            return True
+        return False
+
+    def change_password(self, new_password, confirm_password, old_password):
+        if new_password != confirm_password:
+            raise CustomError(u'两次输入的密码不一致, 请检查')
+        if not self.check_password(old_password):
+            raise CustomError(u'原密码输入错误, 请检查')
+        self.set_password(new_password)
+
+    def update_item(self, validated_data):
+        def update():
+            info = model_meta.get_field_info(self)
+            for attr, value in validated_data.items():
+                if attr in info.relations and info.relations[attr].to_many:
+                    field = getattr(self, attr)
+                    field.set(value)
+                else:
+                    setattr(self, attr, value)
+
+        if not 'username' in validated_data:
+            raise CustomError(u'用户名不能为空!')
+        count = User.objects.filter(username=validated_data['username']).exclude(id=self.id).count()
+        if count > 0:
+            raise CustomError(u'该用户名已存在!')
+
+        if not 'password' in validated_data or not validated_data['password']:
+            validated_data['password'] = self.password
+            update()
+        else:
+            update()
+            self.set_password(validated_data['password'])
+        self.save()
+        return self
+

+ 0 - 0
apps/system/__init__.py


+ 19 - 0
apps/system/filters.py

@@ -0,0 +1,19 @@
+# coding=utf-8
+
+import django_filters
+
+from .models import SysLog
+
+from utils.format import clean_datetime_range
+
+class SysLogFilter(django_filters.FilterSet):
+    type = django_filters.ChoiceFilter(choices=SysLog.TYPE_CHOICES, field_name='type')
+    create_time = django_filters.DateTimeFromToRangeFilter(field_name='create_time')
+
+    class Meta:
+        model = SysLog
+        fields = ('create_time', 'type', )
+
+    def __init__(self, data=None, *args, **kwargs):
+        data = clean_datetime_range(data, 'create_time')
+        super(SysLogFilter, self).__init__(data, *args, **kwargs)

+ 0 - 0
apps/system/migrations/__init__.py


+ 53 - 0
apps/system/models.py

@@ -0,0 +1,53 @@
+# coding=utf-8
+
+import json
+import datetime
+
+from django.db import models
+from django.utils import timezone
+from django.conf import settings
+
+from utils.format import strftime, strfdate
+
+class SysLogManager(models.Manager):
+    def addnew(self, user, type, description, data=None):
+        def default(o):
+            if isinstance(o, datetime.datetime):
+                return strftime(o)
+            elif isinstance(o, datetime.date):
+                return strfdate(o)
+
+        row = self.model(user=user, type=type, description=description)
+        if data:
+            row.data = json.dumps(data, default=default)
+        row.save()
+        return row
+
+class SysLog(models.Model):
+    INSERT = 1
+    UPDATE = 2
+    DELETE = 3
+    TYPE_CHOICES = (
+        (INSERT, u'添加'),
+        (UPDATE, u'修改'),
+        (DELETE, u'删除'),
+    )
+    TYPE_JSON = [{'id': item[0], 'value': item[1]} for item in TYPE_CHOICES]
+
+    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True, blank=True)
+    type = models.PositiveSmallIntegerField(choices=TYPE_CHOICES, verbose_name=u"类别")
+    description = models.CharField(max_length=1000, verbose_name=u"内容")
+    data = models.TextField(verbose_name=u"数据", null=True, blank=True)
+    create_time = models.DateTimeField(verbose_name=u"添加时间", default=timezone.now, editable=False)
+
+    objects = SysLogManager()
+
+    class Meta:
+        db_table = "sys_log"
+        ordering = ['-id']
+        index_together = (
+            'create_time',
+            'type',
+        )
+        verbose_name = u"系统日志"
+        default_permissions = ()

+ 0 - 0
ks/__init__.py


+ 214 - 0
ks/settings.py

@@ -0,0 +1,214 @@
+"""
+Django settings for ks project.
+
+Generated by 'django-admin startproject' using Django 2.2.5.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.2/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/2.2/ref/settings/
+"""
+
+import os, datetime
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = '-u0fk$orr=_6ac0$l8)4$n(k3-=p2)(pc(gt4wqt1js2u+ouo2'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = ['*']
+
+
+# Application definition
+
+INSTALLED_APPS = [
+    #'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+
+    'corsheaders',
+    'rest_framework',
+    'rest_framework_jwt',
+    'django_filters',
+
+    'apps.system',
+    'apps.foundation',
+    'apps.staff',
+    'apps.knowledge',
+    'apps.examination.exam',
+    'apps.examination.exampaper',
+    'apps.examination.examquestion',
+    'apps.practise.errorbook',
+    'apps.practise.practiselog',
+]
+
+MIDDLEWARE = [
+    'django.middleware.security.SecurityMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+    'corsheaders.middleware.CorsMiddleware',
+]
+
+CORS_ALLOW_CREDENTIALS = True
+CORS_ORIGIN_ALLOW_ALL = True
+CORS_ALLOW_METHODS = (
+    'DELETE',
+    'GET',
+    'OPTIONS',
+    'PATCH',
+    'POST',
+    'PUT',
+    'VIEW',
+)
+CORS_ALLOW_HEADERS = (
+    'XMLHttpRequest',
+    'X_FILENAME',
+    'accept-encoding',
+    'authorization',
+    'content-type',
+    'dnt',
+    'origin',
+    'token',
+    'user-agent',
+    'x-csrftoken',
+    'x-requested-with',
+    'Pragma',
+)
+
+ROOT_URLCONF = 'ks.urls'
+AUTH_USER_MODEL = "staff.User"
+AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.AllowAllUsersModelBackend']
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [],
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'ks.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.mysql',
+        'NAME': 'ks',
+        'USER': 'root',
+        'PASSWORD': 'root',
+        'HOST': '127.0.0.1',
+        'PORT': 3306,
+    }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+    {
+        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+    },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/2.2/topics/i18n/
+
+LANGUAGE_CODE = 'zh-hans'
+
+TIME_ZONE = 'Asia/Shanghai'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = False
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/2.2/howto/static-files/
+
+STATIC_URL = '/static/'
+
+MEDIA_URL = '/media/'
+MEDIA_ROOT = os.path.join(BASE_DIR, "uis/media/")
+
+UIS_URL = '/'
+UIS_ROOT = os.path.join(BASE_DIR, "uis/")
+
+JWT_AUTH = {
+    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=30),
+    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=360),
+    'JWT_ALLOW_REFRESH': True,
+}
+
+REST_FRAMEWORK = {
+    'DEFAULT_PERMISSION_CLASSES': (
+        'rest_framework.permissions.AllowAny',
+    ),
+    'DEFAULT_AUTHENTICATION_CLASSES': (
+        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
+        #'rest_framework.authentication.SessionAuthentication',
+        #'rest_framework.authentication.BasicAuthentication',
+    ),
+    'DEFAULT_PARSER_CLASSES': (
+        'rest_framework.parsers.JSONParser',
+        'rest_framework.parsers.FormParser',
+        'rest_framework.parsers.MultiPartParser'
+    ),
+    'DEFAULT_RENDERER_CLASSES': (
+        'rest_framework.renderers.JSONRenderer',
+        # 'rest_framework.renderers.BrowsableAPIRenderer',
+    ),
+    'DEFAULT_FILTER_BACKENDS': (
+        'django_filters.rest_framework.DjangoFilterBackend',
+    ),
+    #'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
+    'DEFAULT_PAGINATION_CLASS': 'utils.pagination.CustomPagination',
+    #'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
+    'EXCEPTION_HANDLER': 'utils.handler.custom_exception_handler',
+    'PAGE_SIZE': 10,
+    'DATETIME_FORMAT': "%Y-%m-%d %H:%M:%S",
+    'NON_FIELD_ERRORS_KEY': "error",  # 序列化器错误KEY名称
+}
+
+try:
+    from ks.local_settings import *
+except ImportError:
+    pass

+ 29 - 0
ks/urls.py

@@ -0,0 +1,29 @@
+"""ks URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/2.2/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  path('', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
+Including another URLconf
+    1. Import the include() function: from django.urls import include, path
+    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
+"""
+from django.conf.urls import url, include
+from django.conf.urls.static import static
+from django.conf import settings
+
+from apps.dashboard.views import index
+
+urlpatterns = [
+    url(r'^$', index),
+    url(r'^admin/', include('apps.api.admin.urls')),
+    url(r'^staff/', include('apps.api.staff.urls')),
+]
+
+urlpatterns += static(settings.UIS_URL, document_root=settings.UIS_ROOT)
+urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

+ 16 - 0
ks/wsgi.py

@@ -0,0 +1,16 @@
+"""
+WSGI config for ks project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ks.settings')
+
+application = get_wsgi_application()

+ 21 - 0
manage.py

@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ks.settings')
+    try:
+        from django.core.management import execute_from_command_line
+    except ImportError as exc:
+        raise ImportError(
+            "Couldn't import Django. Are you sure it's installed and "
+            "available on your PYTHONPATH environment variable? Did you "
+            "forget to activate a virtual environment?"
+        ) from exc
+    execute_from_command_line(sys.argv)
+
+
+if __name__ == '__main__':
+    main()

+ 5 - 0
requirements

@@ -0,0 +1,5 @@
+django==2.2.5
+django-filter
+djangorestframework
+djangorestframework-jwt
+django-cors-headers

+ 145 - 0
uis/admin/index.html

@@ -0,0 +1,145 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>燎原管理系统</title>
+  <meta name="renderer" content="webkit">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
+  <link rel="stylesheet" href="../layuiadmin/layui/css/layui.css" media="all">
+  <link rel="stylesheet" href="../layuiadmin/style/admin.css" media="all">
+</head>
+<body class="layui-layout-body">
+  
+  <div id="LAY_app">
+    <div class="layui-layout layui-layout-admin">
+      <div class="layui-header">
+        <!-- 头部区域 -->
+        <ul class="layui-nav layui-layout-left">
+          <li class="layui-nav-item layadmin-flexible" lay-unselect>
+            <a href="javascript:;" layadmin-event="flexible" title="侧边伸缩">
+              <i class="layui-icon layui-icon-shrink-right" id="LAY_app_flexible"></i>
+            </a>
+          </li>
+          <li class="layui-nav-item" lay-unselect>
+            <a href="javascript:;" layadmin-event="refresh" title="刷新">
+              <i class="layui-icon layui-icon-refresh-3"></i>
+            </a>
+          </li>
+        </ul>
+        <ul class="layui-nav layui-layout-right" lay-filter="layadmin-layout-right">
+          <li class="layui-nav-item layui-hide-xs" lay-unselect>
+            <a href="javascript:;" layadmin-event="theme">
+              <i class="layui-icon layui-icon-theme"></i>
+            </a>
+          </li>
+          <li class="layui-nav-item" lay-unselect>
+            <a href="javascript:;">
+              <cite id="id_username"></cite>
+            </a>
+            <dl class="layui-nav-child">
+              <dd><a lay-href="account/user_password.html">修改密码</a></dd>
+              <hr>
+              <dd layadmin-event="logout" style="text-align: center;"><a>退出</a></dd>
+            </dl>
+          </li>
+
+          <li class="layui-nav-item layui-hide-xs" lay-unselect>
+            <a href="javascript:;" layadmin-event="about"><i class="layui-icon layui-icon-more-vertical"></i></a>
+          </li>
+          <li class="layui-nav-item layui-show-xs-inline-block layui-hide-sm" lay-unselect>
+            <a href="javascript:;" layadmin-event="more"><i class="layui-icon layui-icon-more-vertical"></i></a>
+          </li>
+        </ul>
+      </div>
+      
+      <!-- 侧边菜单 -->
+      <div class="layui-side layui-side-menu">
+        <div class="layui-side-scroll">
+          <div class="layui-logo">
+            <span>燎原管理系统</span>
+          </div>
+
+          <ul class="layui-nav layui-nav-tree" lay-shrink="all" id="LAY-system-side-muen" lay-filter="layadmin-system-side-menu">
+            <li data-name="set" class="layui-nav-item">
+              <a href="javascript:;" lay-tips="基础信息" lay-direction="2">
+                <i class="layui-icon layui-icon-set"></i>
+                <cite>基础信息</cite>
+              </a>
+              <dl class="layui-nav-child">
+                <dd data-name="nav">
+                  <a lay-href="user/index.html">用户管理</a>
+                </dd>
+                <dd data-name="nav">
+                  <a lay-href="tenant/index.html">租户管理</a>
+                </dd>
+                <dd data-name="nav">
+                  <a lay-href="applet/index.html">小程序管理</a>
+                </dd>
+                <dd data-name="nav">
+                  <a lay-href="third_party/index.html">第三方设置</a>
+                </dd>
+              </dl>
+            </li>
+          </ul>
+        </div>
+      </div>
+
+      <!-- 页面标签 -->
+      <div class="layadmin-pagetabs" id="LAY_app_tabs">
+        <div class="layui-icon layadmin-tabs-control layui-icon-prev" layadmin-event="leftPage"></div>
+        <div class="layui-icon layadmin-tabs-control layui-icon-next" layadmin-event="rightPage"></div>
+        <div class="layui-icon layadmin-tabs-control layui-icon-down">
+          <ul class="layui-nav layadmin-tabs-select" lay-filter="layadmin-pagetabs-nav">
+            <li class="layui-nav-item" lay-unselect>
+              <a href="javascript:;"></a>
+              <dl class="layui-nav-child layui-anim-fadein">
+                <dd layadmin-event="closeThisTabs"><a href="javascript:;">关闭当前标签页</a></dd>
+                <dd layadmin-event="closeOtherTabs"><a href="javascript:;">关闭其它标签页</a></dd>
+                <dd layadmin-event="closeAllTabs"><a href="javascript:;">关闭全部标签页</a></dd>
+              </dl>
+            </li>
+          </ul>
+        </div>
+        <div class="layui-tab" lay-unauto lay-allowClose="true" lay-filter="layadmin-layout-tabs">
+          <ul class="layui-tab-title" id="LAY_app_tabsheader">
+            <li lay-id="home/console.html" class="layui-this"><i class="layui-icon layui-icon-home"></i></li>
+          </ul>
+        </div>
+      </div>
+      
+      
+      <!-- 主体内容 -->
+      <div class="layui-body" id="LAY_app_body">
+        <div class="layadmin-tabsbody-item layui-show">
+          <iframe src="dashboard/index.html" frameborder="0" class="layadmin-iframe"></iframe>
+        </div>
+      </div>
+      
+      <!-- 辅助元素,一般用于移动设备下遮罩 -->
+      <div class="layadmin-body-shade" layadmin-event="shade"></div>
+    </div>
+  </div>
+
+  <script src="../layuiadmin/layui/layui.js"></script>
+  <script>
+  layui.config({
+    base: '../layuiadmin/' //静态资源所在路径
+  }).extend({
+    index: 'lib/index' //主入口模块
+  }).use('index', function () {
+      var $ = layui.$;
+      var name = layui.data(layui.setter.tableName)['name'];
+      $('#id_username').html(name);
+
+      $('#LAY-system-side-muen .layui-nav-item dl').each(function () {
+          if($(this).children('dd').length == 0)
+              $(this).parent().remove();
+      });
+
+  });
+  </script>
+</body>
+</html>
+
+

+ 118 - 0
uis/admin/login/login.html

@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>燎原管理系统</title>
+  <meta name="renderer" content="webkit">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
+  <link rel="stylesheet" href="../../layuiadmin/layui/css/layui.css" media="all">
+  <link rel="stylesheet" href="../../layuiadmin/style/admin.css" media="all">
+  <link rel="stylesheet" href="../../layuiadmin/style/login.css" media="all">
+</head>
+<body>
+
+  <div class="layadmin-user-login layadmin-user-display-show" id="LAY-user-login" style="display: none;">
+
+    <div class="layadmin-user-login-main">
+      <div class="layadmin-user-login-box layadmin-user-login-header">
+        <h2>燎原管理系统</h2>
+      </div>
+      <form class="layui-form" action="" lay-filter="component-form-element">
+      <div class="layadmin-user-login-box layadmin-user-login-body layui-form">
+        <div class="layui-form-item">
+          <label class="layadmin-user-login-icon layui-icon layui-icon-username" for="LAY-user-login-username"></label>
+          <input type="text" name="username" id="LAY-user-login-username" placeholder="用户名" autocomplete="off" class="layui-input">
+        </div>
+        <div class="layui-form-item">
+          <label class="layadmin-user-login-icon layui-icon layui-icon-password" for="LAY-user-login-password"></label>
+          <input type="password" name="password" id="LAY-user-login-password" autocomplete="off" placeholder="密码" class="layui-input">
+        </div>
+        <div class="layui-form-item">
+          <button class="layui-btn layui-btn-fluid" lay-submit lay-filter="component-form-element">登 录</button>
+        </div>
+      </div>
+       </form>
+    </div>
+    
+    <div class="layui-trans layadmin-user-login-footer">
+      <p>© 2020 燎原管理系统 <a href="http://www.zzliaoyuan.com/" target="_blank">郑州燎原计算机技术有限公司</a></p>
+    </div>
+    
+  </div>
+
+  <script src="../../layuiadmin/layui/layui.js"></script>
+  <script>
+  layui.config({
+    base: '../../layuiadmin/' //静态资源所在路径
+  }).extend({
+    index: 'lib/index' //主入口模块
+  }).use(['index', 'user'], function(){
+    var $ = layui.$
+    ,setter = layui.setter
+    ,admin = layui.admin
+    ,form = layui.form
+    ,router = layui.router()
+    ,search = router.search;
+
+    if (layui.data(setter.tableName)[setter.request.tokenName]) {
+      admin.req({
+        url: '/admin/token_refresh/'
+        ,data: {token: layui.data(setter.tableName)[setter.request.tokenName].substr(4)}
+        ,type: 'post'
+        ,done: function(res){
+
+          //请求成功后,写入 access_token
+          layui.data(setter.tableName, {
+            key: setter.request.tokenName
+            ,value: 'JWT ' + res.data.token
+          });
+
+          location.href = '../index.html'; //后台主页
+        }
+      });
+    }
+
+    form.render();
+
+    //提交
+    form.on('submit(component-form-element)', function(obj){
+
+      //请求登入接口
+      admin.req({
+        url: '/admin/token/obtain/'
+        ,data: obj.field
+        ,type: 'post'
+        ,done: function(res){
+
+          //请求成功后,写入 access_token
+          layui.data(setter.tableName, {
+            key: setter.request.tokenName
+            ,value: 'JWT ' + res.data.token
+          });
+          layui.data(setter.tableName, {
+            key: setter.request.userId
+            ,value: res.data.user_id
+          });
+          layui.data(setter.tableName, {
+            key: 'name'
+            ,value: res.data.name ? res.data.name: res.data.username
+          });
+
+          //登入成功的提示与跳转
+          layer.msg('登入成功', {
+            offset: '15px'
+            ,icon: 1
+            ,time: 1000
+          }, function(){
+            location.href = '../index.html'; //后台主页
+          });
+        }
+      });
+      return false;
+      
+    });
+  });
+  </script>
+</body>
+</html>

+ 95 - 0
uis/layuiadmin/config.js

@@ -0,0 +1,95 @@
+/**
+
+ @Name:layuiAdmin iframe版全局配置
+ @Author:贤心
+ @Site:http://www.layui.com/admin/
+ @License:LPPL(layui付费产品协议)
+    
+ */
+ 
+layui.define(['laytpl', 'layer', 'element', 'util'], function(exports){
+  exports('setter', {
+    container: 'LAY_app' //容器ID
+    ,base: layui.cache.base //记录静态资源所在路径
+    ,views: layui.cache.base + 'tpl/' //动态模板所在目录
+    ,entry: 'index' //默认视图文件名
+    ,engine: '.html' //视图文件后缀名
+    ,pageTabs: true //是否开启页面选项卡功能。iframe 常规版推荐开启
+    
+    ,name: 'layuiAdmin'
+    ,tableName: 'layuiAdmin' //本地存储表名
+    ,MOD_NAME: 'admin' //模块事件名
+    
+    ,debug: false //是否开启调试模式。如开启,接口异常时会抛出异常 URL 等信息
+
+    //自定义请求字段
+    ,request: {
+      userId: 'USER-ID',
+      tokenName: 'Authorization' //自动携带 token 的字段名(如:access_token)。可设置 false 不携带。
+    }
+    
+    //自定义响应字段
+    ,response: {
+      statusName: 'code' //数据状态的字段名称
+      ,statusCode: {
+        ok: 0 //数据状态一切正常的状态码
+        ,logout: 460 //登录状态失效的状态码
+      }
+      ,msgName: 'msg' //状态信息的字段名称
+      ,dataName: 'data' //数据详情的字段名称
+    }
+    
+    //扩展的第三方模块
+    ,extend: [
+      'echarts', //echarts 核心包
+      'echartsTheme' //echarts 主题
+    ]
+    
+    //主题配置
+    ,theme: {
+      //配色方案,如果用户未设置主题,第一个将作为默认
+      color: [{
+        main: '#20222A' //主题色
+        ,selected: '#009688' //选中色
+        ,alias: 'default' //默认别名
+      },{
+        main: '#03152A'
+        ,selected: '#3B91FF'
+        ,alias: 'dark-blue' //藏蓝
+      },{
+        main: '#2E241B'
+        ,selected: '#A48566'
+        ,alias: 'coffee' //咖啡
+      },{
+        main: '#50314F'
+        ,selected: '#7A4D7B'
+        ,alias: 'purple-red' //紫红
+      },{
+        main: '#344058'
+        ,logo: '#1E9FFF'
+        ,selected: '#1E9FFF'
+        ,alias: 'ocean' //海洋
+      },{
+        main: '#3A3D49'
+        ,logo: '#2F9688'
+        ,selected: '#5FB878'
+        ,alias: 'green' //墨绿
+      },{
+        main: '#20222A'
+        ,logo: '#F78400'
+        ,selected: '#F78400'
+        ,alias: 'red' //橙色
+      },{
+        main: '#28333E'
+        ,logo: '#AA3130'
+        ,selected: '#AA3130'
+        ,alias: 'fashion-red' //时尚红
+      },{
+        main: '#24262F'
+        ,logo: '#3A3D49'
+        ,selected: '#009688'
+        ,alias: 'classic-black' //经典黑
+      }]
+    }
+  });
+});

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 0
uis/layuiadmin/layui/css/layui.css


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 0
uis/layuiadmin/layui/css/layui.mobile.css


+ 2 - 0
uis/layuiadmin/layui/css/modules/code.css

@@ -0,0 +1,2 @@
+/** layui-v2.4.5 MIT License By https://www.layui.com */
+ html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #e2e2e2;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:32px;line-height:32px;border-bottom:1px solid #e2e2e2}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 5px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 0
uis/layuiadmin/layui/css/modules/laydate/default/laydate.css


BIN
uis/layuiadmin/layui/css/modules/layer/default/icon-ext.png


BIN
uis/layuiadmin/layui/css/modules/layer/default/icon.png


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 0
uis/layuiadmin/layui/css/modules/layer/default/layer.css


BIN
uis/layuiadmin/layui/css/modules/layer/default/loading-0.gif


BIN
uis/layuiadmin/layui/css/modules/layer/default/loading-1.gif


BIN
uis/layuiadmin/layui/css/modules/layer/default/loading-2.gif


BIN
uis/layuiadmin/layui/font/iconfont.eot


Dosya farkı çok büyük olduğundan ihmal edildi
+ 25 - 0
uis/layuiadmin/layui/font/iconfont.svg


BIN
uis/layuiadmin/layui/font/iconfont.ttf


BIN
uis/layuiadmin/layui/font/iconfont.woff


BIN
uis/layuiadmin/layui/images/face/0.gif


BIN
uis/layuiadmin/layui/images/face/1.gif


BIN
uis/layuiadmin/layui/images/face/10.gif


BIN
uis/layuiadmin/layui/images/face/11.gif


BIN
uis/layuiadmin/layui/images/face/12.gif


BIN
uis/layuiadmin/layui/images/face/13.gif


BIN
uis/layuiadmin/layui/images/face/14.gif


BIN
uis/layuiadmin/layui/images/face/15.gif


BIN
uis/layuiadmin/layui/images/face/16.gif


BIN
uis/layuiadmin/layui/images/face/17.gif


BIN
uis/layuiadmin/layui/images/face/18.gif


BIN
uis/layuiadmin/layui/images/face/19.gif


BIN
uis/layuiadmin/layui/images/face/2.gif


BIN
uis/layuiadmin/layui/images/face/20.gif


BIN
uis/layuiadmin/layui/images/face/21.gif


BIN
uis/layuiadmin/layui/images/face/22.gif


BIN
uis/layuiadmin/layui/images/face/23.gif


BIN
uis/layuiadmin/layui/images/face/24.gif


Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor