@@ -8,7 +8,7 @@ from mch.models import ConsumeInfoSubmitLogInfo |
||
8 | 8 |
|
9 | 9 |
|
10 | 10 |
class UserInfoAdmin(ChangeOnlyModelAdmin, admin.ModelAdmin): |
11 |
- list_display = ('user_id', 'username', 'unionid', 'openid', 'openid_miniapp', 'name', 'sex', 'nickname', 'phone', 'location', 'balance', 'user_status', 'test_user', 'status', 'created_at', 'updated_at') |
|
11 |
+ list_display = ('user_id', 'unionid', 'openid', 'nickname', 'phone', 'location', 'balance', 'user_status', 'test_user', 'status', 'created_at', 'updated_at') |
|
12 | 12 |
list_filter = ('test_user', 'sex', 'user_status', 'status') |
13 | 13 |
readonly_fields = ('user_id', ) |
14 | 14 |
search_fields = ('user_id', 'username', 'unionid', 'openid', 'openid_miniapp', 'name', 'phone', 'location') |
@@ -14,7 +14,7 @@ from group import views as group_views |
||
14 | 14 |
from message import views as message_views |
15 | 15 |
from miniapp import views as mini_views |
16 | 16 |
from operation import views as op_views |
17 |
-from page import oauth_views, sale_views |
|
17 |
+from page import oauth_views, sale_views, screen_views |
|
18 | 18 |
from pay import views as pay_views |
19 | 19 |
from photo import views as photo_views |
20 | 20 |
from server import server_views |
@@ -269,3 +269,8 @@ urlpatterns += [ |
||
269 | 269 |
url(r'^clerk/update$', clerk_views.clerk_update, name='clerk_update'), |
270 | 270 |
url(r'^clerk/list$', clerk_views.clerk_list, name='clerk_list'), |
271 | 271 |
] |
272 |
+ |
|
273 |
+urlpatterns += [ |
|
274 |
+ url(r'^screen/admin/loginqr$', screen_views.screen_admin_loginqr, name='screen_admin_loginqr'), |
|
275 |
+ url(r'^screen/admin/loginrst$', screen_views.screen_admin_loginrst, name='screen_admin_loginrst'), |
|
276 |
+] |
@@ -0,0 +1,15 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+ |
|
3 |
+from django.contrib import admin |
|
4 |
+from django_admin import ChangeOnlyModelAdmin, ReadOnlyModelAdmin |
|
5 |
+ |
|
6 |
+from guideline.models import ScreenAdminInfo |
|
7 |
+ |
|
8 |
+ |
|
9 |
+class ScreenAdminInfoAdmin(ChangeOnlyModelAdmin, admin.ModelAdmin): |
|
10 |
+ list_display = ('admin_id', 'unionid', 'openid', 'name', 'sex', 'nickname', 'phone', 'location', 'status', 'created_at', 'updated_at') |
|
11 |
+ readonly_fields = ('admin_id',) |
|
12 |
+ search_fields = ('admin_id', 'unionid', 'openid', 'name', 'phone', 'location') |
|
13 |
+ |
|
14 |
+ |
|
15 |
+admin.site.register(ScreenAdminInfo, ScreenAdminInfoAdmin) |
@@ -0,0 +1,8 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+from __future__ import unicode_literals |
|
3 |
+ |
|
4 |
+from django.apps import AppConfig |
|
5 |
+ |
|
6 |
+ |
|
7 |
+class GuidelineConfig(AppConfig): |
|
8 |
+ name = 'guideline' |
@@ -0,0 +1,48 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+# Generated by Django 1.11.16 on 2018-11-14 20:44 |
|
3 |
+from __future__ import unicode_literals |
|
4 |
+ |
|
5 |
+from django.db import migrations, models |
|
6 |
+ |
|
7 |
+ |
|
8 |
+class Migration(migrations.Migration): |
|
9 |
+ |
|
10 |
+ initial = True |
|
11 |
+ |
|
12 |
+ dependencies = [ |
|
13 |
+ ] |
|
14 |
+ |
|
15 |
+ operations = [ |
|
16 |
+ migrations.CreateModel( |
|
17 |
+ name='ScreenAdminInfo', |
|
18 |
+ fields=[ |
|
19 |
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
20 |
+ ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')), |
|
21 |
+ ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), |
|
22 |
+ ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), |
|
23 |
+ ('admin_id', models.CharField(blank=True, db_index=True, help_text='\u5927\u5c4f\u7ba1\u7406\u5458\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, unique=True, verbose_name='admin_id')), |
|
24 |
+ ('unionid', models.CharField(blank=True, db_index=True, help_text='\u5fae\u4fe1 Union ID', max_length=32, null=True, verbose_name='unionid')), |
|
25 |
+ ('openid', models.CharField(blank=True, db_index=True, help_text='\u5fae\u4fe1 Open ID', max_length=32, null=True, verbose_name='openid')), |
|
26 |
+ ('name', models.CharField(blank=True, help_text='\u7528\u6237\u59d3\u540d', max_length=8, null=True, verbose_name='name')), |
|
27 |
+ ('sex', models.IntegerField(choices=[(1, '\u7537'), (0, '\u5973')], default=1, help_text='\u7528\u6237\u6027\u522b', verbose_name='sex')), |
|
28 |
+ ('nickname', models.CharField(blank=True, help_text='\u7528\u6237\u6635\u79f0', max_length=255, null=True, verbose_name='nickname')), |
|
29 |
+ ('avatar', models.CharField(blank=True, help_text='\u7528\u6237\u5934\u50cf', max_length=255, null=True, verbose_name='avatar')), |
|
30 |
+ ('phone', models.CharField(blank=True, db_index=True, help_text='\u7528\u6237\u7535\u8bdd', max_length=11, null=True, verbose_name='phone')), |
|
31 |
+ ('country', models.CharField(blank=True, help_text='\u7528\u6237\u56fd\u5bb6', max_length=16, null=True, verbose_name='country')), |
|
32 |
+ ('province', models.CharField(blank=True, help_text='\u7528\u6237\u7701\u4efd', max_length=16, null=True, verbose_name='province')), |
|
33 |
+ ('city', models.CharField(blank=True, help_text='\u7528\u6237\u57ce\u5e02', max_length=16, null=True, verbose_name='city')), |
|
34 |
+ ('location', models.CharField(blank=True, help_text='\u7528\u6237\u5730\u5740', max_length=255, null=True, verbose_name='location')), |
|
35 |
+ ('brand_id', models.CharField(blank=True, db_index=True, help_text='\u54c1\u724c\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, verbose_name='brand_id')), |
|
36 |
+ ('brand_name', models.CharField(blank=True, help_text='\u54c1\u724c\u540d\u79f0', max_length=255, null=True, verbose_name='brand_name')), |
|
37 |
+ ('user_status', models.IntegerField(choices=[(1, '\u5df2\u6fc0\u6d3b'), (2, '\u5df2\u7981\u7528'), (3, '\u5df2\u5220\u9664')], db_index=True, default=1, help_text='\u7ba1\u7406\u5458\u72b6\u6001', verbose_name='user_status')), |
|
38 |
+ ], |
|
39 |
+ options={ |
|
40 |
+ 'verbose_name': 'ScreenAdminInfo', |
|
41 |
+ 'verbose_name_plural': 'ScreenAdminInfo', |
|
42 |
+ }, |
|
43 |
+ ), |
|
44 |
+ migrations.AlterUniqueTogether( |
|
45 |
+ name='screenadmininfo', |
|
46 |
+ unique_together=set([('brand_id', 'unionid', 'openid')]), |
|
47 |
+ ), |
|
48 |
+ ] |
@@ -0,0 +1,63 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+ |
|
3 |
+from django.db import models |
|
4 |
+from django.utils.translation import ugettext_lazy as _ |
|
5 |
+from django_models_ext import BaseModelMixin |
|
6 |
+ |
|
7 |
+ |
|
8 |
+class ScreenAdminInfo(BaseModelMixin): |
|
9 |
+ MALE = 1 |
|
10 |
+ FEMALE = 0 |
|
11 |
+ |
|
12 |
+ SEX_TYPE_TUPLE = ( |
|
13 |
+ (MALE, u'男'), |
|
14 |
+ (FEMALE, u'女'), |
|
15 |
+ ) |
|
16 |
+ |
|
17 |
+ ACTIVATED = 1 |
|
18 |
+ DISABLED = 2 |
|
19 |
+ DELETED = 3 |
|
20 |
+ |
|
21 |
+ USER_STATUS_TUPLE = ( |
|
22 |
+ (ACTIVATED, u'已激活'), |
|
23 |
+ (DISABLED, u'已禁用'), |
|
24 |
+ (DELETED, u'已删除'), |
|
25 |
+ ) |
|
26 |
+ |
|
27 |
+ admin_id = models.CharField(_(u'admin_id'), max_length=32, blank=True, null=True, help_text=u'大屏管理员唯一标识', db_index=True, unique=True) |
|
28 |
+ |
|
29 |
+ unionid = models.CharField(_(u'unionid'), max_length=32, blank=True, null=True, help_text=u'微信 Union ID', db_index=True) |
|
30 |
+ openid = models.CharField(_(u'openid'), max_length=32, blank=True, null=True, help_text=u'微信 Open ID', db_index=True) |
|
31 |
+ |
|
32 |
+ name = models.CharField(_(u'name'), max_length=8, blank=True, null=True, help_text=u'用户姓名') |
|
33 |
+ sex = models.IntegerField(_(u'sex'), choices=SEX_TYPE_TUPLE, default=MALE, help_text=u'用户性别') |
|
34 |
+ nickname = models.CharField(_(u'nickname'), max_length=255, blank=True, null=True, help_text=u'用户昵称') |
|
35 |
+ avatar = models.CharField(_(u'avatar'), max_length=255, blank=True, null=True, help_text=u'用户头像') |
|
36 |
+ phone = models.CharField(_(u'phone'), max_length=11, blank=True, null=True, help_text=u'用户电话', db_index=True) |
|
37 |
+ country = models.CharField(_(u'country'), max_length=16, blank=True, null=True, help_text=u'用户国家') |
|
38 |
+ province = models.CharField(_(u'province'), max_length=16, blank=True, null=True, help_text=u'用户省份') |
|
39 |
+ city = models.CharField(_(u'city'), max_length=16, blank=True, null=True, help_text=u'用户城市') |
|
40 |
+ location = models.CharField(_(u'location'), max_length=255, blank=True, null=True, help_text=u'用户地址') |
|
41 |
+ |
|
42 |
+ brand_id = models.CharField(_(u'brand_id'), max_length=32, blank=True, null=True, help_text=u'品牌唯一标识', db_index=True) |
|
43 |
+ brand_name = models.CharField(_(u'brand_name'), max_length=255, blank=True, null=True, help_text=u'品牌名称') |
|
44 |
+ |
|
45 |
+ user_status = models.IntegerField(_(u'user_status'), choices=USER_STATUS_TUPLE, default=ACTIVATED, help_text=u'管理员状态', db_index=True) |
|
46 |
+ |
|
47 |
+ class Meta: |
|
48 |
+ verbose_name = _(u'ScreenAdminInfo') |
|
49 |
+ verbose_name_plural = _(u'ScreenAdminInfo') |
|
50 |
+ |
|
51 |
+ unique_together = ( |
|
52 |
+ ('brand_id', 'unionid', 'openid'), |
|
53 |
+ ) |
|
54 |
+ |
|
55 |
+ def __unicode__(self): |
|
56 |
+ return unicode(self.pk) |
|
57 |
+ |
|
58 |
+ @property |
|
59 |
+ def data(self): |
|
60 |
+ return { |
|
61 |
+ 'nickname': self.nickname, |
|
62 |
+ 'avatar': self.avatar, |
|
63 |
+ } |
@@ -0,0 +1,7 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+from __future__ import unicode_literals |
|
3 |
+ |
|
4 |
+from django.test import TestCase |
|
5 |
+ |
|
6 |
+ |
|
7 |
+# Create your tests here. |
@@ -0,0 +1,7 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+from __future__ import unicode_literals |
|
3 |
+ |
|
4 |
+from django.shortcuts import render |
|
5 |
+ |
|
6 |
+ |
|
7 |
+# Create your views here. |
@@ -0,0 +1,27 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+ |
|
3 |
+import os |
|
4 |
+ |
|
5 |
+ |
|
6 |
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
|
7 |
+PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__))) |
|
8 |
+ |
|
9 |
+TEMPLATES = [ |
|
10 |
+ { |
|
11 |
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates', |
|
12 |
+ 'DIRS': [os.path.join(BASE_DIR, 'templates')], |
|
13 |
+ # 'APP_DIRS': True, |
|
14 |
+ 'OPTIONS': { |
|
15 |
+ 'context_processors': [ |
|
16 |
+ 'django.template.context_processors.debug', |
|
17 |
+ 'django.template.context_processors.request', |
|
18 |
+ 'django.contrib.auth.context_processors.auth', |
|
19 |
+ 'django.contrib.messages.context_processors.messages', |
|
20 |
+ ], |
|
21 |
+ 'loaders': [ |
|
22 |
+ 'django.template.loaders.filesystem.Loader', |
|
23 |
+ 'django.template.loaders.app_directories.Loader', |
|
24 |
+ ], |
|
25 |
+ }, |
|
26 |
+ }, |
|
27 |
+] |
@@ -0,0 +1,27 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+ |
|
3 |
+import os |
|
4 |
+ |
|
5 |
+ |
|
6 |
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
|
7 |
+PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__))) |
|
8 |
+ |
|
9 |
+TEMPLATES = [ |
|
10 |
+ { |
|
11 |
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates', |
|
12 |
+ 'DIRS': [os.path.join(BASE_DIR, 'templates')], |
|
13 |
+ # 'APP_DIRS': True, |
|
14 |
+ 'OPTIONS': { |
|
15 |
+ 'context_processors': [ |
|
16 |
+ 'django.template.context_processors.debug', |
|
17 |
+ 'django.template.context_processors.request', |
|
18 |
+ 'django.contrib.auth.context_processors.auth', |
|
19 |
+ 'django.contrib.messages.context_processors.messages', |
|
20 |
+ ], |
|
21 |
+ 'loaders': [ |
|
22 |
+ 'django.template.loaders.filesystem.Loader', |
|
23 |
+ 'django.template.loaders.app_directories.Loader', |
|
24 |
+ ], |
|
25 |
+ }, |
|
26 |
+ }, |
|
27 |
+] |
@@ -54,6 +54,7 @@ INSTALLED_APPS = ( |
||
54 | 54 |
'box', |
55 | 55 |
'commands', |
56 | 56 |
'group', |
57 |
+ 'guideline', |
|
57 | 58 |
'integral', |
58 | 59 |
'logs', |
59 | 60 |
'mch', |
@@ -390,11 +391,20 @@ KODO_DEFAULT_BRAND_NAME = '' |
||
390 | 391 |
KODO_DEFAULT_BRAND_DOMAIN = '' |
391 | 392 |
|
392 | 393 |
KODO_CLERK_AUTH_URL = 'http://pai.ai/w/o?r=http%3A%2F%2Fkodo.xfoto.com.cn%2Fp%2Fclerk%3Fbrand_id%3D{0}' |
394 |
+KODO_SCREEN_AUTH_URL = 'http://pai.ai/w/o?r=http%3A%2F%2Fkodo.xfoto.com.cn%2Fp%2Fscreen%2Fadmin%2Foauth%3Fbrand_id%3D{0}' |
|
395 |
+KODO_SCREEN_LOGIN_URL = 'http://pai.ai/w/o?s=snsapi_base&r=http%3A%2F%2Fkodo.xfoto.com.cn%2Fp%2Fscreen%2Fadmin%2Flogin/%3Fbrand_id%3D{0}%26token%3D{1}' |
|
393 | 396 |
|
394 | 397 |
# 经纬度 |
395 | 398 |
GIS_2_ADMINISTRATIVE_DIVISION = 'http://116.196.105.215:1234/gis?auth_user=freevip&latitude={0}&longitude={1}' |
396 | 399 |
PHONE_2_ADMINISTRATIVE_DIVISION = 'https://www.baifubao.com/callback?cmd=1059&callback=phone&phone={0}' |
397 | 400 |
|
401 |
+# 开发调试相关配置 |
|
402 |
+if DEBUG: |
|
403 |
+ try: |
|
404 |
+ from local_settings_dev import * |
|
405 |
+ except ImportError: |
|
406 |
+ pass |
|
407 |
+ |
|
398 | 408 |
try: |
399 | 409 |
from local_settings import * |
400 | 410 |
except ImportError: |
@@ -0,0 +1,79 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+ |
|
3 |
+import shortuuid |
|
4 |
+from django.conf import settings |
|
5 |
+from django_response import response |
|
6 |
+from json_render import json_render |
|
7 |
+ |
|
8 |
+from guideline.models import ScreenAdminInfo |
|
9 |
+from utils.error.errno_utils import PermissionStatusCode |
|
10 |
+from utils.redis.connect import r |
|
11 |
+from utils.redis.rkeys import KODO_SCREEN_ADMIN_LOGIN |
|
12 |
+ |
|
13 |
+ |
|
14 |
+def screen_admin_oauthqr(request): |
|
15 |
+ brand_id = request.GET.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) |
|
16 |
+ |
|
17 |
+ return json_render(request, 'page/screen_admin_oauth_qrcode.html', unjsondumpsdict={ |
|
18 |
+ 'qr': settings.KODO_SCREEN_AUTH_URL.format(brand_id) |
|
19 |
+ }) |
|
20 |
+ |
|
21 |
+ |
|
22 |
+def screen_admin_oauth(request): |
|
23 |
+ brand_id = request.GET.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) |
|
24 |
+ unionid = request.GET.get('unionid', '') |
|
25 |
+ openid = request.GET.get('openid', '') |
|
26 |
+ |
|
27 |
+ ScreenAdminInfo.objects.update_or_create(brand_id=brand_id, unionid=unionid, openid=openid, defaults={ |
|
28 |
+ 'nickname': request.GET.get('nickname', ''), |
|
29 |
+ 'avatar': request.GET.get('avatar', ''), |
|
30 |
+ 'user_status': ScreenAdminInfo.ACTIVATED, |
|
31 |
+ }) |
|
32 |
+ |
|
33 |
+ return json_render(request, 'page/screen_admin_oauth_success.html', unjsondumpsdict={ |
|
34 |
+ }) |
|
35 |
+ |
|
36 |
+ |
|
37 |
+def screen_admin_loginqr(request): |
|
38 |
+ brand_id = request.GET.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) |
|
39 |
+ |
|
40 |
+ token = shortuuid.uuid() |
|
41 |
+ |
|
42 |
+ return response(200, { |
|
43 |
+ 'qr': settings.KODO_SCREEN_LOGIN_URL.format(brand_id, token), |
|
44 |
+ 'token': token, |
|
45 |
+ }) |
|
46 |
+ |
|
47 |
+ |
|
48 |
+def screen_admin_login(request): |
|
49 |
+ brand_id = request.GET.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) |
|
50 |
+ unionid = request.GET.get('unionid', '') |
|
51 |
+ openid = request.GET.get('openid', '') |
|
52 |
+ token = request.GET.get('token', '') |
|
53 |
+ |
|
54 |
+ try: |
|
55 |
+ admin = ScreenAdminInfo.objects.get(unionid=unionid, user_status=ScreenAdminInfo.ACTIVATED) |
|
56 |
+ except ScreenAdminInfo.DoesNotExist: |
|
57 |
+ return json_render(request, 'page/screen_admin_login_fail.html', unjsondumpsdict={ |
|
58 |
+ }) |
|
59 |
+ |
|
60 |
+ r.setex(KODO_SCREEN_ADMIN_LOGIN % (brand_id, token), r.REDIS_EXPIRED_HALF_HOUR, unionid) |
|
61 |
+ |
|
62 |
+ return json_render(request, 'page/screen_admin_login_success.html', unjsondumpsdict={ |
|
63 |
+ }) |
|
64 |
+ |
|
65 |
+ |
|
66 |
+def screen_admin_loginrst(request): |
|
67 |
+ brand_id = request.GET.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) |
|
68 |
+ token = request.GET.get('token', '') |
|
69 |
+ |
|
70 |
+ unionid = r.get(KODO_SCREEN_ADMIN_LOGIN % (brand_id, token)) |
|
71 |
+ |
|
72 |
+ try: |
|
73 |
+ admin = ScreenAdminInfo.objects.get(unionid=unionid, user_status=ScreenAdminInfo.ACTIVATED) |
|
74 |
+ except ScreenAdminInfo.DoesNotExist: |
|
75 |
+ return response(PermissionStatusCode.PERMISSION_DENIED) |
|
76 |
+ |
|
77 |
+ return response(200, { |
|
78 |
+ 'info': admin.data, |
|
79 |
+ }) |
@@ -0,0 +1,12 @@ |
||
1 |
+<!DOCTYPE html> |
|
2 |
+<html lang="en"> |
|
3 |
+<head> |
|
4 |
+ <meta charset="UTF-8"> |
|
5 |
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
6 |
+ <meta http-equiv="X-UA-Compatible" content="ie=edge"> |
|
7 |
+ <title>登录失败</title> |
|
8 |
+</head> |
|
9 |
+<body> |
|
10 |
+ <div class="" style="text-align:center;margin-top:100px;font-size:25px;">登录失败</div> |
|
11 |
+</body> |
|
12 |
+</html> |
@@ -0,0 +1,12 @@ |
||
1 |
+<!DOCTYPE html> |
|
2 |
+<html lang="en"> |
|
3 |
+<head> |
|
4 |
+ <meta charset="UTF-8"> |
|
5 |
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
6 |
+ <meta http-equiv="X-UA-Compatible" content="ie=edge"> |
|
7 |
+ <title>登录成功</title> |
|
8 |
+</head> |
|
9 |
+<body> |
|
10 |
+ <div class="" style="text-align:center;margin-top:100px;font-size:25px;">登录成功</div> |
|
11 |
+</body> |
|
12 |
+</html> |
@@ -0,0 +1,64 @@ |
||
1 |
+{% load staticfiles %} |
|
2 |
+ |
|
3 |
+<!DOCTYPE html> |
|
4 |
+<html lang="zh-CN"> |
|
5 |
+ <head> |
|
6 |
+ <meta charset="utf-8"> |
|
7 |
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> |
|
8 |
+ <meta name="format-detection" content="telephone=no,email=no,address=no"> |
|
9 |
+ <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"> |
|
10 |
+ <title>授权登录二维码</title> |
|
11 |
+ |
|
12 |
+ <link href="//res.wx.qq.com/open/libs/weui/0.4.3/weui.min.css" rel="stylesheet" type="text/css" /> |
|
13 |
+ |
|
14 |
+ <style> |
|
15 |
+ input:required:invalid { |
|
16 |
+ color: #E64340; |
|
17 |
+ } |
|
18 |
+ input:required:valid { |
|
19 |
+ color: rgb(0, 0, 0); |
|
20 |
+ } |
|
21 |
+ .hidden { |
|
22 |
+ display: none; |
|
23 |
+ } |
|
24 |
+ .qr { |
|
25 |
+ position: fixed; |
|
26 |
+ left: 50%; |
|
27 |
+ top: 50%; |
|
28 |
+ margin-left: -100px; |
|
29 |
+ margin-top: -100px; |
|
30 |
+ padding: 5px 5px 0 5px; |
|
31 |
+ border: 1px solid #000; |
|
32 |
+ border-radius: 5px; |
|
33 |
+ } |
|
34 |
+ </style> |
|
35 |
+ </head> |
|
36 |
+ <body> |
|
37 |
+ <div class="container" > |
|
38 |
+ <img id="qr_logo" class="hidden" src="{% static 'kodo/img/paiai_96_96.png' %}"> |
|
39 |
+ <div id="qr" class="qr"></div> |
|
40 |
+ </div> |
|
41 |
+ |
|
42 |
+ <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> |
|
43 |
+ <script src="//cdnjs.cloudflare.com/ajax/libs/lrsjng.jquery-qrcode/0.14.0/jquery-qrcode.min.js"></script> |
|
44 |
+ <script> |
|
45 |
+ $("#qr").empty().qrcode({ |
|
46 |
+ render: 'canvas', |
|
47 |
+ mode: 0, |
|
48 |
+ text: '{{ qr }}' |
|
49 |
+ }); |
|
50 |
+ </script> |
|
51 |
+ <script type="text/javascript" src="//res.wx.qq.com/open/js/jweixin-1.2.0.js"></script> |
|
52 |
+ <script type="text/javascript" src="{% static 'kodo/js/jswe-0.0.4.js' %}"></script> |
|
53 |
+ <script> |
|
54 |
+ V.initWxData({ |
|
55 |
+ imgUrl: "http://pai.ai/static/kodo/img/paiai_96_96.png", |
|
56 |
+ link: 'http://pai.ai/w/o?r=http%3A%2F%2Fpai.ai%2Fp%2Floginqr', |
|
57 |
+ desc: "授权登录", |
|
58 |
+ title: "授权登录", |
|
59 |
+ timeLine: "" |
|
60 |
+ }, true); |
|
61 |
+ V.hideOptionMenu(); |
|
62 |
+ </script> |
|
63 |
+ </body> |
|
64 |
+</html> |
@@ -0,0 +1,13 @@ |
||
1 |
+<!DOCTYPE html> |
|
2 |
+<html lang="en"> |
|
3 |
+<head> |
|
4 |
+ <meta charset="UTF-8"> |
|
5 |
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
6 |
+ <meta http-equiv="X-UA-Compatible" content="ie=edge"> |
|
7 |
+ <title>授权成功</title> |
|
8 |
+</head> |
|
9 |
+<body> |
|
10 |
+ <div class="" style="text-align:center;margin-top:100px;font-size:25px;">授权成功</div> |
|
11 |
+ <div class="" style="text-align:center;font-size:15px;">请扫描统揽大屏二维码开启大屏</div> |
|
12 |
+</body> |
|
13 |
+</html> |
@@ -4,7 +4,7 @@ from django.conf.urls import url |
||
4 | 4 |
|
5 | 5 |
from account import tourguide_views |
6 | 6 |
from group import lensman_views |
7 |
-from page import info_views, oauth_views, page_views, sale_views |
|
7 |
+from page import info_views, oauth_views, page_views, sale_views, screen_views |
|
8 | 8 |
|
9 | 9 |
|
10 | 10 |
urlpatterns = [ |
@@ -33,3 +33,9 @@ urlpatterns = [ |
||
33 | 33 |
url(r'^clerk$', oauth_views.clerk_oauth, name='clerk_oauth'), # 店员授权页面 |
34 | 34 |
url(r'^clerk/info$', info_views.clerk_info_oauth, name='clerk_info_oauth'), # 店员信息授权页面 |
35 | 35 |
] |
36 |
+ |
|
37 |
+urlpatterns += [ |
|
38 |
+ url(r'^qr$', screen_views.screen_admin_oauthqr, name='oauthqr'), |
|
39 |
+ url(r'^screen/admin/oauth$', screen_views.screen_admin_oauth, name='screen_admin_oauth'), |
|
40 |
+ url(r'^screen/admin/login$', screen_views.screen_admin_login, name='screen_admin_login'), |
|
41 |
+] |
@@ -2,7 +2,7 @@ Django==1.11.16 |
||
2 | 2 |
django-admin==1.3.2 |
3 | 3 |
django-cors-headers==2.4.0 |
4 | 4 |
django-curtail-uuid==1.0.4 |
5 |
-django-detect==1.0.6 |
|
5 |
+django-detect==1.0.8 |
|
6 | 6 |
django-file-md5==1.0.2 |
7 | 7 |
django-file-upload==1.1.0 |
8 | 8 |
django-ip==1.0.2 |
@@ -187,3 +187,8 @@ class TokenStatusCode(BaseStatusCode): |
||
187 | 187 |
""" 票据相关错误码 4090xx """ |
188 | 188 |
TOKEN_NOT_FOUND = StatusCodeField(409901, 'Token Not Found', description=u'票据不存在') |
189 | 189 |
TOKEN_HAS_EXPIRED = StatusCodeField(409911, 'Token Has Expired', description=u'票据过期,请刷新重扫二维码') |
190 |
+ |
|
191 |
+ |
|
192 |
+class PermissionStatusCode(BaseStatusCode): |
|
193 |
+ """ 4099xx 权限相关错误码 """ |
|
194 |
+ PERMISSION_DENIED = StatusCodeField(409900, 'Permission Denied', description=u'权限不足') |
@@ -69,3 +69,5 @@ BOX_PROGRAM_VERSION_INFO = 'box:program:version:info' # STRING,BOX 程序版 |
||
69 | 69 |
|
70 | 70 |
# 小程序相关 |
71 | 71 |
MINI_PROGRAM_GIS_LIST = 'tamron:miniprogram:gis:list' |
72 |
+ |
|
73 |
+KODO_SCREEN_ADMIN_LOGIN = 'kodo:screen:admin:login:%s:%s' # brand_id, token |